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 */
16package com.android.tv.testing.uihelper;
17
18import static junit.framework.Assert.assertTrue;
19
20import android.app.Instrumentation;
21import android.app.UiAutomation;
22import android.os.Build;
23import android.os.SystemClock;
24import android.support.test.uiautomator.Configurator;
25import android.support.test.uiautomator.Direction;
26import android.support.test.uiautomator.UiDevice;
27import android.view.InputDevice;
28import android.view.KeyEvent;
29
30/**
31 * Static utility methods for {@link UiDevice}.
32 */
33public final class UiDeviceUtils {
34
35    public static void pressDpad(UiDevice uiDevice, Direction direction) {
36        switch (direction) {
37            case UP:
38                uiDevice.pressDPadUp();
39                break;
40            case DOWN:
41                uiDevice.pressDPadDown();
42                break;
43            case LEFT:
44                uiDevice.pressDPadLeft();
45                break;
46            case RIGHT:
47                uiDevice.pressDPadRight();
48                break;
49            default:
50                throw new IllegalArgumentException(direction.toString());
51        }
52    }
53
54
55    public static void pressKeys(UiDevice uiDevice, int... keyCodes) {
56        for (int k : keyCodes) {
57            uiDevice.pressKeyCode(k);
58        }
59    }
60
61    /**
62     * Parses the string and sends the corresponding individual key presses.
63     * <p>
64     * <b>Note:</b> only handles 0-9, '.', and '-'.
65     */
66    public static void pressKeys(UiDevice uiDevice, String keys) {
67        for (char c : keys.toCharArray()) {
68            if (c >= '0' && c <= '9') {
69                uiDevice.pressKeyCode(KeyEvent.KEYCODE_0 + c - '0');
70            } else if (c == '-') {
71                uiDevice.pressKeyCode(KeyEvent.KEYCODE_MINUS);
72            } else if (c == '.') {
73                uiDevice.pressKeyCode(KeyEvent.KEYCODE_PERIOD);
74            } else {
75                throw new IllegalArgumentException(c + " is not supported");
76            }
77        }
78    }
79
80    /**
81     * Sends the DPAD Center key presses with the {@code repeat} count.
82     * TODO: Remove instrumentation argument once migrated to JUnit4.
83     */
84    public static void pressDPadCenter(Instrumentation instrumentation, int repeat) {
85        pressKey(instrumentation, KeyEvent.KEYCODE_DPAD_CENTER, repeat);
86    }
87
88    private static void pressKey(Instrumentation instrumentation, int keyCode, int repeat) {
89        UiDevice.getInstance(instrumentation).waitForIdle();
90        for (int i = 0; i < repeat; ++i) {
91            assertPressKeyDown(instrumentation, keyCode, false);
92            if (i < repeat - 1) {
93                assertPressKeyUp(instrumentation, keyCode, false);
94            }
95        }
96        // Send last key event synchronously.
97        assertPressKeyUp(instrumentation, keyCode, true);
98    }
99
100    private static void assertPressKeyDown(Instrumentation instrumentation, int keyCode,
101            boolean sync) {
102        assertPressKey(instrumentation, KeyEvent.ACTION_DOWN, keyCode, sync);
103    }
104
105    private static void assertPressKeyUp(Instrumentation instrumentation, int keyCode,
106            boolean sync) {
107        assertPressKey(instrumentation, KeyEvent.ACTION_UP, keyCode, sync);
108    }
109
110    private static void assertPressKey(Instrumentation instrumentation, int action, int keyCode,
111            boolean sync) {
112        long eventTime = SystemClock.uptimeMillis();
113        KeyEvent event = new KeyEvent(eventTime, eventTime, action, keyCode, 0, 0, -1, 0, 0,
114                InputDevice.SOURCE_KEYBOARD);
115        assertTrue("Failed to inject key up event:" + event,
116                injectEvent(instrumentation, event, sync));
117    }
118
119    private static boolean injectEvent(Instrumentation instrumentation, KeyEvent event,
120            boolean sync) {
121        return getUiAutomation(instrumentation).injectInputEvent(event, sync);
122    }
123
124    private static UiAutomation getUiAutomation(Instrumentation instrumentation) {
125        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
126            int flags = Configurator.getInstance().getUiAutomationFlags();
127            return instrumentation.getUiAutomation(flags);
128        } else {
129            return instrumentation.getUiAutomation();
130        }
131    }
132
133    private UiDeviceUtils() {
134    }
135}
136