InCallContrller内部逻辑

前言

刚刚开始看InCallContrller内部逻辑是会有点复杂的所以我今天来做一个笔记。
作用 : InCallContrller的作用就是为了调用InCallUi页面,InCallContrller的作用就是控制InCallUi的启动与关闭操作。

关系图:

InCallContrller内部逻辑_第1张图片

 

流程图

 

InCallContrller内部逻辑_第2张图片

第一步我们首先来看初始化过程吧:

第一步来电或者去电都是调用一个方法吊起InCall的方法bindToService()方法,看方法的名字就可以看出来,他的意思是绑定服务,服务就是InCallUi的服务一直等待调用

这来开InCallContrller逻辑,首先看bindToService()方法,这里会初始化里面的一些内部类,进行内部绑定

 public void bindToServices(Call call) {
        if (mInCallServiceConnection == null) {
            InCallServiceConnection dialerInCall = null;
            InCallServiceInfo defaultDialerComponentInfo = getDefaultDialerComponent();
            Log.i(this, "defaultDialer: " + defaultDialerComponentInfo);
            if (defaultDialerComponentInfo != null &&
                    !defaultDialerComponentInfo.getComponentName().equals(
                            mSystemInCallComponentName)) {
                dialerInCall = new InCallServiceBindingConnection(defaultDialerComponentInfo);
            }
            Log.i(this, "defaultDialer: " + dialerInCall);

            InCallServiceInfo systemInCallInfo = getInCallServiceComponent(
                    mSystemInCallComponentName, IN_CALL_SERVICE_TYPE_SYSTEM_UI);
            EmergencyInCallServiceConnection systemInCall =
                    new EmergencyInCallServiceConnection(systemInCallInfo, dialerInCall);
            systemInCall.setHasEmergency(mCallsManager.hasEmergencyCall());

            InCallServiceConnection carModeInCall = null;
            InCallServiceInfo carModeComponentInfo = getCarModeComponent();
            if (carModeComponentInfo != null &&
                    !carModeComponentInfo.getComponentName().equals(mSystemInCallComponentName)) {
                carModeInCall = new InCallServiceBindingConnection(carModeComponentInfo);//初始化连接
            }

            mInCallServiceConnection =
                    new CarSwappingInCallServiceConnection(systemInCall, carModeInCall);
        }

        mInCallServiceConnection.setCarMode(shouldUseCarModeUI());

        // Actually try binding to the UI InCallService.  If the response  mInCallServiceConnection这个对象,他在两个独立的实例中切换UI
        if (mInCallServiceConnection.connect(call) ==//mInCallServiceConnection.connect(call)开启调用InCallUi
                InCallServiceConnection.CONNECTION_SUCCEEDED) {
            // Only connect to the non-ui InCallServices if we actually connected to the main UI
            // one.只有当我们实际连接到主UI InCallServices时,才连接到非UI InCallServices。
            connectToNonUiInCallServices(call);
        } else {
            Log.i(this, "bindToServices: current UI doesn't support call; not binding.");
        }
    }

这里初始化一个内部类CarSwappingInCallServiceConnection,他的作用是互相切换InCallServiceBindingConnection和EmergencyInCallServiceConnection。CarSwappingInCallServiceConnection  切换两个子类直接的切换

EmergencInCallSerivceConnection他的作用是处理InCallServiceBindingConnection断开后通过紧急处理Emergenc就是紧急的意思。

CatSwappingInCallServiceConnection:

private class CarSwappingInCallServiceConnection extends InCallServiceConnection {
        private final InCallServiceConnection mDialerConnection;
        private final InCallServiceConnection mCarModeConnection;
        private InCallServiceConnection mCurrentConnection;
        private boolean mIsCarMode = false;
        private boolean mIsConnected = false;

        public CarSwappingInCallServiceConnection(
                InCallServiceConnection dialerConnection,
                InCallServiceConnection carModeConnection) {
            mDialerConnection = dialerConnection;
            mCarModeConnection = carModeConnection;
            mCurrentConnection = getCurrentConnection();
        }

        public synchronized void setCarMode(boolean isCarMode) {
            Log.i(this, "carmodechange: " + mIsCarMode + " => " + isCarMode);
            if (isCarMode != mIsCarMode) {
                mIsCarMode = isCarMode;
                InCallServiceConnection newConnection = getCurrentConnection();
                if (newConnection != mCurrentConnection) {
                    if (mIsConnected) {
                        mCurrentConnection.disconnect();
                        int result = newConnection.connect(null);
                        mIsConnected = result == CONNECTION_SUCCEEDED;
                    }
                    mCurrentConnection = newConnection;
                }
            }
        }

        @Override
        public int connect(Call call) {
            if (mIsConnected) {
                Log.i(this, "already connected");
                return CONNECTION_SUCCEEDED;
            } else {//mCurrentConnection这个获取对象取决于mIsCarMode这个如果是false就是InCallServiceBindingConnection
                int result = mCurrentConnection.connect(call);  //InCallUi调用  调到EmergencyInCallServiceConnection内部类中
                if (result != CONNECTION_FAILED) {
                    mIsConnected = result == CONNECTION_SUCCEEDED;
                    return result;
                }
            }

            return CONNECTION_FAILED;
        }

        @Override
        public void disconnect() {
            if (mIsConnected) {
                mCurrentConnection.disconnect();
                mIsConnected = false;
            } else {
                Log.i(this, "already disconnected");
            }
        }

        @Override
        public boolean isConnected() {
            return mIsConnected;
        }

        @Override
        public void setHasEmergency(boolean hasEmergency) {
            if (mDialerConnection != null) {
                mDialerConnection.setHasEmergency(hasEmergency);
            }
            if (mCarModeConnection != null) {
                mCarModeConnection.setHasEmergency(hasEmergency);
            }
        }

        @Override
        public InCallServiceInfo getInfo() {
            return mCurrentConnection.getInfo();
        }

        @Override
        public void dump(IndentingPrintWriter pw) {
            pw.print("Car Swapping ICS [");
            pw.append(mIsConnected ? "" : "not ").append("connected]\n");
            pw.increaseIndent();
            if (mDialerConnection != null) {
                pw.print("Dialer: ");
                mDialerConnection.dump(pw);
            }
            if (mCarModeConnection != null) {
                pw.print("Car Mode: ");
                mCarModeConnection.dump(pw);
            }
        }

        private InCallServiceConnection getCurrentConnection() {
            if (mIsCarMode && mCarModeConnection != null) {
                return mCarModeConnection;
            } else {
                return mDialerConnection;
            }
        }
    }

CatSwappingInCallServiceConnection这个内部类主要是要看构造方法里面的 mCurrentConnection = getCurrentConnection();这里的getCurrentConnection决定最切换那个的调用目的,mIsCarMode如果是fasle就回调用EmergencyInCallServiceConnection内部类,他的意思就是紧急调用InCallSerivceConnection的意思,在这个内部类中需要看connec方法他里面做了

接下来看一下EmergencyInCallServiceConnection内部处理

 /**
     * InCallServiceBindingConnection的一个版本,它将所有调用委托给一个辅助连接,直到它发现一个紧急调用,
     * 或者另一个连接终止。当这两种情况之一发生时,该类实例将接管连接。
     */
    private class EmergencyInCallServiceConnection extends InCallServiceBindingConnection {
        private boolean mIsProxying = true;
        private boolean mIsConnected = false;
        private final InCallServiceConnection mSubConnection;

        private Listener mSubListener = new Listener() {
            @Override
            public void onDisconnect(InCallServiceConnection subConnection) {
                if (subConnection == mSubConnection) {
                    if (mIsConnected && mIsProxying) {
                        // At this point we know that we need to be connected to the InCallService
                        // and we are proxying to the sub connection.  However, the sub-connection
                        // just died so we need to stop proxying and connect to the system in-call
                        // service instead.此时,我们知道需要连接到InCallService,并代理到子连接。然而,子连接刚刚结束,因此我们需要停止代理并转而连接到系统内调用服务。
                        mIsProxying = false;
                        connect(null);
                    }
                }
            }
        };

        public EmergencyInCallServiceConnection(
                InCallServiceInfo info, InCallServiceConnection subConnection) {

            super(info);
            mSubConnection = subConnection;//传进来时一般是Null  subConnection直接搭载的是 InCallServiceBindingConnection  就是创建他的时候满足条件直接调用父类内容
            if (mSubConnection != null) {
                mSubConnection.setListener(mSubListener);
            }
            mIsProxying = (mSubConnection != null);
        }

        @Override
        public int connect(Call call) {
            mIsConnected = true;
            if (mIsProxying) {  //这里经过我Debug 他进入只会开机第一次进入  如果是false表示代理结束,如果是true开始代理  开机拨号第一次会是true
                int result = mSubConnection.connect(call);//InCallUi调用
                mIsConnected = result == CONNECTION_SUCCEEDED;
                if (result != CONNECTION_FAILED) {
                    return result;
                }
                // Could not connect to child, stop proxying.
                mIsProxying = false;
            }

            mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(call,
                mCallsManager.getCurrentUserHandle());

            if (call != null && call.isIncoming()
                && mEmergencyCallHelper.getLastEmergencyCallTimeMillis() > 0) {
              // Add the last emergency call time to the call
              Bundle extras = new Bundle();
              extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
                      mEmergencyCallHelper.getLastEmergencyCallTimeMillis());
              call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras);
            }

            // 如果条件满足,连接父类中的connect函数
            return super.connect(call);
        }

        @Override
        public void disconnect() {
            Log.i(this, "Disconnect forced!");
            if (mIsProxying) {
                mSubConnection.disconnect();
            } else {
                super.disconnect();
                mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
            }
            mIsConnected = false;
        }

        @Override
        public void setHasEmergency(boolean hasEmergency) {
            if (hasEmergency) {
                takeControl();
            }
        }

        @Override
        public InCallServiceInfo getInfo() {
            if (mIsProxying) {
                return mSubConnection.getInfo();
            } else {
                return super.getInfo();
            }
        }
        @Override
        protected void onDisconnected() {
            // Save this here because super.onDisconnected() could force us to explicitly
            // disconnect() as a cleanup step and that sets mIsConnected to false.
            boolean shouldReconnect = mIsConnected;
            super.onDisconnected();
            // We just disconnected.  Check if we are expected to be connected, and reconnect.
            if (shouldReconnect && !mIsProxying) {
                connect(null);  // reconnect
            }
        }

        @Override
        public void dump(IndentingPrintWriter pw) {
            pw.print("Emergency ICS Connection [");
            pw.append(mIsProxying ? "" : "not ").append("proxying, ");
            pw.append(mIsConnected ? "" : "not ").append("connected]\n");
            pw.increaseIndent();
            pw.print("Emergency: ");
            super.dump(pw);
            if (mSubConnection != null) {
                pw.print("Default-Dialer: ");
                mSubConnection.dump(pw);
            }
            pw.decreaseIndent();
        }

        /**
         * Forces the connection to take control from it's subConnection.
         */
        private void takeControl() {
            if (mIsProxying) {
                mIsProxying = false;
                if (mIsConnected) {
                    mSubConnection.disconnect();
                    super.connect(null);
                }
            }
        }
    }

在这里会做一个是否需要代理,如果需要处理代理逻辑,这里的代理获取的内部对象也是有判断的,建议去看内部逻辑这里就不多讲解了。

接着调用父类的的connec()方法,先看代码。

InCallServiceBindingConnection

 private class InCallServiceBindingConnection extends InCallServiceConnection {

        private final ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.startSession("ICSBC.oSC");
                synchronized (mLock) {
                    try {
                        Log.d(this, "onServiceConnected: %s %b %b", name, mIsBound, mIsConnected);
                        mIsBound = true;
                        if (mIsConnected) {//是否连接
                            // Only proceed if we are supposed to be connected.只有当我们被认为是有联系的时候才继续。 成功后调用InCallServer
                            onConnected(service);
                        }
                    } finally {
                        Log.endSession();
                    }
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.startSession("ICSBC.oSD");
                synchronized (mLock) {
                    try {
                        Log.d(this, "onDisconnected: %s", name);
                        mIsBound = false;
                        onDisconnected();
                    } finally {
                        Log.endSession();
                    }
                }
            }
        };

        private final InCallServiceInfo mInCallServiceInfo;
        private boolean mIsConnected = false;
        private boolean mIsBound = false;

        public InCallServiceBindingConnection(InCallServiceInfo info) {
            mInCallServiceInfo = info;
        }

        @Override
        public int connect(Call call) {
            if (mIsConnected) {
                Log.addEvent(call, LogUtils.Events.INFO, "Already connected, ignoring request.");
                return CONNECTION_SUCCEEDED;
            }

            if (call != null && call.isSelfManaged() &&
                    !mInCallServiceInfo.isSelfManagedCallsSupported()) {
                Log.i(this, "Skipping binding to %s - doesn't support self-mgd calls",
                        mInCallServiceInfo);
                mIsConnected = false;
                return CONNECTION_NOT_SUPPORTED;
            }
            //开启InCallService
            Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
            intent.setComponent(mInCallServiceInfo.getComponentName());
            if (call != null && !call.isIncoming() && !call.isExternalCall()){
                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 InCall %s, with %s", mInCallServiceInfo, intent);
            mIsConnected = true;
            if (!mContext.bindServiceAsUser(intent, mServiceConnection,   //开启服务  调用InCallServiceImpl
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE |
                        Context.BIND_ABOVE_CLIENT,
                        UserHandle.CURRENT)) {
                Log.w(this, "Failed to connect.");
                mIsConnected = false;
            }

            if (call != null && mIsConnected) {
                call.getAnalytics().addInCallService(
                        mInCallServiceInfo.getComponentName().flattenToShortString(),
                        mInCallServiceInfo.getType());
            }

            return mIsConnected ? CONNECTION_SUCCEEDED : CONNECTION_FAILED;
        }

        @Override
        public InCallServiceInfo getInfo() {
            return mInCallServiceInfo;
        }

        @Override
        public void disconnect() {
            if (mIsConnected) {
                mContext.unbindService(mServiceConnection);
                mIsConnected = false;
            } else {
                Log.addEvent(null, LogUtils.Events.INFO, "Already disconnected, ignoring request.");
            }
        }

        @Override
        public boolean isConnected() {
            return mIsConnected;
        }

        @Override
        public void dump(IndentingPrintWriter pw) {
            pw.append("BindingConnection [");
            pw.append(mIsConnected ? "" : "not ").append("connected, ");
            pw.append(mIsBound ? "" : "not ").append("bound]\n");
        }

        protected void onConnected(IBinder service) {
            boolean shouldRemainConnected =
                    InCallController.this.onConnected(mInCallServiceInfo, service);//往下执行
            if (!shouldRemainConnected) {
                // Sometimes we can opt to disconnect for certain reasons, like if the
                // InCallService rejected our initialization step, or the calls went away
                // in the time it took us to bind to the InCallService. In such cases, we go
                // ahead and disconnect ourselves.
                disconnect();
            }
        }

        protected void onDisconnected() {
            InCallController.this.onDisconnected(mInCallServiceInfo);
            disconnect();  // Unbind explicitly if we get disconnected.
            if (mListener != null) {
                mListener.onDisconnect(InCallServiceBindingConnection.this);
            }
        }
    }

这里内部处理了启动InCallUi页面逻辑

你可能感兴趣的:(InCallContrller内部逻辑)