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 }