From ac86b4817afd5b8ed405b79df4793b7a64dca317 Mon Sep 17 00:00:00 2001 From: Manali Bhutiyani Date: Fri, 30 Dec 2022 23:28:01 +0000 Subject: [hbm] Separate HBM times for multi-display devices. This change separates High brightness mode information for different physical displays, which was currently being shared causing both displays to show similar HBM time remaining. Each display's OLED lifetime risk due to HBM is independent, so each display's HBM for SV timer should be independent. Bug: 254588984 Test: atest com.android.server.display.HbmEventTest atest com.android.server.display.HighBrightnessModeControllerTest atest com.android.server.display.HighBrightnessModeMetadataTest atest com.android.server.display.DisplayPowerControllerTest atest com.android.server.display.DisplayPowerControllerTest2 Manual testing: Manually tested this fix on multiple display devices, with high lux and forcing displays into HBM mode, and changing the displays to see if the time events are being updated correctly. $ adb shell dumpsys display | grep -i remainingtime remainingTime=274576 remainingTime=249182 Change-Id: I0ed4ad99108a1a850dae68e1f6cf92adfab8bc1d Merged-In: I0ed4ad99108a1a850dae68e1f6cf92adfab8bc1d --- .../server/display/DisplayManagerService.java | 64 +++++++++++- .../server/display/DisplayPowerController.java | 14 ++- .../java/com/android/server/display/HbmEvent.java | 46 +++++++++ .../display/HighBrightnessModeController.java | 112 ++++++++++----------- .../server/display/HighBrightnessModeMetadata.java | 58 +++++++++++ .../com/android/server/display/HbmEventTest.java | 57 +++++++++++ .../display/HighBrightnessModeControllerTest.java | 15 ++- .../display/HighBrightnessModeMetadataTest.java | 59 +++++++++++ 8 files changed, 351 insertions(+), 74 deletions(-) create mode 100644 services/core/java/com/android/server/display/HbmEvent.java create mode 100644 services/core/java/com/android/server/display/HighBrightnessModeMetadata.java create mode 100644 services/tests/servicestests/src/com/android/server/display/HbmEventTest.java create mode 100644 services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 8f35924128bb..5cfe65baeb9d 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -104,6 +104,7 @@ import android.os.UserManager; import android.provider.Settings; import android.sysprop.DisplayProperties; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; import android.util.IntArray; @@ -256,6 +257,13 @@ public final class DisplayManagerService extends SystemService { final SparseArray> mDisplayWindowPolicyControllers = new SparseArray<>(); + /** + * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by + * {@link DisplayDevice#mUniqueId}. + */ + public final ArrayMap mHighBrightnessModeMetadataMap = + new ArrayMap<>(); + // List of all currently registered display adapters. private final ArrayList mDisplayAdapters = new ArrayList(); @@ -1570,7 +1578,16 @@ public final class DisplayManagerService extends SystemService { DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { - dpc.onDisplayChanged(); + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + if (device == null) { + Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " + + display.getDisplayIdLocked()); + return; + } + + final String uniqueId = device.getUniqueId(); + HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); + dpc.onDisplayChanged(hbmMetadata); } } @@ -1627,7 +1644,15 @@ public final class DisplayManagerService extends SystemService { final int displayId = display.getDisplayIdLocked(); final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { - dpc.onDisplayChanged(); + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + if (device == null) { + Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " + + display.getDisplayIdLocked()); + return; + } + final String uniqueId = device.getUniqueId(); + HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); + dpc.onDisplayChanged(hbmMetadata); } } @@ -2611,6 +2636,31 @@ public final class DisplayManagerService extends SystemService { mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked); } + private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) { + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + if (device == null) { + Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " + + display.getDisplayIdLocked()); + return null; + } + + // HBM brightness mode is only applicable to internal physical displays. + if (display.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) { + return null; + } + + final String uniqueId = device.getUniqueId(); + + if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) { + return mHighBrightnessModeMetadataMap.get(uniqueId); + } + + // HBM Time info not present. Create a new one for this physical display. + HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata(); + mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo); + return hbmInfo; + } + private void addDisplayPowerControllerLocked(LogicalDisplay display) { if (mPowerHandler == null) { // initPowerManagement has not yet been called. @@ -2622,10 +2672,18 @@ public final class DisplayManagerService extends SystemService { final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore, display, mSyncRoot); + + // If display is internal and has a HighBrightnessModeMetadata mapping, use that. + // Or create a new one and use that. + // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to + // displayPowerController, so the hbm info can be correctly associated + // with the corresponding displaydevice. + HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display); + final DisplayPowerController displayPowerController = new DisplayPowerController( mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, - () -> handleBrightnessChange(display)); + () -> handleBrightnessChange(display), hbmMetadata); mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index f88a3372a4ac..b431306e294d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -391,6 +391,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private float[] mNitsRange; private final HighBrightnessModeController mHbmController; + private final HighBrightnessModeMetadata mHighBrightnessModeMetadata; private final BrightnessThrottler mBrightnessThrottler; @@ -511,7 +512,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay, BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting, - Runnable onBrightnessChangeRunnable) { + Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) { mLogicalDisplay = logicalDisplay; mDisplayId = mLogicalDisplay.getDisplayIdLocked(); final String displayIdStr = "[" + mDisplayId + "]"; @@ -521,6 +522,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mSuspendBlockerIdProxPositive = displayIdStr + "prox positive"; mSuspendBlockerIdProxNegative = displayIdStr + "prox negative"; mSuspendBlockerIdProxDebounce = displayIdStr + "prox debounce"; + mHighBrightnessModeMetadata = hbmMetadata; mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); @@ -793,7 +795,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call * of each display need to be properly reflected in AutomaticBrightnessController. */ @GuardedBy("DisplayManagerService.mSyncRoot") - public void onDisplayChanged() { + public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) { final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); if (device == null) { Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " @@ -815,7 +817,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mUniqueDisplayId = uniqueId; mDisplayStatsId = mUniqueDisplayId.hashCode(); mDisplayDeviceConfig = config; - loadFromDisplayDeviceConfig(token, info); + loadFromDisplayDeviceConfig(token, info, hbmMetadata); /// Since the underlying display-device changed, we really don't know the // last command that was sent to change it's state. Lets assume it is unknown so @@ -872,7 +874,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) { + private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info, + HighBrightnessModeMetadata hbmMetadata) { // All properties that depend on the associated DisplayDevice and the DDC must be // updated here. loadBrightnessRampRates(); @@ -885,6 +888,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRampIncreaseMaxTimeMillis, mBrightnessRampDecreaseMaxTimeMillis); } + mHbmController.setHighBrightnessModeMetadata(hbmMetadata); mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, mDisplayDeviceConfig.getHighBrightnessModeData(), new HighBrightnessModeController.HdrBrightnessDeviceConfig() { @@ -1965,7 +1969,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.update(); } - }, mContext); + }, mHighBrightnessModeMetadata, mContext); } private BrightnessThrottler createBrightnessThrottlerLocked() { diff --git a/services/core/java/com/android/server/display/HbmEvent.java b/services/core/java/com/android/server/display/HbmEvent.java new file mode 100644 index 000000000000..5675e2f69230 --- /dev/null +++ b/services/core/java/com/android/server/display/HbmEvent.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 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; + + +/** + * Represents an event in which High Brightness Mode was enabled. + */ +class HbmEvent { + private long mStartTimeMillis; + private long mEndTimeMillis; + + HbmEvent(long startTimeMillis, long endTimeMillis) { + this.mStartTimeMillis = startTimeMillis; + this.mEndTimeMillis = endTimeMillis; + } + + public long getStartTimeMillis() { + return mStartTimeMillis; + } + + public long getEndTimeMillis() { + return mEndTimeMillis; + } + + @Override + public String toString() { + return "HbmEvent: {startTimeMillis:" + mStartTimeMillis + ", endTimeMillis: " + + mEndTimeMillis + "}, total: " + + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]"; + } +} diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java index 0b9d4debd16f..ac32d53daeab 100644 --- a/services/core/java/com/android/server/display/HighBrightnessModeController.java +++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java @@ -42,8 +42,8 @@ import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData; import com.android.server.display.DisplayManagerService.Clock; import java.io.PrintWriter; +import java.util.ArrayDeque; import java.util.Iterator; -import java.util.LinkedList; /** * Controls the status of high-brightness mode for devices that support it. This class assumes that @@ -105,30 +105,24 @@ class HighBrightnessModeController { private int mHbmStatsState = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF; /** - * If HBM is currently running, this is the start time for the current HBM session. + * If HBM is currently running, this is the start time and set of all events, + * for the current HBM session. */ - private long mRunningStartTimeMillis = -1; - - /** - * List of previous HBM-events ordered from most recent to least recent. - * Meant to store only the events that fall into the most recent - * {@link mHbmData.timeWindowMillis}. - */ - private LinkedList mEvents = new LinkedList<>(); + private HighBrightnessModeMetadata mHighBrightnessModeMetadata = null; HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg, - Runnable hbmChangeCallback, Context context) { + Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) { this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin, - brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context); + brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, hbmMetadata, context); } @VisibleForTesting HighBrightnessModeController(Injector injector, Handler handler, int width, int height, IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg, - Runnable hbmChangeCallback, Context context) { + Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) { mInjector = injector; mContext = context; mClock = injector.getClock(); @@ -137,6 +131,7 @@ class HighBrightnessModeController { mBrightnessMin = brightnessMin; mBrightnessMax = brightnessMax; mHbmChangeCallback = hbmChangeCallback; + mHighBrightnessModeMetadata = hbmMetadata; mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mRecalcRunnable = this::recalculateTimeAllowance; @@ -222,19 +217,22 @@ class HighBrightnessModeController { // If we are starting or ending a high brightness mode session, store the current // session in mRunningStartTimeMillis, or the old one in mEvents. - final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1; + final long runningStartTime = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); + final boolean wasHbmDrainingAvailableTime = runningStartTime != -1; final boolean shouldHbmDrainAvailableTime = mBrightness > mHbmData.transitionPoint && !mIsHdrLayerPresent; if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) { final long currentTime = mClock.uptimeMillis(); if (shouldHbmDrainAvailableTime) { - mRunningStartTimeMillis = currentTime; + mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime); } else { - mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime)); - mRunningStartTimeMillis = -1; + final HbmEvent hbmEvent = new HbmEvent(runningStartTime, currentTime); + mHighBrightnessModeMetadata.addHbmEvent(hbmEvent); + mHighBrightnessModeMetadata.setRunningStartTimeMillis(-1); if (DEBUG) { - Slog.d(TAG, "New HBM event: " + mEvents.getFirst()); + Slog.d(TAG, "New HBM event: " + + mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst()); } } } @@ -260,6 +258,10 @@ class HighBrightnessModeController { mSettingsObserver.stopObserving(); } + void setHighBrightnessModeMetadata(HighBrightnessModeMetadata hbmInfo) { + mHighBrightnessModeMetadata = hbmInfo; + } + void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId, HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) { mWidth = width; @@ -316,20 +318,22 @@ class HighBrightnessModeController { pw.println(" mBrightnessMax=" + mBrightnessMax); pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis())); pw.println(" mIsTimeAvailable= " + mIsTimeAvailable); - pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis)); + pw.println(" mRunningStartTimeMillis=" + + TimeUtils.formatUptime(mHighBrightnessModeMetadata.getRunningStartTimeMillis())); pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit); pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode); pw.println(" width*height=" + mWidth + "*" + mHeight); pw.println(" mEvents="); final long currentTime = mClock.uptimeMillis(); long lastStartTime = currentTime; - if (mRunningStartTimeMillis != -1) { - lastStartTime = dumpHbmEvent(pw, new HbmEvent(mRunningStartTimeMillis, currentTime)); + long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); + if (runningStartTimeMillis != -1) { + lastStartTime = dumpHbmEvent(pw, new HbmEvent(runningStartTimeMillis, currentTime)); } - for (HbmEvent event : mEvents) { - if (lastStartTime > event.endTimeMillis) { + for (HbmEvent event : mHighBrightnessModeMetadata.getHbmEventQueue()) { + if (lastStartTime > event.getEndTimeMillis()) { pw.println(" event: [normal brightness]: " - + TimeUtils.formatDuration(lastStartTime - event.endTimeMillis)); + + TimeUtils.formatDuration(lastStartTime - event.getEndTimeMillis())); } lastStartTime = dumpHbmEvent(pw, event); } @@ -338,12 +342,12 @@ class HighBrightnessModeController { } private long dumpHbmEvent(PrintWriter pw, HbmEvent event) { - final long duration = event.endTimeMillis - event.startTimeMillis; + final long duration = event.getEndTimeMillis() - event.getStartTimeMillis(); pw.println(" event: [" - + TimeUtils.formatUptime(event.startTimeMillis) + ", " - + TimeUtils.formatUptime(event.endTimeMillis) + "] (" + + TimeUtils.formatUptime(event.getStartTimeMillis()) + ", " + + TimeUtils.formatUptime(event.getEndTimeMillis()) + "] (" + TimeUtils.formatDuration(duration) + ")"); - return event.startTimeMillis; + return event.getStartTimeMillis(); } private boolean isCurrentlyAllowed() { @@ -372,13 +376,15 @@ class HighBrightnessModeController { // First, lets see how much time we've taken for any currently running // session of HBM. - if (mRunningStartTimeMillis > 0) { - if (mRunningStartTimeMillis > currentTime) { + long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis(); + if (runningStartTimeMillis > 0) { + if (runningStartTimeMillis > currentTime) { Slog.e(TAG, "Start time set to the future. curr: " + currentTime - + ", start: " + mRunningStartTimeMillis); - mRunningStartTimeMillis = currentTime; + + ", start: " + runningStartTimeMillis); + mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime); + runningStartTimeMillis = currentTime; } - timeAlreadyUsed = currentTime - mRunningStartTimeMillis; + timeAlreadyUsed = currentTime - runningStartTimeMillis; } if (DEBUG) { @@ -387,18 +393,19 @@ class HighBrightnessModeController { // Next, lets iterate through the history of previous sessions and add those times. final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis; - Iterator it = mEvents.iterator(); + Iterator it = mHighBrightnessModeMetadata.getHbmEventQueue().iterator(); while (it.hasNext()) { final HbmEvent event = it.next(); // If this event ended before the current Timing window, discard forever and ever. - if (event.endTimeMillis < windowstartTimeMillis) { + if (event.getEndTimeMillis() < windowstartTimeMillis) { it.remove(); continue; } - final long startTimeMillis = Math.max(event.startTimeMillis, windowstartTimeMillis); - timeAlreadyUsed += event.endTimeMillis - startTimeMillis; + final long startTimeMillis = Math.max(event.getStartTimeMillis(), + windowstartTimeMillis); + timeAlreadyUsed += event.getEndTimeMillis() - startTimeMillis; } if (DEBUG) { @@ -425,17 +432,18 @@ class HighBrightnessModeController { // Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or // brightness change doesn't happen before then. long nextTimeout = -1; + final ArrayDeque hbmEvents = mHighBrightnessModeMetadata.getHbmEventQueue(); if (mBrightness > mHbmData.transitionPoint) { // if we're in high-lux now, timeout when we run out of allowed time. nextTimeout = currentTime + remainingTime; - } else if (!mIsTimeAvailable && mEvents.size() > 0) { + } else if (!mIsTimeAvailable && hbmEvents.size() > 0) { // If we are not allowed...timeout when the oldest event moved outside of the timing // window by at least minTime. Basically, we're calculating the soonest time we can // get {@code timeMinMillis} back to us. final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis; - final HbmEvent lastEvent = mEvents.getLast(); + final HbmEvent lastEvent = hbmEvents.peekLast(); final long startTimePlusMinMillis = - Math.max(windowstartTimeMillis, lastEvent.startTimeMillis) + Math.max(windowstartTimeMillis, lastEvent.getStartTimeMillis()) + mHbmData.timeMinMillis; final long timeWhenMinIsGainedBack = currentTime + (startTimePlusMinMillis - windowstartTimeMillis) - remainingTime; @@ -459,9 +467,10 @@ class HighBrightnessModeController { + ", mUnthrottledBrightness: " + mUnthrottledBrightness + ", mThrottlingReason: " + BrightnessInfo.briMaxReasonToString(mThrottlingReason) - + ", RunningStartTimeMillis: " + mRunningStartTimeMillis + + ", RunningStartTimeMillis: " + + mHighBrightnessModeMetadata.getRunningStartTimeMillis() + ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1) - + ", events: " + mEvents); + + ", events: " + hbmEvents); } if (nextTimeout != -1) { @@ -588,25 +597,6 @@ class HighBrightnessModeController { } } - /** - * Represents an event in which High Brightness Mode was enabled. - */ - private static class HbmEvent { - public long startTimeMillis; - public long endTimeMillis; - - HbmEvent(long startTimeMillis, long endTimeMillis) { - this.startTimeMillis = startTimeMillis; - this.endTimeMillis = endTimeMillis; - } - - @Override - public String toString() { - return "[Event: {" + startTimeMillis + ", " + endTimeMillis + "}, total: " - + ((endTimeMillis - startTimeMillis) / 1000) + "]"; - } - } - @VisibleForTesting class HdrListener extends SurfaceControlHdrLayerInfoListener { @Override diff --git a/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java b/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java new file mode 100644 index 000000000000..37234ff0bf19 --- /dev/null +++ b/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 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 java.util.ArrayDeque; + + +/** + * Represents High Brightness Mode metadata associated + * with a specific internal physical display. + * Required for separately storing data like time information, + * and related events when display was in HBM mode per + * physical internal display. + */ +class HighBrightnessModeMetadata { + /** + * Queue of previous HBM-events ordered from most recent to least recent. + * Meant to store only the events that fall into the most recent + * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}. + */ + private final ArrayDeque mEvents = new ArrayDeque<>(); + + /** + * If HBM is currently running, this is the start time for the current HBM session. + */ + private long mRunningStartTimeMillis = -1; + + public long getRunningStartTimeMillis() { + return mRunningStartTimeMillis; + } + + public void setRunningStartTimeMillis(long setTime) { + mRunningStartTimeMillis = setTime; + } + + public ArrayDeque getHbmEventQueue() { + return mEvents; + } + + public void addHbmEvent(HbmEvent hbmEvent) { + mEvents.addFirst(hbmEvent); + } +} + diff --git a/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java b/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java new file mode 100644 index 000000000000..24fc34849829 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java @@ -0,0 +1,57 @@ +/* + * 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.assertEquals; + + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class HbmEventTest { + private long mStartTimeMillis; + private long mEndTimeMillis; + private HbmEvent mHbmEvent; + + @Before + public void setUp() { + mStartTimeMillis = 10; + mEndTimeMillis = 20; + mHbmEvent = new HbmEvent(mStartTimeMillis, mEndTimeMillis); + } + + @Test + public void getCorrectValues() { + assertEquals(mHbmEvent.getStartTimeMillis(), mStartTimeMillis); + assertEquals(mHbmEvent.getEndTimeMillis(), mEndTimeMillis); + } + + @Test + public void toStringGeneratesExpectedString() { + String actualString = mHbmEvent.toString(); + String expectedString = "HbmEvent: {startTimeMillis:" + mStartTimeMillis + + ", endTimeMillis: " + mEndTimeMillis + "}, total: " + + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]"; + assertEquals(actualString, expectedString); + } +} diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java index 53fa3e2db376..da2e1be00769 100644 --- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java @@ -27,9 +27,7 @@ import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIG 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.DisplayDeviceConfig.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT; - import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID; import static org.junit.Assert.assertEquals; @@ -102,6 +100,7 @@ public class HighBrightnessModeControllerTest { private Binder mDisplayToken; private String mDisplayUniqueId; private Context mContextSpy; + private HighBrightnessModeMetadata mHighBrightnessModeMetadata; @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); @@ -124,6 +123,7 @@ public class HighBrightnessModeControllerTest { 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); @@ -140,7 +140,8 @@ public class HighBrightnessModeControllerTest { initHandler(null); final HighBrightnessModeController hbmc = new HighBrightnessModeController( mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, - mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy); + mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, + null, mContextSpy); assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF); assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f); } @@ -150,7 +151,8 @@ public class HighBrightnessModeControllerTest { initHandler(null); final HighBrightnessModeController hbmc = new HighBrightnessModeController( mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, - mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy); + mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, + 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); @@ -705,9 +707,12 @@ public class HighBrightnessModeControllerTest { // Creates instance with standard initialization values. private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) { initHandler(clock); + if (mHighBrightnessModeMetadata == null) { + mHighBrightnessModeMetadata = new HighBrightnessModeMetadata(); + } return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, - DEFAULT_HBM_DATA, null, () -> {}, mContextSpy); + DEFAULT_HBM_DATA, null, () -> {}, mHighBrightnessModeMetadata, mContextSpy); } private void initHandler(OffsettableClock clock) { diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java new file mode 100644 index 000000000000..ede54e096ad0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java @@ -0,0 +1,59 @@ +/* + * 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.assertEquals; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + + +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class HighBrightnessModeMetadataTest { + private HighBrightnessModeMetadata mHighBrightnessModeMetadata; + + private long mRunningStartTimeMillis = -1; + + @Before + public void setUp() { + mHighBrightnessModeMetadata = new HighBrightnessModeMetadata(); + } + + @Test + public void checkDefaultValues() { + assertEquals(mHighBrightnessModeMetadata.getRunningStartTimeMillis(), + mRunningStartTimeMillis); + assertEquals(mHighBrightnessModeMetadata.getHbmEventQueue().size(), 0); + } + + @Test + public void checkSetValues() { + mRunningStartTimeMillis = 10; + mHighBrightnessModeMetadata.setRunningStartTimeMillis(mRunningStartTimeMillis); + assertEquals(mHighBrightnessModeMetadata.getRunningStartTimeMillis(), + mRunningStartTimeMillis); + HbmEvent expectedHbmEvent = new HbmEvent(10, 20); + mHighBrightnessModeMetadata.addHbmEvent(expectedHbmEvent); + HbmEvent actualHbmEvent = mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst(); + assertEquals(expectedHbmEvent.toString(), actualHbmEvent.toString()); + } +} -- cgit v1.2.3-59-g8ed1b