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.feature.DisplayManagerFlags 33 import com.android.server.display.mode.DisplayModeDirector.DisplayDeviceConfigProvider 34 import com.android.server.display.mode.SupportedRefreshRatesVote.RefreshRates 35 import com.android.server.testutils.TestHandler 36 import com.google.common.truth.Truth.assertThat 37 import com.google.common.truth.Truth.assertWithMessage 38 import com.google.testing.junit.testparameterinjector.TestParameter 39 import com.google.testing.junit.testparameterinjector.TestParameterInjector 40 import org.junit.Before 41 import org.junit.Rule 42 import org.junit.Test 43 import org.junit.runner.RunWith 44 import org.mockito.Mockito 45 import org.mockito.junit.MockitoJUnit 46 import org.mockito.kotlin.mock 47 import org.mockito.kotlin.whenever 48 49 private val RANGE_NO_LIMIT = RefreshRateRange(0f, Float.POSITIVE_INFINITY) 50 private val RANGE_0_60 = RefreshRateRange(0f, 60f) 51 private val RANGE_0_90 = RefreshRateRange(0f, 90f) 52 private val RANGE_0_120 = RefreshRateRange(0f, 120f) 53 private val RANGE_60_90 = RefreshRateRange(60f, 90f) 54 private val RANGE_60_120 = RefreshRateRange(60f, 120f) 55 private val RANGE_60_INF = RefreshRateRange(60f, Float.POSITIVE_INFINITY) 56 private val RANGE_90_90 = RefreshRateRange(90f, 90f) 57 private val RANGE_90_120 = RefreshRateRange(90f, 120f) 58 private val RANGE_90_INF = RefreshRateRange(90f, Float.POSITIVE_INFINITY) 59 60 private val RANGES_NO_LIMIT = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_NO_LIMIT) 61 private val RANGES_NO_LIMIT_60 = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_0_60) 62 private val RANGES_NO_LIMIT_90 = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_0_90) 63 private val RANGES_NO_LIMIT_120 = RefreshRateRanges(RANGE_NO_LIMIT, RANGE_0_120) 64 private val RANGES_90 = RefreshRateRanges(RANGE_0_90, RANGE_0_90) 65 private val RANGES_120 = RefreshRateRanges(RANGE_0_120, RANGE_0_120) 66 private val RANGES_90_60 = RefreshRateRanges(RANGE_0_90, RANGE_0_60) 67 private val RANGES_90TO90 = RefreshRateRanges(RANGE_90_90, RANGE_90_90) 68 private val RANGES_90TO120 = RefreshRateRanges(RANGE_90_120, RANGE_90_120) 69 private val RANGES_60TO120_60TO90 = RefreshRateRanges(RANGE_60_120, RANGE_60_90) 70 private val RANGES_MIN90 = RefreshRateRanges(RANGE_90_INF, RANGE_90_INF) 71 private val RANGES_MIN90_90TO120 = RefreshRateRanges(RANGE_90_INF, RANGE_90_120) 72 private val RANGES_MIN60_60TO90 = RefreshRateRanges(RANGE_60_INF, RANGE_60_90) 73 private val RANGES_MIN90_90TO90 = RefreshRateRanges(RANGE_90_INF, RANGE_90_90) 74 75 private val LOW_POWER_GLOBAL_VOTE = Vote.forRenderFrameRates(0f, 60f) 76 private val LOW_POWER_REFRESH_RATE_DATA = createRefreshRateData( 77 lowPowerSupportedModes = listOf(SupportedModeData(60f, 60f), SupportedModeData(60f, 240f))) 78 private val LOW_POWER_EMPTY_REFRESH_RATE_DATA = createRefreshRateData() 79 private val EXPECTED_SUPPORTED_MODES_VOTE = SupportedRefreshRatesVote( 80 listOf(RefreshRates(60f, 60f), RefreshRates(60f, 240f))) 81 82 @SmallTest 83 @RunWith(TestParameterInjector::class) 84 class SettingsObserverTest { 85 @get:Rule 86 val mockitoRule = MockitoJUnit.rule() 87 88 @get:Rule 89 val settingsProviderRule = FakeSettingsProvider.rule() 90 91 private lateinit var spyContext: Context 92 private val mockInjector = mock<DisplayModeDirector.Injector>() 93 private val mockFlags = mock<DisplayManagerFlags>() 94 private val mockDeviceConfig = mock<DisplayDeviceConfig>() 95 private val mockDisplayDeviceConfigProvider = mock<DisplayDeviceConfigProvider>() 96 97 private val testHandler = TestHandler(null) 98 99 @Before setUpnull100 fun setUp() { 101 spyContext = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) 102 } 103 104 @Test test low power modenull105 fun `test low power mode`(@TestParameter testCase: LowPowerTestCase) { 106 whenever(mockFlags.isVsyncLowPowerVoteEnabled).thenReturn(testCase.vsyncLowPowerVoteEnabled) 107 whenever(spyContext.contentResolver) 108 .thenReturn(settingsProviderRule.mockContentResolver(null)) 109 val lowPowerModeSetting = if (testCase.lowPowerModeEnabled) 1 else 0 110 Settings.Global.putInt( 111 spyContext.contentResolver, Settings.Global.LOW_POWER_MODE, lowPowerModeSetting) 112 113 val displayModeDirector = DisplayModeDirector( 114 spyContext, testHandler, mockInjector, mockFlags, mockDisplayDeviceConfigProvider) 115 val ddcByDisplay = SparseArray<DisplayDeviceConfig>() 116 whenever(mockDeviceConfig.refreshRateData).thenReturn(testCase.refreshRateData) 117 ddcByDisplay.put(Display.DEFAULT_DISPLAY, mockDeviceConfig) 118 displayModeDirector.injectDisplayDeviceConfigByDisplay(ddcByDisplay) 119 val settingsObserver = displayModeDirector.SettingsObserver( 120 spyContext, testHandler, mockFlags) 121 122 settingsObserver.onChange( 123 false, Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), 1) 124 125 assertThat(displayModeDirector.getVote(VotesStorage.GLOBAL_ID, 126 Vote.PRIORITY_LOW_POWER_MODE_RENDER_RATE)).isEqualTo(testCase.globalVote) 127 assertThat(displayModeDirector.getVote(Display.DEFAULT_DISPLAY, 128 Vote.PRIORITY_LOW_POWER_MODE_MODES)).isEqualTo(testCase.displayVote) 129 } 130 131 enum class LowPowerTestCase( 132 val refreshRateData: RefreshRateData, 133 val vsyncLowPowerVoteEnabled: Boolean, 134 val lowPowerModeEnabled: Boolean, 135 internal val globalVote: Vote?, 136 internal val displayVote: Vote? 137 ) { 138 ALL_ENABLED(LOW_POWER_REFRESH_RATE_DATA, true, true, 139 LOW_POWER_GLOBAL_VOTE, EXPECTED_SUPPORTED_MODES_VOTE), 140 LOW_POWER_OFF(LOW_POWER_REFRESH_RATE_DATA, true, false, 141 null, null), 142 EMPTY_REFRESH_LOW_POWER_ON(LOW_POWER_EMPTY_REFRESH_RATE_DATA, true, true, 143 LOW_POWER_GLOBAL_VOTE, null), 144 EMPTY_REFRESH__LOW_POWER_OFF(LOW_POWER_EMPTY_REFRESH_RATE_DATA, true, false, 145 null, null), 146 VSYNC_VOTE_DISABLED_SUPPORTED_LOW_POWER_ON(LOW_POWER_REFRESH_RATE_DATA, false, true, 147 LOW_POWER_GLOBAL_VOTE, null), 148 VSYNC_VOTE_DISABLED_LOW_POWER_OFF(LOW_POWER_REFRESH_RATE_DATA, false, false, 149 null, null), 150 } 151 152 @Test test settings refresh ratesnull153 fun `test settings refresh rates`(@TestParameter testCase: SettingsRefreshRateTestCase) { 154 whenever(mockFlags.isPeakRefreshRatePhysicalLimitEnabled) 155 .thenReturn(testCase.peakRefreshRatePhysicalLimitEnabled) 156 157 val displayModeDirector = DisplayModeDirector( 158 spyContext, testHandler, mockInjector, mockFlags, mockDisplayDeviceConfigProvider) 159 160 val modes = arrayOf( 161 Display.Mode(1, 1000, 1000, 60f), 162 Display.Mode(2, 1000, 1000, 90f), 163 Display.Mode(3, 1000, 1000, 120f) 164 ) 165 displayModeDirector.injectSupportedModesByDisplay(SparseArray<Array<Display.Mode>>().apply { 166 append(Display.DEFAULT_DISPLAY, modes) 167 }) 168 displayModeDirector.injectDefaultModeByDisplay(SparseArray<Display.Mode>().apply { 169 append(Display.DEFAULT_DISPLAY, modes[0]) 170 }) 171 172 val specs = displayModeDirector.getDesiredDisplayModeSpecsWithInjectedFpsSettings( 173 testCase.minRefreshRate, testCase.peakRefreshRate, testCase.defaultRefreshRate) 174 175 assertWithMessage("Primary RefreshRateRanges: ") 176 .that(specs.primary).isEqualTo(testCase.expectedPrimaryRefreshRateRanges) 177 assertWithMessage("App RefreshRateRanges: ") 178 .that(specs.appRequest).isEqualTo(testCase.expectedAppRefreshRateRanges) 179 } 180 181 /** 182 * Votes considered: 183 * priority: PRIORITY_USER_SETTING_PEAK_REFRESH_RATE (also used for appRanged) 184 * condition: peakRefreshRatePhysicalLimitEnabled, peakRR > 0 185 * vote: physical(minRR, peakRR) 186 * 187 * priority: PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE (also used for appRanged) 188 * condition: peakRR > 0 189 * vote: render(minRR, peakRR) 190 * 191 * priority: PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE 192 * condition: - 193 * vote: render(minRR, INF) 194 * 195 * priority: PRIORITY_DEFAULT_RENDER_FRAME_RATE 196 * condition: defaultRR > 0 197 * vote: render(0, defaultRR) 198 * 199 * 0 considered not set 200 * 201 * For this test: 202 * primary physical rate: 203 * (minRR, peakRefreshRatePhysicalLimitEnabled ? max(minRR, peakRR) : INF) 204 * primary render rate : (minRR, min(defaultRR, max(minRR, peakRR))) 205 * 206 * app physical rate: (0, peakRefreshRatePhysicalLimitEnabled ? max(minRR, peakRR) : INF) 207 * app render rate: (0, max(minRR, peakRR)) 208 */ 209 enum class SettingsRefreshRateTestCase( 210 val minRefreshRate: Float, 211 val peakRefreshRate: Float, 212 val defaultRefreshRate: Float, 213 val peakRefreshRatePhysicalLimitEnabled: Boolean, 214 val expectedPrimaryRefreshRateRanges: RefreshRateRanges, 215 val expectedAppRefreshRateRanges: RefreshRateRanges, 216 ) { 217 NO_LIMIT(0f, 0f, 0f, false, RANGES_NO_LIMIT, RANGES_NO_LIMIT), 218 NO_LIMIT_WITH_PHYSICAL_RR(0f, 0f, 0f, true, RANGES_NO_LIMIT, RANGES_NO_LIMIT), 219 220 LIMITS_0_0_90(0f, 0f, 90f, false, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT), 221 LIMITS_0_0_90_WITH_PHYSICAL_RR(0f, 0f, 90f, true, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT), 222 223 LIMITS_0_90_0(0f, 90f, 0f, false, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT_90), 224 LIMITS_0_90_0_WITH_PHYSICAL_RR(0f, 90f, 0f, true, RANGES_90, RANGES_90), 225 226 LIMITS_0_90_60(0f, 90f, 60f, false, RANGES_NO_LIMIT_60, RANGES_NO_LIMIT_90), 227 LIMITS_0_90_60_WITH_PHYSICAL_RR(0f, 90f, 60f, true, RANGES_90_60, RANGES_90), 228 229 LIMITS_0_90_120(0f, 90f, 120f, false, RANGES_NO_LIMIT_90, RANGES_NO_LIMIT_90), 230 LIMITS_0_90_120_WITH_PHYSICAL_RR(0f, 90f, 120f, true, RANGES_90, RANGES_90), 231 232 LIMITS_90_0_0(90f, 0f, 0f, false, RANGES_MIN90, RANGES_NO_LIMIT), 233 LIMITS_90_0_0_WITH_PHYSICAL_RR(90f, 0f, 0f, true, RANGES_MIN90, RANGES_NO_LIMIT), 234 235 LIMITS_90_0_120(90f, 0f, 120f, false, RANGES_MIN90_90TO120, RANGES_NO_LIMIT), 236 LIMITS_90_0_120_WITH_PHYSICAL_RR(90f, 237 0f, 238 120f, 239 true, 240 RANGES_MIN90_90TO120, 241 RANGES_NO_LIMIT), 242 243 LIMITS_90_0_60(90f, 0f, 60f, false, RANGES_MIN90, RANGES_NO_LIMIT), 244 LIMITS_90_0_60_WITH_PHYSICAL_RR(90f, 0f, 60f, true, RANGES_MIN90, RANGES_NO_LIMIT), 245 246 LIMITS_90_120_0(90f, 120f, 0f, false, RANGES_MIN90_90TO120, RANGES_NO_LIMIT_120), 247 LIMITS_90_120_0_WITH_PHYSICAL_RR(90f, 120f, 0f, true, RANGES_90TO120, RANGES_120), 248 249 LIMITS_90_60_0(90f, 60f, 0f, false, RANGES_MIN90_90TO90, RANGES_NO_LIMIT_90), 250 LIMITS_90_60_0_WITH_PHYSICAL_RR(90f, 60f, 0f, true, RANGES_90TO90, RANGES_90), 251 252 LIMITS_60_120_90(60f, 120f, 90f, false, RANGES_MIN60_60TO90, RANGES_NO_LIMIT_120), 253 LIMITS_60_120_90_WITH_PHYSICAL_RR(60f, 120f, 90f, true, RANGES_60TO120_60TO90, RANGES_120), 254 } 255 }