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目錄下也是合情合理的。
先不管是幹嘛的,後面已有程式碼更改 部分用到的話再看。
左側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();
}
}