结合源码探讨Android距离传感器亮灭屏机制
2016-04-19 17:19
701 查看
结合源码探讨Android距离传感器亮灭屏机制
本文的分析是基于Android 5.0.0 Google原生代码的。Android中的距离传感器,也就是P-sensors(Proximity Sensors),与G-sensor重力传感器所对应。最常见的应用场景在于,当使用安卓手机接听电话时,贴近屏幕时,屏幕会灭屏,以防止脸部触碰屏幕引起误操作。当我们的脸离开屏幕时,屏幕会自动亮屏,方便我们操作手机,打开键盘输入指令。
开启和关闭距离传感器的方法位于DisplayPowerController的updatePowerState()方法当中。
[java] view
plain copy
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的定义。
[java] view
plain copy
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的意思。
[java] view
plain copy
// The actual proximity sensor threshold value.
private float mProximityThreshold;
mProximityThreshold的赋值位于DisplayPowerController类的构造函数当中。
[java] view
plain copy
/**
* 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)方法。
[java] view
plain copy
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的额外增加时间如下:
[java] view
plain copy
// 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。
[java] view
plain copy
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值。
[java] view
plain copy
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状态,原生代码加入了这样的一个考虑。不少手机厂商会修改,适当增加会减小这个值以获得更好的用户体验和用户反馈。
[java] view
plain copy
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则代表屏幕是因为距离传感器而熄灭的。
[java] view
plain copy
// 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
[java] view
plain copy
// 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的方法。
[java] view
plain copy
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文件中的定义如下:
[java] view
plain copy
// 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的构造函数中,有这么一句:
[java] view
plain copy
/**
* 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():
[java] view
plain copy
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方法。
[java] view
plain copy
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中的回调函数的"庐山真面目"吧。
[java] view
plain copy
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()为例。为了让大家重拾思绪,此处将该方法相关代码再次粘贴出来。
[java] view
plain copy
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解决ViewPager嵌套Fragment,Fragment嵌套ViewPager滑动冲突
- Android官方开发文档Training系列课程中文版:调用相机之简单摄像
- 用户检测手势Gesture implements android.view.GestureDetector.OnGestureListener
- Android activity组件
- android ImageView亮度变化
- Android中的Serialable和Parcelable的区别
- Android 驱动开发系列四
- Android adb 命令
- [Android]嵌套Fragment以及startActivityForResult()
- Android应用中炫酷的横向和环形进度条的实例分享
- Android NavigationBar 显示 Menu 按键
- Android EditText用法及焦点处理总结
- android文件操作
- Android广播BroadcastReceiver
- android中WeekCalendar控件
- Android-Spinner下拉列表显示
- android基础学习之back键的监听和回到主页面