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