(O)Telephony分析之通话流程分析(二)拨打电话流程分析(上)
2018-01-12 17:46
471 查看
拨打电话,是从通话的拨号盘开始的,而拨号盘的界面是在DialpadFragment,因此,需要从这个地方进行分析
一.拨号盘界面拨号流程
public void onClick(View view) {
......
if (resId == R.id.dialpad_floating_action_button) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
// 处理Dial Button点击事件
handleDialButtonPressed();
}
......
}通过调用handleDialButtonPressed方法,处理点击拨号按钮后的流程
private void handleDialButtonPressed() {
// 没有输入号码的情况下,暂不讨论
if (isDigitsEmpty()) { // No number entered.
handleDialButtonClickWithEmptyDigits();
} else {
......
// uri加上tel前缀,并且type设置为INITIATION_DIALPAD,生成URI
final Intent intent = new CallIntentBuilder(number).setCallInitiationType(LogState.INITIATION_DIALPAD).build();
// Leo, 尝试去启动一个Activity,如果启动不了,会弹出一个 "Activity is not found" 的Toast框
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
// Leo,隐藏拨号盘,并且清除号码盘上的号码
hideAndClearDialpad(false);
}
}可以看到此处通过初始化CallIntentBuilder,然后调用其build方法,生成一个Intent对象,并作为参数,调用DialerUtils的startActivityWithErrorToast方法
知道getCallIntent的参数分别为,
第一个参数为刚刚生成的Uri对象,其是以tel:为前缀的
第二个参数由于并未设置过,因此为null
第三个参数由于没有设置过视频通话,因此为VideoProfile.STATE_AUDIO_ONLY,语音通话
第四个参数为传入的LogState.INITIATION_DIALPAD
public static Intent getCallIntent(
Uri uri, PhoneAccountHandle accountHandle, int videoState, int callIntiationType) {
// 初始化一个Intent,action为CALL_ACTION,Data为uri
final Intent intent = new Intent(CALL_ACTION, uri);
// 目前应该是没有videoState的,即为VideoProfile.STATE_AUDIO_ONLY
intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
final Bundle b = new Bundle();
// 设置其INITIATION_TYPE,此处第一次为LogState.INITIATION_DIALPAD
b.putInt(EXTRA_CALL_INITIATION_TYPE, callIntiationType);
// 设置其Extra
intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, b);
// 此前没有设置,应该为null
if (accountHandle != null) {
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
}
return intent;
}确认Intent中所包含的数据
接下来会调用DialerUtils的startActivityWithErrorToast方法
public static void startActivityWithErrorToast(Context context, Intent intent) {
startActivityWithErrorToast(context, intent, R.string.activity_not_available);
}
二.Telecom阶段
看下其代码
registerService(Context.TELECOM_SERVICE, TelecomManager.class,
new CachedServiceFetcher<TelecomManager>() {
@Override
public TelecomManager createService(ContextImpl ctx) {
return new TelecomManager(ctx.getOuterContext());
}});其返回的是新初始化的TelecomManager对象,再看下TelecomManager的构造方法
public TelecomManager(Context context) {
this(context, null);
}
(二)TelecomManagerCompat的placeCall方法分析
public static void placeCall(@Nullable Activity activity,
@Nullable TelecomManager telecomManager, @Nullable Intent intent) {
......
// Android M以上的版本
if (CompatUtils.isMarshmallowCompatible()) {
// 调用了TelecomManager对象的placeCall函数
// 第一个参数为包含号码的URI
telecomManager.placeCall(intent.getData(), intent.getExtras());
return;
}
activity.startActivityForResult(intent, 0);
}由于是O项目,高于M项目,因此调用的是telecomManager的placeCall方法,而telecomManager是刚刚看到的TelecomManager对象,因此
public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
......
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}从此前的分析,TelecomManager的getTelecomService方法,在telecomServiceImpl为null的时候,返回的是TelecomManagerImpl的mBinderImpl
因此,调用了mBinderImpl的placeCall
public void placeCall(Uri handle, Bundle extras, String
4000
callingPackage) {
try {
......
// 判断是否拥有拨打电话的权限
final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
PackageManager.PERMISSION_GRANTED;
synchronized (mLock) {
final UserHandle userHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
try {
final Intent intent = new Intent(Intent.ACTION_CALL, handle);
if (extras != null) {
extras.setDefusable(true);
intent.putExtras(extras);
}
// mUserCallIntentProcessorFactory的create方法是在TelecomSystem的构造方法中重写的
// 返回的是UserCallIntentProcessor对象
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, isSelfManaged ||
(hasCallAppOp && hasCallPermission));
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
......
}调用mUserCallIntentProcessorFactory的create方法,并且调用返回对象的processIntent方法,那么mUserCallIntentProcessorFactory是什么呢?
查看其定义的地方
public TelecomServiceImpl(
Context context,
CallsManager callsManager,
PhoneAccountRegistrar phoneAccountRegistrar,
CallIntentProcessor.Adapter callIntentProcessorAdapter,
UserCallIntentProcessorFactory userCallIntentProcessorFactory,
DefaultDialerCache defaultDialerCache,
SubscriptionManagerAdapter subscriptionManagerAdapter,
TelecomSystem.SyncRoot lock) {
......
mUserCallIntentProcessorFactory = userCallIntentProcessorFactory;
......
}也就是说,这个是由TelecomServiceImpl对象在初始化的时候,传入的,那么TelecomServiceImpl是在什么地方初始化的呢?
还记得前篇中关于TelecomSystem的初始化么?在该类的构造方法中,可以看到
mTelecomServiceImpl = new TelecomServiceImpl(
mContext, mCallsManager, mPhoneAccountRegistrar,
new CallIntentProcessor.AdapterImpl(),
new UserCallIntentProcessorFactory() {
@Override
public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
return new UserCallIntentProcessor(context, userHandle);
}
},
defaultDialerCache,
new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
mLock);也就是说,UserCallIntentProcessorFactory的create方法中,初始化了一个UserCallIntentProcessor对象,因此
上述的TelecomManager的placeCall方法,最终是调用了UserCallIntentProcessor对象的processIntent方法
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
......
String action = intent.getAction();
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
}
}由于此前传入的Intent的ACTION为Intent.ACTION_CALL,因此会调用processOutgoingCallIntent,此处我们需要注意的是,其传入的参数是什么
第一个参数为带有数据的Intent,这个无需多言
第二个参数为callingPackageName,是在TelecomManager中使用mContext.getOpPackageName()得到的,而mContext是由DialpadFragment中使用getActivity得到的,因此,它的值就一目了然了
第三个参数为canCallNonEmergency,是在TelecomServiceImpl中定义的,这个无需多言了
接下来,继续分析代码processOutgoingCallIntent
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
Uri handle = intent.getData(); // tel:号码
String scheme = handle.getScheme(); // tel
String uriString = handle.getSchemeSpecificPart();
......
// 通话状态,默认是语音通话
int videoState = intent.getIntExtra(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY);
Log.d(this, "processOutgoingCallIntent videoState = " + videoState);
// Leo, 传入的package是否为系统默认的Dialer应用
intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
isDefaultOrSystemDialer(callingPackageName));
// Save the user handle of current user before forwarding the intent to primary user.
intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
sendBroadcastToReceiver(intent);
}这个mUserHandle,追述到上面,可以看到是在TelecomServiceImpl中进行定义的,具体的代码为
final UserHandle userHandle = Binder.getCallingUserHandle();
暂时不提
一.拨号盘界面拨号流程
public void onClick(View view) {
......
if (resId == R.id.dialpad_floating_action_button) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
// 处理Dial Button点击事件
handleDialButtonPressed();
}
......
}通过调用handleDialButtonPressed方法,处理点击拨号按钮后的流程
private void handleDialButtonPressed() {
// 没有输入号码的情况下,暂不讨论
if (isDigitsEmpty()) { // No number entered.
handleDialButtonClickWithEmptyDigits();
} else {
......
// uri加上tel前缀,并且type设置为INITIATION_DIALPAD,生成URI
final Intent intent = new CallIntentBuilder(number).setCallInitiationType(LogState.INITIATION_DIALPAD).build();
// Leo, 尝试去启动一个Activity,如果启动不了,会弹出一个 "Activity is not found" 的Toast框
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
// Leo,隐藏拨号盘,并且清除号码盘上的号码
hideAndClearDialpad(false);
}
}可以看到此处通过初始化CallIntentBuilder,然后调用其build方法,生成一个Intent对象,并作为参数,调用DialerUtils的startActivityWithErrorToast方法
public static class CallIntentBuilder { ...... public CallIntentBuilder(Uri uri) { mUri = uri; } public CallIntentBuilder(String number) { this(CallUtil.getCallUri(number)); } public CallIntentBuilder setCallInitiationType(int initiationType) { mCallInitiationType = initiationType; return this; } public Intent build() { // Leo, 初始化一个Intent return getCallIntent( mUri, mPhoneAccountHandle, mIsVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY, mCallInitiationType); } }从这边来看,首先通过构造方法,将number生成一个Uri,然后通过build方法调用getCallIntent方法,返回一个Intent,而通过上述了解,
知道getCallIntent的参数分别为,
第一个参数为刚刚生成的Uri对象,其是以tel:为前缀的
第二个参数由于并未设置过,因此为null
第三个参数由于没有设置过视频通话,因此为VideoProfile.STATE_AUDIO_ONLY,语音通话
第四个参数为传入的LogState.INITIATION_DIALPAD
public static Intent getCallIntent(
Uri uri, PhoneAccountHandle accountHandle, int videoState, int callIntiationType) {
// 初始化一个Intent,action为CALL_ACTION,Data为uri
final Intent intent = new Intent(CALL_ACTION, uri);
// 目前应该是没有videoState的,即为VideoProfile.STATE_AUDIO_ONLY
intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
final Bundle b = new Bundle();
// 设置其INITIATION_TYPE,此处第一次为LogState.INITIATION_DIALPAD
b.putInt(EXTRA_CALL_INITIATION_TYPE, callIntiationType);
// 设置其Extra
intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, b);
// 此前没有设置,应该为null
if (accountHandle != null) {
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
}
return intent;
}确认Intent中所包含的数据
接下来会调用DialerUtils的startActivityWithErrorToast方法
public static void startActivityWithErrorToast(Context context, Intent intent) {
startActivityWithErrorToast(context, intent, R.string.activity_not_available);
}
public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) { try { if ((IntentUtil.CALL_ACTION.equals(intent.getAction()) && context instanceof Activity)) { ...... // 调用TelecomUtil的placeCall函数,传入的参数为intent 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); } } ...... } catch (ActivityNotFoundException e) { Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show(); } }调用TelecomUtil的placeCall方法
二.Telecom阶段
public static boolean placeCall(Activity activity, Intent intent) { if (hasCallPhonePermission(activity)) { // 调用TelecomManagerCompat的placeCall函数,注意其传入的参数 // 第一个参数为DialpadFragment中的getActivity // 第二个参数为TelecomManager对象 // 第三个参数中包含了拨号的所有参数 TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent); return true; } return false; }(一)getTelecomManager是什么
看下其代码
private static TelecomManager getTelecomManager(Context context) { return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); }此前,我们有对getSystemService进行过分析,是在SystemServiceRegistry中进行注册的,如下:
registerService(Context.TELECOM_SERVICE, TelecomManager.class,
new CachedServiceFetcher<TelecomManager>() {
@Override
public TelecomManager createService(ContextImpl ctx) {
return new TelecomManager(ctx.getOuterContext());
}});其返回的是新初始化的TelecomManager对象,再看下TelecomManager的构造方法
public TelecomManager(Context context) {
this(context, null);
}
public TelecomManager(Context context, ITelecomService telecomServiceImpl) { Context appContext = context.getApplicationContext(); if (appContext != null) { mContext = appContext; } else { mContext = context; } mTelecomServiceOverride = telecomServiceImpl; android.telecom.Log.initMd5Sum(); }因此,此处的TelecomManager对象中的telecomServiceImpl为null
(二)TelecomManagerCompat的placeCall方法分析
public static void placeCall(@Nullable Activity activity,
@Nullable TelecomManager telecomManager, @Nullable Intent intent) {
......
// Android M以上的版本
if (CompatUtils.isMarshmallowCompatible()) {
// 调用了TelecomManager对象的placeCall函数
// 第一个参数为包含号码的URI
telecomManager.placeCall(intent.getData(), intent.getExtras());
return;
}
activity.startActivityForResult(intent, 0);
}由于是O项目,高于M项目,因此调用的是telecomManager的placeCall方法,而telecomManager是刚刚看到的TelecomManager对象,因此
public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
......
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}从此前的分析,TelecomManager的getTelecomService方法,在telecomServiceImpl为null的时候,返回的是TelecomManagerImpl的mBinderImpl
因此,调用了mBinderImpl的placeCall
public void placeCall(Uri handle, Bundle extras, String
4000
callingPackage) {
try {
......
// 判断是否拥有拨打电话的权限
final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
PackageManager.PERMISSION_GRANTED;
synchronized (mLock) {
final UserHandle userHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
try {
final Intent intent = new Intent(Intent.ACTION_CALL, handle);
if (extras != null) {
extras.setDefusable(true);
intent.putExtras(extras);
}
// mUserCallIntentProcessorFactory的create方法是在TelecomSystem的构造方法中重写的
// 返回的是UserCallIntentProcessor对象
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, isSelfManaged ||
(hasCallAppOp && hasCallPermission));
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
......
}调用mUserCallIntentProcessorFactory的create方法,并且调用返回对象的processIntent方法,那么mUserCallIntentProcessorFactory是什么呢?
查看其定义的地方
public TelecomServiceImpl(
Context context,
CallsManager callsManager,
PhoneAccountRegistrar phoneAccountRegistrar,
CallIntentProcessor.Adapter callIntentProcessorAdapter,
UserCallIntentProcessorFactory userCallIntentProcessorFactory,
DefaultDialerCache defaultDialerCache,
SubscriptionManagerAdapter subscriptionManagerAdapter,
TelecomSystem.SyncRoot lock) {
......
mUserCallIntentProcessorFactory = userCallIntentProcessorFactory;
......
}也就是说,这个是由TelecomServiceImpl对象在初始化的时候,传入的,那么TelecomServiceImpl是在什么地方初始化的呢?
还记得前篇中关于TelecomSystem的初始化么?在该类的构造方法中,可以看到
mTelecomServiceImpl = new TelecomServiceImpl(
mContext, mCallsManager, mPhoneAccountRegistrar,
new CallIntentProcessor.AdapterImpl(),
new UserCallIntentProcessorFactory() {
@Override
public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
return new UserCallIntentProcessor(context, userHandle);
}
},
defaultDialerCache,
new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
mLock);也就是说,UserCallIntentProcessorFactory的create方法中,初始化了一个UserCallIntentProcessor对象,因此
上述的TelecomManager的placeCall方法,最终是调用了UserCallIntentProcessor对象的processIntent方法
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
......
String action = intent.getAction();
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
}
}由于此前传入的Intent的ACTION为Intent.ACTION_CALL,因此会调用processOutgoingCallIntent,此处我们需要注意的是,其传入的参数是什么
第一个参数为带有数据的Intent,这个无需多言
第二个参数为callingPackageName,是在TelecomManager中使用mContext.getOpPackageName()得到的,而mContext是由DialpadFragment中使用getActivity得到的,因此,它的值就一目了然了
第三个参数为canCallNonEmergency,是在TelecomServiceImpl中定义的,这个无需多言了
接下来,继续分析代码processOutgoingCallIntent
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
Uri handle = intent.getData(); // tel:号码
String scheme = handle.getScheme(); // tel
String uriString = handle.getSchemeSpecificPart();
......
// 通话状态,默认是语音通话
int videoState = intent.getIntExtra(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY);
Log.d(this, "processOutgoingCallIntent videoState = " + videoState);
// Leo, 传入的package是否为系统默认的Dialer应用
intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
isDefaultOrSystemDialer(callingPackageName));
// Save the user handle of current user before forwarding the intent to primary user.
intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
sendBroadcastToReceiver(intent);
}这个mUserHandle,追述到上面,可以看到是在TelecomServiceImpl中进行定义的,具体的代码为
final UserHandle userHandle = Binder.getCallingUserHandle();
暂时不提
private boolean sendBroadcastToReceiver(Intent intent) { // 非incoming call intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); // 设置接受广播的类 intent.setClass(mContext, PrimaryCallReceiver.class); Log.d(this, "Sending broadcast as user to CallReceiver"); // 系统广播 mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); return true; }可以看到,其实是将通话的基本信息发送给PrimaryCallReceiver进行处理
public void onReceive(Context context, Intent intent) { ...... synchronized (getTelecomSystem().getLock()) { // 接收到消息后处理,调用TelecomSystem的getCallIntentPRocessor方法,获取CallIntentProcessor对象 // 并且调用起的processIntent方法 getTelecomSystem().getCallIntentProcessor().processIntent(intent); } ...... }
public TelecomSystem getTelecomSystem() { return TelecomSystem.getInstance(); }这个TelecomSystem的getInstance方法,返回了一个TelecomSystem对象,就是我们前篇所了解到的TelecomSystem对象,那么
public CallIntentProcessor getCallIntentProcessor() { return mCallIntentProcessor; }TelecomSystem的构造函数中
mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);初始化CallIntentProcessor对象,并调用其processIntent方法
public void processIntent(Intent intent) { // 默认false final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false); Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall); Trace.beginSection("processNewCallCallIntent"); if (isUnknownCall) { processUnknownCallIntent(mCallsManager, intent); } else { // 调用 processOutgoingCallIntent(mContext, mCallsManager, intent); } Trace.endSection(); }调用processOutgoingCallIntent方法,注意其参数mCallsManager是在TelecomSystem中初始化CallIntentProcessor时传入的
相关文章推荐
- (O)Telephony分析之通话流程分析(三)拨打电话流程分析(下)
- Android5.1 Telephony流程分析——拨打电话流程(MO CALL)
- (O)Telephony分析之通话流程分析(一) TelecomManager的getTelecomService方法解析
- Android电话拨打流程源码分析
- Android4.4 Telephony流程分析——电话挂断
- Android电话拨打流程源码分析
- Android电话拨打流程源码分析
- Android电话拨打流程源码分析
- Android4.4 Telephony流程分析——拨号应用(Dialer)的通话记录加载过程
- Android电话拨打流程源码分析
- Android电话拨打流程源码分析
- android拨打电话流程分析
- Android电话拨打流程源码分析
- Android4.4 Telephony流程分析——通话状态更新
- Android电话拨打流程源码分析
- Android电话拨打流程源码分析
- Android N拨打电话的流程
- Android4.4 Telephony流程分析——短信(SMS)接收过程
- 使用 Gmail 拨打国内电话,通话双方均免费的方法
- 用Gmail拨打国内电话,通话双方均免费的方法(下载)