這陣子公司安排進(jìn)行8.0的適配,就對比著代碼進(jìn)行差異化分析哼勇,發(fā)現(xiàn)InCallUi的變化很大莲绰,整體架構(gòu)變了吼畏,變的更加清晰。界面變的更加漂亮了懈万,跟之前的版本相比拴清,可以說的上是天壤之別啊。InCallUi8.0也增加了一些比較實(shí)用的功能会通,比如說是來電防誤觸口予。我們把手機(jī)放在口袋,這時(shí)候來電渴语,可能就會(huì)出現(xiàn)誤觸,將電話掛斷或者接聽昆咽,而我們可能并不知道驾凶,這明顯很不好。仔細(xì)的看了一下8.0防誤觸功能的實(shí)現(xiàn)掷酗,做一下筆記调违。
在AnswerScreenPresenter中的onCreate方法中,根據(jù)條件判斷決定是否將距離傳感器初始化好泻轰,AnswerScreenPresenter就相當(dāng)于之前版本的AnswerPresenter技肩。
PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
if (AnswerProximitySensor.shouldUse(context, call)) {
new AnswerProximitySensor(context, call, pseudoScreenState);
} else {
pseudoScreenState.setOn(true);
}
我們現(xiàn)在來看看詳細(xì)的判斷:
1.不是來電狀態(tài)
2.不允許使用來電傳感器
3.不支持距離傳感器
4.當(dāng)前狀態(tài)時(shí)亮屏
public static boolean shouldUse(Context context, DialerCall call) {
// Don't use the AnswerProximitySensor for call waiting and other states. Those states are
// handled by the general ProximitySensor code.
if (call.getState() != State.INCOMING) {
LogUtil.i("AnswerProximitySensor.shouldUse", "call state is not incoming");
return false;
}
if (!ConfigProviderBindings.get(context)
.getBoolean(CONFIG_ANSWER_PROXIMITY_SENSOR_ENABLED, true)) {
LogUtil.i("AnswerProximitySensor.shouldUse", "disabled by config");
return false;
}
if (!context
.getSystemService(PowerManager.class)
.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
LogUtil.i("AnswerProximitySensor.shouldUse", "wake lock level not supported");
return false;
}
if (isDefaultDisplayOn(context)) {
LogUtil.i("AnswerProximitySensor.shouldUse", "display is already on");
return false;
}
return true;
}
PseudoScreenState類的代碼如下:
public class PseudoScreenState {
/** Notifies when the on state has changed. */
public interface StateChangedListener {
void onPseudoScreenStateChanged(boolean isOn);
}
private final Set<StateChangedListener> listeners = new ArraySet<>();
private boolean on = true;
public boolean isOn() {
return on;
}
public void setOn(boolean value) {
if (on != value) {
on = value;
for (StateChangedListener listener : listeners) {
listener.onPseudoScreenStateChanged(on);
}
}
}
public void addListener(StateChangedListener listener) {
listeners.add(listener);
}
public void removeListener(StateChangedListener listener) {
listeners.remove(listener);
}
}
AnswerProximitySensor的構(gòu)造函數(shù)如下:
public AnswerProximitySensor(
Context context, Call call, PseudoScreenState pseudoScreenState) {
this.call = call;
Log.d("AnswerProximitySensor.constructor", "acquiring lock");
if (ConfigProviderBindings.get(context).getBoolean(CONFIG_ANSWER_PSEUDO_PROXIMITY_WAKE_LOCK_ENABLED, true)) {
answerProximityWakeLock = new PseudoProximityWakeLock(context, pseudoScreenState);
} else {
// TODO: choose a wake lock implementation base on framework/device.
// These bugs requires the PseudoProximityWakeLock workaround:
// b/30439151 Proximity sensor not working on M
// b/31499931 fautly touch input when screen is off on marlin/sailfish
answerProximityWakeLock = new SystemProximityWakeLock(context);
}
answerProximityWakeLock.setScreenOnListener(this);
answerProximityWakeLock.acquire();
CallList.getInstance().addListener(this);
}
在電話狀態(tài)發(fā)生改變和遠(yuǎn)離距離傳感器的情況下,將
在InCallActiivityde onResume方法中進(jìn)行了調(diào)用:
PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
pseudoScreenState.addListener(this);
onPseudoScreenStateChanged(pseudoScreenState.isOn());
在onPause方法中將監(jiān)聽移除:
InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
在InCallActivity中浮声,pseudoBlackScreenOverlay是一個(gè)黑色的浮層虚婿,當(dāng)滿足來電防誤觸的情況下時(shí),將浮層設(shè)置為VISIBLE泳挥,使得觸摸事件不響應(yīng)然痊,同時(shí)在dispatchTouchEvent方法中,直接返回true屉符,不繼續(xù)分發(fā)觸摸事件
private View pseudoBlackScreenOverlay;
private boolean touchDownWhenPseudoScreenOff;
@Override
public void onPseudoScreenStateChanged(boolean isOn) {
Log.d("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// Reject any gesture that started when the screen is in the fake off state.
if (touchDownWhenPseudoScreenOff) {
if (event.getAction() == MotionEvent.ACTION_UP) {
touchDownWhenPseudoScreenOff = false;
}
return true;
}
// Reject all touch event when the screen is in the fake off state.
if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
touchDownWhenPseudoScreenOff = true;
Log.d("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
}
return true;
}
return super.dispatchTouchEvent(event);
}