• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.display.mode
18 
19 import android.content.Context
20 import android.content.ContextWrapper
21 import android.provider.Settings
22 import android.util.SparseArray
23 import android.view.Display
24 import android.view.SurfaceControl.RefreshRateRange
25 import android.view.SurfaceControl.RefreshRateRanges
26 import androidx.test.core.app.ApplicationProvider
27 import androidx.test.filters.SmallTest
28 import com.android.internal.util.test.FakeSettingsProvider
29 import com.android.server.display.DisplayDeviceConfig
30 import com.android.server.display.config.RefreshRateData
31 import com.android.server.display.config.SupportedModeData
32 import com.android.server.display.config.createRefreshRateData
33 import com.android.server.display.feature.DisplayManagerFlags
34 import com.android.server.display.mode.DisplayModeDirector.DisplayDeviceConfigProvider
35 import com.android.server.display.mode.SupportedRefreshRatesVote.RefreshRates
36 import com.android.server.testutils.TestHandler
37 import com.google.common.truth.Truth.assertThat
38 import com.google.common.truth.Truth.assertWithMessage
39 import com.google.testing.junit.testparameterinjector.TestParameter
40 import com.google.testing.junit.testparameterinjector.TestParameterInjector
41 import org.junit.Before
42 import org.junit.Rule
43 import org.junit.Test
44 import org.junit.runner.RunWith
45 import org.mockito.Mockito
46 import org.mockito.junit.MockitoJUnit
47 import org.mockito.kotlin.mock
48 import org.mockito.kotlin.whenever
49 
50 private val RANGE_NO_LIMIT = RefreshRateRange(0f, Float.POSITIVE_INFINITY)
51 private val RANGE_0_60 = RefreshRateRange(0f, 60f)
52 private val RANGE_0_90 = RefreshRateRange(0f, 90f)
53 private val RANGE_0_120 = RefreshRateRange(0f, 120f)
54 private val RANGE_60_90 = RefreshRateRange(60f, 90f)
55 private val RANGE_60_120 = RefreshRateRange(60f, 120f)
56 private val RANGE_60_INF = RefreshRateRange(60f, Float.POSITIVE_INFINITY)
57 private val RANGE_90_90 = RefreshRateRange(90f, 90f)
58 private val RANGE_90_120 = RefreshRateRange(90f, 120f)
59 private val RANGE_90_INF = RefreshRateRange(90f, Float.POSITIVE_INFINITY)
60 
61 private val RANGES_NO_LIMIT = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_NO_LIMIT)
62 private val RANGES_NO_LIMIT_60 = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_0_60)
63 private val RANGES_NO_LIMIT_90 = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_0_90)
64 private val RANGES_NO_LIMIT_120 = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_0_120)
65 private val RANGES_90 = RefreshRateRanges(RANGE_0_90, RANGE_0_90)
66 private val RANGES_120 = RefreshRateRanges(RANGE_0_120, RANGE_0_120)
67 private val RANGES_90_60 = RefreshRateRanges(RANGE_0_90, RANGE_0_60)
68 private val RANGES_90TO90 = RefreshRateRanges(RANGE_90_90, RANGE_90_90)
69 private val RANGES_90TO120 = RefreshRateRanges(RANGE_90_120, RANGE_90_120)
70 private val RANGES_60TO120_60TO90 = RefreshRateRanges(RANGE_60_120, RANGE_60_90)
71 private val RANGES_MIN90 = RefreshRateRanges(RANGE_90_INF, RANGE_90_INF)
72 private val RANGES_MIN90_90TO120 = RefreshRateRanges(RANGE_90_INF, RANGE_90_120)
73 private val RANGES_MIN60_60TO90 = RefreshRateRanges(RANGE_60_INF, RANGE_60_90)
74 private val RANGES_MIN90_90TO90 = RefreshRateRanges(RANGE_90_INF, RANGE_90_90)
75 
76 private val LOW_POWER_GLOBAL_VOTE = Vote.forRenderFrameRates(0f, 60f)
77 private val LOW_POWER_REFRESH_RATE_DATA = createRefreshRateData(
78     lowPowerSupportedModes = listOf(SupportedModeData(60f, 60f), SupportedModeData(60f, 240f)))
79 private val LOW_POWER_EMPTY_REFRESH_RATE_DATA = createRefreshRateData()
80 private val EXPECTED_SUPPORTED_MODES_VOTE = SupportedRefreshRatesVote(
81     listOf(RefreshRates(60f, 60f), RefreshRates(60f, 240f)))
82 
83 @SmallTest
84 @RunWith(TestParameterInjector::class)
85 class SettingsObserverTest {
86     @get:Rule
87     val mockitoRule = MockitoJUnit.rule()
88 
89     @get:Rule
90     val settingsProviderRule = FakeSettingsProvider.rule()
91 
92     private lateinit var spyContext: Context
93     private val mockInjector = mock<DisplayModeDirector.Injector>()
94     private val mockFlags = mock<DisplayManagerFlags>()
95     private val mockDeviceConfig = mock<DisplayDeviceConfig>()
96     private val mockDisplayDeviceConfigProvider = mock<DisplayDeviceConfigProvider>()
97 
98     private val testHandler = TestHandler(null)
99 
100     @Before
setUpnull101     fun setUp() {
102         spyContext = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
103     }
104 
105     @Test
testLowPowerModenull106     fun testLowPowerMode(@TestParameter testCase: LowPowerTestCase) {
107         whenever(mockFlags.isVsyncLowPowerVoteEnabled).thenReturn(testCase.vsyncLowPowerVoteEnabled)
108         whenever(spyContext.contentResolver)
109                 .thenReturn(settingsProviderRule.mockContentResolver(null))
110         val lowPowerModeSetting = if (testCase.lowPowerModeEnabled) 1 else 0
111         Settings.Global.putInt(
112                 spyContext.contentResolver, Settings.Global.LOW_POWER_MODE, lowPowerModeSetting)
113 
114         val displayModeDirector = DisplayModeDirector(
115                 spyContext, testHandler, mockInjector, mockFlags, mockDisplayDeviceConfigProvider)
116         val ddcByDisplay = SparseArray<DisplayDeviceConfig>()
117         whenever(mockDeviceConfig.refreshRateData).thenReturn(testCase.refreshRateData)
118         ddcByDisplay.put(Display.DEFAULT_DISPLAY, mockDeviceConfig)
119         displayModeDirector.injectDisplayDeviceConfigByDisplay(ddcByDisplay)
120         val settingsObserver = displayModeDirector.SettingsObserver(
121                 spyContext, testHandler, mockFlags)
122 
123         settingsObserver.onChange(
124                 false, Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), 1)
125 
126         assertThat(displayModeDirector.getVote(VotesStorage.GLOBAL_ID,
127                 Vote.PRIORITY_LOW_POWER_MODE_RENDER_RATE)).isEqualTo(testCase.globalVote)
128         assertThat(displayModeDirector.getVote(Display.DEFAULT_DISPLAY,
129             Vote.PRIORITY_LOW_POWER_MODE_MODES)).isEqualTo(testCase.displayVote)
130     }
131 
132     enum class LowPowerTestCase(
133         val refreshRateData: RefreshRateData,
134         val vsyncLowPowerVoteEnabled: Boolean,
135         val lowPowerModeEnabled: Boolean,
136         internal val globalVote: Vote?,
137         internal val displayVote: Vote?
138     ) {
139         ALL_ENABLED(LOW_POWER_REFRESH_RATE_DATA, true, true,
140             LOW_POWER_GLOBAL_VOTE, EXPECTED_SUPPORTED_MODES_VOTE),
141         LOW_POWER_OFF(LOW_POWER_REFRESH_RATE_DATA, true, false,
142             null, null),
143         EMPTY_REFRESH_LOW_POWER_ON(LOW_POWER_EMPTY_REFRESH_RATE_DATA, true, true,
144             LOW_POWER_GLOBAL_VOTE, null),
145         EMPTY_REFRESH__LOW_POWER_OFF(LOW_POWER_EMPTY_REFRESH_RATE_DATA, true, false,
146             null, null),
147         VSYNC_VOTE_DISABLED_SUPPORTED_LOW_POWER_ON(LOW_POWER_REFRESH_RATE_DATA, false, true,
148             LOW_POWER_GLOBAL_VOTE, null),
149         VSYNC_VOTE_DISABLED_LOW_POWER_OFF(LOW_POWER_REFRESH_RATE_DATA, false, false,
150             null, null),
151     }
152 
153     @Test
testSettingsRefreshRatesnull154     fun testSettingsRefreshRates(@TestParameter testCase: SettingsRefreshRateTestCase) {
155         whenever(mockFlags.isPeakRefreshRatePhysicalLimitEnabled)
156                 .thenReturn(testCase.peakRefreshRatePhysicalLimitEnabled)
157 
158         val displayModeDirector = DisplayModeDirector(
159             spyContext, testHandler, mockInjector, mockFlags, mockDisplayDeviceConfigProvider)
160 
161         val modes = arrayOf(
162             Display.Mode(1, 1000, 1000, 60f),
163             Display.Mode(2, 1000, 1000, 90f),
164             Display.Mode(3, 1000, 1000, 120f)
165         )
166         displayModeDirector.injectSupportedModesByDisplay(SparseArray<Array<Display.Mode>>().apply {
167             append(Display.DEFAULT_DISPLAY, modes)
168         })
169         displayModeDirector.injectDefaultModeByDisplay(SparseArray<Display.Mode>().apply {
170             append(Display.DEFAULT_DISPLAY, modes[0])
171         })
172 
173         val specs = displayModeDirector.getDesiredDisplayModeSpecsWithInjectedFpsSettings(
174             testCase.minRefreshRate, testCase.peakRefreshRate, testCase.defaultRefreshRate)
175 
176         assertWithMessage("Primary RefreshRateRanges: ")
177                 .that(specs.primary).isEqualTo(testCase.expectedPrimaryRefreshRateRanges)
178         assertWithMessage("App RefreshRateRanges: ")
179                 .that(specs.appRequest).isEqualTo(testCase.expectedAppRefreshRateRanges)
180     }
181 
182     /**
183      * Votes considered:
184      * priority: PRIORITY_USER_SETTING_PEAK_REFRESH_RATE (also used for appRanged)
185      * condition: peakRefreshRatePhysicalLimitEnabled, peakRR > 0
186      * vote: physical(minRR, peakRR)
187      *
188      * priority: PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE (also used for appRanged)
189      * condition: peakRR > 0
190      * vote: render(minRR, peakRR)
191      *
192      * priority: PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE
193      * condition: -
194      * vote: render(minRR, INF)
195      *
196      * priority: PRIORITY_DEFAULT_RENDER_FRAME_RATE
197      * condition: defaultRR > 0
198      * vote: render(0, defaultRR)
199      *
200      * 0 considered not set
201      *
202      * For this test:
203      * primary physical rate:
204      *          (minRR, peakRefreshRatePhysicalLimitEnabled ? max(minRR, peakRR) : INF)
205      * primary render rate : (minRR, min(defaultRR, max(minRR, peakRR)))
206      *
207      * app physical rate: (0, peakRefreshRatePhysicalLimitEnabled ? max(minRR, peakRR) : INF)
208      * app render rate: (0, max(minRR, peakRR))
209      */
210     enum class SettingsRefreshRateTestCase(
211         val minRefreshRate: Float,
212         val peakRefreshRate: Float,
213         val defaultRefreshRate: Float,
214         val peakRefreshRatePhysicalLimitEnabled: Boolean,
215         val expectedPrimaryRefreshRateRanges: RefreshRateRanges,
216         val expectedAppRefreshRateRanges: RefreshRateRanges,
217     ) {
218         NO_LIMIT(0f, 0f, 0f, false, RANGES_NO_LIMIT, RANGES_NO_LIMIT),
219         NO_LIMIT_WITH_PHYSICAL_RR(0f, 0f, 0f, true, RANGES_NO_LIMIT, RANGES_NO_LIMIT),
220 
221         LIMITS_0_0_90(0f, 0f, 90f, false, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT),
222         LIMITS_0_0_90_WITH_PHYSICAL_RR(0f, 0f, 90f, true, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT),
223 
224         LIMITS_0_90_0(0f, 90f, 0f, false, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT_90),
225         LIMITS_0_90_0_WITH_PHYSICAL_RR(0f, 90f, 0f, true, RANGES_90, RANGES_90),
226 
227         LIMITS_0_90_60(0f, 90f, 60f, false, RANGES_NO_LIMIT_60, RANGES_NO_LIMIT_90),
228         LIMITS_0_90_60_WITH_PHYSICAL_RR(0f, 90f, 60f, true, RANGES_90_60, RANGES_90),
229 
230         LIMITS_0_90_120(0f, 90f, 120f, false, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT_90),
231         LIMITS_0_90_120_WITH_PHYSICAL_RR(0f, 90f, 120f, true, RANGES_90, RANGES_90),
232 
233         LIMITS_90_0_0(90f, 0f, 0f, false, RANGES_MIN90, RANGES_NO_LIMIT),
234         LIMITS_90_0_0_WITH_PHYSICAL_RR(90f, 0f, 0f, true, RANGES_MIN90, RANGES_NO_LIMIT),
235 
236         LIMITS_90_0_120(90f, 0f, 120f, false, RANGES_MIN90_90TO120, RANGES_NO_LIMIT),
237         LIMITS_90_0_120_WITH_PHYSICAL_RR(90f,
238             0f,
239             120f,
240             true,
241             RANGES_MIN90_90TO120,
242             RANGES_NO_LIMIT),
243 
244         LIMITS_90_0_60(90f, 0f, 60f, false, RANGES_MIN90, RANGES_NO_LIMIT),
245         LIMITS_90_0_60_WITH_PHYSICAL_RR(90f, 0f, 60f, true, RANGES_MIN90, RANGES_NO_LIMIT),
246 
247         LIMITS_90_120_0(90f, 120f, 0f, false, RANGES_MIN90_90TO120, RANGES_NO_LIMIT_120),
248         LIMITS_90_120_0_WITH_PHYSICAL_RR(90f, 120f, 0f, true, RANGES_90TO120, RANGES_120),
249 
250         LIMITS_90_60_0(90f, 60f, 0f, false, RANGES_MIN90_90TO90, RANGES_NO_LIMIT_90),
251         LIMITS_90_60_0_WITH_PHYSICAL_RR(90f, 60f, 0f, true, RANGES_90TO90, RANGES_90),
252 
253         LIMITS_60_120_90(60f, 120f, 90f, false, RANGES_MIN60_60TO90, RANGES_NO_LIMIT_120),
254         LIMITS_60_120_90_WITH_PHYSICAL_RR(60f, 120f, 90f, true, RANGES_60TO120_60TO90, RANGES_120),
255     }
256 }