Loading core/java/android/hardware/display/DisplayManagerInternal.java +46 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.hardware.display; import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Point; import android.hardware.SensorManager; Loading @@ -29,6 +30,9 @@ import android.view.DisplayInfo; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Objects; /** Loading @@ -37,6 +41,16 @@ import java.util.Objects; * @hide Only for use within the system server. */ public abstract class DisplayManagerInternal { @IntDef(prefix = {"REFRESH_RATE_LIMIT_"}, value = { REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE }) @Retention(RetentionPolicy.SOURCE) public @interface RefreshRateLimitType {} /** Refresh rate should be limited when High Brightness Mode is active. */ public static final int REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE = 1; /** * Called by the power manager to initialize power management facilities. */ Loading Loading @@ -296,9 +310,10 @@ public abstract class DisplayManagerInternal { public abstract int getRefreshRateSwitchingType(); /** * TODO: b/191384041 - Replace this with getRefreshRateLimitations() * Return the refresh rate restriction for the specified display and sensor pairing. If the * specified sensor is identified as an associated sensor in the specified display's * display-device-config file, then return any refresh rate restrictions that it might specify. * display-device-config file, then return any refresh rate restrictions that it might define. * If no restriction is specified, or the sensor is not associated with the display, then null * will be returned. * Loading @@ -312,6 +327,15 @@ public abstract class DisplayManagerInternal { public abstract RefreshRateRange getRefreshRateForDisplayAndSensor( int displayId, String name, String type); /** * Returns a list of various refresh rate limitations for the specified display. * * @param displayId The display to get limitations for. * * @return a list of {@link RefreshRateLimitation}s describing the various limits. */ public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId); /** * Describes the requested power state of the display. * Loading Loading @@ -613,4 +637,25 @@ public abstract class DisplayManagerInternal { return "(" + min + " " + max + ")"; } } /** * Describes a limitation on a display's refresh rate. Includes the allowed refresh rate * range as well as information about when it applies, such as high-brightness-mode. */ public static final class RefreshRateLimitation { @RefreshRateLimitType public int type; /** The range the that refresh rate should be limited to. */ public RefreshRateRange range; public RefreshRateLimitation(@RefreshRateLimitType int type, float min, float max) { this.type = type; range = new RefreshRateRange(min, max); } @Override public String toString() { return "RefreshRateLimitation(" + type + ": " + range + ")"; } } } services/core/java/com/android/server/display/DisplayDeviceConfig.java +17 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.display; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.os.Environment; import android.os.PowerManager; import android.text.TextUtils; Loading Loading @@ -86,6 +88,9 @@ public class DisplayDeviceConfig { // The details of the proximity sensor associated with this display. private final SensorData mProximitySensor = new SensorData(); private final List<RefreshRateLimitation> mRefreshRateLimitations = new ArrayList<>(2 /*initialCapacity*/); // Nits and backlight values that are loaded from either the display device config file, or // config.xml. These are the raw values and just used for the dumpsys private float[] mRawNits; Loading Loading @@ -306,6 +311,10 @@ public class DisplayDeviceConfig { return hbmData; } public List<RefreshRateLimitation> getRefreshRateLimitations() { return mRefreshRateLimitations; } @Override public String toString() { String str = "DisplayDeviceConfig{" Loading @@ -329,6 +338,7 @@ public class DisplayDeviceConfig { + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease + ", mAmbientLightSensor=" + mAmbientLightSensor + ", mProximitySensor=" + mProximitySensor + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) + "}"; return str; } Loading Loading @@ -647,6 +657,13 @@ public class DisplayDeviceConfig { mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000; mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000; mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000; final RefreshRateRange rr = hbm.getRefreshRate_all(); if (rr != null) { final float min = rr.getMinimum().floatValue(); final float max = rr.getMaximum().floatValue(); mRefreshRateLimitations.add(new RefreshRateLimitation( DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max)); } } } Loading services/core/java/com/android/server/display/DisplayManagerService.java +20 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayGroupListener; import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.display.DisplayViewport; import android.hardware.display.DisplayedContentSample; Loading Loading @@ -130,6 +131,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; Loading Loading @@ -2111,6 +2113,11 @@ public final class DisplayManagerService extends SystemService { DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED); } private DisplayDevice getDeviceForDisplayLocked(int displayId) { final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId); return display == null ? null : display.getPrimaryDisplayDeviceLocked(); } private final class DisplayManagerHandler extends Handler { public DisplayManagerHandler(Looper looper) { super(looper, null, true /*async*/); Loading Loading @@ -3295,6 +3302,19 @@ public final class DisplayManagerService extends SystemService { } return null; } @Override public List<RefreshRateLimitation> getRefreshRateLimitations(int displayId) { final DisplayDeviceConfig config; synchronized (mSyncRoot) { final DisplayDevice device = getDeviceForDisplayLocked(displayId); if (device == null) { return null; } config = device.getDisplayDeviceConfig(); } return config.getRefreshRateLimitations(); } } class DesiredDisplayModeSpecsObserver Loading services/core/java/com/android/server/display/DisplayModeDirector.java +133 −18 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.display; import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; Loading @@ -26,8 +28,10 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.net.Uri; Loading Loading @@ -102,6 +106,7 @@ public class DisplayModeDirector { private final DisplayObserver mDisplayObserver; private final UdfpsObserver mUdfpsObserver; private final SensorObserver mSensorObserver; private final HbmObserver mHbmObserver; private final DeviceConfigInterface mDeviceConfig; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; Loading @@ -127,7 +132,7 @@ public class DisplayModeDirector { private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { this(context, handler, new RealInjector()); this(context, handler, new RealInjector(context)); } public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, Loading @@ -143,11 +148,13 @@ public class DisplayModeDirector { mDisplayObserver = new DisplayObserver(context, handler); mBrightnessObserver = new BrightnessObserver(context, handler); mUdfpsObserver = new UdfpsObserver(); mSensorObserver = new SensorObserver(context, (displayId, priority, vote) -> { final BallotBox ballotBox = (displayId, priority, vote) -> { synchronized (mLock) { updateVoteLocked(displayId, priority, vote); } }); }; mSensorObserver = new SensorObserver(context, ballotBox); mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler()); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mDeviceConfig = injector.getDeviceConfig(); mAlwaysRespectAppRequest = false; Loading @@ -165,6 +172,7 @@ public class DisplayModeDirector { mDisplayObserver.observe(); mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); synchronized (mLock) { // We may have a listener already registered before the call to start, so go ahead and // notify them to pick up our newly initialized state. Loading Loading @@ -596,6 +604,7 @@ public class DisplayModeDirector { mBrightnessObserver.dumpLocked(pw); mUdfpsObserver.dumpLocked(pw); mSensorObserver.dumpLocked(pw); mHbmObserver.dumpLocked(pw); } } Loading Loading @@ -938,13 +947,16 @@ public class DisplayModeDirector { // user seeing the display flickering when the switches occur. public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8; // High-brightness-mode may need a specific range of refresh-rates to function properly. public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9; // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. public static final int PRIORITY_PROXIMITY = 9; public static final int PRIORITY_PROXIMITY = 10; // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order // to function, so this needs to be the highest priority of all votes. public static final int PRIORITY_UDFPS = 10; public static final int PRIORITY_UDFPS = 11; // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString. Loading Loading @@ -1021,29 +1033,30 @@ public class DisplayModeDirector { public static String priorityToString(int priority) { switch (priority) { case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE"; case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE: return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_DEFAULT_REFRESH_RATE: return "PRIORITY_DEFAULT_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE: return "PRIORITY_FLICKER_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE_SWITCH: return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE: return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE"; case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; case PRIORITY_HIGH_BRIGHTNESS_MODE: return "PRIORITY_HIGH_BRIGHTNESS_MODE"; case PRIORITY_PROXIMITY: return "PRIORITY_PROXIMITY"; case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; case PRIORITY_UDFPS: return "PRIORITY_UDFPS"; case PRIORITY_PROXIMITY: return "PRIORITY_PROXIMITY"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; default: return Integer.toString(priority); } Loading Loading @@ -2155,6 +2168,75 @@ public class DisplayModeDirector { } } /** * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for * HBM that are associated with that display. Restrictions are retrieved from * DisplayManagerInternal but originate in the display-device-config file. */ private static class HbmObserver implements DisplayManager.DisplayListener { private final BallotBox mBallotBox; private final Handler mHandler; private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray(); private final Injector mInjector; private DisplayManagerInternal mDisplayManagerInternal; HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) { mInjector = injector; mBallotBox = ballotBox; mHandler = handler; } public void observe() { mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInjector.registerDisplayListener(this, mHandler, DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); } @Override public void onDisplayAdded(int displayId) {} @Override public void onDisplayRemoved(int displayId) { mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); } @Override public void onDisplayChanged(int displayId) { final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); if (info == null) { // Display no longer there. Assume we'll get an onDisplayRemoved very soon. return; } final boolean isHbmEnabled = info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; if (isHbmEnabled == mHbmEnabled.get(displayId)) { // no change, ignore. return; } Vote vote = null; mHbmEnabled.put(displayId, isHbmEnabled); if (isHbmEnabled) { final List<RefreshRateLimitation> limits = mDisplayManagerInternal.getRefreshRateLimitations(displayId); for (int i = 0; limits != null && i < limits.size(); i++) { final RefreshRateLimitation limitation = limits.get(i); if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max); break; } } } mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); } void dumpLocked(PrintWriter pw) { pw.println(" HbmObserver"); pw.println(" mHbmEnabled: " + mHbmEnabled); } } private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { } Loading Loading @@ -2309,10 +2391,21 @@ public class DisplayModeDirector { void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer); void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, Handler handler, long flags); BrightnessInfo getBrightnessInfo(int displayId); } @VisibleForTesting static class RealInjector implements Injector { private final Context mContext; private DisplayManager mDisplayManager; RealInjector(Context context) { mContext = context; } @Override @NonNull Loading @@ -2339,6 +2432,28 @@ public class DisplayModeDirector { cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, observer, UserHandle.USER_SYSTEM); } @Override public void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler, long flags) { getDisplayManager().registerDisplayListener(listener, handler, flags); } @Override public BrightnessInfo getBrightnessInfo(int displayId) { final Display display = getDisplayManager().getDisplay(displayId); if (display != null) { return display.getBrightnessInfo(); } return null; } private DisplayManager getDisplayManager() { if (mDisplayManager == null) { mDisplayManager = mContext.getSystemService(DisplayManager.class); } return mDisplayManager; } } interface BallotBox { Loading services/core/xsd/display-device-config/display-device-config.xsd +4 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,10 @@ <xs:annotation name="final"/> </xs:element> <xs:element name="timing" type="hbmTiming" minOccurs="1" maxOccurs="1"/> <xs:element type="refreshRateRange" name="refreshRate" minOccurs="0" maxOccurs="1"> <xs:annotation name="nullable"/> <xs:annotation name="final"/> </xs:element> </xs:all> <xs:attribute name="enabled" type="xs:boolean" use="optional"/> </xs:complexType> Loading Loading
core/java/android/hardware/display/DisplayManagerInternal.java +46 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.hardware.display; import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Point; import android.hardware.SensorManager; Loading @@ -29,6 +30,9 @@ import android.view.DisplayInfo; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Objects; /** Loading @@ -37,6 +41,16 @@ import java.util.Objects; * @hide Only for use within the system server. */ public abstract class DisplayManagerInternal { @IntDef(prefix = {"REFRESH_RATE_LIMIT_"}, value = { REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE }) @Retention(RetentionPolicy.SOURCE) public @interface RefreshRateLimitType {} /** Refresh rate should be limited when High Brightness Mode is active. */ public static final int REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE = 1; /** * Called by the power manager to initialize power management facilities. */ Loading Loading @@ -296,9 +310,10 @@ public abstract class DisplayManagerInternal { public abstract int getRefreshRateSwitchingType(); /** * TODO: b/191384041 - Replace this with getRefreshRateLimitations() * Return the refresh rate restriction for the specified display and sensor pairing. If the * specified sensor is identified as an associated sensor in the specified display's * display-device-config file, then return any refresh rate restrictions that it might specify. * display-device-config file, then return any refresh rate restrictions that it might define. * If no restriction is specified, or the sensor is not associated with the display, then null * will be returned. * Loading @@ -312,6 +327,15 @@ public abstract class DisplayManagerInternal { public abstract RefreshRateRange getRefreshRateForDisplayAndSensor( int displayId, String name, String type); /** * Returns a list of various refresh rate limitations for the specified display. * * @param displayId The display to get limitations for. * * @return a list of {@link RefreshRateLimitation}s describing the various limits. */ public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId); /** * Describes the requested power state of the display. * Loading Loading @@ -613,4 +637,25 @@ public abstract class DisplayManagerInternal { return "(" + min + " " + max + ")"; } } /** * Describes a limitation on a display's refresh rate. Includes the allowed refresh rate * range as well as information about when it applies, such as high-brightness-mode. */ public static final class RefreshRateLimitation { @RefreshRateLimitType public int type; /** The range the that refresh rate should be limited to. */ public RefreshRateRange range; public RefreshRateLimitation(@RefreshRateLimitType int type, float min, float max) { this.type = type; range = new RefreshRateRange(min, max); } @Override public String toString() { return "RefreshRateLimitation(" + type + ": " + range + ")"; } } }
services/core/java/com/android/server/display/DisplayDeviceConfig.java +17 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.display; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.os.Environment; import android.os.PowerManager; import android.text.TextUtils; Loading Loading @@ -86,6 +88,9 @@ public class DisplayDeviceConfig { // The details of the proximity sensor associated with this display. private final SensorData mProximitySensor = new SensorData(); private final List<RefreshRateLimitation> mRefreshRateLimitations = new ArrayList<>(2 /*initialCapacity*/); // Nits and backlight values that are loaded from either the display device config file, or // config.xml. These are the raw values and just used for the dumpsys private float[] mRawNits; Loading Loading @@ -306,6 +311,10 @@ public class DisplayDeviceConfig { return hbmData; } public List<RefreshRateLimitation> getRefreshRateLimitations() { return mRefreshRateLimitations; } @Override public String toString() { String str = "DisplayDeviceConfig{" Loading @@ -329,6 +338,7 @@ public class DisplayDeviceConfig { + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease + ", mAmbientLightSensor=" + mAmbientLightSensor + ", mProximitySensor=" + mProximitySensor + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) + "}"; return str; } Loading Loading @@ -647,6 +657,13 @@ public class DisplayDeviceConfig { mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000; mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000; mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000; final RefreshRateRange rr = hbm.getRefreshRate_all(); if (rr != null) { final float min = rr.getMinimum().floatValue(); final float max = rr.getMaximum().floatValue(); mRefreshRateLimitations.add(new RefreshRateLimitation( DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max)); } } } Loading
services/core/java/com/android/server/display/DisplayManagerService.java +20 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayGroupListener; import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.display.DisplayViewport; import android.hardware.display.DisplayedContentSample; Loading Loading @@ -130,6 +131,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; Loading Loading @@ -2111,6 +2113,11 @@ public final class DisplayManagerService extends SystemService { DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED); } private DisplayDevice getDeviceForDisplayLocked(int displayId) { final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId); return display == null ? null : display.getPrimaryDisplayDeviceLocked(); } private final class DisplayManagerHandler extends Handler { public DisplayManagerHandler(Looper looper) { super(looper, null, true /*async*/); Loading Loading @@ -3295,6 +3302,19 @@ public final class DisplayManagerService extends SystemService { } return null; } @Override public List<RefreshRateLimitation> getRefreshRateLimitations(int displayId) { final DisplayDeviceConfig config; synchronized (mSyncRoot) { final DisplayDevice device = getDeviceForDisplayLocked(displayId); if (device == null) { return null; } config = device.getDisplayDeviceConfig(); } return config.getRefreshRateLimitations(); } } class DesiredDisplayModeSpecsObserver Loading
services/core/java/com/android/server/display/DisplayModeDirector.java +133 −18 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.display; import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; Loading @@ -26,8 +28,10 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.net.Uri; Loading Loading @@ -102,6 +106,7 @@ public class DisplayModeDirector { private final DisplayObserver mDisplayObserver; private final UdfpsObserver mUdfpsObserver; private final SensorObserver mSensorObserver; private final HbmObserver mHbmObserver; private final DeviceConfigInterface mDeviceConfig; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; Loading @@ -127,7 +132,7 @@ public class DisplayModeDirector { private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { this(context, handler, new RealInjector()); this(context, handler, new RealInjector(context)); } public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, Loading @@ -143,11 +148,13 @@ public class DisplayModeDirector { mDisplayObserver = new DisplayObserver(context, handler); mBrightnessObserver = new BrightnessObserver(context, handler); mUdfpsObserver = new UdfpsObserver(); mSensorObserver = new SensorObserver(context, (displayId, priority, vote) -> { final BallotBox ballotBox = (displayId, priority, vote) -> { synchronized (mLock) { updateVoteLocked(displayId, priority, vote); } }); }; mSensorObserver = new SensorObserver(context, ballotBox); mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler()); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mDeviceConfig = injector.getDeviceConfig(); mAlwaysRespectAppRequest = false; Loading @@ -165,6 +172,7 @@ public class DisplayModeDirector { mDisplayObserver.observe(); mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); synchronized (mLock) { // We may have a listener already registered before the call to start, so go ahead and // notify them to pick up our newly initialized state. Loading Loading @@ -596,6 +604,7 @@ public class DisplayModeDirector { mBrightnessObserver.dumpLocked(pw); mUdfpsObserver.dumpLocked(pw); mSensorObserver.dumpLocked(pw); mHbmObserver.dumpLocked(pw); } } Loading Loading @@ -938,13 +947,16 @@ public class DisplayModeDirector { // user seeing the display flickering when the switches occur. public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8; // High-brightness-mode may need a specific range of refresh-rates to function properly. public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9; // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. public static final int PRIORITY_PROXIMITY = 9; public static final int PRIORITY_PROXIMITY = 10; // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order // to function, so this needs to be the highest priority of all votes. public static final int PRIORITY_UDFPS = 10; public static final int PRIORITY_UDFPS = 11; // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString. Loading Loading @@ -1021,29 +1033,30 @@ public class DisplayModeDirector { public static String priorityToString(int priority) { switch (priority) { case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE"; case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE: return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_DEFAULT_REFRESH_RATE: return "PRIORITY_DEFAULT_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE: return "PRIORITY_FLICKER_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE_SWITCH: return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE: return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE"; case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; case PRIORITY_HIGH_BRIGHTNESS_MODE: return "PRIORITY_HIGH_BRIGHTNESS_MODE"; case PRIORITY_PROXIMITY: return "PRIORITY_PROXIMITY"; case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; case PRIORITY_UDFPS: return "PRIORITY_UDFPS"; case PRIORITY_PROXIMITY: return "PRIORITY_PROXIMITY"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; default: return Integer.toString(priority); } Loading Loading @@ -2155,6 +2168,75 @@ public class DisplayModeDirector { } } /** * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for * HBM that are associated with that display. Restrictions are retrieved from * DisplayManagerInternal but originate in the display-device-config file. */ private static class HbmObserver implements DisplayManager.DisplayListener { private final BallotBox mBallotBox; private final Handler mHandler; private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray(); private final Injector mInjector; private DisplayManagerInternal mDisplayManagerInternal; HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) { mInjector = injector; mBallotBox = ballotBox; mHandler = handler; } public void observe() { mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInjector.registerDisplayListener(this, mHandler, DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); } @Override public void onDisplayAdded(int displayId) {} @Override public void onDisplayRemoved(int displayId) { mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); } @Override public void onDisplayChanged(int displayId) { final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); if (info == null) { // Display no longer there. Assume we'll get an onDisplayRemoved very soon. return; } final boolean isHbmEnabled = info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; if (isHbmEnabled == mHbmEnabled.get(displayId)) { // no change, ignore. return; } Vote vote = null; mHbmEnabled.put(displayId, isHbmEnabled); if (isHbmEnabled) { final List<RefreshRateLimitation> limits = mDisplayManagerInternal.getRefreshRateLimitations(displayId); for (int i = 0; limits != null && i < limits.size(); i++) { final RefreshRateLimitation limitation = limits.get(i); if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max); break; } } } mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); } void dumpLocked(PrintWriter pw) { pw.println(" HbmObserver"); pw.println(" mHbmEnabled: " + mHbmEnabled); } } private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { } Loading Loading @@ -2309,10 +2391,21 @@ public class DisplayModeDirector { void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer); void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, Handler handler, long flags); BrightnessInfo getBrightnessInfo(int displayId); } @VisibleForTesting static class RealInjector implements Injector { private final Context mContext; private DisplayManager mDisplayManager; RealInjector(Context context) { mContext = context; } @Override @NonNull Loading @@ -2339,6 +2432,28 @@ public class DisplayModeDirector { cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, observer, UserHandle.USER_SYSTEM); } @Override public void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler, long flags) { getDisplayManager().registerDisplayListener(listener, handler, flags); } @Override public BrightnessInfo getBrightnessInfo(int displayId) { final Display display = getDisplayManager().getDisplay(displayId); if (display != null) { return display.getBrightnessInfo(); } return null; } private DisplayManager getDisplayManager() { if (mDisplayManager == null) { mDisplayManager = mContext.getSystemService(DisplayManager.class); } return mDisplayManager; } } interface BallotBox { Loading
services/core/xsd/display-device-config/display-device-config.xsd +4 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,10 @@ <xs:annotation name="final"/> </xs:element> <xs:element name="timing" type="hbmTiming" minOccurs="1" maxOccurs="1"/> <xs:element type="refreshRateRange" name="refreshRate" minOccurs="0" maxOccurs="1"> <xs:annotation name="nullable"/> <xs:annotation name="final"/> </xs:element> </xs:all> <xs:attribute name="enabled" type="xs:boolean" use="optional"/> </xs:complexType> Loading