Merge changes from topic "brightnessthrottler"

* changes:
  Add display brightness throttler
  Add BrightnessThrottler data to display device config
  Report HBM_ON_SUNLIGHT when display is in hbm mode
This commit is contained in:
TreeHugger Robot
2022-01-27 23:21:30 +00:00
committed by Android (Google) Code Review
10 changed files with 1047 additions and 65 deletions

View File

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

View File

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

View File

@@ -33,6 +33,8 @@ import android.view.DisplayAddress;
import com.android.internal.R;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.config.BrightnessThresholds;
import com.android.server.display.config.BrightnessThrottlingMap;
import com.android.server.display.config.BrightnessThrottlingPoint;
import com.android.server.display.config.Density;
import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
@@ -43,6 +45,7 @@ import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.SensorDetails;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.config.ThermalThrottling;
import com.android.server.display.config.Thresholds;
import com.android.server.display.config.XmlParser;
@@ -145,6 +148,8 @@ public class DisplayDeviceConfig {
private DensityMap mDensityMap;
private String mLoadedFrom = null;
private BrightnessThrottlingData mBrightnessThrottlingData;
private DisplayDeviceConfig(Context context) {
mContext = context;
}
@@ -424,6 +429,13 @@ public class DisplayDeviceConfig {
return mDensityMap;
}
/**
* @return brightness throttling data configuration data for the display.
*/
public BrightnessThrottlingData getBrightnessThrottlingData() {
return BrightnessThrottlingData.create(mBrightnessThrottlingData);
}
@Override
public String toString() {
return "DisplayDeviceConfig{"
@@ -441,6 +453,7 @@ public class DisplayDeviceConfig {
+ ", mQuirks=" + mQuirks
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ ", mHbmData=" + mHbmData
+ ", mBrightnessThrottlingData=" + mBrightnessThrottlingData
+ ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
+ ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
@@ -502,6 +515,7 @@ public class DisplayDeviceConfig {
loadBrightnessDefaultFromDdcXml(config);
loadBrightnessConstraintsFromConfigXml();
loadBrightnessMap(config);
loadBrightnessThrottlingMap(config);
loadHighBrightnessModeData(config);
loadQuirks(config);
loadBrightnessRamps(config);
@@ -664,6 +678,41 @@ public class DisplayDeviceConfig {
constrainNitsAndBacklightArrays();
}
private void loadBrightnessThrottlingMap(DisplayConfiguration config) {
final ThermalThrottling throttlingConfig = config.getThermalThrottling();
if (throttlingConfig == null) {
Slog.i(TAG, "no thermal throttling config found");
return;
}
final BrightnessThrottlingMap map = throttlingConfig.getBrightnessThrottlingMap();
if (map == null) {
Slog.i(TAG, "no brightness throttling map found");
return;
}
final List<BrightnessThrottlingPoint> points = map.getBrightnessThrottlingPoint();
// At least 1 point is guaranteed by the display device config schema
List<BrightnessThrottlingData.ThrottlingLevel> throttlingLevels =
new ArrayList<>(points.size());
boolean badConfig = false;
for (BrightnessThrottlingPoint point : points) {
ThermalStatus status = point.getThermalStatus();
if (!thermalStatusIsValid(status)) {
badConfig = true;
break;
}
throttlingLevels.add(new BrightnessThrottlingData.ThrottlingLevel(
convertThermalStatus(status), point.getBrightness().floatValue()));
}
if (!badConfig) {
mBrightnessThrottlingData = BrightnessThrottlingData.create(throttlingLevels);
}
}
private void loadBrightnessMapFromConfigXml() {
// Use the config.xml mapping
final Resources res = mContext.getResources();
@@ -931,6 +980,25 @@ public class DisplayDeviceConfig {
}
}
private boolean thermalStatusIsValid(ThermalStatus value) {
if (value == null) {
return false;
}
switch (value) {
case none:
case light:
case moderate:
case severe:
case critical:
case emergency:
case shutdown:
return true;
default:
return false;
}
}
private @PowerManager.ThermalStatus int convertThermalStatus(ThermalStatus value) {
if (value == null) {
return PowerManager.THERMAL_STATUS_NONE;
@@ -1061,4 +1129,91 @@ public class DisplayDeviceConfig {
+ "} ";
}
}
/**
* Container for brightness throttling data.
*/
static class BrightnessThrottlingData {
static class ThrottlingLevel {
public @PowerManager.ThermalStatus int thermalStatus;
public float brightness;
ThrottlingLevel(@PowerManager.ThermalStatus int thermalStatus, float brightness) {
this.thermalStatus = thermalStatus;
this.brightness = brightness;
}
@Override
public String toString() {
return "[" + thermalStatus + "," + brightness + "]";
}
}
public List<ThrottlingLevel> throttlingLevels;
static public BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels)
{
if (throttlingLevels == null || throttlingLevels.size() == 0) {
Slog.e(TAG, "BrightnessThrottlingData received null or empty throttling levels");
return null;
}
ThrottlingLevel prevLevel = throttlingLevels.get(0);
final int numLevels = throttlingLevels.size();
for (int i = 1; i < numLevels; i++) {
ThrottlingLevel thisLevel = throttlingLevels.get(i);
if (thisLevel.thermalStatus <= prevLevel.thermalStatus) {
Slog.e(TAG, "brightnessThrottlingMap must be strictly increasing, ignoring "
+ "configuration. ThermalStatus " + thisLevel.thermalStatus + " <= "
+ prevLevel.thermalStatus);
return null;
}
if (thisLevel.brightness >= prevLevel.brightness) {
Slog.e(TAG, "brightnessThrottlingMap must be strictly decreasing, ignoring "
+ "configuration. Brightness " + thisLevel.brightness + " >= "
+ thisLevel.brightness);
return null;
}
prevLevel = thisLevel;
}
for (ThrottlingLevel level : throttlingLevels) {
// Non-negative brightness values are enforced by device config schema
if (level.brightness > PowerManager.BRIGHTNESS_MAX) {
Slog.e(TAG, "brightnessThrottlingMap contains a brightness value exceeding "
+ "system max. Brightness " + level.brightness + " > "
+ PowerManager.BRIGHTNESS_MAX);
return null;
}
}
return new BrightnessThrottlingData(throttlingLevels);
}
static public BrightnessThrottlingData create(BrightnessThrottlingData other) {
if (other == null)
return null;
return BrightnessThrottlingData.create(other.throttlingLevels);
}
@Override
public String toString() {
return "BrightnessThrottlingData{"
+ "throttlingLevels:" + throttlingLevels
+ "} ";
}
private BrightnessThrottlingData(List<ThrottlingLevel> inLevels) {
throttlingLevels = new ArrayList<>(inLevels.size());
for (ThrottlingLevel level : inLevels) {
throttlingLevels.add(new ThrottlingLevel(level.thermalStatus, level.brightness));
}
}
}
}

View File

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

View File

@@ -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);
@@ -446,31 +462,44 @@ class HighBrightnessModeController {
private void updateHbmMode() {
int newHbmMode = calculateHighBrightnessMode();
updateHbmStats(mHbmMode, newHbmMode);
updateHbmStats(newHbmMode);
if (mHbmMode != newHbmMode) {
mHbmMode = newHbmMode;
mHbmChangeCallback.run();
}
}
private void updateHbmStats(int mode, int newMode) {
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) {
} else if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT
&& mBrightness > transitionPoint) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT;
}
if (state == mHbmStatsState) {
return;
}
mHbmStatsState = state;
int reason =
FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN;
boolean oldHbmSv = (mode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT);
boolean newHbmSv = (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT);
final boolean oldHbmSv = (mHbmStatsState
== FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT);
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) {
@@ -483,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) {
@@ -496,6 +525,7 @@ class HighBrightnessModeController {
}
mInjector.reportHbmStateChange(mDisplayStatsId, state, reason);
mHbmStatsState = state;
}
private String hbmStatsStateToString(int hbmStatsState) {
@@ -572,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);
});
}
}

View File

@@ -38,6 +38,10 @@
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
<xs:element type="thermalThrottling" name="thermalThrottling">
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
<xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0"
maxOccurs="1"/>
<xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1" />
@@ -154,6 +158,37 @@
</xs:restriction>
</xs:simpleType>
<xs:complexType name="thermalThrottling">
<xs:complexType>
<xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap">
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
</xs:complexType>
</xs:complexType>
<xs:complexType name="brightnessThrottlingMap">
<xs:sequence>
<xs:element name="brightnessThrottlingPoint" type="brightnessThrottlingPoint" maxOccurs="unbounded" minOccurs="1">
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="brightnessThrottlingPoint">
<xs:sequence>
<xs:element type="thermalStatus" name="thermalStatus">
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
<xs:element type="nonNegativeDecimal" name="brightness">
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="nitsMap">
<xs:sequence>
<xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2">

View File

@@ -7,6 +7,19 @@ package com.android.server.display.config {
method public final void setMinimum(@NonNull java.math.BigDecimal);
}
public class BrightnessThrottlingMap {
ctor public BrightnessThrottlingMap();
method @NonNull public final java.util.List<com.android.server.display.config.BrightnessThrottlingPoint> getBrightnessThrottlingPoint();
}
public class BrightnessThrottlingPoint {
ctor public BrightnessThrottlingPoint();
method @NonNull public final java.math.BigDecimal getBrightness();
method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus();
method public final void setBrightness(@NonNull java.math.BigDecimal);
method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus);
}
public class Density {
ctor public Density();
method @NonNull public final java.math.BigInteger getDensity();
@@ -39,6 +52,7 @@ package com.android.server.display.config {
method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease();
method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease();
method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();
method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
method public final void setAmbientLightHorizonLong(java.math.BigInteger);
method public final void setAmbientLightHorizonShort(java.math.BigInteger);
@@ -54,6 +68,7 @@ package com.android.server.display.config {
method public final void setScreenBrightnessRampFastIncrease(java.math.BigDecimal);
method public final void setScreenBrightnessRampSlowDecrease(java.math.BigDecimal);
method public final void setScreenBrightnessRampSlowIncrease(java.math.BigDecimal);
method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling);
}
public class DisplayQuirks {
@@ -131,6 +146,12 @@ package com.android.server.display.config {
enum_constant public static final com.android.server.display.config.ThermalStatus shutdown;
}
public class ThermalThrottling {
ctor public ThermalThrottling();
method @NonNull public final com.android.server.display.config.BrightnessThrottlingMap getBrightnessThrottlingMap();
method public final void setBrightnessThrottlingMap(@NonNull com.android.server.display.config.BrightnessThrottlingMap);
}
public class Thresholds {
ctor public Thresholds();
method @NonNull public final com.android.server.display.config.BrightnessThresholds getBrighteningThresholds();

View File

@@ -0,0 +1,321 @@
/*
* 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 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;
import java.util.Arrays;
import java.util.List;
@SmallTest
@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;
}
});
}
/////////////////
// Test Methods
/////////////////
@Test
public void testBrightnessThrottlingData() {
List<ThrottlingLevel> singleLevel = new ArrayList<>();
singleLevel.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.25f));
List<ThrottlingLevel> validLevels = new ArrayList<>();
validLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.62f));
validLevels.add(new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 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> unsortedBrightnessLevels = new ArrayList<>();
unsortedBrightnessLevels.add(
new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.25f));
unsortedBrightnessLevels.add(
new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 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;
data = BrightnessThrottlingData.create((List<ThrottlingLevel>)null);
assertEquals(data, null);
data = BrightnessThrottlingData.create((BrightnessThrottlingData)null);
assertEquals(data, null);
data = BrightnessThrottlingData.create(new ArrayList<ThrottlingLevel>());
assertEquals(data, null);
data = BrightnessThrottlingData.create(unsortedThermalLevels);
assertEquals(data, null);
data = BrightnessThrottlingData.create(unsortedBrightnessLevels);
assertEquals(data, null);
data = BrightnessThrottlingData.create(unsortedLevels);
assertEquals(data, null);
data = BrightnessThrottlingData.create(invalidLevel);
assertEquals(data, null);
// Test valid data
data = BrightnessThrottlingData.create(singleLevel);
assertNotEquals(data, null);
assertThrottlingLevelsEquals(singleLevel, data.throttlingLevels);
data = BrightnessThrottlingData.create(validLevels);
assertNotEquals(data, null);
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) {
assertEquals(expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
ThrottlingLevel expectedLevel = expected.get(i);
ThrottlingLevel actualLevel = actual.get(i);
assertEquals(expectedLevel.thermalStatus, actualLevel.thermalStatus);
assertEquals(expectedLevel.brightness, actualLevel.brightness, 0.0f);
}
}
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);
}
}

View File

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

View File

@@ -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,7 +526,27 @@ public class HighBrightnessModeControllerTest {
}
@Test
public void testHbmStats_ThermalOff() throws Exception {
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);
hbmcOnBrightnessChanged(hbmc, DEFAULT_MIN);
advanceTime(0);
// verify in HBM sunlight mode
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
// Verify Stats HBM_ON_SUNLIGHT not report
verify(mInjectorMock, never()).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
anyInt());
}
// Test reporting of thermal throttling when triggered by HighBrightnessModeController's
// internal thermal throttling.
@Test
public void testHbmStats_InternalThermalOff() throws Exception {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
final int displayStatsId = mDisplayUniqueId.hashCode();
@@ -534,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),
@@ -548,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());
@@ -555,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),
@@ -576,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),
@@ -595,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),
@@ -649,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);
}
}