OLD | NEW |
---|---|
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.app.AlertDialog; | 8 import android.app.AlertDialog; |
9 import android.content.DialogInterface; | 9 import android.content.DialogInterface; |
10 import android.content.Intent; | 10 import android.content.Intent; |
(...skipping 13 matching lines...) Expand all Loading... | |
24 import android.view.MenuItem; | 24 import android.view.MenuItem; |
25 import android.view.MotionEvent; | 25 import android.view.MotionEvent; |
26 import android.view.View; | 26 import android.view.View; |
27 import android.view.View.OnLayoutChangeListener; | 27 import android.view.View.OnLayoutChangeListener; |
28 import android.view.View.OnTouchListener; | 28 import android.view.View.OnTouchListener; |
29 import android.view.inputmethod.InputMethodManager; | 29 import android.view.inputmethod.InputMethodManager; |
30 | 30 |
31 import org.chromium.chromoting.cardboard.DesktopActivity; | 31 import org.chromium.chromoting.cardboard.DesktopActivity; |
32 import org.chromium.chromoting.help.HelpContext; | 32 import org.chromium.chromoting.help.HelpContext; |
33 import org.chromium.chromoting.help.HelpSingleton; | 33 import org.chromium.chromoting.help.HelpSingleton; |
34 import org.chromium.chromoting.jni.JniInterface; | 34 import org.chromium.chromoting.jni.Client; |
35 | 35 |
36 import java.util.List; | 36 import java.util.List; |
37 import java.util.Set; | 37 import java.util.Set; |
38 import java.util.TreeSet; | 38 import java.util.TreeSet; |
39 | 39 |
40 /** | 40 /** |
41 * A simple screen that does nothing except display a DesktopView and notify it of rotations. | 41 * A simple screen that does nothing except display a DesktopView and notify it of rotations. |
42 */ | 42 */ |
43 public class Desktop | 43 public class Desktop |
44 extends AppCompatActivity implements View.OnSystemUiVisibilityChangeList ener, | 44 extends AppCompatActivity implements View.OnSystemUiVisibilityChangeList ener, |
(...skipping 17 matching lines...) Expand all Loading... | |
62 | 62 |
63 /** Preference used to track the last input mode selected by the user. */ | 63 /** Preference used to track the last input mode selected by the user. */ |
64 private static final String PREFERENCE_INPUT_MODE = "input_mode"; | 64 private static final String PREFERENCE_INPUT_MODE = "input_mode"; |
65 | 65 |
66 /** The amount of time to wait to hide the Actionbar after user input is see n. */ | 66 /** The amount of time to wait to hide the Actionbar after user input is see n. */ |
67 private static final int ACTIONBAR_AUTO_HIDE_DELAY_MS = 3000; | 67 private static final int ACTIONBAR_AUTO_HIDE_DELAY_MS = 3000; |
68 | 68 |
69 /** The surface that displays the remote host's desktop feed. */ | 69 /** The surface that displays the remote host's desktop feed. */ |
70 private DesktopView mRemoteHostDesktop; | 70 private DesktopView mRemoteHostDesktop; |
71 | 71 |
72 private Client mClient; | |
73 | |
72 /** Set of pressed keys for which we've sent TextEvent. */ | 74 /** Set of pressed keys for which we've sent TextEvent. */ |
73 private Set<Integer> mPressedTextKeys = new TreeSet<Integer>(); | 75 private Set<Integer> mPressedTextKeys = new TreeSet<Integer>(); |
74 | 76 |
75 private ActivityLifecycleListener mActivityLifecycleListener; | 77 private ActivityLifecycleListener mActivityLifecycleListener; |
76 | 78 |
77 /** Flag to indicate whether the current activity is switching to Cardboard desktop activity. */ | 79 /** Flag to indicate whether the current activity is switching to Cardboard desktop activity. */ |
78 private boolean mSwitchToCardboardDesktopActivity; | 80 private boolean mSwitchToCardboardDesktopActivity; |
79 | 81 |
80 /** Indicates whether a Soft Input UI (such as a keyboard) is visible. */ | 82 /** Indicates whether a Soft Input UI (such as a keyboard) is visible. */ |
81 private boolean mSoftInputVisible = false; | 83 private boolean mSoftInputVisible = false; |
(...skipping 10 matching lines...) Expand all Loading... | |
92 /** Indicates whether the remote host supports touch injection. */ | 94 /** Indicates whether the remote host supports touch injection. */ |
93 private CapabilityManager.HostCapability mHostTouchCapability = | 95 private CapabilityManager.HostCapability mHostTouchCapability = |
94 CapabilityManager.HostCapability.UNKNOWN; | 96 CapabilityManager.HostCapability.UNKNOWN; |
95 | 97 |
96 /** Called when the activity is first created. */ | 98 /** Called when the activity is first created. */ |
97 @Override | 99 @Override |
98 public void onCreate(Bundle savedInstanceState) { | 100 public void onCreate(Bundle savedInstanceState) { |
99 super.onCreate(savedInstanceState); | 101 super.onCreate(savedInstanceState); |
100 setContentView(R.layout.desktop); | 102 setContentView(R.layout.desktop); |
101 | 103 |
104 mClient = Client.getClient(); | |
Sergey Ulanov
2016/01/30 01:03:23
Is it possible to pass the Client object from the
Lambros
2016/02/03 22:57:43
This is the reason we need the singleton in the fi
Sergey Ulanov
2016/02/08 22:05:16
I see. I think the right way to fix this would be
Lambros
2016/02/08 23:48:51
That would work for the initial connection, but An
| |
105 | |
102 mToolbar = (Toolbar) findViewById(R.id.toolbar); | 106 mToolbar = (Toolbar) findViewById(R.id.toolbar); |
103 setSupportActionBar(mToolbar); | 107 setSupportActionBar(mToolbar); |
104 | 108 |
105 mRemoteHostDesktop = (DesktopView) findViewById(R.id.desktop_view); | 109 mRemoteHostDesktop = (DesktopView) findViewById(R.id.desktop_view); |
106 mRemoteHostDesktop.setDesktop(this); | 110 mRemoteHostDesktop.setDesktop(this); |
111 mRemoteHostDesktop.setClient(mClient); | |
107 mSwitchToCardboardDesktopActivity = false; | 112 mSwitchToCardboardDesktopActivity = false; |
108 | 113 |
109 getSupportActionBar().setDisplayShowTitleEnabled(false); | 114 getSupportActionBar().setDisplayShowTitleEnabled(false); |
110 getSupportActionBar().setDisplayHomeAsUpEnabled(true); | 115 getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
111 | 116 |
112 // For this Activity, the home button in the action bar acts as a Discon nect button, so | 117 // For this Activity, the home button in the action bar acts as a Discon nect button, so |
113 // set the description for accessibility/screen readers. | 118 // set the description for accessibility/screen readers. |
114 getSupportActionBar().setHomeActionContentDescription(R.string.disconnec t_myself_button); | 119 getSupportActionBar().setHomeActionContentDescription(R.string.disconnec t_myself_button); |
115 | 120 |
116 // The action bar is already shown when the activity is started however calling the | 121 // The action bar is already shown when the activity is started however calling the |
117 // function below will set our preferred system UI flags which will adju st the layout | 122 // function below will set our preferred system UI flags which will adju st the layout |
118 // size of the canvas and we can avoid an initial resize event. | 123 // size of the canvas and we can avoid an initial resize event. |
119 showActionBar(); | 124 showActionBar(); |
120 | 125 |
121 View decorView = getWindow().getDecorView(); | 126 View decorView = getWindow().getDecorView(); |
122 decorView.setOnSystemUiVisibilityChangeListener(this); | 127 decorView.setOnSystemUiVisibilityChangeListener(this); |
123 | 128 |
124 mActivityLifecycleListener = CapabilityManager.getInstance().onActivityA cceptingListener( | 129 mActivityLifecycleListener = mClient.getCapabilityManager().onActivityAc ceptingListener( |
125 this, Capabilities.CAST_CAPABILITY); | 130 this, Capabilities.CAST_CAPABILITY); |
126 mActivityLifecycleListener.onActivityCreated(this, savedInstanceState); | 131 mActivityLifecycleListener.onActivityCreated(this, savedInstanceState); |
127 | 132 |
128 mInputMode = getInitialInputModeValue(); | 133 mInputMode = getInitialInputModeValue(); |
129 | 134 |
130 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | 135 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
131 attachKeyboardVisibilityListener(); | 136 attachKeyboardVisibilityListener(); |
132 | 137 |
133 // Only create an Autohide task if the system supports immersive ful lscreen mode. Older | 138 // Only create an Autohide task if the system supports immersive ful lscreen mode. Older |
134 // versions of the OS benefit less from this functionality and we do n't want to change | 139 // versions of the OS benefit less from this functionality and we do n't want to change |
(...skipping 18 matching lines...) Expand all Loading... | |
153 }); | 158 }); |
154 } else { | 159 } else { |
155 mRemoteHostDesktop.setFitsSystemWindows(true); | 160 mRemoteHostDesktop.setFitsSystemWindows(true); |
156 } | 161 } |
157 } | 162 } |
158 | 163 |
159 @Override | 164 @Override |
160 protected void onStart() { | 165 protected void onStart() { |
161 super.onStart(); | 166 super.onStart(); |
162 mActivityLifecycleListener.onActivityStarted(this); | 167 mActivityLifecycleListener.onActivityStarted(this); |
163 JniInterface.enableVideoChannel(true); | 168 mClient.enableVideoChannel(true); |
164 mRemoteHostDesktop.attachRedrawCallback(); | 169 mRemoteHostDesktop.attachRedrawCallback(); |
165 CapabilityManager.getInstance().addListener(this); | 170 mClient.getCapabilityManager().addListener(this); |
166 } | 171 } |
167 | 172 |
168 @Override | 173 @Override |
169 protected void onPause() { | 174 protected void onPause() { |
170 if (isFinishing()) mActivityLifecycleListener.onActivityPaused(this); | 175 if (isFinishing()) mActivityLifecycleListener.onActivityPaused(this); |
171 super.onPause(); | 176 super.onPause(); |
172 if (!mSwitchToCardboardDesktopActivity) { | 177 if (!mSwitchToCardboardDesktopActivity) { |
173 JniInterface.enableVideoChannel(false); | 178 mClient.enableVideoChannel(false); |
174 } | 179 } |
175 stopActionBarAutoHideTimer(); | 180 stopActionBarAutoHideTimer(); |
176 } | 181 } |
177 | 182 |
178 @Override | 183 @Override |
179 public void onResume() { | 184 public void onResume() { |
180 super.onResume(); | 185 super.onResume(); |
181 mActivityLifecycleListener.onActivityResumed(this); | 186 mActivityLifecycleListener.onActivityResumed(this); |
182 JniInterface.enableVideoChannel(true); | 187 mClient.enableVideoChannel(true); |
183 startActionBarAutoHideTimer(); | 188 startActionBarAutoHideTimer(); |
184 } | 189 } |
185 | 190 |
186 @Override | 191 @Override |
187 protected void onStop() { | 192 protected void onStop() { |
188 CapabilityManager.getInstance().removeListener(this); | 193 mClient.getCapabilityManager().removeListener(this); |
189 mActivityLifecycleListener.onActivityStopped(this); | 194 mActivityLifecycleListener.onActivityStopped(this); |
190 super.onStop(); | 195 super.onStop(); |
191 if (mSwitchToCardboardDesktopActivity) { | 196 if (mSwitchToCardboardDesktopActivity) { |
192 mSwitchToCardboardDesktopActivity = false; | 197 mSwitchToCardboardDesktopActivity = false; |
193 } else { | 198 } else { |
194 JniInterface.enableVideoChannel(false); | 199 mClient.enableVideoChannel(false); |
195 } | 200 } |
196 } | 201 } |
197 | 202 |
198 /** Called to initialize the action bar. */ | 203 /** Called to initialize the action bar. */ |
199 @Override | 204 @Override |
200 public boolean onCreateOptionsMenu(Menu menu) { | 205 public boolean onCreateOptionsMenu(Menu menu) { |
201 getMenuInflater().inflate(R.menu.desktop_actionbar, menu); | 206 getMenuInflater().inflate(R.menu.desktop_actionbar, menu); |
202 | 207 |
203 mActivityLifecycleListener.onActivityCreatedOptionsMenu(this, menu); | 208 mActivityLifecycleListener.onActivityCreatedOptionsMenu(this, menu); |
204 | 209 |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 } | 476 } |
472 if (id == R.id.actionbar_keyboard) { | 477 if (id == R.id.actionbar_keyboard) { |
473 ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggle SoftInput(0, 0); | 478 ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggle SoftInput(0, 0); |
474 return true; | 479 return true; |
475 } | 480 } |
476 if (id == R.id.actionbar_hide) { | 481 if (id == R.id.actionbar_hide) { |
477 hideActionBar(); | 482 hideActionBar(); |
478 return true; | 483 return true; |
479 } | 484 } |
480 if (id == R.id.actionbar_disconnect || id == android.R.id.home) { | 485 if (id == R.id.actionbar_disconnect || id == android.R.id.home) { |
481 JniInterface.disconnectFromHost(); | 486 mClient.destroy(); |
482 return true; | 487 return true; |
483 } | 488 } |
484 if (id == R.id.actionbar_send_ctrl_alt_del) { | 489 if (id == R.id.actionbar_send_ctrl_alt_del) { |
485 int[] keys = { | 490 int[] keys = { |
486 KeyEvent.KEYCODE_CTRL_LEFT, | 491 KeyEvent.KEYCODE_CTRL_LEFT, |
487 KeyEvent.KEYCODE_ALT_LEFT, | 492 KeyEvent.KEYCODE_ALT_LEFT, |
488 KeyEvent.KEYCODE_FORWARD_DEL, | 493 KeyEvent.KEYCODE_FORWARD_DEL, |
489 }; | 494 }; |
490 for (int key : keys) { | 495 for (int key : keys) { |
491 JniInterface.sendKeyEvent(0, key, true); | 496 mClient.sendKeyEvent(0, key, true); |
492 } | 497 } |
493 for (int key : keys) { | 498 for (int key : keys) { |
494 JniInterface.sendKeyEvent(0, key, false); | 499 mClient.sendKeyEvent(0, key, false); |
495 } | 500 } |
496 return true; | 501 return true; |
497 } | 502 } |
498 if (id == R.id.actionbar_help) { | 503 if (id == R.id.actionbar_help) { |
499 HelpSingleton.getInstance().launchHelp(this, HelpContext.DESKTOP); | 504 HelpSingleton.getInstance().launchHelp(this, HelpContext.DESKTOP); |
500 return true; | 505 return true; |
501 } | 506 } |
502 return super.onOptionsItemSelected(item); | 507 return super.onOptionsItemSelected(item); |
503 } | 508 } |
504 | 509 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
577 * Called once when a keyboard key is pressed, then again when that same key is released. This | 582 * Called once when a keyboard key is pressed, then again when that same key is released. This |
578 * is not guaranteed to be notified of all soft keyboard events: certian key boards might not | 583 * is not guaranteed to be notified of all soft keyboard events: certian key boards might not |
579 * call it at all, while others might skip it in certain situations (e.g. sw ipe input). | 584 * call it at all, while others might skip it in certain situations (e.g. sw ipe input). |
580 */ | 585 */ |
581 @Override | 586 @Override |
582 public boolean dispatchKeyEvent(KeyEvent event) { | 587 public boolean dispatchKeyEvent(KeyEvent event) { |
583 int keyCode = event.getKeyCode(); | 588 int keyCode = event.getKeyCode(); |
584 | 589 |
585 // Dispatch the back button to the system to handle navigation | 590 // Dispatch the back button to the system to handle navigation |
586 if (keyCode == KeyEvent.KEYCODE_BACK) { | 591 if (keyCode == KeyEvent.KEYCODE_BACK) { |
587 JniInterface.disconnectFromHost(); | 592 mClient.destroy(); |
588 return super.dispatchKeyEvent(event); | 593 return super.dispatchKeyEvent(event); |
589 } | 594 } |
590 | 595 |
591 boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; | 596 boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
592 | 597 |
593 // Physical keyboard must work as if it is connected to the remote host | 598 // Physical keyboard must work as if it is connected to the remote host |
594 // and so events coming from physical keyboard never generate text | 599 // and so events coming from physical keyboard never generate text |
595 // events. Also scan codes must be used instead of key code, so that | 600 // events. Also scan codes must be used instead of key code, so that |
596 // the keyboard layout selected on the client doesn't affect the key | 601 // the keyboard layout selected on the client doesn't affect the key |
597 // codes sent to the host. | 602 // codes sent to the host. |
598 if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) { | 603 if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) { |
599 return JniInterface.sendKeyEvent(event.getScanCode(), 0, pressed); | 604 return mClient.sendKeyEvent(event.getScanCode(), 0, pressed); |
600 } | 605 } |
601 | 606 |
602 // Events received from software keyboards generate TextEvent in two | 607 // Events received from software keyboards generate TextEvent in two |
603 // cases: | 608 // cases: |
604 // 1. This is an ACTION_MULTIPLE event. | 609 // 1. This is an ACTION_MULTIPLE event. |
605 // 2. Ctrl, Alt and Meta are not pressed. | 610 // 2. Ctrl, Alt and Meta are not pressed. |
606 // This ensures that on-screen keyboard always injects input that | 611 // This ensures that on-screen keyboard always injects input that |
607 // correspond to what user sees on the screen, while physical keyboard | 612 // correspond to what user sees on the screen, while physical keyboard |
608 // acts as if it is connected to the remote host. | 613 // acts as if it is connected to the remote host. |
609 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { | 614 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { |
610 JniInterface.sendTextEvent(event.getCharacters()); | 615 mClient.sendTextEvent(event.getCharacters()); |
611 return true; | 616 return true; |
612 } | 617 } |
613 | 618 |
614 // For Enter getUnicodeChar() returns 10 (line feed), but we still | 619 // For Enter getUnicodeChar() returns 10 (line feed), but we still |
615 // want to send it as KeyEvent. | 620 // want to send it as KeyEvent. |
616 int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0; | 621 int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0; |
617 | 622 |
618 boolean no_modifiers = !event.isAltPressed() | 623 boolean no_modifiers = !event.isAltPressed() |
619 && !event.isCtrlPressed() && !event.isMetaPressed(); | 624 && !event.isCtrlPressed() && !event.isMetaPressed(); |
620 | 625 |
621 if (pressed && unicode != 0 && no_modifiers) { | 626 if (pressed && unicode != 0 && no_modifiers) { |
622 mPressedTextKeys.add(keyCode); | 627 mPressedTextKeys.add(keyCode); |
623 int[] codePoints = { unicode }; | 628 int[] codePoints = { unicode }; |
624 JniInterface.sendTextEvent(new String(codePoints, 0, 1)); | 629 mClient.sendTextEvent(new String(codePoints, 0, 1)); |
625 return true; | 630 return true; |
626 } | 631 } |
627 | 632 |
628 if (!pressed && mPressedTextKeys.contains(keyCode)) { | 633 if (!pressed && mPressedTextKeys.contains(keyCode)) { |
629 mPressedTextKeys.remove(keyCode); | 634 mPressedTextKeys.remove(keyCode); |
630 return true; | 635 return true; |
631 } | 636 } |
632 | 637 |
633 switch (keyCode) { | 638 switch (keyCode) { |
634 // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are | 639 // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are |
635 // deprecated, but they still need to be here for older devices and | 640 // deprecated, but they still need to be here for older devices and |
636 // third-party keyboards that may still generate these events. See | 641 // third-party keyboards that may still generate these events. See |
637 // https://source.android.com/devices/input/keyboard-devices.html#le gacy-unsupported-keys | 642 // https://source.android.com/devices/input/keyboard-devices.html#le gacy-unsupported-keys |
638 case KeyEvent.KEYCODE_AT: | 643 case KeyEvent.KEYCODE_AT: |
639 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, presse d); | 644 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
640 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed); | 645 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed); |
641 return true; | 646 return true; |
642 | 647 |
643 case KeyEvent.KEYCODE_POUND: | 648 case KeyEvent.KEYCODE_POUND: |
644 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, presse d); | 649 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
645 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed); | 650 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed); |
646 return true; | 651 return true; |
647 | 652 |
648 case KeyEvent.KEYCODE_STAR: | 653 case KeyEvent.KEYCODE_STAR: |
649 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, presse d); | 654 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
650 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed); | 655 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed); |
651 return true; | 656 return true; |
652 | 657 |
653 case KeyEvent.KEYCODE_PLUS: | 658 case KeyEvent.KEYCODE_PLUS: |
654 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, presse d); | 659 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
655 JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed); | 660 mClient.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed); |
656 return true; | 661 return true; |
657 | 662 |
658 default: | 663 default: |
659 // We try to send all other key codes to the host directly. | 664 // We try to send all other key codes to the host directly. |
660 return JniInterface.sendKeyEvent(0, keyCode, pressed); | 665 return mClient.sendKeyEvent(0, keyCode, pressed); |
661 } | 666 } |
662 } | 667 } |
663 } | 668 } |
OLD | NEW |