RK3399 Android7.1 VoLTE视频通话
一.通话记录 视频拨号按钮
1.1.packages\apps\Dialer\res\values-zh-rCN\strings.xml
<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
<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
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
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;
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
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 方法
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
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
@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 处理拨号
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();
}
}

浙公网安备 33010602011771号