2.去电从拨号盘界面有关拨号的部分由DialpadFragment.java实现,无论是单卡还是双卡,当点击拨号按键时,最后都会调用handleDialButtonPressed方法进行处理,DialogFragmentCall_Action的活动Call_Action的活动
private void handleDialButtonPressed() {
if (isDigitsEmpty() && (mRecipients == null || !mRecipients.isShown())) {
// No number entered.
handleDialButtonClickWithEmptyDigits()
} else {
boolean isDigitsShown = mDigits.isShown()
final String number = isDigitsShown ? mDigits.getText().toString() :
mRecipients.getText().toString().trim()
if (isDigitsShown && isDigitsEmpty()) {
handleDialButtonClickWithEmptyDigits()
} else if (mAddParticipant && isPhoneInUse() && isDigitsEmpty()
&& mRecipients.isShown() && isRecipientEmpty()) {
android.widget.Toast.makeText(getActivity(),
"Error: Cannot dial. Please provide conference recipients.",
android.widget.Toast.LENGTH_SHORT).show()
} else {
if (number != null
&& !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
&& number.matches(mProhibitedPhoneNumberRegexp)) {
Log.i(TAG, "The phone number is prohibited explicitly by a rule.")
if (getActivity() != null) {
DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
R.string.dialog_phone_call_prohibited_message)
dialogFragment.show(getFragmentManager(), "phone_prohibited_dialog")
}
// Clear the digits just in case.
clearDialpad()
} else {
final Intent intent = CallUtil.getCallIntent(number)
if (!isDigitsShown) {
// must be dial conference add extra
intent.putExtra(EXTRA_DIAL_CONFERENCE_URI, true)
}
intent.putExtra(ADD_PARTICIPANT_KEY, mAddParticipant && isPhoneInUse())
//
DialerUtils.startActivityWithErrorToast(getActivity(), intent)
hideAndClearDialpad(false)
}
}
}
}
3.在handleDialButtonPressed方法中,首先进行号码的有效性检查,如果号码没有问题将会进入会调用DialerUtils.startActivityWithErrorToast(getActivity(), intent);然后进入到DialerUtils.java中
public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
try {
if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
&& context instanceof Activity)) {
Point touchPoint = TouchPointManager.getInstance().getPoint();
if (touchPoint.x != 0 || touchPoint.y != 0) {
Bundle 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) {
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();
}
}
4.匹配Call_Action的活动并通过TelecomUtil.placeCall启动
public static boolean placeCall(Activity activity, Intent intent) {
if (hasCallPhonePermission(activity)) {
TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent);
return true;
}
return false;
}
4.1 Telecomutil检测完权限后使用TelecomManagerCompat.placeCall启动
/**
* Places a new outgoing call to the provided address using the system telecom service with
* the specified intent.
*/
public static void placeCall(@Nullable Activity activity,
@Nullable TelecomManager telecomManager, @Nullable Intent intent) {
if (activity == null || telecomManager == null || intent == null) {
return;
}
if (CompatUtils.isMarshmallowCompatible()) {
telecomManager.placeCall(intent.getData(), intent.getExtras());
return;
}
activity.startActivityForResult(intent, 0);
}
4.2通过telecomManager.placeCall启动,这里已经到了telecomm部分
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
if (address == null) {
Log.w(TAG, "Cannot place call to empty address.");
}
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}
5.在telecomManager中会先获取(ITelecomService.aidl)TelecomService然后继续调用placeCall方法处理,由于这是使用aidl方式进行传输,我们继续在TelecommServiceImpl中跟进
/**
* @see android.telecom.TelecomManager#placeCall
*/
@Override
public void placeCall(Uri handle, Bundle extras, String callingPackage) {
Log.d(TAG, "placeCall callingPackage = " + callingPackage);
try {
Log.startSession("TSI.pC");
enforceCallingPackage(callingPackage);
if (!canCallPhone(callingPackage, "placeCall")) {
throw new SecurityException("Package " + callingPackage
+ " is not allowed to place phone calls");
}
final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
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(mContext, userHandle)
.processIntent(
intent, callingPackage, hasCallAppOp && hasCallPermission);
} finally {
Binder.restoreCallingIdentity(token);
}
}
} finally {
Log.endSession();
}
}
6.mUserCallIntentProcessorFactory对象创建一个UserCallIntentProcessor对象调用其processIntent方法
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
Log.d(TAG, "processIntent callingPackageName = " + callingPackageName);
if (!isVoiceCapable()) {
Log.d(TAG, "processIntent(): NOT Voice capable => return");
return;
}
String action = intent.getAction();
Log.d(TAG, "[MO] processIntent(): action " + action);
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
}
}
7.根据三种CALL状态调用processOutgoingCallIntent方法
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
...
//以上主要是一些其他检测,检测是否能呼叫出去
if (!launchHomeDialong) {
//跟进该广播
sendBroadcastToReceiver(intent);
}
}
8.内部校验一些是否能拨号权限以及其它操作限制看是否需要直接弹框拒绝,如果都通过了最后会调用sendBroadcastToReceiver方法发送广播
/**
* Trampolines the intent to the broadcast receiver that runs only as the primary user.
*/
private boolean sendBroadcastToReceiver(Intent intent) {
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");
try {
mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
Log.d(this, "Sending broadcast as user to CallReceiver--");
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
9.最终看到发送一个广播到PrimaryCallReceiver.class中,继续在该广播(
com.android.server.telecom.components. PrimaryCallReceiver)的接收事件中跟进
@Override
public void onReceive(Context context, Intent intent) {
Log.startSession("PCR.oR");
synchronized (getTelecomSystem().getLock()) {
getTelecomSystem().getCallIntentProcessor().processIntent(intent);
}
Log.endSession();
}
10.查看TelecomSystem中的getCallIntentProcessor方法,发现是由CallIntentProcessor的对象调用processIntent方法,
public void processIntent(Intent intent) {
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();
}
Context context,
11.如果不是未知的call类型则调用processOutgoingCallIntent,继续跟进
static void processOutgoingCallIntent(
CallsManager callsManager,
Intent intent) {
...
12.
Call call = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
if (call != null) {
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
isPrivilegedDialer);
final int result = broadcaster.processIntent();
final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
if (!success && call != null) {
callsManager.clearPendingMOEmergencyCall();
disconnectCallAndShowErrorDialog(context, call, result);
}
}
}
13.继续跟进NewOutgoingCallIntentBroadcaster广播中的processIntent方法
@VisibleForTesting
public int processIntent() {
...
//根据Call的类型进行分别处理
if (isVoicemailNumber) {
if (Intent.ACTION_CALL.equals(action)
|| Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
...
boolean speakerphoneOn = mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
//placeOutgoingCall继续跟进
mCallsManager.placeOutgoingCall(mCall, handle, null, speakerphoneOn,
VideoProfile.STATE_AUDIO_ONLY);
return DisconnectCause.NOT_DISCONNECTED;
}
}
...
if (callImmediately) {
Log.i(this, "Placing call immediately instead of waiting for "
+ " OutgoingCallBroadcastReceiver: %s", intent);
String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;
boolean speakerphoneOn = mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
int videoState = mIntent.getIntExtra(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY);
mCall.setNewOutgoingCallIntentBroadcastIsDone();
Log.d(TAG, "processIntent(): scheme " + scheme + ", speakerphoneOn" + speakerphoneOn + ", videoState " + videoState);
mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
speakerphoneOn, videoState);
}
UserHandle targetUser = mCall.getInitiatingUser();
Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
//最终调用的broadcastIntent
if (isSkipSchemaParsing) {
broadcastIntent(intent, handle.toString(), !callImmediately, targetUser);
} else {
broadcastIntent(intent, number, !callImmediately, targetUser);
}
return DisconnectCause.NOT_DISCONNECTED;
}
这里看到processIntent方法主要对三种类型call的一些检查,
1.普通call Intent.ACTION_CALL
普通call任何应用都可以发起,第三方应用拨号都是使用该intent
2.系统call Intent.ACTION_CALL_PRIVILEGED
系统call只有系统应用才能使用
3.紧急呼叫call Intent.ACTION_CALL_EMERGENCY
紧急呼叫call 同样只有系统应用才能使用,并且可以在无卡状态下拨.
最后调用broadcastIntent,根据以上源码分析的流程整理的时序图如下,如果不清楚可以另存为到本地查看。