Merge "Add HDR-HBM support into framework." into sc-dev

This commit is contained in:
Santos Cordon
2021-04-30 14:40:35 +00:00
committed by Android (Google) Code Review
14 changed files with 461 additions and 103 deletions

View File

@@ -33,7 +33,8 @@ public final class BrightnessInfo implements Parcelable {
@IntDef(prefix = {"HIGH_BRIGHTNESS_MODE_"}, value = { @IntDef(prefix = {"HIGH_BRIGHTNESS_MODE_"}, value = {
HIGH_BRIGHTNESS_MODE_OFF, HIGH_BRIGHTNESS_MODE_OFF,
HIGH_BRIGHTNESS_MODE_SUNLIGHT HIGH_BRIGHTNESS_MODE_SUNLIGHT,
HIGH_BRIGHTNESS_MODE_HDR
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface HighBrightnessMode {} public @interface HighBrightnessMode {}
@@ -50,6 +51,12 @@ public final class BrightnessInfo implements Parcelable {
*/ */
public static final int HIGH_BRIGHTNESS_MODE_SUNLIGHT = 1; 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 */ /** Brightness */
public final float brightness; public final float brightness;
@@ -73,6 +80,21 @@ public final class BrightnessInfo implements Parcelable {
this.highBrightnessMode = highBrightnessMode; 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 @Override
public int describeContents() { public int describeContents() {
return 0; return 0;

View File

@@ -738,13 +738,19 @@ class AutomaticBrightnessController {
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
mForegroundAppCategory); mForegroundAppCategory);
float newScreenAutoBrightness = clampScreenBrightness(value); 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, // 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 // in which case we ignore the new screen brightness if it doesn't differ enough from the
// previous one. // previous one.
if (!Float.isNaN(mScreenAutoBrightness) if (!Float.isNaN(mScreenAutoBrightness)
&& !isManuallySet && !isManuallySet
&& newScreenAutoBrightness > mScreenDarkeningThreshold && newScreenAutoBrightness > mScreenDarkeningThreshold
&& newScreenAutoBrightness < mScreenBrighteningThreshold) { && newScreenAutoBrightness < mScreenBrighteningThreshold
&& currentBrightnessWithinAllowedRange) {
if (mLoggingEnabled) { if (mLoggingEnabled) {
Slog.d(TAG, "ignoring newScreenAutoBrightness: " Slog.d(TAG, "ignoring newScreenAutoBrightness: "
+ mScreenDarkeningThreshold + " < " + newScreenAutoBrightness + mScreenDarkeningThreshold + " < " + newScreenAutoBrightness

View File

@@ -20,5 +20,8 @@ package com.android.server.display;
* Interface used to update the actual display state. * Interface used to update the actual display state.
*/ */
public interface DisplayBlanker { 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);
} }

View File

@@ -156,10 +156,12 @@ abstract class DisplayDevice {
* *
* @param state The new display state. * @param state The new display state.
* @param brightnessState The new display brightnessState. * @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 * @return A runnable containing work to be deferred until after we have
* exited the critical section, or null if none. * 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; return null;
} }

View File

@@ -104,6 +104,7 @@ public class DisplayDeviceConfig {
private float mBrightnessRampSlowIncrease = Float.NaN; private float mBrightnessRampSlowIncrease = Float.NaN;
private Spline mBrightnessToBacklightSpline; private Spline mBrightnessToBacklightSpline;
private Spline mBacklightToBrightnessSpline; private Spline mBacklightToBrightnessSpline;
private Spline mBacklightToNitsSpline;
private List<String> mQuirks; private List<String> mQuirks;
private boolean mIsHighBrightnessModeEnabled = false; private boolean mIsHighBrightnessModeEnabled = false;
private HighBrightnessModeData mHbmData; private HighBrightnessModeData mHbmData;
@@ -218,6 +219,20 @@ public class DisplayDeviceConfig {
return mBrightnessToBacklightSpline.interpolate(brightness); return mBrightnessToBacklightSpline.interpolate(brightness);
} }
/**
* 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 * Return an array of equal length to backlight and nits, that covers the entire system
* brightness range of 0.0-1.0. * brightness range of 0.0-1.0.
@@ -257,6 +272,13 @@ public class DisplayDeviceConfig {
return mAmbientLightSensor; return mAmbientLightSensor;
} }
/**
* @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. * @param quirkValue The quirk to test.
* @return {@code true} if the specified quirk is present in this configuration, * @return {@code true} if the specified quirk is present in this configuration,
@@ -584,6 +606,7 @@ public class DisplayDeviceConfig {
} }
mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight); mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness); mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
mBacklightToNitsSpline = Spline.createSpline(mBacklight, mNits);
} }
private void loadQuirks(DisplayConfiguration config) { private void loadQuirks(DisplayConfiguration config) {

View File

@@ -257,7 +257,8 @@ public final class DisplayManagerService extends SystemService {
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() { private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
// Synchronized to avoid race conditions when updating multiple display states. // Synchronized to avoid race conditions when updating multiple display states.
@Override @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 allInactive = true;
boolean allOff = true; boolean allOff = true;
final boolean stateChanged; final boolean stateChanged;
@@ -288,7 +289,7 @@ public final class DisplayManagerService extends SystemService {
// The order of operations is important for legacy reasons. // The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) { if (state == Display.STATE_OFF) {
requestDisplayStateInternal(displayId, state, brightness); requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
} }
if (stateChanged) { if (stateChanged) {
@@ -296,7 +297,7 @@ public final class DisplayManagerService extends SystemService {
} }
if (state != Display.STATE_OFF) { 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. // A map from LogicalDisplay ID to display brightness.
@GuardedBy("mSyncRoot") @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 // Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state. // to the surface flinger state.
@@ -667,11 +668,8 @@ public final class DisplayManagerService extends SystemService {
} }
} }
private void requestDisplayStateInternal(int displayId, int state, float brightnessState) { private float clampBrightness(int displayState, float brightnessState) {
if (state == Display.STATE_UNKNOWN) { if (displayState == Display.STATE_OFF) {
state = Display.STATE_ON;
}
if (state == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT; brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
} else if (brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT } else if (brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT
&& brightnessState < PowerManager.BRIGHTNESS_MIN) { && brightnessState < PowerManager.BRIGHTNESS_MIN) {
@@ -679,6 +677,17 @@ public final class DisplayManagerService extends SystemService {
} else if (brightnessState > PowerManager.BRIGHTNESS_MAX) { } else if (brightnessState > PowerManager.BRIGHTNESS_MAX) {
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. // Update the display state within the lock.
// Note that we do not need to schedule traversals here although it // Note that we do not need to schedule traversals here although it
@@ -688,20 +697,26 @@ public final class DisplayManagerService extends SystemService {
synchronized (mSyncRoot) { synchronized (mSyncRoot) {
final int index = mDisplayStates.indexOfKey(displayId); final int index = mDisplayStates.indexOfKey(displayId);
final BrightnessPair brightnessPair =
index < 0 ? null : mDisplayBrightnesses.valueAt(index);
if (index < 0 || (mDisplayStates.valueAt(index) == state if (index < 0 || (mDisplayStates.valueAt(index) == state
&& BrightnessSynchronizer.floatEquals(mDisplayBrightnesses.valueAt(index), && BrightnessSynchronizer.floatEquals(
brightnessState))) { brightnessPair.brightness, brightnessState)
&& BrightnessSynchronizer.floatEquals(
brightnessPair.sdrBrightness, sdrBrightnessState))) {
return; // Display no longer exists or no change. return; // Display no longer exists or no change.
} }
traceMessage = "requestDisplayStateInternal(" traceMessage = "requestDisplayStateInternal("
+ displayId + ", " + displayId + ", "
+ Display.stateToString(state) + Display.stateToString(state)
+ ", brightness=" + brightnessState + ")"; + ", brightness=" + brightnessState
+ ", sdrBrightness=" + sdrBrightnessState + ")";
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, traceMessage, displayId); Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, traceMessage, displayId);
mDisplayStates.setValueAt(index, state); mDisplayStates.setValueAt(index, state);
mDisplayBrightnesses.setValueAt(index, brightnessState); brightnessPair.brightness = brightnessState;
brightnessPair.sdrBrightness = sdrBrightnessState;
runnable = updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId) runnable = updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId)
.getPrimaryDisplayDeviceLocked()); .getPrimaryDisplayDeviceLocked());
} }
@@ -1235,7 +1250,9 @@ public final class DisplayManagerService extends SystemService {
addDisplayPowerControllerLocked(display); addDisplayPowerControllerLocked(display);
mDisplayStates.append(displayId, Display.STATE_UNKNOWN); 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(); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1265,11 +1282,6 @@ public final class DisplayManagerService extends SystemService {
// this point. // this point.
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
scheduleTraversalLocked(false); scheduleTraversalLocked(false);
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.onDisplayChanged();
}
} }
private void handleLogicalDisplayFrameRateOverridesChangedLocked( private void handleLogicalDisplayFrameRateOverridesChangedLocked(
@@ -1301,6 +1313,11 @@ public final class DisplayManagerService extends SystemService {
if (work != null) { if (work != null) {
mHandler.post(work); mHandler.post(work);
} }
final int displayId = display.getDisplayIdLocked();
DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
dpc.onDisplayChanged();
}
handleLogicalDisplayChangedLocked(display); 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. // Only send a request for display state if display state has already been initialized.
if (state != Display.STATE_UNKNOWN) { if (state != Display.STATE_UNKNOWN) {
final float brightness = mDisplayBrightnesses.get(displayId); final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
return device.requestDisplayStateLocked(state, brightness); return device.requestDisplayStateLocked(state, brightnessPair.brightness,
brightnessPair.sdrBrightness);
} }
} }
return null; return null;
@@ -1935,10 +1953,11 @@ public final class DisplayManagerService extends SystemService {
for (int i = 0; i < displayStateCount; i++) { for (int i = 0; i < displayStateCount; i++) {
final int displayId = mDisplayStates.keyAt(i); final int displayId = mDisplayStates.keyAt(i);
final int displayState = mDisplayStates.valueAt(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 Id=" + displayId);
pw.println(" Display State=" + Display.stateToString(displayState)); 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, " "); 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. * Functional interface for providing time.
* TODO(b/184781936): merge with PowerManagerService.Clock * TODO(b/184781936): merge with PowerManagerService.Clock
@@ -3288,5 +3317,4 @@ public final class DisplayManagerService extends SystemService {
*/ */
long uptimeMillis(); long uptimeMillis();
} }
} }

View File

@@ -38,6 +38,7 @@ import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.metrics.LogMaker; import android.metrics.LogMaker;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.PowerManager; 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.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService; 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.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener; import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController; import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
@@ -223,6 +225,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@GuardedBy("mCachedBrightnessInfo") @GuardedBy("mCachedBrightnessInfo")
private final CachedBrightnessInfo mCachedBrightnessInfo = new CachedBrightnessInfo(); 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 // True if we should fade the screen while turning it off, false if we should play
// a stylish color fade animation instead. // a stylish color fade animation instead.
private boolean mColorFadeFadesConfig; private boolean mColorFadeFadesConfig;
@@ -424,7 +428,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Animators. // Animators.
private ObjectAnimator mColorFadeOnAnimator; private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator; private ObjectAnimator mColorFadeOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator; private DualRampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener; private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener;
// True if this DisplayPowerController has been stopped and should no longer be running. // 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) { Runnable onBrightnessChangeRunnable) {
mLogicalDisplay = logicalDisplay; mLogicalDisplay = logicalDisplay;
mDisplayId = mLogicalDisplay.getDisplayIdLocked(); mDisplayId = mLogicalDisplay.getDisplayIdLocked();
mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mHandler = new DisplayControllerHandler(handler.getLooper()); mHandler = new DisplayControllerHandler(handler.getLooper());
if (mDisplayId == Display.DEFAULT_DISPLAY) { 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 * when displays get swapped on foldable devices. For example, different brightness properties
* of each display need to be properly reflected in AutomaticBrightnessController. * of each display need to be properly reflected in AutomaticBrightnessController.
*/ */
@GuardedBy("DisplayManagerService.mSyncRoot")
public void onDisplayChanged() { public void onDisplayChanged() {
// TODO: b/175821789 - Support high brightness on multiple (folding) displays final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mUniqueDisplayId = mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); if (device == null) {
mDisplayDeviceConfig = mLogicalDisplay.getPrimaryDisplayDeviceLocked() Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
.getDisplayDeviceConfig(); + mLogicalDisplay.getDisplayIdLocked());
loadAmbientLightSensor(); 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); mColorFadeOffAnimator.addListener(mAnimatorListener);
} }
mScreenBrightnessRampAnimator = new RampAnimator<>( mScreenBrightnessRampAnimator = new DualRampAnimator<>(mPowerState,
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT); DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener); mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
noteScreenState(mPowerState.getScreenState()); 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. */ /** Clean up all resources that are accessed via the {@link #mHandler} thread. */
private void cleanupHandlerThreadAfterStop() { private void cleanupHandlerThreadAfterStop() {
setProximitySensorEnabled(false); setProximitySensorEnabled(false);
mHbmController.stop();
mHandler.removeCallbacksAndMessages(null); mHandler.removeCallbacksAndMessages(null);
if (mUnfinishedBusiness) { if (mUnfinishedBusiness) {
mCallbacks.releaseSuspendBlocker(); mCallbacks.releaseSuspendBlocker();
@@ -1205,9 +1229,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// timeout is about to expire. // timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) { if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightnessState > PowerManager.BRIGHTNESS_MIN) { if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
brightnessState = Math.max(Math.min(brightnessState brightnessState = Math.max(
- SCREEN_DIM_MINIMUM_REDUCTION_FLOAT, Math.min(brightnessState - SCREEN_DIM_MINIMUM_REDUCTION_FLOAT,
mScreenBrightnessDimConfig), PowerManager.BRIGHTNESS_MIN); mScreenBrightnessDimConfig),
PowerManager.BRIGHTNESS_MIN);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED); mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED);
} }
if (!mAppliedDimming) { if (!mAppliedDimming) {
@@ -1282,12 +1307,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// transformations to the brightness have pushed it outside of the currently // transformations to the brightness have pushed it outside of the currently
// allowed range. // allowed range.
float animateValue = clampScreenBrightness(brightnessState); 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 currentBrightness = mPowerState.getScreenBrightness();
final float currentSdrBrightness = mPowerState.getSdrScreenBrightness();
if (isValidBrightnessValue(animateValue) if (isValidBrightnessValue(animateValue)
&& !BrightnessSynchronizer.floatEquals(animateValue, currentBrightness)) { && (!BrightnessSynchronizer.floatEquals(animateValue, currentBrightness)
|| !BrightnessSynchronizer.floatEquals(
sdrAnimateValue, currentSdrBrightness))) {
if (initialRampSkip || hasBrightnessBuckets if (initialRampSkip || hasBrightnessBuckets
|| wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) { || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM); animateScreenBrightness(animateValue, sdrAnimateValue,
SCREEN_ANIMATION_RATE_MINIMUM);
} else { } else {
boolean isIncreasing = animateValue > currentBrightness; boolean isIncreasing = animateValue > currentBrightness;
final float rampSpeed; final float rampSpeed;
@@ -1300,7 +1340,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} else { } else {
rampSpeed = mBrightnessRampRateFastDecrease; rampSpeed = mBrightnessRampRateFastDecrease;
} }
animateScreenBrightness(animateValue, rampSpeed); animateScreenBrightness(animateValue, sdrAnimateValue, rampSpeed);
} }
} }
@@ -1446,9 +1486,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private HighBrightnessModeController createHbmController() { private HighBrightnessModeController createHbmController() {
final DisplayDeviceConfig ddConfig = final DisplayDeviceConfig ddConfig =
mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig(); mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
final IBinder displayToken =
mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayTokenLocked();
final DisplayDeviceConfig.HighBrightnessModeData hbmData = final DisplayDeviceConfig.HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null; ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
return new HighBrightnessModeController(mHandler, PowerManager.BRIGHTNESS_MIN, return new HighBrightnessModeController(mHandler, displayToken, PowerManager.BRIGHTNESS_MIN,
PowerManager.BRIGHTNESS_MAX, hbmData, PowerManager.BRIGHTNESS_MAX, hbmData,
() -> { () -> {
sendUpdatePowerStateLocked(); sendUpdatePowerStateLocked();
@@ -1596,11 +1638,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
&& brightnessState <= PowerManager.BRIGHTNESS_MAX; && brightnessState <= PowerManager.BRIGHTNESS_MAX;
} }
private void animateScreenBrightness(float target, float rate) { private void animateScreenBrightness(float target, float sdrTarget, float rate) {
if (DEBUG) { 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); Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target);
// TODO(b/153319140) remove when we can get this from the above trace invocation // TODO(b/153319140) remove when we can get this from the above trace invocation
SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target)); SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target));
@@ -2295,6 +2338,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return; return;
} }
handleSettingsChange(false /*userSwitch*/); handleSettingsChange(false /*userSwitch*/);
break;
} }
} }
} }
@@ -2392,7 +2436,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
static final int MODIFIER_DIMMED = 0x1; static final int MODIFIER_DIMMED = 0x1;
static final int MODIFIER_LOW_POWER = 0x2; 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_* // ADJUSTMENT_*
// These things can happen at any point, even if the main brightness reason doesn't // 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) { if ((modifier & MODIFIER_DIMMED) != 0) {
sb.append(" dim"); sb.append(" dim");
} }
if ((modifier & MODIFIER_HDR) != 0) {
sb.append(" hdr");
}
int strlen = sb.length(); int strlen = sb.length();
if (sb.charAt(strlen - 1) == '[') { if (sb.charAt(strlen - 1) == '[') {
sb.setLength(strlen - 2); sb.setLength(strlen - 2);

View File

@@ -62,6 +62,7 @@ final class DisplayPowerState {
private int mScreenState; private int mScreenState;
private float mScreenBrightness; private float mScreenBrightness;
private float mSdrScreenBrightness;
private boolean mScreenReady; private boolean mScreenReady;
private boolean mScreenUpdatePending; private boolean mScreenUpdatePending;
@@ -92,6 +93,7 @@ final class DisplayPowerState {
mScreenState = displayState; mScreenState = displayState;
mScreenBrightness = (displayState != Display.STATE_OFF) ? PowerManager.BRIGHTNESS_MAX mScreenBrightness = (displayState != Display.STATE_OFF) ? PowerManager.BRIGHTNESS_MAX
: PowerManager.BRIGHTNESS_OFF_FLOAT; : PowerManager.BRIGHTNESS_OFF_FLOAT;
mSdrScreenBrightness = mScreenBrightness;
scheduleScreenUpdate(); scheduleScreenUpdate();
mColorFadePrepared = false; 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. * Sets whether the screen is on, off, or dozing.
*/ */
@@ -148,13 +163,39 @@ final class DisplayPowerState {
return mScreenState; return mScreenState;
} }
/**
* 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. * Sets the display brightness.
* *
* @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest). * @param brightness The brightness, ranges from 0.0f (minimum / off) to 1.0f (brightest).
*/ */
public void setScreenBrightness(float brightness) { public void setScreenBrightness(float brightness) {
if (mScreenBrightness != brightness) { if (!BrightnessSynchronizer.floatEquals(mScreenBrightness, brightness)) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "setScreenBrightness: brightness=" + brightness); Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
} }
@@ -286,6 +327,7 @@ final class DisplayPowerState {
pw.println(" mStopped=" + mStopped); pw.println(" mStopped=" + mStopped);
pw.println(" mScreenState=" + Display.stateToString(mScreenState)); pw.println(" mScreenState=" + Display.stateToString(mScreenState));
pw.println(" mScreenBrightness=" + mScreenBrightness); pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mSdrScreenBrightness=" + mSdrScreenBrightness);
pw.println(" mScreenReady=" + mScreenReady); pw.println(" mScreenReady=" + mScreenReady);
pw.println(" mScreenUpdatePending=" + mScreenUpdatePending); pw.println(" mScreenUpdatePending=" + mScreenUpdatePending);
pw.println(" mColorFadePrepared=" + mColorFadePrepared); pw.println(" mColorFadePrepared=" + mColorFadePrepared);
@@ -332,7 +374,10 @@ final class DisplayPowerState {
float brightnessState = mScreenState != Display.STATE_OFF float brightnessState = mScreenState != Display.STATE_OFF
&& mColorFadeLevel > 0f ? mScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT; && 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) { if (DEBUG) {
Slog.d(TAG, "Screen ready"); Slog.d(TAG, "Screen ready");
} }
@@ -373,8 +418,10 @@ final class DisplayPowerState {
private int mPendingState = INITIAL_SCREEN_STATE; private int mPendingState = INITIAL_SCREEN_STATE;
private float mPendingBacklight = INITIAL_BACKLIGHT_FLOAT; private float mPendingBacklight = INITIAL_BACKLIGHT_FLOAT;
private float mPendingSdrBacklight = INITIAL_BACKLIGHT_FLOAT;
private int mActualState = INITIAL_SCREEN_STATE; private int mActualState = INITIAL_SCREEN_STATE;
private float mActualBacklight = INITIAL_BACKLIGHT_FLOAT; private float mActualBacklight = INITIAL_BACKLIGHT_FLOAT;
private float mActualSdrBacklight = INITIAL_BACKLIGHT_FLOAT;
private boolean mStateChangeInProgress; private boolean mStateChangeInProgress;
private boolean mBacklightChangeInProgress; private boolean mBacklightChangeInProgress;
@@ -382,11 +429,13 @@ final class DisplayPowerState {
super("PhotonicModulator"); super("PhotonicModulator");
} }
public boolean setState(int state, float brightnessState) { public boolean setState(int state, float brightnessState, float sdrBrightnessState) {
synchronized (mLock) { synchronized (mLock) {
boolean stateChanged = state != mPendingState; boolean stateChanged = state != mPendingState;
boolean backlightChanged = !BrightnessSynchronizer.floatEquals( boolean backlightChanged =
brightnessState, mPendingBacklight); !BrightnessSynchronizer.floatEquals(brightnessState, mPendingBacklight)
|| !BrightnessSynchronizer.floatEquals(
sdrBrightnessState, mPendingSdrBacklight);
if (stateChanged || backlightChanged) { if (stateChanged || backlightChanged) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Requesting new screen state: state=" Slog.d(TAG, "Requesting new screen state: state="
@@ -395,6 +444,7 @@ final class DisplayPowerState {
mPendingState = state; mPendingState = state;
mPendingBacklight = brightnessState; mPendingBacklight = brightnessState;
mPendingSdrBacklight = sdrBrightnessState;
boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress; boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
mStateChangeInProgress = stateChanged || mStateChangeInProgress; mStateChangeInProgress = stateChanged || mStateChangeInProgress;
mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress; mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
@@ -413,8 +463,10 @@ final class DisplayPowerState {
pw.println("Photonic Modulator State:"); pw.println("Photonic Modulator State:");
pw.println(" mPendingState=" + Display.stateToString(mPendingState)); pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mPendingBacklight=" + mPendingBacklight); pw.println(" mPendingBacklight=" + mPendingBacklight);
pw.println(" mPendingSdrBacklight=" + mPendingSdrBacklight);
pw.println(" mActualState=" + Display.stateToString(mActualState)); pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight); pw.println(" mActualBacklight=" + mActualBacklight);
pw.println(" mActualSdrBacklight=" + mActualSdrBacklight);
pw.println(" mStateChangeInProgress=" + mStateChangeInProgress); pw.println(" mStateChangeInProgress=" + mStateChangeInProgress);
pw.println(" mBacklightChangeInProgress=" + mBacklightChangeInProgress); pw.println(" mBacklightChangeInProgress=" + mBacklightChangeInProgress);
} }
@@ -427,13 +479,17 @@ final class DisplayPowerState {
final int state; final int state;
final boolean stateChanged; final boolean stateChanged;
final float brightnessState; final float brightnessState;
final float sdrBrightnessState;
final boolean backlightChanged; final boolean backlightChanged;
synchronized (mLock) { synchronized (mLock) {
state = mPendingState; state = mPendingState;
stateChanged = (state != mActualState); stateChanged = (state != mActualState);
brightnessState = mPendingBacklight; brightnessState = mPendingBacklight;
backlightChanged = !BrightnessSynchronizer.floatEquals( sdrBrightnessState = mPendingSdrBacklight;
brightnessState, mActualBacklight); backlightChanged =
!BrightnessSynchronizer.floatEquals(brightnessState, mActualBacklight)
|| !BrightnessSynchronizer.floatEquals(
sdrBrightnessState, mActualSdrBacklight);
if (!stateChanged) { if (!stateChanged) {
// State changed applied, notify outer class. // State changed applied, notify outer class.
postScreenUpdateThreadSafe(); postScreenUpdateThreadSafe();
@@ -454,14 +510,17 @@ final class DisplayPowerState {
} }
mActualState = state; mActualState = state;
mActualBacklight = brightnessState; mActualBacklight = brightnessState;
mActualSdrBacklight = sdrBrightnessState;
} }
// Apply pending change. // Apply pending change.
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Updating screen state: id=" + mDisplayId + ", state=" 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);
} }
} }
} }

View File

@@ -18,9 +18,11 @@ package com.android.server.display;
import android.hardware.display.BrightnessInfo; import android.hardware.display.BrightnessInfo;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Slog; import android.util.Slog;
import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData; import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
@@ -45,17 +47,21 @@ class HighBrightnessModeController {
private final float mBrightnessMin; private final float mBrightnessMin;
private final float mBrightnessMax; private final float mBrightnessMax;
private final HighBrightnessModeData mHbmData;
private final Handler mHandler; private final Handler mHandler;
private final Runnable mHbmChangeCallback; private final Runnable mHbmChangeCallback;
private final Runnable mRecalcRunnable; private final Runnable mRecalcRunnable;
private final Clock mClock; private final Clock mClock;
private SurfaceControlHdrLayerInfoListener mHdrListener;
private HighBrightnessModeData mHbmData;
private IBinder mRegisteredDisplayToken;
private boolean mIsInAllowedAmbientRange = false; private boolean mIsInAllowedAmbientRange = false;
private boolean mIsTimeAvailable = false; private boolean mIsTimeAvailable = false;
private boolean mIsAutoBrightnessEnabled = false; private boolean mIsAutoBrightnessEnabled = false;
private float mAutoBrightness; private float mAutoBrightness;
private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; 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. * 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<>(); private LinkedList<HbmEvent> mEvents = new LinkedList<>();
HighBrightnessModeController(Handler handler, float brightnessMin, float brightnessMax, HighBrightnessModeController(Handler handler, IBinder displayToken, float brightnessMin,
HighBrightnessModeData hbmData, Runnable hbmChangeCallback) { float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
this(SystemClock::uptimeMillis, handler, brightnessMin, brightnessMax, hbmData, this(SystemClock::uptimeMillis, handler, displayToken, brightnessMin, brightnessMax,
hbmChangeCallback); hbmData, hbmChangeCallback);
} }
@VisibleForTesting @VisibleForTesting
HighBrightnessModeController(Clock clock, Handler handler, float brightnessMin, HighBrightnessModeController(Clock clock, Handler handler, IBinder displayToken,
float brightnessMax, HighBrightnessModeData hbmData, Runnable hbmChangeCallback) { float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData,
Runnable hbmChangeCallback) {
mClock = clock; mClock = clock;
mHandler = handler; mHandler = handler;
mBrightnessMin = brightnessMin; mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax; mBrightnessMax = brightnessMax;
mHbmData = hbmData;
mHbmChangeCallback = hbmChangeCallback; mHbmChangeCallback = hbmChangeCallback;
mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mRecalcRunnable = this::recalculateTimeAllowance; mRecalcRunnable = this::recalculateTimeAllowance;
mHdrListener = new HdrListener();
resetHbmData(displayToken, hbmData);
} }
void setAutoBrightnessEnabled(boolean isEnabled) { void setAutoBrightnessEnabled(boolean isEnabled) {
@@ -117,6 +126,10 @@ class HighBrightnessModeController {
} }
} }
float getHdrBrightnessValue() {
return mBrightnessMax;
}
void onAmbientLuxChange(float ambientLux) { void onAmbientLuxChange(float ambientLux) {
if (!deviceSupportsHbm() || !mIsAutoBrightnessEnabled) { if (!deviceSupportsHbm() || !mIsAutoBrightnessEnabled) {
return; return;
@@ -138,11 +151,12 @@ class HighBrightnessModeController {
// If we are starting or ending a high brightness mode session, store the current // If we are starting or ending a high brightness mode session, store the current
// session in mRunningStartTimeMillis, or the old one in mEvents. // session in mRunningStartTimeMillis, or the old one in mEvents.
final boolean wasOldBrightnessHigh = oldAutoBrightness > mHbmData.transitionPoint; final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1;
final boolean isNewBrightnessHigh = mAutoBrightness > mHbmData.transitionPoint; final boolean shouldHbmDrainAvailableTime = mAutoBrightness > mHbmData.transitionPoint
if (wasOldBrightnessHigh != isNewBrightnessHigh) { && !mIsHdrLayerPresent;
if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) {
final long currentTime = mClock.uptimeMillis(); final long currentTime = mClock.uptimeMillis();
if (isNewBrightnessHigh) { if (shouldHbmDrainAvailableTime) {
mRunningStartTimeMillis = currentTime; mRunningStartTimeMillis = currentTime;
} else { } else {
mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime)); mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime));
@@ -161,30 +175,49 @@ class HighBrightnessModeController {
return mHbmMode; 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) { void dump(PrintWriter pw) {
pw.println("HighBrightnessModeController:"); pw.println("HighBrightnessModeController:");
pw.println(" mBrightnessMin=" + mBrightnessMin); pw.println(" mCurrentMin=" + getCurrentBrightnessMin());
pw.println(" mBrightnessMax=" + mBrightnessMax); pw.println(" mCurrentMax=" + getCurrentBrightnessMax());
pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode));
pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis()));
pw.println(" mHbmData=" + mHbmData); pw.println(" mHbmData=" + mHbmData);
pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange); pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange);
pw.println(" mIsTimeAvailable= " + mIsTimeAvailable); pw.println(" mIsTimeAvailable= " + mIsTimeAvailable);
pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled); pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled);
pw.println(" mAutoBrightness=" + mAutoBrightness); pw.println(" mAutoBrightness=" + mAutoBrightness);
pw.println(" mIsHdrLayerPresent=" + mIsHdrLayerPresent);
pw.println(" mBrightnessMin=" + mBrightnessMin);
pw.println(" mBrightnessMax=" + mBrightnessMax);
} }
private boolean isCurrentlyAllowed() { private boolean isCurrentlyAllowed() {
return mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange; return mIsHdrLayerPresent
|| (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange);
} }
private boolean deviceSupportsHbm() { private boolean deviceSupportsHbm() {
return mHbmData != null; return mHbmData != null;
} }
/** private long calculateRemainingTime(long currentTime) {
* Recalculates the allowable HBM time. if (!deviceSupportsHbm()) {
*/ return 0;
private void recalculateTimeAllowance() { }
final long currentTime = mClock.uptimeMillis();
long timeAlreadyUsed = 0; long timeAlreadyUsed = 0;
// First, lets see how much time we've taken for any currently running // 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); Slog.d(TAG, "Time already used after all sessions: " + timeAlreadyUsed);
} }
// See how much allowable time we have left. return Math.max(0, mHbmData.timeMaxMillis - timeAlreadyUsed);
final long remainingTime = 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 // 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. // 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 // 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 // window by at least minTime. Basically, we're calculating the soonest time we can
// get {@code timeMinMillis} back to us. // get {@code timeMinMillis} back to us.
final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
final HbmEvent lastEvent = mEvents.getLast(); final HbmEvent lastEvent = mEvents.getLast();
final long startTimePlusMinMillis = final long startTimePlusMinMillis =
Math.max(windowstartTimeMillis, lastEvent.startTimeMillis) Math.max(windowstartTimeMillis, lastEvent.startTimeMillis)
@@ -278,12 +319,36 @@ class HighBrightnessModeController {
} }
private int calculateHighBrightnessMode() { 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_SUNLIGHT;
} }
return BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; 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. * Represents an event in which High Brightness Mode was enabled.
*/ */
@@ -302,4 +367,18 @@ class HighBrightnessModeController {
+ ((endTimeMillis - startTimeMillis) / 1000) + "]"; + ((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);
});
}
}
} }

View File

@@ -67,6 +67,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final int NO_DISPLAY_MODE_ID = 0; 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 LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>();
private final Injector mInjector; private final Injector mInjector;
@@ -190,6 +192,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int mState = Display.STATE_UNKNOWN; private int mState = Display.STATE_UNKNOWN;
// This is only set in the runnable returned from requestDisplayStateLocked. // This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private int mDefaultModeId; private int mDefaultModeId;
private int mDefaultModeGroup; private int mDefaultModeGroup;
private int mActiveModeId; private int mActiveModeId;
@@ -644,13 +647,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} }
@Override @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. // Assume that the brightness is off if the display is being turned off.
assert state != Display.STATE_OFF || BrightnessSynchronizer.floatEquals( assert state != Display.STATE_OFF || BrightnessSynchronizer.floatEquals(
brightnessState, PowerManager.BRIGHTNESS_OFF_FLOAT); brightnessState, PowerManager.BRIGHTNESS_OFF_FLOAT);
final boolean stateChanged = (mState != state); final boolean stateChanged = (mState != state);
final boolean brightnessChanged = (!BrightnessSynchronizer.floatEquals( final boolean brightnessChanged =
mBrightnessState, brightnessState)); !(BrightnessSynchronizer.floatEquals(mBrightnessState, brightnessState)
&& BrightnessSynchronizer.floatEquals(mSdrBrightnessState, sdrBrightnessState));
if (stateChanged || brightnessChanged) { if (stateChanged || brightnessChanged) {
final long physicalDisplayId = mPhysicalDisplayId; final long physicalDisplayId = mPhysicalDisplayId;
final IBinder token = getDisplayTokenLocked(); 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. // Apply brightness changes given that we are in a non-suspended state.
if (brightnessChanged || vrModeChange) { if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightnessState); setDisplayBrightness(brightnessState, sdrBrightnessState);
mBrightnessState = brightnessState; mBrightnessState = brightnessState;
mSdrBrightnessState = sdrBrightnessState;
} }
// Enter the final desired state, possibly suspended. // Enter the final desired state, possibly suspended.
@@ -764,8 +770,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} }
} }
private void setDisplayBrightness(float brightness) { private void setDisplayBrightness(float brightness, float sdrBrightness) {
// Ensure brightnessState is valid, before processing and sending to // Ensure brightnessState is valid before processing and sending to
// surface control // surface control
if (Float.isNaN(brightness)) { if (Float.isNaN(brightness)) {
return; return;
@@ -774,17 +780,31 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "setDisplayBrightness(" Slog.d(TAG, "setDisplayBrightness("
+ "id=" + physicalDisplayId + "id=" + physicalDisplayId
+ ", brightness=" + brightness + ")"); + ", brightness=" + brightness
+ ", sdrBrightness=" + sdrBrightness + ")");
} }
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness(" Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+ "id=" + physicalDisplayId + ", brightness=" + brightness + ")"); + "id=" + physicalDisplayId + ", brightness=" + brightness
+ ", sdrBrightness=" + sdrBrightness + ")");
try { try {
float backlight = brightnessToBacklight(brightness); final float backlight = brightnessToBacklight(brightness);
mBacklightAdapter.setBacklight(backlight); 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, Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness", "ScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(brightness)); BrightnessSynchronizer.brightnessFloatToInt(brightness));
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"SdrScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(sdrBrightness));
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER); Trace.traceEnd(Trace.TRACE_TAG_POWER);
} }
@@ -793,6 +813,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private float brightnessToBacklight(float brightness) { private float brightnessToBacklight(float brightness) {
return getDisplayDeviceConfig().getBacklightFromBrightness(brightness); return getDisplayDeviceConfig().getBacklightFromBrightness(brightness);
} }
private float backlightToNits(float backlight) {
return getDisplayDeviceConfig().getNitsFromBacklight(backlight);
}
}; };
} }
return null; return null;
@@ -1242,6 +1266,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public boolean setDisplayBrightness(IBinder displayToken, float brightness) { public boolean setDisplayBrightness(IBinder displayToken, float brightness) {
return SurfaceControl.setDisplayBrightness(displayToken, 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 { static class BacklightAdapter {
@@ -1273,9 +1304,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
} }
// Set backlight within min and max backlight values // 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) { 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) { } else if (mBacklight != null) {
mBacklight.setBrightness(backlight); mBacklight.setBrightness(backlight);
} }

View File

@@ -26,7 +26,7 @@ import com.android.internal.display.BrightnessSynchronizer;
* A custom animator that progressively updates a property value at * A custom animator that progressively updates a property value at
* a given variable rate until it reaches a particular target value. * a given variable rate until it reaches a particular target value.
*/ */
final class RampAnimator<T> { class RampAnimator<T> {
private final T mObject; private final T mObject;
private final FloatProperty<T> mProperty; private final FloatProperty<T> mProperty;
private final Choreographer mChoreographer; private final Choreographer mChoreographer;
@@ -174,4 +174,52 @@ final class RampAnimator<T> {
public interface Listener { public interface Listener {
void onAnimationEnd(); 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();
}
}
} }

View File

@@ -293,7 +293,8 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
} }
@Override @Override
public Runnable requestDisplayStateLocked(int state, float brightnessState) { public Runnable requestDisplayStateLocked(int state, float brightnessState,
float sdrBrightnessState) {
if (state != mDisplayState) { if (state != mDisplayState) {
mDisplayState = state; mDisplayState = state;
if (state == Display.STATE_OFF) { if (state == Display.STATE_OFF) {

View File

@@ -649,14 +649,14 @@ public class LocalDisplayAdapterTest {
// Test as default display // Test as default display
BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/, BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
mSurfaceControlProxy); mSurfaceControlProxy);
ba.setBacklight(0.514f); ba.setBacklight(0.514f, 100f, 0.614f, 500f);
verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f); verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f, 100f, 0.614f, 500f);
// Test as not default display // Test as not default display
BacklightAdapter ba2 = new BacklightAdapter(displayToken, false /*isDefault*/, BacklightAdapter ba2 = new BacklightAdapter(displayToken, false /*isDefault*/,
mSurfaceControlProxy); mSurfaceControlProxy);
ba2.setBacklight(0.323f); ba2.setBacklight(0.323f, 101f, 0.723f, 601f);
verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f); verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f, 101f, 0.723f, 601f);
} }
@Test @Test
@@ -668,7 +668,7 @@ public class LocalDisplayAdapterTest {
BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/, BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
mSurfaceControlProxy); mSurfaceControlProxy);
ba.setBacklight(0.123f); ba.setBacklight(1f, 1f, 0.123f, 1f);
verify(mMockedBacklight).setBrightness(0.123f); verify(mMockedBacklight).setBrightness(0.123f);
} }
@@ -681,7 +681,7 @@ public class LocalDisplayAdapterTest {
BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/, BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/,
mSurfaceControlProxy); mSurfaceControlProxy);
ba.setBacklight(0.456f); ba.setBacklight(0.456f, 1f, 1f, 1f);
// Adapter does not forward any brightness in this case. // Adapter does not forward any brightness in this case.
verify(mMockedBacklight, never()).setBrightness(anyFloat()); verify(mMockedBacklight, never()).setBrightness(anyFloat());

View File

@@ -21,6 +21,7 @@ import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLI
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.test.TestLooper; import android.os.test.TestLooper;
@@ -55,6 +56,7 @@ public class HighBrightnessModeControllerTest {
private OffsettableClock mClock; private OffsettableClock mClock;
private TestLooper mTestLooper; private TestLooper mTestLooper;
private Handler mHandler; private Handler mHandler;
private Binder mDisplayToken;
private static final HighBrightnessModeData DEFAULT_HBM_DATA = private static final HighBrightnessModeData DEFAULT_HBM_DATA =
new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS, new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
@@ -64,6 +66,7 @@ public class HighBrightnessModeControllerTest {
public void setUp() { public void setUp() {
mClock = new OffsettableClock.Stopped(); mClock = new OffsettableClock.Stopped();
mTestLooper = new TestLooper(mClock::now); mTestLooper = new TestLooper(mClock::now);
mDisplayToken = null;
mHandler = new Handler(mTestLooper.getLooper(), new Handler.Callback() { mHandler = new Handler(mTestLooper.getLooper(), new Handler.Callback() {
@Override @Override
public boolean handleMessage(Message msg) { public boolean handleMessage(Message msg) {
@@ -79,14 +82,14 @@ public class HighBrightnessModeControllerTest {
@Test @Test
public void testNoHbmData() { public void testNoHbmData() {
final HighBrightnessModeController hbmc = new HighBrightnessModeController( 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); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
} }
@Test @Test
public void testNoHbmData_Enabled() { public void testNoHbmData_Enabled() {
final HighBrightnessModeController hbmc = new HighBrightnessModeController( 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.setAutoBrightnessEnabled(true);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -264,8 +267,8 @@ public class HighBrightnessModeControllerTest {
// Creates instance with standard initialization values. // Creates instance with standard initialization values.
private HighBrightnessModeController createDefaultHbm() { private HighBrightnessModeController createDefaultHbm() {
return new HighBrightnessModeController(mClock::now, mHandler, DEFAULT_MIN, DEFAULT_MAX, return new HighBrightnessModeController(mClock::now, mHandler, mDisplayToken, DEFAULT_MIN,
DEFAULT_HBM_DATA, () -> {}); DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {});
} }
private void advanceTime(long timeMs) { private void advanceTime(long timeMs) {