Android距離感應器P-Sensor淺析

(一)  前言
P-Sensor,距離感應器,能夠感應手機和人體距離。具體使用用途是在通話過程當中打開P-Sensor,那麼當手機屏幕貼近用戶臉部時,就會自動感應出手機和人體距離是多少。當小於某一個值時,就會熄滅屏幕,再也不接收用戶觸摸屏幕事件,從而有效的防止通話過程當中誤觸摸事件的出現。(有不少人通話過程當中臉部會觸碰到掛斷鍵,從而致使通話中斷有沒有? ^_^)。

(二)  打開P-Sensor
剛纔咱們講了,P-Sensor主要用於通話過程當中防止用戶誤操做屏幕,那麼咱們就以通話過程爲例,看看電話程序爲P-Sensor作了什麼。
a.  電話程序在啓動的時候,在PhoneApp.java裏面新建了一個P-Sensor的wackLock對象,以下:
複製內容到剪貼板
代碼:
mProximityWakeLock =  pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG);
其實,wackLock這個東東咱們之前講過,它是用來請求控制屏幕點亮和熄滅的一個東東, 具體能夠看這個帖子: http://bbs.51cto.com/thread-1018050-1.html

b.  ok,那既然咱們擁有了這個關於P-Sensor對象,怎麼使用它呢?
在電話狀態發生改變的時候,好比,接通了電話,它就會調用PhoneApp.java的updateProximitySensorMode(Phone.State state)方法,這個方法會根據當前電話的狀態,決定要不要打開P-Sensor,
那麼若是在通話過程當中,電話也就是OFF-HOOK狀態,嗯,打開P-Sensor:
複製內容到剪貼板
代碼:
if (!mProximityWakeLock.isHeld()) {
                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
                        mProximityWakeLock.acquire();
                    }
其中mProximityWakeLock.acquire();會展轉調用到PowerManagerService.java的enableProximityLockLocked()方法,顧名思義,這個方法是打開P-Sensor,是的!這個方法會去判斷當前手機有沒有P-Sensor,若是有的話,就會去向SensorManager註冊一個P-Sensor監聽器,那麼當P-Sensor檢測到手機和人體距離發生改變時,就會調用咱們PowerManagerService.java的監聽器.一樣,當電話掛斷時,電話模塊會去調用mProximityWakeLock.release(flags), 這樣就會取消P-Sensor監聽器.
ok.. 那麼接下來就是分析PowerManagerService裏面這個P-Sensor是怎麼工做的。



(三)   PowerManagerService裏面P-Sensor監聽器工做原理
監聽器的代碼,當P-Sensor檢測到距離有變化時發生。
複製內容到剪貼板
代碼:
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;

                // compare against getMaximumRange to support sensors that only return 0 or 1
                boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
                        distance < mProximitySensor.getMaximumRange());  //若是距離小於某一個距離閾值,默認是5.0f,說明手機和臉部距離貼近,應該要熄滅屏幕。

                if (mDebugProximitySensor) {
                    Slog.d(TAG, "mProximityListener.onSensorChanged active: " + 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);   //熄滅屏幕操做
                }

                // update mProximityPartialLock state
                boolean held = mProximityPartialLock.isHeld();
                if (!held && proximityTaskQueued) {
                    // hold wakelock until mProximityTask runs
                    mProximityPartialLock.acquire();
                } else if (held && !proximityTaskQueued) {
                    mProximityPartialLock.release();
                }
            }
        }

        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // ignore
        }
    };
代碼裏面我已經有一些註釋,下面來用文字描述下。
a.  首先會拿到這測距離變化的距離,float distance = event.values[0];
b.  檢測此次距離變化和上次距離變化時間差,若是小於系統設置的閾值,則不會去熄滅屏幕。過於頻繁的操做系統會忽略掉。 因此,若是你感受P-Sensor不夠靈敏,就能夠修改這個系統默認值
複製內容到剪貼板
代碼:
private static final int PROXIMITY_SENSOR_DELAY = 1000;
若是你改的很小,就會發現P-Sensor會變得靈敏不少。。。
c.  嗯,若是P-Sensor檢測到此次距離變化小於系統默認值,且此次是一次正常的變化,那麼就應該去熄滅屏幕:
複製內容到剪貼板
代碼:
proximityChangedLocked(active);
這裏的active是true,一樣,在這裏它還會判斷P-Sensor是否能夠用,若是不可用,則返回。。忽略此次距離變化
複製內容到剪貼板
代碼:
if (!mProximitySensorEnabled) {
            Slog.d(TAG, "Ignoring proximity change after sensor is disabled");
            return;
        }
若是一切都知足,則調用:
複製內容到剪貼板
代碼:
goToSleepLocked(SystemClock.uptimeMillis(),                         WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
熄滅屏幕。。
相關文章
相關標籤/搜索