Android6.0拨打电话流程

2019-04-14 20:34发布

class="markdown_views prism-github-gist">

Telephony框架学习(一)Android6.0MO流程

相关模块

packagesappsDialer
packagesappsInCallUI
packagesservicesTelecomm
packagesservicesTelephony
frameworksase elecomm
frameworksase elephony
frameworksopt elephony
frameworksopt etims
vendormediatekproprietarypackagesservicesIms

时序图

Android6.0去电流程,(右键点击在新标签页查看大图)
这里写图片描述

概要图

这里写图片描述

MO Log

无Update的Log Step 68 69 70 71 72
这里写图片描述
这里写图片描述

VOLTECall Log

这里写图片描述
这里写图片描述
(后期会加注释)

Dialer

Step1

@Override public void onClick(View view) { /** M: Prevent the event if dialpad is not shown. @{ */ if (getActivity() != null && !((DialtactsActivity)getActivity()).isDialpadShown()) { Log.d(TAG, "onClick but dialpad is not shown, skip !!!"); return; } /** @} */ switch (view.getId()) { case R.id.dialpad_floating_action_button: mHaptic.vibrate(); android.util.Log.d("wds_mo","step1-->Dialer-->DialpadFragment.onClick()"); handleDialButtonPressed(); break; ....

Step3

private void handleDialButtonPressed(int type) { if (isDigitsEmpty()) { // No number entered. handleDialButtonClickWithEmptyDigits(); } else { final String number = mDigits.getText().toString(); // "persist.radio.otaspdial" is a temporary hack needed for one carrier's automated // test equipment. // TODO: clean it up. 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; /** M: [IP Dial] check the type of call @{ */ if (type != Constants.DIAL_NUMBER_INTENT_NORMAL) { intent = IntentUtil.getCallIntent(IntentUtil.getCallUri(number), (getActivity() instanceof DialtactsActivity ? ((DialtactsActivity) getActivity()).getCallOrigin() : null), type); } else { intent = IntentUtil.getCallIntent(number, (getActivity() instanceof DialtactsActivity ? ((DialtactsActivity) getActivity()).getCallOrigin() : null)); } /** @} */ android.util.Log.d("wds_mo","step3-->Dialer-->DialpadFragment.handleDialButtonPressed()"); DialerUtils.startActivityWithErrorToast(getActivity(), intent); hideAndClearDialpad(false); } } }

Step5

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 = new Bundle(); extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint); intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); } android.util.Log.d("wds_mo","step5-->Dialer-->DialerUtils.startActivityWithErrorToast()"); final TelecomManager tm = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); tm.placeCall(intent.getData(), intent.getExtras()); /// M: add log for debugging if (DEBUG) { Log.d(TAG, "startActivityWithErrorToast placeCall with intent " + intent); } } else { context.startActivity(intent); } } catch (ActivityNotFoundException e) { Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show(); } }

framework/telecom

Step6

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 { android.util.Log.d("wds_mo","step6-->framework/base/Telecom-->TelecomManager.placeCall()"); service.placeCall(address, extras == null ? new Bundle() : extras, mContext.getOpPackageName()); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#placeCall", e); } } }

package/services/Telecomm

Step7

@Override public void placeCall(Uri handle, Bundle extras, String callingPackage) { enforceCallingPackage(callingPackage); if (!canCallPhone(callingPackage, "placeCall")) { throw new SecurityException("Package " + callingPackage + " is not allowed to place phone calls"); } // Note: we can still get here for the default/system dialer, even if the Phone // permission is turned off. This is because the default/system dialer is always // allowed to attempt to place a call (regardless of permission state), in case // it turns out to be an emergency call. If the permission is denied and the // call is being made to a non-emergency number, the call will be denied later on // by {@link UserCallIntentProcessor}. 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); intent.putExtras(extras); android.util.Log.d("wds_mo","step7-->Telecom-->TelecomServiceImpl.placeCall()"); new UserCallIntentProcessor(mContext, userHandle).processIntent(intent, callingPackage, hasCallAppOp && hasCallPermission); } finally { Binder.restoreCallingIdentity(token); } } }

Step8

public void processIntent(Intent intent, String callingPackageName, boolean canCallNonEmergency) { // Ensure call intents are not processed on devices that are not capable of calling. if (!isVoiceCapable()) { return; } String action = intent.getAction(); if (Intent.ACTION_CALL.equals(action) || Intent.ACTION_CALL_PRIVILEGED.equals(action) || Intent.ACTION_CALL_EMERGENCY.equals(action)) { android.util.Log.d("wds_mo","step8-->Telecom-->UserCallIntentProcessor.processIntent()"); processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency); } }

Step9

private void processOutgoingCallIntent(Intent intent, String callingPackageName, boolean canCallNonEmergency) { Uri handle = intent.getData(); String scheme = handle.getScheme(); String uriString = handle.getSchemeSpecificPart(); /// M: Do noting for CDMA empty flash at present if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) { Log.w(this, "Empty flash obtained from the call intent."); return; } if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) { handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null); } final UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, mUserHandle) && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS // restriction. showErrorDialogForRestrictedOutgoingCall(mContext, R.string.outgoing_call_not_allowed_user_restriction); Log.w(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS " + "restriction"); return; } if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { showErrorDialogForRestrictedOutgoingCall(mContext, R.string.outgoing_call_not_allowed_no_permission); Log.w(this, "Rejecting non-emergency phone call because " + android.Manifest.permission.CALL_PHONE + " permission is not granted."); return; } int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, VideoProfile.STATE_AUDIO_ONLY); Log.d(this, "processOutgoingCallIntent videoState = " + videoState); if (VideoProfile.isVideo(videoState) && TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { Log.d(this, "Emergency call...Converting video call to voice..."); videoState = VideoProfile.STATE_AUDIO_ONLY; intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); } if (VideoProfile.isVideo(videoState) && isTtyModeEnabled()) { Toast.makeText(mContext, mContext.getResources().getString(R.string. video_call_not_allowed_if_tty_enabled), Toast.LENGTH_SHORT).show(); Log.d(this, "Rejecting video calls as tty is enabled"); return; } intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER, isDefaultOrSystemDialer(callingPackageName)); android.util.Log.d("wds_mo","step9-->Telecom-->UserCallIntentProcessor.processOutgoingCallIntent()"); sendBroadcastToReceiver(intent); } private boolean isTtyModeEnabled() { return (android.provider.Settings.Secure.getInt( mContext.getContentResolver(), android.provider.Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF); } private boolean isDefaultOrSystemDialer(String callingPackageName) { if (TextUtils.isEmpty(callingPackageName)) { return false; } final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext, mUserHandle.getIdentifier()); if (TextUtils.equals(defaultDialer, callingPackageName)) { return true; } final TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); return TextUtils.equals(telecomManager.getSystemDialerPackage(), callingPackageName); }

Step10

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"); android.util.Log.d("wds_mo","step10-->Telecom-->UserCallIntentProcessor.sendBroadcastToReceiver()"); mContext.sendBroadcastAsUser(intent, UserHandle.OWNER); return true; }

Step11

public class PrimaryCallReceiver extends BroadcastReceiver implements TelecomSystem.Component { @Override public void onReceive(Context context, Intent intent) { synchronized (getTelecomSystem().getLock()) { android.util.Log.d("wds_mo","step11-->Telecom-->PrimaryCallReceiver.onReceive()"); getTelecomSystem().getCallIntentProcessor().processIntent(intent); } }

Step12

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 { android.util.Log.d("wds_mo","step12-->Telecom-->CallIntentProcessor.processIntent()"); processOutgoingCallIntent(mContext, mCallsManager, intent); } Trace.endSection(); }

Step13

分两部分执行
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent) {
/// M: for log parser @{ LogUtils.logIntent(intent); /// @} if (shouldPreventDuplicateVideoCall(context, callsManager, intent)) { return; } Uri handle = intent.getData(); String scheme = handle.getScheme(); String uriString = handle.getSchemeSpecificPart(); if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) { handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null); } PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra( TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); Bundle clientExtras = null; if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) { clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS); } if (clientExtras == null) { clientExtras = new Bundle(); } final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false); /// M: For dial via specified slot. @{ if (intent.hasExtra(TelecomUtils.EXTRA_SLOT)) { int slotId = intent.getIntExtra(TelecomUtils.EXTRA_SLOT, -1); phoneAccountHandle = TelecomUtils .getPhoneAccountHandleWithSlotId(context, slotId, phoneAccountHandle); } /// @} /// M: for VoLTE @{ // Here we handle all error case for VoLTE. boolean isImsCallRequest = TelecomVolteUtils.isImsCallOnlyRequest(intent); boolean isConferenceDialRequest = TelecomVolteUtils.isConferenceDialRequest(intent); if (isImsCallRequest || isConferenceDialRequest) { Log.d(TAG, "MO - VoLTE case: Ims Call / Conference Dial = %s / %s", isImsCallRequest, isConferenceDialRequest); if (!TelecomVolteUtils.isImsEnabled(context)) { Log.d(TAG, "MO - VoLTE case: Ims is disabled => Abandon"); TelecomVolteUtils.showImsDisableDialog(context); return; } List accounts = TelecomUtils.getVoltePhoneAccountHandles(); if (accounts == null || accounts.isEmpty()) { Log.d(TAG, "MO - VoLTE case: No VoLTE account => Abandon"); TelecomVolteUtils.showNoImsAccountDialog(context); return; } if (isImsCallRequest) { clientExtras.putBoolean(TelecomVolteUtils.EXTRA_VOLTE_IMS_CALL, true); } if (isConferenceDialRequest) { handle = TelecomVolteUtils.checkHandleForConferenceDial(context, handle); } } /// @} /// M: For Ip dial & suggested account & VoLTE-Ims Call & // VoLTE-Conference Dial & ViLTE-Block certain ViLTE. @{ copyExtraToBundle(intent, clientExtras); /// @} // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns android.util.Log.d("wds_mo","step13-->Telecom-->CallIntentProcessor.processOutgoingCallIntent()-- to InCallUI"); Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras); if (call != null) { /// M: ip dial. ip prefix already add, here need to change intent @{ if (call.isIpCall()) { intent.setData(call.getHandle()); } /// @} /// M: For VoLTE - Conference Dial @{ // For Con dial, skip NewOutgoingCallIntentBroadcaster. createConnection() directly. if (call.isConferenceDial()) { call.startCreateConnection(TelecomSystem.getInstance().getPhoneAccountRegistrar()); return; } /// @} // Asynchronous calls should not usually be made inside a BroadcastReceiver // because once // onReceive is complete, the BroadcastReceiver's process runs the risk of getting // killed if memory is scarce. However, this is OK here because the entire Telecom // process will be running throughout the duration of the phone call and should never // be killed. NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster( context, callsManager, call, intent, isPrivilegedDialer); final int result = broadcaster.processIntent(); final boolean success = result == DisconnectCause.NOT_DISCONNECTED; if (!success && call != null) { disconnectCallAndShowErrorDialog(context, call, result); } } }

Step14

Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras) { ... // Do not add the call if it is a potential MMI code. if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) { call.addListener(this); /// M: If no account for MMI Code, show a dialog with "No SIM or SIM error" message. @{ if (phoneAccountHandle == null) { Log.d(this, "MO - MMI with no sim: show error dialog and return"); TelecomUtils.showErrorDialog(mContext, R.string.callFailed_simError); disconnectCall(call); return null; } /// @} } else if (!mCalls.contains(call)) { // We check if mCalls already contains the call because we could potentially be reusing // a call which was previously added (See {@link #getNewOutgoingCall}). android.util.Log.d("wds_mo","step14-->Telecom-->CallsManager.startOutgoingCall()"); addCall(call); } return call; }

Step15

private void addCall(Call call) { Trace.beginSection("addCall"); Log.v(this, "addCall(%s)", call); call.addListener(this); mCalls.add(call); // TODO: Update mForegroundCall prior to invoking // onCallAdded for calls which immediately take the foreground (like the first call). android.util.Log.d("wds_mo","step15-->Telecom-->CallsManager.addCall()"); for (CallsManagerListener listener : mListeners) { if (Log.SYSTRACE_DEBUG) { Trace.beginSection(listener.getClass().toString() + " addCall"); } listener.onCallAdded(call); if (Log.SYSTRACE_DEBUG) { Trace.endSection(); } } updateCallsManagerState(); Trace.endSection(); }

Step16

@Override public void onCallAdded(Call call) { if (!isBoundToServices()) { android.util.Log.d("wds_mo","step16-->Telecom-->InCallController.onCallAdded()"); bindToServices(call); } else { adjustServiceBindingsForEmergency(); Log.i(this, "onCallAdded: %s", call); // Track the call if we don't already know about it. addCall(call); for (Map.Entry entry : mInCallServices.entrySet()) { ComponentName componentName = entry.getKey(); IInCallService inCallService = entry.getValue(); ParcelableCall parcelableCall = toParcelableCall(call, true /* includeVideoProvider */); try { inCallService.addCall(parcelableCall); } catch (RemoteException ignored) { } } } }

Step17

private void bindToServices(Call call) { PackageManager packageManager = mContext.getPackageManager(); Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE); List inCallControlServices = new ArrayList<>(); ComponentName inCallUIService = null; .... .... if (inCallUIService != null) { // skip default dialer if we have an emergency call or if it failed binding. android.util.Log.d("wds_mo","step17-->Telecom-->InCallController.bindToServices()"); if (mCallsManager.hasEmergencyCall()) { Log.i(this, "Skipping default-dialer because of emergency call"); inCallUIService = null; } else if (!bindToInCallService(inCallUIService, call, "def-dialer")) { Log.event(call, Log.Events.ERROR_LOG, "InCallService UI failed binding: " + inCallUIService); inCallUIService = null; } } ...... }

Step18

private boolean bindToInCallService(ComponentName componentName, Call call, String tag) { if (mInCallServices.containsKey(componentName)) { Log.i(this, "An InCallService already exists: %s", componentName); return true; } if (mServiceConnections.containsKey(componentName)) { Log.w(this, "The service is already bound for this component %s", componentName); return true; } Intent intent = new Intent(InCallService.SERVICE_INTERFACE); intent.setComponent(componentName); if (call != null && !call.isIncoming()){ intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, call.getIntentExtras()); intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, call.getTargetPhoneAccount()); } Log.i(this, "Attempting to bind to [%s] InCall %s, with %s", tag, componentName, intent); InCallServiceConnection inCallServiceConnection = new InCallServiceConnection(); android.util.Log.d("wds_mo","step18-->Telecom-->InCallController.bindToInCallService()"); if (mContext.bindServiceAsUser(intent, inCallServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.CURRENT)) { mServiceConnections.put(componentName, inCallServiceConnection); /// M: Register voice recording listener @{ PhoneRecorderHandler.getInstance().setListener(mRecorderListener); /// @} return true; } return false; }

package/apps/InCallUI

Step19

@Override public IBinder onBind(Intent intent) { Log.d(this, "onBind"); final Context context = getApplicationContext(); /// M: [plugin]ensure a context is valid. ExtensionManager.registerApplicationContext(context); final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context); android.util.Log.d("wds_mo","step19-->InCallUI-->InCallServiceImpl.onBind()"); InCallPresenter.getInstance().setUp( getApplicationContext(), CallList.getInstance(), AudioModeProvider.getInstance(), new StatusBarNotifier(context, contactInfoCache), contactInfoCache, new ProximitySensor(context, AudioModeProvider.getInstance()) ); InCallPresenter.getInstance().onServiceBind(); InCallPresenter.getInstance().maybeStartRevealAnimation(intent); TelecomAdapter.getInstance().setInCallService(this); return super.onBind(intent); }

Step20

public void setUp(Context context, CallList callList, AudioModeProvider audioModeProvider, StatusBarNotifier statusBarNotifier, ContactInfoCache contactInfoCache, ProximitySensor proximitySensor) { android.util.Log.d("wds_mo","step20-->InCallUI-->InCallPresenter.setUp()"); if (mServiceConnected) { Log.i(this, "New service connection replacing existing one."); // retain the current resources, no need to create new ones. Preconditions.checkState(context == mContext); Preconditions.checkState(callList == mCallList); Preconditions.checkState(audioModeProvider == mAudioModeProvider); return; } Preconditions.checkNotNull(context); mContext = context; mContactInfoCache = contactInfoCache; /// M: for ALPS01328763 @{ // remove the original one before add new listener if (mStatusBarNotifier != null) { removeListener(mStatusBarNotifier); removeIncomingCallListener(mStatusBarNotifier); mStatusBarNotifier.tearDown(); } /// @} mStatusBarNotifier = statusBarNotifier; addListener(mStatusBarNotifier); /// M: ALPS01843428 @{ // Passing incoming event to StatusBarNotifier for updating the notification. addIncomingCallListener(mStatusBarNotifier); /// @} mAudioModeProvider = audioModeProvider; /// M: for ALPS01328763 @{ // remove the original one before add new listener if (mProximitySensor != null) { removeListener(mProximitySensor); //M: fix ALPS02535607 removeDetailsListener(mProximitySensor); } /// @} mProximitySensor = proximitySensor; addListener(mProximitySensor); //M: fix ALPS02535607,add onDetail change listener for ProximitySensor addDetailsListener(mProximitySensor); addIncomingCallListener(mAnswerPresenter); addInCallUiListener(mAnswerPresenter); mCallList = callList; /// M: add for phone recording. mRecordingState = PhoneRecorderUtils.RecorderState.IDLE_STATE; // This only gets called by the service so this is okay. mServiceConnected = true; ///M: WFC @{ if (ImsManager.isWfcEnabledByPlatform(mContext)) { mRoveOutReceiver = new InCallUiWfcUtils.RoveOutReceiver(mContext); mRoveOutReceiver.register(mContext); } /// @} // The final thing we do in this set up is add ourselves as a listener to CallList. This // will kick off an update and the whole process can start. mCallList.addListener(this); VideoPauseController.getInstance().setUp(this); VideoSessionController.getInstance().setUp(this); /// M: [AutoAnswer]for Engineer Mode @{ mAutoAnswer = new AutoAnswerHelper(mContext); addIncomingCallListener(mAutoAnswer); /// @} Log.d(this, "Finished InCallPresenter.setUp"); }

Step21

public void maybeStartRevealAnimation(Intent intent) { if (intent == null || mInCallActivity != null) { return; } final Bundle extras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS); if (extras == null) { // Incoming call, just show the in-call UI directly. return; } if (extras.containsKey(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS)) { // Account selection dialog will show up so don't show the animation. return; } final PhoneAccountHandle accountHandle = intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); final Point touchPoint = extras.getParcelable(TouchPointManager.TOUCH_POINT); InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(true, accountHandle); final Intent incallIntent = getInCallIntent(false, true); incallIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint); android.util.Log.d("wds_mo","step21-->InCallUI-->InCallPresenter.maybeStartRevealAnimation()"); mContext.startActivity(incallIntent); }

Step22

@Override protected void onCreate(Bundle icicle) { Log.d(this, "onCreate()... this = " + this); android.util.Log.d("wds_mo","step22-->InCallUI-->startActivity-->InCallActivity.onCreate() "); super.onCreate(icicle); ...... }

package/services/Telecomm

Step23

public final class InCallController extends CallsManagerListenerBase { /** * Used to bind to the in-call app and triggers the start of communication between * this class and in-call app. */ private class InCallServiceConnection implements ServiceConnection { /** {@inheritDoc} */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(this, "onServiceConnected: %s", name); android.util.Log.d("wds_mo","step23-->Telecom-->InCallController.InCallServiceConnection.onServiceConnected()"); onConnected(name, service); } /** {@inheritDoc} */ @Override public void onServiceDisconnected(ComponentName name) { Log.d(this, "onDisconnected: %s", name); onDisconnected(name); } }

Step24

这里分两部分,先初始化InCallAdapter,后执行addCall
private void onConnected(ComponentName componentName, IBinder service) { Trace.beginSection("onConnected: " + componentName); Log.i(this, "onConnected to %s", componentName); IInCallService inCallService = IInCallService.Stub.asInterface(service); mInCallServices.put(componentName, inCallService); try { android.util.Log.d("wds_mo","step24-->Telecom-->InCallController.onConnected()"); inCallService.setInCallAdapter( new InCallAdapter( mCallsManager, mCallIdMapper, mLock)); } catch (RemoteException e) { Log.e(this, e, "Failed to set the in-call adapter."); Trace.endSection(); onInCallServiceFailure(componentName, "setInCallAdapter"); return; } // Upon successful connection, send the state of the world to the service. Collection calls = mCallsManager.getCalls(); if (!calls.isEmpty()) { Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(), componentName); for (Call call : calls) { try { // Track the call if we don't already know about it. addCall(call); inCallService.addCall(toParcelableCall(call, true /* includeVideoProvider */)); } catch (RemoteException ignored) { } } onCallAudioStateChanged( null, mCallsManager.getAudioState()); onCanAddCallChanged(mCallsManager.canAddCall()); } else { unbindFromServices(); } Trace.endSection(); }

Step25&27

framewrok/base/telecomm

先后执行初始化,后使用
/** Manages the binder calls so that the implementor does not need to deal with it. */ private final class InCallServiceBinder extends IInCallService.Stub { @Override public void setInCallAdapter(IInCallAdapter inCallAdapter) { android.util.Log.d("wds_mo","step25-->framework/base/Telecom-->InCallService.InCallServiceBinder.setInCallAdapter()"); mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget(); } @Override public void addCall(ParcelableCall call) { android.util.Log.d("wds_mo","step27-->framework/base/Telecom-->InCallService.InCallServiceBinder.addCall()"); mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget(); } @Override public void updateCall(ParcelableCall call) { android.util.Log.d("wds_mo","step70-->framework/base/Telecom-->InCallService.InCallServiceBinder.updateCall()"); mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget(); } @Override public void setPostDial(String callId, String remaining) { // TODO: Unused } .............

Step26&28 需要先初始化Phone才能执行addCall

@Override public void handleMessage(Message msg) { /// M: [log optimize]for performance debugging. mMessageAnalyzer.onStartHandleMessage(msg); if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) { /// M: [log optimize]for performance debugging. mMessageAnalyzer.onMessageHandled(msg); return; } SomeArgs args; switch (msg.what) { case MSG_SET_IN_CALL_ADAPTER: android.util.Log.d("wds_mo","step26-->framework/base/Telecom-->InCallService.handleMessage_MSG_SET_IN_CALL_ADAPTER"); mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj)); mPhone.addListener(mPhoneListener); onPhoneCreated(mPhone); break; case MSG_ADD_CALL: android.util.Log.d("wds_mo","step28-->framework/base/Telecom-->InCallService.handleMessage_MSG_ADD_CALL"); mPhone.internalAddCall((ParcelableCall) msg.obj); break;

Step29

final void internalAddCall(ParcelableCall parcelableCall) { Call call = new Call(this, parcelableCall.getId(), mInCallAdapter, parcelableCall.getState()); mCallByTelecomCallId.put(parcelableCall.getId(), call); mCalls.add(call); checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); android.util.Log.d("wds_mo","step29-->framework/base/Telecom-->InCallService.internalAddCall()"); fireCallAdded(call); }

Step30

private void fireCallAdded(Call call) { android.util.Log.d("wds_mo","step30-->framework/base/Telecom-->Phone.fireCallAdded()"); for (Listener listener : mListeners) { listener.onCallAdded(this, call); } }

Step32

package/apps/InCallUI

public void onCallAdded(android.telecom.Call telecommCall) { Trace.beginSection("onCallAdded"); Call call = new Call(telecommCall); Log.d(this, "onCallAdded: callState=" + call.getState()); if (call.getState() == Call.State.INCOMING || call.getState() == Call.State.CALL_WAITING) { onIncoming(call, call.getCannedSmsResponses()); } else { android.util.Log.d("wds_mo","step32-->InCallUI-->CallList.onCallAdded() "); onUpdate(call); } /// M: [log optimize] @{ if (call.isConferenceCall()) { Log.notify(call, Log.CcNotifyAction.CONFERENCED, "ConfCreated"); } /// @} Trace.endSection(); }

Step33

public void onUpdate(Call call) { Trace.beginSection("onUpdate"); onUpdateCall(call); android.util.Log.d("wds_mo","step33-->InCallUI-->CallList.onUpdate()"); notifyGenericListeners(); Trace.endSection(); }

Step34

private void notifyGenericListeners() { android.util.Log.d("wds_mo","step34-->InCallUI-->CallList.notifyGenericListeners()"); for (Listener listener : mListeners) { listener.onCallListChange(this); } }

Step35

@Override public void onCallListChange(CallList callList) { android.util.Log.d("wds_mo","step35-->InCallUI-->InCallPresenter.onCallListChange()"); if (mInCallActivity != null && mInCallActivity.getCallCardFragment() != null && mInCallActivity.getCallCardFragment().isAnimating()) { /// M: add for monitor call card animation process Log.d(this, "[onCallListChange] Call Card view is animating!"); mAwaitingCallListUpdate = true; return; } if (callList == null) { return; } .................. }

Step13

package/services/Telecomm

Step13继续执行
static void processOutgoingCallIntent( ...... NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster( context, callsManager, call, intent, isPrivilegedDialer); final int result = broadcaster.processIntent(); final boolean success = result == DisconnectCause.NOT_DISCONNECTED; if (!success && call != null) { disconnectCallAndShowErrorDialog(context, call, result); } } }

Step36

private class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ........... Uri originalUri = mIntent.getData(); if (originalUri.getSchemeSpecificPart().equals(resultNumber)) { Log.v(this, "Call number unmodified after new outgoing call intent broadcast."); } else { Log.v(this, "Retrieved modified handle after outgoing call intent broadcast: " + "Original: %s, Modified: %s", Log.pii(originalUri), Log.pii(resultHandleUri)); } GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri); android.util.Log.d("wds_mo","step36-->Telecom-->NewOutgoingCallIntentBroadcaster.onReceive()"); mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo, mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false), mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, VideoProfile.STATE_AUDIO_ONLY)); Trace.endSection(); } } }

Step37

void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn, int videoState) { ........... /// M: ALPS02035599 Since NewOutgoingCallIntentBroadcaster and the SELECT_PHONE_ACCOUNT @{ // sequence run in parallel, this call may be already disconnected in the select phone // account sequence. if (call.getState() == CallState.DISCONNECTED) { return; } /// @} if (call.getTargetPhoneAccount() != null || isEmergencyCall) { // If the account has been set, proceed to place the outgoing call. // Otherwise the connection will be initiated when the account is set by the user. android.util.Log.d("wds_mo","step37-->Telecom-->CallsManager.placeOutgoingCall()"); call.startCreateConnection(mPhoneAccountRegistrar); }

Step38

void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) { /// M: Workaround for ALPS01845919. @{ // Maybe broadcast will be delayed, the phoneAccount selected earlier than received broadcast, // and the call will be place twice, need cancel the duplicate one. if (mCreateConnectionProcessor != null) { Log.v(this, "Canceling this duplicate call."); return; } /// @} Preconditions.checkState(mCreateConnectionProcessor == null); mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext); android.util.Log.d("wds_mo","step38-->Telecom-->Call.startCreateConnection()"); mCreateConnectionProcessor.process(); }

Step39

void process() { Log.v(this, "process"); clearTimeout(); mAttemptRecords = new ArrayList<>(); if (mCall.getTargetPhoneAccount() != null) { mAttemptRecords.add(new CallAttemptRecord( mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount())); } adjustAttemptsForConnectionManager(); adjustAttemptsForEmergency(); mAttemptRecordIterator = mAttemptRecords.iterator(); android.util.Log.d("wds_mo","step39-->Telecom-->CreateConnectionProcessor.process()"); attemptNextPhoneAccount(); }

Step40

private void attemptNextPhoneAccount() { .......... if (mResponse != null && attempt != null) { Log.i(this, "Trying attempt %s", attempt); PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount; ConnectionServiceWrapper service = mRepository.getService( phoneAccount.getComponentName(), phoneAccount.getUserHandle()); if (service == null) { Log.i(this, "Found no connection service for attempt %s", attempt); attemptNextPhoneAccount(); } else { mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount); /// M: Valid phone account for ECC may have been set.@{ if (mCall.getTargetPhoneAccount() == null) { mCall.setTargetPhoneAccount(attempt.targetPhoneAccount); } /// @} mCall.setConnectionService(service); setTimeoutIfNeeded(service, attempt); android.util.Log.d("wds_mo","step40-->Telecom-->CreateConnectionProcessor.attemptNextPhoneAccount()"); service.createConnection(mCall, new Response(service)); } } else { Log.v(this, "attemptNextPhoneAccount, no more accounts, failing"); if (mResponse != null) { clearTimeout(); mResponse.handleCreateConnectionFailure(mLastErrorDisconnectCause != null ? mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR)); mResponse = null; mCall.clearConnectionService(); } } }

Step41

void createConnection(final Call call, final CreateConnectionResponse response) { logOutgoing("createConnection(%s) via %s.", call, getComponentName()); BindCallback callback = new BindCallback() { @Override public void onSuccess() { ..... android.util.Log.d("wds_mo","step41-->Telecom-->ConnectionServiceWrapper.createConnection()"); mBinder.bind(callback, call); }

Step42

void bind(BindCallback callback, Call call) { Log.d(ServiceBinder.this, "bind()"); // Reset any abort request if we're asked to bind again. clearAbort(); if (!mCallbacks.isEmpty()) { // Binding already in progress, append to the list of callbacks and bail out. mCallbacks.add(callback); return; } mCallbacks.add(callback); if (mServiceConnection == null) { Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName); ServiceConnection connection = new ServiceBinderConnection(call); Log.event(call, Log.Events.BIND_CS, mComponentName); final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; final boolean isBound; if (mUserHandle != null) { android.util.Log.d("wds_mo","step42-->Telecom-->Binder2.bind(()"); isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags, mUserHandle); } else { isBound = mContext.bindService(serviceIntent, connection, bindingFlags); } if (!isBound) { handleFailedConnection(); return; } } else { Log.d(ServiceBinder.this, "Service is already bound."); Preconditions.checkNotNull(mBinder); handleSuccessfulConnection(); } } }

Step43

private final class ServiceBinderConnection implements ServiceConnection { ........ @Override public void onServiceConnected(ComponentName componentName, IBinder binder) { synchronized (mLock) { Log.i(this, "Service bound %s", componentName); Log.event(mCall, Log.Events.CS_BOUND, componentName); mCall = null; // Unbind request was queued so unbind immediately. if (mIsBindingAborted) { clearAbort(); logServiceDisconnected("onServiceConnected"); mContext.unbindService(this); handleFailedConnection(); return; } mServiceConnection = this; android.util.Log.d("wds_mo","step43-->Telecom-->Binder2.onServiceConnected()"); setBinder(binder); handleSuccessfulConnection(); } } ..........

Step44

private void setBinder(IBinder binder) { if (mBinder != binder) { mBinder = binder; android.util.Log.d("wds_mo","step44-->Telecom-->Binder2.setBinder()"); setServiceInterface(binder); if (binder == null) { for (Listener l : mListeners) { l.onUnbind(this); } } } }

Step45

@Override protected void setServiceInterface(IBinder binder) { if (binder == null) { // We have lost our service connection. Notify the world that this service is done. // We must notify the adapter before CallsManager. The adapter will force any pending // outgoing calls to try the next service. This needs to happen before CallsManager // tries to clean up any calls still associated with this service. handleConnectionServiceDeath(); mCallsManager.handleConnectionServiceDeath(this); mServiceInterface = null; } else { android.util.Log.d("wds_mo","step45-->Telecom-->ConnectionServiceWrapper.setServiceInterface()"); mServiceInterface = IConnectionService.Stub.asInterface(binder); addConnectionServiceAdapter(mAdapter); } }

Step46

private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { if (isServiceValid("addConnectionServiceAdapter")) { try { logOutgoing("addConnectionServiceAdapter %s", adapter); android.util.Log.d("wds_mo","step46-->Telecom-->ConnectionServiceWrapper.addConnectionServiceAdapter()"); mServiceInterface.addConnectionServiceAdapter(adapter); } catch (RemoteException e) { } } }

Step47

返回到43步继续执行,因为4647是并发执行,这里按照Log的顺序来,46执行到48 ,47执行到50,
private void handleSuccessfulConnection() { android.util.Log.d("wds_mo","step47-->Telecom-->ServiceBinder.handleSuccessfulConnection()"); for (BindCallback callback : mCallbacks) { callback.onSuccess(); } mCallbacks.clear(); }

Step50

返回到41,如果47步callback.onSuccess() 继续执行
void createConnection(final Call call, final CreateConnectionResponse response) { logOutgoing("createConnection(%s) via %s.", call, getComponentName()); BindCallback callback = new BindCallback() { @Override public void onSuccess() { String callId = mCallIdMapper.getCallId(call); /// M: In some complex scenario, before binding success, the call has been // disconnected. So here pass a null callId to telephony will cause JE. if (callId == null) { Log.w(this, "createConnection stop, callId is null"); return; } mPendingResponses.put(callId, response); GatewayInfo gatewayInfo = call.getGatewayInfo(); Bundle extras = call.getIntentExtras(); if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && gatewayInfo.getOriginalAddress() != null) { extras = (Bundle) extras.clone(); extras.putString( TelecomManager.GATEWAY_PROVIDER_PACKAGE, gatewayInfo.getGatewayProviderPackageName()); extras.putParcelable( TelecomManager.GATEWAY_ORIGINAL_ADDRESS, gatewayInfo.getOriginalAddress()); } Log.event(call, Log.Events.START_CONNECTION, Log.piiHandle(call.getHandle())); try { /// M: For VoLTE @{ boolean isConferenceDial = call.isConferenceDial(); if (isConferenceDial) { logOutgoing("createConference(%s) via %s.", call, getComponentName()); mServiceInterface.createConference( call.getConnectionManagerPhoneAccount(), callId, new ConnectionRequest( call.getTargetPhoneAccount(), call.getHandle(), extras, call.getVideoState()), call.getConferenceParticipants(), call.isIncoming()); } else { android.util.Log.d("wds_mo","step50-->Telecom-->ConnectionServiceWrapper.createConnection().onSuccess"); mServiceInterface.createConnection( call.getConnectionManagerPhoneAccount(), callId, new ConnectionRequest( call.getTargetPhoneAccount(), call.getHandle(), extras, call.getVideoState()), call.isIncoming(), call.isUnknown()); } /// @} .......

Step48&52

46和50 都是IConnectionService.aidl 客服端发送请求到服务端 mServiceInterface
private final IBinder mBinder = new IConnectionService.Stub() { @Override public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { android.util.Log.d("wds_mo","step48-->framework/base/Telecom-->ConnectionService.IBinder.addConnectionServiceAdapter()"); mHandler.obtainMessage(MSG_ADD_CONNECTION_SERVICE_ADAPTER, adapter).sendToTarget(); } public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) { mHandler.obtainMessage(MSG_REMOVE_CONNECTION_SERVICE_ADAPTER, adapter).sendToTarget(); } @Override public void createConnection( PhoneAccountHandle connectionManagerPhoneAccount, String id, ConnectionRequest request, boolean isIncoming, boolean isUnknown) { SomeArgs args = SomeArgs.obtain(); args.arg1 = connectionManagerPhoneAccount; args.arg2 = id; args.arg3 = request; args.argi1 = isIncoming ? 1 : 0; args.argi2 = isUnknown ? 1 : 0; android.util.Log.d("wds_mo","step52-->framework/base/Telecom-->ConnectionService.IBinder.createConnection()"); mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget(); } .....................

Step49&53

private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_ADD_CONNECTION_SERVICE_ADAPTER: android.util.Log.d("wds_mo","step49-->framework/base/Telecom-->handleMessage.MSG_ADD_CONNECTION_SERVICE_ADAPTER"); mAdapter.addAdapter((IConnectionServiceAdapter) msg.obj); onAdapterAttached(); break; case MSG_REMOVE_CONNECTION_SERVICE_ADAPTER: mAdapter.removeAdapter((IConnectionServiceAdapter) msg.obj); break; case MSG_CREATE_CONNECTION: { SomeArgs args = (SomeArgs) msg.obj; try { final PhoneAccountHandle connectionManagerPhoneAccount = (PhoneAccountHandle) args.arg1; final String id = (String) args.arg2; final ConnectionRequest request = (ConnectionRequest) args.arg3; final boolean isIncoming = args.argi1 == 1; final boolean isUnknown = args.argi2 == 1; if (!mAreAccountsInitialized) { Log.d(this, "Enqueueing pre-init request %s", id); mPreInitializationConnectionRequests.add(new Runnable() { @Override public void run() { android.util.Log.d("wds_mo","step53-->framework/base/Telecom-->handleMessage.MSG_CREATE_CONNECTION"); createConnection( connectionManagerPhoneAccount, id, request, isIncoming, isUnknown); } }); } else { createConnection( connectionManagerPhoneAccount, id, request, isIncoming, isUnknown); } } finally { args.recycle(); } break; } .............

Step52

继续刚才49步的执行
void addAdapter(IConnectionServiceAdapter adapter) { android.util.Log.d("wds_mo","step51-->framework/base/Telecom-->ConnectionServiceAdapter.addAdapter()"); for (IConnectionServiceAdapter it : mAdapters) { if (it.asBinder() == adapter.asBinder()) { Log.w(this, "Ignoring duplicate adapter addition."); return; } } if (mAdapters.add(adapter)) { try { adapter.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { mAdapters.remove(adapter); } } }

Step54

继续执行53步
private void createConnection(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
Log.d(this, “createConnection, callManagerAccount: %s, callId: %s, request: %s, ” +
“isIncoming: %b, isUnknown: %b”, callManagerAccount, callId, request, isIncoming,
isUnknown);
/// M: ALPS02136977. Prints debug messages for MO. @{ if (!isIncoming) { String callNumber = null; if (request != null && request.getAddress() != null) { callNumber = request.getAddress().getSchemeSpecificPart(); } FormattedLog formattedLog = new FormattedLog.Builder() .setCategory("CC") .setServiceName(getConnectionServiceName()) .setOpType(FormattedLog.OpType.OPERATION) .setActionName("Dial") .setCallNumber(callNumber) .setCallId("") .buildDebugMsg(); if (formattedLog != null) { Log.d(this, formattedLog.toString()); } } /// @} android.util.Log.d("wds_mo","step54-->framework/base/Telecom-->Connection.createConnection()"); Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request) : isIncoming ? onCreateIncomingConnection(callManagerAccount, request) : onCreateOutgoingConnection(callManagerAccount, request); Log.d(this, "createConnection, connection: %s", connection); if (connection == null) { connection = Connection.createFailedConnection( new DisconnectCause(DisconnectCause.ERROR)); } if (connection.getState() != Connection.STATE_DISCONNECTED) { addConnection(callId, connection); } ........

pacakge/services/Telephony

Step55

@Override public Connection onCreateOutgoingConnection( PhoneAccountHandle connectionManagerPhoneAccount, final ConnectionRequest request) { ........... } else { android.util.Log.d("wds_mo","step55-->Telephony-->TelephonyConnectionService.onCreateOutgoingConnection()"); placeOutgoingConnection(connection, phone, request); } return connection; }

Step56

private void placeOutgoingConnection( TelephonyConnection connection, Phone phone, ConnectionRequest request) { String number = connection.getAddress().getSchemeSpecificPart(); boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(this, number); /// M: CC036: [ALPS01794357] Set PhoneAccountHandle for ECC @{ if (isEmergencyNumber) { final PhoneAccountHandle phoneAccountHandle; String phoneIccId = phone.getIccSerialNumber(); int slotId = SubscriptionController.getInstance().getSlotId(phone.getSubId()); if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { phoneIccId = !TextUtils.isEmpty(phoneIccId) ? phoneIccId : TelephonyManagerEx.getDefault().getSimSerialNumber(slotId); } if (TextUtils.isEmpty(phoneIccId)) { // If No SIM is inserted, the corresponding IccId will be null, // take phoneId as PhoneAccountHandle::mId which is IccId originally phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle( Integer.toString(phone.getPhoneId())); } else { phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(phoneIccId); } Log.d(this, "placeOutgoingConnection, set back account mId: %s, iccId: %s", phoneAccountHandle.getId(), phoneIccId); connection.setAccountHandle(phoneAccountHandle); } /// @} com.android.internal.telephony.Connection originalConnection; try { android.util.Log.d("wds_mo","step56-->Telephony-->TelephonyConnectionService.placeOutgoingConnection()"); originalConnection = phone.dial(number, null, request.getVideoState(), request.getExtras()); } catch (CallStateException e) { ....... }

framework/opt/telephony

Step57

@Override public Connection dial (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras) throws CallStateException { boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString); ImsPhone imsPhone = mImsPhone; ....... if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) { throw new CallStateException("cannot dial in current state"); } if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Trying (non-IMS) CS call"); /// M: For 3G VT only @{ //return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras); Rlog.d("wds_mo","step57-->framework/opt/telephony-->GSMPhone.dial()B"); return dialInternal(dialString, null, videoState, intentExtras); /// @} }

Step58

@Override protected Connection dialInternal (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras) throws CallStateException { /// M: Ignore stripping for VoLTE SIP uri. @{ String newDialString = dialString; if (!PhoneNumberUtils.isUriNumber(dialString)) { // Need to make sure dialString gets parsed properly newDialString = PhoneNumberUtils.stripSeparators(dialString); } /// @} // handle in-call MMI first if applicable if (handleInCallMmiCommands(newDialString)) { return null; } // Only look at the Network portion for mmi String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); /* M: SS part */ Rlog.d(LOG_TAG, "network portion:" + networkPortion); /* M: SS part end */ GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get()); if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "dialing w/ mmi '" + mmi + "'..."); if (mmi == null) { /// M: For 3G VT only @{ //return mCT.dial(newDialString, uusInfo, intentExtras); if (videoState == VideoProfile.STATE_AUDIO_ONLY) { Rlog.d("wds_mo","step58-->framework/opt/telephony-->GSMPhone.dialInternal()A"); return mCT.dial(newDialString, uusInfo, intentExtras); } else { if (!is3GVTEnabled()) { throw new CallStateException("cannot vtDial for non-3GVT-capable device"); } return mCT.vtDial(newDialString, uusInfo, intentExtras); } /// @} } else if (mmi.isTemporaryModeCLIR()) { /// M: For 3G VT only @{ //return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras); if (videoState == VideoProfile.STATE_AUDIO_ONLY) { return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras); } else { if (!is3GVTEnabled()) { throw new CallStateException("cannot vtDial for non-3GVT-capable device"); } return mCT.vtDial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras); } /// @} } else { /* M: SS part */ Rlog.d(LOG_TAG, "[dial]mPendingMMIs.add(mmi) + " + mmi); /* M: SS part end */ mPendingMMIs.add(mmi); mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.processCode(); // FIXME should this return null or something else? return null; } }

Step59

synchronized Connection dial (String dialString, int clirMode, UUSInfo uusInfo, Bundl