天天看點

Android N 與Android M InCallUI代碼對比(基于CM)

今天是2016.11.30,google已經開始推送android 7.1了。

我們都知道其實7.0早就放出來了,那為什麼我現在才寫7.1的源碼閱讀分析呢?

因為等了高通兩個月N的代碼,他們遲遲不給我們。那我隻有看CM的了。

下面内容以CM 14.1和CM 13.0(對應android 6.0和android7.1)的InCallUI相比較,解讀一下這兩個版本之間的差異。都是以目前最新的代碼為基礎比較的,是以很可能這個CM 13.0上有些代碼,你們的代碼還沒有包含進去。

不會寫的很詳細,寫的都是我之前版本關注過的地方。

最明顯的就是InCallUI的目錄換位置了,其實我們都知道。之前InCallUI之前都是編譯到Dialerapk裡面的,而且也是泡在dialer程序裡面的,那現在把InCallUI移動到Dialer目錄下也是合情合理的。

新增java檔案一堆 。

先不管是幹嘛的,後面已有代碼更改 部分用到的話再看。

左側CM 14.1,右側CM 13.0。

Android N 與Android M InCallUI代碼對比(基于CM)

AnswerPresenter.java

中很多通過mCalls得到SubId和PhoneId的地方被換成了QtiCallUtils,估計是QCOM改的。

Android N 與Android M InCallUI代碼對比(基于CM)

QtiCallUtils.java

可以看到用的是反射的方法得到subId,PhoneId等,而從送出記錄來看修改是for DSDA。

static int getPhoneId(int subId) {
        try {
            Class c = Class.forName("android.telephony.SubscriptionManager");
            Method m = c.getMethod("getPhoneId",new Class[]{int.class});
            int phoneId = (Integer)m.invoke(null, subId);
            if (phoneId >= InCallServiceImpl.sPhoneCount || phoneId < 0) {
                phoneId = 0;
            }
            Log.d (LOG_TAG, "phoneid:" + phoneId);
            return phoneId;
        } catch (Exception e) {
            Log.e(LOG_TAG, " ex: " + e);
        }
        return 0;
    }

    static int getSubId(int phoneId) {
        try {
            Class c = Class.forName("android.telephony.SubscriptionManager");
            Method m = c.getMethod("getSubId",new Class[]{int.class});
            int subId[] = (int[])m.invoke(null, phoneId);
            Log.d (LOG_TAG, "getSubId:" + subId[0]);
            if (subId != null && subId.length > 0) {
                return subId[0];
            } else {
                Log.e(LOG_TAG, "subId not valid: " + subId);
            }
        } catch (Exception e) {
            Log.e(LOG_TAG, " ex: " + e);
        }
        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    }

    static void switchToActiveSub(int subId) {
        try {
            IExtTelephony mExtTelephony = getIExtTelephony();
            Log.d(LOG_TAG, "switchToActiveSub, mExtTelephony:" + mExtTelephony);
            mExtTelephony.switchToActiveSub(subId);
        } catch (RemoteException ex) {
            Log.e(LOG_TAG, "Exception : " + ex);
        } catch (NullPointerException ex) {
            Log.e(LOG_TAG, "Exception : " + ex);
        }
    }

    static int getPhoneCount(Context context) {
        TelephonyManager tm = null;
        try {
            Class c = Class.forName("android.telephony.TelephonyManager");
            Method m = c.getMethod("from",new Class[]{Context.class});
            tm = (TelephonyManager)m.invoke(null, context);
        } catch (Exception e) {
            Log.e(LOG_TAG, " ex: " + e);
        }
        if (tm != null) {
            return tm.getPhoneCount();
        } else {
            Log.e(LOG_TAG, "tm is null" );
            return 1;
        }
    }

    static Boolean dsdaEnabled = null;
    static boolean isDsdaEnabled() {
        try {
            if (dsdaEnabled == null) {
                IExtTelephony mExtTelephony = getIExtTelephony();
                Log.d(LOG_TAG, "isDsdaEnabled, mExtTelephony:" + mExtTelephony);
                dsdaEnabled = mExtTelephony.isDsdaEnabled();
                return dsdaEnabled;
            }
        } catch (RemoteException ex) {
            Log.e(LOG_TAG, "Exception : " + ex);
        } catch (NullPointerException ex) {
            Log.e(LOG_TAG, "Exception : " + ex);
        }
        return (dsdaEnabled == null) ? false : dsdaEnabled;
    }
           

Call.java

黑名單功能。可以看出一個趨勢,CM在歸屬地和黑名單這倆功能上越做越好了。歸屬地這個有點屬于中國特色功能,也是前段時間才完善的。

Android N 與Android M InCallUI代碼對比(基于CM)

另外Call.java裡面把Telecomm都改成了Telecom,然後一些名為Modify的變量和方法改成了Request,比如 getModifyToVideoState()->getRequestedVideoState().新增 isIncomingConfCall()

CallButtonFragment.java

新增BUTTON_DOWNGRADE_TO_AUDIO看來是要把modify差分成upgrade和downgrade,與downgrade相對應的ImageButton是mChangeToVoiceButton。

CallButtonPresenter.java

mergeClicked()方法裡對參與者數量加了判斷,達到最大值後不再允許合并了。

Android N 與Android M InCallUI代碼對比(基于CM)

新增changeToVideo()方法,之前升降級由同一個button負責

Android N 與Android M InCallUI代碼對比(基于CM)

CallCardPresenter.java

加了個歸屬地相關的方法

Android N 與Android M InCallUI代碼對比(基于CM)

因為實作AudioModeListener,是以加了下面幾個方法

Android N 與Android M InCallUI代碼對比(基于CM)

哦?把音量增強(VB)的按鈕加進來了?

還真是

Android N 與Android M InCallUI代碼對比(基于CM)

CallList.java

新增一個方法

   public Call getSecondActiveCall() {
        return getCallWithState(Call.State.ACTIVE, 1);
    }
           

對了,record 錄音功能的代碼調整了一下

InCallActivity.java

增加dismiss SIM選擇框的邏輯(這個功能我踩過大坑!QAQ)

Android N 與Android M InCallUI代碼對比(基于CM)

這裡下面的InCallLoeBatteryListener應該是處理視訊電話中手機低電的情況,這塊我不熟,就不多說了

InCallAudioManager.java

新增一個方法來控制接通視訊電話後audio的狀态

Android N 與Android M InCallUI代碼對比(基于CM)

InCallPresenter.java

在onUpgradeToVideoRequest(Call call, int videoState)中曾加了wakeUpScreen();點亮螢幕的操作,之前是在 InCallVideoCallCallback.java中的onSessionModifyRequestReceived()調用InCallPresenter.getInstance().wakeUpScreen();實作的。

answerIncomingCall拆分成兩個方法,調用了 InCallAudioManager.getInstance().onAnswerIncomingCall(call, videoState);控制audio。

Android N 與Android M InCallUI代碼對比(基于CM)

增加一個無參數的declineUpgradeRequest(),避免context為空的情況(不止注釋裡面寫的情況,我今天就解了這麼一個bug)

   /*package*/
    void declineUpgradeRequest() {
        // Pass mContext if InCallActivity is destroyed.
        // Ex: When user pressed back key while in active call and
        // then modify request is received followed by MT call.
        declineUpgradeRequest(mInCallActivity != null ? mInCallActivity : mContext);
    }
           

看了代碼的話可以發現,接聽,拒接,更新,都有兩個同名的方法,參數都差一個。

StatusBarNotifier.java

這個厲害了,新增獲得VoWiFi通話品質的方法。目前看是在顯示Heads-up Notification的時候才調用,那接通電話以後呢?

Android N 與Android M InCallUI代碼對比(基于CM)

vowifi_in_call_fair.xml

Android N 與Android M InCallUI代碼對比(基于CM)

VideoCallFragment.java

新增長按點選事件

       /**
         * Handles a user long pressing on the surface, which is the trigger to show the
         * picture mode pop up alert dialog
         *
         * @param View The view receiving the long press.
         */
        @Override
        public boolean onLongClick(View v) {
            Log.d(this, "onLongClick:");
            return mPresenter.onLongClick();
        }
           

VideoCallPresenter.java

enterVideoMode()更名為adjustVideoMode()

長按事件的處理邏輯,目前還沒見過這個現象,不知道具體效果是什麼。

   /**
     * The function is called to create and display picture mode alert dialog when user long
     * presses on the video call screen
     */
     public boolean onLongClick() {
        // Don't show the alert if either the adb property "persist.disable.pip.mode" is not set
        // or if we are supposed to hide preview for conference calls
        if ((SystemProperties.getInt(PROP_DISABLE_VIDEOCALL_PIP_MODE, 0) == 0) ||
            shallHidePreview(isConfCall(), mCurrentVideoState)) {
            return false;
        }
        mPictureModeHelper.create(mContext);
        mPictureModeHelper.show();
        return true;
    }
           

新增shallHidePreview(),根據營運商判斷在視訊會議電話中是否要隐藏自己這邊的預覽視訊,Reliance在android M上就有隐藏的這個要求,高通平台還需要底層NV值有對應的修改

   /**
     * Hide preview window if it is a VT conference call
     */
    private boolean shallHidePreview(boolean isConf, int videoState) {
        return VideoProfile.isBidirectional(videoState) && isConf
                && QtiImsExtUtils.shallHidePreviewInVtConference(mContext);
    }
           

新增onSessionModificationStateChange()方法,配合其他代碼實作在收到視訊更新請求時,在點選接受之前預覽自己的視訊。

   @Override
    public void onSessionModificationStateChange(Call call, int sessionModificationState) {
        Log.d(this, "onSessionModificationStateChange : sessionModificationState = " +
                sessionModificationState + " call:" + call);
        if (call != mPrimaryCall ||
                (sessionModificationState == Call.SessionModificationState.NO_REQUEST)) {
            return;
        }
        if (!VideoProfile.isTransmissionEnabled(call.getRequestedVideoState())) {
           call.setRequestedVideoState(VideoProfile.STATE_AUDIO_ONLY);
           return;
        }

        if (sessionModificationState != Call.SessionModificationState.WAITING_FOR_RESPONSE) {
            call.setRequestedVideoState(VideoProfile.STATE_AUDIO_ONLY);
        }

        checkForVideoStateChange(call);

        if (sessionModificationState == Call.SessionModificationState.REQUEST_REJECTED
                || sessionModificationState == Call.SessionModificationState.REQUEST_FAILED
                || sessionModificationState ==
                Call.SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT) {
             mCurrentVideoState = call.getVideoState();
        }
    }
           

繼續閱讀