1/* 2 * Copyright (C) 2013 DroidDriver committers 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 17package io.appium.droiddriver.util; 18 19import android.annotation.TargetApi; 20import android.os.Build; 21import android.os.SystemClock; 22import android.util.Log; 23import android.view.InputDevice; 24import android.view.InputEvent; 25import android.view.KeyEvent; 26import android.view.MotionEvent; 27 28import io.appium.droiddriver.actions.InputInjector; 29import io.appium.droiddriver.exceptions.ActionException; 30 31/** 32 * Helper methods to create InputEvents. 33 */ 34public class Events { 35 /** 36 * @return a touch down event at the specified coordinates 37 */ 38 @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 39 private static MotionEvent newTouchDownEvent(int x, int y) { 40 long downTime = SystemClock.uptimeMillis(); 41 MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 1); 42 // TODO: Fix this if 'source' is required on devices older than HONEYCOMB_MR1. 43 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { 44 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 45 } 46 return event; 47 } 48 49 /** 50 * @return a touch up event at the specified coordinates 51 */ 52 @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 53 private static MotionEvent newTouchUpEvent(long downTime, int x, int y) { 54 long eventTime = SystemClock.uptimeMillis(); 55 MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 1); 56 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { 57 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 58 } 59 return event; 60 } 61 62 /** 63 * @return a touch move event at the specified coordinates 64 */ 65 @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 66 private static MotionEvent newTouchMoveEvent(long downTime, int x, int y) { 67 long eventTime = SystemClock.uptimeMillis(); 68 MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 1); 69 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { 70 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 71 } 72 return event; 73 } 74 75 @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 76 private static KeyEvent newKeyEvent(long downTime, long eventTime, int action, int keyCode, 77 int metaState) { 78 KeyEvent event = new KeyEvent(downTime, eventTime, action, keyCode, 0 /* repeat */, metaState); 79 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { 80 event.setSource(InputDevice.SOURCE_KEYBOARD); 81 } 82 return event; 83 } 84 85 /** 86 * Injects {@code event}. {@code event} is recycled and should not be used 87 * after. 88 * 89 * @throws ActionException if injection failed 90 */ 91 private static void injectEvent(InputInjector injector, InputEvent event) { 92 injectEvent(Log.DEBUG, injector, event); 93 } 94 95 private static void injectEvent(int priority, InputInjector injector, InputEvent event) { 96 Logs.call(priority, injector, "injectInputEvent", event); 97 try { 98 if (!injector.injectInputEvent(event)) { 99 throw new ActionException("Failed to inject " + event); 100 } 101 } finally { 102 if (event instanceof MotionEvent) { 103 ((MotionEvent) event).recycle(); 104 } 105 } 106 } 107 108 public static long touchDown(InputInjector injector, int x, int y) { 109 MotionEvent downEvent = newTouchDownEvent(x, y); 110 long downTime = downEvent.getDownTime(); 111 injectEvent(injector, downEvent); 112 return downTime; 113 } 114 115 public static void touchUp(InputInjector injector, long downTime, int x, int y) { 116 injectEvent(injector, newTouchUpEvent(downTime, x, y)); 117 } 118 119 public static void touchMove(InputInjector injector, long downTime, int x, int y) { 120 injectEvent(Log.VERBOSE, injector, newTouchMoveEvent(downTime, x, y)); 121 } 122 123 public static long keyDown(InputInjector injector, int keyCode, int metaState) { 124 long downTime = SystemClock.uptimeMillis(); 125 KeyEvent downEvent = newKeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, metaState); 126 injectEvent(injector, downEvent); 127 return downTime; 128 } 129 130 public static void keyUp(InputInjector injector, long downTime, int keyCode, int metaState) { 131 injectEvent(injector, 132 newKeyEvent(downTime, SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keyCode, metaState)); 133 } 134 135 private Events() {} 136} 137