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