结合源码探讨Android距离传感器亮灭屏机制
来源:互联网 发布:张爱玲感情 知乎 编辑:程序博客网 时间:2024/06/05 02:09
本文的分析是基于Android 5.0.0 Google原生代码的。
Android中的距离传感器,也就是P-sensors(Proximity Sensors),与G-sensor重力传感器所对应。最常见的应用场景在于,当使用安卓手机接听电话时,贴近屏幕时,屏幕会灭屏,以防止脸部触碰屏幕引起误操作。当我们的脸离开屏幕时,屏幕会自动亮屏,方便我们操作手机,打开键盘输入指令。
开启和关闭距离传感器的方法位于DisplayPowerController的updatePowerState()方法当中。
private void setProximitySensorEnabled(boolean enable) { if (enable) { if (!mProximitySensorEnabled) { // Register the listener. // Proximity sensor state already cleared initially. mProximitySensorEnabled = true; mSensorManager.registerListener(mProximitySensorListener, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL, mHandler); } } else { if (mProximitySensorEnabled) { // Unregister the listener. // Clear the proximity sensor state for next time. mProximitySensorEnabled = false; mProximity = PROXIMITY_UNKNOWN; mPendingProximity = PROXIMITY_UNKNOWN; mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); mSensorManager.unregisterListener(mProximitySensorListener); clearPendingProximityDebounceTime(); // release wake lock (must be last) } }该方法位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
这个方法的逻辑非常清晰,enable参数是一个boolean类型变量,enable等于true代表启用距离传感器,enable等于false代表关闭或停用距离传感器。
mProximitySensorEnabled参数用于表示当前距离传感器是否正在启用。
1. 当enable等于true且当前距离传感器不处于启用的状态的情况下,我们就在SensorManager注册一个类型为mProximitySensorListener的监听器。
2. 当enable等于false且当前距离传感器已经启用的状态下,我们便取消监听这个Listener。
接下来看下mProximitySensorListener的定义。
private final SensorEventListener mProximitySensorListener = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { if (mProximitySensorEnabled) { final long time = SystemClock.uptimeMillis(); final float distance = event.values[0]; boolean positive = distance >= 0.0f && distance < mProximityThreshold; handleProximitySensorEvent(time, positive); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // Not used. } };这个监听器的声明位于同一文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
可以发现,mProximitySensorListener是一个传感器事件监听器,并且重写了onSensorChanged方法。
其执行的主要操作是对positive这个变量进行赋值。在接下来的流程当中,我们会看到positive和negative是一个相对的流程。
如果distance小于一定的范围(mProximityThreshold内),positive为true。如果大于此阀值,positive就为false,换而言之,也就是negative的意思。
// The actual proximity sensor threshold value. private float mProximityThreshold;mProximityThreshold的赋值位于DisplayPowerController类的构造函数当中。
/** * Creates the display power controller. */ public DisplayPowerController(Context context, DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager, DisplayBlanker blanker) { //...... if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) { mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); if (mProximitySensor != null) { //在这里定义 mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(), TYPICAL_PROXIMITY_THRESHOLD); } } }
在对positive进行完赋值之后,调用handleProximitySensorEvent(time, positive)方法。
private void handleProximitySensorEvent(long time, boolean positive) { if (mProximitySensorEnabled) { if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) { return; // no change } if (mPendingProximity == PROXIMITY_POSITIVE && positive) { return; // no change } // Only accept a proximity sensor reading if it remains // stable for the entire debounce delay. We hold a wake lock while // debouncing the sensor. mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); if (positive) { mPendingProximity = PROXIMITY_POSITIVE; setPendingProximityDebounceTime( time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock } else { mPendingProximity = PROXIMITY_NEGATIVE; //这边会有一个额外的250ms防抖动延迟时间 setPendingProximityDebounceTime( time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock } // Debounce the new sensor reading. debounceProximitySensor(); } }该方法位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
//里面出现了典型的Handler.removeMessage的延时操作。具体这是一个什么样的过程,我会在以后专门开辟一篇文章提及。
原生代码中对mPendingProximityDebounceTime的额外增加时间如下:
// Proximity sensor debounce delay in milliseconds for positive or negative transitions. private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0; private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
先设置好debounceTime。
private void setPendingProximityDebounceTime(long debounceTime) { if (mPendingProximityDebounceTime < 0) { mCallbacks.acquireSuspendBlocker(); // acquire wake lock } mPendingProximityDebounceTime = debounceTime; }
该方法位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
然后更新Debounce处理后的mProximity值。
private void debounceProximitySensor() { if (mProximitySensorEnabled && mPendingProximity != PROXIMITY_UNKNOWN && mPendingProximityDebounceTime >= 0) { final long now = SystemClock.uptimeMillis(); if (mPendingProximityDebounceTime <= now) { // Sensor reading accepted. Apply the change then release the wake lock. mProximity = mPendingProximity; //非常重要,传感器触发的最后结果就是设置这个标志位 updatePowerState(); //重新更新屏幕的显示Display状态 clearPendingProximityDebounceTime(); // release wake lock (must be last) } else { // Need to wait a little longer. // Debounce again later. We continue holding a wake lock while waiting. Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED); //如果时间没到会再次发送一次新的消息,在恰当的时间再调用debounceProximitySensor()方法 msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime); } } }
该方法位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
为什么会在监听到negative事件的加一个250ms的延迟处理呢,主要是为了防抖动。当用户拿在手上操作时,很多时候会使手机处于一种抖动颠簸状态。为了防止接下来频繁地刷新Display和Power状态,原生代码加入了这样的一个考虑。不少手机厂商会修改,适当增加会减小这个值以获得更好的用户体验和用户反馈。
private void updatePowerState() { //......截录传感器处理的这一部分 // Apply the proximity sensor. if (mProximitySensor != null) { //当距离传感器的锁被申请之后,且不是亮屏时,该条件满足 if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) { setProximitySensorEnabled(true); //距离传感器被遮挡时,会调用回调函数 if (!mScreenOffBecauseOfProximity && mProximity == PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity = true; sendOnProximityPositiveWithWakelock(); } } else if (mWaitingForNegativeProximity && mScreenOffBecauseOfProximity && mProximity == PROXIMITY_POSITIVE && state != Display.STATE_OFF) { setProximitySensorEnabled(true); } else { //当没有距离传感器的锁被申请时,将距离传感器停用 setProximitySensorEnabled(false); mWaitingForNegativeProximity = false; } //离开了屏幕一定范围 if (mScreenOffBecauseOfProximity && mProximity != PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity = false; sendOnProximityNegativeWithWakelock(); } } else { mWaitingForNegativeProximity = false; } if (mScreenOffBecauseOfProximity) { state = Display.STATE_OFF; } //...... }该方法位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
先对几个变量进行解释:
1. mScreenOffBecauseOfProximity 如果为true则代表屏幕是因为距离传感器而熄灭的。
// True if the screen was turned off because of the proximity sensor. // When the screen turns on again, we report user activity to the power manager. private boolean mScreenOffBecauseOfProximity;
2. mProximity代表经过防抖处理后的传感器状态。
3. mWaitingForNegativeProximity
// True if the device should wait for negative proximity sensor before // waking up the screen. This is set to false as soon as a negative // proximity sensor measurement is observed or when the device is forced to // go to sleep by the user. While true, the screen remains off. private boolean mWaitingForNegativeProximity;注释写的非常精彩,我在这里就仅仅做一次大自然的搬运工:
mWaitingForNegativeProximity为true代表屏幕应当等到距离传感器检测到距离增大后才变亮。
有两种情况会将这个变量设置为false: ①是检测到一个negative的传感器监听器事件发生(距离大于阀值) ②用户按下power键强制使手机进入休眠
这个方法中最关键的最需要理解的部分,位于其多个if else-if else逻辑之间。
此方法调用到的sendOnProximityPositiveWithWakelock()、sendOnProximityNegativeWithWakelock()将回调PowerManagerService的方法。
private void sendOnProximityPositiveWithWakelock() { mCallbacks.acquireSuspendBlocker(); mHandler.post(mOnProximityPositiveRunnable); } private final Runnable mOnProximityPositiveRunnable = new Runnable() { @Override public void run() { mCallbacks.onProximityPositive(); mCallbacks.releaseSuspendBlocker(); } }; //-------------------------------------------------------- private void sendOnProximityNegativeWithWakelock() { mCallbacks.acquireSuspendBlocker(); mHandler.post(mOnProximityNegativeRunnable); } private final Runnable mOnProximityNegativeRunnable = new Runnable() { @Override public void run() { mCallbacks.onProximityNegative(); mCallbacks.releaseSuspendBlocker(); } };以sendOnProximityPositiveWithWakelock()为例,我们了解下,在DisplayPowerController.java是怎么调用到PowerMS中的回调方法了。
因为读者即便借助SourceInsight和Eclipse等代码阅读工具,如果不梳理清楚DisplayPowerController和PowerManagerService是如何建立联系的,也难以确认mCallbacks就是PowerManagerService中的回调。
mCallbacks在DisplayPowerController.java文件中的定义如下:
// Asynchronous callbacks into the power manager service. // Only invoked from the handler thread while no locks are held. private final DisplayPowerCallbacks mCallbacks;
此处提供的信息是:mCallbacks是DisplayPowerCallbacks类型的的callbacks,而且是PowerManagerService中的异步回调。
同时在此文件中又能看到DispalyPowerController的构造函数中,有这么一句:
/** * Creates the display power controller. */ public DisplayPowerController(Context context, DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager, DisplayBlanker blanker) { mHandler = new DisplayControllerHandler(handler.getLooper()); // mCallbacks = callbacks; //...... }
系统关键服务启动的时候,往往会调用SystemReady()方法告知系统此服务已经就绪。
PowerManagerService的SystemReady():
public void systemReady(IAppOpsService appOps) { synchronized (mLock) { //...... //此处mDisplayManagerInternal初始化为DisplayManagerService.LocalService mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class); // Initialize display power management. mDisplayManagerInternal.initPowerManagement( mDisplayPowerCallbacks, mHandler, sensorManager); //...... } }
此方法位于文件/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java中。
getLocalService是PowerManagerService的父类SystemService的私有方法,且PowerManagerService并没有对它进行重写。在SystemServer启动时,会启动DisplayManagerService,并调用DisplayManagerService的startService方法把此DisplayManagerService的LocalService加入到一个HASHMAP中,使其能够通过getLocalService方法获取出来。此处不做深入探讨。这一流程要做的就是实例化mDisplayManagerInternal这个变量,并调用它的initPowerManagerment方法。
private final class LocalService extends DisplayManagerInternal { @Override public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) { synchronized (mSyncRoot) { DisplayBlanker blanker = new DisplayBlanker() { @Override public void requestDisplayState(int state) { // The order of operations is important for legacy reasons. if (state == Display.STATE_OFF) { requestGlobalDisplayStateInternal(state); } callbacks.onDisplayStateChange(state); if (state != Display.STATE_OFF) { requestGlobalDisplayStateInternal(state); } } }; //一路传递下来,终于在此处将PowerManagerService的Callbacks传递到了DisplayPowerController当中 mDisplayPowerController = new DisplayPowerController( mContext, callbacks, handler, sensorManager, blanker); } } @Override public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity); } @Override public boolean isProximitySensorAvailable() { return mDisplayPowerController.isProximitySensorAvailable(); } @Override public DisplayInfo getDisplayInfo(int displayId) { return getDisplayInfoInternal(displayId, Process.myUid()); } @Override public void registerDisplayTransactionListener(DisplayTransactionListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } registerDisplayTransactionListenerInternal(listener); } @Override public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } unregisterDisplayTransactionListenerInternal(listener); } @Override public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) { setDisplayInfoOverrideFromWindowManagerInternal(displayId, info); } @Override public void performTraversalInTransactionFromWindowManager() { performTraversalInTransactionFromWindowManagerInternal(); } @Override public void setDisplayProperties(int displayId, boolean hasContent, float requestedRefreshRate, boolean inTraversal) { setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal); } }此内部类定义位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java中。
在梳理清楚后,我们理一下思绪,回头重新PowerManagerService中的回调函数的"庐山真面目"吧。
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks = new DisplayManagerInternal.DisplayPowerCallbacks() { private int mDisplayState = Display.STATE_UNKNOWN; @Override public void onStateChanged() { synchronized (mLock) { mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED; updatePowerStateLocked(); } } @Override public void onProximityPositive() { synchronized (mLock) { mProximityPositive = true; mDirty |= DIRTY_PROXIMITY_POSITIVE; updatePowerStateLocked(); } } @Override public void onProximityNegative() { synchronized (mLock) { mProximityPositive = false; mDirty |= DIRTY_PROXIMITY_POSITIVE; userActivityNoUpdateLocked(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); updatePowerStateLocked(); } } @Override public void onDisplayStateChange(int state) { // This method is only needed to support legacy display blanking behavior // where the display's power state is coupled to suspend or to the power HAL. // The order of operations matters here. synchronized (mLock) { if (mDisplayState != state) { mDisplayState = state; if (state == Display.STATE_OFF) { if (!mDecoupleHalInteractiveModeFromDisplayConfig) { setHalInteractiveModeLocked(false); } if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { setHalAutoSuspendModeLocked(true); } } else { if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { setHalAutoSuspendModeLocked(false); } if (!mDecoupleHalInteractiveModeFromDisplayConfig) { setHalInteractiveModeLocked(true); } } } } } @Override public void acquireSuspendBlocker() { mDisplaySuspendBlocker.acquire(); } @Override public void releaseSuspendBlocker() { mDisplaySuspendBlocker.release(); } @Override public String toString() { synchronized (this) { return "state=" + Display.stateToString(mDisplayState); } } };
该方法位于文件/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java当中。
继续以sendOnProximityPositiveWithWakelock()为例。为了让大家重拾思绪,此处将该方法相关代码再次粘贴出来。
private void sendOnProximityPositiveWithWakelock() { mCallbacks.acquireSuspendBlocker(); mHandler.post(mOnProximityPositiveRunnable); } private final Runnable mOnProximityPositiveRunnable = new Runnable() { @Override public void run() { mCallbacks.onProximityPositive(); mCallbacks.releaseSuspendBlocker(); } };该方法位于文件/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController当中。
此处先调用了mCallbacks.acquireSuspendBlocker()方法申请一个锁。 然后以post一个Runnable的方式调用mCallbacks.onProximityPositive()方法,将PowerManagerService中mDirty的Proximity相关位 置位。代表此处有变化,并调用updatePowerStateLocked方法,刷新改变power状态。最后释放掉mCallbacks自身所持有的锁。
- 结合源码探讨Android距离传感器亮灭屏机制
- 结合源码探讨Android距离传感器亮灭屏机制
- 结合源码探讨Android Input输入机制
- Android传感器之距离传感器
- 深入探讨 Android 传感器
- 深入探讨 Android 传感器
- 深入探讨 Android 传感器
- 深入探讨 Android 传感器
- 深入探讨 Android 传感器
- 深入探讨 Android 传感器
- [实战示例] 带您深入探讨 Android 传感器【附源码】
- Android监听距离传感器
- Android距离传感器
- 【Android】从源码中探讨Handler机制
- Android传感器(四):距离传感器
- 结合源码探讨Android系统的启动流程
- 结合源码探讨Android系统的启动流程
- 结合源码分析android的消息机制
- NIOS II 开发流程
- 一步一步学习TypeScript(03.let与const)
- MapReduce性能优化_8. 优化MapReduce的用户JAVA代码
- 最全Pycharm教程(12)——Pycharm调试器之Java脚本调试
- 提示框第三方库之MBProgressHUD iOS toast效果 动态提示框效果
- 结合源码探讨Android距离传感器亮灭屏机制
- 第14周项目2 二叉树排序树中查找的路径
- C++通过DLL调用C#代码
- asp.net生成二维码
- 获取android手机基本信息
- Unity3d热更新(二):资源打包AssetBundle
- python link to Orcal
- 安卓学习:(4)安卓LinearLayout布局
- Java编程思想学习心得(六)关系操作符的陷阱