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

Side by Side Diff: remoting/android/java/src/org/chromium/chromoting/Desktop.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 unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chromoting; 5 package org.chromium.chromoting;
6 6
7 import android.annotation.SuppressLint; 7 import android.annotation.SuppressLint;
8 import android.content.DialogInterface; 8 import android.content.DialogInterface;
9 import android.content.Intent; 9 import android.content.Intent;
10 import android.content.pm.ApplicationInfo; 10 import android.content.pm.ApplicationInfo;
11 import android.content.pm.PackageManager; 11 import android.content.pm.PackageManager;
12 import android.content.pm.PackageManager.NameNotFoundException; 12 import android.content.pm.PackageManager.NameNotFoundException;
13 import android.os.Build; 13 import android.os.Build;
14 import android.os.Bundle; 14 import android.os.Bundle;
15 import android.os.Handler; 15 import android.os.Handler;
16 import android.support.v7.app.ActionBar.OnMenuVisibilityListener; 16 import android.support.v7.app.ActionBar.OnMenuVisibilityListener;
17 import android.support.v7.app.AlertDialog; 17 import android.support.v7.app.AlertDialog;
18 import android.support.v7.app.AppCompatActivity; 18 import android.support.v7.app.AppCompatActivity;
19 import android.support.v7.widget.Toolbar; 19 import android.support.v7.widget.Toolbar;
20 import android.view.KeyCharacterMap;
21 import android.view.KeyEvent; 20 import android.view.KeyEvent;
22 import android.view.Menu; 21 import android.view.Menu;
23 import android.view.MenuItem; 22 import android.view.MenuItem;
24 import android.view.MotionEvent; 23 import android.view.MotionEvent;
25 import android.view.View; 24 import android.view.View;
26 import android.view.View.OnLayoutChangeListener; 25 import android.view.View.OnLayoutChangeListener;
27 import android.view.View.OnTouchListener; 26 import android.view.View.OnTouchListener;
28 import android.view.inputmethod.InputMethodManager; 27 import android.view.inputmethod.InputMethodManager;
29 28
30 import org.chromium.chromoting.cardboard.DesktopActivity; 29 import org.chromium.chromoting.cardboard.DesktopActivity;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 /** The amount of time to wait to hide the Actionbar after user input is see n. */ 64 /** The amount of time to wait to hide the Actionbar after user input is see n. */
66 private static final int ACTIONBAR_AUTO_HIDE_DELAY_MS = 3000; 65 private static final int ACTIONBAR_AUTO_HIDE_DELAY_MS = 3000;
67 66
68 private final Event.Raisable<SoftInputMethodVisibilityChangedEventParameter> 67 private final Event.Raisable<SoftInputMethodVisibilityChangedEventParameter>
69 mOnSoftInputMethodVisibilityChanged = new Event.Raisable<>(); 68 mOnSoftInputMethodVisibilityChanged = new Event.Raisable<>();
70 69
71 private final Event.Raisable<InputModeChangedEventParameter> mOnInputModeCha nged = 70 private final Event.Raisable<InputModeChangedEventParameter> mOnInputModeCha nged =
72 new Event.Raisable<>(); 71 new Event.Raisable<>();
73 72
74 private Client mClient; 73 private Client mClient;
74 private InputInjectorWrapper mInjector;
75 75
76 /** Set of pressed keys for which we've sent TextEvent. */ 76 /** Set of pressed keys for which we've sent TextEvent. */
77 private Set<Integer> mPressedTextKeys = new TreeSet<Integer>(); 77 private Set<Integer> mPressedTextKeys = new TreeSet<Integer>();
Lambros 2016/06/17 23:00:09 Remove this, it's not used.
Hzj_jie 2016/06/19 23:41:38 Done.
78 78
79 private ActivityLifecycleListener mActivityLifecycleListener; 79 private ActivityLifecycleListener mActivityLifecycleListener;
80 80
81 /** Flag to indicate whether the current activity is switching to Cardboard desktop activity. */ 81 /** Flag to indicate whether the current activity is switching to Cardboard desktop activity. */
82 private boolean mSwitchToCardboardDesktopActivity; 82 private boolean mSwitchToCardboardDesktopActivity;
83 83
84 /** Flag to indicate whether to manually hide the system UI when the OSK is dismissed. */ 84 /** Flag to indicate whether to manually hide the system UI when the OSK is dismissed. */
85 private boolean mHideSystemUIOnSoftKeyboardDismiss = false; 85 private boolean mHideSystemUIOnSoftKeyboardDismiss = false;
86 86
87 /** Indicates whether a Soft Input UI (such as a keyboard) is visible. */ 87 /** Indicates whether a Soft Input UI (such as a keyboard) is visible. */
(...skipping 12 matching lines...) Expand all
100 private CapabilityManager.HostCapability mHostTouchCapability = 100 private CapabilityManager.HostCapability mHostTouchCapability =
101 CapabilityManager.HostCapability.UNKNOWN; 101 CapabilityManager.HostCapability.UNKNOWN;
102 102
103 /** Called when the activity is first created. */ 103 /** Called when the activity is first created. */
104 @Override 104 @Override
105 public void onCreate(Bundle savedInstanceState) { 105 public void onCreate(Bundle savedInstanceState) {
106 super.onCreate(savedInstanceState); 106 super.onCreate(savedInstanceState);
107 setContentView(R.layout.desktop); 107 setContentView(R.layout.desktop);
108 108
109 mClient = Client.getInstance(); 109 mClient = Client.getInstance();
110 mInjector = new InputInjectorWrapper(mClient);
110 111
111 mToolbar = (Toolbar) findViewById(R.id.toolbar); 112 mToolbar = (Toolbar) findViewById(R.id.toolbar);
112 setSupportActionBar(mToolbar); 113 setSupportActionBar(mToolbar);
113 114
114 DesktopView remoteHostDesktop = (DesktopView) findViewById(R.id.desktop_ view); 115 DesktopView remoteHostDesktop = (DesktopView) findViewById(R.id.desktop_ view);
115 remoteHostDesktop.init(this, mClient); 116 remoteHostDesktop.init(this, mClient);
116 mSwitchToCardboardDesktopActivity = false; 117 mSwitchToCardboardDesktopActivity = false;
117 118
118 getSupportActionBar().setDisplayShowTitleEnabled(false); 119 getSupportActionBar().setDisplayShowTitleEnabled(false);
119 getSupportActionBar().setDisplayHomeAsUpEnabled(true); 120 getSupportActionBar().setDisplayHomeAsUpEnabled(true);
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 } 505 }
505 if (id == R.id.actionbar_hide) { 506 if (id == R.id.actionbar_hide) {
506 hideActionBar(); 507 hideActionBar();
507 return true; 508 return true;
508 } 509 }
509 if (id == R.id.actionbar_disconnect || id == android.R.id.home) { 510 if (id == R.id.actionbar_disconnect || id == android.R.id.home) {
510 mClient.destroy(); 511 mClient.destroy();
511 return true; 512 return true;
512 } 513 }
513 if (id == R.id.actionbar_send_ctrl_alt_del) { 514 if (id == R.id.actionbar_send_ctrl_alt_del) {
514 int[] keys = { 515 mInjector.sendCtrlAltDel();
515 KeyEvent.KEYCODE_CTRL_LEFT,
516 KeyEvent.KEYCODE_ALT_LEFT,
517 KeyEvent.KEYCODE_FORWARD_DEL,
518 };
519 for (int key : keys) {
520 mClient.sendKeyEvent(0, key, true);
521 }
522 for (int key : keys) {
523 mClient.sendKeyEvent(0, key, false);
524 }
525 return true; 516 return true;
526 } 517 }
527 if (id == R.id.actionbar_help) { 518 if (id == R.id.actionbar_help) {
528 HelpSingleton.getInstance().launchHelp(this, HelpContext.DESKTOP); 519 HelpSingleton.getInstance().launchHelp(this, HelpContext.DESKTOP);
529 return true; 520 return true;
530 } 521 }
531 return super.onOptionsItemSelected(item); 522 return super.onOptionsItemSelected(item);
532 } 523 }
533 524
534 private void attachKeyboardVisibilityListener() { 525 private void attachKeyboardVisibilityListener() {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 startActivityForResult(intent, Chromoting.CARDBOARD_DESKTOP_ACTIVITY); 608 startActivityForResult(intent, Chromoting.CARDBOARD_DESKTOP_ACTIVITY);
618 } 609 }
619 610
620 /** 611 /**
621 * Called once when a keyboard key is pressed, then again when that same key is released. This 612 * Called once when a keyboard key is pressed, then again when that same key is released. This
622 * is not guaranteed to be notified of all soft keyboard events: certian key boards might not 613 * is not guaranteed to be notified of all soft keyboard events: certian key boards might not
623 * call it at all, while others might skip it in certain situations (e.g. sw ipe input). 614 * call it at all, while others might skip it in certain situations (e.g. sw ipe input).
624 */ 615 */
625 @Override 616 @Override
626 public boolean dispatchKeyEvent(KeyEvent event) { 617 public boolean dispatchKeyEvent(KeyEvent event) {
627 int keyCode = event.getKeyCode(); 618 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
628
629 // Dispatch the back button to the system to handle navigation
630 if (keyCode == KeyEvent.KEYCODE_BACK) {
631 mClient.destroy(); 619 mClient.destroy();
632 return super.dispatchKeyEvent(event); 620 return super.dispatchKeyEvent(event);
633 } 621 }
634 622
635 boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; 623 return mInjector.sendKeyEvent(event);
636
637 // Physical keyboard must work as if it is connected to the remote host
638 // and so events coming from physical keyboard never generate text
639 // events. Also scan codes must be used instead of key code, so that
640 // the keyboard layout selected on the client doesn't affect the key
641 // codes sent to the host.
642 if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) {
643 return mClient.sendKeyEvent(event.getScanCode(), 0, pressed);
644 }
645
646 // Events received from software keyboards generate TextEvent in two
647 // cases:
648 // 1. This is an ACTION_MULTIPLE event.
649 // 2. Ctrl, Alt and Meta are not pressed.
650 // This ensures that on-screen keyboard always injects input that
651 // correspond to what user sees on the screen, while physical keyboard
652 // acts as if it is connected to the remote host.
653 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) {
654 mClient.sendTextEvent(event.getCharacters());
655 return true;
656 }
657
658 // For Enter getUnicodeChar() returns 10 (line feed), but we still
659 // want to send it as KeyEvent.
660 int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0;
661
662 boolean no_modifiers = !event.isAltPressed()
663 && !event.isCtrlPressed() && !event.isMetaPressed();
664
665 if (pressed && unicode != 0 && no_modifiers) {
666 mPressedTextKeys.add(keyCode);
667 int[] codePoints = { unicode };
668 mClient.sendTextEvent(new String(codePoints, 0, 1));
669 return true;
670 }
671
672 if (!pressed && mPressedTextKeys.contains(keyCode)) {
673 mPressedTextKeys.remove(keyCode);
674 return true;
675 }
676
677 switch (keyCode) {
678 // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are
679 // deprecated, but they still need to be here for older devices and
680 // third-party keyboards that may still generate these events. See
681 // https://source.android.com/devices/input/keyboard-devices.html#le gacy-unsupported-keys
682 case KeyEvent.KEYCODE_AT:
683 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
684 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed);
685 return true;
686
687 case KeyEvent.KEYCODE_POUND:
688 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
689 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed);
690 return true;
691
692 case KeyEvent.KEYCODE_STAR:
693 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
694 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed);
695 return true;
696
697 case KeyEvent.KEYCODE_PLUS:
698 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
699 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed);
700 return true;
701
702 default:
703 // We try to send all other key codes to the host directly.
704 return mClient.sendKeyEvent(0, keyCode, pressed);
705 }
706 } 624 }
707 } 625 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698