Loading services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +13 −0 Original line number Original line Diff line number Diff line Loading @@ -212,6 +212,10 @@ public class DisplayManagerFlags { Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE, Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE, Flags::blockAutobrightnessChangesOnStylusUsage Flags::blockAutobrightnessChangesOnStylusUsage ); ); private final FlagState mIsUserRefreshRateForExternalDisplayEnabled = new FlagState( Flags.FLAG_ENABLE_USER_REFRESH_RATE_FOR_EXTERNAL_DISPLAY, Flags::enableUserRefreshRateForExternalDisplay ); private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState( private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState( Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS, Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS, Loading Loading @@ -455,6 +459,14 @@ public class DisplayManagerFlags { return mBlockAutobrightnessChangesOnStylusUsage.isEnabled(); return mBlockAutobrightnessChangesOnStylusUsage.isEnabled(); } } /** * @return {@code true} if need to use user refresh rate settings for * external displays. */ public boolean isUserRefreshRateForExternalDisplayEnabled() { return mIsUserRefreshRateForExternalDisplayEnabled.isEnabled(); } /** /** * dumps all flagstates * dumps all flagstates * @param pw printWriter * @param pw printWriter Loading Loading @@ -501,6 +513,7 @@ public class DisplayManagerFlags { pw.println(" " + mIdleScreenConfigInSubscribingLightSensor); pw.println(" " + mIdleScreenConfigInSubscribingLightSensor); pw.println(" " + mEnableBatteryStatsForAllDisplays); pw.println(" " + mEnableBatteryStatsForAllDisplays); pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage); pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage); pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled); } } private static class FlagState { private static class FlagState { Loading services/core/java/com/android/server/display/feature/display_flags.aconfig +11 −0 Original line number Original line Diff line number Diff line Loading @@ -381,3 +381,14 @@ flag { bug: "352411468" bug: "352411468" is_fixed_read_only: true is_fixed_read_only: true } } flag { name: "enable_user_refresh_rate_for_external_display" namespace: "display_manager" description: "Apply refresh rate from user preferred display mode to external displays" bug: "370657357" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } services/core/java/com/android/server/display/mode/DisplayModeDirector.java +56 −25 Original line number Original line Diff line number Diff line Loading @@ -1194,6 +1194,13 @@ public class DisplayModeDirector { @GuardedBy("mLock") @GuardedBy("mLock") private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, float defaultRefreshRate, int displayId) { float defaultRefreshRate, int displayId) { if (mDisplayObserver.isExternalDisplayLocked(displayId)) { if (mLoggingEnabled) { Slog.d(TAG, "skip updateRefreshRateSettingLocked for external display " + displayId); } return; } // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is // 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 // 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 // so, enable the brightness observer. The logic here is more complicated and fragile Loading Loading @@ -1243,6 +1250,8 @@ public class DisplayModeDirector { } } private void removeRefreshRateSetting(int displayId) { private void removeRefreshRateSetting(int displayId) { mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, null); null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, Loading Loading @@ -1458,11 +1467,11 @@ public class DisplayModeDirector { public void onDisplayAdded(int displayId) { public void onDisplayAdded(int displayId) { updateDisplayDeviceConfig(displayId); updateDisplayDeviceConfig(displayId); DisplayInfo displayInfo = getDisplayInfo(displayId); DisplayInfo displayInfo = getDisplayInfo(displayId); registerExternalDisplay(displayInfo); updateDisplayModes(displayId, displayInfo); updateDisplayModes(displayId, displayInfo); updateLayoutLimitedFrameRate(displayId, displayInfo); updateLayoutLimitedFrameRate(displayId, displayInfo); updateUserSettingDisplayPreferredSize(displayInfo); updateUserSettingDisplayPreferredSize(displayInfo); updateDisplaysPeakRefreshRateAndResolution(displayInfo); updateDisplaysPeakRefreshRateAndResolution(displayInfo); addDisplaysSynchronizedPeakRefreshRate(displayInfo); } } @Override @Override Loading @@ -1477,7 +1486,7 @@ public class DisplayModeDirector { updateLayoutLimitedFrameRate(displayId, null); updateLayoutLimitedFrameRate(displayId, null); removeUserSettingDisplayPreferredSize(displayId); removeUserSettingDisplayPreferredSize(displayId); removeDisplaysPeakRefreshRateAndResolution(displayId); removeDisplaysPeakRefreshRateAndResolution(displayId); removeDisplaysSynchronizedPeakRefreshRate(displayId); unregisterExternalDisplay(displayId); } } @Override @Override Loading @@ -1489,6 +1498,30 @@ public class DisplayModeDirector { updateUserSettingDisplayPreferredSize(displayInfo); updateUserSettingDisplayPreferredSize(displayInfo); } } private void registerExternalDisplay(DisplayInfo displayInfo) { if (displayInfo == null || displayInfo.type != Display.TYPE_EXTERNAL) { return; } synchronized (mLock) { mExternalDisplaysConnected.add(displayInfo.displayId); if (mExternalDisplaysConnected.size() == 1) { addDisplaysSynchronizedPeakRefreshRate(); } } } private void unregisterExternalDisplay(int displayId) { synchronized (mLock) { if (!isExternalDisplayLocked(displayId)) { return; } mExternalDisplaysConnected.remove(displayId); if (mExternalDisplaysConnected.isEmpty()) { removeDisplaysSynchronizedPeakRefreshRate(); } } } boolean isExternalDisplayLocked(int displayId) { boolean isExternalDisplayLocked(int displayId) { return mExternalDisplaysConnected.contains(displayId); return mExternalDisplaysConnected.contains(displayId); } } Loading Loading @@ -1534,11 +1567,25 @@ public class DisplayModeDirector { return; return; } } if (info.type == Display.TYPE_EXTERNAL && mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled() && !isRefreshRateSynchronizationEnabled()) { mVotesStorage.updateVote(info.displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, Vote.forSizeAndPhysicalRefreshRatesRange( /* minWidth */ preferredMode.getPhysicalWidth(), /* minHeight */ preferredMode.getPhysicalHeight(), /* width */ preferredMode.getPhysicalWidth(), /* height */ preferredMode.getPhysicalHeight(), /* minRefreshRate */ preferredMode.getRefreshRate(), /* maxRefreshRate */ preferredMode.getRefreshRate())); } else { mVotesStorage.updateVote(info.displayId, mVotesStorage.updateVote(info.displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, Vote.forSize(/* width */ preferredMode.getPhysicalWidth(), Vote.forSize(/* width */ preferredMode.getPhysicalWidth(), /* height */ preferredMode.getPhysicalHeight())); /* height */ preferredMode.getPhysicalHeight())); } } } @Nullable @Nullable private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) { private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) { Loading Loading @@ -1584,17 +1631,10 @@ public class DisplayModeDirector { * Sets 60Hz target refresh rate as the vote with * Sets 60Hz target refresh rate as the vote with * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority. * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority. */ */ private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) { private void addDisplaysSynchronizedPeakRefreshRate() { if (info == null || info.type != Display.TYPE_EXTERNAL if (!isRefreshRateSynchronizationEnabled()) { || !isRefreshRateSynchronizationEnabled()) { return; } synchronized (mLock) { mExternalDisplaysConnected.add(info.displayId); if (mExternalDisplaysConnected.size() != 1) { return; return; } } } // set minRefreshRate as the max refresh rate. // set minRefreshRate as the max refresh rate. mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, Vote.forPhysicalRefreshRates( Vote.forPhysicalRefreshRates( Loading @@ -1610,19 +1650,10 @@ public class DisplayModeDirector { + SYNCHRONIZED_REFRESH_RATE_TOLERANCE)); + SYNCHRONIZED_REFRESH_RATE_TOLERANCE)); } } private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) { private void removeDisplaysSynchronizedPeakRefreshRate() { if (!isRefreshRateSynchronizationEnabled()) { if (!isRefreshRateSynchronizationEnabled()) { return; return; } } synchronized (mLock) { if (!isExternalDisplayLocked(displayId)) { return; } mExternalDisplaysConnected.remove(displayId); if (!mExternalDisplaysConnected.isEmpty()) { return; } } mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null); mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null); mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null); mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null); } } Loading services/core/java/com/android/server/display/mode/Vote.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -44,7 +44,7 @@ interface Vote { // It votes [minRefreshRate, Float.POSITIVE_INFINITY] // It votes [minRefreshRate, Float.POSITIVE_INFINITY] int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3; int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3; // User setting preferred display resolution. // User setting preferred display resolution, for external displays also includes refresh rate. int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4; int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4; // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render Loading services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +59 −2 Original line number Original line Diff line number Diff line Loading @@ -1871,6 +1871,60 @@ public class DisplayModeDirectorTest { /* frameRateHigh= */ peakRefreshRate); /* frameRateHigh= */ peakRefreshRate); } } @Test public void testPeakRefreshRate_notAppliedToExternalDisplays() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); mInjector.mDisplayInfo.type = Display.TYPE_EXTERNAL; DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags, mDisplayDeviceConfigProvider); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); director.getDisplayObserver().onDisplayAdded(DISPLAY_ID); director.getDisplayObserver().onDisplayAdded(DISPLAY_ID_2); 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); // Disable Smooth Display setPeakRefreshRate(RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE); Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertThat(vote1).isNull(); assertThat(vote2).isNull(); // Enable Smooth Display setPeakRefreshRate(Float.POSITIVE_INFINITY); vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertThat(vote1).isNull(); assertThat(vote2).isNull(); } @Test @Test public void testPeakRefreshRate_DisplayChanged() { public void testPeakRefreshRate_DisplayChanged() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) Loading Loading @@ -1968,8 +2022,9 @@ public class DisplayModeDirectorTest { @Test @Test @Parameters({ @Parameters({ "true, true, 60", "true, true, 60", "false, true, 50", "false, true, 60", "true, false, 50" "true, false, 50", "false, false, 50" }) }) public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled, public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled, boolean isExternalDisplay, float expectedMaxRenderFrameRate) { boolean isExternalDisplay, float expectedMaxRenderFrameRate) { Loading Loading @@ -3810,6 +3865,7 @@ public class DisplayModeDirectorTest { SensorManagerInternal sensorManagerInternal) { SensorManagerInternal sensorManagerInternal) { mDeviceConfig = new FakeDeviceConfig(); mDeviceConfig = new FakeDeviceConfig(); mDisplayInfo = new DisplayInfo(); mDisplayInfo = new DisplayInfo(); mDisplayInfo.type = Display.TYPE_INTERNAL; mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, 800, 600, /* refreshRate= */ 60)}; 800, 600, /* refreshRate= */ 60)}; Loading Loading @@ -3856,6 +3912,7 @@ public class DisplayModeDirectorTest { @Override @Override public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { displayInfo.copyFrom(mDisplayInfo); displayInfo.copyFrom(mDisplayInfo); displayInfo.displayId = displayId; return mDisplayInfoValid; return mDisplayInfoValid; } } Loading Loading
services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +13 −0 Original line number Original line Diff line number Diff line Loading @@ -212,6 +212,10 @@ public class DisplayManagerFlags { Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE, Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE, Flags::blockAutobrightnessChangesOnStylusUsage Flags::blockAutobrightnessChangesOnStylusUsage ); ); private final FlagState mIsUserRefreshRateForExternalDisplayEnabled = new FlagState( Flags.FLAG_ENABLE_USER_REFRESH_RATE_FOR_EXTERNAL_DISPLAY, Flags::enableUserRefreshRateForExternalDisplay ); private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState( private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState( Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS, Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS, Loading Loading @@ -455,6 +459,14 @@ public class DisplayManagerFlags { return mBlockAutobrightnessChangesOnStylusUsage.isEnabled(); return mBlockAutobrightnessChangesOnStylusUsage.isEnabled(); } } /** * @return {@code true} if need to use user refresh rate settings for * external displays. */ public boolean isUserRefreshRateForExternalDisplayEnabled() { return mIsUserRefreshRateForExternalDisplayEnabled.isEnabled(); } /** /** * dumps all flagstates * dumps all flagstates * @param pw printWriter * @param pw printWriter Loading Loading @@ -501,6 +513,7 @@ public class DisplayManagerFlags { pw.println(" " + mIdleScreenConfigInSubscribingLightSensor); pw.println(" " + mIdleScreenConfigInSubscribingLightSensor); pw.println(" " + mEnableBatteryStatsForAllDisplays); pw.println(" " + mEnableBatteryStatsForAllDisplays); pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage); pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage); pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled); } } private static class FlagState { private static class FlagState { Loading
services/core/java/com/android/server/display/feature/display_flags.aconfig +11 −0 Original line number Original line Diff line number Diff line Loading @@ -381,3 +381,14 @@ flag { bug: "352411468" bug: "352411468" is_fixed_read_only: true is_fixed_read_only: true } } flag { name: "enable_user_refresh_rate_for_external_display" namespace: "display_manager" description: "Apply refresh rate from user preferred display mode to external displays" bug: "370657357" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } }
services/core/java/com/android/server/display/mode/DisplayModeDirector.java +56 −25 Original line number Original line Diff line number Diff line Loading @@ -1194,6 +1194,13 @@ public class DisplayModeDirector { @GuardedBy("mLock") @GuardedBy("mLock") private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, float defaultRefreshRate, int displayId) { float defaultRefreshRate, int displayId) { if (mDisplayObserver.isExternalDisplayLocked(displayId)) { if (mLoggingEnabled) { Slog.d(TAG, "skip updateRefreshRateSettingLocked for external display " + displayId); } return; } // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is // 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 // 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 // so, enable the brightness observer. The logic here is more complicated and fragile Loading Loading @@ -1243,6 +1250,8 @@ public class DisplayModeDirector { } } private void removeRefreshRateSetting(int displayId) { private void removeRefreshRateSetting(int displayId) { mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, null); null); mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, Loading Loading @@ -1458,11 +1467,11 @@ public class DisplayModeDirector { public void onDisplayAdded(int displayId) { public void onDisplayAdded(int displayId) { updateDisplayDeviceConfig(displayId); updateDisplayDeviceConfig(displayId); DisplayInfo displayInfo = getDisplayInfo(displayId); DisplayInfo displayInfo = getDisplayInfo(displayId); registerExternalDisplay(displayInfo); updateDisplayModes(displayId, displayInfo); updateDisplayModes(displayId, displayInfo); updateLayoutLimitedFrameRate(displayId, displayInfo); updateLayoutLimitedFrameRate(displayId, displayInfo); updateUserSettingDisplayPreferredSize(displayInfo); updateUserSettingDisplayPreferredSize(displayInfo); updateDisplaysPeakRefreshRateAndResolution(displayInfo); updateDisplaysPeakRefreshRateAndResolution(displayInfo); addDisplaysSynchronizedPeakRefreshRate(displayInfo); } } @Override @Override Loading @@ -1477,7 +1486,7 @@ public class DisplayModeDirector { updateLayoutLimitedFrameRate(displayId, null); updateLayoutLimitedFrameRate(displayId, null); removeUserSettingDisplayPreferredSize(displayId); removeUserSettingDisplayPreferredSize(displayId); removeDisplaysPeakRefreshRateAndResolution(displayId); removeDisplaysPeakRefreshRateAndResolution(displayId); removeDisplaysSynchronizedPeakRefreshRate(displayId); unregisterExternalDisplay(displayId); } } @Override @Override Loading @@ -1489,6 +1498,30 @@ public class DisplayModeDirector { updateUserSettingDisplayPreferredSize(displayInfo); updateUserSettingDisplayPreferredSize(displayInfo); } } private void registerExternalDisplay(DisplayInfo displayInfo) { if (displayInfo == null || displayInfo.type != Display.TYPE_EXTERNAL) { return; } synchronized (mLock) { mExternalDisplaysConnected.add(displayInfo.displayId); if (mExternalDisplaysConnected.size() == 1) { addDisplaysSynchronizedPeakRefreshRate(); } } } private void unregisterExternalDisplay(int displayId) { synchronized (mLock) { if (!isExternalDisplayLocked(displayId)) { return; } mExternalDisplaysConnected.remove(displayId); if (mExternalDisplaysConnected.isEmpty()) { removeDisplaysSynchronizedPeakRefreshRate(); } } } boolean isExternalDisplayLocked(int displayId) { boolean isExternalDisplayLocked(int displayId) { return mExternalDisplaysConnected.contains(displayId); return mExternalDisplaysConnected.contains(displayId); } } Loading Loading @@ -1534,11 +1567,25 @@ public class DisplayModeDirector { return; return; } } if (info.type == Display.TYPE_EXTERNAL && mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled() && !isRefreshRateSynchronizationEnabled()) { mVotesStorage.updateVote(info.displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, Vote.forSizeAndPhysicalRefreshRatesRange( /* minWidth */ preferredMode.getPhysicalWidth(), /* minHeight */ preferredMode.getPhysicalHeight(), /* width */ preferredMode.getPhysicalWidth(), /* height */ preferredMode.getPhysicalHeight(), /* minRefreshRate */ preferredMode.getRefreshRate(), /* maxRefreshRate */ preferredMode.getRefreshRate())); } else { mVotesStorage.updateVote(info.displayId, mVotesStorage.updateVote(info.displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, Vote.forSize(/* width */ preferredMode.getPhysicalWidth(), Vote.forSize(/* width */ preferredMode.getPhysicalWidth(), /* height */ preferredMode.getPhysicalHeight())); /* height */ preferredMode.getPhysicalHeight())); } } } @Nullable @Nullable private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) { private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) { Loading Loading @@ -1584,17 +1631,10 @@ public class DisplayModeDirector { * Sets 60Hz target refresh rate as the vote with * Sets 60Hz target refresh rate as the vote with * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority. * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority. */ */ private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) { private void addDisplaysSynchronizedPeakRefreshRate() { if (info == null || info.type != Display.TYPE_EXTERNAL if (!isRefreshRateSynchronizationEnabled()) { || !isRefreshRateSynchronizationEnabled()) { return; } synchronized (mLock) { mExternalDisplaysConnected.add(info.displayId); if (mExternalDisplaysConnected.size() != 1) { return; return; } } } // set minRefreshRate as the max refresh rate. // set minRefreshRate as the max refresh rate. mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, Vote.forPhysicalRefreshRates( Vote.forPhysicalRefreshRates( Loading @@ -1610,19 +1650,10 @@ public class DisplayModeDirector { + SYNCHRONIZED_REFRESH_RATE_TOLERANCE)); + SYNCHRONIZED_REFRESH_RATE_TOLERANCE)); } } private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) { private void removeDisplaysSynchronizedPeakRefreshRate() { if (!isRefreshRateSynchronizationEnabled()) { if (!isRefreshRateSynchronizationEnabled()) { return; return; } } synchronized (mLock) { if (!isExternalDisplayLocked(displayId)) { return; } mExternalDisplaysConnected.remove(displayId); if (!mExternalDisplaysConnected.isEmpty()) { return; } } mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null); mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null); mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null); mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null); } } Loading
services/core/java/com/android/server/display/mode/Vote.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -44,7 +44,7 @@ interface Vote { // It votes [minRefreshRate, Float.POSITIVE_INFINITY] // It votes [minRefreshRate, Float.POSITIVE_INFINITY] int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3; int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3; // User setting preferred display resolution. // User setting preferred display resolution, for external displays also includes refresh rate. int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4; int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4; // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render Loading
services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +59 −2 Original line number Original line Diff line number Diff line Loading @@ -1871,6 +1871,60 @@ public class DisplayModeDirectorTest { /* frameRateHigh= */ peakRefreshRate); /* frameRateHigh= */ peakRefreshRate); } } @Test public void testPeakRefreshRate_notAppliedToExternalDisplays() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); mInjector.mDisplayInfo.type = Display.TYPE_EXTERNAL; DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags, mDisplayDeviceConfigProvider); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); director.getDisplayObserver().onDisplayAdded(DISPLAY_ID); director.getDisplayObserver().onDisplayAdded(DISPLAY_ID_2); 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); // Disable Smooth Display setPeakRefreshRate(RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE); Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertThat(vote1).isNull(); assertThat(vote2).isNull(); // Enable Smooth Display setPeakRefreshRate(Float.POSITIVE_INFINITY); vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); assertThat(vote1).isNull(); assertThat(vote2).isNull(); } @Test @Test public void testPeakRefreshRate_DisplayChanged() { public void testPeakRefreshRate_DisplayChanged() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) Loading Loading @@ -1968,8 +2022,9 @@ public class DisplayModeDirectorTest { @Test @Test @Parameters({ @Parameters({ "true, true, 60", "true, true, 60", "false, true, 50", "false, true, 60", "true, false, 50" "true, false, 50", "false, false, 50" }) }) public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled, public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled, boolean isExternalDisplay, float expectedMaxRenderFrameRate) { boolean isExternalDisplay, float expectedMaxRenderFrameRate) { Loading Loading @@ -3810,6 +3865,7 @@ public class DisplayModeDirectorTest { SensorManagerInternal sensorManagerInternal) { SensorManagerInternal sensorManagerInternal) { mDeviceConfig = new FakeDeviceConfig(); mDeviceConfig = new FakeDeviceConfig(); mDisplayInfo = new DisplayInfo(); mDisplayInfo = new DisplayInfo(); mDisplayInfo.type = Display.TYPE_INTERNAL; mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, 800, 600, /* refreshRate= */ 60)}; 800, 600, /* refreshRate= */ 60)}; Loading Loading @@ -3856,6 +3912,7 @@ public class DisplayModeDirectorTest { @Override @Override public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { displayInfo.copyFrom(mDisplayInfo); displayInfo.copyFrom(mDisplayInfo); displayInfo.displayId = displayId; return mDisplayInfoValid; return mDisplayInfoValid; } } Loading