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
This commit is contained in:
Daniel Solomon
2021-09-17 15:29:49 -07:00
parent de460d153e
commit a49b90befe
4 changed files with 114 additions and 93 deletions

View File

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

View File

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

View File

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

View File

@@ -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<SensorEventListener> listenerCaptor =
ArgumentCaptor<DisplayListener> 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<SensorEventListener> 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<DisplayListener> 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<SensorEventListener> 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) {