与Dialer相关的ProximitySensor传感器

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 17:54   1646   0

一开始想,既然视频通话永远不灭,语音通话关闭免提会灭屏。那么就想,应该是会灭屏情况,调用SensorManager的registerListener;永不灭屏时,根本调用unRegisterListener。Sensor的类型是TYPE_PROXIMITY。 但是这么搜索没有收获。

Dialer中ProximitySensor.java等文件也和距离传感器有关。但是逻辑较多没有找到入口。

后来才知道,原来我搜索的方法太底层了。拨号盘在某些地方的距离传感器灭屏功能是用SensorManager registerListener实现。

而此问题的功能拨号盘是用PowerManager的WakeLOCK 功能实现。

怎么定位的呢,用老方法,抓对比log,看看log有什么差异吧。

拨号盘通话过程中靠近灭屏的代码入口

果真抓音频和视频通话 关闭打开外放,手靠近和远离时的log。通过audio,earpiece等关键字查询,有如下明显差异。

一个打开传感器,一个关闭传感器。从上面变量查看,screenOnImmediately变量有差异。然后查看代码,问题果真在这里。

#语音通话关闭外放
08-24 09:42:46.135 2688 2688 I Dialer : CallButtonPresenter.setAudioRoute - sending new audio route: EARPIECE, WIRED_HEADSET
08-24 09:42:46.143 2688 2688 I Dialer : ProximitySensor.updateProximitySensorMode - screenOnImmediately: false, dialPadVisible: false, offHook: true, horizontal: true, uiShowing: true, audioRoute: EARPIECE
08-24 09:42:46.143 2688 2688 V Dialer : ProximitySensor.updateProximitySensorMode - turning on proximity sensor
08-24 09:42:46.143 2688 2688 I Dialer : ProximitySensor.turnOnProximitySensor - acquiring wake lock

#视频通话关闭外放
08-24 10:02:33.096 2698 2698 I Dialer : SpeakerButtonController.setSupportedAudio - audioState: [AudioState isMuted: false, route: EARPIECE, supportedRouteMask: EARPIECE, SPEAKER]
08-24 10:02:33.095 2698 2698 I Dialer : ProximitySensor.updateProximitySensorMode - screenOnImmediately: true, dialPadVisible: false, offHook: true, horizontal: true, uiShowing: true, audioRoute: EARPIECE
08-24 10:02:33.095 2698 2698 V Dialer : ProximitySensor.updateProximitySensorMode - turning off proximity sensor
08-24 10:02:33.096 2698 2698 I Dialer : ProximitySensor.turnOffProximitySensor - wake lock already released

代码如下,在updateProximitySensorMode函数中,判断是否开启基于距离传感器的亮灭屏功能,设置screenOnImmediately。

如果是通话中,并且screenOnImmediately 为false,则开启距离传感器的亮灭屏功能。否则关闭距离传感器功能,则靠近屏幕不会息屏。

视频通话时,mIsVideoCall 是true。则screenOnImmediately是TRUE,所以关闭距离传感器功能。

通话靠近远离亮灭屏功能开启和关闭分别由turnOnProxmitySensor()和turnOnProxmitySensor()

PowerManager的WakeLOCK

接下来看看turnOnProximitySensor() 和turnOffProximitySensor()函数。

顾名思义,是打开和关闭距离传感器。如何做到呢?就是通过PowerManger提供的WakeLock接口实现的。

当然其实也可以直接通过SensorManager(TYPE_PROXIMITY)的registerListener()来开启远近事件的监听,在监听回调中根据远近触发亮灭屏。

不过PowerManager提供的WakeLock封装了不同级别的亮灭屏方案,其中就包括距离传感器触发亮灭屏。

WakeLock的类型需要选择为PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK。打开就是WakeLock.acquire,关闭就是WakeLock.release。 代码如下:

WakeLOCK类别

WakeLock 分类如下:

  • PARTIAL_WAKE_LOCK: 灭屏,关闭键盘背光的情况下,CPU依然保持运行。
  • PROXIMITY_SCREEN_OFF_WAKE_LOCK: 基于距离感应器熄灭屏幕。最典型的运用场景是我们贴近耳朵打电话时,屏幕会自动熄灭。
  • SCREEN_DIM_WAKE_LOCK/SCREEN_BRIGHT_WAKE_LOCK/FULL_WAKE_LOCK:这三种WakeLock都已经过时了,它们的目的是为了保持屏幕长亮,Android官方建议用getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);方式替换。因为比起申请WakeLock,这种方式更简单,还不需要特别申请android.permission.WAKE_LOCK权限。
  • DOZE_WAKE_LOCK/DRAW_WAKE_LOCK: 隐藏的分类,系统级别才会用到。DreamMan监听移除:

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

    链接:https://www.jianshu.com/p/f9ff07f56fe3

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP