美文网首页
Android8.0来电防误触

Android8.0来电防误触

作者: 嚣张鱼 | 来源:发表于2017-11-15 16:23 被阅读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);
        }
    

    相关文章

      网友评论

          本文标题:Android8.0来电防误触

          本文链接:https://www.haomeiwen.com/subject/yubamxtx.html