通話中自動關閉螢幕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
著作權,轉載請註明出處:http://www.jwisp.com/?p=102