From a49b90befed61e22f382ce320df13cb6cc3031ed Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Fri, 17 Sep 2021 15:29:49 -0700 Subject: [PATCH] Change DisplayModeDirector's brightness source to DisplayListener Currently, DisplayModeDirector listens to brightness changes from Settings. However, brightness value in Settings is overridden for various reasons inside DisplayPowerController before being propagated to HALs. As a result, the brightness value that DisplayModeDirector is acting on isn't always the brightness value that gets applied to the display. This change, - Changes DisplayPowerController so that the final brightness value (after all modifications) is saved. - Changes DisplayModeDirector to use DisplayManager.DisplayListener to observe brightness changes and then retrieve and act on the final brightness value saved in DisplayPowerController. Bug: 199955532 Test: atest DisplayModeDirectorTest Change-Id: Ia6dd7d194b6913d2942bea9c29a2011b8058beef --- .../hardware/display/BrightnessInfo.java | 11 +++ .../server/display/DisplayModeDirector.java | 91 ++++++++----------- .../display/DisplayPowerController.java | 26 +++++- .../display/DisplayModeDirectorTest.java | 79 ++++++++-------- 4 files changed, 114 insertions(+), 93 deletions(-) diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java index c5d37c2d0b906..6a2b900eea591 100644 --- a/core/java/android/hardware/display/BrightnessInfo.java +++ b/core/java/android/hardware/display/BrightnessInfo.java @@ -60,6 +60,9 @@ public final class BrightnessInfo implements Parcelable { /** Brightness */ public final float brightness; + /** Brightness after {@link DisplayPowerController} adjustments */ + public final float adjustedBrightness; + /** Current minimum supported brightness. */ public final float brightnessMinimum; @@ -74,7 +77,13 @@ public final class BrightnessInfo implements Parcelable { public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum, @HighBrightnessMode int highBrightnessMode) { + this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode); + } + + public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum, + float brightnessMaximum, @HighBrightnessMode int highBrightnessMode) { this.brightness = brightness; + this.adjustedBrightness = adjustedBrightness; this.brightnessMinimum = brightnessMinimum; this.brightnessMaximum = brightnessMaximum; this.highBrightnessMode = highBrightnessMode; @@ -103,6 +112,7 @@ public final class BrightnessInfo implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeFloat(brightness); + dest.writeFloat(adjustedBrightness); dest.writeFloat(brightnessMinimum); dest.writeFloat(brightnessMaximum); dest.writeInt(highBrightnessMode); @@ -123,6 +133,7 @@ public final class BrightnessInfo implements Parcelable { private BrightnessInfo(Parcel source) { brightness = source.readFloat(); + adjustedBrightness = source.readFloat(); brightnessMinimum = source.readFloat(); brightnessMaximum = source.readFloat(); highBrightnessMode = source.readInt(); diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 5fc301e60b9d7..ee6df426c82d8 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -17,6 +17,7 @@ package com.android.server.display; import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; +import static android.os.PowerManager.BRIGHTNESS_INVALID; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,6 +41,7 @@ import android.os.IThermalEventListener; import android.os.IThermalService; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -60,6 +62,7 @@ import android.view.DisplayInfo; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; import com.android.server.display.utils.AmbientFilter; @@ -155,7 +158,7 @@ public class DisplayModeDirector { mAppRequestObserver = new AppRequestObserver(); mSettingsObserver = new SettingsObserver(context, handler); mDisplayObserver = new DisplayObserver(context, handler); - mBrightnessObserver = new BrightnessObserver(context, handler); + mBrightnessObserver = new BrightnessObserver(context, handler, injector); mUdfpsObserver = new UdfpsObserver(); final BallotBox ballotBox = (displayId, priority, vote) -> { synchronized (mLock) { @@ -1427,8 +1430,6 @@ public class DisplayModeDirector { @Override public void onDisplayChanged(int displayId) { updateDisplayModes(displayId); - // TODO: Break the coupling between DisplayObserver and BrightnessObserver. - mBrightnessObserver.onDisplayChanged(displayId); } private void updateDisplayModes(int displayId) { @@ -1465,7 +1466,7 @@ public class DisplayModeDirector { * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}. */ @VisibleForTesting - public class BrightnessObserver extends ContentObserver { + public class BrightnessObserver implements DisplayManager.DisplayListener { private final static int LIGHT_SENSOR_RATE_MS = 250; private int[] mLowDisplayBrightnessThresholds; private int[] mLowAmbientBrightnessThresholds; @@ -1488,6 +1489,8 @@ public class DisplayModeDirector { private int mBrightness = -1; private final Context mContext; + private final Injector mInjector; + private final Handler mHandler; // Enable light sensor only when mShouldObserveAmbientLowChange is true or // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate @@ -1500,9 +1503,11 @@ public class DisplayModeDirector { private int mRefreshRateInLowZone; private int mRefreshRateInHighZone; - BrightnessObserver(Context context, Handler handler) { - super(handler); + BrightnessObserver(Context context, Handler handler, Injector injector) { mContext = context; + mHandler = handler; + mInjector = injector; + mLowDisplayBrightnessThresholds = context.getResources().getIntArray( R.array.config_brightnessThresholdsOfPeakRefreshRate); mLowAmbientBrightnessThresholds = context.getResources().getIntArray( @@ -1569,8 +1574,7 @@ public class DisplayModeDirector { public void observe(SensorManager sensorManager) { mSensorManager = sensorManager; final ContentResolver cr = mContext.getContentResolver(); - mBrightness = Settings.System.getIntForUser(cr, - Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId()); + mBrightness = getBrightness(Display.DEFAULT_DISPLAY); // DeviceConfig is accessible after system ready. int[] lowDisplayBrightnessThresholds = @@ -1603,6 +1607,10 @@ public class DisplayModeDirector { restartObserver(); mDeviceConfigDisplaySettings.startListening(); + + mInjector.registerDisplayListener(this, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_CHANGED | + DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); } public void setLoggingEnabled(boolean loggingEnabled) { @@ -1718,28 +1726,30 @@ public class DisplayModeDirector { } } + @Override + public void onDisplayAdded(int displayId) {} + + @Override + public void onDisplayRemoved(int displayId) {} + + @Override public void onDisplayChanged(int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { updateDefaultDisplayState(); - } - } - @Override - public void onChange(boolean selfChange, Uri uri, int userId) { - synchronized (mLock) { - final ContentResolver cr = mContext.getContentResolver(); - int brightness = Settings.System.getIntForUser(cr, - Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId()); - if (brightness != mBrightness) { - mBrightness = brightness; - onBrightnessChangedLocked(); + // We don't support multiple display blocking zones yet, so only handle + // brightness changes for the default display for now. + int brightness = getBrightness(displayId); + synchronized (mLock) { + if (brightness != mBrightness) { + mBrightness = brightness; + onBrightnessChangedLocked(); + } } } } private void restartObserver() { - final ContentResolver cr = mContext.getContentResolver(); - if (mRefreshRateInLowZone > 0) { mShouldObserveDisplayLowChange = hasValidThreshold( mLowDisplayBrightnessThresholds); @@ -1760,15 +1770,6 @@ public class DisplayModeDirector { mShouldObserveAmbientHighChange = false; } - if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) { - // Content Service does not check if an listener has already been registered. - // To ensure only one listener is registered, force an unregistration first. - mInjector.unregisterBrightnessObserver(cr, this); - mInjector.registerBrightnessObserver(cr, this); - } else { - mInjector.unregisterBrightnessObserver(cr, this); - } - if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) { Resources resources = mContext.getResources(); String lightSensorType = resources.getString( @@ -1968,6 +1969,15 @@ public class DisplayModeDirector { return mDefaultDisplayState == Display.STATE_ON; } + private int getBrightness(int displayId) { + final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); + if (info != null) { + return BrightnessSynchronizer.brightnessFloatToInt(info.adjustedBrightness); + } + + return BRIGHTNESS_INVALID; + } + private final class LightSensorEventListener implements SensorEventListener { final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS; private float mLastSensorData; @@ -2630,19 +2640,11 @@ public class DisplayModeDirector { } interface Injector { - // TODO: brightnessfloat: change this to the float setting - Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); @NonNull DeviceConfigInterface getDeviceConfig(); - void registerBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer); - - void unregisterBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer); - void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer); @@ -2671,19 +2673,6 @@ public class DisplayModeDirector { return DeviceConfigInterface.REAL; } - @Override - public void registerBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/, - observer, UserHandle.USER_SYSTEM); - } - - @Override - public void unregisterBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - cr.unregisterContentObserver(observer); - } - @Override public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index abbe13ac260f8..25afc3f8b2135 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1259,10 +1259,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true); } - // We save the brightness info *after* the brightness setting has been changed so that - // the brightness info reflects the latest value. - saveBrightnessInfo(getScreenBrightnessSetting()); - // Apply dimming by at least some minimum amount when user activity // timeout is about to expire. if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) { @@ -1393,6 +1389,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call hadUserBrightnessPoint); } + // We save the brightness info *after* the brightness setting has been changed and + // adjustments made so that the brightness info reflects the latest value. + saveBrightnessInfo(getScreenBrightnessSetting(), animateValue); + } else { + saveBrightnessInfo(getScreenBrightnessSetting()); } // Log any changes to what is currently driving the brightness setting. @@ -1509,6 +1510,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call synchronized (mCachedBrightnessInfo) { return new BrightnessInfo( mCachedBrightnessInfo.brightness, + mCachedBrightnessInfo.adjustedBrightness, mCachedBrightnessInfo.brightnessMin, mCachedBrightnessInfo.brightnessMax, mCachedBrightnessInfo.hbmMode); @@ -1516,8 +1518,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void saveBrightnessInfo(float brightness) { + saveBrightnessInfo(brightness, brightness); + } + + private void saveBrightnessInfo(float brightness, float adjustedBrightness) { synchronized (mCachedBrightnessInfo) { mCachedBrightnessInfo.brightness = brightness; + mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness; mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin(); mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax(); mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode(); @@ -2195,6 +2202,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp); pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig); pw.println(" mColorFadeEnabled=" + mColorFadeEnabled); + synchronized (mCachedBrightnessInfo) { + pw.println(" mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness); + pw.println(" mCachedBrightnessInfo.adjustedBrightness=" + + mCachedBrightnessInfo.adjustedBrightness); + pw.println(" mCachedBrightnessInfo.brightnessMin=" + + mCachedBrightnessInfo.brightnessMin); + pw.println(" mCachedBrightnessInfo.brightnessMax=" + + mCachedBrightnessInfo.brightnessMax); + pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode); + } pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); @@ -2606,6 +2623,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call static class CachedBrightnessInfo { public float brightness; + public float adjustedBrightness; public float brightnessMin; public float brightnessMax; public int hbmMode; diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 0dd5c61121dbf..511687bf2d232 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -74,6 +74,7 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.util.Preconditions; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProviderRule; @@ -751,19 +752,27 @@ public class DisplayModeDirectorTest { director.start(sensorManager); - ArgumentCaptor listenerCaptor = + ArgumentCaptor displayListenerCaptor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), + any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + DisplayListener displayListener = displayListenerCaptor.getValue(); + + ArgumentCaptor sensorListenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1))) .registerListener( - listenerCaptor.capture(), + sensorListenerCaptor.capture(), eq(lightSensor), anyInt(), any(Handler.class)); - SensorEventListener listener = listenerCaptor.getValue(); + SensorEventListener sensorListener = sensorListenerCaptor.getValue(); - setBrightness(10); + setBrightness(10, 10, displayListener); // Sensor reads 20 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/)); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertVoteForRefreshRate(vote, 90 /*fps*/); @@ -771,9 +780,11 @@ public class DisplayModeDirectorTest { assertThat(vote).isNotNull(); assertThat(vote.disableRefreshRateSwitching).isTrue(); - setBrightness(125); + // We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this + // parameter to the necessary threshold + setBrightness(10, 125, displayListener); // Sensor reads 1000 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/)); vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertThat(vote).isNull(); @@ -799,6 +810,14 @@ public class DisplayModeDirectorTest { director.start(sensorManager); + ArgumentCaptor displayListenerCaptor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(), + any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + DisplayListener displayListener = displayListenerCaptor.getValue(); + ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1))) @@ -807,20 +826,22 @@ public class DisplayModeDirectorTest { eq(lightSensor), anyInt(), any(Handler.class)); - SensorEventListener listener = listenerCaptor.getValue(); + SensorEventListener sensorListener = listenerCaptor.getValue(); - setBrightness(100); + setBrightness(100, 100, displayListener); // Sensor reads 2000 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000)); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertThat(vote).isNull(); vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH); assertThat(vote).isNull(); - setBrightness(255); + // We expect DisplayModeDirector to act on BrightnessInfo.adjustedBrightness; set only this + // parameter to the necessary threshold + setBrightness(100, 255, displayListener); // Sensor reads 9000 lux, - listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000)); + sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000)); vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE); assertVoteForRefreshRate(vote, 60 /*fps*/); @@ -1834,11 +1855,14 @@ public class DisplayModeDirectorTest { } } - private void setBrightness(int brightness) { - Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, - brightness); - mInjector.notifyBrightnessChanged(); - waitForIdleSync(); + private void setBrightness(int brightness, int adjustedBrightness, DisplayListener listener) { + float floatBri = BrightnessSynchronizer.brightnessIntToFloat(brightness); + float floatAdjBri = BrightnessSynchronizer.brightnessIntToFloat(adjustedBrightness); + + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(floatBri, floatAdjBri, 0.0f, 1.0f, + BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + listener.onDisplayChanged(DISPLAY_ID); } private void setPeakRefreshRate(float fps) { @@ -1901,27 +1925,6 @@ public class DisplayModeDirectorTest { return mDeviceConfig; } - @Override - public void registerBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - if (mBrightnessObserver != null) { - throw new IllegalStateException("Tried to register a second brightness observer"); - } - mBrightnessObserver = observer; - } - - @Override - public void unregisterBrightnessObserver(@NonNull ContentResolver cr, - @NonNull ContentObserver observer) { - mBrightnessObserver = null; - } - - void notifyBrightnessChanged() { - if (mBrightnessObserver != null) { - mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI); - } - } - @Override public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer) {