1 /* 2 * Copyright (C) 2016 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.wearable.ime.janktests; 18 19 import android.app.Instrumentation; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.SystemClock; 23 import android.support.test.uiautomator.By; 24 import android.support.test.uiautomator.UiDevice; 25 import android.support.test.uiautomator.UiObject2; 26 import android.support.test.uiautomator.Until; 27 import android.util.Log; 28 29 import junit.framework.Assert; 30 31 import java.io.IOException; 32 33 /** 34 * Helpers for Wear IME Jank Tests 35 */ 36 37 public class IMEJankTestsHelper { 38 39 public static final int LONG_TIMEOUT = 5000; 40 public static final int SHORT_TIMEOUT = 1500; 41 public static final int WFM_EXPECTED_FRAMES = 10; 42 public static final int GFX_EXPECTED_FRAMES = 10; 43 public static final String IME_PACKAGE_NAME = "com.google.android.inputmethod.latin"; 44 private static final String LOG_TAG = IMEJankTestsHelper.class.getSimpleName(); 45 private static final String HOME_INDICATOR = "charging_icon"; 46 private static final String LAUNCHER_VIEW_NAME = "launcher_view"; 47 private static final String CARD_TITLE_NAME = "title"; 48 private static final String IME_BUTTON_NAME = "ime_choice"; 49 private static final String REPLY_BUTTON_TEXT = "Reply"; 50 private static final String REMOTE_INPUT_TEXT = "Quick reply"; 51 private static final String REMOTE_INPUT_PACKAGE_NAME = 52 "com.google.android.wearable.app"; 53 private static final String RELOAD_NOTIFICATION_CARD_INTENT = "com.google.android.wearable." 54 + "support.wearnotificationgenerator.SHOW_NOTIFICATION"; 55 private static final String KEYBOARD_ID = 56 "com.google.android.inputmethod.latin/com.google.android.apps.inputmethod.wear.WearIME"; 57 private static final String HANDWRITING_ID = "com.google.android.apps.handwriting.ime/" 58 + "com.google.android.wearable.input.handwriting.HandwriterInputMethodService"; 59 private static final String SET_IME_CMD = "ime set %s"; 60 private static final String ENABLE_IME_CMD = "ime enable %s"; 61 private static final String INPUT_BOX_PACKAGE_NAME = 62 "com.google.android.wearable.input.latin.activity"; 63 private static IMEJankTestsHelper mInstance; 64 private UiDevice mDevice; 65 private Instrumentation mInstrumentation; 66 67 private IMEJankTestsHelper(UiDevice device, Instrumentation instrumentation) { 68 mDevice = device; 69 mInstrumentation = instrumentation; 70 } 71 72 public static IMEJankTestsHelper getInstance(UiDevice device, Instrumentation instrumentation) { 73 if (mInstance == null) { 74 mInstance = new IMEJankTestsHelper(device, instrumentation); 75 } 76 return mInstance; 77 } 78 79 public void swipeUp() { 80 mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2 + 50, 81 mDevice.getDisplayWidth() / 2, 0, 30); // slow speed 82 SystemClock.sleep(SHORT_TIMEOUT); 83 } 84 85 public void swipeRight(int heightOffset) { 86 mDevice.swipe(50, 87 mDevice.getDisplayHeight() / 2 + heightOffset, mDevice.getDisplayWidth() - 25, 88 mDevice.getDisplayHeight() / 2 + heightOffset, 30); // slow speed 89 SystemClock.sleep(SHORT_TIMEOUT); 90 } 91 92 // Helper function to go back to home screen 93 public void goBackHome() { 94 String launcherPackage = mDevice.getLauncherPackageName(); 95 UiObject2 homeScreen = mDevice.findObject(By.res(launcherPackage, HOME_INDICATOR)); 96 int count = 0; 97 while (homeScreen == null && count < 5) { 98 mDevice.pressBack(); 99 Log.d(LOG_TAG, "Pressed back"); 100 homeScreen = mDevice.findObject(By.res(launcherPackage, HOME_INDICATOR)); 101 count++; 102 } 103 104 // TODO (yuanlang@) Delete the following hacky codes after charging icon issue fixed 105 // App launcher still draw changing icon. Make sure we're not in the launcher 106 homeScreen = mDevice.findObject(By.res(launcherPackage, LAUNCHER_VIEW_NAME)); 107 if (homeScreen != null) { 108 mDevice.pressBack(); 109 } 110 111 SystemClock.sleep(SHORT_TIMEOUT); 112 } 113 114 public void launchRemoteInputActivity() { 115 String launcherPackage = mDevice.getLauncherPackageName(); 116 // Swipe up 5 times to bring up demo cards 117 // in case there are some real cards on top 118 reloadDemoCards(); 119 int i = 0; 120 UiObject2 cardTitle = null; 121 while (i < 5) { 122 swipeUp(); 123 cardTitle = mDevice.wait( 124 Until.findObject(By.text("Clockwork Notifications-10")), SHORT_TIMEOUT); 125 if (cardTitle != null) { 126 cardTitle.click(); 127 break; 128 } 129 i ++; 130 } 131 Assert.assertNotNull("Cannot find demo card with remote input", cardTitle); 132 // Click on reply action button 133 UiObject2 replyButton = mDevice 134 .wait(Until.findObject(By.text(REPLY_BUTTON_TEXT)), LONG_TIMEOUT); 135 Assert.assertNotNull(replyButton); 136 replyButton.click(); 137 138 // Make sure remote input activity launched 139 UiObject2 replyText = mDevice 140 .wait(Until.findObject(By.text(REMOTE_INPUT_TEXT)), LONG_TIMEOUT); 141 Assert.assertNotNull(replyText); 142 } 143 144 public void launchInputBoxActivity() { 145 Context context = mInstrumentation.getContext(); 146 Intent intent = context.getPackageManager() 147 .getLaunchIntentForPackage(INPUT_BOX_PACKAGE_NAME); 148 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 149 context.startActivity(intent); 150 Assert.assertTrue("Input box activity not started", 151 mDevice.wait(Until.hasObject(By.pkg(INPUT_BOX_PACKAGE_NAME).depth(0)), 152 LONG_TIMEOUT)); 153 } 154 155 public void tapIMEButton() { 156 UiObject2 imeButton = mDevice.wait( 157 Until.findObject(By.res(REMOTE_INPUT_PACKAGE_NAME, IME_BUTTON_NAME)), LONG_TIMEOUT); 158 Assert.assertNotNull(imeButton); 159 imeButton.click(); 160 SystemClock.sleep(SHORT_TIMEOUT); 161 } 162 163 // This will ensure to reload notification cards by launching NotificationsGeneratorWear app 164 // when there are insufficient cards. 165 private void reloadDemoCards() { 166 Intent intent = new Intent(); 167 intent.setAction(RELOAD_NOTIFICATION_CARD_INTENT); 168 mInstrumentation.getContext().sendBroadcast(intent); 169 Log.d(LOG_TAG, "Demo cards have been reloaded"); 170 SystemClock.sleep(LONG_TIMEOUT); 171 } 172 173 public void activateIMEKeyboard() { 174 try { 175 mDevice.executeShellCommand(String.format(ENABLE_IME_CMD, KEYBOARD_ID)); 176 mDevice.executeShellCommand(String.format(SET_IME_CMD, KEYBOARD_ID)); 177 } catch (IOException e) { 178 Log.e(LOG_TAG, e.toString()); 179 } 180 Log.d(LOG_TAG, "Keyboard activated"); 181 } 182 183 public void activateIMEHandwriting() { 184 try { 185 mDevice.executeShellCommand(String.format(ENABLE_IME_CMD, HANDWRITING_ID)); 186 mDevice.executeShellCommand(String.format(SET_IME_CMD, HANDWRITING_ID)); 187 } catch (IOException e) { 188 Log.e(LOG_TAG, e.toString()); 189 } 190 Log.d(LOG_TAG, "Handwriting activated"); 191 } 192 193 public void pressBack() { 194 mDevice.pressBack(); 195 SystemClock.sleep(SHORT_TIMEOUT); 196 } 197 198 public void tapOnScreen() { 199 mDevice.click(mDevice.getDisplayHeight() / 2, mDevice.getDisplayWidth() / 2); 200 SystemClock.sleep(SHORT_TIMEOUT); 201 } 202 203 public void clickSoftKey(String softKeyDescription) { 204 UiObject2 softKey = mDevice.wait( 205 Until.findObject(By.res(IME_PACKAGE_NAME, keyPosIdByDesc(softKeyDescription))), 206 SHORT_TIMEOUT); 207 Assert.assertNotNull("Soft Key " + softKeyDescription + " not found in UI", softKey); 208 softKey.click(); 209 } 210 211 private String keyPosIdByDesc(String desc) { 212 return String.format("key_pos_%s", desc); 213 } 214 }