diff options
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) { |