diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index d076b262d5fe2..c06101f202e74 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -26,8 +26,6 @@ import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; @@ -54,7 +52,6 @@ import android.util.MathUtils; import android.util.MutableFloat; import android.util.MutableInt; import android.util.Slog; -import android.util.TimeUtils; import android.view.Display; import com.android.internal.R; @@ -109,7 +106,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked"; private static final boolean DEBUG = false; - private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; + // If true, uses the color fade on animation. // We might want to turn this off if we cannot get a guarantee that the screen @@ -123,31 +120,19 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 400; private static final int MSG_UPDATE_POWER_STATE = 1; - private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2; - private static final int MSG_SCREEN_ON_UNBLOCKED = 3; - private static final int MSG_SCREEN_OFF_UNBLOCKED = 4; - private static final int MSG_CONFIGURE_BRIGHTNESS = 5; - private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 6; - private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 7; - private static final int MSG_IGNORE_PROXIMITY = 8; - private static final int MSG_STOP = 9; - private static final int MSG_UPDATE_BRIGHTNESS = 10; - private static final int MSG_UPDATE_RBC = 11; - private static final int MSG_BRIGHTNESS_RAMP_DONE = 12; - private static final int MSG_STATSD_HBM_BRIGHTNESS = 13; - - private static final int PROXIMITY_UNKNOWN = -1; - private static final int PROXIMITY_NEGATIVE = 0; - private static final int PROXIMITY_POSITIVE = 1; - - // 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; + private static final int MSG_SCREEN_ON_UNBLOCKED = 2; + private static final int MSG_SCREEN_OFF_UNBLOCKED = 3; + private static final int MSG_CONFIGURE_BRIGHTNESS = 4; + private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 5; + private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 6; + private static final int MSG_STOP = 7; + private static final int MSG_UPDATE_BRIGHTNESS = 8; + private static final int MSG_UPDATE_RBC = 9; + private static final int MSG_BRIGHTNESS_RAMP_DONE = 10; + private static final int MSG_STATSD_HBM_BRIGHTNESS = 11; private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500; - // Trigger proximity if distance is less than 5 cm. - private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f; // State machine constants for tracking initial brightness ramp skipping when enabled. private static final int RAMP_STATE_SKIP_NONE = 0; @@ -200,9 +185,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // Tracker for brightness settings changes. private final SettingsObserver mSettingsObserver; - // The proximity sensor, or null if not available or needed. - private Sensor mProximitySensor; - // The doze screen brightness. private final float mScreenBrightnessDozeConfig; @@ -266,10 +248,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal @GuardedBy("mLock") private DisplayPowerRequest mPendingRequestLocked; - // True if a request has been made to wait for the proximity sensor to go negative. - @GuardedBy("mLock") - private boolean mPendingWaitForNegativeProximityLocked; - // True if the pending power request or wait for negative proximity flag // has been changed since the last update occurred. @GuardedBy("mLock") @@ -296,37 +274,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // Must only be accessed on the handler thread. private DisplayPowerState mPowerState; - // 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; - // True if the device should not take into account the proximity sensor - // until either the proximity sensor state changes, or there is no longer a - // request to listen to proximity sensor. - private boolean mIgnoreProximityUntilChanged; - - // The actual proximity sensor threshold value. - private float mProximityThreshold; - - // Set to true if the proximity sensor listener has been registered - // with the sensor manager. - private boolean mProximitySensorEnabled; - - // The debounced proximity sensor state. - private int mProximity = PROXIMITY_UNKNOWN; - - // The raw non-debounced proximity sensor state. - private int mPendingProximity = PROXIMITY_UNKNOWN; - - // -1 if fully debounced. Else, represents the time in ms when the debounce suspend blocker will - // be removed. Applies for both positive and negative proximity flips. - private long mPendingProximityDebounceTime = -1; - - // 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; // The currently active screen on unblocker. This field is non-null whenever // we are waiting for a callback to release it and unblock the screen. @@ -407,6 +355,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // a medium of communication between this class and the PowerManagerService. private final WakelockController mWakelockController; + // Tracks and manages the proximity state of the associated display. + private final DisplayPowerProximityStateController mDisplayPowerProximityStateController; + // A record of state for skipping brightness ramps. private int mSkipRampState = RAMP_STATE_SKIP_NONE; @@ -491,13 +442,20 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mClock = mInjector.getClock(); mLogicalDisplay = logicalDisplay; mDisplayId = mLogicalDisplay.getDisplayIdLocked(); + mSensorManager = sensorManager; + mHandler = new DisplayControllerHandler(handler.getLooper()); + mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked() + .getDisplayDeviceConfig(); mWakelockController = mInjector.getWakelockController(mDisplayId, callbacks); + mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController( + mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(), + () -> updatePowerState(), mDisplayId, mSensorManager); mTag = "DisplayPowerController2[" + mDisplayId + "]"; mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); mDisplayStatsId = mUniqueDisplayId.hashCode(); - mHandler = new DisplayControllerHandler(handler.getLooper()); + mLastBrightnessEvent = new BrightnessEvent(mDisplayId); mTempBrightnessEvent = new BrightnessEvent(mDisplayId); @@ -508,7 +466,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } mSettingsObserver = new SettingsObserver(mHandler); - mSensorManager = sensorManager; mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); mBlanker = blanker; mContext = context; @@ -545,9 +502,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean( R.bool.config_allowAutoBrightnessWhileDozing); - mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked() - .getDisplayDeviceConfig(); - loadBrightnessRampRates(); mSkipScreenOnBrightnessRamp = resources.getBoolean( R.bool.config_skipScreenOnBrightnessRamp); @@ -611,8 +565,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mBrightnessBucketsInDozeConfig = resources.getBoolean( R.bool.config_displayBrightnessBucketsInDoze); - loadProximitySensor(); - mCurrentScreenBrightnessSetting = getScreenBrightnessSetting(); mScreenBrightnessForVr = getScreenBrightnessForVrSetting(); mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); @@ -653,7 +605,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal */ @Override public boolean isProximitySensorAvailable() { - return mProximitySensor != null; + return mDisplayPowerProximityStateController.isProximitySensorAvailable(); } /** @@ -727,13 +679,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal return true; } - boolean changed = false; - - if (waitForNegativeProximity - && !mPendingWaitForNegativeProximityLocked) { - mPendingWaitForNegativeProximityLocked = true; - changed = true; - } + boolean changed = mDisplayPowerProximityStateController + .setPendingWaitForNegativeProximityLocked(waitForNegativeProximity); if (mPendingRequestLocked == null) { mPendingRequestLocked = new DisplayPowerRequest(request); @@ -790,6 +737,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayDeviceConfig = config; loadFromDisplayDeviceConfig(token, info); + mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config); updatePowerState(); } }); @@ -838,7 +786,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // All properties that depend on the associated DisplayDevice and the DDC must be // updated here. loadBrightnessRampRates(); - loadProximitySensor(); loadNitsRange(mContext.getResources()); setUpAutoBrightness(mContext.getResources(), mHandler); reloadReduceBrightColours(); @@ -1134,7 +1081,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal /** Clean up all resources that are accessed via the {@link #mHandler} thread. */ private void cleanupHandlerThreadAfterStop() { - setProximitySensorEnabled(false); + mDisplayPowerProximityStateController.cleanup(); mHbmController.stop(); mBrightnessThrottler.stop(); mHandler.removeCallbacksAndMessages(null); @@ -1179,7 +1126,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal if (mPowerRequest == null) { mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked); - updatePendingProximityRequestsLocked(); + mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked(); mPendingRequestChangedLocked = false; mustInitialize = true; // Assume we're on and bright until told otherwise, since that's the state we turn @@ -1188,7 +1135,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } else if (mPendingRequestChangedLocked) { previousPolicy = mPowerRequest.policy; mPowerRequest.copyFrom(mPendingRequestLocked); - updatePendingProximityRequestsLocked(); + mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked(); mPendingRequestChangedLocked = false; mDisplayReadyLocked = false; } else { @@ -1231,55 +1178,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } assert (state != Display.STATE_UNKNOWN); - boolean skipRampBecauseOfProximityChangeToNegative = false; - // Apply the proximity sensor. - if (mProximitySensor != null) { - if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) { - // At this point the policy says that the screen should be on, but we've been - // asked to listen to the prox sensor to adjust the display state, so lets make - // sure the sensor is on. - setProximitySensorEnabled(true); - if (!mScreenOffBecauseOfProximity - && mProximity == PROXIMITY_POSITIVE - && !mIgnoreProximityUntilChanged) { - // Prox sensor already reporting "near" so we should turn off the screen. - // Also checked that we aren't currently set to ignore the proximity sensor - // temporarily. - mScreenOffBecauseOfProximity = true; - sendOnProximityPositiveWithWakelock(); - } - } else if (mWaitingForNegativeProximity - && mScreenOffBecauseOfProximity - && mProximity == PROXIMITY_POSITIVE - && state != Display.STATE_OFF) { - // The policy says that we should have the screen on, but it's off due to the prox - // and we've been asked to wait until the screen is far from the user to turn it - // back on. Let keep the prox sensor on so we can tell when it's far again. - setProximitySensorEnabled(true); - } else { - // We haven't been asked to use the prox sensor and we're not waiting on the screen - // to turn back on...so lets shut down the prox sensor. - setProximitySensorEnabled(false); - mWaitingForNegativeProximity = false; - } - - if (mScreenOffBecauseOfProximity - && (mProximity != PROXIMITY_POSITIVE || mIgnoreProximityUntilChanged)) { - // The screen *was* off due to prox being near, but now it's "far" so lets turn - // the screen back on. Also turn it back on if we've been asked to ignore the - // prox sensor temporarily. - mScreenOffBecauseOfProximity = false; - skipRampBecauseOfProximityChangeToNegative = true; - sendOnProximityNegativeWithWakelock(); - } - } else { - mWaitingForNegativeProximity = false; - mIgnoreProximityUntilChanged = false; - } + mDisplayPowerProximityStateController.updateProximityState(mPowerRequest, state); if (!mLogicalDisplay.isEnabled() || mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION - || mScreenOffBecauseOfProximity) { + || mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { state = Display.STATE_OFF; } @@ -1550,7 +1453,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal final boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR); final boolean initialRampSkip = (state == Display.STATE_ON && mSkipRampState - != RAMP_STATE_SKIP_NONE) || skipRampBecauseOfProximityChangeToNegative; + != RAMP_STATE_SKIP_NONE) || mDisplayPowerProximityStateController + .shouldSkipRampBecauseOfProximityChangeToNegative(); // While dozing, sometimes the brightness is split into buckets. Rather than animating // through the buckets, which is unlikely to be smooth in the first place, just jump // right to the suggested brightness. @@ -1770,7 +1674,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal */ @Override public void ignoreProximitySensorUntilChanged() { - mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY); + mDisplayPowerProximityStateController.ignoreProximitySensorUntilChanged(); } @Override @@ -1936,7 +1840,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { // If we are trying to turn screen off, give policy a chance to do something before we // actually turn the screen off. - if (isOff && !mScreenOffBecauseOfProximity) { + if (isOff && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF); @@ -1966,7 +1870,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // it is only removed once the window manager tells us that the activity has // finished drawing underneath. if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF - && !mScreenOffBecauseOfProximity) { + && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); unblockScreenOn(); mWindowManagerPolicy.screenTurnedOff(mDisplayId); @@ -2008,22 +1912,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal fallbackType); } - private void loadProximitySensor() { - if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) { - return; - } - final DisplayDeviceConfig.SensorData proxSensor = - mDisplayDeviceConfig.getProximitySensor(); - final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY - ? Sensor.TYPE_PROXIMITY : SensorUtils.NO_FALLBACK; - mProximitySensor = SensorUtils.findSensor(mSensorManager, proxSensor.type, proxSensor.name, - fallbackType); - if (mProximitySensor != null) { - mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(), - TYPICAL_PROXIMITY_THRESHOLD); - } - } - private float clampScreenBrightnessForVr(float value) { return MathUtils.constrain( value, mScreenBrightnessForVrRangeMinimum, @@ -2225,98 +2113,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private final Runnable mCleanListener = this::sendUpdatePowerState; - private void setProximitySensorEnabled(boolean enable) { - if (enable) { - if (!mProximitySensorEnabled) { - // Register the listener. - // Proximity sensor state already cleared initially. - mProximitySensorEnabled = true; - mIgnoreProximityUntilChanged = false; - 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; - mIgnoreProximityUntilChanged = false; - mPendingProximity = PROXIMITY_UNKNOWN; - mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); - mSensorManager.unregisterListener(mProximitySensorListener); - // release wake lock(must be last) - boolean proxDebounceSuspendBlockerReleased = - mWakelockController.releaseWakelock( - WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); - if (proxDebounceSuspendBlockerReleased) { - mPendingProximityDebounceTime = -1; - } - } - } - } - - 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; - mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY; - mWakelockController.acquireWakelock( - WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock - } else { - mPendingProximity = PROXIMITY_NEGATIVE; - mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY; - mWakelockController.acquireWakelock( - WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock - } - - // Debounce the new sensor reading. - debounceProximitySensor(); - } - } - - private void debounceProximitySensor() { - if (mProximitySensorEnabled - && mPendingProximity != PROXIMITY_UNKNOWN - && mPendingProximityDebounceTime >= 0) { - final long now = mClock.uptimeMillis(); - if (mPendingProximityDebounceTime <= now) { - if (mProximity != mPendingProximity) { - // if the status of the sensor changed, stop ignoring. - mIgnoreProximityUntilChanged = false; - Slog.i(mTag, "No longer ignoring proximity [" + mPendingProximity + "]"); - } - // Sensor reading accepted. Apply the change then release the wake lock. - mProximity = mPendingProximity; - updatePowerState(); - // (must be last) - boolean proxDebounceSuspendBlockerReleased = - mWakelockController.releaseWakelock( - WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); - if (proxDebounceSuspendBlockerReleased) { - mPendingProximityDebounceTime = -1; - } - - } 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); - mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime); - } - } - } - private void sendOnStateChangedWithWakelock() { boolean wakeLockAcquired = mWakelockController.acquireWakelock( WakelockController.WAKE_LOCK_STATE_CHANGED); @@ -2461,39 +2257,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal return mAutomaticBrightnessController.convertToNits(brightness); } - @GuardedBy("mLock") - private void updatePendingProximityRequestsLocked() { - mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; - mPendingWaitForNegativeProximityLocked = false; - - if (mIgnoreProximityUntilChanged) { - // Also, lets stop waiting for negative proximity if we're ignoring it. - mWaitingForNegativeProximity = false; - } - } - - private void ignoreProximitySensorUntilChangedInternal() { - if (!mIgnoreProximityUntilChanged - && mProximity == PROXIMITY_POSITIVE) { - // Only ignore if it is still reporting positive (near) - mIgnoreProximityUntilChanged = true; - Slog.i(mTag, "Ignoring proximity"); - updatePowerState(); - } - } - - private void sendOnProximityPositiveWithWakelock() { - mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE); - mHandler.post(mWakelockController.getOnProximityPositiveRunnable()); - } - - - private void sendOnProximityNegativeWithWakelock() { - mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE); - mHandler.post(mWakelockController.getOnProximityNegativeRunnable()); - } - - @Override public void dump(final PrintWriter pw) { synchronized (mLock) { @@ -2507,8 +2270,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked); pw.println(" mPendingRequestLocked=" + mPendingRequestLocked); pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked); - pw.println(" mPendingWaitForNegativeProximityLocked=" - + mPendingWaitForNegativeProximityLocked); pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked); } @@ -2543,7 +2304,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); - mHandler.runWithScissors(() -> dumpLocal(pw), 1000); } @@ -2551,15 +2311,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal pw.println(); pw.println("Display Power Controller Thread State:"); pw.println(" mPowerRequest=" + mPowerRequest); - pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity); - pw.println(" mProximitySensor=" + mProximitySensor); - pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled); - pw.println(" mProximityThreshold=" + mProximityThreshold); - pw.println(" mProximity=" + proximityToString(mProximity)); - pw.println(" mPendingProximity=" + proximityToString(mPendingProximity)); - pw.println(" mPendingProximityDebounceTime=" - + TimeUtils.formatUptime(mPendingProximityDebounceTime)); - pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity); pw.println(" mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness); pw.println(" mPendingScreenBrightnessSetting=" + mPendingScreenBrightnessSetting); @@ -2631,21 +2382,13 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal if (mWakelockController != null) { mWakelockController.dumpLocal(pw); } - } - private static String proximityToString(int state) { - switch (state) { - case PROXIMITY_UNKNOWN: - return "Unknown"; - case PROXIMITY_NEGATIVE: - return "Negative"; - case PROXIMITY_POSITIVE: - return "Positive"; - default: - return Integer.toString(state); + if (mDisplayPowerProximityStateController != null) { + mDisplayPowerProximityStateController.dumpLocal(pw); } } + private static String reportedToPolicyToString(int state) { switch (state) { case REPORTED_TO_POLICY_SCREEN_OFF: @@ -2795,10 +2538,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal updatePowerState(); break; - case MSG_PROXIMITY_SENSOR_DEBOUNCED: - debounceProximitySensor(); - break; - case MSG_SCREEN_ON_UNBLOCKED: if (mPendingScreenOnUnblocker == msg.obj) { unblockScreenOn(); @@ -2827,10 +2566,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal updatePowerState(); break; - case MSG_IGNORE_PROXIMITY: - ignoreProximitySensorUntilChangedInternal(); - break; - case MSG_STOP: cleanupHandlerThreadAfterStop(); break; @@ -2860,23 +2595,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } } - private final SensorEventListener mProximitySensorListener = new SensorEventListener() { - @Override - public void onSensorChanged(SensorEvent event) { - if (mProximitySensorEnabled) { - final long time = mClock.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. - } - }; - private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -2966,6 +2684,15 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal DisplayPowerCallbacks displayPowerCallbacks) { return new WakelockController(displayId, displayPowerCallbacks); } + + DisplayPowerProximityStateController getDisplayPowerProximityStateController( + WakelockController wakelockController, DisplayDeviceConfig displayDeviceConfig, + Looper looper, Runnable nudgeUpdatePowerState, + int displayId, SensorManager sensorManager) { + return new DisplayPowerProximityStateController(wakelockController, displayDeviceConfig, + looper, nudgeUpdatePowerState, + displayId, sensorManager); + } } static class CachedBrightnessInfo { diff --git a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java new file mode 100644 index 0000000000000..5b64dd5ff3196 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.hardware.display.DisplayManagerInternal; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.util.Slog; +import android.util.TimeUtils; +import android.view.Display; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.display.utils.SensorUtils; + +import java.io.PrintWriter; + +/** + * Maintains the proximity state of the display. + * Internally listens for proximity updates and schedules a power state update when the proximity + * state changes. + */ +public final class DisplayPowerProximityStateController { + private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 1; + private static final int MSG_IGNORE_PROXIMITY = 2; + + private static final int PROXIMITY_UNKNOWN = -1; + private static final int PROXIMITY_NEGATIVE = 0; + private static final int PROXIMITY_POSITIVE = 1; + + private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; + // Proximity sensor debounce delay in milliseconds for positive transitions. + private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0; + // Proximity sensor debounce delay in milliseconds for negative transitions. + private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250; + // Trigger proximity if distance is less than 5 cm. + private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f; + + private final String mTag; + // A lock to handle the deadlock and race conditions. + private final Object mLock = new Object(); + // The manager which lets us access the device's ProximitySensor + private final SensorManager mSensorManager; + // An entity which manages the wakelocks. + private final WakelockController mWakelockController; + // A handler to process all the events on this thread in a synchronous manner + private final DisplayPowerProximityStateHandler mHandler; + // A runnable to execute the utility to update the power state. + private final Runnable mNudgeUpdatePowerState; + // A listener which listen's to the events emitted by the proximity sensor. + 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. + } + }; + + // The proximity sensor, or null if not available or needed. + private Sensor mProximitySensor; + + // The configurations for the associated display + private DisplayDeviceConfig mDisplayDeviceConfig; + + // True if a request has been made to wait for the proximity sensor to go negative. + @GuardedBy("mLock") + private boolean mPendingWaitForNegativeProximityLocked; + + // 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; + + // True if the device should not take into account the proximity sensor + // until either the proximity sensor state changes, or there is no longer a + // request to listen to proximity sensor. + private boolean mIgnoreProximityUntilChanged; + + // Set to true if the proximity sensor listener has been registered + // with the sensor manager. + private boolean mProximitySensorEnabled; + + // The raw non-debounced proximity sensor state. + private int mPendingProximity = PROXIMITY_UNKNOWN; + + // -1 if fully debounced. Else, represents the time in ms when the debounce suspend blocker will + // be removed. Applies for both positive and negative proximity flips. + private long mPendingProximityDebounceTime = -1; + + // 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; + + // The debounced proximity sensor state. + private int mProximity = PROXIMITY_UNKNOWN; + + // The actual proximity sensor threshold value. + private float mProximityThreshold; + + // A flag representing if the ramp is to be skipped when the proximity changes from positive + // to negative + private boolean mSkipRampBecauseOfProximityChangeToNegative = false; + + // The DisplayId of the associated Logical Display. + private int mDisplayId; + + /** + * Create a new instance of DisplayPowerProximityStateController. + * + * @param wakeLockController WakelockController used to acquire/release wakelocks + * @param displayDeviceConfig DisplayDeviceConfig instance from which the configs(Proximity + * Sensor) are to be loaded + * @param looper A looper onto which the handler is to be associated. + * @param nudgeUpdatePowerState A runnable to execute the utility to update the power state + * @param displayId The DisplayId of the associated Logical Display. + * @param sensorManager The manager which lets us access the display's ProximitySensor + */ + public DisplayPowerProximityStateController( + WakelockController wakeLockController, DisplayDeviceConfig displayDeviceConfig, + Looper looper, + Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager) { + mWakelockController = wakeLockController; + mHandler = new DisplayPowerProximityStateHandler(looper); + mNudgeUpdatePowerState = nudgeUpdatePowerState; + mDisplayDeviceConfig = displayDeviceConfig; + mDisplayId = displayId; + mTag = "DisplayPowerProximityStateController[" + mDisplayId + "]"; + mSensorManager = sensorManager; + loadProximitySensor(); + } + + /** + * Manages the pending state of the proximity. + */ + public void updatePendingProximityRequestsLocked() { + synchronized (mLock) { + mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; + mPendingWaitForNegativeProximityLocked = false; + + if (mIgnoreProximityUntilChanged) { + // Also, lets stop waiting for negative proximity if we're ignoring it. + mWaitingForNegativeProximity = false; + } + } + } + + /** + * Clean up all resources that are accessed via the {@link #mHandler} thread. + */ + public void cleanup() { + setProximitySensorEnabled(false); + } + + /** + * Returns true if the proximity sensor screen-off function is available. + */ + public boolean isProximitySensorAvailable() { + return mProximitySensor != null; + } + + /** + * Sets the flag to indicate that the system is waiting for the negative proximity event + */ + public boolean setPendingWaitForNegativeProximityLocked( + boolean requestWaitForNegativeProximity) { + synchronized (mLock) { + if (requestWaitForNegativeProximity + && !mPendingWaitForNegativeProximityLocked) { + mPendingWaitForNegativeProximityLocked = true; + return true; + } + return false; + } + } + + /** + * Updates the proximity state of the display, based on the newly received DisplayPowerRequest + * and the target display state + */ + public void updateProximityState( + DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, + int displayState) { + mSkipRampBecauseOfProximityChangeToNegative = false; + if (mProximitySensor != null) { + if (displayPowerRequest.useProximitySensor && displayState != Display.STATE_OFF) { + // At this point the policy says that the screen should be on, but we've been + // asked to listen to the prox sensor to adjust the display state, so lets make + // sure the sensor is on. + setProximitySensorEnabled(true); + if (!mScreenOffBecauseOfProximity + && mProximity == PROXIMITY_POSITIVE + && !mIgnoreProximityUntilChanged) { + // Prox sensor already reporting "near" so we should turn off the screen. + // Also checked that we aren't currently set to ignore the proximity sensor + // temporarily. + mScreenOffBecauseOfProximity = true; + sendOnProximityPositiveWithWakelock(); + } + } else if (mWaitingForNegativeProximity + && mScreenOffBecauseOfProximity + && mProximity == PROXIMITY_POSITIVE + && displayState != Display.STATE_OFF) { + // The policy says that we should have the screen on, but it's off due to the prox + // and we've been asked to wait until the screen is far from the user to turn it + // back on. Let keep the prox sensor on so we can tell when it's far again. + setProximitySensorEnabled(true); + } else { + // We haven't been asked to use the prox sensor and we're not waiting on the screen + // to turn back on...so let's shut down the prox sensor. + setProximitySensorEnabled(false); + mWaitingForNegativeProximity = false; + } + + if (mScreenOffBecauseOfProximity + && (mProximity != PROXIMITY_POSITIVE || mIgnoreProximityUntilChanged)) { + // The screen *was* off due to prox being near, but now it's "far" so lets turn + // the screen back on. Also turn it back on if we've been asked to ignore the + // prox sensor temporarily. + mScreenOffBecauseOfProximity = false; + mSkipRampBecauseOfProximityChangeToNegative = true; + sendOnProximityNegativeWithWakelock(); + } + } else { + mWaitingForNegativeProximity = false; + mIgnoreProximityUntilChanged = false; + } + } + + /** + * A utility to check if the brightness change ramp is to be skipped because the proximity was + * changed from positive to negative. + */ + public boolean shouldSkipRampBecauseOfProximityChangeToNegative() { + return mSkipRampBecauseOfProximityChangeToNegative; + } + + /** + * Represents of the screen is currently turned off because of the proximity state. + */ + public boolean isScreenOffBecauseOfProximity() { + return mScreenOffBecauseOfProximity; + } + + /** + * Ignores the proximity sensor until the sensor state changes, but only if the sensor is + * currently enabled and forcing the screen to be dark. + */ + public void ignoreProximitySensorUntilChanged() { + mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY); + } + + /** + * This adjusts the state of this class when a change in the DisplayDevice is detected. + */ + public void notifyDisplayDeviceChanged(DisplayDeviceConfig displayDeviceConfig) { + this.mDisplayDeviceConfig = displayDeviceConfig; + loadProximitySensor(); + } + + /** + * Used to dump the state. + * + * @param pw The PrintWriter used to dump the state. + */ + public void dumpLocal(PrintWriter pw) { + pw.println(); + pw.println("DisplayPowerProximityStateController:"); + synchronized (mLock) { + pw.println(" mPendingWaitForNegativeProximityLocked=" + + mPendingWaitForNegativeProximityLocked); + } + pw.println(" mDisplayId=" + mDisplayId); + pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity); + pw.println(" mIgnoreProximityUntilChanged=" + mIgnoreProximityUntilChanged); + pw.println(" mProximitySensor=" + mProximitySensor); + pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled); + pw.println(" mProximityThreshold=" + mProximityThreshold); + pw.println(" mProximity=" + proximityToString(mProximity)); + pw.println(" mPendingProximity=" + proximityToString(mPendingProximity)); + pw.println(" mPendingProximityDebounceTime=" + + TimeUtils.formatUptime(mPendingProximityDebounceTime)); + pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity); + pw.println(" mSkipRampBecauseOfProximityChangeToNegative=" + + mSkipRampBecauseOfProximityChangeToNegative); + } + + private void ignoreProximitySensorUntilChangedInternal() { + if (!mIgnoreProximityUntilChanged + && mProximity == PROXIMITY_POSITIVE) { + // Only ignore if it is still reporting positive (near) + mIgnoreProximityUntilChanged = true; + Slog.i(mTag, "Ignoring proximity"); + mNudgeUpdatePowerState.run(); + } + } + + private void sendOnProximityPositiveWithWakelock() { + mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE); + mHandler.post(mWakelockController.getOnProximityPositiveRunnable()); + } + + private void sendOnProximityNegativeWithWakelock() { + mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE); + mHandler.post(mWakelockController.getOnProximityNegativeRunnable()); + } + + private void loadProximitySensor() { + if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) { + return; + } + final DisplayDeviceConfig.SensorData proxSensor = + mDisplayDeviceConfig.getProximitySensor(); + final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY + ? Sensor.TYPE_PROXIMITY : SensorUtils.NO_FALLBACK; + mProximitySensor = SensorUtils.findSensor(mSensorManager, proxSensor.type, proxSensor.name, + fallbackType); + if (mProximitySensor != null) { + mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(), + TYPICAL_PROXIMITY_THRESHOLD); + } + } + + private void setProximitySensorEnabled(boolean enable) { + if (enable) { + if (!mProximitySensorEnabled) { + // Register the listener. + // Proximity sensor state already cleared initially. + mProximitySensorEnabled = true; + mIgnoreProximityUntilChanged = false; + 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; + mIgnoreProximityUntilChanged = false; + mPendingProximity = PROXIMITY_UNKNOWN; + mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); + mSensorManager.unregisterListener(mProximitySensorListener); + // release wake lock(must be last) + boolean proxDebounceSuspendBlockerReleased = + mWakelockController.releaseWakelock( + WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); + if (proxDebounceSuspendBlockerReleased) { + mPendingProximityDebounceTime = -1; + } + } + } + } + + 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; + mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY; + mWakelockController.acquireWakelock( + WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock + } else { + mPendingProximity = PROXIMITY_NEGATIVE; + mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY; + mWakelockController.acquireWakelock( + WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock + } + + // Debounce the new sensor reading. + debounceProximitySensor(); + } + } + + private void debounceProximitySensor() { + if (mProximitySensorEnabled + && mPendingProximity != PROXIMITY_UNKNOWN + && mPendingProximityDebounceTime >= 0) { + final long now = SystemClock.uptimeMillis(); + if (mPendingProximityDebounceTime <= now) { + if (mProximity != mPendingProximity) { + // if the status of the sensor changed, stop ignoring. + mIgnoreProximityUntilChanged = false; + Slog.i(mTag, "No longer ignoring proximity [" + mPendingProximity + "]"); + } + // Sensor reading accepted. Apply the change then release the wake lock. + mProximity = mPendingProximity; + mNudgeUpdatePowerState.run(); + // (must be last) + boolean proxDebounceSuspendBlockerReleased = + mWakelockController.releaseWakelock( + WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); + if (proxDebounceSuspendBlockerReleased) { + mPendingProximityDebounceTime = -1; + } + + } 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); + mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime); + } + } + } + + private class DisplayPowerProximityStateHandler extends Handler { + DisplayPowerProximityStateHandler(Looper looper) { + super(looper, null, true /*async*/); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_PROXIMITY_SENSOR_DEBOUNCED: + debounceProximitySensor(); + break; + + case MSG_IGNORE_PROXIMITY: + ignoreProximitySensorUntilChangedInternal(); + break; + } + } + } + + private String proximityToString(int state) { + switch (state) { + case PROXIMITY_UNKNOWN: + return "Unknown"; + case PROXIMITY_NEGATIVE: + return "Negative"; + case PROXIMITY_POSITIVE: + return "Positive"; + default: + return Integer.toString(state); + } + } + +} diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java index 20af02e19a3d5..dc49a94eb5c5c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -33,6 +33,7 @@ import android.hardware.SensorManager; import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.os.Handler; +import android.os.Looper; import android.os.PowerManager; import android.os.test.TestLooper; import android.util.FloatProperty; @@ -135,6 +136,16 @@ public final class DisplayPowerController2Test { DisplayPowerCallbacks displayPowerCallbacks) { return mWakelockController; } + + @Override + DisplayPowerProximityStateController getDisplayPowerProximityStateController( + WakelockController wakelockController, DisplayDeviceConfig displayDeviceConfig, + Looper looper, Runnable nudgeUpdatePowerState, int displayId, + SensorManager sensorManager) { + return new DisplayPowerProximityStateController(wakelockController, + displayDeviceConfig, looper, nudgeUpdatePowerState, displayId, + sensorManager); + } }; addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock);