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 android.platform.test.utils;
18 
19 import android.app.Instrumentation;
20 import android.os.SystemClock;
21 import android.support.test.uiautomator.Direction;
22 import android.support.test.uiautomator.EventCondition;
23 import android.support.test.uiautomator.UiDevice;
24 import android.util.Log;
25 import android.view.KeyEvent;
26 
27 import java.io.IOException;
28 
29 
30 public class DPadUtil {
31 
32     private static final String TAG = DPadUtil.class.getSimpleName();
33     private static final long DPAD_DEFAULT_WAIT_TIME_MS = 1000; // 1 sec
34     private UiDevice mDevice;
35 
36 
DPadUtil(Instrumentation instrumentation)37     public DPadUtil(Instrumentation instrumentation) {
38         mDevice = UiDevice.getInstance(instrumentation);
39     }
40 
DPadUtil(UiDevice uiDevice)41     public DPadUtil(UiDevice uiDevice) {
42         mDevice = uiDevice;
43     }
44 
setUiDevice(UiDevice uiDevice)45     public void setUiDevice(UiDevice uiDevice) {
46         mDevice = uiDevice;
47     }
48 
pressDPad(Direction direction)49     public boolean pressDPad(Direction direction) {
50         return pressDPad(direction, 1, DPAD_DEFAULT_WAIT_TIME_MS);
51     }
52 
pressDPad(Direction direction, long repeat)53     public void pressDPad(Direction direction, long repeat) {
54         pressDPad(direction, repeat, DPAD_DEFAULT_WAIT_TIME_MS);
55     }
56 
57     /**
58      * Presses DPad button of the same direction for the count times.
59      * It sleeps between each press for DPAD_DEFAULT_WAIT_TIME_MS.
60      *
61      * @param direction the direction of the button to press.
62      * @param repeat the number of times to press the button.
63      * @param timeout the timeout for the wait.
64      * @return true if the last key simulation is successful, else return false
65      */
pressDPad(Direction direction, long repeat, long timeout)66     public boolean pressDPad(Direction direction, long repeat, long timeout) {
67         int iteration = 0;
68         boolean result = false;
69         while (iteration++ < repeat) {
70             switch (direction) {
71                 case LEFT:
72                     result = mDevice.pressDPadLeft();
73                     break;
74                 case RIGHT:
75                     result = mDevice.pressDPadRight();
76                     break;
77                 case UP:
78                     result = mDevice.pressDPadUp();
79                     break;
80                 case DOWN:
81                     result = mDevice.pressDPadDown();
82                     break;
83             }
84             SystemClock.sleep(timeout);
85         }
86         return result;
87     }
88 
pressDPadLeft()89     public boolean pressDPadLeft() {
90         return pressKeyCodeAndWait(KeyEvent.KEYCODE_DPAD_LEFT);
91     }
92 
pressDPadRight()93     public boolean pressDPadRight() {
94         return pressKeyCodeAndWait(KeyEvent.KEYCODE_DPAD_RIGHT);
95     }
96 
pressDPadUp()97     public boolean pressDPadUp() {
98         return pressKeyCodeAndWait(KeyEvent.KEYCODE_DPAD_UP);
99     }
100 
pressDPadDown()101     public boolean pressDPadDown() {
102         return pressKeyCodeAndWait(KeyEvent.KEYCODE_DPAD_DOWN);
103     }
104 
pressDPadCenter()105     public boolean pressDPadCenter() {
106         return pressKeyCodeAndWait(KeyEvent.KEYCODE_DPAD_CENTER);
107     }
108 
pressEnter()109     public boolean pressEnter() {
110         return pressKeyCodeAndWait(KeyEvent.KEYCODE_ENTER);
111     }
112 
pressPipKey()113     public boolean pressPipKey() {
114         return pressKeyCodeAndWait(KeyEvent.KEYCODE_WINDOW);
115     }
116 
pressSearch()117     public boolean pressSearch() {
118         return pressKeyCodeAndWait(KeyEvent.KEYCODE_SEARCH);
119     }
120 
pressKeyCode(int keyCode)121     public boolean pressKeyCode(int keyCode) {
122         return pressKeyCodeAndWait(keyCode);
123     }
pressKeyCodeAndWait(int keyCode)124     public boolean pressKeyCodeAndWait(int keyCode) {
125         boolean retVal = mDevice.pressKeyCode(keyCode);
126         // Dpad key presses will cause some UI change to occur.
127         // Wait for the accessibility event stream to become idle.
128         mDevice.waitForIdle();
129         return retVal;
130     }
131 
pressHome()132     public boolean pressHome() {
133         return mDevice.pressHome();
134     }
135 
pressBack()136     public boolean pressBack() {
137         return mDevice.pressBack();
138     }
139 
longPressKeyCode(int keyCode)140     public boolean longPressKeyCode(int keyCode) {
141         try {
142             mDevice.executeShellCommand(String.format("input keyevent --longpress %d", keyCode));
143             mDevice.waitForIdle();
144             return true;
145         } catch (IOException e) {
146             // Ignore
147             Log.w(TAG, String.format("Failed to long press the key code: %d", keyCode));
148             return false;
149         }
150     }
151 
152     /**
153      * Press the key code, and waits for the given condition to become true.
154      * @param keyCode
155      * @param condition
156      * @param longpress
157      * @param timeout
158      * @param <R>
159      * @return
160      */
pressKeyCodeAndWait(int keyCode, EventCondition<R> condition, boolean longpress, long timeout)161     public <R> R pressKeyCodeAndWait(int keyCode, EventCondition<R> condition, boolean longpress,
162             long timeout) {
163         return mDevice.performActionAndWait(new KeyEventRunnable(keyCode, longpress), condition,
164                 timeout);
165     }
166 
pressKeyCodeAndWait(int keyCode, EventCondition<R> condition, long timeout)167     public <R> R pressKeyCodeAndWait(int keyCode, EventCondition<R> condition, long timeout) {
168         return pressKeyCodeAndWait(keyCode, condition, false, timeout);
169     }
170 
pressDPadCenterAndWait(EventCondition<R> condition, long timeout)171     public <R> R pressDPadCenterAndWait(EventCondition<R> condition, long timeout) {
172         return mDevice.performActionAndWait(new KeyEventRunnable(KeyEvent.KEYCODE_DPAD_CENTER),
173                 condition, timeout);
174     }
175 
pressEnterAndWait(EventCondition<R> condition, long timeout)176     public <R> R pressEnterAndWait(EventCondition<R> condition, long timeout) {
177         return mDevice.performActionAndWait(new KeyEventRunnable(KeyEvent.KEYCODE_ENTER),
178                 condition, timeout);
179     }
180 
181     private class KeyEventRunnable implements Runnable {
182         private int mKeyCode;
183         private boolean mLongPress = false;
KeyEventRunnable(int keyCode)184         public KeyEventRunnable(int keyCode) {
185             mKeyCode = keyCode;
186         }
KeyEventRunnable(int keyCode, boolean longpress)187         public KeyEventRunnable(int keyCode, boolean longpress) {
188             mKeyCode = keyCode;
189             mLongPress = longpress;
190         }
191         @Override
run()192         public void run() {
193             if (mLongPress) {
194                 longPressKeyCode(mKeyCode);
195             } else {
196                 pressKeyCode(mKeyCode);
197             }
198         }
199     }
200 }
201