通话中自动关闭屏幕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