结合源码探讨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自身所持有的锁。






0 0
原创粉丝点击