Adding keyboard service.
This allows to show the soft keyboard on Android.
Also updated platform_viewport_android to dispatch key events.
R=abarth@chromium.org
BUG=449002
Review URL: https://codereview.chromium.org/856063002
diff --git a/mojo/services/keyboard/public/interfaces/BUILD.gn b/mojo/services/keyboard/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..4685f86
--- /dev/null
+++ b/mojo/services/keyboard/public/interfaces/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2014 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.
+
+import("../../../mojo_sdk_root.gni")
+import("$mojo_sdk_root/mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "keyboard.mojom",
+ ]
+}
diff --git a/mojo/services/keyboard/public/interfaces/keyboard.mojom b/mojo/services/keyboard/public/interfaces/keyboard.mojom
new file mode 100644
index 0000000..d11253e
--- /dev/null
+++ b/mojo/services/keyboard/public/interfaces/keyboard.mojom
@@ -0,0 +1,10 @@
+// Copyright 2014 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.
+
+module mojo;
+
+interface Keyboard {
+ Show();
+ Hide();
+};
diff --git a/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java b/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java
index e8eeb4c..712de95 100644
--- a/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java
+++ b/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java
@@ -6,10 +6,12 @@
import android.app.Activity;
import android.content.Context;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.View;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
@@ -32,6 +34,9 @@
public PlatformViewportAndroid(Context context, long nativeViewport) {
super(context);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+
mNativeMojoViewport = nativeViewport;
assert mNativeMojoViewport != 0;
@@ -68,11 +73,49 @@
}
@Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == View.VISIBLE) {
+ requestFocusFromTouch();
+ requestFocus();
+ }
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
return nativeTouchEvent(mNativeMojoViewport, event.getPointerId(0), event.getAction(),
event.getX(), event.getY(), event.getEventTime());
}
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (privateDispatchKeyEvent(event)) {
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean dispatchKeyEventPreIme(KeyEvent event) {
+ if (privateDispatchKeyEvent(event)) {
+ return true;
+ }
+ return super.dispatchKeyEventPreIme(event);
+ }
+
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ if (privateDispatchKeyEvent(event)) {
+ return true;
+ }
+ return super.dispatchKeyShortcutEvent(event);
+ }
+
+ private boolean privateDispatchKeyEvent(KeyEvent event) {
+ return nativeKeyEvent(mNativeMojoViewport, event.getAction() == KeyEvent.ACTION_DOWN,
+ event.getKeyCode(), event.getUnicodeChar());
+ }
+
private static native void nativeDestroy(long nativePlatformViewportAndroid);
private static native void nativeSurfaceCreated(
@@ -90,4 +133,7 @@
int action,
float x, float y,
long timeMs);
+
+ private static native boolean nativeKeyEvent(
+ long nativePlatformViewportAndroid, boolean pressed, int keyCode, int unicodeCharacter);
}
diff --git a/services/native_viewport/platform_viewport_android.cc b/services/native_viewport/platform_viewport_android.cc
index 8090625..f3db992 100644
--- a/services/native_viewport/platform_viewport_android.cc
+++ b/services/native_viewport/platform_viewport_android.cc
@@ -11,6 +11,7 @@
#include "jni/PlatformViewportAndroid_jni.h"
#include "mojo/converters/geometry/geometry_type_converters.h"
#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_code_conversion_android.h"
#include "ui/gfx/point.h"
namespace native_viewport {
@@ -115,6 +116,24 @@
return true;
}
+bool PlatformViewportAndroid::KeyEvent(JNIEnv* env,
+ jobject obj,
+ bool pressed,
+ jint key_code,
+ jint unicode_character) {
+ ui::KeyEvent event(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
+ ui::KeyboardCodeFromAndroidKeyCode(key_code), 0);
+ event.set_platform_keycode(key_code);
+ delegate_->OnEvent(&event);
+ if (pressed && unicode_character) {
+ ui::KeyEvent char_event(unicode_character,
+ ui::KeyboardCodeFromAndroidKeyCode(key_code), 0);
+ char_event.set_platform_keycode(key_code);
+ delegate_->OnEvent(&char_event);
+ }
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// PlatformViewportAndroid, PlatformViewport implementation:
diff --git a/services/native_viewport/platform_viewport_android.h b/services/native_viewport/platform_viewport_android.h
index 5fdaf1f..88b6908 100644
--- a/services/native_viewport/platform_viewport_android.h
+++ b/services/native_viewport/platform_viewport_android.h
@@ -40,6 +40,11 @@
jfloat density);
bool TouchEvent(JNIEnv* env, jobject obj, jint pointer_id, jint action,
jfloat x, jfloat y, jlong time_ms);
+ bool KeyEvent(JNIEnv* env,
+ jobject obj,
+ bool pressed,
+ jint key_code,
+ jint unicode_character);
private:
// Overridden from PlatformViewport:
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index 2ce1174..d494fc1 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -203,6 +203,8 @@
"android/android_handler_loader.h",
"android/background_application_loader.cc",
"android/background_application_loader.h",
+ "android/keyboard_impl.cc",
+ "android/keyboard_impl.h",
"android/native_viewport_application_loader.cc",
"android/native_viewport_application_loader.h",
"android/ui_application_loader_android.cc",
@@ -213,6 +215,7 @@
":jni_headers",
":run_android_application_function",
"//mojo/application:content_handler",
+ "//mojo/services/keyboard/public/interfaces",
"//services/gles2",
"//services/native_viewport:lib",
]
@@ -232,6 +235,7 @@
sources = [
"android/apk/src/org/chromium/mojo/shell/AndroidHandler.java",
"android/apk/src/org/chromium/mojo/shell/Bootstrap.java",
+ "android/apk/src/org/chromium/mojo/shell/Keyboard.java",
"android/apk/src/org/chromium/mojo/shell/MojoMain.java",
"android/tests/src/org/chromium/mojo/shell/ShellTestBase.java",
]
@@ -275,6 +279,7 @@
java_files = [
"android/apk/src/org/chromium/mojo/shell/AndroidHandler.java",
"android/apk/src/org/chromium/mojo/shell/FileHelper.java",
+ "android/apk/src/org/chromium/mojo/shell/Keyboard.java",
"android/apk/src/org/chromium/mojo/shell/MojoMain.java",
"android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java",
"android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java",
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/Keyboard.java b/shell/android/apk/src/org/chromium/mojo/shell/Keyboard.java
new file mode 100644
index 0000000..e13ddea
--- /dev/null
+++ b/shell/android/apk/src/org/chromium/mojo/shell/Keyboard.java
@@ -0,0 +1,35 @@
+// Copyright 2014 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.mojo.shell;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+
+/**
+ * Interaction with the keyboard.
+ */
+@JNINamespace("mojo::shell")
+public class Keyboard {
+ @CalledByNative
+ private static void showSoftKeyboard(Activity activity) {
+ View v = activity.getCurrentFocus();
+ InputMethodManager imm =
+ (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT);
+ }
+
+ @CalledByNative
+ private static void hideSoftKeyboard(Activity activity) {
+ View v = activity.getCurrentFocus();
+ InputMethodManager imm =
+ (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), 0);
+ }
+}
diff --git a/shell/android/keyboard_impl.cc b/shell/android/keyboard_impl.cc
new file mode 100644
index 0000000..4282348
--- /dev/null
+++ b/shell/android/keyboard_impl.cc
@@ -0,0 +1,36 @@
+// Copyright 2015 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 "shell/android/keyboard_impl.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "jni/Keyboard_jni.h"
+
+namespace mojo {
+namespace shell {
+
+KeyboardImpl::KeyboardImpl(InterfaceRequest<Keyboard> request)
+ : binding_(this, request.Pass()) {
+}
+
+KeyboardImpl::~KeyboardImpl() {
+}
+
+void KeyboardImpl::Show() {
+ Java_Keyboard_showSoftKeyboard(base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext());
+}
+
+void KeyboardImpl::Hide() {
+ Java_Keyboard_hideSoftKeyboard(base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext());
+}
+
+bool RegisterKeyboardJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace shell
+} // namespace mojo
diff --git a/shell/android/keyboard_impl.h b/shell/android/keyboard_impl.h
new file mode 100644
index 0000000..e40b7dd
--- /dev/null
+++ b/shell/android/keyboard_impl.h
@@ -0,0 +1,35 @@
+// Copyright 2015 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 SHELL_ANDROID_KEYBOARD_IMPL_H_
+#define SHELL_ANDROID_KEYBOARD_IMPL_H_
+
+#include <jni.h>
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/services/keyboard/public/interfaces/keyboard.mojom.h"
+
+namespace mojo {
+namespace shell {
+
+class KeyboardImpl : public Keyboard {
+ public:
+ KeyboardImpl(InterfaceRequest<Keyboard> request);
+ ~KeyboardImpl();
+
+ // Keyboard implementation
+ void Show() override;
+ void Hide() override;
+
+ private:
+ StrongBinding<Keyboard> binding_;
+};
+
+bool RegisterKeyboardJni(JNIEnv* env);
+
+} // namespace shell
+} // namespace mojo
+
+#endif // SHELL_ANDROID_KEYBOARD_IMPL_H_
diff --git a/shell/android/library_loader.cc b/shell/android/library_loader.cc
index c112db6..42e02df 100644
--- a/shell/android/library_loader.cc
+++ b/shell/android/library_loader.cc
@@ -9,12 +9,14 @@
#include "base/logging.h"
#include "services/native_viewport/platform_viewport_android.h"
#include "shell/android/android_handler.h"
+#include "shell/android/keyboard_impl.h"
#include "shell/android/mojo_main.h"
namespace {
base::android::RegistrationMethod kMojoRegisteredMethods[] = {
{"AndroidHandler", mojo::RegisterAndroidHandlerJni},
+ {"Keyboard", mojo::shell::RegisterKeyboardJni},
{"MojoMain", mojo::shell::RegisterMojoMain},
{"PlatformViewportAndroid",
native_viewport::PlatformViewportAndroid::Register},
diff --git a/shell/android/mojo_main.cc b/shell/android/mojo_main.cc
index 502a340..9c8178b 100644
--- a/shell/android/mojo_main.cc
+++ b/shell/android/mojo_main.cc
@@ -83,6 +83,10 @@
make_scoped_ptr(new AndroidHandlerLoader()), "android_handler",
base::MessageLoop::TYPE_DEFAULT)),
GURL("mojo:android_handler"));
+
+ // By default, the keyboard is handled by the native_viewport_service.
+ context->mojo_url_resolver()->AddCustomMapping(
+ GURL("mojo:keyboard"), GURL("mojo:native_viewport_service"));
}
void QuitShellThread() {
diff --git a/shell/android/native_viewport_application_loader.cc b/shell/android/native_viewport_application_loader.cc
index e84fa90..9f96417 100644
--- a/shell/android/native_viewport_application_loader.cc
+++ b/shell/android/native_viewport_application_loader.cc
@@ -6,6 +6,7 @@
#include "mojo/public/cpp/application/application_impl.h"
#include "services/native_viewport/native_viewport_impl.h"
+#include "shell/android/keyboard_impl.h"
namespace mojo {
namespace shell {
@@ -33,6 +34,7 @@
mojo::ApplicationConnection* connection) {
connection->AddService<NativeViewport>(this);
connection->AddService<Gpu>(this);
+ connection->AddService<Keyboard>(this);
return true;
}
@@ -45,7 +47,12 @@
void NativeViewportApplicationLoader::Create(
ApplicationConnection* connection,
- InterfaceRequest<Gpu> request) {
+ InterfaceRequest<Keyboard> request) {
+ new KeyboardImpl(request.Pass());
+}
+
+void NativeViewportApplicationLoader::Create(ApplicationConnection* connection,
+ InterfaceRequest<Gpu> request) {
if (!gpu_state_)
gpu_state_ = new gles2::GpuImpl::State;
new gles2::GpuImpl(request.Pass(), gpu_state_);
diff --git a/shell/android/native_viewport_application_loader.h b/shell/android/native_viewport_application_loader.h
index f5d53ea..060d3aa 100644
--- a/shell/android/native_viewport_application_loader.h
+++ b/shell/android/native_viewport_application_loader.h
@@ -8,6 +8,7 @@
#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/interface_factory.h"
#include "mojo/services/gpu/public/interfaces/gpu.mojom.h"
+#include "mojo/services/keyboard/public/interfaces/keyboard.mojom.h"
#include "mojo/services/native_viewport/public/interfaces/native_viewport.mojom.h"
#include "services/gles2/gpu_impl.h"
#include "shell/application_manager/application_loader.h"
@@ -20,6 +21,7 @@
class NativeViewportApplicationLoader : public ApplicationLoader,
public ApplicationDelegate,
+ public InterfaceFactory<Keyboard>,
public InterfaceFactory<NativeViewport>,
public InterfaceFactory<Gpu> {
public:
@@ -48,6 +50,10 @@
void Create(ApplicationConnection* connection,
InterfaceRequest<Gpu> request) override;
+ // InterfaceFactory<Keyboard> implementation.
+ void Create(ApplicationConnection* connection,
+ InterfaceRequest<Keyboard> request) override;
+
scoped_refptr<gles2::GpuImpl::State> gpu_state_;
scoped_ptr<ApplicationImpl> app_;
diff --git a/sky/engine/core/BUILD.gn b/sky/engine/core/BUILD.gn
index afb5dfe..54a92a6 100644
--- a/sky/engine/core/BUILD.gn
+++ b/sky/engine/core/BUILD.gn
@@ -23,6 +23,7 @@
"//mojo/public/cpp/system",
"//mojo/public/cpp/utility",
"//mojo/public/interfaces/application",
+ "//mojo/services/keyboard/public/interfaces",
"//mojo/services/navigation/public/interfaces",
"//mojo/services/view_manager/public/cpp",
"//skia",
diff --git a/sky/framework/sky-input.sky b/sky/framework/sky-input.sky
index 9ad21fb..9ebbaed 100644
--- a/sky/framework/sky-input.sky
+++ b/sky/framework/sky-input.sky
@@ -3,7 +3,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-->
+<import src="/sky/framework/shell.sky" as="shell" />
<import src="/sky/framework/sky-element/sky-element.sky" as="SkyElement" />
+<import src="/mojo/services/keyboard/public/interfaces/keyboard.mojom.sky" as="keyboard" />
<sky-element name="sky-input" attributes="value:string">
<template>
@@ -22,9 +24,13 @@
overflow: hidden;
}
</style>
- <div id="control" contenteditable on-keydown="handleKeyDown">{{ value }}</div>
+ <div id="control" contenteditable
+ on-focus="handleFocus"
+ on-blur="handleBlur"
+ on-keydown="handleKeyDown">{{ value }}</div>
</template>
<script>
+var keyboard = shell.connectToService("mojo:keyboard", keyboard.Keyboard);
module.exports = class extends SkyElement {
shadowRootReady() {
var control = this.shadowRoot.getElementById('control');
@@ -54,6 +60,12 @@
if (event.keyCode == 0xD)
event.preventDefault();
}
+ handleFocus(event) {
+ keyboard.show();
+ }
+ handleBlur(event) {
+ keyboard.hide();
+ }
}.register();
</script>
</sky-element>
diff --git a/sky/viewer/document_view.cc b/sky/viewer/document_view.cc
index cf48567..8125379 100644
--- a/sky/viewer/document_view.cc
+++ b/sky/viewer/document_view.cc
@@ -126,6 +126,8 @@
// TODO(abarth): We should ask the view whether it is focused instead of
// assuming that we're focused.
web_view_->setFocus(true);
+ // Needed on android, as the window does not get the focus otherwise.
+ root_->SetFocus();
root_->AddObserver(this);
}