Android8.0来电防误触

2017-11-15  本文已影响0人  嚣张鱼

这阵子公司安排进行8.0的适配,就对比着代码进行差异化分析,发现InCallUi的变化很大,整体架构变了,变的更加清晰。界面变的更加漂亮了,跟之前的版本相比,可以说的上是天壤之别啊。InCallUi8.0也增加了一些比较实用的功能,比如说是来电防误触。我们把手机放在口袋,这时候来电,可能就会出现误触,将电话挂断或者接听,而我们可能并不知道,这明显很不好。仔细的看了一下8.0防误触功能的实现,做一下笔记。

在AnswerScreenPresenter中的onCreate方法中,根据条件判断决定是否将距离传感器初始化好,AnswerScreenPresenter就相当于之前版本的AnswerPresenter。

    PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
    if (AnswerProximitySensor.shouldUse(context, call)) {
      new AnswerProximitySensor(context, call, pseudoScreenState);
    } else {
      pseudoScreenState.setOn(true);
    }

我们现在来看看详细的判断:
1.不是来电状态
2.不允许使用来电传感器
3.不支持距离传感器
4.当前状态时亮屏

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的构造函数如下:

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

在电话状态发生改变和远离距离传感器的情况下,将
在InCallActiivityde onResume方法中进行了调用:

PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
pseudoScreenState.addListener(this);
onPseudoScreenStateChanged(pseudoScreenState.isOn());

在onPause方法中将监听移除:

InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);

在InCallActivity中,pseudoBlackScreenOverlay是一个黑色的浮层,当满足来电防误触的情况下时,将浮层设置为VISIBLE,使得触摸事件不响应,同时在dispatchTouchEvent方法中,直接返回true,不继续分发触摸事件

    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);
    }
上一篇下一篇

猜你喜欢

热点阅读