1. 程式人生 > >Android N 與Android M InCallUI程式碼對比(基於CM)

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。


AnswerPresenter.java

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


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在歸屬地和黑名單這倆功能上越做越好了。歸屬地這個有點屬於中國特色功能,也是前段時間才完善的。


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

CallButtonFragment.java

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

CallButtonPresenter.java

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


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


CallCardPresenter.java

加了個歸屬地相關的方法


因為實現AudioModeListener,所以加了下面幾個方法


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

還真是


CallList.java

新增一個方法

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

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

InCallActivity.java

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


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

InCallAudioManager.java

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


InCallPresenter.java

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

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


增加一個無引數的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的時候才呼叫,那接通電話以後呢?


vowifi_in_call_fair.xml


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