结合源码探讨Android距离传感器亮灭屏机制
结合源码探讨Android距离传感器亮灭屏机制
本文的分析是基于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系统的启动流程 由于本人能力有限,所考虑或者疏忽错漏的地方或多或少应该存在.同时,Android从启动过程开始,实际上就涉及多个技术难点和多种通信机制的知识点. 基于上面两个 ...
- Android Keyguard 亮灭屏流程分析
文章目录 概述 Keyguard 关键文件 Power 灭屏 超时灭屏 Power 亮屏 FAQ 亮屏慢 概述 Keyguard 锁屏流程: Keyguard 加载时机:一个是开机的时候:另一个是灭屏 ...
- android流程点击开机键熄屏,一种基于android系统的灭屏状态下指纹解锁加速亮屏方法与流程...
本发明涉及android系统解锁显示方法,尤其涉及一种基于android系统的灭屏状态下指纹解锁加速亮屏方法. 背景技术: 目前,随着指纹技术越来越普及,很多android系统设备都带有指纹外设,特别 ...
- Android 系统(40)--Android7.0 PowerManagerService亮灭屏分析(一)
Android7.0 PowerManagerService亮灭屏分析(一) 可以导致手机亮灭屏的因素有多种,而在本文中主要讲解按power键亮灭屏过程以及来电亮屏.在亮灭屏过程power中主要的实现 ...
- Android 8.0 手机亮灭屏
本文主要跟踪分析通过按松power键来唤醒,熄灭屏幕的逻辑.下面是一些相关类的介绍 PowerManagerService.java:简称PMS,负责Andorid系统中电源管理方面的工作.作为系统核 ...
- Android 知识点 109 —— Android7.0 PowerManagerService 之亮灭屏
原文地址: https://www.cnblogs.com/dyufei/p/8017604.html 写的太好了,粘过来! 本篇从按下power按键后,按键事件从InputManagerServic ...
- 【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )
文章目录 安卓直播推流专栏博客总结 一. RTMP 协议 二. RTMP 协议使用 三. RTMPDump 源码下载 四. RTMPDump 源码交叉编译 五. RTMPDump 源码导入 Andro ...
- 源码分析Android Handler是如何实现线程间通信的
源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...
- Android 系统(42)---Android7.0 PowerManagerService亮灭屏分析(三)
Android7.0 PowerManagerService亮灭屏分析(三) 在前面两部分已经对绘制windows与设置设备状态进行了详细讲解. 之后接着就该对亮度值进行设置, 实现亮屏动作了. 在D ...
最新文章
- vb打开服务器excel文件路径,咨询下VB如何打开EXCEL文件并将内容显示在listbox中
- 小马拉大车,无线网络优化
- 魅族用鸿蒙系统吗,魅族宣布接入鸿蒙是怎么回事?魅族手机可以刷鸿蒙系统吗?...
- 搜索不包含关键词_亚马逊listing关键词优化
- P4055 [JSOI2009]游戏
- 百度谷歌2013年母亲节 赏析中文搜索引擎庆祝涂鸦
- 虚拟主机金华php空间,金华虚拟主机_金华云虚机_金华主机申请_金华网站空间_爱名网(www.22.cn)...
- MySQL 指定各分区路径
- css3中的过度transition与动画animation以及字体@font-face
- 【UWB 定位】室内定位 三边定位算法
- matlab中画花瓣,matlab花瓣图的编程原理是什么,向天下大侠求解!!!!给力的? 爱问知识人...
- 如何解决移动端 Retina 屏(高清屏)1px 像素问题
- JAVA | MongoDB 去重、聚合函数、Criteria Query使用
- 苹果笔记本显卡性能测试软件,测试结果来了!新款Macbook Pro显卡性能怎样?
- 初学入门YOLOv5手势识别之制作并训练自己的数据集
- 采购货物和服务的有效步骤
- UIWebView使用app内自定义字体
- ABAP 调用webservice 错误
- Python 实战系列-微信或网页远程控制电脑
- 基于Ethernet KRL,上位机C#通过TCP/IP与KUKA库卡机械臂通讯Demo
热门文章
- spring 操作对象写入mongo去除_class列
- 支付宝接口调试经验总结
- 《高性能Linux服务器构建实战Ⅱ》一书纠错汇总(12月30日更新)
- 机器学习三个部分:输入、算法、输出 资料收集
- 深度学习 --- 受限玻尔兹曼机RBM(MCMC和Gibbs采样)
- 单目摄像头光学图像测距_挑战激光雷达,MAXIEYE要重新定义单目摄像头?
- python 空列表对象的布尔值_python – 从TensorFlow对象中检索数据 – 来自correct_prediction的布尔值列表...
- 反序列化对象列表发生异常_面试官:你知道Java对象的序列化与反序列化背后的原理吗?...
- 三星手机怎么把html,三星手机怎么连接电脑 只要四步轻松搞定【图文】
- linux虚拟化技术 教程,Linux上实现虚拟化技术的优势