1 /* 2 * Copyright (C) 2020 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 android.gameframerate.cts; 18 19 import android.Manifest; 20 import android.app.compat.CompatChanges; 21 import android.gameframerate.cts.GameFrameRateCtsActivity.FrameRateObserver; 22 import android.hardware.display.DisplayManager; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.SystemProperties; 26 import android.platform.test.annotations.RequiresFlagsEnabled; 27 import android.platform.test.flag.junit.CheckFlagsRule; 28 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 29 import android.support.test.uiautomator.UiDevice; 30 import android.sysprop.SurfaceFlingerProperties; 31 import android.util.Log; 32 import android.view.Display; 33 import android.view.Window; 34 import android.view.WindowManager; 35 36 import androidx.test.InstrumentationRegistry; 37 import androidx.test.rule.ActivityTestRule; 38 import androidx.test.runner.AndroidJUnit4; 39 40 import org.junit.After; 41 import org.junit.Before; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.io.IOException; 47 import java.util.ArrayList; 48 import java.util.List; 49 50 /** 51 * Tests for frame rate override and the behaviour of {@link Display#getRefreshRate()} and 52 * {@link Display.Mode#getRefreshRate()} Api. 53 */ 54 @RunWith(AndroidJUnit4.class) 55 public final class GameFrameRateTest { 56 private static final String TAG = "GameFrameRateTest"; 57 // See b/170503758 for more details 58 private static final long DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGEID = 170503758; 59 60 private static final String TEST_PKG = "android.gameframerate.cts"; 61 62 @Rule 63 public final CheckFlagsRule mCheckFlagsRule = 64 DeviceFlagsValueProvider.createCheckFlagsRule(); 65 66 // The tolerance within which we consider refresh rates are equal 67 private static final float REFRESH_RATE_TOLERANCE = 0.01f; 68 69 private int mInitialMatchContentFrameRate; 70 private DisplayManager mDisplayManager; 71 private UiDevice mUiDevice; 72 private final Handler mHandler = new Handler(Looper.getMainLooper()); 73 74 private static final int[] refreshRateDivisorsToTest = 75 {120, 110, 100, 90, 80, 70, 60, 50, 40, 30}; 76 77 78 @Rule 79 public ActivityTestRule<GameFrameRateCtsActivity> mActivityRule = 80 new ActivityTestRule<>(GameFrameRateCtsActivity.class); 81 82 @Before setUp()83 public void setUp() throws Exception { 84 mUiDevice = UiDevice.getInstance( 85 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()); 86 mUiDevice.wakeUp(); 87 mUiDevice.executeShellCommand("wm dismiss-keyguard"); 88 mUiDevice.executeShellCommand("device_config put game_overlay" 89 + TEST_PKG + " mode=2:mode=3"); 90 91 InstrumentationRegistry.getInstrumentation().getUiAutomation() 92 .adoptShellPermissionIdentity( 93 Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE, 94 Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS, 95 Manifest.permission.MANAGE_GAME_MODE); 96 97 mDisplayManager = mActivityRule.getActivity().getSystemService(DisplayManager.class); 98 mInitialMatchContentFrameRate = toSwitchingType( 99 mDisplayManager.getMatchContentFrameRateUserPreference()); 100 mDisplayManager.setRefreshRateSwitchingType( 101 DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY); 102 mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true); 103 boolean changeIsEnabled = 104 CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGEID); 105 Log.i(TAG, "DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGEID is " 106 + (changeIsEnabled ? "enabled" : "disabled")); 107 } 108 109 @After tearDown()110 public void tearDown() throws Exception { 111 mUiDevice.executeShellCommand("device_config delete game_overlay " + TEST_PKG); 112 mDisplayManager.setRefreshRateSwitchingType(mInitialMatchContentFrameRate); 113 mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false); 114 InstrumentationRegistry.getInstrumentation().getUiAutomation() 115 .dropShellPermissionIdentity(); 116 } 117 toSwitchingType(int matchContentFrameRateUserPreference)118 private int toSwitchingType(int matchContentFrameRateUserPreference) { 119 switch (matchContentFrameRateUserPreference) { 120 case DisplayManager.MATCH_CONTENT_FRAMERATE_NEVER: 121 return DisplayManager.SWITCHING_TYPE_NONE; 122 case DisplayManager.MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY: 123 return DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; 124 case DisplayManager.MATCH_CONTENT_FRAMERATE_ALWAYS: 125 return DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; 126 default: 127 return -1; 128 } 129 } 130 setMode(Display.Mode mode)131 private void setMode(Display.Mode mode) { 132 Log.i(TAG, "Setting display refresh rate to " + mode.getRefreshRate()); 133 mHandler.post(() -> { 134 Window window = mActivityRule.getActivity().getWindow(); 135 WindowManager.LayoutParams params = window.getAttributes(); 136 params.preferredDisplayModeId = mode.getModeId(); 137 params.preferredRefreshRate = 0; 138 params.preferredMinDisplayRefreshRate = 0; 139 params.preferredMaxDisplayRefreshRate = 0; 140 window.setAttributes(params); 141 }); 142 } 143 144 // The TV emulator is not expected to be a performant device, 145 // so backpressure tests will always fail. isTvEmulator()146 private boolean isTvEmulator() { 147 return SystemProperties.get("ro.build.characteristics").equals("emulator") 148 && SystemProperties.get("ro.product.system.name").equals("atv_generic"); 149 } 150 151 // Find refresh rates with the same resolution. getModesToTest()152 private List<Display.Mode> getModesToTest() { 153 List<Display.Mode> modesWithSameResolution = new ArrayList<>(); 154 if (!SurfaceFlingerProperties.enable_frame_rate_override().orElse(true)) { 155 Log.i(TAG, "Frame rate override is not enabled, skipping"); 156 return modesWithSameResolution; 157 } 158 159 Display.Mode[] modes = mActivityRule.getActivity().getDisplay().getSupportedModes(); 160 Display.Mode currentMode = mActivityRule.getActivity().getDisplay().getMode(); 161 final long currentDisplayHeight = currentMode.getPhysicalHeight(); 162 final long currentDisplayWidth = currentMode.getPhysicalWidth(); 163 164 for (Display.Mode mode : modes) { 165 if (mode.getPhysicalHeight() == currentDisplayHeight 166 && mode.getPhysicalWidth() == currentDisplayWidth) { 167 modesWithSameResolution.add(mode); 168 } 169 } 170 171 return modesWithSameResolution; 172 } 173 testGameModeFrameRateOverride(FrameRateObserver frameRateObserver)174 private void testGameModeFrameRateOverride(FrameRateObserver frameRateObserver) 175 throws InterruptedException, IOException { 176 GameFrameRateCtsActivity activity = mActivityRule.getActivity(); 177 List<Display.Mode> modesToTest = getModesToTest(); 178 179 for (Display.Mode mode : modesToTest) { 180 setMode(mode); 181 activity.testFrameRateOverride( 182 activity.new GameModeTest(mUiDevice), 183 frameRateObserver, mode.getRefreshRate(), refreshRateDivisorsToTest); 184 Log.i(TAG, "\n"); 185 } 186 187 Log.i(TAG, "\n"); 188 } 189 190 @Test 191 @RequiresFlagsEnabled({android.server.app.Flags.FLAG_GAME_DEFAULT_FRAME_RATE, 192 com.android.graphics.surfaceflinger.flags.Flags.FLAG_GAME_DEFAULT_FRAME_RATE}) testGameModeBackpressure()193 public void testGameModeBackpressure() throws InterruptedException, IOException { 194 if (isTvEmulator()) { 195 Log.i(TAG, "**** Skipping Backpressure ****"); 196 return; 197 } 198 199 Log.i(TAG, "**** Starting Game Mode Backpressure Test ****"); 200 GameFrameRateCtsActivity activity = mActivityRule.getActivity(); 201 testGameModeFrameRateOverride(activity.new BackpressureFrameRateObserver()); 202 } 203 204 @Test 205 @RequiresFlagsEnabled({android.server.app.Flags.FLAG_GAME_DEFAULT_FRAME_RATE, 206 com.android.graphics.surfaceflinger.flags.Flags.FLAG_GAME_DEFAULT_FRAME_RATE}) testGameModeChoreographer()207 public void testGameModeChoreographer() throws InterruptedException, IOException { 208 Log.i(TAG, "**** Starting Game Mode Choreographer Test ****"); 209 GameFrameRateCtsActivity activity = mActivityRule.getActivity(); 210 testGameModeFrameRateOverride(activity.new ChoreographerFrameRateObserver()); 211 } 212 213 @Test 214 @RequiresFlagsEnabled({android.server.app.Flags.FLAG_GAME_DEFAULT_FRAME_RATE, 215 com.android.graphics.surfaceflinger.flags.Flags.FLAG_GAME_DEFAULT_FRAME_RATE}) testGameModeDisplayGetRefreshRate()216 public void testGameModeDisplayGetRefreshRate() throws InterruptedException, IOException { 217 Log.i(TAG, "**** Starting Game Mode Display#getRefreshRate Test ****"); 218 GameFrameRateCtsActivity activity = mActivityRule.getActivity(); 219 testGameModeFrameRateOverride(activity.new DisplayGetRefreshRateFrameRateObserver()); 220 } 221 222 @Test 223 @RequiresFlagsEnabled({android.server.app.Flags.FLAG_GAME_DEFAULT_FRAME_RATE, 224 com.android.graphics.surfaceflinger.flags.Flags.FLAG_GAME_DEFAULT_FRAME_RATE}) testGameModeDisplayModeGetRefreshRateDisplayModeReturnsPhysicalRefreshRate()225 public void testGameModeDisplayModeGetRefreshRateDisplayModeReturnsPhysicalRefreshRate() 226 throws InterruptedException, IOException { 227 Log.i(TAG, "**** Starting Game Mode Display.Mode#getRefreshRate Test ****"); 228 GameFrameRateCtsActivity activity = mActivityRule.getActivity(); 229 testGameModeFrameRateOverride( 230 activity.new DisplayModeGetRefreshRateFrameRateObserver()); 231 } 232 } 233