Android 7.0 去电流程

来源:互联网 发布:身份证登记软件下载 编辑:程序博客网 时间:2024/05/02 11:18

拨号的入口在TelecomManager的placeCall的方法,该方法实际调用TelecomServiceImpl的placeCall(),接着调用UserCallIntentProcessor的processIntent()方法

TelecomServiceImpl->placeCall()

public void placeCall(Uri handle, Bundle extras, String callingPackage) {            try {            ...                synchronized (mLock) {                    final UserHandle userHandle = Binder.getCallingUserHandle();                    long token = Binder.clearCallingIdentity();                    try {                        final Intent intent = new Intent(Intent.ACTION_CALL, handle);                        if (extras != null) {                            extras.setDefusable(true);                            intent.putExtras(extras);                        }                        mUserCallIntentProcessorFactory.create(mContext, userHandle)                                .processIntent(                                        intent, callingPackage, hasCallAppOp && hasCallPermission);//mUserCallIntentProcessorFactory是在TelecomSystem中初始化的                    } finally {                        Binder.restoreCallingIdentity(token);                    }                }            } finally {                Log.endSession();            }        }

UserCallIntentProcessor又在process(),UserCallIntentProcessor中方执行顺序为
process()->processOutgoingCallIntent()->sendBroadcastToReceiver():

UserCallIntentProcessor->process():

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)) {            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);        }    }

UserCallIntentProcessor->processOutgoingCallIntent()

private void processOutgoingCallIntent(Intent intent, String callingPackageName,            boolean canCallNonEmergency) {    ...        int videoState = intent.getIntExtra(                TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,                VideoProfile.STATE_AUDIO_ONLY);        Log.d(this, "processOutgoingCallIntent videoState = " + videoState);        intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,                isDefaultOrSystemDialer(callingPackageName));        // Save the user handle of current user before forwarding the intent to primary user.        intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);        sendBroadcastToReceiver(intent);    }

UserCallIntentProcessor->sendBroadcastToReceiver():

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");        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);        return true;    }

UserCallIntentProcessor给PrimaryCallReceiver发送广播后, PrimaryCallReceiver在onReceive()实际上就了调用CallIntentProcessor的processIntent的方法,接着调用CallsManager的startOutgoingCall 初始化Call,然后NewOutgoingCallIntentBroadcaster的processIntent()方法:

public void onReceive(Context context, Intent intent) {        synchronized (getTelecomSystem().getLock()) {            getTelecomSystem().getCallIntentProcessor().processIntent(intent);        }    }

在CallIntentProcessor的processIntent方法中调用processOutgoingCallIntent()方法。
CallIntentProcessor->processOutgoingCallIntent():

static void processOutgoingCallIntent(            Context context,            CallsManager callsManager,            Intent intent) {            ...        Call call = callsManager                .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);//初始化call及启动InCallUI        if (call != null) {            // 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, callsManager.getPhoneNumberUtilsAdapter(),                    isPrivilegedDialer);            final int result = broadcaster.processIntent();            final boolean success = result == DisconnectCause.NOT_DISCONNECTED;            if (!success && call != null) {                callsManager.clearPendingMOEmergencyCall();                disconnectCallAndShowErrorDialog(context, call, result);            }        }}

NewOutgoingCallIntentBroadcaster ->processIntent():

public int processIntent() {    ...        if (callImmediately) {            boolean speakerphoneOn = mIntent.getBooleanExtra(                    TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);            int videoState = mIntent.getIntExtra(                    TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,                    VideoProfile.STATE_AUDIO_ONLY);            // Since we will not start NewOutgoingCallBroadcastIntentReceiver in case of            // callImmediately is true, make sure to mark it as ready, so that when user            // selects account, call can go ahead in case of numbers which are potential emergency            // but not actual emergeny.            mCall.setNewOutgoingCallIntentBroadcastIsDone();            mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,                    speakerphoneOn, videoState);        }    }

CallsManager->placeOutgoingCall():

        ...        if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {            if (!call.isEmergencyCall()) {                updateLchStatus(call.getTargetPhoneAccount().getId());            }                call.startCreateConnection(mPhoneAccountRegistrar);            }        }         ...

Call->startCreateConnection():

void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {        ...        mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,                phoneAccountRegistrar, mContext);        mCreateConnectionProcessor.process();    }

CreateConnectionProcessor->process():

public void process() {        clearTimeout();        mAttemptRecords = new ArrayList<>();        if (mCall.getTargetPhoneAccount() != null) {            mAttemptRecords.add(new CallAttemptRecord(                    mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));        }        adjustAttemptsForConnectionManager();        adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());        mAttemptRecordIterator = mAttemptRecords.iterator();        attemptNextPhoneAccount();    }

CreateConnectionProcessor->attemptNextPhoneAccount()

 private void attemptNextPhoneAccount() { ...  if (mCallResponse != null && attempt != null) {            Log.i(this, "Trying attempt %s", attempt);            PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;            mService = mRepository.getService(phoneAccount.getComponentName(),                    phoneAccount.getUserHandle());            if (mService == null) {                Log.i(this, "Found no connection service for attempt %s", attempt);                attemptNextPhoneAccount();//递归            } else {                mConnectionAttempt++;                mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);                mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);                mCall.setConnectionService(mService);                setTimeoutIfNeeded(mService, attempt);                mService.createConnection(mCall, this);            }        }    }

ConnectionServiceWrapper->createConnection():

public void createConnection(final Call call, final CreateConnectionResponse response) {        Log.d(this, "createConnection(%s) via %s.", call, getComponentName());        BindCallback callback = new BindCallback() {            @Override            public void onSuccess() {                String callId = mCallIdMapper.getCallId(call);                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 {                    mServiceInterface.createConnection(                            call.getConnectionManagerPhoneAccount(),                            callId,                            new ConnectionRequest(                                    call.getTargetPhoneAccount(),                                    call.getHandle(),                                    extras,                                    call.getVideoState(),                                    callId),                            call.shouldAttachToExistingConnection(),                            call.isUnknown());                } catch (RemoteException e) {                    Log.e(this, e, "Failure to createConnection -- %s", getComponentName());                    mPendingResponses.remove(callId).handleCreateConnectionFailure(                            new DisconnectCause(DisconnectCause.ERROR, e.toString()));                }            }            @Override            public void onFailure() {                Log.e(this, new Exception(), "Failure to call %s", getComponentName());                response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));            }        };        mBinder.bind(callback, call);//回调    }

ConnetctionService->createConnection():

private void createConnection(            final PhoneAccountHandle callManagerAccount,            final String callId,            final ConnectionRequest request,            boolean isIncoming,            boolean isUnknown) {        Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)                : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)                : onCreateOutgoingConnection(callManagerAccount, request);                ...         }

onCreateOutgoingConnection是在ConnetctionService的子类TelephonyConnectionService中实现的
TelephonyConnectionService->onCreateOutgoingConnection():

 public Connection onCreateOutgoingConnection(            PhoneAccountHandle connectionManagerPhoneAccount,            final ConnectionRequest request) {            ...            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);            Connection resultConnection = getTelephonyConnection(request, numberToDial,                    isEmergencyNumber, handle, phone);            // If there was a failure, the resulting connection will not be a TelephonyConnection,            // so don't place the call!            if(resultConnection instanceof TelephonyConnection) {                placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);            }            return resultConnection;        }

TelephonyConnectionService->placeOutgoingConnection():

private void placeOutgoingConnection(            TelephonyConnection connection, Phone phone, int videoState, Bundle extras,            ConnectionRequest request) {            ...        String number = connection.getAddress().getSchemeSpecificPart();com.android.internal.telephony.Connection originalConnection = null;        try {            if (phone != null) {                if (isAddParticipant) {                    phone.addParticipant(number);                    return;                } else {                    originalConnection = phone.dial(number, null, request.getVideoState(), bundle);                }            }        } catch (CallStateException e) {            Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);            int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;            if (e.getError() == CallStateException.ERROR_DISCONNECTED) {                cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;            } else if (e.getError() == CallStateException.ERROR_POWER_OFF) {                cause = android.telephony.DisconnectCause.POWER_OFF;            }            connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(                    cause, e.getMessage()));            return;        }    }

GsmCdmaPhone->dial():

public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)            throws CallStateException {            ...        if (isPhoneTypeGsm()) {            return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);        } else {            return dialInternal(dialString, null, videoState, intentExtras);        }    }

GsmCdmaPhone->dialInternal():

protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,                                      Bundle intentExtras)            throws CallStateException {        // Need to make sure dialString gets parsed properly        String newDialString = PhoneNumberUtils.stripSeparators(dialString);        if (isPhoneTypeGsm()) {            // 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);            GsmMmiCode mmi =                    GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());            if (DBG) logd("dialing w/ mmi '" + mmi + "'...");            if (mmi == null) {                return mCT.dial(newDialString, uusInfo, intentExtras);            } else if (mmi.isTemporaryModeCLIR()) {                return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);            } else {                mPendingMMIs.add(mmi);                mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));                try {                    mmi.processCode();                } catch (CallStateException e) {                    //do nothing                }                // FIXME should this return null or something else?                return null;            }        } else {            return mCT.dial(newDialString);        }    }

GsmCdmaCallTracker->dial():

public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,                                        Bundle intentExtras)            throws CallStateException {            ...        if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0                || mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {            // Phone number is invalid            mPendingMO.mCause = DisconnectCause.INVALID_NUMBER;            // handlePollCalls() will notice this call not present            // and will mark it as dropped.            pollCallsWhenSafe();        } else {            // Always unmute when initiating a new call            setMute(false);            mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());        }        if (mNumberConverted) {            mPendingMO.setConverted(origNumber);            mNumberConverted = false;        }        updatePhoneState();        mPhone.notifyPreciseCallStateChanged();        return mPendingMO;    }