summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsolb@chromium.org <solb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-31 09:20:17 +0000
committersolb@chromium.org <solb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-31 09:20:17 +0000
commit192c7a49de6264582d38ad3ed83fc9dc554342f4 (patch)
tree623dd6593863c3941f8d3149311e949f66e6c4d9 /remoting
parent316ec762de4612c0ab8eb0e4154ec8dc515d6fd1 (diff)
downloadchromium_src-192c7a49de6264582d38ad3ed83fc9dc554342f4.zip
chromium_src-192c7a49de6264582d38ad3ed83fc9dc554342f4.tar.gz
chromium_src-192c7a49de6264582d38ad3ed83fc9dc554342f4.tar.bz2
Add Android Chromoting client keyboard input
Tapping the screen with three fingers now shows more options, namely one to pop up a keyboard! Review URL: https://chromiumcodereview.appspot.com/21120005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@214646 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/android/java/AndroidManifest.xml7
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/Desktop.java45
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/DesktopView.java60
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java14
-rw-r--r--remoting/client/jni/android_keymap.cc208
-rw-r--r--remoting/client/jni/android_keymap.h23
-rw-r--r--remoting/client/jni/chromoting_jni_instance.cc23
-rw-r--r--remoting/client/jni/chromoting_jni_instance.h3
-rw-r--r--remoting/client/jni/jni_interface.cc9
-rw-r--r--remoting/remoting.gyp9
-rw-r--r--remoting/resources/actionbar.xml12
-rw-r--r--remoting/resources/strings.xml4
-rw-r--r--remoting/resources/styles.xml8
13 files changed, 398 insertions, 27 deletions
diff --git a/remoting/android/java/AndroidManifest.xml b/remoting/android/java/AndroidManifest.xml
index 02db6dd..16014ad 100644
--- a/remoting/android/java/AndroidManifest.xml
+++ b/remoting/android/java/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.chromium.chromoting"
- android:versionCode="5"
- android:versionName="0.05">
+ android:versionCode="6"
+ android:versionName="0.06">
<uses-sdk android:minSdkVersion="14"
android:targetSdkVersion="14"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
@@ -19,6 +19,7 @@
</activity>
<activity android:name="Desktop"
android:configChanges="orientation|screenSize"
- android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"/>
+ android:theme="@style/Theme_ElusiveActionBar"
+ android:windowSoftInputMode="adjustResize"/>
</application>
</manifest>
diff --git a/remoting/android/java/src/org/chromium/chromoting/Desktop.java b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
index 36b6f74..7c8bb11 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Desktop.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
@@ -7,6 +7,12 @@ package org.chromium.chromoting;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
import org.chromium.chromoting.jni.JniInterface;
@@ -14,7 +20,7 @@ import org.chromium.chromoting.jni.JniInterface;
* A simple screen that does nothing except display a DesktopView and notify it of rotations.
*/
public class Desktop extends Activity {
- /** Whether the device has just been rotated. */
+ /** The surface that displays the remote host's desktop feed. */
private DesktopView remoteHostDesktop;
/** Called when the activity is first created. */
@@ -36,6 +42,41 @@ public class Desktop extends Activity {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- remoteHostDesktop.requestCanvasRedraw();
+ remoteHostDesktop.requestRecheckConstrainingDimension();
+ }
+
+ /** Called to initialize the action bar. */
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.actionbar, menu);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ /** Called whenever an action bar button is pressed. */
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.actionbar_keyboard:
+ ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, 0);
+ return true;
+ case R.id.actionbar_hide:
+ getActionBar().hide();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ /** Called when a hardware key is pressed, and usually when a software key is pressed. */
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ JniInterface.keyboardAction(event.getKeyCode(), event.getAction() == KeyEvent.ACTION_DOWN);
+
+ if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
+ // We stop this event from propagating further to prevent the keyboard from closing.
+ return true;
+ }
+
+ return super.dispatchKeyEvent(event);
}
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
index 52151c6..f02dd78 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -4,7 +4,8 @@
package org.chromium.chromoting;
-import android.content.Context;
+import android.app.ActionBar;
+import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -52,6 +53,8 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
UNDEFINED, WIDTH, HEIGHT
}
+ private ActionBar mActionBar;
+
private GestureDetector mScroller;
private ScaleGestureDetector mZoomer;
@@ -64,6 +67,9 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
/** Specifies the dimension by which the zoom level is being lower-bounded. */
private Constraint mConstraint;
+ /** Whether the dimension of constraint should be reckecked on the next aspect ratio change. */
+ private boolean mRecheckConstraint;
+
/** Whether the right edge of the image was visible on-screen during the last render. */
private boolean mRightUsedToBeOut;
@@ -73,11 +79,10 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
private int mMouseButton;
private boolean mMousePressed;
- /** Whether the canvas needs to be redrawn. The update occurs when its size is next updated. */
- private boolean mCanvasNeedsRedraw;
-
- public DesktopView(Context context) {
+ public DesktopView(Activity context) {
super(context);
+ mActionBar = context.getActionBar();
+
getHolder().addCallback(this);
DesktopListener listener = new DesktopListener();
mScroller = new GestureDetector(context, listener);
@@ -86,15 +91,15 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
mTransform = new Matrix();
mScreenWidth = 0;
mScreenHeight = 0;
+
mConstraint = Constraint.UNDEFINED;
+ mRecheckConstraint = false;
mRightUsedToBeOut = false;
mBottomUsedToBeOut = false;
mMouseButton = BUTTON_UNDEFINED;
mMousePressed = false;
-
- mCanvasNeedsRedraw = false;
}
/**
@@ -127,8 +132,8 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
boolean recenter = false;
if (mConstraint == Constraint.UNDEFINED) {
- mConstraint = image.getWidth()/image.getHeight() > mScreenWidth/mScreenHeight ?
- Constraint.WIDTH : Constraint.HEIGHT;
+ mConstraint = (double)image.getWidth()/image.getHeight() >
+ (double)mScreenWidth/mScreenHeight ? Constraint.WIDTH : Constraint.HEIGHT;
recenter = true; // We always rescale and recenter after a rotation.
}
@@ -209,9 +214,15 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
getHolder().unlockCanvasAndPost(canvas);
}
- /** Causes the canvas to be redrawn the next time our surface changes. */
- public void requestCanvasRedraw() {
- mCanvasNeedsRedraw = true;
+ /**
+ * Causes the next canvas redraw to perform a check for which screen dimension more tightly
+ * constrains the view of the image. This should be called between the time that a screen size
+ * change is requested and the time it actually occurs. If it is not called in such a case, the
+ * screen will not be rearranged as aggressively (which is desirable when the software keyboard
+ * appears in order to allow it to cover the image without forcing a resize).
+ */
+ public void requestRecheckConstrainingDimension() {
+ mRecheckConstraint = true;
}
/**
@@ -221,15 +232,20 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
@Override
public void surfaceChanged(
SurfaceHolder holder, int format, int width, int height) {
+ mActionBar.hide();
+
synchronized (mTransform) {
mScreenWidth = width;
mScreenHeight = height;
- mConstraint = Constraint.UNDEFINED;
+
+ if (mRecheckConstraint) {
+ mConstraint = Constraint.UNDEFINED;
+ mRecheckConstraint = false;
+ }
}
- if (mCanvasNeedsRedraw) {
- JniInterface.redrawGraphics();
- mCanvasNeedsRedraw = false;
+ if (!JniInterface.redrawGraphics()) {
+ JniInterface.provideRedrawCallback(this);
}
}
@@ -237,7 +253,6 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i("deskview", "DesktopView.surfaceCreated(...)");
- JniInterface.provideRedrawCallback(this);
}
/**
@@ -247,10 +262,9 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("deskview", "DesktopView.surfaceDestroyed(...)");
- JniInterface.provideRedrawCallback(null);
- // Redraw the desktop as soon as the user switches back to this window.
- mCanvasNeedsRedraw = true;
+ // Stop this canvas from being redrawn.
+ JniInterface.provideRedrawCallback(null);
}
/** Called when a mouse action is made. */
@@ -270,9 +284,13 @@ public class DesktopView extends SurfaceView implements Runnable, SurfaceHolder.
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (event.getPointerCount() == 3) {
+ mActionBar.show();
+ }
+
boolean handled = mScroller.onTouchEvent(event) || mZoomer.onTouchEvent(event);
- if (event.getPointerCount()==1) {
+ if (event.getPointerCount() == 1) {
float[] coordinates = {event.getRawX(), event.getY()};
switch (event.getActionMasked()) {
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
index 0d7660b..5505618 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -179,7 +179,7 @@ public class JniInterface {
/** Forces the native graphics thread to redraw to the canvas. */
public static boolean redrawGraphics() {
synchronized(JniInterface.class) {
- if (!sConnected) return false;
+ if (!sConnected || sRedrawCallback == null) return false;
}
scheduleRedrawNative();
@@ -222,6 +222,15 @@ public class JniInterface {
mouseActionNative(x, y, whichButton, buttonDown);
}
+ /** Presses and releases the specified key. */
+ public static void keyboardAction(int keyCode, boolean keyDown) {
+ if (!sConnected) {
+ return;
+ }
+
+ keyboardActionNative(keyCode, keyDown);
+ }
+
/** Performs the native response to the user's PIN. */
private static native void authenticationResponse(String pin);
@@ -230,4 +239,7 @@ public class JniInterface {
/** Passes mouse information to the native handling code. */
private static native void mouseActionNative(int x, int y, int whichButton, boolean buttonDown);
+
+ /** Passes key press information to the native handling code. */
+ private static native void keyboardActionNative(int keyCode, boolean keyDown);
}
diff --git a/remoting/client/jni/android_keymap.cc b/remoting/client/jni/android_keymap.cc
new file mode 100644
index 0000000..f427046
--- /dev/null
+++ b/remoting/client/jni/android_keymap.cc
@@ -0,0 +1,208 @@
+// Copyright 2013 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.
+
+#include "remoting/client/jni/android_keymap.h"
+
+namespace {
+
+// These must be defined in the same order as the Android keycodes in
+// <android/keycodes.h> and
+// "ui/base/keycodes/keyboard_code_conversion_android.cc" . Some of these
+// mappings assume a US keyboard layout for now.
+const uint32 usb_keycodes[] = {
+ 0, // UNKNOWN
+ 0, // SOFT_LEFT
+ 0, // SOFT_RIGHT
+ 0, // HOME
+ 0, // BACK
+ 0, // CALL
+ 0, // ENDCALL
+
+ 0x070027, // 0
+ 0x07001e, // 1
+ 0x07001f, // 2
+ 0x070020, // 3
+ 0x070021, // 4
+ 0x070022, // 5
+ 0x070023, // 6
+ 0x070024, // 7
+ 0x070025, // 8
+ 0x070026, // 9
+
+ 0, // STAR
+ 0, // POUND
+ 0x070052, // DPAD_UP
+ 0x070051, // DPAD_DOWN
+ 0x070050, // DPAD_LEFT
+ 0x07004f, // DPAD_RIGHT
+ 0, // DPAD_CENTER
+ 0, // VOLUME_UP
+ 0, // VOLUME_DOWN
+ 0, // POWER
+ 0, // CAMERA
+ 0, // CLEAR
+
+ 0x070004, // A
+ 0x070005, // B
+ 0x070006, // C
+ 0x070007, // D
+ 0x070008, // E
+ 0x070009, // F
+ 0x07000a, // G
+ 0x07000b, // H
+ 0x07000c, // I
+ 0x07000d, // J
+ 0x07000e, // K
+ 0x07000f, // L
+ 0x070010, // M
+ 0x070011, // N
+ 0x070012, // O
+ 0x070013, // P
+ 0x070014, // Q
+ 0x070015, // R
+ 0x070016, // S
+ 0x070017, // T
+ 0x070018, // U
+ 0x070019, // V
+ 0x07001a, // W
+ 0x07001b, // X
+ 0x07001c, // Y
+ 0x07001d, // Z
+
+ 0x070036, // COMMA
+ 0x070037, // PERIOD
+
+ 0x0700e2, // ALT_LEFT
+ 0x0700e6, // ALT_RIGHT
+ 0x0700e1, // SHIFT_LEFT
+ 0x0700e5, // SHIFT_RIGHT
+
+ 0x07002b, // TAB
+ 0x07002c, // SPACE
+
+ 0, // SYM
+ 0, // EXPLORER
+ 0, // ENVELOPE
+
+ 0x070028, // ENTER
+ 0x07002a, // DEL (backspace)
+
+ 0x070035, // GRAVE (backtick)
+ 0x07002d, // MINUS
+ 0x07002e, // EQUALS
+ 0x07002f, // LEFT_BRACKET
+ 0x070030, // RIGHT_BRACKET
+ 0x070031, // BACKSLASH
+ 0x070033, // SEMICOLON
+ 0x070034, // APOSTROPHE
+ 0x070038, // SLASH
+
+ 0, // AT
+ 0, // NUM
+ 0, // HEADSETHOOK
+ 0, // FOCUS
+ 0, // PLUS
+ 0, // MENU
+ 0, // NOTIFICATION
+ 0, // SEARCH
+ 0, // MEDIA_PLAY_PAUSE
+ 0, // MEDIA_STOP
+ 0, // MEDIA_NEXT
+ 0, // MEDIA_PREVIOUS
+ 0, // MEDIA_REWIND
+ 0, // MEDIA_FAST_FORWARD
+ 0, // MUTE
+
+ 0x07004b, // PAGE_UP
+ 0x07004e, // PAGE_DOWN
+
+ 0, // PICTSYMBOLS
+ 0, // SWITCH_CHARSET
+ 0, // BUTTON_A
+ 0, // BUTTON_B
+ 0, // BUTTON_C
+ 0, // BUTTON_X
+ 0, // BUTTON_Y
+ 0, // BUTTON_Z
+ 0, // BUTTON_L1
+ 0, // BUTTON_R1
+ 0, // BUTTON_L2
+ 0, // BUTTON_R2
+ 0, // BUTTON_THUMBL
+ 0, // BUTTON_THUMBR
+ 0, // BUTTON_START
+ 0, // BUTTON_SELECT
+ 0, // BUTTON_MODE
+
+ 0x070029, // ESCAPE
+ 0x07004c, // FORWARD_DEL
+
+ 0x0700e0, // CTRL_LEFT
+ 0x0700e4, // CTRL_RIGHT
+ 0, // CAPS_LOCK
+ 0, // SCROLL_LOCK
+ 0x0700e3, // META_LEFT
+ 0x0700e7, // META_RIGHT
+ 0, // FUNCTION
+
+ 0x070046, // SYSRQ (printscreen)
+ 0x070048, // BREAK (pause)
+ 0x07004a, // MOVE_HOME (home)
+ 0x07004d, // MOVE_END (end)
+ 0x070049, // INSERT
+
+ 0, // FORWARD
+ 0, // MEDIA_PLAY
+ 0, // MEDIA_PAUSE
+ 0, // MEDIA_CLOSE
+ 0, // MEDIA_EJECT
+ 0, // MEDIA_RECORD
+
+ 0x07003a, // F1
+ 0x07003b, // F2
+ 0x07003c, // F3
+ 0x07003d, // F4
+ 0x07003e, // F5
+ 0x07003f, // F6
+ 0x070040, // F7
+ 0x070041, // F8
+ 0x070042, // F9
+ 0x070043, // F10
+ 0x070044, // F11
+ 0x070045, // F12
+
+ 0, // NUM_LOCK
+
+ 0x070062, // NUMPAD_0
+ 0x070059, // NUMPAD_1
+ 0x07005a, // NUMPAD_2
+ 0x07005b, // NUMPAD_3
+ 0x07005c, // NUMPAD_4
+ 0x07005d, // NUMPAD_5
+ 0x07005e, // NUMPAD_6
+ 0x07005f, // NUMPAD_7
+ 0x070060, // NUMPAD_8
+ 0x070061, // NUMPAD_9
+
+ 0x070054, // NUMPAD_DIVIDE
+ 0x070055, // NUMPAD_MULTIPLY
+ 0x070056, // NUMPAD_SUBTRACT
+ 0x070057, // NUMPAD_ADD
+ 0x070063, // NUMPAD_DOT
+ 0x070085, // NUMPAD_COMMA
+ 0x070058, // NUMPAD_ENTER
+ 0x070067, // NUMPAD_EQUALS
+ 0x0700b6, // NUMPAD_LEFT_PAREN
+ 0x0700b7, // NUMPAD_RIGHT_PAREN
+};
+
+}
+
+namespace remoting {
+
+uint32 AndroidKeycodeToUsbKeycode(int android) {
+ return usb_keycodes[android];
+}
+
+} // namespace remoting
diff --git a/remoting/client/jni/android_keymap.h b/remoting/client/jni/android_keymap.h
new file mode 100644
index 0000000..9a9f3a3
--- /dev/null
+++ b/remoting/client/jni/android_keymap.h
@@ -0,0 +1,23 @@
+// Copyright 2013 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.
+
+#ifndef REMOTING_CLIENT_JNI_ANDROID_KEYMAP_H_
+#define REMOTING_CLIENT_JNI_ANDROID_KEYMAP_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace remoting {
+
+// This is a temporary hack to convert Android's virtual keycodes into USB
+// scancodes. Unfortunately, the current solution uses key mappings whose
+// layout is determined according to the client device's input locale instead
+// of the host's internationalization preferences. The whole process needs to
+// be rethought to accomplish this in an localizable and future-proof way.
+// TODO(solb): crbug.com/265945
+uint32 AndroidKeycodeToUsbKeycode(int android);
+
+} // namespace remoting
+
+#endif
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index ecf8632..dcec68f 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "remoting/client/audio_player.h"
+#include "remoting/client/jni/android_keymap.h"
#include "remoting/client/jni/chromoting_jni_runtime.h"
#include "remoting/protocol/libjingle_transport_factory.h"
@@ -105,6 +106,28 @@ void ChromotingJniInstance::PerformMouseAction(
connection_->input_stub()->InjectMouseEvent(action);
}
+void ChromotingJniInstance::PerformKeyboardAction(int keyCode, bool keyDown) {
+ if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
+ jni_runtime_->network_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ChromotingJniInstance::PerformKeyboardAction,
+ this,
+ keyCode,
+ keyDown));
+ return;
+ }
+
+ uint32 usbCode = AndroidKeycodeToUsbKeycode(keyCode);
+ if (usbCode) {
+ protocol::KeyEvent action;
+ action.set_usb_keycode(usbCode);
+ action.set_pressed(keyDown);
+ connection_->input_stub()->InjectKeyEvent(action);
+ }
+ else
+ LOG(WARNING) << "Ignoring unknown keycode: " << keyCode;
+}
+
void ChromotingJniInstance::OnConnectionState(
protocol::ConnectionToHost::State state,
protocol::ErrorCode error) {
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h
index 5a26cf4..9fb1516 100644
--- a/remoting/client/jni/chromoting_jni_instance.h
+++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -64,6 +64,9 @@ class ChromotingJniInstance
protocol::MouseEvent_MouseButton button,
bool buttonDown);
+ // Sends the provided keyboard scan code to the host.
+ void PerformKeyboardAction(int keyCode, bool keyDown);
+
// ClientUserInterface implementation.
virtual void OnConnectionState(
protocol::ConnectionToHost::State state,
diff --git a/remoting/client/jni/jni_interface.cc b/remoting/client/jni/jni_interface.cc
index 5dc462d..5ca45a0 100644
--- a/remoting/client/jni/jni_interface.cc
+++ b/remoting/client/jni/jni_interface.cc
@@ -127,4 +127,13 @@ JNIEXPORT void JNICALL JNI_IMPLEMENTATION(mouseActionNative)(
button_down);
}
+JNIEXPORT void JNICALL JNI_IMPLEMENTATION(keyboardActionNative)(
+ JNIEnv* env,
+ jobject that,
+ jint key_code,
+ jboolean key_down) {
+ remoting::ChromotingJniRuntime::GetInstance()->session()->
+ PerformKeyboardAction(key_code, key_down);
+}
+
} // extern "C"
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index c8c14cd..890775c 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -1694,6 +1694,8 @@
'../google_apis/google_apis.gyp:google_apis',
],
'sources': [
+ 'client/jni/android_keymap.cc',
+ 'client/jni/android_keymap.h',
'client/jni/chromoting_jni_instance.cc',
'client/jni/chromoting_jni_instance.h',
'client/jni/chromoting_jni_runtime.cc',
@@ -1722,9 +1724,16 @@
],
},
{
+ 'destination': '<(SHARED_INTERMEDIATE_DIR)/remoting/android/res/menu',
+ 'files': [
+ 'resources/actionbar.xml',
+ ],
+ },
+ {
'destination': '<(SHARED_INTERMEDIATE_DIR)/remoting/android/res/values',
'files': [
'resources/strings.xml',
+ 'resources/styles.xml',
],
},
],
diff --git a/remoting/resources/actionbar.xml b/remoting/resources/actionbar.xml
new file mode 100644
index 0000000..4cf611ed
--- /dev/null
+++ b/remoting/resources/actionbar.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Action bar buttons for the Android app-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/actionbar_keyboard"
+ android:title="@string/actionbar_keyboard"
+ android:icon="@android:drawable/ic_menu_edit"
+ android:showAsAction="ifRoom|withText"/>
+ <item android:id="@+id/actionbar_hide"
+ android:title="@string/actionbar_hide"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:showAsAction="ifRoom|withText"/>
+</menu>
diff --git a/remoting/resources/strings.xml b/remoting/resources/strings.xml
index e2efc8e..27dad55 100644
--- a/remoting/resources/strings.xml
+++ b/remoting/resources/strings.xml
@@ -14,6 +14,10 @@
<string name="pin_entry_connect">Connect</string>
<string name="pin_entry_cancel">Cancel</string>
+ <!--Action bar buttons-->
+ <string name="actionbar_hide">Hide</string>
+ <string name="actionbar_keyboard">Keyboard</string>
+
<!--Informative messages-->
<string name="msg_pin_canceled">No PIN was provided, so the connection attempt was canceled</string>
<string name="msg_pin_entered">Attempting to authenticate to specified host with provided PIN</string>
diff --git a/remoting/resources/styles.xml b/remoting/resources/styles.xml
new file mode 100644
index 0000000..ecd4929
--- /dev/null
+++ b/remoting/resources/styles.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Activity styles for the Android app-->
+<resources>
+ <style name="Theme_ElusiveActionBar">
+ <item name="android:windowActionBarOverlay">true</item>
+ <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar.Solid</item>
+ </style>
+</resources>