Telephony框架学习(一)Android6.0MO流程
相关模块
\packages\apps\Dialer
\packages\apps\InCallUI
\packages\services\Telecomm
\packages\services\Telephony
\frameworks\base\telecomm
\frameworks\base\telephony
\frameworks\opt\telephony
\frameworks\opt\net\ims
\vendor\mediatek\proprietary\packages\services\Ims
时序图
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<PhoneAccountHandle> 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<ComponentName, IInCallService> 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<ComponentName> 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<Call> 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, Bundle intentExtras)
throws CallStateException {
// note that this triggers call state changed notif
clearDisconnected();
if (!canDial()) {
throw new CallStateException("cannot dial in current state");
}
String origNumber = dialString;
dialString = convertNumberIfNecessary(mPhone, dialString);
// The new call must be assigned to the foreground call.
// That call must be idle, so place anything that's
// there on hold
if (mForegroundCall.getState() == GsmCall.State.ACTIVE) {
// this will probably be done by the radio anyway
// but the dial might fail before this happens
// and we need to make sure the foreground call is clear
// for the newly dialed connection
/// M: CC015: CRSS special handling @{
mWaitingForHoldRequest.set();
/// @}
switchWaitingOrHoldingAndActive();
// This is a hack to delay DIAL so that it is sent out to RIL only after
// EVENT_SWITCH_RESULT is received. We've seen failures when adding a new call to
// multi-way conference calls due to DIAL being sent out before SWITCH is processed
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// do nothing
}
// Fake local state so that
// a) foregroundCall is empty for the newly dialed connection
// b) hasNonHangupStateChanged remains false in the
// next poll, so that we don't clear a failed dialing call
fakeHoldForegroundBeforeDial();
}
if (mForegroundCall.getState() != GsmCall.State.IDLE) {
//we should have failed in !canDial() above before we get here
throw new CallStateException("cannot dial in current state");
}
mPendingMO = new GsmConnection(mPhone.getContext(), checkForTestEmergencyNumber(dialString),
this, mForegroundCall);
mHangupPendingMO = false;
if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0
|| mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0
) {
// Phone number is invalid
mPendingMO.mCause = DisconnectCause.INVALID_NUMBER;
/// M: CC015: CRSS special handling @{
mWaitingForHoldRequest.reset();
/// @}
// handlePollCalls() will notice this call not present
// and will mark it as dropped.
pollCallsWhenSafe();
} else {
// Always unmute when initiating a new call
setMute(false);
/// M: CC015: CRSS special handling @{
if (!mWaitingForHoldRequest.isWaiting()) {
/// M: CC010: Add RIL interface @{
/// M: ECC Retry @{
if (PhoneNumberUtils.isEmergencyNumber(mPhone.getSubId(), dialString)
/// @}
&& !PhoneNumberUtils.isSpecialEmergencyNumber(dialString)) {
int serviceCategory = PhoneNumberUtils.getServiceCategoryFromEccBySubId(
dialString, mPhone.getSubId());
mCi.setEccServiceCategory(serviceCategory);
mCi.emergencyDial(mPendingMO.getAddress(), clirMode, uusInfo,
obtainCompleteMessage(EVENT_DIAL_CALL_RESULT));
/// @}
} else {
Rlog.d("wds_mo","step59-->framework/opt/telephony-->GsmCallTracker.dial()");
mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo,
obtainCompleteMessage(EVENT_DIAL_CALL_RESULT));
}
} else {
mWaitingForHoldRequest.set(mPendingMO.getAddress(), clirMode, uusInfo);
}
/// @}
}
if (mNumberConverted) {
mPendingMO.setConverted(origNumber);
mNumberConverted = false;
}
updatePhoneState();
mPhone.notifyPreciseCallStateChanged();
return mPendingMO;
}
Step60
@Override
public void
dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
Rlog.d("wds_mo","step60-->framework/opt/telephony-->RIL.dial() ");
if (!PhoneNumberUtils.isUriNumber(address)) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
rr.mParcel.writeString(address);
rr.mParcel.writeInt(clirMode);
if (uusInfo == null) {
rr.mParcel.writeInt(0); // UUS information is absent
} else {
rr.mParcel.writeInt(1); // UUS information is present
rr.mParcel.writeInt(uusInfo.getType());
rr.mParcel.writeInt(uusInfo.getDcs());
rr.mParcel.writeByteArray(uusInfo.getUserData());
}
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
} else {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL_WITH_SIP_URI, result);
rr.mParcel.writeString(address);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
}
framework/base/telecomm
Step60
继续执行第54步,未执行完的
void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
android.util.Log.d("wds_mo","step60-->Telephony-->ConnectionServiceAdapter.handleCreateConnectionComplete()");
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
adapter.handleCreateConnectionComplete(id, request, connection);
} catch (RemoteException e) {
}
}
}
package/service/Telecomm
Step61
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
public void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
/// M: for log parser @{
String number = "";
String action = "";
Uri uri = connection.getHandle();
if (uri != null) {
number = uri.getSchemeSpecificPart();
}
Call call = mCallIdMapper.getCall(callId);
if (call != null) {
if (call.isIncoming()) {
action = LogUtils.NOTIFY_ACTION_CREATE_MT_SUCCESS;
} else if (!call.isUnknown()) {
action = LogUtils.NOTIFY_ACTION_CREATE_MO_SUCCESS;
}
}
LogUtils.logCcNotify(number, action, callId, connection.toString());
/// @}
logIncoming("handleCreateConnectionComplete %s", callId);
if (mCallIdMapper.isValidCallId(callId)) {
android.util.Log.d("wds_mo","step61-->Telecom-->ConnectionServiceWrapper.Adapter.handleCreateConnectionComplete()");
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
...........
Step62
private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
// TODO: Note we are not using parameter "request", which is a side effect of our tacit
// assumption that we have at most one outgoing connection attempt per ConnectionService.
// This may not continue to be the case.
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// A connection that begins in the DISCONNECTED state is an indication of
// failure to connect; we handle all failures uniformly
removeCall(callId, connection.getDisconnectCause());
} else {
// Successful connection
if (mPendingResponses.containsKey(callId)) {
String num = connection.getHandle().getSchemeSpecificPart();
/// M: add for CMCC L + C ecc retry
if (PhoneNumberUtils.isEmergencyNumber(num)) {
mPendingResponses.get(callId).
handleCreateConnectionSuccess(mCallIdMapper, connection);
} else {
android.util.Log.d("wds_mo","step62-->Telecom-->ConnectionServiceWrapper.handleCreateConnectionComplete");
mPendingResponses.remove(callId)
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
}
}
}
Step63
@Override
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
setConnectionCapabilities(connection.getConnectionCapabilities());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
setExtras(connection.getExtras());
mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
mConferenceableCalls.add(idMapper.getCall(id));
}
if (mIsUnknown) {
for (Listener l : mListeners) {
l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection.getState()));
}
} else if (mIsIncoming) {
// We do not handle incoming calls immediately when they are verified by the connection
// service. We allow the caller-info-query code to execute first so that we can read the
// direct-to-voicemail property before deciding if we want to show the incoming call to
// the user or if we want to reject the call.
mDirectToVoicemailQueryPending = true;
// Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
// showing the user the incoming call screen.
mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis(
mContext.getContentResolver()));
} else {
/// M: ALPS02568075 @{
// when perform ECC retry from dialing state
// force to set as CONNECTING this time
// in order to reset audio mode as normal in CallAudioManager.onCallStateChanged
// then Ecc is changed to dialing again, can set audio mode once time.
android.util.Log.d("wds_mo","step63-->Telecom-->Call.handleCreateConnectionSuccess()");
if (isEmergencyCall() && getState() == CallState.DIALING) {
Log.v(this, "Change ecc state as connecting");
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this, CallState.CONNECTING);
}
}
/// @}
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
getStateFromConnectionState(connection.getState()));
}
}
}
Step64
@Override
public void onSuccessfulOutgoingCall(Call call, int callState) {
Log.v(this, "onSuccessfulOutgoingCall, %s", call);
setCallState(call, callState, "successful outgoing call");
if (!mCalls.contains(call)) {
// Call was not added previously in startOutgoingCall due to it being a potential MMI
// code, so add it now.
/// M: If already exist other calls, should handle properly. @{
// original google code:
//addCall(call);
handleShouldAddOutgoingCall(call);
/// @}
} else {
// M: Temp solution for ALPS02548133.
handleCallsWhenOutgoingSuccess(call);
}
// The call's ConnectionService has been updated.
for (CallsManagerListener listener : mListeners) {
listener.onConnectionServiceChanged(call, null, call.getConnectionService());
}
//ALPS01781841, do not mark Ecc call as dialing state this time point
//Ecc call is marked as dialing state only when FWK call state event(MSG_SET_DIALING) post to ConnectionServiceWrapper.Adapter
android.util.Log.d("wds_mo","step64-->Telecom-->CallsManager.onSuccessfulOutgoingCall()");
if (!call.isEmergencyCall()) {
markCallAsDialing(call);
}
}
Step66
private void setCallState(Call call, int newState, String tag) {
if (call == null) {
return;
}
int oldState = call.getState();
Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
CallState.toString(newState), call);
if (newState != oldState) {
// Unfortunately, in the telephony world the radio is king. So if the call notifies
// us that the call is in a particular state, we allow it even if it doesn't make
// sense (e.g., STATE_ACTIVE -> STATE_RINGING).
// TODO: Consider putting a stop to the above and turning CallState
// into a well-defined state machine.
// TODO: Define expected state transitions here, and log when an
// unexpected transition occurs.
call.setState(newState, tag);
/// M: Set the voice recording capability
int capabilities = call.getConnectionCapabilities();
boolean hasRecordCap = (capabilities & Connection.CAPABILITY_VOICE_RECORD) == 0
? false : true;
boolean okToRecord = okToRecordVoice(call);
if (okToRecord && !hasRecordCap) {
call.setConnectionCapabilities(capabilities
| Connection.CAPABILITY_VOICE_RECORD);
}
if (!okToRecord && hasRecordCap) {
PhoneRecorderHandler.getInstance().stopVoiceRecordIfNecessary(call);
call.setConnectionCapabilities(capabilities
& ~Connection.CAPABILITY_VOICE_RECORD);
}
Trace.beginSection("onCallStateChanged");
// Only broadcast state change for calls that are being tracked.
android.util.Log.d("wds_mo","step66-->Telecom-->CallsManager.setCallState()");
if (mCalls.contains(call)) {
for (CallsManagerListener listener : mListeners) {
if (Log.SYSTRACE_DEBUG) {
Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
}
listener.onCallStateChanged(call, oldState, newState);
if (Log.SYSTRACE_DEBUG) {
Trace.endSection();
}
}
updateCallsManagerState();
}
/// M: MSMA call control, first call action finished. @{
handleActionProcessComplete(call);
/// @}
Trace.endSection();
}
}
Step67
@Override
public void onCallStateChanged(Call call, int oldState, int newState) {
android.util.Log.d("wds_mo","step67-->Telecom-->InCallController.onCallStateChanged()");
updateCall(call);
}
Step69
private void updateCall(Call call, boolean videoProviderChanged) {
if (!mInCallServices.isEmpty()) {
ParcelableCall parcelableCall = toParcelableCall(call,
videoProviderChanged /* includeVideoProvider */);
Log.i(this, "Sending updateCall %s ==> %s", call, parcelableCall);
List<ComponentName> componentsUpdated = new ArrayList<>();
android.util.Log.d("wds_mo","step69-->Telecom-->InCallController.updateCall()");
for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
componentsUpdated.add(componentName);
try {
inCallService.updateCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
Log.i(this, "Components updated: %s", componentsUpdated);
}
}
framework/base/Telecomm
Step70
private final class InCallServiceBinder extends IInCallService.Stub {
.......
@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();
}
.....
Step71
@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_UPDATE_CALL:
android.util.Log.d("wds_mo","step71-->framework/base/Telecom-->InCallService.handleMessage_MSG_UPDATE_CALL");
TelecomTrace.begin("InCallService_update");
mPhone.internalUpdateCall((ParcelableCall) msg.obj);
TelecomTrace.end("InCallService_update");
break;
...
Step72
final void internalUpdateCall(ParcelableCall parcelableCall) {
Call call = mCallByTelecomCallId.get(parcelableCall.getId());
if (call != null) {
checkCallTree(parcelableCall);
android.util.Log.d("wds_mo","step72-->framework/base/Telecom-->Phone.internalUpdateCall");
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
}
}
Step73
/** {@hide} */
final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
// First, we update the internal state as far as possible before firing any updates.
.........
if (stateChanged) {
android.util.Log.d("wds_mo","step73-->framework/base/Telecom-->Call.internalUpdate()");
fireStateChanged(mState);
}
.............
}
Step74
private void fireStateChanged(final int newState) {
android.util.Log.d("wds_mo","step74-->framework/base/Telecom-->Call.fireStateChanged()");
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
final Callback callback = record.getCallback();
record.getHandler().post(new Runnable() {
@Override
public void run() {
callback.onStateChanged(call, newState);
}
});
}
}
package/apps/InCallUI
Step75
private android.telecom.Call.Callback mTelecomCallCallback =
new android.telecom.Call.Callback() {
@Override
public void onStateChanged(android.telecom.Call call, int newState) {
Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " newState="
+ newState);
android.util.Log.d("wds_mo","step75-->InCallUI-->Call.mTelecomCallCallback.onStateChanged()");
InCallTrace.begin("telecomStateChanged");
update();
InCallTrace.end("telecomStateChanged");
}
.....
Step76
private void update() {
Trace.beginSection("Update");
int oldState = getState();
updateFromTelecommCall();
if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
/// M: [log optimize]
Log.notify(this, Log.CcNotifyAction.DISCONNECTED,
mDisconnectCause == null ?
"DisconnectCause: null" : mDisconnectCause.toString());
CallList.getInstance().onDisconnect(this);
} else {
android.util.Log.d("wds_mo","step76-->InCallUI-->Call.update()");
CallList.getInstance().onUpdate(this);
}
Trace.endSection();
}
之后与33步重合