intent

因为拨号的流程从应用层到框架层是同步的,所以说一路分析调用就可以

DialpadFragment
重点关注intent构建,传递拨号盘number信息

35.详解 http://blog.csdn.net/qq_27104805/article/details/79630698

@Override
public void onClick(View view) {
}
private void handleDialButtonPressed() {

   final String number = mDigits.getText().toString();
        //35.找到了吧,最初的构造数据是number
        //35.回到最初的起点
        //35.构造一个uri,videoState,number信息的intent
       final Intent intent = new CallIntentBuilder(number).
               setCallInitiationType(LogState.INITIATION_DIALPAD)
               .build();
        //34.临门一脚
       DialerUtils.startActivityWithErrorToast(getActivity(), intent);
       hideAndClearDialpad(false);
}

DialerUtils
主要向intent中添加信息

//33.不要停
public static void startActivityWithErrorToast(Context context, Intent intent) {
    startActivityWithErrorToast(context, intent, R.string.activity_not_available);
}

public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
    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;
            // Make sure to not accidentally clobber any existing 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);
        }
}

TelecomUtil

//31.这里传递的intent
public static boolean placeCall(Activity activity, Intent intent) {
}

TelecomManagerCompat

public static void placeCall(@Nullable Activity activity,
        @Nullable TelecomManager telecomManager, @Nullable Intent intent) {
    //30.又回到intent,但是这个intent跟下文的intent不一样,继续跟踪

    //36.返回头来,这个intent.getData()就是对应的uri,目标号码number的地址
    //36.这里很奇怪,intent.getExtras()正常,但是在IntentUtil中进行赋值的时候,赋了很多值,怎么就获取Bundle
    if (CompatUtils.isMarshmallowCompatible()) {
        telecomManager.placeCall(intent.getData(), intent.getExtras());//placeCall方法,会一路往下走
        return;
    }
}

TelecomManager

//29.继续extras ,uri
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void placeCall(Uri address, Bundle extras) {
    service.placeCall(address, extras == null ? new Bundle() : extras,
                    mContext.getOpPackageName());

}

TelecomServiceImpl.mBinderImpl

//28.我们最初的寻找Bundle extras,估计向上就能找到源头
//28.此处还有构造intent的uri 

//37.都不知道为啥命名为handle,一点都不直观,反正就是uri,number的地址
@Override
public void placeCall(Uri handle, Bundle extras, String callingPackage) {
                final Intent intent = new Intent(Intent.ACTION_CALL, handle);
                //26.extras在此赋值进intent
                if (extras != null) {
                    extras.setDefusable(true);
                    intent.putExtras(extras);
                }
}

UserCallIntentProcessor

//25.不要停
public void processIntent(Intent intent, String callingPackageName,
        boolean canCallNonEmergency) {
    String action = intent.getAction();
}
//24.继续上
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
        boolean canCallNonEmergency) {
    Uri handle = intent.getData();
    String scheme = handle.getScheme();
    String uriString = handle.getSchemeSpecificPart();
    int videoState = intent.getIntExtra(
            TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
            VideoProfile.STATE_AUDIO_ONLY);

    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);
}
private boolean sendBroadcastToReceiver(Intent intent) {
    intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
    intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    intent.setClass(mContext, PrimaryCallReceiver.class);
}

PrimaryCallReceiver

//23.继续走
@Override
public void onReceive(Context context, Intent intent) {
}
@Override
public TelecomSystem getTelecomSystem() {
}

TelecomSystem

public static TelecomSystem getInstance() {
    return INSTANCE;//有个setInstance,具体什么时候set的?
}

CallIntentProcessor

//22.intent参数直接传递
public void processIntent(Intent intent) {
    final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
}

static void processOutgoingCallIntent(
        Context context,
        CallsManager callsManager,
        Intent intent) {

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

    // Ensure call subject is passed on to the connection service.
    if (intent.hasExtra(TelecomManager.EXTRA_CALL_SUBJECT)) {
        String callsubject = intent.getStringExtra(TelecomManager.EXTRA_CALL_SUBJECT);
        clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject);
    }

    final int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
            VideoProfile.STATE_AUDIO_ONLY);
    clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);

    final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);

    boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent);
    // Show the toast to warn user that it is a personal call though initiated in work profile.
    if (fixedInitiatingUser) {
        Toast.makeText(context, R.string.toast_personal_call_msg, Toast.LENGTH_LONG).show();
    }

    UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);

    // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
    //成功返回一个call对象
    //21.阶段性胜利,这里才是创建call(包括extras属性)的源头,至于具体属性是什么那就要进一步弄清每个参数的含义了
    //21.这四个参数均是通过intent获取到的,所以下一步重点关注intent,至此我们的关注点:extras-->request-->call-->intent

    ==========================================================
    //39.上面对intent一系列操作,参数的取出,相当于将参数同样关联到Call
    //39.phoneAccountHandle应该还是null
    ==========================================================
    Call call = callsManager
            .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);

    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();//NewOutgoingCallIntentBroadcaster.processIntent继续调用

        final boolean success = result == DisconnectCause.NOT_DISCONNECTED;

        if (!success && call != null) {
            disconnectCallAndShowErrorDialog(context, call, result);
        }
    }
}

NewOutgoingCallIntentBroadcaster

@VisibleForTesting
public int processIntent() {
    Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");

    Intent intent = mIntent;
    String action = intent.getAction();
    final Uri handle = intent.getData();

    boolean isVoicemailNumber = PhoneAccount.SCHEME_VOICEMAIL.equals(handle.getScheme());

    String number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);

    boolean isUriNumber = mPhoneNumberUtilsAdapter.isUriNumber(number);
    if (!isUriNumber) {
        number = mPhoneNumberUtilsAdapter.convertKeypadLettersToDigits(number);
        number = mPhoneNumberUtilsAdapter.stripSeparators(number);
    }

    final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
    Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);

    rewriteCallIntentAction(intent, isPotentialEmergencyNumber);//根据call类型进行转换,如普通,系统call,紧急call
    action = intent.getAction();
    // True for certain types of numbers that are not intended to be intercepted or modified
    // by third parties (e.g. emergency numbers).
    boolean callImmediately = false;

    if (Intent.ACTION_CALL.equals(action)) {
        if (isPotentialEmergencyNumber) {
            if (!mIsDefaultOrSystemPhoneApp) {
                Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
                        + "unless caller is system or default dialer.", number, intent);
                launchSystemDialer(intent.getData());
                return DisconnectCause.OUTGOING_CANCELED;
            } else {
                callImmediately = true;
            }
        }
    } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
        if (!isPotentialEmergencyNumber) {
            Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "
                    + "Intent %s.", number, intent);
            return DisconnectCause.OUTGOING_CANCELED;
        }
        callImmediately = true;
    } else {
        Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
        return DisconnectCause.INVALID_NUMBER;
    }

    if (callImmediately) {
        Log.i(this, "Placing call immediately instead of waiting for "
                + " OutgoingCallBroadcastReceiver: %s", intent);
        String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;
        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);
                //21.这里mCall
        mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
                speakerphoneOn, videoState);//下一步调用

        // Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
        // so that third parties can still inspect (but not intercept) the outgoing call. When
        // the broadcast finally reaches the OutgoingCallBroadcastReceiver, we'll know not to
        // initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.
    }

    UserHandle targetUser = mCall.getInitiatingUser();
    Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
    //紧接着mCallsManager.placeOutgoingCall 
    broadcastIntent(intent, number, !callImmediately, targetUser);
    return DisconnectCause.NOT_DISCONNECTED;
}

CallsManager

@VisibleForTesting
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
        boolean speakerphoneOn, int videoState) {

    final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();

    if (gatewayInfo == null) {
        Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle));
    } else {
        Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
                Log.pii(uriHandle), Log.pii(handle));
    }

    call.setHandle(uriHandle);
    call.setGatewayInfo(gatewayInfo);

    final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
            R.bool.use_speaker_when_docked);
    final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
    final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);

    // Auto-enable speakerphone if the originating intent specified to do so, if the call
    // is a video call, of if using speaker when docked
    call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
            || (useSpeakerWhenDocked && useSpeakerForDock));
    call.setVideoState(videoState);

    if (call.isEmergencyCall()) {
        new AsyncEmergencyContactNotifier(mContext).execute();
    }

    final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
            com.android.internal.R.bool.config_requireCallCapableAccountForHandle);

    if (call.getTargetPhoneAccount() != null || call.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.
        call.startCreateConnection(mPhoneAccountRegistrar);
    } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
            requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false,
            call.getInitiatingUser()).isEmpty()) {
        // If there are no call capable accounts, disconnect the call.
        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
                "No registered PhoneAccounts"));
        markCallAsRemoved(call);
    }
}

NewOutgoingCallIntentBroadcaster
调用broadcastIntent之后还会回到placeOutgoingCall

private void broadcastIntent(
        Intent originalCallIntent,
        String number,
        boolean receiverRequired,
        UserHandle targetUser) {
        //一个Intent.ACTION_NEW_OUTGOING_CALL广播
    Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
    if (number != null) {
        broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
    }

    // Force receivers of this broadcast intent to run at foreground priority because we
    // want to finish processing the broadcast intent as soon as possible.
    broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    Log.v(this, "Broadcasting intent: %s.", broadcastIntent);

    checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);

    mContext.sendOrderedBroadcastAsUser(
            broadcastIntent,
            targetUser,
            android.Manifest.permission.PROCESS_OUTGOING_CALLS,
            AppOpsManager.OP_PROCESS_OUTGOING_CALLS,
            receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
            null,  // scheduler
            Activity.RESULT_OK,  // initialCode
            number,  // initialData: initial value for the result data (number to be modified)
            null);  // initialExtras
}   

CallsManager

//20.call仍然作为参数传递,虽然进行了部分初始化,仍然需要逆流而上
@VisibleForTesting
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
        boolean speakerphoneOn, int videoState) {

    final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayAddress();

    if (gatewayInfo == null) {
        Log.i(this, "Creating a new outgoing call with handle: %s", Log.piiHandle(uriHandle));
    } else {
        Log.i(this, "Creating a new outgoing call with gateway handle: %s, original handle: %s",
                Log.pii(uriHandle), Log.pii(handle));
    }

    call.setHandle(uriHandle);
    call.setGatewayInfo(gatewayInfo);

    final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
            R.bool.use_speaker_when_docked);
    final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
    final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);

    // Auto-enable speakerphone if the originating intent specified to do so, if the call
    // is a video call, of if using speaker when docked
    call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
            || (useSpeakerWhenDocked && useSpeakerForDock));
    //这里有个伏笔啊,跟我们关注的extras同级的属性videoState
    call.setVideoState(videoState);
    if (call.isEmergencyCall()) {
        new AsyncEmergencyContactNotifier(mContext).execute();
    }

    final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
            com.android.internal.R.bool.config_requireCallCapableAccountForHandle);

    if (call.getTargetPhoneAccount() != null || call.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.
        // 如果是紧急号码或者已指定通话账户,则创建连接
        //19.这里有对象call,那么call对象有什么时候创建的呢?
        call.startCreateConnection(mPhoneAccountRegistrar);
    } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
            requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false,
            call.getInitiatingUser()).isEmpty()) {
        // If there are no call capable accounts, disconnect the call.
        markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
                "No registered PhoneAccounts"));
        markCallAsRemoved(call);
    }
}

Call

public void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
    if (mCreateConnectionProcessor != null) {
        Log.w(TAG, "mCreateConnectionProcessor in startCreateConnection is not null. This is" +
                " due to a race between NewOutgoingCallIntentBroadcaster and " +
                "phoneAccountSelected, but is harmlessly resolved by ignoring the second " +
                "invocation.");
        return;
    }
    //18.重点来了,这里对CreateConnectionProcessor的mCall进行的初始化,构造函数。继续...
    mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
            phoneAccountRegistrar, mContext);
    mCreateConnectionProcessor.process();
}

CreateConnectionProcessor

public void process() {
    Log.v(TAG, "process");
    mAttemptRecords = new ArrayList<>();
    //17.这里有对call对象操作取值,需要了解到什么时候call对象进行的初始化
    if (mCall.getTargetPhoneAccount() != null) {
        mAttemptRecords.add(new CallAttemptRecord(
                mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
    }
    adjustAttemptsForConnectionManager();
    adjustAttemptsForEmergency();
    mAttemptRecordIterator = mAttemptRecords.iterator();
    attemptNextPhoneAccount();
}
private void attemptNextPhoneAccount() {
    Log.v(TAG, "attemptNextPhoneAccount");
    CallAttemptRecord attempt = null;
    if (mAttemptRecordIterator.hasNext()) {
        attempt = mAttemptRecordIterator.next();

        if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
                attempt.connectionManagerPhoneAccount)) {
            Log.w(TAG,
                    "Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for "
                            + "attempt: %s", attempt);
            attemptNextPhoneAccount();
            return;
        }

        // If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it
        // also requires the BIND_TELECOM_CONNECTION_SERVICE permission.
        if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) &&
                !mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
                        attempt.targetPhoneAccount)) {
            Log.w(TAG,
                    "Target PhoneAccount does not have BIND_TELECOM_CONNECTION_SERVICE for "
                            + "attempt: %s", attempt);
            attemptNextPhoneAccount();
            return;
        }
    }

    if (mCallResponse != null && attempt != null) {
        PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
        mService = mRepository.getService(phoneAccount.getComponentName(),
                phoneAccount.getUserHandle());
        if (mService == null) {
            Log.i(TAG, "Found no connection service for attempt %s", attempt);
            attemptNextPhoneAccount();
        } else {
            //16.call对象,部分初始化和传递
            mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
            mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
            mCall.setConnectionService(mService);
            Log.i(TAG, "Attempting to call");
            mService.createConnection(mCall, this);
        }
    } else {
        Log.v(TAG, "attemptNextPhoneAccount, no more accounts, failing");
        DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?
                mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);
        notifyCallConnectionFailure(disconnectCause);
    }
}

ConnectionServiceWrapper

//15.下一步重点关注Call call
@VisibleForTesting
public void createConnection(final Call call, final CreateConnectionResponse response) {
    Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
    //BindCallback 匿名类
    BindCallback callback = new BindCallback() {
        @Override
        public void onSuccess() {
            String callId = mCallIdMapper.getCallId(call);
            mPendingResponses.put(callId, response);

            GatewayInfo gatewayInfo = call.getGatewayInfo();
            //14.核心在这里,通过call获取的extras,正好request也是通过call进行创建的,水乳交融啊
            //14.当然这里也是重点,extras额外进行了一些初始化操作
            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 {
                //13.这里就来到了ConnectionRequest request初始化,主要根据extras和call进行属性的初始化
                mServiceInterface.createConnection(
                        call.getConnectionManagerPhoneAccount(),
                        callId,
                        new ConnectionRequest(
                                call.getTargetPhoneAccount(),
                                call.getHandle(),
                                extras,//12.相信这就是我们最初寻找的Bundle 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));
        }
    };
    //最终回到callback的onSuccess方法。先创建匿名类,然后bind,回调至onSuccess
    mBinder.bind(callback, call);
}

ConnectionService.mBinder

//11.这里还是回归到ConnectionRequest request,此方法只是中转了下,在handler中进行了消息的传递
@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;
    //10.what=MSG_CREATE_CONNECTION,obj=args
    mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
}

ConnectionService.mHandler

private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case 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: {
            //9.这里args=msg.obj--》request =args.arg3,重点来到msg什么时候进行的赋值操作
            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() {
                        //8.在这
                            createConnection(
                                    connectionManagerPhoneAccount,
                                    id,
                                    request,
                                    isIncoming,
                                    isUnknown);
                        }
                    });
                } else {
                    createConnection(
                            connectionManagerPhoneAccount,
                            id,
                            request,
                            isIncoming,
                            isUnknown);
                }
            } finally {
                args.recycle();
            }
            break;
        }

    }
}
};
//7.这里还是传递的参数
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);
    //6.在这里进行传递ConnectionRequest request参数,继续走,还没到头
    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));
    }

    connection.setTelecomCallId(callId);
    if (connection.getState() != Connection.STATE_DISCONNECTED) {
        addConnection(callId, connection);
    }

    Uri address = connection.getAddress();
    String number = address == null ? "null" : address.getSchemeSpecificPart();
    Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s",
            Connection.toLogSafePhoneNumber(number),
            Connection.stateToString(connection.getState()),
            Connection.capabilitiesToString(connection.getConnectionCapabilities()),
            Connection.propertiesToString(connection.getConnectionProperties()));

    Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
    mAdapter.handleCreateConnectionComplete(
            callId,
            request,
            new ParcelableConnection(
                    request.getAccountHandle(),
                    connection.getState(),
                    connection.getConnectionCapabilities(),
                    connection.getConnectionProperties(),
                    connection.getAddress(),
                    connection.getAddressPresentation(),
                    connection.getCallerDisplayName(),
                    connection.getCallerDisplayNamePresentation(),
                    connection.getVideoProvider() == null ?
                            null : connection.getVideoProvider().getInterface(),
                    connection.getVideoState(),
                    connection.isRingbackRequested(),
                    connection.getAudioModeIsVoip(),
                    connection.getConnectTimeMillis(),
                    connection.getStatusHints(),
                    connection.getDisconnectCause(),
                    createIdList(connection.getConferenceables()),
                    connection.getExtras()));
    if (isUnknown) {
        triggerConferenceRecalculate();
    }
}

TelephonyConnectionService

//5.谁调用的onCreateOutgoingConnection--》传递的ConnectionRequest request
@Override
public Connection onCreateOutgoingConnection(
        PhoneAccountHandle connectionManagerPhoneAccount,
        final ConnectionRequest request) {
    Log.i(this, "onCreateOutgoingConnection, request: " + request);

    Uri handle = request.getAddress();

    String scheme = handle.getScheme();
    String number;
    if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
        // TODO: We don't check for SecurityException here (requires
        // CALL_PRIVILEGED permission).
        final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);         
        number = phone.getVoiceMailNumber();        
        // Convert voicemail: to tel:
        handle = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
    } else {          
        number = handle.getSchemeSpecificPart();         
        final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
        if (phone != null && CDMA_ACTIVATION_CODE_REGEX_PATTERN.matcher(number).matches()) {
            // Obtain the configuration for the outgoing phone's SIM. If the outgoing number
            // matches the *228 regex pattern, fail the call. This number is used for OTASP, and
            // when dialed could lock LTE SIMs to 3G if not prohibited..
            boolean disableActivation = false;
            CarrierConfigManager cfgManager = (CarrierConfigManager)
                    phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
            if (cfgManager != null) {
                disableActivation = cfgManager.getConfigForSubId(phone.getSubId())
                        .getBoolean(CarrierConfigManager.KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL);
            }

        }
    }
    final String numberToDial = number;

    final boolean isEmergencyNumber =
            PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);

    // Get the right phone object from the account data passed in.
    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) {
        //4.重点的request,继续往上走
        placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);
    }
    return resultConnection;
}

private Connection getTelephonyConnection(final ConnectionRequest request, final String number,
        boolean isEmergencyNumber, final Uri handle, Phone phone) {

    if (phone == null) {
        final Context context = getApplicationContext();
        if (context.getResources().getBoolean(R.bool.config_checkSimStateBeforeOutgoingCall)) {
            // Check SIM card state before the outgoing call.
            // Start the SIM unlock activity if PIN_REQUIRED.
            final Phone defaultPhone = PhoneFactory.getDefaultPhone();
            final IccCard icc = defaultPhone.getIccCard();
            IccCardConstants.State simState = IccCardConstants.State.UNKNOWN;
            if (icc != null) {
                simState = icc.getState();
            }
            if (simState == IccCardConstants.State.PIN_REQUIRED) {
                final String simUnlockUiPackage = context.getResources().getString(
                        R.string.config_simUnlockUiPackage);
                final String simUnlockUiClass = context.getResources().getString(
                        R.string.config_simUnlockUiClass);
                if (simUnlockUiPackage != null && simUnlockUiClass != null) {
                    Intent simUnlockIntent = new Intent().setComponent(new ComponentName(
                            simUnlockUiPackage, simUnlockUiClass));
                    simUnlockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    try {
                        context.startActivity(simUnlockIntent);
                    } catch (ActivityNotFoundException exception) {
                        Log.e(this, exception, "Unable to find SIM unlock UI activity.");
                    }
                }
                return Connection.createFailedConnection(
                        DisconnectCauseUtil.toTelecomDisconnectCause(
                                android.telephony.DisconnectCause.OUT_OF_SERVICE,
                                "SIM_STATE_PIN_REQUIRED"));
            }
        }

        Log.d(this, "onCreateOutgoingConnection, phone is null");
        return Connection.createFailedConnection(
                DisconnectCauseUtil.toTelecomDisconnectCause(
                        android.telephony.DisconnectCause.OUT_OF_SERVICE, "Phone is null"));
    }

    // Check both voice & data RAT to enable normal CS call,
    // when voice RAT is OOS but Data RAT is present.
    int state = phone.getServiceState().getState();
    if (state == ServiceState.STATE_OUT_OF_SERVICE) {
        int dataNetType = phone.getServiceState().getDataNetworkType();
        if (dataNetType == TelephonyManager.NETWORK_TYPE_LTE ||
                dataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
            state = phone.getServiceState().getDataRegState();
        }
    }

    // If we're dialing a non-emergency number and the phone is in ECM mode, reject the call if
    // carrier configuration specifies that we cannot make non-emergency calls in ECM mode.
    if (!isEmergencyNumber && phone.isInEcm()) {
        boolean allowNonEmergencyCalls = true;
        CarrierConfigManager cfgManager = (CarrierConfigManager)
                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
        if (cfgManager != null) {
            allowNonEmergencyCalls = cfgManager.getConfigForSubId(phone.getSubId())
                    .getBoolean(CarrierConfigManager.KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL);
        }

        if (!allowNonEmergencyCalls) {
            return Connection.createFailedConnection(
                    DisconnectCauseUtil.toTelecomDisconnectCause(
                            android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY,
                            "Cannot make non-emergency call in ECM mode."
                    ));
        }
    }

    if (!isEmergencyNumber) {
        switch (state) {
            case ServiceState.STATE_IN_SERVICE:
            case ServiceState.STATE_EMERGENCY_ONLY:
                break;
            case ServiceState.STATE_OUT_OF_SERVICE:
                if (phone.isUtEnabled() && number.endsWith("#")) {
                    Log.d(this, "onCreateOutgoingConnection dial for UT");
                    break;
                } else {
                    return Connection.createFailedConnection(
                            DisconnectCauseUtil.toTelecomDisconnectCause(
                                    android.telephony.DisconnectCause.OUT_OF_SERVICE,
                                    "ServiceState.STATE_OUT_OF_SERVICE"));
                }
            case ServiceState.STATE_POWER_OFF:
                return Connection.createFailedConnection(
                        DisconnectCauseUtil.toTelecomDisconnectCause(
                                android.telephony.DisconnectCause.POWER_OFF,
                                "ServiceState.STATE_POWER_OFF"));
            default:
                Log.d(this, "onCreateOutgoingConnection, unknown service state: %d", state);
                return Connection.createFailedConnection(
                        DisconnectCauseUtil.toTelecomDisconnectCause(
                                android.telephony.DisconnectCause.OUTGOING_FAILURE,
                                "Unknown service state " + state));
        }
    }

    final Context context = getApplicationContext();
    if (VideoProfile.isVideo(request.getVideoState()) && isTtyModeEnabled(context) &&
            !isEmergencyNumber) {
        return Connection.createFailedConnection(DisconnectCauseUtil.toTelecomDisconnectCause(
                android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED));
    }

    // Check for additional limits on CDMA phones.
    final Connection failedConnection = checkAdditionalOutgoingCallLimits(phone);
    if (failedConnection != null) {
        return failedConnection;
    }

    final TelephonyConnection connection =
            createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
                    request.getTelecomCallId(), request.getAddress(), request.getVideoState());
    if (connection == null) {
        return Connection.createFailedConnection(
                DisconnectCauseUtil.toTelecomDisconnectCause(
                        android.telephony.DisconnectCause.OUTGOING_FAILURE,
                        "Invalid phone type"));
    }
    connection.setAddress(handle, PhoneConstants.PRESENTATION_ALLOWED);
    connection.setInitializing();
    connection.setVideoState(request.getVideoState());

    return connection;
}


private TelephonyConnection createConnectionFor(
        Phone phone,
        com.android.internal.telephony.Connection originalConnection,
        boolean isOutgoing,
        PhoneAccountHandle phoneAccountHandle,
        String telecomCallId,
        Uri address,
        int videoState) {
    TelephonyConnection returnConnection = null;
    int phoneType = phone.getPhoneType();
    if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
        returnConnection = new GsmConnection(originalConnection, telecomCallId);
    } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
        boolean allowsMute = allowsMute(phone);
        returnConnection = new CdmaConnection(originalConnection, mEmergencyTonePlayer,
                allowsMute, isOutgoing, telecomCallId);
    }
    if (returnConnection != null) {
        // Listen to Telephony specific callbacks from the connection
        returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
        returnConnection.setVideoPauseSupported(
                TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
                        phoneAccountHandle));
    }
    return returnConnection;
}
//3.是谁调用的placeOutgoingConnection--》onCreateOutgoingConnection方法
private void placeOutgoingConnection(
    TelephonyConnection connection, Phone phone, ConnectionRequest request) {
    //2.Bundle extras追本溯源,是ConnectionRequest request的一个属性,现在request是个重点
    placeOutgoingConnection(connection, phone, request.getVideoState(), request.getExtras());
}

private void placeOutgoingConnection(
        TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
    String number = connection.getAddress().getSchemeSpecificPart();

    com.android.internal.telephony.Connection originalConnection = null;
    try {
        if (phone != null) {
            //走到这一步就正式进入dial
            //1.第一步先理清这个Bundle extras,携带了什么信息,有什么作用。首先说明Bundle就是携带数据的
            originalConnection = phone.dial(number, null, videoState, extras);
        }
    } 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;
        }
        connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
                cause, e.getMessage()));
        return;
    }

    if (originalConnection == null) {
        int telephonyDisconnectCause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
        // On GSM phones, null connection means that we dialed an MMI code
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
            Log.d(this, "dialed MMI code");
            telephonyDisconnectCause = android.telephony.DisconnectCause.DIALED_MMI;
            final Intent intent = new Intent(this, MMIDialogActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            startActivity(intent);
        }
        Log.d(this, "placeOutgoingConnection, phone.dial returned null");
        connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
                telephonyDisconnectCause, "Connection is null"));
    } else {
        connection.setOriginalConnection(originalConnection);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值