Android Dialer原始碼分析之去電流程
阿新 • • 發佈:2021-01-31
技術標籤:Dialer
Android的撥號流程,從撥號盤的點選撥號按鈕開始,
DialpadFragment.java
@Override
public void onClick(View view) {
int resId = view.getId();
if (resId == R.id.dialpad_floating_action_button) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
handleDialButtonPressed() ;
}
....
}
private void handleDialButtonPressed() {
...
final String number = digits.getText().toString();
...
PreCall.start(getContext(), new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD));
...
}
static void start(Context context, CallIntentBuilder builder) {
DialerUtils.startActivityWithErrorToast(context, getIntent(context, builder));
}
public static void startActivityWithErrorToast(Context context, Intent intent) {
...
startActivityWithErrorToast(context, intent, R.string.activity_not_available);
}
public static void startActivityWithErrorToast (
final Context context, final Intent intent, int msgId) {
try {
if ((Intent.ACTION_CALL.equals(intent.getAction()))) {
Point touchPoint = TouchPointManager.getInstance().getPoint();
if (touchPoint.x != 0 || touchPoint.y != 0) {
Bundle extras;
if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
extras = intent.getParcelableExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
} else {
extras = new Bundle();
}
extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint);
intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
}
...
placeCallOrMakeToast(context, intent);
...
} else {
context.startActivity(intent);
}
} catch (ActivityNotFoundException e) {
Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
}
}
private static void placeCallOrMakeToast(Context context, Intent intent) {
ExtensionManager.getDialerOthersExtension().setPrecallInfo(context, intent);
final boolean hasCallPermission = TelecomUtil.placeCall(context, intent);
if (!hasCallPermission) {
Toast.makeText(context, "Cannot place call without Phone permission", Toast.LENGTH_SHORT)
.show();
}
}
TelecomUtil.java
public static boolean placeCall(Context context, Intent intent) {
if (hasCallPhonePermission(context)) {
getTelecomManager(context).placeCall(intent.getData(), intent.getExtras());
return true;
}
return false;
}
TelecomManager.java
public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
...
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}
TelecomServiceImpl.java
@Override
public void placeCall(Uri handle, Bundle extras, String callingPackage,
String callingFeatureId) {
...
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, isSelfManaged ||
(hasCallAppOp && hasCallPermission),
true /* isLocalInvocation */);
...
}
UserCallIntentProcessor.java
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency, boolean isLocalInvocation) {
...
String action = intent.getAction();
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
isLocalInvocation);
}
...
}
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency, boolean isLocalInvocation) {
...
sendIntentToDestination(intent, isLocalInvocation, callingPackageName);
}
private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation,
String callingPackage) {
...
TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
tm.handleCallIntent(intent, callingPackage);
...
}
public void handleCallIntent(Intent intent, String callingPackageProxy) {
...
getTelecomService().handleCallIntent(intent, callingPackageProxy);
...
}
TelecomServiceImpl.java
@Override
public void handleCallIntent(Intent intent, String callingPackage) {
...
mCallIntentProcessorAdapter.processOutgoingCallIntent(mContext,
mCallsManager, intent, callingPackage);
...
}
@Override
public void processOutgoingCallIntent(Context context, CallsManager callsManager,
Intent intent, String callingPackage) {
CallIntentProcessor.processOutgoingCallIntent(context, callsManager, intent,
callingPackage, mDefaultDialerCache);
}
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent,
String callingPackage,
DefaultDialerCache defaultDialerCache) {
...
CompletableFuture<Call> callFuture = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
intent, callingPackage);
...
}
CallsManager.java
public CompletableFuture<Call> startOutgoingCall(Uri handle,
PhoneAccountHandle requestedAccountHandle,
Bundle extras, UserHandle initiatingUser, Intent originalIntent,
String callingPackage) {
...
return startOutgoingCall(callee, requestedAccountHandle, extras, initiatingUser,
originalIntent, callingPackage, false);
}
private CompletableFuture<Call> startOutgoingCall(List<Uri> participants,
PhoneAccountHandle requestedAccountHandle,
Bundle extras, UserHandle initiatingUser, Intent originalIntent,
String callingPackage, boolean isConference) {
...
call = new Call(.....)
...
addCall(callToPlace);
...
****
```java
@VisibleForTesting
public void addCall(Call call) {
...
call.addListener(this);
mCalls.add(call);
// Specifies the time telecom finished routing the call. This is used by the dialer for
// analytics.
Bundle extras = call.getIntentExtras();
extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
SystemClock.elapsedRealtime());
updateCanAddCall();
updateHasActiveRttCall();
updateExternalCallCanPullSupport();
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
...
listener.onCallAdded(call);
...
}
...
}
InCallController.java
@Override
public void onCallAdded(Call call) {
...
addCall(call);
...
IInCallService inCallService = entry.getValue();
inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
...
}
InCallServiceBinder
@Override
public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
}
InCallService.java
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
break;
final void internalAddCall(ParcelableCall parcelableCall) {
...
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
...
}
final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
...
if (stateChanged) {
fireStateChanged(mState);
}
if (detailsChanged) {
fireDetailsChanged(mDetails);
}
...
}
private void fireStateChanged(final int newState) {
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);
}
});
}
}
DialerCall.java
@Override
public void onStateChanged(Call call, int newState) {
...
stateUpdate();
...
}
private void stateUpdate() {
...
for (DialerCallListener listener : listeners) {
listener.onDialerCallUpdate();
}
...
}
DialerCallListenerImpl
@Override
public void onDialerCallUpdate() {
Trace.beginSection("CallList.onDialerCallUpdate");
onUpdateCall(call);
notifyGenericListeners();
Trace.endSection();
}
private void notifyGenericListeners() {
for (Listener listener : listeners) {
listener.onCallListChange(this);
}
}
InCallPresenter.java
@Override
public void onCallListChange(CallList callList) {
...
newState = startOrFinishUi(newState);
...
}
private InCallState startOrFinishUi(InCallState newState) {
...
showInCall(...)
...
}
public void showInCall(boolean showDialpad, boolean newOutgoingCall) {
LogUtil.i("InCallPresenter.showInCall", "Showing InCallActivity");
context.startActivity(
InCallActivity.getIntent(context, showDialpad, newOutgoingCall, false));
}
至此,InCallActivity將會啟動到並顯示UI