卓派观点

通话中自动关闭屏幕proximit ysensor功能应用

在android中, 接近传感器(proximity sensor)在系统中唯一有用处的地方, 应该就是通话过程中, 为防止脸部触碰通话中界面按键, 而自动关闭屏幕.

下面jwisp从框架层来给大家分析一下, 这个功能是如何实现的

涉及类: PowerManagerService.java(frameworks\base\services\java\com\android\server\)

 分析时应首先想到, ProximityListener*********中的onSensorChanged是决定是否关闭或打开屏幕的入口, 我们来看看代码

    SensorEventListener mProximityListener = new SensorEventListener() {
        public void onSensorChanged(SensorEvent event) {
            long milliseconds = SystemClock.elapsedRealtime();
            synchronized (mLocks) {
                float distance = event.values[0];
                long timeSinceLastEvent = milliseconds - mLastProximityEventTime;
                mLastProximityEventTime = milliseconds;
                mHandler.removeCallbacks(mProximityTask);
                boolean proximityTaskQueued = false;

                boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
                        distance < mProximitySensor.getMaximumRange());
    
                if (timeSinceLastEvent < PROXIMITY_SENSOR_DELAY) {
                    mProximityPendingValue = (active ? 1 : 0);
                    mHandler.postDelayed(mProximityTask, PROXIMITY_SENSOR_DELAY - timeSinceLastEvent);
                    proximityTaskQueued = true;
                } else {
                    mProximityPendingValue = -1;
                    proximityChangedLocked(active);
                }

                boolean held = mProximityPartialLock.isHeld();
                if (!held && proximityTaskQueued) {
                    mProximityPartialLock.acquire();
                } else if (held && !proximityTaskQueued) {
                    mProximityPartialLock.release();
                }
            }
        }
    };

我们来逐行分析一下

            long milliseconds = SystemClock.elapsedRealtime();
            long timeSinceLastEvent = milliseconds - mLastProximityEventTime;
            mLastProximityEventTime = milliseconds;

           
milliseconds得到系统从启动到当前的时间(不论休眠与否)
mLastProximityEventTime为上次获得的milliseconds
timeSinceLastEvent 从上次事件发生到现在所间隔的时间, 也就是上面两个变量的相对时间.

 float distance = event.values[0];
 boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD && distance < mProximitySensor.getMaximumRange());

由distance获得psensor事件中感应到的距离值是多少

PROXIMITY_THRESHOLD为距离值达到多少才经行相应动作的阀值(门槛)

所以在下面的代码中, 将由active来决定是否需要关闭或打开屏幕

        if (timeSinceLastEvent < PROXIMITY_SENSOR_DELAY) {
            // enforce delaying atleast PROXIMITY_SENSOR_DELAY before processing
            mProximityPendingValue = (active ? 1 : 0);
            mHandler.postDelayed(mProximityTask, PROXIMITY_SENSOR_DELAY - timeSinceLastEvent);
            proximityTaskQueued = true;
        } else {
            // process the value immediately
            mProximityPendingValue = -1;
            proximityChangedLocked(active);
        }

PROXIMITY_SENSOR_DELAY为PowerMangerService设置的psensor感应延迟时间, 这里解决bug时会用的. 比如当你觉得通话中, psensor感应太慢, 如果能排除是驱动的问题, 那基本上就是这里设置的问题了.

jwisp这里的问题就是这样, 于是将默认的1000ms改成了100ms, 明显会感觉到psensor灵敏多了.

if判断两次事件发生的间距时间若小于延迟时间, 则由handler执行mProximityTask任务

若大于等于延迟时间, 则执行proximityChangedLocked()方法

我们来看一下mProximityTask是一个什么样的任务

    private Runnable mProximityTask = new Runnable() {
        public void run() {
            synchronized (mLocks) {
                if (mProximityPendingValue != -1) {
                    proximityChangedLocked(mProximityPendingValue == 1);
                    mProximityPendingValue = -1;
                }
                if (mProximityPartialLock.isHeld()) {
                    mProximityPartialLock.release();
                }
            }
        }
    };

看出来主要也是执行了proximityChangedLocked()方法

所以上面的if-else判断,只是判断是否需要延迟执行任务, 而不管延迟或不延迟, 都是需要执行proximityChangedLocked()方法的.

其实proximityChangedLocked()方法也是真正关闭开启屏幕的执行者

我们来看看它:

    private void proximityChangedLocked(boolean active) {
        if (!mProximitySensorEnabled) {
            return;
        }
        if (active) {
            if (!mProxIgnoredBecauseScreenTurnedOff) {
                goToSleepLocked(SystemClock.uptimeMillis(),
                        WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
            }
            mProximitySensorActive = true;
        } else {
            mProximitySensorActive = false;
            if (!mProxIgnoredBecauseScreenTurnedOff) {
                forceUserActivityLocked();
            }
            if (mProximityWakeLockCount == 0) {
                disableProximityLockLocked();
            }
        }
    }

意思很明显了, 如果active为true则执行goToSleepLocked()方法, 并设置ProximitySensorActive = true

如果为false则执行forceUserActivityLocked方法

在下一篇中, jwisp将深入分析这两个方法是怎么如何实现的.

移植总结:

若proximity sensor在接电话中反映太慢, 感觉不灵敏, 可以通过设置PROXIMITY_SENSOR_DELAY的值来调试, 若降低该值, 灵敏度提高, 基本上就可用确定不是驱动的问题了.

若距离太远, 屏幕就已经关闭, 则可通过设置距离传感器的阀值, 来调节在多远的距离可以关闭屏幕. 常量值为PROXIMITY_THRESHOLD 默认 = 5.0f

版权所有,转载请注明出处。
转载自 <a href="http://www.jwisp.com/?p=102" title="通话中自动关闭屏幕proximit ysensor功能分析" rel="bookmark">通话中自动关闭屏幕proximit ysensor功能分析 | 卓派</a>

我简单说几句


随机推荐

最新评论

固定链接

随机链接