Introducing DisplayPowerProximityStateController

This is a part of restructuring the way display service
updates the power state of the system. All the proximity related logic
has been abstracted out to a new class. As an attempt to keep this
simple and contained, no new logic has been added.

Bug: 241308364
Test: atest com.android.server.display
Change-Id: I45bb8cff3f6da805a816a9c3eef7428e7f7fbf7d
This commit is contained in:
Rupesh Bansal
2022-10-10 15:56:09 +00:00
parent a3608b5624
commit c9aa96111f
3 changed files with 535 additions and 321 deletions

View File

@@ -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 {

View File

@@ -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);
}
}
}

View File

@@ -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);