Desktop.java revision effb81e5f8246d0db0270817048dc992db66e9fb
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 3// found in the LICENSE file. 4 5package org.chromium.chromoting; 6 7import android.app.Activity; 8import android.content.res.Configuration; 9import android.os.Bundle; 10import android.view.KeyEvent; 11import android.view.Menu; 12import android.view.MenuItem; 13import android.view.View; 14import android.view.inputmethod.InputMethodManager; 15import android.widget.ImageButton; 16 17import org.chromium.chromoting.jni.JniInterface; 18 19/** 20 * A simple screen that does nothing except display a DesktopView and notify it of rotations. 21 */ 22public class Desktop extends Activity { 23 /** Web page to be displayed in the Help screen when launched from this activity. */ 24 private static final String HELP_URL = 25 "http://support.google.com/chrome/?p=mobile_crd_connecthost"; 26 27 /** The surface that displays the remote host's desktop feed. */ 28 private DesktopView mRemoteHostDesktop; 29 30 /** The button used to show the action bar. */ 31 private ImageButton mOverlayButton; 32 33 /** Called when the activity is first created. */ 34 @Override 35 public void onCreate(Bundle savedInstanceState) { 36 super.onCreate(savedInstanceState); 37 setContentView(R.layout.desktop); 38 mRemoteHostDesktop = (DesktopView)findViewById(R.id.desktop_view); 39 mOverlayButton = (ImageButton)findViewById(R.id.desktop_overlay_button); 40 mRemoteHostDesktop.setDesktop(this); 41 42 // Ensure the button is initially hidden. 43 showActionBar(); 44 } 45 46 /** Called when the activity is finally finished. */ 47 @Override 48 public void onDestroy() { 49 super.onDestroy(); 50 JniInterface.disconnectFromHost(); 51 } 52 53 /** Called when the display is rotated (as registered in the manifest). */ 54 @Override 55 public void onConfigurationChanged(Configuration newConfig) { 56 super.onConfigurationChanged(newConfig); 57 mRemoteHostDesktop.onScreenConfigurationChanged(); 58 } 59 60 /** Called to initialize the action bar. */ 61 @Override 62 public boolean onCreateOptionsMenu(Menu menu) { 63 getMenuInflater().inflate(R.menu.desktop_actionbar, menu); 64 return super.onCreateOptionsMenu(menu); 65 } 66 67 public void showActionBar() { 68 mOverlayButton.setVisibility(View.INVISIBLE); 69 getActionBar().show(); 70 } 71 72 public void hideActionBar() { 73 mOverlayButton.setVisibility(View.VISIBLE); 74 getActionBar().hide(); 75 } 76 77 /** The overlay button's onClick handler. */ 78 public void onOverlayButtonPressed(View view) { 79 showActionBar(); 80 } 81 82 /** Called whenever an action bar button is pressed. */ 83 @Override 84 public boolean onOptionsItemSelected(MenuItem item) { 85 switch (item.getItemId()) { 86 case R.id.actionbar_keyboard: 87 ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, 0); 88 return true; 89 90 case R.id.actionbar_hide: 91 hideActionBar(); 92 return true; 93 94 case R.id.actionbar_disconnect: 95 JniInterface.disconnectFromHost(); 96 return true; 97 98 case R.id.actionbar_send_ctrl_alt_del: 99 { 100 int[] keys = { 101 KeyEvent.KEYCODE_CTRL_LEFT, 102 KeyEvent.KEYCODE_ALT_LEFT, 103 KeyEvent.KEYCODE_FORWARD_DEL, 104 }; 105 for (int key : keys) { 106 JniInterface.sendKeyEvent(key, true); 107 } 108 for (int key : keys) { 109 JniInterface.sendKeyEvent(key, false); 110 } 111 } 112 return true; 113 114 case R.id.actionbar_help: 115 HelpActivity.launch(this, HELP_URL); 116 return true; 117 118 default: 119 return super.onOptionsItemSelected(item); 120 } 121 } 122 123 /** 124 * Called once when a keyboard key is pressed, then again when that same key is released. This 125 * is not guaranteed to be notified of all soft keyboard events: certian keyboards might not 126 * call it at all, while others might skip it in certain situations (e.g. swipe input). 127 */ 128 @Override 129 public boolean dispatchKeyEvent(KeyEvent event) { 130 // Send ACTION_MULTIPLE event as TextEvent. 131 // 132 // TODO(sergeyu): For all keys on English keyboard Android generates 133 // ACTION_DOWN/ACTION_UP events, so they are sent as KeyEvent instead of 134 // TextEvent. As result the host may handle them as non-English chars 135 // when it has non-English layout selected, which might be confusing for 136 // the user. This code should be fixed to send all text input events as 137 // TextEvent, but it cannot be done now because not all hosts support 138 // TextEvent. Also, to handle keyboard shortcuts properly this code will 139 // need to track the state of modifier keys (such as Ctrl or Alt) and 140 // send KeyEvents in the case any of the modifier keys are pressed. 141 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { 142 JniInterface.sendTextEvent(event.getCharacters()); 143 return super.dispatchKeyEvent(event); 144 } 145 146 boolean depressed = event.getAction() == KeyEvent.ACTION_DOWN; 147 148 switch (event.getKeyCode()) { 149 case KeyEvent.KEYCODE_AT: 150 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed); 151 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, depressed); 152 break; 153 154 case KeyEvent.KEYCODE_POUND: 155 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed); 156 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, depressed); 157 break; 158 159 case KeyEvent.KEYCODE_STAR: 160 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed); 161 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, depressed); 162 break; 163 164 case KeyEvent.KEYCODE_PLUS: 165 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed); 166 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, depressed); 167 break; 168 169 default: 170 // We try to send all other key codes to the host directly. 171 JniInterface.sendKeyEvent(event.getKeyCode(), depressed); 172 } 173 174 return super.dispatchKeyEvent(event); 175 } 176} 177