• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.androidtv.janktests;
18 
19 import android.os.Bundle;
20 import android.platform.test.utils.DPadUtil;
21 import android.support.test.jank.GfxMonitor;
22 import android.support.test.jank.JankTest;
23 import android.support.test.jank.JankTestBase;
24 import android.support.test.uiautomator.By;
25 import android.support.test.uiautomator.BySelector;
26 import android.support.test.uiautomator.Direction;
27 import android.support.test.uiautomator.UiDevice;
28 import android.support.test.uiautomator.UiObject2;
29 import android.support.test.uiautomator.UiObjectNotFoundException;
30 import android.support.test.uiautomator.Until;
31 import android.util.Log;
32 
33 import junit.framework.Assert;
34 
35 import java.io.IOException;
36 
37 /*
38  * This class contains the tests for Android TV jank.
39  */
40 public class SystemUiJankTests extends JankTestBase {
41 
42     private static final String TAG = SystemUiJankTests.class.getSimpleName();
43     private static final int SHORT_TIMEOUT = 1000;
44     private static final int INNER_LOOP = 4;
45     private static final int INNER_LOOP_SETTINGS = 8;
46     private static final String TVLAUNCHER_PACKAGE = "com.google.android.tvlauncher";
47     private static final String SETTINGS_PACKAGE = "com.android.tv.settings";
48     private static final BySelector SELECTOR_TOP_ROW = By.res(TVLAUNCHER_PACKAGE, "top_row");
49     private UiDevice mDevice;
50     private DPadUtil mDPadUtil;
51 
52     @Override
setUp()53     public void setUp() {
54         mDevice = UiDevice.getInstance(getInstrumentation());
55         mDPadUtil = new DPadUtil(getInstrumentation());
56     }
57 
58     @Override
tearDown()59     protected void tearDown() throws Exception {
60         super.tearDown();
61     }
62 
goHome()63     public void goHome() {
64         mDevice.pressHome();
65         UiObject2 homeScreen = mDevice
66             .wait(Until.findObject(By.res(TVLAUNCHER_PACKAGE, "home_view_container")),
67                 SHORT_TIMEOUT);
68         Assert.assertNotNull("Ensure that Home screen is being displayed", homeScreen);
69     }
70 
goTopRow()71     public void goTopRow() {
72         Assert.assertNotNull(select(SELECTOR_TOP_ROW.hasDescendant(By.focused(true)), Direction.UP,
73                 SHORT_TIMEOUT));
74     }
75 
afterTestHomeScreenNavigation(Bundle metrics)76     public void afterTestHomeScreenNavigation(Bundle metrics) throws IOException {
77         super.afterTest(metrics);
78     }
79 
80     // Measures jank while navigating up and down the Home screen
81     @JankTest(expectedFrames=100, beforeTest = "goHome",
82             afterTest="afterTestHomeScreenNavigation")
83     @GfxMonitor(processName=TVLAUNCHER_PACKAGE)
testHomeScreenNavigation()84     public void testHomeScreenNavigation() throws UiObjectNotFoundException {
85         // We've already verified that Home screen is being displayed.
86         // Navigate up and down the home screen.
87         navigateDownAndUpCurrentScreen(INNER_LOOP);
88     }
89 
90     // Navigates to the Settings button on the Top row
goToSettingsButton()91     public void goToSettingsButton() {
92         // Navigate to Home screen and verify that it is being displayed.
93         goHome();
94         goTopRow();
95         Assert.assertNotNull("Ensure that Settings button is focused",
96             selectBidirect(By.res(TVLAUNCHER_PACKAGE, "settings").focused(true), Direction.RIGHT));
97     }
98 
afterTestSettings(Bundle metrics)99     public void afterTestSettings(Bundle metrics) throws IOException {
100         // Navigate back home
101         goHome();
102         super.afterTest(metrics);
103     }
104 
105     // Measures jank while navigating to Settings from Home and back
106     @JankTest(expectedFrames=100, beforeTest="goToSettingsButton",
107             afterTest="afterTestSettings")
108     @GfxMonitor(processName=SETTINGS_PACKAGE)
testNavigateToSettings()109     public void testNavigateToSettings() throws UiObjectNotFoundException {
110         for (int i = 0; i < INNER_LOOP * 10; i++) {
111             // Press DPad center button to navigate to settings.
112             mDPadUtil.pressDPadCenter();
113             mDevice.wait(Until.hasObject(
114                     By.res(SETTINGS_PACKAGE, "settings_preference_fragment_container")),
115                     SHORT_TIMEOUT);
116             // Press Back button to go back to the Home screen with focus on Settings
117             mDPadUtil.pressBack();
118         }
119     }
120 
121     // Navigates to the Settings Screen
goToSettings()122     public void goToSettings() {
123         goToSettingsButton();
124         mDPadUtil.pressDPadCenter();
125         Assert.assertNotNull("Ensure that Settings is being displayed",
126             mDevice.wait(
127                 Until.hasObject(By.res(SETTINGS_PACKAGE, "settings_preference_fragment_container")),
128                 SHORT_TIMEOUT));
129     }
130 
131     // Measures jank while scrolling on the Settings screen
132     @JankTest(expectedFrames=100, beforeTest="goToSettings",
133             afterTest="afterTestSettings")
134     @GfxMonitor(processName=SETTINGS_PACKAGE)
testSettingsScreenNavigation()135     public void testSettingsScreenNavigation() throws UiObjectNotFoundException {
136         navigateDownAndUpCurrentScreen(INNER_LOOP_SETTINGS);
137     }
138 
navigateDownAndUpCurrentScreen(int iterations)139     public void navigateDownAndUpCurrentScreen(int iterations) {
140         for (int i = 0; i < iterations; i++) {
141             // Press DPad button down eight times in succession
142             mDPadUtil.pressDPadDown();
143         }
144         for (int i = 0; i < iterations; i++) {
145             // Press DPad button up eight times in succession.
146             mDPadUtil.pressDPadUp();
147         }
148     }
149 
150     /**
151      * Select an UI element with given {@link BySelector}. This action keeps moving a focus
152      * in a given {@link Direction} until it finds a matched element.
153      * @param selector the search criteria to match an element
154      * @param direction the direction to find
155      * @param timeoutMs timeout in milliseconds to select
156      * @return a UiObject2 which represents the matched element
157      */
select(BySelector selector, Direction direction, long timeoutMs)158     public UiObject2 select(BySelector selector, Direction direction, long timeoutMs) {
159         UiObject2 focus = mDevice.wait(Until.findObject(By.focused(true)), SHORT_TIMEOUT);
160         while (!mDevice.wait(Until.hasObject(selector), timeoutMs)) {
161             Log.d(TAG, String.format("select: moving a focus from %s to %s", focus, direction));
162             UiObject2 focused = focus;
163             mDPadUtil.pressDPad(direction);
164             focus = mDevice.wait(Until.findObject(By.focused(true)), SHORT_TIMEOUT);
165             // Hack: A focus might be lost in some UI. Take one more step forward.
166             if (focus == null) {
167                 mDPadUtil.pressDPad(direction);
168                 focus = mDevice.wait(Until.findObject(By.focused(true)), SHORT_TIMEOUT);
169             }
170             // Check if it reaches to an end where it no longer moves a focus to next element
171             if (focused.equals(focus)) {
172                 Log.d(TAG, "select: not found until it reaches to an end.");
173                 return null;
174             }
175         }
176         Log.i(TAG, String.format("select: %s is selected", focus));
177         return focus;
178     }
179 
180     /**
181      * Select an element with a given {@link BySelector} in both given direction and reverse.
182      */
selectBidirect(BySelector selector, Direction direction)183     public UiObject2 selectBidirect(BySelector selector, Direction direction) {
184         Log.d(TAG, String.format("selectBidirect [direction]%s", direction));
185         UiObject2 object = select(selector, direction, SHORT_TIMEOUT);
186         if (object == null) {
187             object = select(selector, Direction.reverse(direction), SHORT_TIMEOUT);
188         }
189         return object;
190     }
191 }
192