当前位置: 首页 > 工具软件 > psensor > 使用案例 >

Android距离感应器P-Sensor浅析

毛勇
2023-12-01
(一)  前言
P-Sensor,距离感应器,可以感应手机和人体距离。具体使用用途是在通话过程中打开P-Sensor,那么当手机屏幕贴近用户脸部时,就会自动感应出手机和人体距离是多少。当小于某一个值时,就会熄灭屏幕,不再接收用户触摸屏幕事件,从而有效的防止通话过程中误触摸事件的出现。(有很多人通话过程中脸部会触碰到挂断键,从而导致通话中断有没有? ^_^)。

(二)  打开P-Sensor
刚才我们讲了,P-Sensor主要用于通话过程中防止用户误操作屏幕,那么我们就以通话过程为例,看看电话程序为P-Sensor做了什么。
a.  电话程序在启动的时候,在PhoneApp.java里面新建了一个P-Sensor的wackLock对象,如下:
  1. [/color][/size]
  2. [backcolor=rgb(255,255,255)][size=12px]mProximityWakeLock =  pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG);
  3. [/size][/backcolor]
  4. [size=3][color=#0000ff]
复制代码

其实,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:
  1. [/color][/size]
  2. [backcolor=rgb(255,255,255)][size=12px]if (!mProximityWakeLock.isHeld()) {
  3.                         if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
  4.                         mProximityWakeLock.acquire();
  5.                     }
  6. [/size][/backcolor]
  7. [size=3][color=#0000ff]
复制代码

其中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检测到距离有变化时发生。
  1. [/color][/size]
  2. [backcolor=rgb(255,255,255)][size=12px]SensorEventListener mProximityListener = new SensorEventListener() {
  3.         public void onSensorChanged(SensorEvent event) {
  4.             long milliseconds = SystemClock.elapsedRealtime();
  5.             synchronized (mLocks) {
  6.                 float distance = event.values[0];  //检测到手机和人体的距离
  7.                 long timeSinceLastEvent = milliseconds - mLastProximityEventTime;  //这次检测和上次检测的时间差
  8.                 mLastProximityEventTime = milliseconds;  //更新上一次检测的时间
  9.                 mHandler.removeCallbacks(mProximityTask); 
  10.                 boolean proximityTaskQueued = false;

  11.                 // compare against getMaximumRange to support sensors that only return 0 or 1
  12.                 boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
  13.                         distance < mProximitySensor.getMaximumRange());  //如果距离小于某一个距离阈值,默认是5.0f,说明手机和脸部距离贴近,应该要熄灭屏幕。

  14.                 if (mDebugProximitySensor) {
  15.                     Slog.d(TAG, "mProximityListener.onSensorChanged active: " + active);
  16.                 }
  17.                 if (timeSinceLastEvent < PROXIMITY_SENSOR_DELAY) {
  18.                     // enforce delaying atleast PROXIMITY_SENSOR_DELAY before processing
  19.                     mProximityPendingValue = (active ? 1 : 0);
  20.                     mHandler.postDelayed(mProximityTask, PROXIMITY_SENSOR_DELAY - timeSinceLastEvent);
  21.                     proximityTaskQueued = true;
  22.                 } else {
  23.                     // process the value immediately
  24.                     mProximityPendingValue = -1;
  25.                     proximityChangedLocked(active);   //熄灭屏幕操作
  26.                 }

  27.                 // update mProximityPartialLock state
  28.                 boolean held = mProximityPartialLock.isHeld();
  29.                 if (!held && proximityTaskQueued) {
  30.                     // hold wakelock until mProximityTask runs
  31.                     mProximityPartialLock.acquire();
  32.                 } else if (held && !proximityTaskQueued) {
  33.                     mProximityPartialLock.release();
  34.                 }
  35.             }
  36.         }

  37.         public void onAccuracyChanged(Sensor sensor, int accuracy) {
  38.             // ignore
  39.         }
  40.     };
  41. [/size][/backcolor]
  42. [size=3][color=#0000ff]
复制代码

代码里面我已经有一些注释,下面来用文字描述下。
a.  首先会拿到这测距离变化的距离,float distance = event.values[0];
b.  检测这次距离变化和上次距离变化时间差,如果小于系统设置的阈值,则不会去熄灭屏幕。过于频繁的操作系统会忽略掉。 所以,如果你感觉P-Sensor不够灵敏,就可以修改这个系统默认值

  1. [/color][backcolor=rgb(255,255,255)][size=12px]private static final int PROXIMITY_SENSOR_DELAY = 1000;
  2. [/size][/backcolor]
  3. [color=#0000ff]
复制代码

如果你改的很小,就会发现P-Sensor会变得灵敏很多。。。
c.  嗯,如果P-Sensor检测到这次距离变化小于系统默认值,且这次是一次正常的变化,那么就应该去熄灭屏幕:
  1. [/color][/size]
  2. proximityChangedLocked(active);
  3. [/size][/backcolor]
  4. [color=#0000ff]
复制代码

这里的active是true,同样,在这里它还会判断P-Sensor是否可以用,如果不可用,则返回。。忽略这次距离变化
  1. [/color][/size]
  2. [backcolor=rgb(255,255,255)][size=12px]if (!mProximitySensorEnabled) {
  3.             Slog.d(TAG, "Ignoring proximity change after sensor is disabled");
  4.             return;
  5.         }
  6. [/size][/backcolor]

  7. [color=#0000ff]
复制代码

如果一切都满足,则调用:
  1. [/color][/size]
  2. [backcolor=rgb(255,255,255)][size=12px]goToSleepLocked(SystemClock.uptimeMillis(),
  3.                         WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
  4. [/size][/backcolor]
  5. [color=#0000ff]
复制代码

熄灭屏幕。。

当然了,这里面还有很多,比较复杂,如果大家有兴趣,可以把系统源代码下载下来,慢慢研究啦~
 类似资料: