1 /* 2 * Copyright (C) 2015 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.jankmicrobenchmark.janktests; 18 19 import android.content.Intent; 20 import android.os.Bundle; 21 import android.os.SystemClock; 22 import android.support.test.launcherhelper.LauncherStrategyFactory; 23 import android.support.test.uiautomator.By; 24 import android.support.test.uiautomator.Direction; 25 import android.support.test.uiautomator.UiDevice; 26 import android.support.test.uiautomator.UiObject2; 27 import android.support.test.uiautomator.UiObjectNotFoundException; 28 import android.support.test.uiautomator.Until; 29 import android.widget.Button; 30 31 import androidx.test.jank.GfxMonitor; 32 import androidx.test.jank.JankTest; 33 import androidx.test.jank.JankTestBase; 34 35 import junit.framework.Assert; 36 37 /** 38 * Jank micro benchmark tests 39 * App : ApiDemos 40 */ 41 42 public class ApiDemoJankTests extends JankTestBase { 43 private static final int LONG_TIMEOUT = 5000; 44 private static final int SHORT_TIMEOUT = 500; 45 private static final int INNER_LOOP = 5; 46 private static final int EXPECTED_FRAMES = 100; 47 private static final String PACKAGE_NAME = "com.example.android.apis"; 48 private static final String RES_PACKAGE_NAME = "android"; 49 private static final String LEANBACK_LAUNCHER = "com.google.android.leanbacklauncher"; 50 private UiDevice mDevice; 51 private UiObject2 mListView; 52 53 @Override setUp()54 public void setUp() throws Exception { 55 super.setUp(); 56 mDevice = UiDevice.getInstance(getInstrumentation()); 57 mDevice.setOrientationNatural(); 58 LauncherStrategyFactory.getInstance(mDevice).getLauncherStrategy().open(); 59 } 60 61 @Override tearDown()62 protected void tearDown() throws Exception { 63 mDevice.unfreezeRotation(); 64 super.tearDown(); 65 } 66 67 // This method distinguishes between home screen for handheld devices 68 // and home screen for Android TV, both of whom have different Home elements. getHomeScreen()69 public UiObject2 getHomeScreen() throws UiObjectNotFoundException { 70 if (mDevice.getProductName().equals("fugu")) { 71 return mDevice.wait(Until.findObject(By.res(LEANBACK_LAUNCHER, "main_list_view")), 72 LONG_TIMEOUT); 73 } 74 else { 75 String launcherPackage = mDevice.getLauncherPackageName(); 76 return mDevice.wait(Until.findObject(By.res(launcherPackage,"workspace")), 77 LONG_TIMEOUT); 78 } 79 } 80 launchApiDemos()81 public void launchApiDemos() throws UiObjectNotFoundException { 82 UiObject2 homeScreen = getHomeScreen(); 83 if (homeScreen == null) 84 navigateToHome(); 85 Intent intent = getInstrumentation().getContext().getPackageManager() 86 .getLaunchIntentForPackage(PACKAGE_NAME); 87 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 88 getInstrumentation().getContext().startActivity(intent); 89 mDevice.waitForIdle(); 90 } 91 selectAnimation(String optionName)92 public void selectAnimation(String optionName) throws UiObjectNotFoundException { 93 launchApiDemos(); 94 UiObject2 animation = mDevice.wait(Until.findObject( 95 By.res(RES_PACKAGE_NAME, "text1").text("Animation")), LONG_TIMEOUT); 96 Assert.assertNotNull("Animation isn't found in ApiDemos", animation); 97 animation.click(); 98 UiObject2 option = mDevice.wait(Until.findObject( 99 By.res(RES_PACKAGE_NAME, "text1").text(optionName)), LONG_TIMEOUT); 100 int maxAttempt = 3; 101 while (option == null && maxAttempt > 0) { 102 mDevice.wait(Until.findObject(By.res(RES_PACKAGE_NAME, "content")), LONG_TIMEOUT) 103 .scroll(Direction.DOWN, 1.0f); 104 option = mDevice.wait(Until.findObject(By.res(RES_PACKAGE_NAME, "text1") 105 .text(optionName)), LONG_TIMEOUT); 106 --maxAttempt; 107 } 108 Assert.assertNotNull("Target option in APiDemos animation for test isn't found", option); 109 option.click(); 110 } 111 112 // Since afterTest only runs when the test has passed, there's no way of going 113 // back to the Home Screen if a test fails. This method is a workaround. A feature 114 // request has been filed to have a per test tearDown method - b/25673300 navigateToHome()115 public void navigateToHome() throws UiObjectNotFoundException { 116 UiObject2 homeScreen = getHomeScreen(); 117 int count = 0; 118 while (homeScreen == null && count <= 10) { 119 mDevice.pressBack(); 120 homeScreen = getHomeScreen(); 121 count++; 122 } 123 Assert.assertNotNull("Hit maximum retries and couldn't find Home Screen", homeScreen); 124 } 125 126 // Since the app doesn't start at the first page when reloaded after the first time, 127 // ensuring that we head back to the first screen before going Home so we're always 128 // on screen one. goBackHome(Bundle metrics)129 public void goBackHome(Bundle metrics) throws UiObjectNotFoundException { 130 navigateToHome(); 131 super.afterTest(metrics); 132 } 133 134 // Loads the 'activity transition' animation selectActivityTransitionAnimation()135 public void selectActivityTransitionAnimation() throws UiObjectNotFoundException { 136 selectAnimation("Activity Transition"); 137 } 138 139 // Measures jank for activity transition animation 140 @JankTest(beforeTest="selectActivityTransitionAnimation", afterTest="goBackHome", 141 expectedFrames=EXPECTED_FRAMES) 142 @GfxMonitor(processName=PACKAGE_NAME) testActivityTransitionAnimation()143 public void testActivityTransitionAnimation() { 144 for (int i = 0; i < INNER_LOOP; i++) { 145 UiObject2 redBallTile = mDevice.wait(Until.findObject(By.res(PACKAGE_NAME, "ball")), 146 LONG_TIMEOUT); 147 redBallTile.click(); 148 SystemClock.sleep(LONG_TIMEOUT); 149 mDevice.pressBack(); 150 } 151 } 152 153 // Loads the 'view flip' animation selectViewFlipAnimation()154 public void selectViewFlipAnimation() throws UiObjectNotFoundException { 155 selectAnimation("View Flip"); 156 } 157 158 // Measures jank for view flip animation 159 @JankTest(beforeTest="selectViewFlipAnimation", afterTest="goBackHome", 160 expectedFrames=EXPECTED_FRAMES) 161 @GfxMonitor(processName=PACKAGE_NAME) testViewFlipAnimation()162 public void testViewFlipAnimation() { 163 for (int i = 0; i < INNER_LOOP; i++) { 164 UiObject2 flipButton = mDevice.findObject(By.res(PACKAGE_NAME, "button")); 165 flipButton.click(); 166 SystemClock.sleep(LONG_TIMEOUT); 167 } 168 } 169 170 // Loads the 'cloning' animation selectCloningAnimation()171 public void selectCloningAnimation() throws UiObjectNotFoundException { 172 selectAnimation("Cloning"); 173 } 174 175 // Measures jank for cloning animation 176 @JankTest(beforeTest="selectCloningAnimation", afterTest="goBackHome", 177 expectedFrames=EXPECTED_FRAMES) 178 @GfxMonitor(processName=PACKAGE_NAME) testCloningAnimation()179 public void testCloningAnimation() { 180 for (int i = 0; i < INNER_LOOP; i++) { 181 UiObject2 runCloningButton = mDevice.findObject(By.res(PACKAGE_NAME, "startButton")); 182 runCloningButton.click(); 183 SystemClock.sleep(LONG_TIMEOUT); 184 } 185 } 186 187 // Loads the 'loading' animation selectLoadingOption()188 public void selectLoadingOption() throws UiObjectNotFoundException { 189 selectAnimation("Loading"); 190 } 191 192 // Measures jank for 'loading' animation 193 @JankTest(beforeTest="selectLoadingOption", afterTest="goBackHome", 194 expectedFrames=EXPECTED_FRAMES) 195 @GfxMonitor(processName=PACKAGE_NAME) testLoadingJank()196 public void testLoadingJank() { 197 UiObject2 runButton = mDevice.wait(Until.findObject( 198 By.res(PACKAGE_NAME, "startButton").text("RUN")), LONG_TIMEOUT); 199 Assert.assertNotNull("Run button is null", runButton); 200 for (int i = 0; i < INNER_LOOP; i++) { 201 runButton.click(); 202 SystemClock.sleep(SHORT_TIMEOUT * 2); 203 } 204 } 205 206 // Loads the 'simple transition' animation selectSimpleTransitionOption()207 public void selectSimpleTransitionOption() throws UiObjectNotFoundException { 208 selectAnimation("Simple Transitions"); 209 } 210 211 // Measures jank for 'simple transition' animation 212 @JankTest(beforeTest="selectSimpleTransitionOption", afterTest="goBackHome", 213 expectedFrames=EXPECTED_FRAMES) 214 @GfxMonitor(processName=PACKAGE_NAME) testSimpleTransitionJank()215 public void testSimpleTransitionJank() { 216 for (int i = 0; i < INNER_LOOP; i++) { 217 UiObject2 scene2 = mDevice.wait(Until.findObject( 218 By.res(PACKAGE_NAME, "scene2")), LONG_TIMEOUT); 219 Assert.assertNotNull("Scene2 button can't be found", scene2); 220 scene2.click(); 221 SystemClock.sleep(SHORT_TIMEOUT); 222 223 UiObject2 scene1 = mDevice.wait(Until.findObject( 224 By.res(PACKAGE_NAME, "scene1")), LONG_TIMEOUT); 225 Assert.assertNotNull("Scene1 button can't be found", scene1); 226 scene1.click(); 227 SystemClock.sleep(SHORT_TIMEOUT); 228 } 229 } 230 231 // Loads the 'hide/show' animation selectHideShowAnimationOption()232 public void selectHideShowAnimationOption() throws UiObjectNotFoundException { 233 selectAnimation("Hide-Show Animations"); 234 } 235 236 // Measures jank for 'hide/show' animation 237 @JankTest(beforeTest="selectHideShowAnimationOption", afterTest="goBackHome", 238 expectedFrames=EXPECTED_FRAMES) 239 @GfxMonitor(processName=PACKAGE_NAME) testHideShowAnimationJank()240 public void testHideShowAnimationJank() { 241 for (int i = 0; i < INNER_LOOP; i++) { 242 UiObject2 showButton = mDevice.wait(Until.findObject(By.res( 243 PACKAGE_NAME, "addNewButton").text("SHOW BUTTONS")), LONG_TIMEOUT); 244 Assert.assertNotNull("'Show Buttons' button can't be found", showButton); 245 showButton.click(); 246 SystemClock.sleep(SHORT_TIMEOUT); 247 248 UiObject2 button0 = mDevice.wait(Until.findObject( 249 By.clazz(Button.class).text("0")), LONG_TIMEOUT); 250 Assert.assertNotNull("Button0 isn't found", button0); 251 button0.click(); 252 SystemClock.sleep(SHORT_TIMEOUT); 253 254 UiObject2 button1 = mDevice.wait(Until.findObject( 255 By.clazz(Button.class).text("1")), LONG_TIMEOUT); 256 Assert.assertNotNull("Button1 isn't found", button1); 257 button1.click(); 258 SystemClock.sleep(SHORT_TIMEOUT); 259 260 UiObject2 button2 = mDevice.wait(Until.findObject( 261 By.clazz(Button.class).text("2")), LONG_TIMEOUT); 262 Assert.assertNotNull("Button2 isn't found", button2); 263 button2.click(); 264 SystemClock.sleep(SHORT_TIMEOUT); 265 266 UiObject2 button3 = mDevice.wait(Until.findObject( 267 By.clazz(Button.class).text("3")), LONG_TIMEOUT); 268 Assert.assertNotNull("Button3 isn't found", button3); 269 button3.click(); 270 SystemClock.sleep(SHORT_TIMEOUT); 271 } 272 } 273 selectViews(String optionName)274 public void selectViews(String optionName) throws UiObjectNotFoundException { 275 launchApiDemos(); 276 UiObject2 views = null; 277 short maxAttempt = 4; 278 while (views == null && maxAttempt > 0) { 279 views = mDevice.wait(Until.findObject(By.res(RES_PACKAGE_NAME, "text1") 280 .text("Views")), LONG_TIMEOUT); 281 if (views == null) { 282 mDevice.wait(Until.findObject(By.res(RES_PACKAGE_NAME, "content")), LONG_TIMEOUT) 283 .scroll(Direction.DOWN, 1.0f); 284 } 285 --maxAttempt; 286 } 287 Assert.assertNotNull("Views item can't be found", views); 288 views.click(); 289 // Opens selective view (provided as param) from different 'ApiDemos Views' options 290 UiObject2 option = null; 291 maxAttempt = 4; 292 while (option == null && maxAttempt > 0) { 293 option = mDevice.wait(Until.findObject(By.res(RES_PACKAGE_NAME, "text1") 294 .text(optionName)), LONG_TIMEOUT); 295 if (option == null) { 296 mDevice.wait(Until.findObject(By.res(RES_PACKAGE_NAME, "content")), LONG_TIMEOUT) 297 .scroll(Direction.DOWN, 1.0f); 298 } 299 --maxAttempt; 300 } 301 Assert.assertNotNull("Target option to be tested in ApiDemos Views can't be found", option); 302 option.click(); 303 } 304 305 // Loads simple listview selectListsArray()306 public void selectListsArray() throws UiObjectNotFoundException { 307 selectViews("Lists"); 308 UiObject2 array = mDevice.wait(Until.findObject( 309 By.res(RES_PACKAGE_NAME, "text1").text("01. Array")), LONG_TIMEOUT); 310 Assert.assertNotNull("Array listview can't be found", array); 311 array.click(); 312 mListView = mDevice.wait(Until.findObject(By.res( 313 RES_PACKAGE_NAME, "content")), LONG_TIMEOUT); 314 Assert.assertNotNull("Content pane isn't found to move up", mListView); 315 } 316 317 // Measures jank for simple listview fling 318 @JankTest(beforeTest="selectListsArray", afterTest="goBackHome", 319 expectedFrames=EXPECTED_FRAMES) 320 @GfxMonitor(processName=PACKAGE_NAME) testListViewJank()321 public void testListViewJank() { 322 for (int i = 0; i < INNER_LOOP; i++) { 323 mListView.fling(Direction.DOWN); 324 SystemClock.sleep(SHORT_TIMEOUT); 325 mListView.fling(Direction.UP); 326 SystemClock.sleep(SHORT_TIMEOUT); 327 } 328 } 329 330 // Loads simple expandable list view selectExpandableListsSimpleAdapter()331 public void selectExpandableListsSimpleAdapter() throws UiObjectNotFoundException { 332 selectViews("Expandable Lists"); 333 UiObject2 simpleAdapter = mDevice.wait(Until.findObject( 334 By.res(RES_PACKAGE_NAME, "text1").text("3. Simple Adapter")), LONG_TIMEOUT); 335 Assert.assertNotNull("Simple adapter can't be found", simpleAdapter); 336 simpleAdapter.click(); 337 } 338 339 // Measures jank for simple expandable list view expansion 340 // Expansion group1, group3 and group4 arbitrarily selected 341 @JankTest(beforeTest="selectExpandableListsSimpleAdapter", afterTest="goBackHome", 342 expectedFrames=EXPECTED_FRAMES) 343 @GfxMonitor(processName=PACKAGE_NAME) testExapandableListViewJank()344 public void testExapandableListViewJank() { 345 for (int i = 0; i < INNER_LOOP; i++) { 346 UiObject2 group1 = mDevice.wait(Until.findObject(By.res( 347 RES_PACKAGE_NAME, "text1").text("Group 1")), LONG_TIMEOUT); 348 Assert.assertNotNull("Group 1 isn't found to be expanded", group1); 349 group1.click(); 350 SystemClock.sleep(SHORT_TIMEOUT); 351 group1.click(); 352 SystemClock.sleep(SHORT_TIMEOUT); 353 UiObject2 group3 = mDevice.wait(Until.findObject(By.res( 354 RES_PACKAGE_NAME, "text1").text("Group 3")), LONG_TIMEOUT); 355 Assert.assertNotNull("Group 3 isn't found to be expanded", group3); 356 group3.click(); 357 SystemClock.sleep(SHORT_TIMEOUT); 358 group3.click(); 359 SystemClock.sleep(SHORT_TIMEOUT); 360 UiObject2 group4 = mDevice.wait(Until.findObject(By.res( 361 RES_PACKAGE_NAME, "text1").text("Group 4")), LONG_TIMEOUT); 362 Assert.assertNotNull("Group 4 isn't found to be expanded", group4); 363 group4.click(); 364 SystemClock.sleep(SHORT_TIMEOUT); 365 group4.click(); 366 SystemClock.sleep(SHORT_TIMEOUT); 367 UiObject2 content = mDevice.wait(Until.findObject(By.res( 368 RES_PACKAGE_NAME, "content")), LONG_TIMEOUT); 369 Assert.assertNotNull("Content pane isn't found to move up", content); 370 content.fling(Direction.UP); 371 SystemClock.sleep(SHORT_TIMEOUT); 372 } 373 } 374 } 375