1 /* 2 * Copyright (C) 2011 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.view.cts; 18 19 import static org.junit.Assert.assertTrue; 20 import static org.junit.Assume.assumeTrue; 21 22 import android.Manifest; 23 import android.content.Context; 24 import android.hardware.display.DisplayManager; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.SystemClock; 28 import android.platform.test.annotations.AppModeSdkSandbox; 29 import android.util.Log; 30 import android.view.Display; 31 import android.view.WindowManager; 32 33 import androidx.test.filters.LargeTest; 34 import androidx.test.platform.app.InstrumentationRegistry; 35 import androidx.test.rule.ActivityTestRule; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 39 import com.android.cts.display.DisplayUtilKt; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Rule; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 47 import java.util.concurrent.CountDownLatch; 48 import java.util.concurrent.TimeUnit; 49 50 /** 51 * Test that the screen refresh rate claimed by 52 * android.view.Display.getRefreshRate() matches the steady-state framerate 53 * achieved by vsync-limited eglSwapBuffers(). The primary goal is to test 54 * Display.getRefreshRate() -- using GL is just an easy and hopefully reliable 55 * way of measuring the actual refresh rate. 56 */ 57 @LargeTest 58 @RunWith(AndroidJUnit4.class) 59 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 60 public class DisplayRefreshRateTest { 61 // The test passes if 62 // abs(measured_fps - Display.getRefreshRate()) <= FPS_TOLERANCE. 63 // A smaller tolerance requires a more accurate measured_fps in order 64 // to avoid false negatives. 65 private static final float FPS_TOLERANCE = 2.0f; 66 67 private static final String TAG = "DisplayRefreshRateTest"; 68 69 private DisplayManager mDisplayManager; 70 71 private Display mDisplay; 72 73 private int mInitialMatchContentFrameRate; 74 75 private final DisplayListener mDisplayListener = new DisplayListener(); 76 77 private DisplayRefreshRateCtsActivity mActivity; 78 private DisplayRefreshRateCtsActivity.FpsResult mFpsResult; 79 80 @Rule(order = 1) 81 public ActivityTestRule<DisplayRefreshRateCtsActivity> mActivityRule = 82 new ActivityTestRule<>(DisplayRefreshRateCtsActivity.class); 83 84 @Rule(order = 0) 85 public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( 86 InstrumentationRegistry.getInstrumentation().getUiAutomation(), 87 Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS, 88 Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE, 89 Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX); 90 91 class DisplayListener implements DisplayManager.DisplayListener { 92 private CountDownLatch mCountDownLatch = new CountDownLatch(1); 93 waitForModeToChange(int modeId)94 void waitForModeToChange(int modeId) throws InterruptedException { 95 while (modeId != mDisplay.getMode().getModeId() 96 && mDisplay.getMode().getRefreshRate() != mDisplay.getRefreshRate()) { 97 mCountDownLatch.await(5, TimeUnit.SECONDS); 98 } 99 } 100 101 @Override onDisplayAdded(int displayId)102 public void onDisplayAdded(int displayId) { 103 104 } 105 106 @Override onDisplayRemoved(int displayId)107 public void onDisplayRemoved(int displayId) { 108 109 } 110 111 @Override onDisplayChanged(int displayId)112 public void onDisplayChanged(int displayId) { 113 if (displayId != mDisplay.getDisplayId()) { 114 return; 115 } 116 117 mCountDownLatch.countDown(); 118 } 119 } 120 121 122 @Before setup()123 public void setup() throws InterruptedException { 124 mActivity = mActivityRule.getActivity(); 125 mFpsResult = mActivity.getFpsResult(); 126 127 Context context = mActivity.getApplicationContext(); 128 mDisplayManager = context.getSystemService(DisplayManager.class); 129 assumeTrue(DisplayUtilKt.validateOnlyDefaultDisplayOn(mDisplayManager, TAG)); 130 131 mInitialMatchContentFrameRate = 132 toSwitchingType(mDisplayManager.getMatchContentFrameRateUserPreference()); 133 mDisplayManager.setRefreshRateSwitchingType(DisplayManager.SWITCHING_TYPE_NONE); 134 mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true); 135 136 // This tests the fps of the default display. 137 // In consideration of multi-display devices we use getApplicationContext() 138 // to get the default display. 139 WindowManager wm = context.getSystemService(WindowManager.class); 140 mDisplay = wm.getDefaultDisplay(); 141 142 mDisplayManager.registerDisplayListener(mDisplayListener, 143 new Handler(Looper.getMainLooper())); 144 145 int highestRefreshRateModeId = getHighestRefreshRateModeId(); 146 mActivity.setModeId(highestRefreshRateModeId); 147 mDisplayListener.waitForModeToChange(highestRefreshRateModeId); 148 } 149 getHighestRefreshRateModeId()150 private int getHighestRefreshRateModeId() { 151 int highestRefreshRateModeId = mDisplay.getMode().getModeId(); 152 for (Display.Mode mode : mDisplay.getSupportedModes()) { 153 if (mode.getPhysicalHeight() != mDisplay.getMode().getPhysicalHeight()) { 154 continue; 155 } 156 157 if (mode.getPhysicalWidth() != mDisplay.getMode().getPhysicalWidth()) { 158 continue; 159 } 160 161 if (mode.getRefreshRate() > mDisplay.getMode().getRefreshRate()) { 162 highestRefreshRateModeId = mode.getModeId(); 163 } 164 } 165 return highestRefreshRateModeId; 166 } 167 168 @After tearDown()169 public void tearDown() { 170 mDisplayManager.setRefreshRateSwitchingType(mInitialMatchContentFrameRate); 171 mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false); 172 } 173 174 @Test testRefreshRate()175 public void testRefreshRate() { 176 boolean fpsOk = false; 177 178 for (int i = 0; i < 3; i++) { 179 float claimedFps = mDisplay.getRefreshRate(); 180 float achievedFps = mFpsResult.waitResult(); 181 Log.d(TAG, "claimed " + claimedFps + " fps, " + 182 "achieved " + achievedFps + " fps"); 183 fpsOk = Math.abs(claimedFps - achievedFps) <= FPS_TOLERANCE; 184 if (fpsOk) { 185 break; 186 } else { 187 // it could be other activity like bug report capturing for other failures 188 // sleep for a while and re-try 189 SystemClock.sleep(10000); 190 mFpsResult.restart(); 191 } 192 } 193 mActivity.finish(); 194 assertTrue(fpsOk); 195 } 196 toSwitchingType(int matchContentFrameRateUserPreference)197 private static int toSwitchingType(int matchContentFrameRateUserPreference) { 198 switch (matchContentFrameRateUserPreference) { 199 case DisplayManager.MATCH_CONTENT_FRAMERATE_NEVER: 200 return DisplayManager.SWITCHING_TYPE_NONE; 201 case DisplayManager.MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY: 202 return DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; 203 case DisplayManager.MATCH_CONTENT_FRAMERATE_ALWAYS: 204 return DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; 205 default: 206 return -1; 207 } 208 } 209 } 210