Loading core/java/com/android/internal/display/RefreshRateSettingsUtils.java +2 −1 Original line number Diff line number Diff line Loading @@ -33,13 +33,14 @@ public class RefreshRateSettingsUtils { /** * Find the highest refresh rate among all the modes of the default display. * * This method will acquire DisplayManager.mLock, so calling it while holding other locks * should be done with care. * @param context The context * @return The highest refresh rate */ public static float findHighestRefreshRateForDefaultDisplay(Context context) { final DisplayManager dm = context.getSystemService(DisplayManager.class); final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (display == null) { Log.w(TAG, "No valid default display device"); return DEFAULT_REFRESH_RATE; Loading services/core/java/com/android/server/display/mode/DisplayModeDirector.java +54 −17 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT; import static android.view.Display.Mode.INVALID_MODE_ID; import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE; import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.annotation.IntegerRes; import android.annotation.NonNull; Loading Loading @@ -238,8 +237,11 @@ public class DisplayModeDirector { * is ready. */ public void start(SensorManager sensorManager) { mSettingsObserver.observe(); // This has to be called first to read the supported display modes that will be used by // other observers mDisplayObserver.observe(); mSettingsObserver.observe(); mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); Loading Loading @@ -619,12 +621,17 @@ public class DisplayModeDirector { return mHbmObserver; } @VisibleForTesting DisplayObserver getDisplayObserver() { return mDisplayObserver; } @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { synchronized (mLock) { mSettingsObserver.updateRefreshRateSettingLocked( minRefreshRate, peakRefreshRate, defaultRefreshRate); mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, defaultRefreshRate, Display.DEFAULT_DISPLAY); return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY); } } Loading Loading @@ -897,19 +904,17 @@ public class DisplayModeDirector { if (defaultPeakRefreshRate == null) { setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig, /* attemptReadFromFeatureParams= */ false); updateRefreshRateSettingLocked(); } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { mDefaultPeakRefreshRate = defaultPeakRefreshRate; updateRefreshRateSettingLocked(); } updateRefreshRateSettingLocked(); } } @Override public void onChange(boolean selfChange, Uri uri, int userId) { synchronized (mLock) { if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) { if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) { updateRefreshRateSettingLocked(); } else if (mLowPowerModeSetting.equals(uri)) { updateLowPowerModeSettingLocked(); Loading Loading @@ -969,9 +974,29 @@ public class DisplayModeDirector { mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode); } /** * Update refresh rate settings for all displays */ @GuardedBy("mLock") private void updateRefreshRateSettingLocked() { for (int i = 0; i < mSupportedModesByDisplay.size(); i++) { updateRefreshRateSettingLocked(mSupportedModesByDisplay.keyAt(i)); } } /** * Update refresh rate settings for a specific display * @param displayId The display ID */ @GuardedBy("mLock") private void updateRefreshRateSettingLocked(int displayId) { final ContentResolver cr = mContext.getContentResolver(); float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext); if (!mSupportedModesByDisplay.contains(displayId)) { Slog.e(TAG, "Cannot update refresh rate setting: no supported modes for display " + displayId); return; } float highestRefreshRate = getMaxRefreshRateLocked(displayId); float minRefreshRate = Settings.System.getFloatForUser(cr, Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId()); Loading Loading @@ -1009,11 +1034,13 @@ public class DisplayModeDirector { Float.POSITIVE_INFINITY, cr.getUserId()); } updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate); updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate, displayId); } private void updateRefreshRateSettingLocked( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { @GuardedBy("mLock") private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, float defaultRefreshRate, int displayId) { // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is // used to predict if we're going to be doing frequent refresh rate switching, and if // so, enable the brightness observer. The logic here is more complicated and fragile Loading @@ -1021,9 +1048,9 @@ public class DisplayModeDirector { Vote peakVote = peakRefreshRate == 0f ? null : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate)); mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, peakVote); mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY)); Vote defaultVote = defaultRefreshRate == 0f Loading @@ -1050,6 +1077,14 @@ public class DisplayModeDirector { mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, maxRefreshRate); } private void removeRefreshRateSetting(int displayId) { mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, null); } private void updateModeSwitchingTypeSettingLocked() { final ContentResolver cr = mContext.getContentResolver(); int switchingType = Settings.Secure.getIntForUser( Loading Loading @@ -1180,7 +1215,8 @@ public class DisplayModeDirector { } } private final class DisplayObserver implements DisplayManager.DisplayListener { @VisibleForTesting public final class DisplayObserver implements DisplayManager.DisplayListener { // Note that we can never call into DisplayManager or any of the non-POD classes it // returns, while holding mLock since it may call into DMS, which might be simultaneously // calling into us already holding its own lock. Loading Loading @@ -1227,11 +1263,10 @@ public class DisplayModeDirector { // Populate existing displays SparseArray<Display.Mode[]> modes = new SparseArray<>(); SparseArray<Display.Mode> defaultModes = new SparseArray<>(); DisplayInfo info = new DisplayInfo(); Display[] displays = mInjector.getDisplays(); for (Display d : displays) { final int displayId = d.getDisplayId(); d.getDisplayInfo(info); DisplayInfo info = getDisplayInfo(displayId); modes.put(displayId, info.supportedModes); defaultModes.put(displayId, info.getDefaultMode()); } Loading Loading @@ -1259,6 +1294,7 @@ public class DisplayModeDirector { synchronized (mLock) { mSupportedModesByDisplay.remove(displayId); mDefaultModeByDisplay.remove(displayId); mSettingsObserver.removeRefreshRateSetting(displayId); } updateLayoutLimitedFrameRate(displayId, null); removeUserSettingDisplayPreferredSize(displayId); Loading Loading @@ -1409,6 +1445,7 @@ public class DisplayModeDirector { } if (changed) { notifyDesiredDisplayModeSpecsChangedLocked(); mSettingsObserver.updateRefreshRateSettingLocked(displayId); } } } Loading services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java +8 −4 Original line number Diff line number Diff line Loading @@ -72,14 +72,18 @@ public class RefreshRateSettingsUtilsTest { @Test public void testFindHighestRefreshRateForDefaultDisplay() { when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); assertEquals(DEFAULT_REFRESH_RATE, when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); assertEquals(120, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); } when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); assertEquals(120, @Test public void testFindHighestRefreshRate_DisplayIsNull() { when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); assertEquals(DEFAULT_REFRESH_RATE, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); } } services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +130 −24 Original line number Diff line number Diff line Loading @@ -27,8 +27,6 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; Loading Loading @@ -290,6 +288,7 @@ public class DisplayModeDirectorTest { }; private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY; private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1; private static final int MODE_ID = 1; private static final float TRANSITION_POINT = 0.763f; Loading Loading @@ -1550,23 +1549,39 @@ public class DisplayModeDirectorTest { public void testPeakRefreshRate_FlagEnabled() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); float highestRefreshRate = 130; doReturn(highestRefreshRate).when(() -> RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); Display.Mode[] modes1 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Display.Mode[] modes2 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); supportedModesByDisplay.put(DISPLAY_ID, modes1); supportedModesByDisplay.put(DISPLAY_ID_2, modes2); Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); director.injectSupportedModesByDisplay(supportedModesByDisplay); setPeakRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ highestRefreshRate); Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0, /* frameRateHigh= */ 130); assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0, /* frameRateHigh= */ 140); } @Test Loading @@ -1584,32 +1599,85 @@ public class DisplayModeDirectorTest { setPeakRefreshRate(peakRefreshRate); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ peakRefreshRate); } @Test public void testPeakRefreshRate_DisplayChanged() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); setPeakRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ peakRefreshRate); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 130); // The highest refresh rate of the display changes mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; director.getDisplayObserver().onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 140); } @Test public void testMinRefreshRate_FlagEnabled() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); float highestRefreshRate = 130; doReturn(highestRefreshRate).when(() -> RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); Display.Mode[] modes1 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Display.Mode[] modes2 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); supportedModesByDisplay.put(DISPLAY_ID, modes1); supportedModesByDisplay.put(DISPLAY_ID_2, modes2); Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); director.injectSupportedModesByDisplay(supportedModesByDisplay); setMinRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate, assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 130, /* frameRateHigh= */ Float.POSITIVE_INFINITY); assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 140, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } Loading @@ -1628,12 +1696,49 @@ public class DisplayModeDirectorTest { setMinRefreshRate(minRefreshRate); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } @Test public void testMinRefreshRate_DisplayChanged() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); setMinRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 130, /* frameRateHigh= */ Float.POSITIVE_INFINITY); // The highest refresh rate of the display changes mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; director.getDisplayObserver().onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 140, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } @Test public void testSensorRegistration() { // First, configure brightness zones or DMD won't register for sensor data. Loading Loading @@ -3329,7 +3434,7 @@ public class DisplayModeDirectorTest { public static class FakesInjector implements DisplayModeDirector.Injector { private final FakeDeviceConfig mDeviceConfig; private final DisplayInfo mDisplayInfo; private final Display mDisplay; private final Map<Integer, Display> mDisplays; private boolean mDisplayInfoValid = true; private final DisplayManagerInternal mDisplayManagerInternal; private final StatusBarManagerInternal mStatusBarManagerInternal; Loading @@ -3350,7 +3455,8 @@ public class DisplayModeDirectorTest { mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, 800, 600, /* refreshRate= */ 60)}; mDisplay = createDisplay(DISPLAY_ID); mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID), DISPLAY_ID_2, createDisplay(DISPLAY_ID_2)); mDisplayManagerInternal = displayManagerInternal; mStatusBarManagerInternal = statusBarManagerInternal; mSensorManagerInternal = sensorManagerInternal; Loading Loading @@ -3381,12 +3487,12 @@ public class DisplayModeDirectorTest { @Override public Display getDisplay(int displayId) { return mDisplay; return mDisplays.get(displayId); } @Override public Display[] getDisplays() { return new Display[] { mDisplay }; return mDisplays.values().toArray(new Display[0]); } @Override Loading Loading
core/java/com/android/internal/display/RefreshRateSettingsUtils.java +2 −1 Original line number Diff line number Diff line Loading @@ -33,13 +33,14 @@ public class RefreshRateSettingsUtils { /** * Find the highest refresh rate among all the modes of the default display. * * This method will acquire DisplayManager.mLock, so calling it while holding other locks * should be done with care. * @param context The context * @return The highest refresh rate */ public static float findHighestRefreshRateForDefaultDisplay(Context context) { final DisplayManager dm = context.getSystemService(DisplayManager.class); final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (display == null) { Log.w(TAG, "No valid default display device"); return DEFAULT_REFRESH_RATE; Loading
services/core/java/com/android/server/display/mode/DisplayModeDirector.java +54 −17 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT; import static android.view.Display.Mode.INVALID_MODE_ID; import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE; import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.annotation.IntegerRes; import android.annotation.NonNull; Loading Loading @@ -238,8 +237,11 @@ public class DisplayModeDirector { * is ready. */ public void start(SensorManager sensorManager) { mSettingsObserver.observe(); // This has to be called first to read the supported display modes that will be used by // other observers mDisplayObserver.observe(); mSettingsObserver.observe(); mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); Loading Loading @@ -619,12 +621,17 @@ public class DisplayModeDirector { return mHbmObserver; } @VisibleForTesting DisplayObserver getDisplayObserver() { return mDisplayObserver; } @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { synchronized (mLock) { mSettingsObserver.updateRefreshRateSettingLocked( minRefreshRate, peakRefreshRate, defaultRefreshRate); mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, defaultRefreshRate, Display.DEFAULT_DISPLAY); return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY); } } Loading Loading @@ -897,19 +904,17 @@ public class DisplayModeDirector { if (defaultPeakRefreshRate == null) { setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig, /* attemptReadFromFeatureParams= */ false); updateRefreshRateSettingLocked(); } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { mDefaultPeakRefreshRate = defaultPeakRefreshRate; updateRefreshRateSettingLocked(); } updateRefreshRateSettingLocked(); } } @Override public void onChange(boolean selfChange, Uri uri, int userId) { synchronized (mLock) { if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) { if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) { updateRefreshRateSettingLocked(); } else if (mLowPowerModeSetting.equals(uri)) { updateLowPowerModeSettingLocked(); Loading Loading @@ -969,9 +974,29 @@ public class DisplayModeDirector { mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode); } /** * Update refresh rate settings for all displays */ @GuardedBy("mLock") private void updateRefreshRateSettingLocked() { for (int i = 0; i < mSupportedModesByDisplay.size(); i++) { updateRefreshRateSettingLocked(mSupportedModesByDisplay.keyAt(i)); } } /** * Update refresh rate settings for a specific display * @param displayId The display ID */ @GuardedBy("mLock") private void updateRefreshRateSettingLocked(int displayId) { final ContentResolver cr = mContext.getContentResolver(); float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext); if (!mSupportedModesByDisplay.contains(displayId)) { Slog.e(TAG, "Cannot update refresh rate setting: no supported modes for display " + displayId); return; } float highestRefreshRate = getMaxRefreshRateLocked(displayId); float minRefreshRate = Settings.System.getFloatForUser(cr, Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId()); Loading Loading @@ -1009,11 +1034,13 @@ public class DisplayModeDirector { Float.POSITIVE_INFINITY, cr.getUserId()); } updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate); updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate, displayId); } private void updateRefreshRateSettingLocked( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { @GuardedBy("mLock") private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, float defaultRefreshRate, int displayId) { // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is // used to predict if we're going to be doing frequent refresh rate switching, and if // so, enable the brightness observer. The logic here is more complicated and fragile Loading @@ -1021,9 +1048,9 @@ public class DisplayModeDirector { Vote peakVote = peakRefreshRate == 0f ? null : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate)); mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, peakVote); mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY)); Vote defaultVote = defaultRefreshRate == 0f Loading @@ -1050,6 +1077,14 @@ public class DisplayModeDirector { mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, maxRefreshRate); } private void removeRefreshRateSetting(int displayId) { mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, null); } private void updateModeSwitchingTypeSettingLocked() { final ContentResolver cr = mContext.getContentResolver(); int switchingType = Settings.Secure.getIntForUser( Loading Loading @@ -1180,7 +1215,8 @@ public class DisplayModeDirector { } } private final class DisplayObserver implements DisplayManager.DisplayListener { @VisibleForTesting public final class DisplayObserver implements DisplayManager.DisplayListener { // Note that we can never call into DisplayManager or any of the non-POD classes it // returns, while holding mLock since it may call into DMS, which might be simultaneously // calling into us already holding its own lock. Loading Loading @@ -1227,11 +1263,10 @@ public class DisplayModeDirector { // Populate existing displays SparseArray<Display.Mode[]> modes = new SparseArray<>(); SparseArray<Display.Mode> defaultModes = new SparseArray<>(); DisplayInfo info = new DisplayInfo(); Display[] displays = mInjector.getDisplays(); for (Display d : displays) { final int displayId = d.getDisplayId(); d.getDisplayInfo(info); DisplayInfo info = getDisplayInfo(displayId); modes.put(displayId, info.supportedModes); defaultModes.put(displayId, info.getDefaultMode()); } Loading Loading @@ -1259,6 +1294,7 @@ public class DisplayModeDirector { synchronized (mLock) { mSupportedModesByDisplay.remove(displayId); mDefaultModeByDisplay.remove(displayId); mSettingsObserver.removeRefreshRateSetting(displayId); } updateLayoutLimitedFrameRate(displayId, null); removeUserSettingDisplayPreferredSize(displayId); Loading Loading @@ -1409,6 +1445,7 @@ public class DisplayModeDirector { } if (changed) { notifyDesiredDisplayModeSpecsChangedLocked(); mSettingsObserver.updateRefreshRateSettingLocked(displayId); } } } Loading
services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java +8 −4 Original line number Diff line number Diff line Loading @@ -72,14 +72,18 @@ public class RefreshRateSettingsUtilsTest { @Test public void testFindHighestRefreshRateForDefaultDisplay() { when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); assertEquals(DEFAULT_REFRESH_RATE, when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); assertEquals(120, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); } when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); assertEquals(120, @Test public void testFindHighestRefreshRate_DisplayIsNull() { when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); assertEquals(DEFAULT_REFRESH_RATE, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); } }
services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +130 −24 Original line number Diff line number Diff line Loading @@ -27,8 +27,6 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; Loading Loading @@ -290,6 +288,7 @@ public class DisplayModeDirectorTest { }; private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY; private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1; private static final int MODE_ID = 1; private static final float TRANSITION_POINT = 0.763f; Loading Loading @@ -1550,23 +1549,39 @@ public class DisplayModeDirectorTest { public void testPeakRefreshRate_FlagEnabled() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); float highestRefreshRate = 130; doReturn(highestRefreshRate).when(() -> RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); Display.Mode[] modes1 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Display.Mode[] modes2 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); supportedModesByDisplay.put(DISPLAY_ID, modes1); supportedModesByDisplay.put(DISPLAY_ID_2, modes2); Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); director.injectSupportedModesByDisplay(supportedModesByDisplay); setPeakRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ highestRefreshRate); Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0, /* frameRateHigh= */ 130); assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0, /* frameRateHigh= */ 140); } @Test Loading @@ -1584,32 +1599,85 @@ public class DisplayModeDirectorTest { setPeakRefreshRate(peakRefreshRate); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ peakRefreshRate); } @Test public void testPeakRefreshRate_DisplayChanged() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); setPeakRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ peakRefreshRate); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 130); // The highest refresh rate of the display changes mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; director.getDisplayObserver().onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 140); } @Test public void testMinRefreshRate_FlagEnabled() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); float highestRefreshRate = 130; doReturn(highestRefreshRate).when(() -> RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); Display.Mode[] modes1 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Display.Mode[] modes2 = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); supportedModesByDisplay.put(DISPLAY_ID, modes1); supportedModesByDisplay.put(DISPLAY_ID_2, modes2); Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); director.injectSupportedModesByDisplay(supportedModesByDisplay); setMinRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate, assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 130, /* frameRateHigh= */ Float.POSITIVE_INFINITY); assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 140, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } Loading @@ -1628,12 +1696,49 @@ public class DisplayModeDirectorTest { setMinRefreshRate(minRefreshRate); Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } @Test public void testMinRefreshRate_DisplayChanged() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 130), }; Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); setMinRefreshRate(Float.POSITIVE_INFINITY); Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 130, /* frameRateHigh= */ Float.POSITIVE_INFINITY); // The highest refresh rate of the display changes mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 60), new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, /* refreshRate= */ 140), }; director.getDisplayObserver().onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 140, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } @Test public void testSensorRegistration() { // First, configure brightness zones or DMD won't register for sensor data. Loading Loading @@ -3329,7 +3434,7 @@ public class DisplayModeDirectorTest { public static class FakesInjector implements DisplayModeDirector.Injector { private final FakeDeviceConfig mDeviceConfig; private final DisplayInfo mDisplayInfo; private final Display mDisplay; private final Map<Integer, Display> mDisplays; private boolean mDisplayInfoValid = true; private final DisplayManagerInternal mDisplayManagerInternal; private final StatusBarManagerInternal mStatusBarManagerInternal; Loading @@ -3350,7 +3455,8 @@ public class DisplayModeDirectorTest { mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, 800, 600, /* refreshRate= */ 60)}; mDisplay = createDisplay(DISPLAY_ID); mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID), DISPLAY_ID_2, createDisplay(DISPLAY_ID_2)); mDisplayManagerInternal = displayManagerInternal; mStatusBarManagerInternal = statusBarManagerInternal; mSensorManagerInternal = sensorManagerInternal; Loading Loading @@ -3381,12 +3487,12 @@ public class DisplayModeDirectorTest { @Override public Display getDisplay(int displayId) { return mDisplay; return mDisplays.get(displayId); } @Override public Display[] getDisplays() { return new Display[] { mDisplay }; return mDisplays.values().toArray(new Display[0]); } @Override Loading