summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/BrightnessInfo.java24
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java8
-rw-r--r--services/core/java/com/android/server/display/DisplayBlanker.java5
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java23
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java76
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java86
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java77
-rw-r--r--services/core/java/com/android/server/display/HighBrightnessModeController.java125
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java60
-rw-r--r--services/core/java/com/android/server/display/RampAnimator.java50
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java11
14 files changed, 461 insertions, 103 deletions
diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java
index 4289860d4e8a..c5d37c2d0b90 100644
--- a/core/java/android/hardware/display/BrightnessInfo.java
+++ b/core/java/android/hardware/display/BrightnessInfo.java
@@ -33,7 +33,8 @@ public final class BrightnessInfo implements Parcelable {
@IntDef(prefix = {"HIGH_BRIGHTNESS_MODE_"}, value = {
HIGH_BRIGHTNESS_MODE_OFF,
- HIGH_BRIGHTNESS_MODE_SUNLIGHT
+ HIGH_BRIGHTNESS_MODE_SUNLIGHT,
+ HIGH_BRIGHTNESS_MODE_HDR
})
@Retention(RetentionPolicy.SOURCE)
public @interface HighBrightnessMode {}
@@ -50,6 +51,12 @@ public final class BrightnessInfo implements Parcelable {
*/
public static final int HIGH_BRIGHTNESS_MODE_SUNLIGHT = 1;
+ /**
+ * High brightness mode is ON due to high ambient light (sunlight). The high brightness range is
+ * currently accessible to the user.
+ */
+ public static final int HIGH_BRIGHTNESS_MODE_HDR = 2;
+
/** Brightness */
public final float brightness;
@@ -73,6 +80,21 @@ public final class BrightnessInfo implements Parcelable {
this.highBrightnessMode = highBrightnessMode;
}
+ /**
+ * @return User-friendly string for specified {@link HighBrightnessMode} parameter.
+ */
+ public static String hbmToString(@HighBrightnessMode int highBrightnessMode) {
+ switch (highBrightnessMode) {
+ case HIGH_BRIGHTNESS_MODE_OFF:
+ return "off";
+ case HIGH_BRIGHTNESS_MODE_HDR:
+ return "hdr";
+ case HIGH_BRIGHTNESS_MODE_SUNLIGHT:
+ return "sunlight";
+ }
+ return "invalid";
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 91b96dc17473..1a07cb854cae 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -738,13 +738,19 @@ class AutomaticBrightnessController {
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
mForegroundAppCategory);
float newScreenAutoBrightness = clampScreenBrightness(value);
+
+ // The min/max range can change for brightness due to HBM. See if the current brightness
+ // value still falls within the current range (which could have changed).
+ final boolean currentBrightnessWithinAllowedRange = BrightnessSynchronizer.floatEquals(
+ mScreenAutoBrightness, clampScreenBrightness(mScreenAutoBrightness));
// If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
// in which case we ignore the new screen brightness if it doesn't differ enough from the
// previous one.
if (!Float.isNaN(mScreenAutoBrightness)
&& !isManuallySet
&& newScreenAutoBrightness > mScreenDarkeningThreshold
- && newScreenAutoBrightness < mScreenBrighteningThreshold) {
+ && newScreenAutoBrightness < mScreenBrighteningThreshold
+ && currentBrightnessWithinAllowedRange) {
if (mLoggingEnabled) {
Slog.d(TAG, "ignoring newScreenAutoBrightness: "
+ mScreenDarkeningThreshold + " < " + newScreenAutoBrightness
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
index e2129ba13626..8de49af3de22 100644
--- a/services/core/java/com/android/server/display/DisplayBlanker.java
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -20,5 +20,8 @@ package com.android.server.display;
* Interface used to update the actual display state.
*/
public interface DisplayBlanker {
- void requestDisplayState(int displayId, int state, float brightness);
+ /**
+ * Requests the specified display state and brightness levels for the specified displayId.
+ */
+ void requestDisplayState(int displayId, int state, float brightness, float sdrBrightness);
}
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index b3070b7cf1ba..35f29579b417 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -156,10 +156,12 @@ abstract class DisplayDevice {
*
* @param state The new display state.
* @param brightnessState The new display brightnessState.
+ * @param sdrBrightnessState The new display brightnessState for SDR layers.
* @return A runnable containing work to be deferred until after we have
* exited the critical section, or null if none.
*/
- public Runnable requestDisplayStateLocked(int state, float brightnessState) {
+ public Runnable requestDisplayStateLocked(int state, float brightnessState,
+ float sdrBrightnessState) {
return null;
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 2d7145fef69c..c46cfe3d1d2f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -104,6 +104,7 @@ public class DisplayDeviceConfig {
private float mBrightnessRampSlowIncrease = Float.NaN;
private Spline mBrightnessToBacklightSpline;
private Spline mBacklightToBrightnessSpline;
+ private Spline mBacklightToNitsSpline;
private List<String> mQuirks;
private boolean mIsHighBrightnessModeEnabled = false;
private HighBrightnessModeData mHbmData;
@@ -219,6 +220,20 @@ public class DisplayDeviceConfig {
}
/**
+ * Calculates the nits value for the specified backlight value if a mapping exists.
+ *
+ * @return The mapped nits or 0 if no mapping exits.
+ */
+ public float getNitsFromBacklight(float backlight) {
+ if (mBacklightToNitsSpline == null) {
+ Slog.wtf(TAG, "requesting nits when no mapping exists.");
+ return -1;
+ }
+ backlight = Math.max(backlight, mBacklightMinimum);
+ return mBacklightToNitsSpline.interpolate(backlight);
+ }
+
+ /**
* Return an array of equal length to backlight and nits, that covers the entire system
* brightness range of 0.0-1.0.
*
@@ -258,6 +273,13 @@ public class DisplayDeviceConfig {
}
/**
+ * @return true if a nits to backlight mapping is defined in this config, false otherwise.
+ */
+ public boolean hasNitsMapping() {
+ return mBacklightToNitsSpline != null;
+ }
+
+ /**
* @param quirkValue The quirk to test.
* @return {@code true} if the specified quirk is present in this configuration,
* {@code false} otherwise.
@@ -584,6 +606,7 @@ public class DisplayDeviceConfig {
}
mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
+ mBacklightToNitsSpline = Spline.createSpline(mBacklight, mNits);
}
private void loadQuirks(DisplayConfiguration config) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 789f08fb3187..0a4b137fa6cd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -257,7 +257,8 @@ public final class DisplayManagerService extends SystemService {
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
// Synchronized to avoid race conditions when updating multiple display states.
@Override
- public synchronized void requestDisplayState(int displayId, int state, float brightness) {
+ public synchronized void requestDisplayState(int displayId, int state, float brightness,
+ float sdrBrightness) {
boolean allInactive = true;
boolean allOff = true;
final boolean stateChanged;
@@ -288,7 +289,7 @@ public final class DisplayManagerService extends SystemService {
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
- requestDisplayStateInternal(displayId, state, brightness);
+ requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
}
if (stateChanged) {
@@ -296,7 +297,7 @@ public final class DisplayManagerService extends SystemService {
}
if (state != Display.STATE_OFF) {
- requestDisplayStateInternal(displayId, state, brightness);
+ requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
}
}
};
@@ -316,7 +317,7 @@ public final class DisplayManagerService extends SystemService {
// A map from LogicalDisplay ID to display brightness.
@GuardedBy("mSyncRoot")
- private final SparseArray<Float> mDisplayBrightnesses = new SparseArray<>();
+ private final SparseArray<BrightnessPair> mDisplayBrightnesses = new SparseArray<>();
// Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state.
@@ -667,11 +668,8 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void requestDisplayStateInternal(int displayId, int state, float brightnessState) {
- if (state == Display.STATE_UNKNOWN) {
- state = Display.STATE_ON;
- }
- if (state == Display.STATE_OFF) {
+ private float clampBrightness(int displayState, float brightnessState) {
+ if (displayState == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
} else if (brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT
&& brightnessState < PowerManager.BRIGHTNESS_MIN) {
@@ -679,6 +677,17 @@ public final class DisplayManagerService extends SystemService {
} else if (brightnessState > PowerManager.BRIGHTNESS_MAX) {
brightnessState = PowerManager.BRIGHTNESS_MAX;
}
+ return brightnessState;
+ }
+
+ private void requestDisplayStateInternal(int displayId, int state, float brightnessState,
+ float sdrBrightnessState) {
+ if (state == Display.STATE_UNKNOWN) {
+ state = Display.STATE_ON;
+ }
+
+ brightnessState = clampBrightness(state, brightnessState);
+ sdrBrightnessState = clampBrightness(state, sdrBrightnessState);
// Update the display state within the lock.
// Note that we do not need to schedule traversals here although it
@@ -688,20 +697,26 @@ public final class DisplayManagerService extends SystemService {
synchronized (mSyncRoot) {
final int index = mDisplayStates.indexOfKey(displayId);
+ final BrightnessPair brightnessPair =
+ index < 0 ? null : mDisplayBrightnesses.valueAt(index);
if (index < 0 || (mDisplayStates.valueAt(index) == state
- && BrightnessSynchronizer.floatEquals(mDisplayBrightnesses.valueAt(index),
- brightnessState))) {
+ && BrightnessSynchronizer.floatEquals(
+ brightnessPair.brightness, brightnessState)
+ && BrightnessSynchronizer.floatEquals(
+ brightnessPair.sdrBrightness, sdrBrightnessState))) {
return; // Display no longer exists or no change.
}
traceMessage = "requestDisplayStateInternal("
+ displayId + ", "
+ Display.stateToString(state)
- + ", brightness=" + brightnessState + ")";
+ + ", brightness=" + brightnessState
+ + ", sdrBrightness=" + sdrBrightnessState + ")";
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, traceMessage, displayId);
mDisplayStates.setValueAt(index, state);
- mDisplayBrightnesses.setValueAt(index, brightnessState);
+ brightnessPair.brightness = brightnessState;
+ brightnessPair.sdrBrightness = sdrBrightnessState;
runnable = updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId)
.getPrimaryDisplayDeviceLocked());
}
@@ -1235,7 +1250,9 @@ public final class DisplayManagerService extends SystemService {
addDisplayPowerControllerLocked(display);
mDisplayStates.append(displayId, Display.STATE_UNKNOWN);
- mDisplayBrightnesses.append(displayId, display.getDisplayInfoLocked().brightnessDefault);
+ final float brightnessDefault = display.getDisplayInfoLocked().brightnessDefault;
+ mDisplayBrightnesses.append(displayId,
+ new BrightnessPair(brightnessDefault, brightnessDefault));
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1265,11 +1282,6 @@ public final class DisplayManagerService extends SystemService {
// this point.
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
scheduleTraversalLocked(false);
-
- DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
- if (dpc != null) {
- dpc.onDisplayChanged();
- }
}
private void handleLogicalDisplayFrameRateOverridesChangedLocked(
@@ -1301,6 +1313,11 @@ public final class DisplayManagerService extends SystemService {
if (work != null) {
mHandler.post(work);
}
+ final int displayId = display.getDisplayIdLocked();
+ DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ if (dpc != null) {
+ dpc.onDisplayChanged();
+ }
handleLogicalDisplayChangedLocked(display);
}
@@ -1326,8 +1343,9 @@ public final class DisplayManagerService extends SystemService {
// Only send a request for display state if display state has already been initialized.
if (state != Display.STATE_UNKNOWN) {
- final float brightness = mDisplayBrightnesses.get(displayId);
- return device.requestDisplayStateLocked(state, brightness);
+ final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
+ return device.requestDisplayStateLocked(state, brightnessPair.brightness,
+ brightnessPair.sdrBrightness);
}
}
return null;
@@ -1935,10 +1953,11 @@ public final class DisplayManagerService extends SystemService {
for (int i = 0; i < displayStateCount; i++) {
final int displayId = mDisplayStates.keyAt(i);
final int displayState = mDisplayStates.valueAt(i);
- final float brightness = mDisplayBrightnesses.valueAt(i);
+ final BrightnessPair brightnessPair = mDisplayBrightnesses.valueAt(i);
pw.println(" Display Id=" + displayId);
pw.println(" Display State=" + Display.stateToString(displayState));
- pw.println(" Display Brightness=" + brightness);
+ pw.println(" Display Brightness=" + brightnessPair.brightness);
+ pw.println(" Display SdrBrightness=" + brightnessPair.sdrBrightness);
}
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
@@ -3277,6 +3296,16 @@ public final class DisplayManagerService extends SystemService {
}
};
+ private class BrightnessPair {
+ public float brightness;
+ public float sdrBrightness;
+
+ BrightnessPair(float brightness, float sdrBrightness) {
+ this.brightness = brightness;
+ this.sdrBrightness = sdrBrightness;
+ }
+ }
+
/**
* Functional interface for providing time.
* TODO(b/184781936): merge with PowerManagerService.Clock
@@ -3288,5 +3317,4 @@ public final class DisplayManagerService extends SystemService {
*/
long uptimeMillis();
}
-
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3340e3c73fa1..7a50a34ae4ad 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -38,6 +38,7 @@ import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -61,6 +62,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
+import com.android.server.display.RampAnimator.DualRampAnimator;
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
@@ -223,6 +225,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@GuardedBy("mCachedBrightnessInfo")
private final CachedBrightnessInfo mCachedBrightnessInfo = new CachedBrightnessInfo();
+ private DisplayDevice mDisplayDevice;
+
// True if we should fade the screen while turning it off, false if we should play
// a stylish color fade animation instead.
private boolean mColorFadeFadesConfig;
@@ -424,7 +428,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
- private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
+ private DualRampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener;
// True if this DisplayPowerController has been stopped and should no longer be running.
@@ -442,6 +446,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
Runnable onBrightnessChangeRunnable) {
mLogicalDisplay = logicalDisplay;
mDisplayId = mLogicalDisplay.getDisplayIdLocked();
+ mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mHandler = new DisplayControllerHandler(handler.getLooper());
if (mDisplayId == Display.DEFAULT_DISPLAY) {
@@ -780,12 +785,29 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
* when displays get swapped on foldable devices. For example, different brightness properties
* of each display need to be properly reflected in AutomaticBrightnessController.
*/
+ @GuardedBy("DisplayManagerService.mSyncRoot")
public void onDisplayChanged() {
- // TODO: b/175821789 - Support high brightness on multiple (folding) displays
- mUniqueDisplayId = mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
- mDisplayDeviceConfig = mLogicalDisplay.getPrimaryDisplayDeviceLocked()
- .getDisplayDeviceConfig();
- loadAmbientLightSensor();
+ final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
+ + mLogicalDisplay.getDisplayIdLocked());
+ return;
+ }
+
+ final String uniqueId = device.getUniqueId();
+ final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
+ final IBinder token = device.getDisplayTokenLocked();
+ mHandler.post(() -> {
+ if (mDisplayDevice == device) {
+ return;
+ }
+ mDisplayDevice = device;
+ mUniqueDisplayId = uniqueId;
+ mDisplayDeviceConfig = config;
+
+ loadAmbientLightSensor();
+ mHbmController.resetHbmData(token, config.getHighBrightnessModeData());
+ });
}
/**
@@ -855,8 +877,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mColorFadeOffAnimator.addListener(mAnimatorListener);
}
- mScreenBrightnessRampAnimator = new RampAnimator<>(
- mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT);
+ mScreenBrightnessRampAnimator = new DualRampAnimator<>(mPowerState,
+ DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
+ DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
noteScreenState(mPowerState.getScreenState());
@@ -902,6 +925,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
/** Clean up all resources that are accessed via the {@link #mHandler} thread. */
private void cleanupHandlerThreadAfterStop() {
setProximitySensorEnabled(false);
+ mHbmController.stop();
mHandler.removeCallbacksAndMessages(null);
if (mUnfinishedBusiness) {
mCallbacks.releaseSuspendBlocker();
@@ -1205,9 +1229,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
- brightnessState = Math.max(Math.min(brightnessState
- - SCREEN_DIM_MINIMUM_REDUCTION_FLOAT,
- mScreenBrightnessDimConfig), PowerManager.BRIGHTNESS_MIN);
+ brightnessState = Math.max(
+ Math.min(brightnessState - SCREEN_DIM_MINIMUM_REDUCTION_FLOAT,
+ mScreenBrightnessDimConfig),
+ PowerManager.BRIGHTNESS_MIN);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED);
}
if (!mAppliedDimming) {
@@ -1282,12 +1307,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// transformations to the brightness have pushed it outside of the currently
// allowed range.
float animateValue = clampScreenBrightness(brightnessState);
+
+ // If there are any HDR layers on the screen, we have a special brightness value that we
+ // use instead. We still preserve the calculated brightness for Standard Dynamic Range
+ // (SDR) layers, but the main brightness value will be the one for HDR.
+ float sdrAnimateValue = animateValue;
+ if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ && ((mBrightnessReason.modifier & BrightnessReason.MODIFIER_DIMMED) == 0
+ || (mBrightnessReason.modifier & BrightnessReason.MODIFIER_LOW_POWER) == 0)) {
+ animateValue = mHbmController.getHdrBrightnessValue();
+ }
+
final float currentBrightness = mPowerState.getScreenBrightness();
+ final float currentSdrBrightness = mPowerState.getSdrScreenBrightness();
if (isValidBrightnessValue(animateValue)
- && !BrightnessSynchronizer.floatEquals(animateValue, currentBrightness)) {
+ && (!BrightnessSynchronizer.floatEquals(animateValue, currentBrightness)
+ || !BrightnessSynchronizer.floatEquals(
+ sdrAnimateValue, currentSdrBrightness))) {
if (initialRampSkip || hasBrightnessBuckets
|| wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
- animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM);
+ animateScreenBrightness(animateValue, sdrAnimateValue,
+ SCREEN_ANIMATION_RATE_MINIMUM);
} else {
boolean isIncreasing = animateValue > currentBrightness;
final float rampSpeed;
@@ -1300,7 +1340,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} else {
rampSpeed = mBrightnessRampRateFastDecrease;
}
- animateScreenBrightness(animateValue, rampSpeed);
+ animateScreenBrightness(animateValue, sdrAnimateValue, rampSpeed);
}
}
@@ -1446,9 +1486,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private HighBrightnessModeController createHbmController() {
final DisplayDeviceConfig ddConfig =
mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
+ final IBinder displayToken =
+ mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayTokenLocked();
final DisplayDeviceConfig.HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
- return new HighBrightnessModeController(mHandler, PowerManager.BRIGHTNESS_MIN,
+ return new HighBrightnessModeController(mHandler, displayToken, PowerManager.BRIGHTNESS_MIN,
PowerManager.BRIGHTNESS_MAX, hbmData,
() -> {
sendUpdatePowerStateLocked();
@@ -1596,11 +1638,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
&& brightnessState <= PowerManager.BRIGHTNESS_MAX;
}
- private void animateScreenBrightness(float target, float rate) {
+ private void animateScreenBrightness(float target, float sdrTarget, float rate) {
if (DEBUG) {
- Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
+ Slog.d(TAG, "Animating brightness: target=" + target + ", sdrTarget=" + sdrTarget
+ + ", rate=" + rate);
}
- if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
+ if (mScreenBrightnessRampAnimator.animateTo(target, sdrTarget, rate)) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target);
// TODO(b/153319140) remove when we can get this from the above trace invocation
SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target));
@@ -2295,6 +2338,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return;
}
handleSettingsChange(false /*userSwitch*/);
+ break;
}
}
}
@@ -2392,7 +2436,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
static final int MODIFIER_DIMMED = 0x1;
static final int MODIFIER_LOW_POWER = 0x2;
- static final int MODIFIER_MASK = 0x3;
+ static final int MODIFIER_HDR = 0x4;
+ static final int MODIFIER_MASK = MODIFIER_DIMMED | MODIFIER_LOW_POWER | MODIFIER_HDR;
// ADJUSTMENT_*
// These things can happen at any point, even if the main brightness reason doesn't
@@ -2464,6 +2509,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if ((modifier & MODIFIER_DIMMED) != 0) {
sb.append(" dim");
}
+ if ((modifier & MODIFIER_HDR) != 0) {
+ sb.append(" hdr");
+ }
int strlen = sb.length();
if (sb.charAt(strlen - 1) == '[') {
sb.setLength(strlen - 2);
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 77aff5b03dd2..b58dd38348aa 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -62,6 +62,7 @@ final class DisplayPowerState {
private int mScreenState;
private float mScreenBrightness;
+ private float mSdrScreenBrightness;
private boolean mScreenReady;
private boolean mScreenUpdatePending;
@@ -92,6 +93,7 @@ final class DisplayPowerState {
mScreenState = displayState;
mScreenBrightness = (displayState != Display.STATE_OFF) ? PowerManager.BRIGHTNESS_MAX
: PowerManager.BRIGHTNESS_OFF_FLOAT;
+ mSdrScreenBrightness = mScreenBrightness;
scheduleScreenUpdate();
mColorFadePrepared = false;
@@ -126,6 +128,19 @@ final class DisplayPowerState {
}
};
+ public static final FloatProperty<DisplayPowerState> SCREEN_SDR_BRIGHTNESS_FLOAT =
+ new FloatProperty<DisplayPowerState>("sdrScreenBrightnessFloat") {
+ @Override
+ public void setValue(DisplayPowerState object, float value) {
+ object.setSdrScreenBrightness(value);
+ }
+
+ @Override
+ public Float get(DisplayPowerState object) {
+ return object.getSdrScreenBrightness();
+ }
+ };
+
/**
* Sets whether the screen is on, off, or dozing.
*/
@@ -149,12 +164,38 @@ final class DisplayPowerState {
}
/**
+ * Sets the display's SDR brightness.
+ *
+ * @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest).
+ */
+ public void setSdrScreenBrightness(float brightness) {
+ if (!BrightnessSynchronizer.floatEquals(mSdrScreenBrightness, brightness)) {
+ if (DEBUG) {
+ Slog.d(TAG, "setSdrScreenBrightness: brightness=" + brightness);
+ }
+
+ mSdrScreenBrightness = brightness;
+ if (mScreenState != Display.STATE_OFF) {
+ mScreenReady = false;
+ scheduleScreenUpdate();
+ }
+ }
+ }
+
+ /**
+ * Gets the screen SDR brightness.
+ */
+ public float getSdrScreenBrightness() {
+ return mSdrScreenBrightness;
+ }
+
+ /**
* Sets the display brightness.
*
* @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest).
*/
public void setScreenBrightness(float brightness) {
- if (mScreenBrightness != brightness) {
+ if (!BrightnessSynchronizer.floatEquals(mScreenBrightness, brightness)) {
if (DEBUG) {
Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
}
@@ -286,6 +327,7 @@ final class DisplayPowerState {
pw.println(" mStopped=" + mStopped);
pw.println(" mScreenState=" + Display.stateToString(mScreenState));
pw.println(" mScreenBrightness=" + mScreenBrightness);
+ pw.println(" mSdrScreenBrightness=" + mSdrScreenBrightness);
pw.println(" mScreenReady=" + mScreenReady);
pw.println(" mScreenUpdatePending=" + mScreenUpdatePending);
pw.println(" mColorFadePrepared=" + mColorFadePrepared);
@@ -332,7 +374,10 @@ final class DisplayPowerState {
float brightnessState = mScreenState != Display.STATE_OFF
&& mColorFadeLevel > 0f ? mScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT;
- if (mPhotonicModulator.setState(mScreenState, brightnessState)) {
+ float sdrBrightnessState = mScreenState != Display.STATE_OFF
+ && mColorFadeLevel > 0f
+ ? mSdrScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT;
+ if (mPhotonicModulator.setState(mScreenState, brightnessState, sdrBrightnessState)) {
if (DEBUG) {
Slog.d(TAG, "Screen ready");
}
@@ -373,8 +418,10 @@ final class DisplayPowerState {
private int mPendingState = INITIAL_SCREEN_STATE;
private float mPendingBacklight = INITIAL_BACKLIGHT_FLOAT;
+ private float mPendingSdrBacklight = INITIAL_BACKLIGHT_FLOAT;
private int mActualState = INITIAL_SCREEN_STATE;
private float mActualBacklight = INITIAL_BACKLIGHT_FLOAT;
+ private float mActualSdrBacklight = INITIAL_BACKLIGHT_FLOAT;
private boolean mStateChangeInProgress;
private boolean mBacklightChangeInProgress;
@@ -382,11 +429,13 @@ final class DisplayPowerState {
super("PhotonicModulator");
}
- public boolean setState(int state, float brightnessState) {
+ public boolean setState(int state, float brightnessState, float sdrBrightnessState) {
synchronized (mLock) {
boolean stateChanged = state != mPendingState;
- boolean backlightChanged = !BrightnessSynchronizer.floatEquals(
- brightnessState, mPendingBacklight);
+ boolean backlightChanged =
+ !BrightnessSynchronizer.floatEquals(brightnessState, mPendingBacklight)
+ || !BrightnessSynchronizer.floatEquals(
+ sdrBrightnessState, mPendingSdrBacklight);
if (stateChanged || backlightChanged) {
if (DEBUG) {
Slog.d(TAG, "Requesting new screen state: state="
@@ -395,6 +444,7 @@ final class DisplayPowerState {
mPendingState = state;
mPendingBacklight = brightnessState;
+ mPendingSdrBacklight = sdrBrightnessState;
boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
mStateChangeInProgress = stateChanged || mStateChangeInProgress;
mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
@@ -413,8 +463,10 @@ final class DisplayPowerState {
pw.println("Photonic Modulator State:");
pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mPendingBacklight=" + mPendingBacklight);
+ pw.println(" mPendingSdrBacklight=" + mPendingSdrBacklight);
pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight);
+ pw.println(" mActualSdrBacklight=" + mActualSdrBacklight);
pw.println(" mStateChangeInProgress=" + mStateChangeInProgress);
pw.println(" mBacklightChangeInProgress=" + mBacklightChangeInProgress);
}
@@ -427,13 +479,17 @@ final class DisplayPowerState {
final int state;
final boolean stateChanged;
final float brightnessState;
+ final float sdrBrightnessState;
final boolean backlightChanged;
synchronized (mLock) {
state = mPendingState;
stateChanged = (state != mActualState);
brightnessState = mPendingBacklight;
- backlightChanged = !BrightnessSynchronizer.floatEquals(
- brightnessState, mActualBacklight);
+ sdrBrightnessState = mPendingSdrBacklight;
+ backlightChanged =
+ !BrightnessSynchronizer.floatEquals(brightnessState, mActualBacklight)
+ || !BrightnessSynchronizer.floatEquals(
+ sdrBrightnessState, mActualSdrBacklight);
if (!stateChanged) {
// State changed applied, notify outer class.
postScreenUpdateThreadSafe();
@@ -454,14 +510,17 @@ final class DisplayPowerState {
}
mActualState = state;
mActualBacklight = brightnessState;
+ mActualSdrBacklight = sdrBrightnessState;
}
// Apply pending change.
if (DEBUG) {
Slog.d(TAG, "Updating screen state: id=" + mDisplayId + ", state="
- + Display.stateToString(state) + ", backlight=" + brightnessState);
+ + Display.stateToString(state) + ", backlight=" + brightnessState
+ + ", sdrBacklight=" + sdrBrightnessState);
}
- mBlanker.requestDisplayState(mDisplayId, state, brightnessState);
+ mBlanker.requestDisplayState(mDisplayId, state, brightnessState,
+ sdrBrightnessState);
}
}
}
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index e6486bd2a79a..b9487779dfd3 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -18,9 +18,11 @@ package com.android.server.display;
import android.hardware.display.BrightnessInfo;
import android.os.Handler;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Slog;
+import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
@@ -45,17 +47,21 @@ class HighBrightnessModeController {
private final float mBrightnessMin;
private final float mBrightnessMax;
- private final HighBrightnessModeData mHbmData;
private final Handler mHandler;
private final Runnable mHbmChangeCallback;
private final Runnable mRecalcRunnable;
private final Clock mClock;
+ private SurfaceControlHdrLayerInfoListener mHdrListener;
+ private HighBrightnessModeData mHbmData;
+ private IBinder mRegisteredDisplayToken;
+
private boolean mIsInAllowedAmbientRange = false;
private boolean mIsTimeAvailable = false;
private boolean mIsAutoBrightnessEnabled = false;
private float mAutoBrightness;
private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
+ private boolean mIsHdrLayerPresent = false;
/**
* If HBM is currently running, this is the start time for the current HBM session.
@@ -69,23 +75,26 @@ class HighBrightnessModeController {
*/
private LinkedList<HbmEvent> mEvents = new LinkedList<>();
- HighBrightnessModeController(Handler handler, float brightnessMin, float brightnessMax,
- HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
- this(SystemClock::uptimeMillis, handler, brightnessMin, brightnessMax, hbmData,
- hbmChangeCallback);
+ HighBrightnessModeController(Handler handler, IBinder displayToken, float brightnessMin,
+ float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
+ this(SystemClock::uptimeMillis, handler, displayToken, brightnessMin, brightnessMax,
+ hbmData, hbmChangeCallback);
}
@VisibleForTesting
- HighBrightnessModeController(Clock clock, Handler handler, float brightnessMin,
- float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
+ HighBrightnessModeController(Clock clock, Handler handler, IBinder displayToken,
+ float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData,
+ Runnable hbmChangeCallback) {
mClock = clock;
mHandler = handler;
mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax;
- mHbmData = hbmData;
mHbmChangeCallback = hbmChangeCallback;
mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mRecalcRunnable = this::recalculateTimeAllowance;
+ mHdrListener = new HdrListener();
+
+ resetHbmData(displayToken, hbmData);
}
void setAutoBrightnessEnabled(boolean isEnabled) {
@@ -117,6 +126,10 @@ class HighBrightnessModeController {
}
}
+ float getHdrBrightnessValue() {
+ return mBrightnessMax;
+ }
+
void onAmbientLuxChange(float ambientLux) {
if (!deviceSupportsHbm() || !mIsAutoBrightnessEnabled) {
return;
@@ -138,11 +151,12 @@ class HighBrightnessModeController {
// If we are starting or ending a high brightness mode session, store the current
// session in mRunningStartTimeMillis, or the old one in mEvents.
- final boolean wasOldBrightnessHigh = oldAutoBrightness > mHbmData.transitionPoint;
- final boolean isNewBrightnessHigh = mAutoBrightness > mHbmData.transitionPoint;
- if (wasOldBrightnessHigh != isNewBrightnessHigh) {
+ final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1;
+ final boolean shouldHbmDrainAvailableTime = mAutoBrightness > mHbmData.transitionPoint
+ && !mIsHdrLayerPresent;
+ if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) {
final long currentTime = mClock.uptimeMillis();
- if (isNewBrightnessHigh) {
+ if (shouldHbmDrainAvailableTime) {
mRunningStartTimeMillis = currentTime;
} else {
mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime));
@@ -161,30 +175,49 @@ class HighBrightnessModeController {
return mHbmMode;
}
+ void stop() {
+ registerHdrListener(null /*displayToken*/);
+ }
+
+ void resetHbmData(IBinder displayToken, HighBrightnessModeData hbmData) {
+ mHbmData = hbmData;
+ unregisterHdrListener();
+ if (deviceSupportsHbm()) {
+ registerHdrListener(displayToken);
+ recalculateTimeAllowance();
+ }
+ }
+
void dump(PrintWriter pw) {
pw.println("HighBrightnessModeController:");
- pw.println(" mBrightnessMin=" + mBrightnessMin);
- pw.println(" mBrightnessMax=" + mBrightnessMax);
+ pw.println(" mCurrentMin=" + getCurrentBrightnessMin());
+ pw.println(" mCurrentMax=" + getCurrentBrightnessMax());
+ pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode));
+ pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis()));
pw.println(" mHbmData=" + mHbmData);
pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange);
pw.println(" mIsTimeAvailable= " + mIsTimeAvailable);
pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled);
pw.println(" mAutoBrightness=" + mAutoBrightness);
+ pw.println(" mIsHdrLayerPresent=" + mIsHdrLayerPresent);
+ pw.println(" mBrightnessMin=" + mBrightnessMin);
+ pw.println(" mBrightnessMax=" + mBrightnessMax);
}
private boolean isCurrentlyAllowed() {
- return mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange;
+ return mIsHdrLayerPresent
+ || (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange);
}
private boolean deviceSupportsHbm() {
return mHbmData != null;
}
- /**
- * Recalculates the allowable HBM time.
- */
- private void recalculateTimeAllowance() {
- final long currentTime = mClock.uptimeMillis();
+ private long calculateRemainingTime(long currentTime) {
+ if (!deviceSupportsHbm()) {
+ return 0;
+ }
+
long timeAlreadyUsed = 0;
// First, lets see how much time we've taken for any currently running
@@ -222,8 +255,15 @@ class HighBrightnessModeController {
Slog.d(TAG, "Time already used after all sessions: " + timeAlreadyUsed);
}
- // See how much allowable time we have left.
- final long remainingTime = Math.max(0, mHbmData.timeMaxMillis - timeAlreadyUsed);
+ return Math.max(0, mHbmData.timeMaxMillis - timeAlreadyUsed);
+ }
+
+ /**
+ * Recalculates the allowable HBM time.
+ */
+ private void recalculateTimeAllowance() {
+ final long currentTime = mClock.uptimeMillis();
+ final long remainingTime = calculateRemainingTime(currentTime);
// We allow HBM if there is more than the minimum required time available
// or if brightness is already in the high range, if there is any time left at all.
@@ -242,6 +282,7 @@ class HighBrightnessModeController {
// If we are not allowed...timeout when the oldest event moved outside of the timing
// window by at least minTime. Basically, we're calculating the soonest time we can
// get {@code timeMinMillis} back to us.
+ final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
final HbmEvent lastEvent = mEvents.getLast();
final long startTimePlusMinMillis =
Math.max(windowstartTimeMillis, lastEvent.startTimeMillis)
@@ -278,12 +319,36 @@ class HighBrightnessModeController {
}
private int calculateHighBrightnessMode() {
- if (deviceSupportsHbm() && isCurrentlyAllowed()) {
+ if (!deviceSupportsHbm()) {
+ return BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
+ } else if (mIsHdrLayerPresent) {
+ return BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR;
+ } else if (isCurrentlyAllowed()) {
return BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
}
+
return BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
}
+ private void registerHdrListener(IBinder displayToken) {
+ if (mRegisteredDisplayToken == displayToken) {
+ return;
+ }
+
+ unregisterHdrListener();
+ mRegisteredDisplayToken = displayToken;
+ if (mRegisteredDisplayToken != null) {
+ mHdrListener.register(mRegisteredDisplayToken);
+ }
+ }
+
+ private void unregisterHdrListener() {
+ if (mRegisteredDisplayToken != null) {
+ mHdrListener.unregister(mRegisteredDisplayToken);
+ mIsHdrLayerPresent = false;
+ }
+ }
+
/**
* Represents an event in which High Brightness Mode was enabled.
*/
@@ -302,4 +367,18 @@ class HighBrightnessModeController {
+ ((endTimeMillis - startTimeMillis) / 1000) + "]";
}
}
+
+ private class HdrListener extends SurfaceControlHdrLayerInfoListener {
+ @Override
+ public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
+ int maxW, int maxH, int flags) {
+ mHandler.post(() -> {
+ mIsHdrLayerPresent = numberOfHdrLayers > 0;
+ // Calling the auto-brightness update so that we can recalculate
+ // auto-brightness with HDR in mind. When HDR layers are present,
+ // we don't limit auto-brightness' HBM time limits.
+ onAutoBrightnessChanged(mAutoBrightness);
+ });
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 2546118f1cc7..754e35eff6c1 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -67,6 +67,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final int NO_DISPLAY_MODE_ID = 0;
+ private static final float NITS_INVALID = -1;
+
private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>();
private final Injector mInjector;
@@ -190,6 +192,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int mState = Display.STATE_UNKNOWN;
// This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private int mDefaultModeId;
private int mDefaultModeGroup;
private int mActiveModeId;
@@ -644,13 +647,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public Runnable requestDisplayStateLocked(final int state, final float brightnessState) {
+ public Runnable requestDisplayStateLocked(final int state, final float brightnessState,
+ final float sdrBrightnessState) {
// Assume that the brightness is off if the display is being turned off.
assert state != Display.STATE_OFF || BrightnessSynchronizer.floatEquals(
brightnessState, PowerManager.BRIGHTNESS_OFF_FLOAT);
final boolean stateChanged = (mState != state);
- final boolean brightnessChanged = (!BrightnessSynchronizer.floatEquals(
- mBrightnessState, brightnessState));
+ final boolean brightnessChanged =
+ !(BrightnessSynchronizer.floatEquals(mBrightnessState, brightnessState)
+ && BrightnessSynchronizer.floatEquals(mSdrBrightnessState, sdrBrightnessState));
if (stateChanged || brightnessChanged) {
final long physicalDisplayId = mPhysicalDisplayId;
final IBinder token = getDisplayTokenLocked();
@@ -702,8 +707,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Apply brightness changes given that we are in a non-suspended state.
if (brightnessChanged || vrModeChange) {
- setDisplayBrightness(brightnessState);
+ setDisplayBrightness(brightnessState, sdrBrightnessState);
mBrightnessState = brightnessState;
+ mSdrBrightnessState = sdrBrightnessState;
}
// Enter the final desired state, possibly suspended.
@@ -764,8 +770,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- private void setDisplayBrightness(float brightness) {
- // Ensure brightnessState is valid, before processing and sending to
+ private void setDisplayBrightness(float brightness, float sdrBrightness) {
+ // Ensure brightnessState is valid before processing and sending to
// surface control
if (Float.isNaN(brightness)) {
return;
@@ -774,17 +780,31 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (DEBUG) {
Slog.d(TAG, "setDisplayBrightness("
+ "id=" + physicalDisplayId
- + ", brightness=" + brightness + ")");
+ + ", brightness=" + brightness
+ + ", sdrBrightness=" + sdrBrightness + ")");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
- + "id=" + physicalDisplayId + ", brightness=" + brightness + ")");
+ + "id=" + physicalDisplayId + ", brightness=" + brightness
+ + ", sdrBrightness=" + sdrBrightness + ")");
try {
- float backlight = brightnessToBacklight(brightness);
- mBacklightAdapter.setBacklight(backlight);
+ final float backlight = brightnessToBacklight(brightness);
+ float nits = NITS_INVALID;
+ float sdrBacklight = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ float sdrNits = NITS_INVALID;
+ if (getDisplayDeviceConfig().hasNitsMapping()
+ && sdrBrightness != PowerManager.BRIGHTNESS_INVALID_FLOAT) {
+ nits = backlightToNits(backlight);
+ sdrBacklight = brightnessToBacklight(sdrBrightness);
+ sdrNits = backlightToNits(sdrBacklight);
+ }
+ mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits);
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(brightness));
+ Trace.traceCounter(Trace.TRACE_TAG_POWER,
+ "SdrScreenBrightness",
+ BrightnessSynchronizer.brightnessFloatToInt(sdrBrightness));
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -793,6 +813,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private float brightnessToBacklight(float brightness) {
return getDisplayDeviceConfig().getBacklightFromBrightness(brightness);
}
+
+ private float backlightToNits(float backlight) {
+ return getDisplayDeviceConfig().getNitsFromBacklight(backlight);
+ }
};
}
return null;
@@ -1242,6 +1266,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public boolean setDisplayBrightness(IBinder displayToken, float brightness) {
return SurfaceControl.setDisplayBrightness(displayToken, brightness);
}
+
+ public boolean setDisplayBrightness(IBinder displayToken, float sdrBacklight,
+ float sdrNits, float displayBacklight, float displayNits) {
+ return SurfaceControl.setDisplayBrightness(displayToken, sdrBacklight, sdrNits,
+ displayBacklight, displayNits);
+ }
+
}
static class BacklightAdapter {
@@ -1273,9 +1304,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
// Set backlight within min and max backlight values
- void setBacklight(float backlight) {
+ void setBacklight(float sdrBacklight, float sdrNits, float backlight, float nits) {
if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
- mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
+ if (sdrBacklight == PowerManager.BRIGHTNESS_INVALID_FLOAT) {
+ mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
+ } else {
+ mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, sdrBacklight, sdrNits,
+ backlight, nits);
+ }
} else if (mBacklight != null) {
mBacklight.setBrightness(backlight);
}
diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java
index 26004a8da1a1..20feafa2d19c 100644
--- a/services/core/java/com/android/server/display/RampAnimator.java
+++ b/services/core/java/com/android/server/display/RampAnimator.java
@@ -26,7 +26,7 @@ import com.android.internal.display.BrightnessSynchronizer;
* A custom animator that progressively updates a property value at
* a given variable rate until it reaches a particular target value.
*/
-final class RampAnimator<T> {
+class RampAnimator<T> {
private final T mObject;
private final FloatProperty<T> mProperty;
private final Choreographer mChoreographer;
@@ -174,4 +174,52 @@ final class RampAnimator<T> {
public interface Listener {
void onAnimationEnd();
}
+
+ static class DualRampAnimator<T> {
+ private final RampAnimator<T> mFirst;
+ private final RampAnimator<T> mSecond;
+ private final Listener mInternalListener = new Listener() {
+ @Override
+ public void onAnimationEnd() {
+ if (mListener != null && !isAnimating()) {
+ mListener.onAnimationEnd();
+ }
+ }
+ };
+
+ private Listener mListener;
+
+ DualRampAnimator(T object, FloatProperty<T> firstProperty,
+ FloatProperty<T> secondProperty) {
+ mFirst = new RampAnimator(object, firstProperty);
+ mFirst.setListener(mInternalListener);
+ mSecond = new RampAnimator(object, secondProperty);
+ mSecond.setListener(mInternalListener);
+ }
+
+ /**
+ * Starts animating towards the specified values.
+ *
+ * If this is the first time the property is being set or if the rate is 0,
+ * the value jumps directly to the target.
+ *
+ * @param firstTarget The first target value.
+ * @param secondTarget The second target value.
+ * @param rate The convergence rate in units per second, or 0 to set the value immediately.
+ * @return True if either target differs from the previous target.
+ */
+ public boolean animateTo(float firstTarget, float secondTarget, float rate) {
+ final boolean firstRetval = mFirst.animateTo(firstTarget, rate);
+ final boolean secondRetval = mSecond.animateTo(secondTarget, rate);
+ return firstRetval && secondRetval;
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public boolean isAnimating() {
+ return mFirst.isAnimating() && mSecond.isAnimating();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 52a810bd8caa..b7931c8a8424 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -293,7 +293,8 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
@Override
- public Runnable requestDisplayStateLocked(int state, float brightnessState) {
+ public Runnable requestDisplayStateLocked(int state, float brightnessState,
+ float sdrBrightnessState) {
if (state != mDisplayState) {
mDisplayState = state;
if (state == Display.STATE_OFF) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index f1d8e6c167d7..e1012a9a4cad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -649,14 +649,14 @@ public class LocalDisplayAdapterTest {
// Test as default display
BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
mSurfaceControlProxy);
- ba.setBacklight(0.514f);
- verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f);
+ ba.setBacklight(0.514f, 100f, 0.614f, 500f);
+ verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f, 100f, 0.614f, 500f);
// Test as not default display
BacklightAdapter ba2 = new BacklightAdapter(displayToken, false /*isDefault*/,
mSurfaceControlProxy);
- ba2.setBacklight(0.323f);
- verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f);
+ ba2.setBacklight(0.323f, 101f, 0.723f, 601f);
+ verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f, 101f, 0.723f, 601f);
}
@Test
@@ -668,7 +668,7 @@ public class LocalDisplayAdapterTest {
BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
mSurfaceControlProxy);
- ba.setBacklight(0.123f);
+ ba.setBacklight(1f, 1f, 0.123f, 1f);
verify(mMockedBacklight).setBrightness(0.123f);
}
@@ -681,7 +681,7 @@ public class LocalDisplayAdapterTest {
BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/,
mSurfaceControlProxy);
- ba.setBacklight(0.456f);
+ ba.setBacklight(0.456f, 1f, 1f, 1f);
// Adapter does not forward any brightness in this case.
verify(mMockedBacklight, never()).setBrightness(anyFloat());
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 88a21b4a8fa8..8e4cdc91d0e6 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -21,6 +21,7 @@ import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLI
import static org.junit.Assert.assertEquals;
+import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.os.test.TestLooper;
@@ -55,6 +56,7 @@ public class HighBrightnessModeControllerTest {
private OffsettableClock mClock;
private TestLooper mTestLooper;
private Handler mHandler;
+ private Binder mDisplayToken;
private static final HighBrightnessModeData DEFAULT_HBM_DATA =
new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
@@ -64,6 +66,7 @@ public class HighBrightnessModeControllerTest {
public void setUp() {
mClock = new OffsettableClock.Stopped();
mTestLooper = new TestLooper(mClock::now);
+ mDisplayToken = null;
mHandler = new Handler(mTestLooper.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
@@ -79,14 +82,14 @@ public class HighBrightnessModeControllerTest {
@Test
public void testNoHbmData() {
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
- mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX, null, () -> {});
+ mClock::now, mHandler, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, null, () -> {});
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
}
@Test
public void testNoHbmData_Enabled() {
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
- mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX, null, () -> {});
+ mClock::now, mHandler, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, null, () -> {});
hbmc.setAutoBrightnessEnabled(true);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -264,8 +267,8 @@ public class HighBrightnessModeControllerTest {
// Creates instance with standard initialization values.
private HighBrightnessModeController createDefaultHbm() {
- return new HighBrightnessModeController(mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX,
- DEFAULT_HBM_DATA, () -> {});
+ return new HighBrightnessModeController(mClock::now, mHandler, mDisplayToken, DEFAULT_MIN,
+ DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {});
}
private void advanceTime(long timeMs) {