Merge "Report HBM events to StatsLog"

This commit is contained in:
Long Ling
2022-01-15 06:07:23 +00:00
committed by Android (Google) Code Review
5 changed files with 320 additions and 37 deletions

View File

@@ -54,6 +54,10 @@ class AutomaticBrightnessController {
private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
public static final int AUTO_BRIGHTNESS_ENABLED = 1;
public static final int AUTO_BRIGHTNESS_DISABLED = 2;
public static final int AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE = 3;
// How long the current sensor reading is assumed to be valid beyond the current time.
// This provides a bit of prediction, as well as ensures that the weight for the last sample is
// non-zero, which in turn ensures that the total weight is non-zero.
@@ -214,6 +218,7 @@ class AutomaticBrightnessController {
private IActivityTaskManager mActivityTaskManager;
private PackageManager mPackageManager;
private Context mContext;
private int mState = AUTO_BRIGHTNESS_DISABLED;
private final Injector mInjector;
@@ -331,10 +336,11 @@ class AutomaticBrightnessController {
return mCurrentBrightnessMapper.getAutoBrightnessAdjustment();
}
public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
public void configure(int state, @Nullable BrightnessConfiguration configuration,
float brightness, boolean userChangedBrightness, float adjustment,
boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
mHbmController.setAutoBrightnessEnabled(enable);
mState = state;
mHbmController.setAutoBrightnessEnabled(mState);
// While dozing, the application processor may be suspended which will prevent us from
// receiving new information from the light sensor. On some devices, we may be able to
// switch to a wake-up light sensor instead but for now we will simply disable the sensor
@@ -346,6 +352,7 @@ class AutomaticBrightnessController {
if (userChangedAutoBrightnessAdjustment) {
changed |= setAutoBrightnessAdjustment(adjustment);
}
final boolean enable = mState == AUTO_BRIGHTNESS_ENABLED;
if (userChangedBrightness && enable) {
// Update the brightness curve with the new user control point. It's critical this
// happens after we update the autobrightness adjustment since it may reset it.
@@ -459,6 +466,7 @@ class AutomaticBrightnessController {
public void dump(PrintWriter pw) {
pw.println();
pw.println("Automatic Brightness Controller Configuration:");
pw.println(" mState=" + configStateToString(mState));
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mDozeScaleFactor=" + mDozeScaleFactor);
@@ -520,6 +528,19 @@ class AutomaticBrightnessController {
mScreenBrightnessThresholds.dump(pw);
}
private String configStateToString(int state) {
switch (state) {
case AUTO_BRIGHTNESS_ENABLED:
return "AUTO_BRIGHTNESS_ENABLED";
case AUTO_BRIGHTNESS_DISABLED:
return "AUTO_BRIGHTNESS_DISABLED";
case AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE:
return "AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE";
default:
return String.valueOf(state);
}
}
private boolean setLightSensorEnabled(boolean enable) {
if (enable) {
if (!mLightSensorEnabled) {

View File

@@ -62,6 +62,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.RampAnimator.DualRampAnimator;
@@ -127,6 +128,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int MSG_STOP = 9;
private static final int MSG_UPDATE_BRIGHTNESS = 10;
private static final int MSG_UPDATE_RBC = 11;
private static final int MSG_STATSD_HBM_BRIGHTNESS = 12;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -136,6 +138,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500;
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -356,6 +360,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private float mBrightnessRampRateSlowDecrease;
private float mBrightnessRampRateSlowIncrease;
// Report HBM brightness change to StatsD
private int mDisplayStatsId;
private float mLastStatsBrightness = PowerManager.BRIGHTNESS_MIN;
// Whether or not to skip the initial brightness ramps into STATE_ON.
private final boolean mSkipScreenOnBrightnessRamp;
@@ -466,6 +473,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
TAG = "DisplayPowerController[" + mDisplayId + "]";
mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
mDisplayStatsId = mUniqueDisplayId.hashCode();
mHandler = new DisplayControllerHandler(handler.getLooper());
if (mDisplayId == Display.DEFAULT_DISPLAY) {
@@ -763,6 +771,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mDisplayDevice != device) {
mDisplayDevice = device;
mUniqueDisplayId = uniqueId;
mDisplayStatsId = mUniqueDisplayId.hashCode();
mDisplayDeviceConfig = config;
loadFromDisplayDeviceConfig(token, info);
updatePowerState();
@@ -816,7 +825,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
loadNitsRange(mContext.getResources());
setUpAutoBrightness(mContext.getResources(), mHandler);
reloadReduceBrightColours();
mHbmController.resetHbmData(info.width, info.height, token,
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
mDisplayDeviceConfig.getHighBrightnessModeData());
}
@@ -1004,7 +1013,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
};
private final RampAnimator.Listener mRampAnimatorListener = this::sendUpdatePowerState;
private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
@Override
public void onAnimationEnd() {
sendUpdatePowerState();
final float brightness = mPowerState.getScreenBrightness();
reportStats(brightness);
}
};
/** Clean up all resources that are accessed via the {@link #mHandler} thread. */
private void cleanupHandlerThreadAfterStop() {
@@ -1179,6 +1196,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& Float.isNaN(brightnessState)
&& mAutomaticBrightnessController != null;
final boolean autoBrightnessDisabledDueToDisplayOff = mPowerRequest.useAutoBrightness
&& !(state == Display.STATE_ON || autoBrightnessEnabledInDoze);
final int autoBrightnessState = autoBrightnessEnabled
? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
: autoBrightnessDisabledDueToDisplayOff
? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
: AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
@@ -1229,7 +1253,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Configure auto-brightness.
if (mAutomaticBrightnessController != null) {
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mAutomaticBrightnessController.configure(autoBrightnessState,
mBrightnessConfiguration,
mLastUserSetScreenBrightness,
userSetBrightnessChanged, autoBrightnessAdjustment,
@@ -1626,11 +1650,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
final IBinder displayToken =
mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayTokenLocked();
final String displayUniqueId =
mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
final DisplayDeviceConfig.HighBrightnessModeData hbmData =
ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
() -> {
sendUpdatePowerStateLocked();
postBrightnessChangeRunnable();
@@ -2462,6 +2488,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
private void reportStats(float brightness) {
float hbmTransitionPoint = PowerManager.BRIGHTNESS_MAX;
synchronized(mCachedBrightnessInfo) {
if (mCachedBrightnessInfo.hbmTransitionPoint == null) {
return;
}
hbmTransitionPoint = mCachedBrightnessInfo.hbmTransitionPoint.value;
}
final boolean aboveTransition = brightness > hbmTransitionPoint;
final boolean oldAboveTransition = mLastStatsBrightness > hbmTransitionPoint;
if (aboveTransition || oldAboveTransition) {
mLastStatsBrightness = brightness;
mHandler.removeMessages(MSG_STATSD_HBM_BRIGHTNESS);
if (aboveTransition != oldAboveTransition) {
// report immediately
logHbmBrightnessStats(brightness, mDisplayStatsId);
} else {
// delay for rate limiting
Message msg = mHandler.obtainMessage();
msg.what = MSG_STATSD_HBM_BRIGHTNESS;
msg.arg1 = Float.floatToIntBits(brightness);
msg.arg2 = mDisplayStatsId;
mHandler.sendMessageDelayed(msg, BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS);
}
}
}
private final void logHbmBrightnessStats(float brightness, int displayStatsId) {
synchronized (mHandler) {
FrameworkStatsLog.write(
FrameworkStatsLog.DISPLAY_HBM_BRIGHTNESS_CHANGED, displayStatsId, brightness);
}
}
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -2526,6 +2588,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final int justActivated = msg.arg2;
handleRbcChanged(strengthChanged == 1, justActivated == 1);
break;
case MSG_STATSD_HBM_BRIGHTNESS:
logHbmBrightnessStats(Float.intBitsToFloat(msg.arg1), msg.arg2);
break;
}
}
}

View File

@@ -37,6 +37,7 @@ import android.util.TimeUtils;
import android.view.SurfaceControlHdrLayerInfoListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import com.android.server.display.DisplayManagerService.Clock;
@@ -80,6 +81,7 @@ class HighBrightnessModeController {
private boolean mIsInAllowedAmbientRange = false;
private boolean mIsTimeAvailable = false;
private boolean mIsAutoBrightnessEnabled = false;
private boolean mIsAutoBrightnessOffByState = false;
private float mBrightness;
private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
private boolean mIsHdrLayerPresent = false;
@@ -88,6 +90,7 @@ class HighBrightnessModeController {
private int mWidth;
private int mHeight;
private float mAmbientLux;
private int mDisplayStatsId;
/**
* If HBM is currently running, this is the start time for the current HBM session.
@@ -102,15 +105,15 @@ class HighBrightnessModeController {
private LinkedList<HbmEvent> mEvents = new LinkedList<>();
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData,
Runnable hbmChangeCallback, Context context) {
this(new Injector(), handler, width, height, displayToken, brightnessMin, brightnessMax,
hbmData, hbmChangeCallback, context);
String displayUniqueId, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, Runnable hbmChangeCallback, Context context) {
this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin,
brightnessMax, hbmData, hbmChangeCallback, context);
}
@VisibleForTesting
HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
IBinder displayToken, float brightnessMin, float brightnessMax,
IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
Context context) {
mInjector = injector;
@@ -126,10 +129,13 @@ class HighBrightnessModeController {
mRecalcRunnable = this::recalculateTimeAllowance;
mHdrListener = new HdrListener();
resetHbmData(width, height, displayToken, hbmData);
resetHbmData(width, height, displayToken, displayUniqueId, hbmData);
}
void setAutoBrightnessEnabled(boolean isEnabled) {
void setAutoBrightnessEnabled(int state) {
final boolean isEnabled = state == AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
mIsAutoBrightnessOffByState =
state == AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE;
if (!deviceSupportsHbm() || isEnabled == mIsAutoBrightnessEnabled) {
return;
}
@@ -231,10 +237,12 @@ class HighBrightnessModeController {
mSettingsObserver.stopObserving();
}
void resetHbmData(int width, int height, IBinder displayToken, HighBrightnessModeData hbmData) {
void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId,
HighBrightnessModeData hbmData) {
mWidth = width;
mHeight = height;
mHbmData = hbmData;
mDisplayStatsId = displayUniqueId.hashCode();
unregisterHdrListener();
mSkinThermalStatusObserver.stopObserving();
@@ -275,6 +283,7 @@ class HighBrightnessModeController {
+ (mIsAutoBrightnessEnabled ? "" : " (old/invalid)"));
pw.println(" mIsInAllowedAmbientRange=" + mIsInAllowedAmbientRange);
pw.println(" mIsAutoBrightnessEnabled=" + mIsAutoBrightnessEnabled);
pw.println(" mIsAutoBrightnessOffByState=" + mIsAutoBrightnessOffByState);
pw.println(" mIsHdrLayerPresent=" + mIsHdrLayerPresent);
pw.println(" mBrightnessMin=" + mBrightnessMin);
pw.println(" mBrightnessMax=" + mBrightnessMax);
@@ -436,11 +445,52 @@ class HighBrightnessModeController {
private void updateHbmMode() {
int newHbmMode = calculateHighBrightnessMode();
if (mHbmMode != newHbmMode) {
updateHbmStats(mHbmMode, newHbmMode);
mHbmMode = newHbmMode;
mHbmChangeCallback.run();
}
}
private void updateHbmStats(int mode, int newMode) {
int state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR;
} else if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT;
}
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);
if (oldHbmSv && !newHbmSv) {
// 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) {
reason = FrameworkStatsLog
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_DISPLAY_OFF;
} else if (!mIsAutoBrightnessEnabled) {
reason = FrameworkStatsLog
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_AUTOBRIGHTNESS_OFF;
} else if (!mIsInAllowedAmbientRange) {
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) {
reason = FrameworkStatsLog
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT;
} else if (mIsHdrLayerPresent) {
reason = FrameworkStatsLog
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_HDR_PLAYING;
} else if (mIsBlockedByLowPowerMode) {
reason = FrameworkStatsLog
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_BATTERY_SAVE_ON;
}
}
mInjector.reportHbmStateChange(mDisplayStatsId, state, reason);
}
private int calculateHighBrightnessMode() {
if (!deviceSupportsHbm()) {
return BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
@@ -642,5 +692,10 @@ class HighBrightnessModeController {
return IThermalService.Stub.asInterface(
ServiceManager.getService(Context.THERMAL_SERVICE));
}
public void reportHbmStateChange(int display, int state, int reason) {
FrameworkStatsLog.write(
FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED, display, state, reason);
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.server.display;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
@@ -111,7 +113,7 @@ public class AutomaticBrightnessControllerTest {
// Configure the brightness controller and grab an instance of the sensor listener,
// through which we can deliver fake (for test) sensor values.
controller.configure(true /* enable */, null /* configuration */,
controller.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
0 /* brightness */, false /* userChangedBrightness */, 0 /* adjustment */,
false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
@@ -227,7 +229,7 @@ public class AutomaticBrightnessControllerTest {
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000));
// User sets brightness to 100
mController.configure(true /* enable */, null /* configuration */,
mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */,
false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
@@ -250,7 +252,7 @@ public class AutomaticBrightnessControllerTest {
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000));
// User sets brightness to 100
mController.configure(true /* enable */, null /* configuration */,
mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */,
false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
@@ -267,7 +269,7 @@ public class AutomaticBrightnessControllerTest {
verifyNoMoreInteractions(mBrightnessMappingStrategy);
// User sets idle brightness to 0.5
mController.configure(true /* enable */, null /* configuration */,
mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */,
false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);

View File

@@ -20,6 +20,11 @@ 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;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
import static com.android.server.display.AutomaticBrightnessController
.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE;
import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static org.junit.Assert.assertEquals;
@@ -47,6 +52,7 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
@@ -87,6 +93,7 @@ public class HighBrightnessModeControllerTest {
private TestLooper mTestLooper;
private Handler mHandler;
private Binder mDisplayToken;
private String mDisplayUniqueId;
private Context mContextSpy;
@Rule
@@ -108,6 +115,7 @@ public class HighBrightnessModeControllerTest {
mClock = new OffsettableClock.Stopped();
mTestLooper = new TestLooper(mClock::now);
mDisplayToken = null;
mDisplayUniqueId = "unique_id";
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
when(mContextSpy.getContentResolver()).thenReturn(resolver);
@@ -123,8 +131,8 @@ public class HighBrightnessModeControllerTest {
public void testNoHbmData() {
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
DEFAULT_MAX, null, () -> {}, mContextSpy);
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
}
@@ -133,9 +141,9 @@ public class HighBrightnessModeControllerTest {
public void testNoHbmData_Enabled() {
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN,
DEFAULT_MAX, null, () -> {}, mContextSpy);
hbmc.setAutoBrightnessEnabled(true);
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
@@ -152,7 +160,7 @@ public class HighBrightnessModeControllerTest {
public void testAutoBrightnessEnabled_NoLux() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
}
@@ -160,7 +168,7 @@ public class HighBrightnessModeControllerTest {
public void testAutoBrightnessEnabled_LowLux() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
}
@@ -169,7 +177,7 @@ public class HighBrightnessModeControllerTest {
public void testAutoBrightnessEnabled_HighLux() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_SUNLIGHT);
}
@@ -178,9 +186,9 @@ public class HighBrightnessModeControllerTest {
public void testAutoBrightnessEnabled_HighLux_ThenDisable() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.setAutoBrightnessEnabled(false);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_DISABLED);
assertState(hbmc, DEFAULT_MIN, TRANSITION_POINT, HIGH_BRIGHTNESS_MODE_OFF);
}
@@ -189,7 +197,7 @@ public class HighBrightnessModeControllerTest {
public void testWithinHighRange_thenOverTime_thenEarnBackTime() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
@@ -221,7 +229,7 @@ public class HighBrightnessModeControllerTest {
public void testInHBM_ThenLowLux() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
@@ -245,7 +253,7 @@ public class HighBrightnessModeControllerTest {
public void testInHBM_TestMultipleEvents_DueToAutoBrightness() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
@@ -274,7 +282,7 @@ public class HighBrightnessModeControllerTest {
public void testInHBM_TestMultipleEvents_DueToLux() {
final HighBrightnessModeController hbmc = createDefaultHbm();
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
// Go into HBM for half the allowed window
@@ -316,7 +324,7 @@ public class HighBrightnessModeControllerTest {
listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
// Try to go into HBM mode but fail
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
advanceTime(10);
@@ -335,7 +343,7 @@ public class HighBrightnessModeControllerTest {
listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_LIGHT));
// Try to go into HBM mode
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
advanceTime(1);
@@ -378,7 +386,7 @@ public class HighBrightnessModeControllerTest {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
// Turn on sunlight
hbmc.setAutoBrightnessEnabled(true);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
@@ -451,6 +459,137 @@ public class HighBrightnessModeControllerTest {
assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
}
@Test
public void testHbmStats_StateChange() {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
final int displayStatsId = mDisplayUniqueId.hashCode();
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onBrightnessChanged(TRANSITION_POINT);
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
// Verify Stats HBM_ON_HDR
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
0, 0, 0 /*flags*/);
advanceTime(0);
// Verify Stats HBM_OFF
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
// Verify Stats HBM_ON_SUNLIGHT
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));
hbmc.onAmbientLuxChange(1);
advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2 + 1);
// Verify Stats HBM_OFF
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LUX_DROP));
}
@Test
public void testHbmStats_ThermalOff() throws Exception {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
final int displayStatsId = mDisplayUniqueId.hashCode();
verify(mThermalServiceMock).registerThermalEventListenerWithType(
mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
final IThermalEventListener thermListener = mThermalEventListenerCaptor.getValue();
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
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));
thermListener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
advanceTime(10);
assertEquals(HIGH_BRIGHTNESS_MODE_OFF, 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());
final int displayStatsId = mDisplayUniqueId.hashCode();
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
advanceTime(0);
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));
// Use up all the time in the window.
advanceTime(TIME_WINDOW_MILLIS + 1);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_TIME_LIMIT));
}
@Test
public void testHbmStats_DisplayOff() {
final HighBrightnessModeController hbmc = createDefaultHbm();
final int displayStatsId = mDisplayUniqueId.hashCode();
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
advanceTime(0);
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));
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_DISPLAY_OFF));
}
@Test
public void testHbmStats_HdrPlaying() {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
final int displayStatsId = mDisplayUniqueId.hashCode();
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
hbmc.onBrightnessChanged(TRANSITION_POINT + 0.01f);
advanceTime(0);
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));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
advanceTime(0);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_HDR_PLAYING));
}
private void assertState(HighBrightnessModeController hbmc,
float brightnessMin, float brightnessMax, int hbmMode) {
assertEquals(brightnessMin, hbmc.getCurrentBrightnessMin(), EPSILON);
@@ -466,8 +605,8 @@ public class HighBrightnessModeControllerTest {
private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) {
initHandler(clock);
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, DEFAULT_MIN, DEFAULT_MAX, DEFAULT_HBM_DATA, () -> {},
mContextSpy);
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
DEFAULT_HBM_DATA, () -> {}, mContextSpy);
}
private void initHandler(OffsettableClock clock) {