157e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le/*
21194ec356a16f3c6dcf408289e36e42c149d6dc8Kevin Jin * Copyright (C) 2013 DroidDriver committers
357e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le *
457e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * Licensed under the Apache License, Version 2.0 (the "License");
557e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * you may not use this file except in compliance with the License.
657e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * You may obtain a copy of the License at
757e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le *
857e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le *      http://www.apache.org/licenses/LICENSE-2.0
957e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le *
1057e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * Unless required by applicable law or agreed to in writing, software
1157e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * distributed under the License is distributed on an "AS IS" BASIS,
1257e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1357e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * See the License for the specific language governing permissions and
1457e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * limitations under the License.
1557e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le */
1657e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le
174b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinpackage io.appium.droiddriver.util;
1857e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le
19082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jinimport android.annotation.TargetApi;
20082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jinimport android.os.Build;
2157e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Leimport android.os.SystemClock;
221e9f07f4cb681fb142202113caedba35737a83efKevin Jinimport android.util.Log;
2357e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Leimport android.view.InputDevice;
24337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchettimport android.view.InputEvent;
25cce3dd4492cf04a89154e36fda1909ab4e35213aThanh Leimport android.view.KeyEvent;
2657e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Leimport android.view.MotionEvent;
2757e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le
284b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.actions.InputInjector;
294b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.exceptions.ActionException;
30f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin
3157e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le/**
3257e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le * Helper methods to create InputEvents.
3357e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le */
3457e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Lepublic class Events {
35544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le  /**
36544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le   * @return a touch down event at the specified coordinates
37544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le   */
38082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin  @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
39337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  private static MotionEvent newTouchDownEvent(int x, int y) {
4031692a4134ef82a4144d25980c0c5f14bbf1bfadThanh Le    long downTime = SystemClock.uptimeMillis();
4131692a4134ef82a4144d25980c0c5f14bbf1bfadThanh Le    MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 1);
42082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    // TODO: Fix this if 'source' is required on devices older than HONEYCOMB_MR1.
43082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
44082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin      event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
45082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    }
4657e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le    return event;
4757e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le  }
4857e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le
49544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le  /**
50544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le   * @return a touch up event at the specified coordinates
51544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le   */
52082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin  @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
53337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  private static MotionEvent newTouchUpEvent(long downTime, int x, int y) {
54544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le    long eventTime = SystemClock.uptimeMillis();
55544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le    MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 1);
56082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
57082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin      event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
58082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    }
59544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le    return event;
60544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le  }
61544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le
62544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le  /**
63544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le   * @return a touch move event at the specified coordinates
64544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le   */
65082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin  @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
66337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  private static MotionEvent newTouchMoveEvent(long downTime, int x, int y) {
67544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le    long eventTime = SystemClock.uptimeMillis();
68544e68a6af3ef73316b9994bb7a63790c19415b9Thanh Le    MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 1);
69082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
70082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin      event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
71082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    }
7257e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le    return event;
7357e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le  }
7457e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le
75082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin  @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
76337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  private static KeyEvent newKeyEvent(long downTime, long eventTime, int action, int keyCode,
77337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett      int metaState) {
78337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett    KeyEvent event = new KeyEvent(downTime, eventTime, action, keyCode, 0 /* repeat */, metaState);
79082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
80082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin      event.setSource(InputDevice.SOURCE_KEYBOARD);
81082c7925e5109092ff31d7021f1f9bb6daabee12Kevin Jin    }
82cce3dd4492cf04a89154e36fda1909ab4e35213aThanh Le    return event;
83cce3dd4492cf04a89154e36fda1909ab4e35213aThanh Le  }
84cce3dd4492cf04a89154e36fda1909ab4e35213aThanh Le
85f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin  /**
86f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin   * Injects {@code event}. {@code event} is recycled and should not be used
87f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin   * after.
88f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin   *
89f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin   * @throws ActionException if injection failed
90f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin   */
91337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  private static void injectEvent(InputInjector injector, InputEvent event) {
921e9f07f4cb681fb142202113caedba35737a83efKevin Jin    injectEvent(Log.DEBUG, injector, event);
931e9f07f4cb681fb142202113caedba35737a83efKevin Jin  }
941e9f07f4cb681fb142202113caedba35737a83efKevin Jin
95337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  private static void injectEvent(int priority, InputInjector injector, InputEvent event) {
961e9f07f4cb681fb142202113caedba35737a83efKevin Jin    Logs.call(priority, injector, "injectInputEvent", event);
97f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    try {
98f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin      if (!injector.injectInputEvent(event)) {
99f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin        throw new ActionException("Failed to inject " + event);
100f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin      }
101f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    } finally {
102337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett      if (event instanceof MotionEvent) {
103337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett        ((MotionEvent) event).recycle();
104337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett      }
105f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    }
106f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin  }
107f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin
108f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin  public static long touchDown(InputInjector injector, int x, int y) {
109f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    MotionEvent downEvent = newTouchDownEvent(x, y);
110f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    long downTime = downEvent.getDownTime();
111f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    injectEvent(injector, downEvent);
112f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    return downTime;
113f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin  }
114f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin
115f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin  public static void touchUp(InputInjector injector, long downTime, int x, int y) {
116f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin    injectEvent(injector, newTouchUpEvent(downTime, x, y));
117f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin  }
118f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin
119f9c6c5063b38b623679e47d7095cccddb0481319Kevin Jin  public static void touchMove(InputInjector injector, long downTime, int x, int y) {
1201e9f07f4cb681fb142202113caedba35737a83efKevin Jin    injectEvent(Log.VERBOSE, injector, newTouchMoveEvent(downTime, x, y));
121f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin  }
122f9c2a591497874769b87bf492a0666cf853e0ae5Kevin Jin
123337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  public static long keyDown(InputInjector injector, int keyCode, int metaState) {
124337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett    long downTime = SystemClock.uptimeMillis();
125337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett    KeyEvent downEvent = newKeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, metaState);
126337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett    injectEvent(injector, downEvent);
127337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett    return downTime;
128337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  }
129337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett
130337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  public static void keyUp(InputInjector injector, long downTime, int keyCode, int metaState) {
131337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett    injectEvent(injector,
132337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett        newKeyEvent(downTime, SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keyCode, metaState));
133337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett  }
134337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett
13557e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le  private Events() {}
13657e46577852ffa1dde4662f6018f7fbcfacb6148Thanh Le}
137