您的位置:首页 > 移动开发 > Android开发

结合源码探讨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自身所持有的锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: