(一) 前言
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);
熄灭屏幕。。