• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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