RK3399 Android7.1 VoLTE视频通话

通话记录分析 --- 通话详情 之一 

一.通话记录 视频拨号按钮

1.1.packages\apps\Dialer\res\values-zh-rCN\strings.xml

1
2
3
<string name="call_log_action_video_call" msgid="7724301709041128296">"视频通话"</string>
<string name="call_log_action_send_message" msgid="5679719296905285131">"发送短信"</string>
<string name="call_log_action_details" msgid="701345508704970622">"通话详情"</string>

 1.1.2.packages\apps\Dialer\res\layout\call_log_list_item_actions.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<LinearLayout
    android:id="@+id/video_call_action"
    style="@style/CallLogActionStyle">
 
    <ImageView
        style="@style/CallLogActionIconStyle"
        android:src="@drawable/ic_videocam_24dp" />
 
    <TextView
        style="@style/CallLogActionTextStyle"
        android:text="@string/call_log_action_video_call" />
 
</LinearLayout>

1.2. 加载控件  

packages\apps\Dialer\src\com\android\dialer\calllog\CallLogListItemViewHolder.java 

1
2
3
4
public void inflateActionViewStub() {
        ……
        videoCallButtonView = actionsView.findViewById(R.id.video_call_action);
        videoCallButtonView.setOnClickListener(this);       

 1.3.

// If one of the calls had video capabilities, show the video call button.

//如果其中一个通话具有视频功能,则显示视频通话按钮。

mCallLogCache.isVideoEnabled()->false
canPlaceCallToNumber->true
phoneCallDetailsViews.callTypeIcons.isVideoShown()->false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    private void bindActionButtons() {
        boolean canPlaceCallToNumber = PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation);
 
        if (!TextUtils.isEmpty(voicemailUri) && canPlaceCallToNumber) {
            callButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number));
            ((TextView) callButtonView.findViewById(R.id.call_action_text))
                    .setText(TextUtils.expandTemplate(
                            mContext.getString(R.string.call_log_action_call),
                            nameOrNumber));
            TextView callTypeOrLocationView = ((TextView) callButtonView.findViewById(
                    R.id.call_type_or_location_text));
            if (callType == Calls.VOICEMAIL_TYPE && !TextUtils.isEmpty(callTypeOrLocation)) {
                callTypeOrLocationView.setText(callTypeOrLocation);
                callTypeOrLocationView.setVisibility(View.VISIBLE);
            } else {
                callTypeOrLocationView.setVisibility(View.GONE);
            }
            callButtonView.setVisibility(View.VISIBLE);
        } else {
            callButtonView.setVisibility(View.GONE);
        }
 
        // If one of the calls had video capabilities, show the video call button.
        if (mCallLogCache.isVideoEnabled() && canPlaceCallToNumber &&
                phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
            videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number));
            videoCallButtonView.setVisibility(View.VISIBLE);
        } else {
            videoCallButtonView.setVisibility(View.GONE);
        }
 
……

A.通话是否具有视频功能   mCallLogCache.isVideoEnabled()

packages\apps\Dialer\src\com\android\dialer\calllog\calllogcache\CallLogCache.java

mIsVideoEnabled = CallUtil.isVideoEnabled(mContext);  import com.android.contacts.common.CallUtil;

1
2
3
4
5
6
7
public boolean isVideoEnabled() {
    if (!mHasCheckedForVideoEnabled) {
        mIsVideoEnabled = CallUtil.isVideoEnabled(mContext);
        mHasCheckedForVideoEnabled = true;
    }
    return mIsVideoEnabled;
}

packages\apps\ContactsCommon\src\com\android\contacts\common\CallUtil.java

/**
* Indicates that the video calling is not available.
*/
public static final int VIDEO_CALLING_DISABLED = 0;

/**
* Indicates that video calling is enabled, regardless of presence status.
*/
public static final int VIDEO_CALLING_ENABLED = 1;

getVideoCallingAvailability 看支不支持 video_calling 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static boolean isVideoEnabled(Context context) {
    return (getVideoCallingAvailability(context) & VIDEO_CALLING_ENABLED) != 0;
}
 
 
public static int getVideoCallingAvailability(Context context) {
    if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
            || !CompatUtils.isVideoCompatible()) {
        return VIDEO_CALLING_DISABLED;
    }
    TelecomManager telecommMgr = (TelecomManager)
            context.getSystemService(Context.TELECOM_SERVICE);
    if (telecommMgr == null) {
        return VIDEO_CALLING_DISABLED;
    }
 
    List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts();
    for (PhoneAccountHandle accountHandle : accountHandles) {
        PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
        if (account != null) {
            if (account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {//能够视频通话的标志
                // Builds prior to N do not have presence support.
                if (!CompatUtils.isVideoPresenceCompatible()) {
                    return VIDEO_CALLING_ENABLED;
                }
 
                int videoCapabilities = VIDEO_CALLING_ENABLED;
                if (account.hasCapabilities(
                        PhoneAccountSdkCompat.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {//列表示是否联系人的电话号码支持视频通话
                    videoCapabilities |= VIDEO_CALLING_PRESENCE;
                }
                return videoCapabilities;
            }
        }
    }
    return VIDEO_CALLING_DISABLED;//以上条件均不满足 最后就会返回VIDEO_CALLING_DISABLED 0
}   

frameworks\base\telecomm\java\android\telecom\PhoneAccount.java

Android 8.0 PhoneAccount全面解析 PhoneAccount这个类是关于SIM卡信息的

PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);

account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)  

account.hasCapabilities(PhoneAccountSdkCompat.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)

 

B.添加拨号的intent  videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number));

b.1. packages\apps\Dialer\src\com\android\dialer\calllog\IntentProvider.java

主要看 new IntentProvider() 类中 getIntent 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static IntentProvider getReturnVideoCallIntentProvider(final String number) {
    return getReturnVideoCallIntentProvider(number, null);
}
 
public static IntentProvider getReturnVideoCallIntentProvider(final String number,
        final PhoneAccountHandle accountHandle) {
    return new IntentProvider() {
        @Override
        public Intent getIntent(Context context) {
            return new CallIntentBuilder(number)
                    .setPhoneAccountHandle(accountHandle)
                    .setCallInitiationType(LogState.INITIATION_CALL_LOG)
                    .setIsVideoCall(true)
                    .build();
        }
    };
}  

public abstract Intent getIntent(Context context);

没想到IntentProvider 也是个抽象类  public abstract class IntentProvider  {

b.2. packages\apps\Dialer\src\com\android\dialer\util\IntentUtil.java   构建intent   // 普通电话为VideoProfile.STATE_AUDIO_ONLY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class CallIntentBuilder {
    private Uri mUri;
    private int mCallInitiationType;
    private PhoneAccountHandle mPhoneAccountHandle;
    private boolean mIsVideoCall = false;
   ……
    public Intent build() {
        return getCallIntent(
                mUri,
                mPhoneAccountHandle,
                mIsVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY,
                mCallInitiationType);
    }
}  

1.4.按钮监听事件 走 else startActivityWithErrorToast

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public void onClick(View view) {
    if (view.getId() == R.id.primary_action_button && !TextUtils.isEmpty(voicemailUri)) {
        mVoicemailPrimaryActionButtonClicked = true;
        mExpandCollapseListener.onClick(primaryActionView);
    } else if (view.getId() == R.id.call_with_note_action) {
        CallSubjectDialog.start(
                (Activity) mContext,
                info.photoId,
                info.photoUri,
                info.lookupUri,
                (String) nameOrNumber /* top line of contact view in call subject dialog */,
                isBusiness,
                number,
                TextUtils.isEmpty(info.name) ? null : displayNumber, /* second line of contact
                                                                       view in dialog. */
                numberType, /* phone number type (e.g. mobile) in second line of contact view */
                accountHandle);
    } else {
        final IntentProvider intentProvider = (IntentProvider) view.getTag();
        if (intentProvider != null) {
            final Intent intent = intentProvider.getIntent(mContext);
            // See IntentProvider.getCallDetailIntentProvider() for why this may be null.
            if (intent != null) {
                DialerUtils.startActivityWithErrorToast(mContext, intent);
            }
        }
    }
}

1.5.packages\apps\Dialer\src\com\android\dialer\util\DialerUtils.java

 intent.getAction()->android.intent.action.CALL 处理拨号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
    try {
        if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
                        && context instanceof Activity)) {
            // All dialer-initiated calls should pass the touch point to the InCallUI
            Point touchPoint = TouchPointManager.getInstance().getPoint();
            if (touchPoint.x != 0 || touchPoint.y != 0) {
                Bundle extras;
                // Make sure to not accidentally clobber any existing extras
                if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
                    extras = intent.getParcelableExtra(
                            TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
                } else {
                    extras = new Bundle();
                }
                extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint);
                intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
            }
 
            final boolean hasCallPermission = TelecomUtil.placeCall((Activity) context, intent);
            if (!hasCallPermission) {
                // TODO: Make calling activity show request permission dialog and handle
                // callback results appropriately.
                Toast.makeText(context, "Cannot place call without Phone permission",
                        Toast.LENGTH_SHORT);
            }
        } else {
            context.startActivity(intent);
        }
    } catch (ActivityNotFoundException e) {
        Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
    }
}

  

 

posted @   CrushGirl  阅读(644)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2020-08-05 android:theme
2020-08-05 android:excludeFromRecents="true"
点击右上角即可分享
微信分享提示