1 /* 2 * Copyright (C) 2018 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.server.wm; 18 19 import static android.server.wm.StateLogger.logE; 20 import static android.view.KeyEvent.KEYCODE_APP_SWITCH; 21 import static android.view.KeyEvent.KEYCODE_MENU; 22 import static android.view.KeyEvent.KEYCODE_SLEEP; 23 import static android.view.KeyEvent.KEYCODE_WAKEUP; 24 import static android.view.KeyEvent.KEYCODE_WINDOW; 25 26 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 27 28 import android.app.DreamManager; 29 import android.app.KeyguardManager; 30 import android.content.Context; 31 import android.graphics.Point; 32 import android.os.PowerManager; 33 import android.os.RemoteException; 34 import android.os.SystemClock; 35 import android.util.Log; 36 import android.view.KeyEvent; 37 38 import androidx.test.uiautomator.UiDevice; 39 40 import com.android.compatibility.common.util.SystemUtil; 41 42 import java.util.function.BooleanSupplier; 43 44 /** 45 * Helper class to interact with {@link UiDevice}. 46 * 47 * All references to {@link UiDevice} and {@link KeyEvent} should be here for easy debugging. 48 */ 49 public class UiDeviceUtils { 50 51 private static final String TAG = "UiDeviceUtils"; 52 private static final boolean DEBUG = false; 53 waitForDeviceIdle(long timeout)54 static void waitForDeviceIdle(long timeout) { 55 if (DEBUG) Log.d(TAG, "waitForDeviceIdle: timeout=" + timeout); 56 getDevice().waitForIdle(timeout); 57 } 58 wakeUpAndUnlock(Context context)59 public static void wakeUpAndUnlock(Context context) { 60 final KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class); 61 final PowerManager powerManager = context.getSystemService(PowerManager.class); 62 final DreamManager dreamManager = context.getSystemService(DreamManager.class); 63 if (keyguardManager == null || powerManager == null) { 64 return; 65 } 66 67 if (keyguardManager.isKeyguardLocked() || !powerManager.isInteractive() 68 || (dreamManager != null 69 && SystemUtil.runWithShellPermissionIdentity(dreamManager::isDreaming))) { 70 pressWakeupButton(); 71 pressUnlockButton(); 72 } 73 } 74 wakeUpDevice()75 public static void wakeUpDevice() throws RemoteException { 76 if (DEBUG) Log.d(TAG, "wakeUpDevice"); 77 getDevice().wakeUp(); 78 } 79 dragPointer(Point from, Point to, int steps)80 public static void dragPointer(Point from, Point to, int steps) { 81 if (DEBUG) Log.d(TAG, "dragPointer: from=" + from + " to=" + to + " steps=" + steps); 82 getDevice().drag(from.x, from.y, to.x, to.y, steps); 83 } 84 pressEnterButton()85 public static void pressEnterButton() { 86 if (DEBUG) Log.d(TAG, "pressEnterButton"); 87 getDevice().pressEnter(); 88 } 89 90 /** 91 * Simulates a pressed event of {@link KeyEvent#KEYCODE_HOME}. Note this will stop app switches 92 * for 5s (see android.permission.STOP_APP_SWITCHES). 93 */ pressHomeButton()94 public static void pressHomeButton() { 95 if (DEBUG) Log.d(TAG, "pressHomeButton"); 96 getDevice().pressHome(); 97 } 98 pressBackButton()99 public static void pressBackButton() { 100 if (DEBUG) Log.d(TAG, "pressBackButton"); 101 getDevice().pressBack(); 102 } 103 pressMenuButton()104 public static void pressMenuButton() { 105 if (DEBUG) Log.d(TAG, "pressMenuButton"); 106 getDevice().pressMenu(); 107 } 108 pressSleepButton()109 public static void pressSleepButton() { 110 if (DEBUG) Log.d(TAG, "pressSleepButton"); 111 final PowerManager pm = getInstrumentation() 112 .getContext().getSystemService(PowerManager.class); 113 retryPressKeyCode(KEYCODE_SLEEP, () -> pm != null && !pm.isInteractive(), 114 "***Waiting for device sleep..."); 115 } 116 pressWakeupButton()117 public static void pressWakeupButton() { 118 if (DEBUG) Log.d(TAG, "pressWakeupButton"); 119 final PowerManager pm = getInstrumentation() 120 .getContext().getSystemService(PowerManager.class); 121 retryPressKeyCode(KEYCODE_WAKEUP, () -> pm != null && pm.isInteractive(), 122 "***Waiting for device wakeup..."); 123 } 124 pressUnlockButton()125 public static void pressUnlockButton() { 126 if (DEBUG) Log.d(TAG, "pressUnlockButton"); 127 final KeyguardManager kgm = getInstrumentation() 128 .getContext().getSystemService(KeyguardManager.class); 129 retryPressKeyCode(KEYCODE_MENU, () -> kgm != null && !kgm.isKeyguardLocked(), 130 "***Waiting for device unlock..."); 131 } 132 pressWindowButton()133 public static void pressWindowButton() { 134 if (DEBUG) Log.d(TAG, "pressWindowButton"); 135 pressKeyCode(KEYCODE_WINDOW); 136 } 137 pressAppSwitchButton()138 public static void pressAppSwitchButton() { 139 if (DEBUG) Log.d(TAG, "pressAppSwitchButton"); 140 pressKeyCode(KEYCODE_APP_SWITCH); 141 } 142 retryPressKeyCode(int keyCode, BooleanSupplier waitFor, String msg)143 private static void retryPressKeyCode(int keyCode, BooleanSupplier waitFor, String msg) { 144 int retry = 1; 145 do { 146 pressKeyCode(keyCode); 147 if (waitFor.getAsBoolean()) { 148 return; 149 } 150 Log.d(TAG, msg + " retry=" + retry); 151 SystemClock.sleep(50); 152 } while (retry++ < 5); 153 if (!waitFor.getAsBoolean()) { 154 logE(msg + " FAILED"); 155 } 156 } 157 pressKeyCode(int keyCode)158 private static void pressKeyCode(int keyCode) { 159 getDevice().pressKeyCode(keyCode); 160 } 161 getDevice()162 private static UiDevice getDevice() { 163 return UiDevice.getInstance(getInstrumentation()); 164 } 165 } 166