Add display brightness throttler
This change adds BrightnessThrottler, which is responsible for limiting
the usable range of display brightness based on skin temperature thermal
throttling (extensible to account for other events/conditions in the
future). Brightness constraints calculated by BrightnessThrottling are
applied by DisplayPowerController as a brightness transform similarly to
dimming and low power states.
This change also adds a field to BrightnessInfo in order to capture the
reason for an unusual max brightness (currently only accounts for a
thermal reason).
Finally, change HighBrightnessModeController (HBMC) so that HBM thermal
throttling is still reported correctly to FrameworkStatsLog when
brightness throttling is performed in DisplayPowerController (through
BrightnessThrottler) rather than through HBMC's own thermal throttling
mechanism. HBMC's own thermal throttling mechanism will be deprecated in
a future change.
Bug: 206857086
Bug: 212634465
Test: atest BrightnessThrottlerTest DisplayModeDirectorTest
BrightnessLevelPreferenceControllerTest
HighBrightnessModeControllerTest
Test: Manually trigger and clear thermal throttling, and verify
transitions,
1. While in manual brightness mode
2. While in automatic Brightness mode
3. While high brightness mode is enabled for HDR
3. Across display suspend/resume events
Change-Id: I4c10f037a0a616e84fc109cc755bf3a5eaa3d111
This commit is contained in:
@@ -57,6 +57,23 @@ public final class BrightnessInfo implements Parcelable {
|
||||
*/
|
||||
public static final int HIGH_BRIGHTNESS_MODE_HDR = 2;
|
||||
|
||||
@IntDef(prefix = {"BRIGHTNESS_MAX_REASON_"}, value = {
|
||||
BRIGHTNESS_MAX_REASON_NONE,
|
||||
BRIGHTNESS_MAX_REASON_THERMAL
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface BrightnessMaxReason {}
|
||||
|
||||
/**
|
||||
* Maximum brightness is unrestricted.
|
||||
*/
|
||||
public static final int BRIGHTNESS_MAX_REASON_NONE = 0;
|
||||
|
||||
/**
|
||||
* Maximum brightness is restricted due to thermal throttling.
|
||||
*/
|
||||
public static final int BRIGHTNESS_MAX_REASON_THERMAL = 1;
|
||||
|
||||
/** Brightness */
|
||||
public final float brightness;
|
||||
|
||||
@@ -78,21 +95,29 @@ public final class BrightnessInfo implements Parcelable {
|
||||
*/
|
||||
public final int highBrightnessMode;
|
||||
|
||||
/**
|
||||
* The current reason for restricting maximum brightness.
|
||||
* Can be any of BRIGHTNESS_MAX_REASON_* values.
|
||||
*/
|
||||
public final int brightnessMaxReason;
|
||||
|
||||
public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum,
|
||||
@HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint) {
|
||||
@HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint,
|
||||
@BrightnessMaxReason int brightnessMaxReason) {
|
||||
this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode,
|
||||
highBrightnessTransitionPoint);
|
||||
highBrightnessTransitionPoint, brightnessMaxReason);
|
||||
}
|
||||
|
||||
public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum,
|
||||
float brightnessMaximum, @HighBrightnessMode int highBrightnessMode,
|
||||
float highBrightnessTransitionPoint) {
|
||||
float highBrightnessTransitionPoint, @BrightnessMaxReason int brightnessMaxReason) {
|
||||
this.brightness = brightness;
|
||||
this.adjustedBrightness = adjustedBrightness;
|
||||
this.brightnessMinimum = brightnessMinimum;
|
||||
this.brightnessMaximum = brightnessMaximum;
|
||||
this.highBrightnessMode = highBrightnessMode;
|
||||
this.highBrightnessTransitionPoint = highBrightnessTransitionPoint;
|
||||
this.brightnessMaxReason = brightnessMaxReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,6 +135,19 @@ public final class BrightnessInfo implements Parcelable {
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User-friendly string for specified {@link BrightnessMaxReason} parameter.
|
||||
*/
|
||||
public static String briMaxReasonToString(@BrightnessMaxReason int reason) {
|
||||
switch (reason) {
|
||||
case BRIGHTNESS_MAX_REASON_NONE:
|
||||
return "none";
|
||||
case BRIGHTNESS_MAX_REASON_THERMAL:
|
||||
return "thermal";
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
@@ -123,6 +161,7 @@ public final class BrightnessInfo implements Parcelable {
|
||||
dest.writeFloat(brightnessMaximum);
|
||||
dest.writeInt(highBrightnessMode);
|
||||
dest.writeFloat(highBrightnessTransitionPoint);
|
||||
dest.writeInt(brightnessMaxReason);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR =
|
||||
@@ -145,6 +184,7 @@ public final class BrightnessInfo implements Parcelable {
|
||||
brightnessMaximum = source.readFloat();
|
||||
highBrightnessMode = source.readInt();
|
||||
highBrightnessTransitionPoint = source.readFloat();
|
||||
brightnessMaxReason = source.readInt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.display;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.display.BrightnessInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.IThermalEventListener;
|
||||
import android.os.IThermalService;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.Temperature;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel;
|
||||
import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* This class monitors various conditions, such as skin temperature throttling status, and limits
|
||||
* the allowed brightness range accordingly.
|
||||
*/
|
||||
class BrightnessThrottler {
|
||||
private static final String TAG = "BrightnessThrottler";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int THROTTLING_INVALID = -1;
|
||||
|
||||
private final Injector mInjector;
|
||||
private final Handler mHandler;
|
||||
private BrightnessThrottlingData mThrottlingData;
|
||||
private final Runnable mThrottlingChangeCallback;
|
||||
private final SkinThermalStatusObserver mSkinThermalStatusObserver;
|
||||
private int mThrottlingStatus;
|
||||
private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
|
||||
private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason =
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
|
||||
|
||||
BrightnessThrottler(Handler handler, BrightnessThrottlingData throttlingData,
|
||||
Runnable throttlingChangeCallback) {
|
||||
this(new Injector(), handler, throttlingData, throttlingChangeCallback);
|
||||
}
|
||||
|
||||
BrightnessThrottler(Injector injector, Handler handler, BrightnessThrottlingData throttlingData,
|
||||
Runnable throttlingChangeCallback) {
|
||||
mInjector = injector;
|
||||
mHandler = handler;
|
||||
mThrottlingData = throttlingData;
|
||||
mThrottlingChangeCallback = throttlingChangeCallback;
|
||||
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
|
||||
|
||||
resetThrottlingData(mThrottlingData);
|
||||
}
|
||||
|
||||
boolean deviceSupportsThrottling() {
|
||||
return mThrottlingData != null;
|
||||
}
|
||||
|
||||
float getBrightnessCap() {
|
||||
return mBrightnessCap;
|
||||
}
|
||||
|
||||
int getBrightnessMaxReason() {
|
||||
return mBrightnessMaxReason;
|
||||
}
|
||||
|
||||
boolean isThrottled() {
|
||||
return mBrightnessMaxReason != BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
mSkinThermalStatusObserver.stopObserving();
|
||||
|
||||
// We're asked to stop throttling, so reset brightness restrictions.
|
||||
mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
|
||||
mBrightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
|
||||
|
||||
// We set throttling status to an invalid value here so that we act on the first throttling
|
||||
// value received from the thermal service after registration, even if that throttling value
|
||||
// is THROTTLING_NONE.
|
||||
mThrottlingStatus = THROTTLING_INVALID;
|
||||
}
|
||||
|
||||
void resetThrottlingData(BrightnessThrottlingData throttlingData) {
|
||||
stop();
|
||||
mThrottlingData = throttlingData;
|
||||
|
||||
if (deviceSupportsThrottling()) {
|
||||
mSkinThermalStatusObserver.startObserving();
|
||||
}
|
||||
}
|
||||
|
||||
private float verifyAndConstrainBrightnessCap(float brightness) {
|
||||
if (brightness < PowerManager.BRIGHTNESS_MIN) {
|
||||
Slog.e(TAG, "brightness " + brightness + " is lower than the minimum possible "
|
||||
+ "brightness " + PowerManager.BRIGHTNESS_MIN);
|
||||
brightness = PowerManager.BRIGHTNESS_MIN;
|
||||
}
|
||||
|
||||
if (brightness > PowerManager.BRIGHTNESS_MAX) {
|
||||
Slog.e(TAG, "brightness " + brightness + " is higher than the maximum possible "
|
||||
+ "brightness " + PowerManager.BRIGHTNESS_MAX);
|
||||
brightness = PowerManager.BRIGHTNESS_MAX;
|
||||
}
|
||||
|
||||
return brightness;
|
||||
}
|
||||
|
||||
private void thermalStatusChanged(@Temperature.ThrottlingStatus int newStatus) {
|
||||
if (mThrottlingStatus != newStatus) {
|
||||
mThrottlingStatus = newStatus;
|
||||
updateThrottling();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateThrottling() {
|
||||
if (!deviceSupportsThrottling()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float brightnessCap = PowerManager.BRIGHTNESS_MAX;
|
||||
int brightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
|
||||
|
||||
if (mThrottlingStatus != THROTTLING_INVALID) {
|
||||
// Throttling levels are sorted by increasing severity
|
||||
for (ThrottlingLevel level : mThrottlingData.throttlingLevels) {
|
||||
if (level.thermalStatus <= mThrottlingStatus) {
|
||||
brightnessCap = level.brightness;
|
||||
brightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
|
||||
} else {
|
||||
// Throttling levels that are greater than the current status are irrelevant
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrightnessCap != brightnessCap || mBrightnessMaxReason != brightnessMaxReason) {
|
||||
mBrightnessCap = verifyAndConstrainBrightnessCap(brightnessCap);
|
||||
mBrightnessMaxReason = brightnessMaxReason;
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "State changed: mBrightnessCap = " + mBrightnessCap
|
||||
+ ", mBrightnessMaxReason = "
|
||||
+ BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason));
|
||||
}
|
||||
|
||||
if (mThrottlingChangeCallback != null) {
|
||||
mThrottlingChangeCallback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump(PrintWriter pw) {
|
||||
mHandler.runWithScissors(() -> dumpLocal(pw), 1000);
|
||||
}
|
||||
|
||||
private void dumpLocal(PrintWriter pw) {
|
||||
pw.println("BrightnessThrottler:");
|
||||
pw.println(" mThrottlingData=" + mThrottlingData);
|
||||
pw.println(" mThrottlingStatus=" + mThrottlingStatus);
|
||||
pw.println(" mBrightnessCap=" + mBrightnessCap);
|
||||
pw.println(" mBrightnessMaxReason=" +
|
||||
BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason));
|
||||
|
||||
mSkinThermalStatusObserver.dump(pw);
|
||||
}
|
||||
|
||||
private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
|
||||
private final Injector mInjector;
|
||||
private final Handler mHandler;
|
||||
|
||||
private IThermalService mThermalService;
|
||||
private boolean mStarted;
|
||||
|
||||
SkinThermalStatusObserver(Injector injector, Handler handler) {
|
||||
mInjector = injector;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyThrottling(Temperature temp) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "New thermal throttling status = " + temp.getStatus());
|
||||
}
|
||||
mHandler.post(() -> {
|
||||
final @Temperature.ThrottlingStatus int status = temp.getStatus();
|
||||
thermalStatusChanged(status);
|
||||
});
|
||||
}
|
||||
|
||||
void startObserving() {
|
||||
if (mStarted) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Thermal status observer already started");
|
||||
}
|
||||
return;
|
||||
}
|
||||
mThermalService = mInjector.getThermalService();
|
||||
if (mThermalService == null) {
|
||||
Slog.e(TAG, "Could not observe thermal status. Service not available");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// We get a callback immediately upon registering so there's no need to query
|
||||
// for the current value.
|
||||
mThermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
|
||||
mStarted = true;
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to register thermal status listener", e);
|
||||
}
|
||||
}
|
||||
|
||||
void stopObserving() {
|
||||
if (!mStarted) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Stop skipped because thermal status observer not started");
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mThermalService.unregisterThermalEventListener(this);
|
||||
mStarted = false;
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to unregister thermal status listener", e);
|
||||
}
|
||||
mThermalService = null;
|
||||
}
|
||||
|
||||
void dump(PrintWriter writer) {
|
||||
writer.println(" SkinThermalStatusObserver:");
|
||||
writer.println(" mStarted: " + mStarted);
|
||||
if (mThermalService != null) {
|
||||
writer.println(" ThermalService available");
|
||||
} else {
|
||||
writer.println(" ThermalService not available");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Injector {
|
||||
public IThermalService getThermalService() {
|
||||
return IThermalService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.THERMAL_SERVICE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,6 +346,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
private boolean mAppliedTemporaryBrightness;
|
||||
private boolean mAppliedTemporaryAutoBrightnessAdjustment;
|
||||
private boolean mAppliedBrightnessBoost;
|
||||
private boolean mAppliedThrottling;
|
||||
|
||||
// Reason for which the brightness was last changed. See {@link BrightnessReason} for more
|
||||
// information.
|
||||
@@ -379,6 +380,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
|
||||
private final HighBrightnessModeController mHbmController;
|
||||
|
||||
private final BrightnessThrottler mBrightnessThrottler;
|
||||
|
||||
private final BrightnessSetting mBrightnessSetting;
|
||||
|
||||
private final Runnable mOnBrightnessChangeRunnable;
|
||||
@@ -538,6 +541,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
|
||||
mHbmController = createHbmControllerLocked();
|
||||
|
||||
mBrightnessThrottler = createBrightnessThrottlerLocked();
|
||||
|
||||
// Seed the cached brightness
|
||||
saveBrightnessInfo(getScreenBrightnessSetting());
|
||||
|
||||
@@ -827,6 +832,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
reloadReduceBrightColours();
|
||||
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
|
||||
mDisplayDeviceConfig.getHighBrightnessModeData());
|
||||
mBrightnessThrottler.resetThrottlingData(
|
||||
mDisplayDeviceConfig.getBrightnessThrottlingData());
|
||||
}
|
||||
|
||||
private void sendUpdatePowerState() {
|
||||
@@ -1039,6 +1046,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
private void cleanupHandlerThreadAfterStop() {
|
||||
setProximitySensorEnabled(false);
|
||||
mHbmController.stop();
|
||||
mBrightnessThrottler.stop();
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
if (mUnfinishedBusiness) {
|
||||
mCallbacks.releaseSuspendBlocker();
|
||||
@@ -1336,14 +1344,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
|
||||
}
|
||||
|
||||
// The current brightness to use has been calculated at this point (minus the adjustments
|
||||
// like low-power and dim), and HbmController should be notified so that it can accurately
|
||||
// calculate HDR or HBM levels. We specifically do it here instead of having HbmController
|
||||
// listen to the brightness setting because certain brightness sources (just as an app
|
||||
// override) are not saved to the setting, but should be reflected in HBM
|
||||
// calculations.
|
||||
mHbmController.onBrightnessChanged(brightnessState);
|
||||
|
||||
if (updateScreenBrightnessSetting) {
|
||||
// Tell the rest of the system about the new brightness in case we had to change it
|
||||
// for things like auto-brightness or high-brightness-mode. Note that we do this
|
||||
@@ -1390,6 +1390,28 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mAppliedLowPower = false;
|
||||
}
|
||||
|
||||
// Apply brightness throttling after applying all other transforms
|
||||
final float unthrottledBrightnessState = brightnessState;
|
||||
if (mBrightnessThrottler.isThrottled()) {
|
||||
brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
|
||||
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
|
||||
if (!mAppliedThrottling) {
|
||||
slowChange = false;
|
||||
}
|
||||
mAppliedThrottling = true;
|
||||
} else if (mAppliedThrottling) {
|
||||
slowChange = false;
|
||||
mAppliedThrottling = false;
|
||||
}
|
||||
|
||||
// The current brightness to use has been calculated at this point, and HbmController should
|
||||
// be notified so that it can accurately calculate HDR or HBM levels. We specifically do it
|
||||
// here instead of having HbmController listen to the brightness setting because certain
|
||||
// brightness sources (such as an app override) are not saved to the setting, but should be
|
||||
// reflected in HBM calculations.
|
||||
mHbmController.onBrightnessChanged(brightnessState, unthrottledBrightnessState,
|
||||
mBrightnessThrottler.getBrightnessMaxReason());
|
||||
|
||||
// Animate the screen brightness when the screen is on or dozing.
|
||||
// Skip the animation when the screen is off or suspended or transition to/from VR.
|
||||
boolean brightnessAdjusted = false;
|
||||
@@ -1441,6 +1463,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
// 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;
|
||||
// TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be
|
||||
// done in HighBrightnessModeController.
|
||||
if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
|
||||
&& ((mBrightnessReason.modifier & BrightnessReason.MODIFIER_DIMMED) == 0
|
||||
|| (mBrightnessReason.modifier & BrightnessReason.MODIFIER_LOW_POWER) == 0)) {
|
||||
@@ -1618,7 +1642,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mCachedBrightnessInfo.brightnessMin.value,
|
||||
mCachedBrightnessInfo.brightnessMax.value,
|
||||
mCachedBrightnessInfo.hbmMode.value,
|
||||
mCachedBrightnessInfo.hbmTransitionPoint.value);
|
||||
mCachedBrightnessInfo.hbmTransitionPoint.value,
|
||||
mCachedBrightnessInfo.brightnessMaxReason.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1648,6 +1673,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
changed |=
|
||||
mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint,
|
||||
mHbmController.getTransitionPoint());
|
||||
changed |=
|
||||
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason,
|
||||
mBrightnessThrottler.getBrightnessMaxReason());
|
||||
|
||||
return changed;
|
||||
}
|
||||
@@ -1679,6 +1707,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
}, mContext);
|
||||
}
|
||||
|
||||
private BrightnessThrottler createBrightnessThrottlerLocked() {
|
||||
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
|
||||
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
|
||||
final DisplayDeviceConfig.BrightnessThrottlingData data =
|
||||
ddConfig != null ? ddConfig.getBrightnessThrottlingData() : null;
|
||||
return new BrightnessThrottler(mHandler, data,
|
||||
() -> {
|
||||
sendUpdatePowerStateLocked();
|
||||
postBrightnessChangeRunnable();
|
||||
});
|
||||
}
|
||||
|
||||
private void blockScreenOn() {
|
||||
if (mPendingScreenOnUnblocker == null) {
|
||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
|
||||
@@ -2346,6 +2386,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value);
|
||||
pw.println(" mCachedBrightnessInfo.hbmTransitionPoint=" +
|
||||
mCachedBrightnessInfo.hbmTransitionPoint.value);
|
||||
pw.println(" mCachedBrightnessInfo.brightnessMaxReason =" +
|
||||
mCachedBrightnessInfo.brightnessMaxReason .value);
|
||||
}
|
||||
pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
|
||||
pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
|
||||
@@ -2384,6 +2426,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
pw.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness);
|
||||
pw.println(" mAppliedDimming=" + mAppliedDimming);
|
||||
pw.println(" mAppliedLowPower=" + mAppliedLowPower);
|
||||
pw.println(" mAppliedThrottling=" + mAppliedThrottling);
|
||||
pw.println(" mAppliedScreenBrightnessOverride=" + mAppliedScreenBrightnessOverride);
|
||||
pw.println(" mAppliedTemporaryBrightness=" + mAppliedTemporaryBrightness);
|
||||
pw.println(" mDozing=" + mDozing);
|
||||
@@ -2422,6 +2465,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mHbmController.dump(pw);
|
||||
}
|
||||
|
||||
if (mBrightnessThrottler != null) {
|
||||
mBrightnessThrottler.dump(pw);
|
||||
}
|
||||
|
||||
pw.println();
|
||||
if (mDisplayWhiteBalanceController != null) {
|
||||
mDisplayWhiteBalanceController.dump(pw);
|
||||
@@ -2702,7 +2749,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
static final int MODIFIER_DIMMED = 0x1;
|
||||
static final int MODIFIER_LOW_POWER = 0x2;
|
||||
static final int MODIFIER_HDR = 0x4;
|
||||
static final int MODIFIER_MASK = MODIFIER_DIMMED | MODIFIER_LOW_POWER | MODIFIER_HDR;
|
||||
static final int MODIFIER_THROTTLED = 0x8;
|
||||
static final int MODIFIER_MASK = MODIFIER_DIMMED | MODIFIER_LOW_POWER | MODIFIER_HDR
|
||||
| MODIFIER_THROTTLED;
|
||||
|
||||
// ADJUSTMENT_*
|
||||
// These things can happen at any point, even if the main brightness reason doesn't
|
||||
@@ -2777,6 +2826,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
if ((modifier & MODIFIER_HDR) != 0) {
|
||||
sb.append(" hdr");
|
||||
}
|
||||
if ((modifier & MODIFIER_THROTTLED) != 0) {
|
||||
sb.append(" throttled");
|
||||
}
|
||||
int strlen = sb.length();
|
||||
if (sb.charAt(strlen - 1) == '[') {
|
||||
sb.setLength(strlen - 2);
|
||||
@@ -2813,6 +2865,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
public MutableInt hbmMode = new MutableInt(BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
|
||||
public MutableFloat hbmTransitionPoint =
|
||||
new MutableFloat(HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID);
|
||||
public MutableInt brightnessMaxReason =
|
||||
new MutableInt(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
|
||||
|
||||
public boolean checkAndSetFloat(MutableFloat mf, float f) {
|
||||
if (mf.value != f) {
|
||||
|
||||
@@ -82,7 +82,15 @@ class HighBrightnessModeController {
|
||||
private boolean mIsTimeAvailable = false;
|
||||
private boolean mIsAutoBrightnessEnabled = false;
|
||||
private boolean mIsAutoBrightnessOffByState = false;
|
||||
|
||||
// The following values are typically reported by DisplayPowerController.
|
||||
// This value includes brightness throttling effects.
|
||||
private float mBrightness;
|
||||
// This value excludes brightness throttling effects.
|
||||
private float mUnthrottledBrightness;
|
||||
private @BrightnessInfo.BrightnessMaxReason int mThrottlingReason =
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
|
||||
|
||||
private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
|
||||
private boolean mIsHdrLayerPresent = false;
|
||||
private boolean mIsThermalStatusWithinLimit = true;
|
||||
@@ -192,11 +200,14 @@ class HighBrightnessModeController {
|
||||
}
|
||||
}
|
||||
|
||||
void onBrightnessChanged(float brightness) {
|
||||
void onBrightnessChanged(float brightness, float unthrottledBrightness,
|
||||
@BrightnessInfo.BrightnessMaxReason int throttlingReason) {
|
||||
if (!deviceSupportsHbm()) {
|
||||
return;
|
||||
}
|
||||
mBrightness = brightness;
|
||||
mUnthrottledBrightness = unthrottledBrightness;
|
||||
mThrottlingReason = throttlingReason;
|
||||
|
||||
// If we are starting or ending a high brightness mode session, store the current
|
||||
// session in mRunningStartTimeMillis, or the old one in mEvents.
|
||||
@@ -274,6 +285,8 @@ class HighBrightnessModeController {
|
||||
private void dumpLocal(PrintWriter pw) {
|
||||
pw.println("HighBrightnessModeController:");
|
||||
pw.println(" mBrightness=" + mBrightness);
|
||||
pw.println(" mUnthrottledBrightness=" + mUnthrottledBrightness);
|
||||
pw.println(" mThrottlingReason=" + BrightnessInfo.briMaxReasonToString(mThrottlingReason));
|
||||
pw.println(" mCurrentMin=" + getCurrentBrightnessMin());
|
||||
pw.println(" mCurrentMax=" + getCurrentBrightnessMax());
|
||||
pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode)
|
||||
@@ -431,6 +444,9 @@ class HighBrightnessModeController {
|
||||
+ ", mIsThermalStatusWithinLimit: " + mIsThermalStatusWithinLimit
|
||||
+ ", mIsBlockedByLowPowerMode: " + mIsBlockedByLowPowerMode
|
||||
+ ", mBrightness: " + mBrightness
|
||||
+ ", mUnthrottledBrightness: " + mUnthrottledBrightness
|
||||
+ ", mThrottlingReason: "
|
||||
+ BrightnessInfo.briMaxReasonToString(mThrottlingReason)
|
||||
+ ", RunningStartTimeMillis: " + mRunningStartTimeMillis
|
||||
+ ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1)
|
||||
+ ", events: " + mEvents);
|
||||
@@ -454,12 +470,13 @@ class HighBrightnessModeController {
|
||||
}
|
||||
|
||||
private void updateHbmStats(int newMode) {
|
||||
final float transitionPoint = mHbmData.transitionPoint;
|
||||
int state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
|
||||
if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
|
||||
&& getHdrBrightnessValue() > mHbmData.transitionPoint) {
|
||||
&& getHdrBrightnessValue() > transitionPoint) {
|
||||
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR;
|
||||
} else if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT
|
||||
&& mBrightness > mHbmData.transitionPoint) {
|
||||
&& mBrightness > transitionPoint) {
|
||||
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT;
|
||||
}
|
||||
if (state == mHbmStatsState) {
|
||||
@@ -468,11 +485,21 @@ class HighBrightnessModeController {
|
||||
|
||||
int reason =
|
||||
FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN;
|
||||
boolean oldHbmSv = (mHbmStatsState
|
||||
final boolean oldHbmSv = (mHbmStatsState
|
||||
== FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT);
|
||||
boolean newHbmSv =
|
||||
final boolean newHbmSv =
|
||||
(state == FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT);
|
||||
if (oldHbmSv && !newHbmSv) {
|
||||
// HighBrightnessModeController (HBMC) currently supports throttling from two sources:
|
||||
// 1. Internal, received from HBMC.SkinThermalStatusObserver.notifyThrottling()
|
||||
// 2. External, received from HBMC.onBrightnessChanged()
|
||||
// TODO(b/216373254): Deprecate internal throttling source
|
||||
final boolean internalThermalThrottling = !mIsThermalStatusWithinLimit;
|
||||
final boolean externalThermalThrottling =
|
||||
mUnthrottledBrightness > transitionPoint && // We would've liked HBM brightness...
|
||||
mBrightness <= transitionPoint && // ...but we got NBM, because of...
|
||||
mThrottlingReason == BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL; // ...thermals.
|
||||
|
||||
// If more than one conditions are flipped and turn off HBM sunlight
|
||||
// visibility, only one condition will be reported to make it simple.
|
||||
if (!mIsAutoBrightnessEnabled && mIsAutoBrightnessOffByState) {
|
||||
@@ -485,7 +512,7 @@ class HighBrightnessModeController {
|
||||
reason = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LUX_DROP;
|
||||
} else if (!mIsTimeAvailable) {
|
||||
reason = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_TIME_LIMIT;
|
||||
} else if (!mIsThermalStatusWithinLimit) {
|
||||
} else if (internalThermalThrottling || externalThermalThrottling) {
|
||||
reason = FrameworkStatsLog
|
||||
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT;
|
||||
} else if (mIsHdrLayerPresent) {
|
||||
@@ -575,7 +602,7 @@ class HighBrightnessModeController {
|
||||
>= ((float) (mWidth * mHeight) * HDR_PERCENT_OF_SCREEN_REQUIRED);
|
||||
// Calling the brightness update so that we can recalculate
|
||||
// brightness with HDR in mind.
|
||||
onBrightnessChanged(mBrightness);
|
||||
onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,21 +18,40 @@ package com.android.server.display;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.hardware.display.BrightnessInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.IThermalEventListener;
|
||||
import android.os.IThermalService;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Temperature.ThrottlingStatus;
|
||||
import android.os.Temperature;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.display.BrightnessThrottler.Injector;
|
||||
import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel;
|
||||
import com.android.server.display.DisplayDeviceConfig.BrightnessThrottlingData;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -43,10 +62,28 @@ import java.util.List;
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BrightnessThrottlerTest {
|
||||
private static final float EPSILON = 0.000001f;
|
||||
|
||||
private Handler mHandler;
|
||||
private TestLooper mTestLooper;
|
||||
|
||||
@Mock IThermalService mThermalServiceMock;
|
||||
@Mock Injector mInjectorMock;
|
||||
|
||||
@Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mInjectorMock.getThermalService()).thenReturn(mThermalServiceMock);
|
||||
mTestLooper = new TestLooper();
|
||||
mHandler = new Handler(mTestLooper.getLooper(), new Handler.Callback() {
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/////////////////
|
||||
@@ -62,19 +99,23 @@ public class BrightnessThrottlerTest {
|
||||
validLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f));
|
||||
validLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f));
|
||||
|
||||
List<ThrottlingLevel> invalidThermalLevels = new ArrayList<>();
|
||||
invalidThermalLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.62f));
|
||||
invalidThermalLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.25f));
|
||||
List<ThrottlingLevel> unsortedThermalLevels = new ArrayList<>();
|
||||
unsortedThermalLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.62f));
|
||||
unsortedThermalLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.25f));
|
||||
|
||||
List<ThrottlingLevel> invalidBrightnessLevels = new ArrayList<>();
|
||||
invalidBrightnessLevels.add(
|
||||
List<ThrottlingLevel> unsortedBrightnessLevels = new ArrayList<>();
|
||||
unsortedBrightnessLevels.add(
|
||||
new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.25f));
|
||||
invalidBrightnessLevels.add(
|
||||
unsortedBrightnessLevels.add(
|
||||
new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.62f));
|
||||
|
||||
List<ThrottlingLevel> invalidLevels = new ArrayList<>();
|
||||
invalidLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f));
|
||||
invalidLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f));
|
||||
List<ThrottlingLevel> unsortedLevels = new ArrayList<>();
|
||||
unsortedLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f));
|
||||
unsortedLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f));
|
||||
|
||||
List<ThrottlingLevel> invalidLevel = new ArrayList<>();
|
||||
invalidLevel.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
|
||||
PowerManager.BRIGHTNESS_MAX + EPSILON));
|
||||
|
||||
// Test invalid data
|
||||
BrightnessThrottlingData data;
|
||||
@@ -84,11 +125,13 @@ public class BrightnessThrottlerTest {
|
||||
assertEquals(data, null);
|
||||
data = BrightnessThrottlingData.create(new ArrayList<ThrottlingLevel>());
|
||||
assertEquals(data, null);
|
||||
data = BrightnessThrottlingData.create(invalidThermalLevels);
|
||||
data = BrightnessThrottlingData.create(unsortedThermalLevels);
|
||||
assertEquals(data, null);
|
||||
data = BrightnessThrottlingData.create(invalidBrightnessLevels);
|
||||
data = BrightnessThrottlingData.create(unsortedBrightnessLevels);
|
||||
assertEquals(data, null);
|
||||
data = BrightnessThrottlingData.create(invalidLevels);
|
||||
data = BrightnessThrottlingData.create(unsortedLevels);
|
||||
assertEquals(data, null);
|
||||
data = BrightnessThrottlingData.create(invalidLevel);
|
||||
assertEquals(data, null);
|
||||
|
||||
// Test valid data
|
||||
@@ -101,6 +144,154 @@ public class BrightnessThrottlerTest {
|
||||
assertThrottlingLevelsEquals(validLevels, data.throttlingLevels);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrottlingUnsupported() throws Exception {
|
||||
final BrightnessThrottler throttler = createThrottlerUnsupported();
|
||||
assertFalse(throttler.deviceSupportsThrottling());
|
||||
|
||||
// Thermal listener shouldn't be registered if throttling is unsupported
|
||||
verify(mInjectorMock, never()).getThermalService();
|
||||
|
||||
// Ensure that brightness is uncapped when the device doesn't support throttling
|
||||
assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrottlingSingleLevel() throws Exception {
|
||||
final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
|
||||
0.25f);
|
||||
|
||||
List<ThrottlingLevel> levels = new ArrayList<>();
|
||||
levels.add(level);
|
||||
final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels);
|
||||
final BrightnessThrottler throttler = createThrottlerSupported(data);
|
||||
assertTrue(throttler.deviceSupportsThrottling());
|
||||
|
||||
verify(mThermalServiceMock).registerThermalEventListenerWithType(
|
||||
mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
|
||||
final IThermalEventListener listener = mThermalEventListenerCaptor.getValue();
|
||||
|
||||
// Set status too low to trigger throttling
|
||||
listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
|
||||
assertFalse(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason());
|
||||
|
||||
// Set status just high enough to trigger throttling
|
||||
listener.notifyThrottling(getSkinTemp(level.thermalStatus));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(level.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Set status more than high enough to trigger throttling
|
||||
listener.notifyThrottling(getSkinTemp(level.thermalStatus + 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(level.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Return to the lower throttling level
|
||||
listener.notifyThrottling(getSkinTemp(level.thermalStatus));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(level.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Cool down
|
||||
listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
|
||||
assertFalse(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE,
|
||||
throttler.getBrightnessMaxReason());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrottlingMultiLevel() throws Exception {
|
||||
final ThrottlingLevel levelLo = new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE,
|
||||
0.62f);
|
||||
final ThrottlingLevel levelHi = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
|
||||
0.25f);
|
||||
|
||||
List<ThrottlingLevel> levels = new ArrayList<>();
|
||||
levels.add(levelLo);
|
||||
levels.add(levelHi);
|
||||
final BrightnessThrottlingData data = BrightnessThrottlingData.create(levels);
|
||||
final BrightnessThrottler throttler = createThrottlerSupported(data);
|
||||
assertTrue(throttler.deviceSupportsThrottling());
|
||||
|
||||
verify(mThermalServiceMock).registerThermalEventListenerWithType(
|
||||
mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
|
||||
final IThermalEventListener listener = mThermalEventListenerCaptor.getValue();
|
||||
|
||||
// Set status too low to trigger throttling
|
||||
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus - 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
|
||||
assertFalse(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason());
|
||||
|
||||
// Set status just high enough to trigger throttling
|
||||
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Set status to an intermediate throttling level
|
||||
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus + 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Set status to the highest configured throttling level
|
||||
listener.notifyThrottling(getSkinTemp(levelHi.thermalStatus));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(levelHi.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Set status to exceed the highest configured throttling level
|
||||
listener.notifyThrottling(getSkinTemp(levelHi.thermalStatus + 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(levelHi.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Return to an intermediate throttling level
|
||||
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus + 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Return to the lowest configured throttling level
|
||||
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
|
||||
assertTrue(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
|
||||
throttler.getBrightnessMaxReason());
|
||||
|
||||
// Cool down
|
||||
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus - 1));
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
|
||||
assertFalse(throttler.isThrottled());
|
||||
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE, throttler.getBrightnessMaxReason());
|
||||
}
|
||||
|
||||
private void assertThrottlingLevelsEquals(
|
||||
List<ThrottlingLevel> expected,
|
||||
List<ThrottlingLevel> actual) {
|
||||
@@ -115,4 +306,16 @@ public class BrightnessThrottlerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private BrightnessThrottler createThrottlerUnsupported() {
|
||||
return new BrightnessThrottler(mInjectorMock, mHandler, null, () -> {});
|
||||
}
|
||||
|
||||
private BrightnessThrottler createThrottlerSupported(BrightnessThrottlingData data) {
|
||||
assertNotNull(data);
|
||||
return new BrightnessThrottler(mInjectorMock, mHandler, data, () -> {});
|
||||
}
|
||||
|
||||
private Temperature getSkinTemp(@ThrottlingStatus int status) {
|
||||
return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1461,7 +1461,8 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM, with brightness in the HBM range
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(TRANSITION_POINT + FLOAT_TOLERANCE, 0.0f, 1.0f,
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, hbmRefreshRate);
|
||||
@@ -1469,7 +1470,8 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM, with brightness below the HBM range
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(TRANSITION_POINT - FLOAT_TOLERANCE, 0.0f, 1.0f,
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1477,7 +1479,8 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1485,7 +1488,8 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM, with brightness in the HBM range
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(TRANSITION_POINT + FLOAT_TOLERANCE, 0.0f, 1.0f,
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, hbmRefreshRate);
|
||||
@@ -1493,7 +1497,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1501,7 +1505,8 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM, with brightness below the HBM range
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(TRANSITION_POINT - FLOAT_TOLERANCE, 0.0f, 1.0f,
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT));
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1509,7 +1514,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1580,7 +1585,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, initialRefreshRate);
|
||||
@@ -1598,7 +1603,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1606,7 +1611,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn HBM on again and ensure the updated vote value stuck
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, updatedRefreshRate);
|
||||
@@ -1622,7 +1627,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1654,7 +1659,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1662,7 +1667,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1694,7 +1699,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM when HBM is supported; expect a valid transition point and a vote.
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, 60.0f);
|
||||
@@ -1702,7 +1707,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1711,7 +1716,7 @@ public class DisplayModeDirectorTest {
|
||||
// no vote.
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
|
||||
HBM_TRANSITION_POINT_INVALID));
|
||||
HBM_TRANSITION_POINT_INVALID, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1720,7 +1725,7 @@ public class DisplayModeDirectorTest {
|
||||
// no vote.
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR,
|
||||
HBM_TRANSITION_POINT_INVALID));
|
||||
HBM_TRANSITION_POINT_INVALID, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1728,7 +1733,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
@@ -1737,7 +1742,8 @@ public class DisplayModeDirectorTest {
|
||||
private void setHbmAndAssertRefreshRate(
|
||||
DisplayModeDirector director, DisplayListener listener, int mode, float rr) {
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID))
|
||||
.thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode, TRANSITION_POINT));
|
||||
.thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode, TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
|
||||
final Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
@@ -1817,7 +1823,7 @@ public class DisplayModeDirectorTest {
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
|
||||
TRANSITION_POINT));
|
||||
TRANSITION_POINT, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, 60.f);
|
||||
@@ -1978,7 +1984,8 @@ public class DisplayModeDirectorTest {
|
||||
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(floatBri, floatAdjBri, 0.0f, 1.0f,
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, TRANSITION_POINT));
|
||||
BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, TRANSITION_POINT,
|
||||
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.display;
|
||||
|
||||
import static android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
|
||||
import static android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
|
||||
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR;
|
||||
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
|
||||
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
|
||||
@@ -201,7 +203,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
|
||||
// Verify we are in HBM
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
@@ -233,7 +235,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
|
||||
// Verify we are in HBM
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
@@ -258,18 +260,18 @@ public class HighBrightnessModeControllerTest {
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
|
||||
|
||||
// Verify we are in HBM
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT - 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT - 0.01f);
|
||||
advanceTime(1);
|
||||
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
|
||||
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
@@ -288,13 +290,13 @@ public class HighBrightnessModeControllerTest {
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
|
||||
// Go into HBM for half the allowed window
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2);
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
|
||||
// Move lux below threshold (ending first event);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT);
|
||||
assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
|
||||
|
||||
// Move up some amount of time so that there's still time in the window even after a
|
||||
@@ -304,7 +306,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
// Go into HBM for just under the second half of allowed window
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 1);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 1);
|
||||
advanceTime((TIME_ALLOWED_IN_WINDOW_MILLIS / 2) - 1);
|
||||
|
||||
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
|
||||
@@ -434,7 +436,7 @@ public class HighBrightnessModeControllerTest {
|
||||
float brightness = 0.5f;
|
||||
float expectedHdrBrightness = MathUtils.map(DEFAULT_MIN, TRANSITION_POINT,
|
||||
DEFAULT_MIN, DEFAULT_MAX, brightness); // map value from normal range to hdr range
|
||||
hbmc.onBrightnessChanged(brightness);
|
||||
hbmcOnBrightnessChanged(hbmc, brightness);
|
||||
advanceTime(0);
|
||||
assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
|
||||
|
||||
@@ -442,21 +444,21 @@ public class HighBrightnessModeControllerTest {
|
||||
brightness = 0.33f;
|
||||
expectedHdrBrightness = MathUtils.map(DEFAULT_MIN, TRANSITION_POINT,
|
||||
DEFAULT_MIN, DEFAULT_MAX, brightness); // map value from normal range to hdr range
|
||||
hbmc.onBrightnessChanged(brightness);
|
||||
hbmcOnBrightnessChanged(hbmc, brightness);
|
||||
advanceTime(0);
|
||||
assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
|
||||
|
||||
// Try the min value
|
||||
brightness = DEFAULT_MIN;
|
||||
expectedHdrBrightness = DEFAULT_MIN;
|
||||
hbmc.onBrightnessChanged(brightness);
|
||||
hbmcOnBrightnessChanged(hbmc, brightness);
|
||||
advanceTime(0);
|
||||
assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
|
||||
|
||||
// Try the max value
|
||||
brightness = TRANSITION_POINT;
|
||||
expectedHdrBrightness = DEFAULT_MAX;
|
||||
hbmc.onBrightnessChanged(brightness);
|
||||
hbmcOnBrightnessChanged(hbmc, brightness);
|
||||
advanceTime(0);
|
||||
assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
|
||||
}
|
||||
@@ -467,7 +469,7 @@ public class HighBrightnessModeControllerTest {
|
||||
final int displayStatsId = mDisplayUniqueId.hashCode();
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT);
|
||||
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
|
||||
advanceTime(0);
|
||||
@@ -489,7 +491,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
|
||||
// Verify Stats HBM_ON_SUNLIGHT
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
@@ -506,12 +508,12 @@ public class HighBrightnessModeControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tetHbmStats_NbmHdrNoReport() {
|
||||
public void testHbmStats_NbmHdrNoReport() {
|
||||
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
|
||||
final int displayStatsId = mDisplayUniqueId.hashCode();
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onBrightnessChanged(DEFAULT_MIN);
|
||||
hbmcOnBrightnessChanged(hbmc, DEFAULT_MIN);
|
||||
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
|
||||
advanceTime(0);
|
||||
@@ -524,13 +526,13 @@ public class HighBrightnessModeControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tetHbmStats_HighLuxLowBrightnessNoReport() {
|
||||
public void testHbmStats_HighLuxLowBrightnessNoReport() {
|
||||
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
|
||||
final int displayStatsId = mDisplayUniqueId.hashCode();
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(DEFAULT_MIN);
|
||||
hbmcOnBrightnessChanged(hbmc, DEFAULT_MIN);
|
||||
advanceTime(0);
|
||||
// verify in HBM sunlight mode
|
||||
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
|
||||
@@ -541,8 +543,10 @@ public class HighBrightnessModeControllerTest {
|
||||
anyInt());
|
||||
}
|
||||
|
||||
// Test reporting of thermal throttling when triggered by HighBrightnessModeController's
|
||||
// internal thermal throttling.
|
||||
@Test
|
||||
public void testHbmStats_ThermalOff() throws Exception {
|
||||
public void testHbmStats_InternalThermalOff() throws Exception {
|
||||
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
|
||||
final int displayStatsId = mDisplayUniqueId.hashCode();
|
||||
|
||||
@@ -552,7 +556,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(1);
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
|
||||
@@ -566,6 +570,37 @@ public class HighBrightnessModeControllerTest {
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT));
|
||||
}
|
||||
|
||||
// Test reporting of thermal throttling when triggered externally through
|
||||
// HighBrightnessModeController.onBrightnessChanged()
|
||||
@Test
|
||||
public void testHbmStats_ExternalThermalOff() throws Exception {
|
||||
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
|
||||
final int displayStatsId = mDisplayUniqueId.hashCode();
|
||||
final float hbmBrightness = TRANSITION_POINT + 0.01f;
|
||||
final float nbmBrightness = TRANSITION_POINT - 0.01f;
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
// Brightness is unthrottled, HBM brightness granted
|
||||
hbmc.onBrightnessChanged(hbmBrightness, hbmBrightness, BRIGHTNESS_MAX_REASON_NONE);
|
||||
advanceTime(1);
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
|
||||
|
||||
// Brightness is thermally throttled, HBM brightness denied (NBM brightness granted)
|
||||
hbmc.onBrightnessChanged(nbmBrightness, hbmBrightness, BRIGHTNESS_MAX_REASON_THERMAL);
|
||||
advanceTime(1);
|
||||
// We expect HBM mode to remain set to sunlight, indicating that HBMC *allows* this mode.
|
||||
// However, we expect the HBM state reported by HBMC to be off, since external thermal
|
||||
// throttling (reported to HBMC through onBrightnessChanged()) lowers brightness to below
|
||||
// the HBM transition point.
|
||||
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHbmStats_TimeOut() {
|
||||
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
|
||||
@@ -573,7 +608,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(0);
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
|
||||
@@ -594,7 +629,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(0);
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
|
||||
@@ -613,7 +648,7 @@ public class HighBrightnessModeControllerTest {
|
||||
|
||||
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
|
||||
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
|
||||
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
|
||||
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
|
||||
advanceTime(0);
|
||||
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
|
||||
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
|
||||
@@ -667,4 +702,8 @@ public class HighBrightnessModeControllerTest {
|
||||
private Temperature getSkinTemp(@ThrottlingStatus int status) {
|
||||
return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
|
||||
}
|
||||
|
||||
private void hbmcOnBrightnessChanged(HighBrightnessModeController hbmc, float brightness) {
|
||||
hbmc.onBrightnessChanged(brightness, brightness, BRIGHTNESS_MAX_REASON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user