(O)Telephony分析之通话流程分析(二)拨打电话流程分析(上)

拨打电话,是从通话的拨号盘开始的,而拨号盘的界面是在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方法
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() {
						    @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 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时传入的


















你可能感兴趣的:(Telephony分析)