From 96343a9effe959782fefc2cf11be88f6d4a9ae65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wilczy=C5=84ski?= Date: Fri, 16 Feb 2024 19:21:33 +0000 Subject: [PATCH] Refresh rate preference controllers aware of multiple displays Set mPeakRefreshRate in the preference controllers to the highest refresh rate among all the modes of all the displays. It'll then be used to determine two things: - if the setting is available - the summary of the setting This should only be done if the back up smooth display feature flag is enabled. If it's disabled, mPeakRefreshRate is passed to DisplayModeDirector and used for the votes. If the highest refresh rate of one display is 120 and that of the other is 130, we shouldn't set the vote to 130 for both displays. With the flag enabled, DisplayModeDirector figures out the highest refresh rate for each display. Bug: 310238382 Test: atest PeakRefreshRatePreferenceControllerTest Test: atest ForcePeakRefreshRatePreferenceControllerTest Test: atest RefreshRateSettingsUtilsTest Change-Id: I369927ba22df70958178505d8fc7c5747aaa8fdd --- ...cePeakRefreshRatePreferenceController.java | 5 +- .../PeakRefreshRatePreferenceController.java | 5 +- tests/robotests/Android.bp | 2 + ...akRefreshRatePreferenceControllerTest.java | 58 +++++++++++++++++-- ...akRefreshRatePreferenceControllerTest.java | 57 +++++++++++++++++- 5 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java b/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java index abeb94991fb..455f74f837a 100644 --- a/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java +++ b/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.development; import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; +import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays; import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.content.Context; @@ -47,7 +48,9 @@ public class ForcePeakRefreshRatePreferenceController extends DeveloperOptionsPr public ForcePeakRefreshRatePreferenceController(Context context) { super(context); - mPeakRefreshRate = findHighestRefreshRateForDefaultDisplay(context); + mPeakRefreshRate = Flags.backUpSmoothDisplayAndForcePeakRefreshRate() + ? findHighestRefreshRateAmongAllDisplays(context) + : findHighestRefreshRateForDefaultDisplay(context); Log.d(TAG, "DEFAULT_REFRESH_RATE : " + DEFAULT_REFRESH_RATE + " mPeakRefreshRate : " + mPeakRefreshRate); } diff --git a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java index 17d763ac42a..261eaf1316e 100644 --- a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java +++ b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.display; import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; +import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays; import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.content.Context; @@ -66,7 +67,9 @@ public class PeakRefreshRatePreferenceController extends TogglePreferenceControl updateState(mPreference); } }; - mPeakRefreshRate = Math.round(findHighestRefreshRateForDefaultDisplay(context)); + mPeakRefreshRate = Math.round(Flags.backUpSmoothDisplayAndForcePeakRefreshRate() + ? findHighestRefreshRateAmongAllDisplays(context) + : findHighestRefreshRateForDefaultDisplay(context)); Log.d( TAG, "DEFAULT_REFRESH_RATE : " diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp index 56482904be8..1c6794d027f 100644 --- a/tests/robotests/Android.bp +++ b/tests/robotests/Android.bp @@ -71,10 +71,12 @@ android_robolectric_test { "Settings-testutils2", "notification_flags_lib", "com_android_server_accessibility_flags_lib", + "testables", ], libs: [ "ims-common", + "android.test.mock", ], java_resource_dirs: [ diff --git a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java index 314120aa126..c7c76b19809 100644 --- a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.development; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; import static com.android.settings.development.ForcePeakRefreshRatePreferenceController.NO_CONFIG; @@ -24,15 +26,18 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; +import android.hardware.display.DisplayManager; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import android.testing.TestableContext; +import android.view.Display; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.display.feature.flags.Flags; @@ -43,7 +48,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @@ -53,17 +57,51 @@ public class ForcePeakRefreshRatePreferenceControllerTest { private SwitchPreference mPreference; @Mock private PreferenceScreen mScreen; + @Mock + private DisplayManager mDisplayManagerMock; + @Mock + private Display mDisplayMock; + @Mock + private Display mDisplayMock2; - private Context mContext; private ForcePeakRefreshRatePreferenceController mController; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock); + + Display.Mode[] modes = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 120), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 90) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + when(mDisplayMock.getSupportedModes()).thenReturn(modes); + + Display.Mode[] modes2 = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 70), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 130), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 80) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2); + when(mDisplayMock2.getSupportedModes()).thenReturn(modes2); + + when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 }); + mController = new ForcePeakRefreshRatePreferenceController(mContext); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); @@ -153,4 +191,16 @@ public class ForcePeakRefreshRatePreferenceControllerTest { assertThat(mPreference.isChecked()).isFalse(); assertThat(mPreference.isEnabled()).isFalse(); } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() { + assertThat(mController.mPeakRefreshRate).isEqualTo(120); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() { + assertThat(mController.mPeakRefreshRate).isEqualTo(130); + } } diff --git a/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java index cb0963b19ba..f8e91bd09e9 100644 --- a/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.display; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; @@ -24,14 +26,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; -import android.content.Context; +import android.hardware.display.DisplayManager; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import android.testing.TestableContext; +import android.view.Display; import androidx.preference.SwitchPreference; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.display.feature.flags.Flags; @@ -48,21 +53,55 @@ import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) public class PeakRefreshRatePreferenceControllerTest { - private Context mContext; private PeakRefreshRatePreferenceController mController; private SwitchPreference mPreference; @Mock private PeakRefreshRatePreferenceController.DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; + @Mock + private DisplayManager mDisplayManagerMock; + @Mock + private Display mDisplayMock; + @Mock + private Display mDisplayMock2; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock); + + Display.Mode[] modes = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 120), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 90) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + when(mDisplayMock.getSupportedModes()).thenReturn(modes); + + Display.Mode[] modes2 = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 70), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 130), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 80) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2); + when(mDisplayMock2.getSupportedModes()).thenReturn(modes2); + + when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 }); + mController = new PeakRefreshRatePreferenceController(mContext, "key"); mController.injectDeviceConfigDisplaySettings(mDeviceConfigDisplaySettings); mPreference = new SwitchPreference(RuntimeEnvironment.application); @@ -152,4 +191,16 @@ public class PeakRefreshRatePreferenceControllerTest { assertThat(mController.isChecked()).isFalse(); } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() { + assertThat(mController.mPeakRefreshRate).isEqualTo(120); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() { + assertThat(mController.mPeakRefreshRate).isEqualTo(130); + } }