@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);
}
}
/// 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);
}
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
}
.............
@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();
}
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);
}
}