Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(410)

Unified Diff: remoting/android/java/src/org/chromium/chromoting/InputInjectorWrapper.java

Issue 2066683003: [Chromoting] Add InputInjector and InputInjectorWrapper for easy unittesting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix FindBugs errors Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/android/java/src/org/chromium/chromoting/InputInjectorWrapper.java
diff --git a/remoting/android/java/src/org/chromium/chromoting/InputInjectorWrapper.java b/remoting/android/java/src/org/chromium/chromoting/InputInjectorWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1a5d78b9ab387d7259377abae51dd1e29bb24c8
--- /dev/null
+++ b/remoting/android/java/src/org/chromium/chromoting/InputInjectorWrapper.java
@@ -0,0 +1,218 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chromoting;
+
+import android.graphics.Point;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import org.chromium.chromoting.jni.TouchEventData;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * A set of functions to send users' activities, which are represented by Android classes, to
+ * remove host machine. This class uses a {@link InputInjector} to do the real injections. This
+ * class is not thread-safe.
Lambros 2016/06/17 23:00:10 I don't think it's worth documenting that a class
Hzj_jie 2016/06/19 23:41:39 Done.
+ */
+public final class InputInjectorWrapper {
+ private static final int[] CTRL_ALT_DEL = {
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_FORWARD_DEL,
+ };
+
+ private final InputInjector mInjector;
+ /** Set of pressed keys for which we've sent TextEvent. */
Lambros 2016/06/17 23:00:09 Blank line before comment.
Hzj_jie 2016/06/19 23:41:38 Done.
+ private final Set<Integer> mPressedTextKeys;
+
+ public InputInjectorWrapper(InputInjector injector) {
+ Preconditions.notNull(injector);
+ mInjector = injector;
+ mPressedTextKeys = new TreeSet<>();
+ }
+
+ public void sendMouseEvent(Point pos, int button, boolean down) {
+ Preconditions.isTrue(button == TouchInputHandler.BUTTON_UNDEFINED
Lambros 2016/06/17 23:00:09 You could consider adding a button enum for this?
Hzj_jie 2016/06/19 23:41:39 I thought we still discourage from using enum in A
+ || button == TouchInputHandler.BUTTON_LEFT
Lambros 2016/06/17 23:00:09 Line-continuation in Java is +8 spaces from previo
Hzj_jie 2016/06/19 23:41:39 Done.
+ || button == TouchInputHandler.BUTTON_MIDDLE
+ || button == TouchInputHandler.BUTTON_RIGHT);
+ mInjector.sendMouseEvent(pos.x, pos.y, button, down);
+ }
+
+ public void sendMouseDown(Point pos, int button) {
+ sendMouseEvent(pos, button, true);
+ }
+
+ public void sendMouseUp(Point pos, int button) {
+ sendMouseEvent(pos, button, false);
+ }
+
+ public void sendMouseClick(Point pos, int button) {
+ sendMouseDown(pos, button);
+ sendMouseUp(pos, button);
+ }
+
+ public void sendCursorMove(Point pos) {
+ sendMouseUp(pos, TouchInputHandler.BUTTON_UNDEFINED);
+ }
+
+ // TODO (zijiehe): This function will be eventually removed after {@link InputStrategyInterface}
+ // has been deprecated.
+ public void sendCursorMove(int x, int y) {
+ sendCursorMove(new Point(x, y));
+ }
+
+ public void sendMouseWheelEvent(float distanceX, float distanceY) {
+ mInjector.sendMouseWheelEvent((int) distanceX, (int) distanceY);
+ }
+
+ public void sendReverseMouseWheelEvent(float distanceX, float distanceY) {
+ sendMouseWheelEvent(-distanceX, -distanceY);
+ }
+
+ /**
+ * Extracts the touch point data from a MotionEvent, converts each point into a marshallable
+ * object and passes the set of points to the JNI layer to be transmitted to the remote host.
+ *
+ * @param event The event to send to the remote host for injection. NOTE: This object must be
+ * updated to represent the remote machine's coordinate system before calling this
+ * function.
+ */
+ public void sendTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ TouchEventData.EventType touchEventType = TouchEventData.EventType.fromMaskedAction(action);
+ List<TouchEventData> touchEventList = new ArrayList<TouchEventData>();
+
+ if (action == MotionEvent.ACTION_MOVE) {
+ // In order to process all of the events associated with an ACTION_MOVE event, we need
+ // to walk the list of historical events in order and add each event to our list, then
+ // retrieve the current move event data.
+ int pointerCount = event.getPointerCount();
+ int historySize = event.getHistorySize();
+ for (int h = 0; h < historySize; ++h) {
+ for (int p = 0; p < pointerCount; ++p) {
+ touchEventList.add(new TouchEventData(event.getPointerId(p),
+ event.getHistoricalX(p, h), event.getHistoricalY(p, h),
+ event.getHistoricalSize(p, h), event.getHistoricalSize(p, h),
+ event.getHistoricalOrientation(p, h),
+ event.getHistoricalPressure(p, h)));
+ }
+ }
+
+ for (int p = 0; p < pointerCount; p++) {
+ touchEventList.add(new TouchEventData(event.getPointerId(p), event.getX(p),
+ event.getY(p), event.getSize(p), event.getSize(p), event.getOrientation(p),
+ event.getPressure(p)));
+ }
+ } else {
+ // For all other events, we only want to grab the current/active pointer. The event
+ // contains a list of every active pointer but passing all of of these to the host can
+ // cause confusion on the remote OS side and result in broken touch gestures.
+ int activePointerIndex = event.getActionIndex();
+ touchEventList.add(new TouchEventData(event.getPointerId(activePointerIndex),
+ event.getX(activePointerIndex), event.getY(activePointerIndex),
+ event.getSize(activePointerIndex), event.getSize(activePointerIndex),
+ event.getOrientation(activePointerIndex),
+ event.getPressure(activePointerIndex)));
+ }
+
+ if (!touchEventList.isEmpty()) {
+ mInjector.sendTouchEvent(touchEventType, touchEventList.toArray(new TouchEventData[0]));
+ }
+ }
+
+ public boolean sendKeyEvent(KeyEvent event) {
Lambros 2016/06/17 23:00:10 Add some JavaDoc for this. Maybe: Converts the Key
Hzj_jie 2016/06/19 23:41:39 Done.
+ int keyCode = event.getKeyCode();
+ boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
+
+ // Events received from software keyboards generate TextEvent in two
+ // cases:
+ // 1. This is an ACTION_MULTIPLE event.
+ // 2. Ctrl, Alt and Meta are not pressed.
+ // This ensures that on-screen keyboard always injects input that
+ // correspond to what user sees on the screen, while physical keyboard
+ // acts as if it is connected to the remote host.
+ if (event.getAction() == KeyEvent.ACTION_MULTIPLE) {
+ mInjector.sendTextEvent(event.getCharacters());
+ return true;
+ }
+
+ // For Enter getUnicodeChar() returns 10 (line feed), but we still
+ // want to send it as KeyEvent.
+ int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0;
+
+ boolean no_modifiers = !event.isAltPressed()
+ && !event.isCtrlPressed() && !event.isMetaPressed();
+
+ if (pressed && unicode != 0 && no_modifiers) {
+ mPressedTextKeys.add(keyCode);
+ int[] codePoints = { unicode };
+ mInjector.sendTextEvent(new String(codePoints, 0, 1));
+ return true;
+ }
+
+ if (!pressed && mPressedTextKeys.contains(keyCode)) {
+ mPressedTextKeys.remove(keyCode);
+ return true;
+ }
+
+ switch (keyCode) {
+ // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are
+ // deprecated, but they still need to be here for older devices and
+ // third-party keyboards that may still generate these events. See
+ // https://source.android.com/devices/input/keyboard-devices.html#legacy-unsupported-keys
+ case KeyEvent.KEYCODE_AT:
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed);
+ return true;
+
+ case KeyEvent.KEYCODE_POUND:
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed);
+ return true;
+
+ case KeyEvent.KEYCODE_STAR:
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed);
+ return true;
+
+ case KeyEvent.KEYCODE_PLUS:
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
+ mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed);
+ return true;
+
+ default:
+ // We try to send all other key codes to the host directly.
+ return mInjector.sendKeyEvent(0, keyCode, pressed);
+ }
+ }
+
+ public void sendKeyDown(int keyCode) {
+ mInjector.sendKeyEvent(0, keyCode, true);
+ }
+
+ public void sendKeyUp(int keyCode) {
+ mInjector.sendKeyEvent(0, keyCode, false);
+ }
+
+ public void sendKeysPress(int[] keyCodes) {
Lambros 2016/06/17 23:00:09 Maybe add JavaDoc for this? This is intended for s
Hzj_jie 2016/06/19 23:41:39 Done.
+ if (keyCodes != null && keyCodes.length > 0) {
+ for (int keyCode : keyCodes) {
+ sendKeyDown(keyCode);
+ }
+ for (int keyCode : keyCodes) {
+ sendKeyUp(keyCode);
+ }
+ }
+ }
+
+ public void sendCtrlAltDel() {
+ sendKeysPress(CTRL_ALT_DEL);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698