InCallUI中的Listeners

InCallUI中维护通话状态需要大量的消息传递,而为了消息传递代码中定义了的大量的接口,主要集中在InCallPresenter和CallList中

InCallPresenter

packages/apps/InCallUI/src/com/android/incallui/InCallPresenter.java,MVP模式中的M

InCallStateListener

通知通话状态有改变

  public interface InCallStateListener {
        // TODO: Enhance state to contain the call objects instead of passing CallList
        public void onStateChange(InCallState oldState, InCallState newState, CallList callList);
    }
    private final Set<InCallStateListener> mListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<InCallStateListener, Boolean>(8, 0.9f, 1));
在onCallListChange中被调用

@Override
    public void onCallListChange(CallList callList) {
        ...
        for (InCallStateListener listener : mListeners) {
            listener.onStateChange(oldState, mInCallState, callList);
        }
        ...
   }

这个是CallList中接口的实现,调用链条会在后面的CallList中讲。

InCallStateListener是最主要的通知通话状态变化的接口,CallButtonPresenter、CallCardPresenter、ConferenceManagerPresenter、ProximitySensor、StatusBarNotifier和VideoPauseController使用它

IncomingCallListener

通知来电

    public interface IncomingCallListener {
        public void onIncomingCall(InCallState oldState, InCallState newState, Call call);
    }
    private final List<IncomingCallListener> mIncomingCallListeners = new CopyOnWriteArrayList<>();
被调用方法

    @Override
    public void onIncomingCall(Call call) {
        ...
        InCallState newState = startOrFinishUi(InCallState.INCOMING);
        InCallState oldState = mInCallState;

        Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
        mInCallState = newState;

        for (IncomingCallListener listener : mIncomingCallListeners) {
            listener.onIncomingCall(oldState, mInCallState, call);
        }
    }

这个是CallList中接口的实现,调用链会追述到CallList中的

    public void onCallAdded(android.telecom.Call telecommCall) {
        Call call = new Call(telecommCall);
        if (call.getState() == Call.State.INCOMING ||
                call.getState() == Call.State.CALL_WAITING) {
            onIncoming(call, call.getCannedSmsResponses());
        } else {
            onUpdate(call);
        }
        ...
    }

其中onUpdate(call)会导致InCallStateListener接口的调用,依据Call状态分别走不同的路径。

AnswerPresenter、CallButtonPresenter、CallCardPresenter、ConferenceManagerPresenter、StatusBarNotifier和VideoPauseController中使用

CanAddCallListener

通知有Call添加
    public interface CanAddCallListener {
        public void onCanAddCallChanged(boolean canAddCall);
    }
    private final Set<CanAddCallListener> mCanAddCallListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<CanAddCallListener, Boolean>(8, 0.9f, 1));
被调用方法
 public void onCanAddCallChanged(boolean canAddCall) {
        for (CanAddCallListener listener : mCanAddCallListeners) {
            listener.onCanAddCallChanged(canAddCall);
        }
    }
被packages/apps/InCallUI/src/com/android/incallui/InCallServiceImpl.java调用
    @Override
    public void onCanAddCallChanged(boolean canAddCall) {
        InCallPresenter.getInstance().onCanAddCallChanged(canAddCall);
    }
只在CallButtonPresenter中注册和反注册,更新通话按键状态。

InCallDetailsListener

通知Call的信息变化
    public interface InCallDetailsListener {
        public void onDetailsChanged(Call call, android.telecom.Call.Details details);
    }
    private final Set<InCallDetailsListener> mDetailsListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<InCallDetailsListener, Boolean>(8, 0.9f, 1));
被调用方法
 private final android.telecom.Call.Callback mCallCallback =
            new android.telecom.Call.Callback() {
        ...

        @Override
        public void onDetailsChanged(android.telecom.Call telecomCall,
                android.telecom.Call.Details details) {
            final Call call = mCallList.getCallByTelecommCall(telecomCall);
            ...
            for (InCallDetailsListener listener : mDetailsListeners) {           
                listener.onDetailsChanged(call, details);
            }
        }

        ...
    };
是个回调,注册方法为
    public void onCallAdded(android.telecom.Call call) {
        ...
        call.registerCallback(mCallCallback);
    }
被InCallServiceImpl调用
   @Override
    public void onCallAdded(Call call) {      
        if ((CallList.getInstance().getVideoUpgradeRequestCall() != null ||
                CallList.getInstance().getSendingVideoUpgradeRequestCall() != null)
                && !isEmergency(call)) {
            call.disconnect();          
            InCallUtils.showOutgoingFailMsg(getApplicationContext(), call);
        } else {
            CallList.getInstance().onCallAdded(call);
            InCallPresenter.getInstance().onCallAdded(call);
        }
    }

CallButtonPresenter、ConferenceManagerPresenter、VideoCallPresenter和ProximitySensor使用该接口

InCallOrientationListener

横竖屏切换
    public interface InCallOrientationListener {
        public void onDeviceOrientationChanged(int orientation);
    }
    private final Set<InCallOrientationListener> mOrientationListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<InCallOrientationListener, Boolean>(8, 0.9f, 1));
被调用方法
    public void onDeviceOrientationChange(int orientation) {
        for (InCallOrientationListener listener : mOrientationListeners) {
            listener.onDeviceOrientationChanged(orientation);
        }
    }
本应该是InCallActivity中调用的,不过mtk目前代码中是注释掉的状态
private void doOrientationChanged(int rotation) 
VideoCallPresenter中使用

InCallEventListener

通知视频通话全屏显示的状态变化
    public interface InCallEventListener {
        public void onFullscreenModeChanged(boolean isFullscreenMode);
    }
    private final Set<InCallEventListener> mInCallEventListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<InCallEventListener, Boolean>(8, 0.9f, 1));
被调用方法
    public void notifyFullscreenModeChange(boolean isFullscreenMode) {
        for (InCallEventListener listener : mInCallEventListeners) {
            listener.onFullscreenModeChanged(isFullscreenMode);
        }
    }
被调用方法
 public boolean toggleFullscreenMode() {
        mIsFullScreen = !mIsFullScreen;
        Log.v(this, "toggleFullscreenMode = " + mIsFullScreen);
        notifyFullscreenModeChange(mIsFullScreen);
        return mIsFullScreen;
    }

    public void setFullScreen(boolean isFullScreen) {
        Log.v(this, "setFullScreen = " + isFullScreen);
        if (mIsFullScreen == isFullScreen) {
            Log.v(this, "setFullScreen ignored as already in that state.");
            return;
        }
        mIsFullScreen = isFullScreen;
        notifyFullscreenModeChange(mIsFullScreen);
    }
CallCardPresenter和VideoCallPresenter中使用

InCallUiListener

通知通话UI是否要在前台显示或退出前台
    public interface InCallUiListener {
        void onUiShowing(boolean showing);
    }
    private final Set<InCallUiListener> mInCallUiListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<InCallUiListener, Boolean>(8, 0.9f, 1));
被调用方法
public void onUiShowing(boolean showing) {
        ...
        for (InCallUiListener listener : mInCallUiListeners) {
            listener.onUiShowing(showing);          
        }
        ...
    }
InCallActivity的onResume和onPause调用
实现这个接口的的地方是AnswerPresenter和VideoPauseController

InCallVideoCallListener

通知视频通话中是否开启摄像头和要退出全屏通话状态
    public interface InCallVideoCallListener {
        void onHidePreviewRequest(boolean hide);
        void disbaleFullScreen();
    }
    private final Set<InCallVideoCallListener> mInCallVideoCallListener = Collections.newSetFromMap(
            new ConcurrentHashMap<InCallVideoCallListener, Boolean>(8, 0.9f, 1));
被调用方法
    public void notifyHideLocalVideoChanged(boolean hide) {
        for (InCallVideoCallListener listener : mInCallVideoCallListener) {
            listener.onHidePreviewRequest(hide);
        }

    }

    public void notifyDisableVideoCallFullScreen() {
        for (InCallVideoCallListener listener : mInCallVideoCallListener) {
            listener.disbaleFullScreen();
        }
    }
notifyHideLocalVideoChanged被CallButtonFragment的onClick(打开或关闭摄像头),notifyDisableVideoCallFullScreen被CallButtonFragment的onClick(能点击证明肯定不是全屏状态)和InCallActivity的onStop(要退出全屏状态)
VideoCallPresenter中使用

PhoneRecorderListener

更新通话录音Ui
    public interface PhoneRecorderListener {
        public void onUpdateRecordState(int state, int customValue);
    }
  private final ArrayList<PhoneRecorderListener> mPhoneRecorderListeners = Lists.newArrayList();
被调用方法
    public void onUpdateRecordState(int state, int customValue) {
        Log.i(this, "onUpdateRecordState: state = " + state + " ;customValue = " + customValue);
        mRecordingState = state;
        for (PhoneRecorderListener listener : mPhoneRecorderListeners) {
            listener.onUpdateRecordState(state, customValue);
        }
    }
CallCardlPresenter和CallButtonPresenter中使用

CallList

代码在packages/apps/InCallUI/src/com/android/incallui/CallList.java,维护了Telecom模块上报的通话信息,以Call的形式,所以名称叫CallList。

Listener

  public interface Listener {
        /**
         * Called when a new incoming call comes in.
         * This is the only method that gets called for incoming calls. Listeners
         * that want to perform an action on incoming call should respond in this method
         * because {@link #onCallListChange} does not automatically get called for
         * incoming calls.
         */
        public void onIncomingCall(Call call);
        /**
         * Called when a new modify call request comes in
         * This is the only method that gets called for modify requests.
         */
        public void onUpgradeToVideo(Call call);
        /**
         * Called anytime there are changes to the call list.  The change can be switching call
         * states, updating information, etc. This method will NOT be called for new incoming
         * calls and for calls that switch to disconnected state. Listeners must add actions
         * to those method implementations if they want to deal with those actions.
         */
        public void onCallListChange(CallList callList);

        /**
         * Called when a call switches to the disconnected state.  This is the only method
         * that will get called upon disconnection.
         */
        public void onDisconnect(Call call);

        /// M: Add for recording. @{
        public void onStorageFull();
        public void onUpdateRecordState(final int state, final int customValue);
        /// @}
    }
    private final Set<Listener> mListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
InCallPresenter实现该接口,并在setUp中注册监听
        mCallList.addListener(this);
这个通知调用的地方众多,拿最常用的路径举例:
    private void notifyGenericListeners() {
        for (Listener listener : mListeners) {
            listener.onCallListChange(this);
        }
    }
   public void onUpdate(Call call) {
        onUpdateCall(call);
        notifyGenericListeners();
    }
packages/apps/InCallUI/src/com/android/incallui/Call.java
 private android.telecom.Call.Callback mTelecomCallCallback =
            new android.telecom.Call.Callback() {
                @Override
                public void onStateChanged(android.telecom.Call call, int newState) {
                    Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " newState="
                            + newState);
                    InCallTrace.begin("telecomStateChanged");
                    update();
                    InCallTrace.end("telecomStateChanged");
                }

                @Override
                public void onParentChanged(android.telecom.Call call,
                        android.telecom.Call newParent) {
                    Log.d(this, "TelecommCallCallback onParentChanged call=" + call + " newParent="
                            + newParent);
                    update();
                }

                @Override
                public void onChildrenChanged(android.telecom.Call call,
                        List<android.telecom.Call> children) {
                    /// M: for VOLTE @{
                    handleChildrenChanged();
                    /// @}
                    update();
                }

                @Override
                public void onDetailsChanged(android.telecom.Call call,
                        android.telecom.Call.Details details) {
                    Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " details="
                            + details);
                    InCallTrace.begin("telecomDetailsChanged");
                    update();
                    InCallTrace.end("telecomDetailsChanged");
                    /// M: for VOLTE @{
                    handleDetailsChanged(details);
                    /// @}
                }

                @Override
                public void onCannedTextResponsesLoaded(android.telecom.Call call,
                        List<String> cannedTextResponses) {
                    Log.d(this, "TelecommCallCallback onStateChanged call=" + call
                            + " cannedTextResponses=" + cannedTextResponses);
                    update();
                }

                @Override
                public void onPostDialWait(android.telecom.Call call,
                        String remainingPostDialSequence) {
                    Log.d(this, "TelecommCallCallback onStateChanged call=" + call
                            + " remainingPostDialSequence=" + remainingPostDialSequence);
                    update();
                }

                @Override
                public void onVideoCallChanged(android.telecom.Call call,
                        VideoCall videoCall) {
                    Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " videoCall="
                            + videoCall);
                    update();
                }

                ...

                @Override
                public void onConferenceableCallsChanged(android.telecom.Call call,
                        List<android.telecom.Call> conferenceableCalls) {
                    update();
                }
            };
该回调可以看到众多引起Call变化的原因,它是在Call构造函数中注册的
   public Call(android.telecom.Call telecommCall) {
        mTelecommCall = telecommCall;
        mId = ID_PREFIX + Integer.toString(sIdCounter++);
        updateFromTelecommCall();
        mTelecommCall.registerCallback(mTelecomCallCallback);
        ...
    }
这样Call有任何变化都会通知已注册的对象。

CallUpdateListener

   public interface CallUpdateListener {
        public void onCallChanged(Call call);
        public void onSessionModificationStateChange(int sessionModificationState);
    }
    private final HashMap<String, List<CallUpdateListener>> mCallUpdateListenerMap = Maps
            .newHashMap();
被调用路径
   public void onSessionModificationStateChange(Call call, int sessionModificationState) {
        final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId());
        if (listeners != null) {
            for (CallUpdateListener listener : listeners) {
                listener.onSessionModificationStateChange(sessionModificationState);
            }
        }
    }

    public void notifyCallUpdateListeners(Call call) {
        final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId());
        if (listeners != null) {
            for (CallUpdateListener listener : listeners) {
                listener.onCallChanged(call);
            }
        }
    }
onSessionModificationStateChange被Call调用,
  public void setSessionModificationState(int state) { 
        ...
        if (hasChanged) {
            CallList.getInstance().onSessionModificationStateChange(this, state);
        }
        ...
    }
该方法调用地方很多,都是音频和视频通话切换的地方。
notifyCallUpdateListeners调用链最后还是追述到刚才讲的mTelecomCallCallback中
众多xxxPresenter都有注册它,不过注册的地方都不在onUiReady方法中。其它类中都是空实现,只有AnswerPresenter确切实现了onCallChanged,主要功能是用于更新短信拒接的内容。

吐槽

可以看出接口很多很复杂很头晕。
1.CanAddCallListener,为啥要单独定义这么个接口给CallButton用,onStateChange也在更新通话状态呀,这个是多余的接口
2.IncomingCallListener,为啥要单独定义这个接口,这个和InCallStateListener对比只是Call的状态不同,而且只在添加通话的时候调用一次,代码中基本都是IncomingCallListener和InCallStateListener要同时实现,有什么意义吗?
CallCardPresenter中的实现:
   @Override
    public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
        // same logic should happen as with onStateChange()
        onStateChange(oldState, newState, CallList.getInstance());
    }
CallButtonPresenter中的实现:
    @Override
    public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
        ...
        onStateChange(oldState, newState, CallList.getInstance());
    }
StatusBarNotifier中实现
    @Override
    public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
        ...
            updateNotification(newState, CallList.getInstance());
        ...
    }
StatusBarNotifier中的InCallStateListener实现
@Override
    public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
        ...
        updateNotification(newState, callList);
    }
这个有意思吗?一个if语句的事甚至if都不用要单独一个接口
3.CallUpdateListener ,一堆类实现它,为啥都是空方法?只有一个AnswerPresenter不是空方法,看了代码有必要单独写个接口?更新短信拒接的内容和UI是依据号码就能完成的事情,只有在获取不到对方号码的时候才设置为不能短信拒接,至于短信内容这个是完全固定的。
4.AnswerPresenter 实现了CallList.Listener,这个有点破坏了InCallUI的代码设计,Presenter获取通知应该只和InCallPresenter打交道才对。不过这个是mtk为了视频通话加的,google原生没这样写。
5.和通话状态无关的事件,例如InCallOrientationListener和InCallEventListener(横竖屏变化和退出全屏),可以用本地广播实现。和CallList和InCallPresenter完全没啥关系,实现的地方发送个广播,需要的地方接受广播就可以了。再说也并没有使用InCallOrientationListener,而是直接用了InCallPresenter中的方法:
    public void onDeviceRotationChange(int rotation) {
        if (mCallList != null) {
            mCallList.notifyCallsOfDeviceRotation(toRotationAngle(rotation));
        } 
    }
继而调用了CallList中的notifyCallsOfDeviceRotation:
 public void notifyCallsOfDeviceRotation(int rotation) {
        for (Call call : mCallById.values()) {
            if (call.getVideoCall() != null && CallUtils.isVideoCall(call)) {
                call.getVideoCall().setDeviceOrientation(rotation);
            }
        }
    }
其它的notify方法都是CallList通知InCallPresenter,而这个却是调用Call的方法,破坏了CallList的含义,它是被动接受Call变化并发送通知的这么一个类,却有了一个和Telecom通信的方法,应该把这个方法挪到TelecomAdapter中,TelecomAdapter才负责与Telecom通信。
总之接口漫天飞,有过度设计的嫌疑。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值