Implement Linux IME support

Create a Linux implementation of mojo:keyboard
Add a method to receive key events from native viewport
Add an interface to keyboard.mojom to allow binding the Linux
implementation as the native viewport's key event listener

R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/1453823005 .
diff --git a/mojo/dart/packages/mojo_services/lib/keyboard/keyboard.mojom.dart b/mojo/dart/packages/mojo_services/lib/keyboard/keyboard.mojom.dart
index 7e7f67d..2aa0ef5 100644
--- a/mojo/dart/packages/mojo_services/lib/keyboard/keyboard.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/keyboard/keyboard.mojom.dart
@@ -8,6 +8,7 @@
 
 import 'package:mojo/bindings.dart' as bindings;
 import 'package:mojo/core.dart' as core;
+import 'package:mojo_services/mojo/native_viewport.mojom.dart' as native_viewport_mojom;
 class SubmitAction extends bindings.MojoEnum {
   static const DONE = const SubmitAction._(0);
 
@@ -1218,6 +1219,80 @@
   }
 }
 
+
+class KeyboardServiceFactoryCreateKeyboardServiceParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  Object keyEventDispatcher = null;
+  Object serviceRequest = null;
+
+  KeyboardServiceFactoryCreateKeyboardServiceParams() : super(kVersions.last.size);
+
+  static KeyboardServiceFactoryCreateKeyboardServiceParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static KeyboardServiceFactoryCreateKeyboardServiceParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    KeyboardServiceFactoryCreateKeyboardServiceParams result = new KeyboardServiceFactoryCreateKeyboardServiceParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.keyEventDispatcher = decoder0.decodeInterfaceRequest(8, false, native_viewport_mojom.NativeViewportEventDispatcherStub.newFromEndpoint);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.serviceRequest = decoder0.decodeInterfaceRequest(12, false, KeyboardServiceStub.newFromEndpoint);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    
+    encoder0.encodeInterfaceRequest(keyEventDispatcher, 8, false);
+    
+    encoder0.encodeInterfaceRequest(serviceRequest, 12, false);
+  }
+
+  String toString() {
+    return "KeyboardServiceFactoryCreateKeyboardServiceParams("
+           "keyEventDispatcher: $keyEventDispatcher" ", "
+           "serviceRequest: $serviceRequest" ")";
+  }
+
+  Map toJson() {
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
+  }
+}
+
 const int kKeyboardClient_commitCompletion_name = 0;
 const int kKeyboardClient_commitCorrection_name = 1;
 const int kKeyboardClient_commitText_name = 2;
@@ -1760,4 +1835,180 @@
   int get version => 0;
 }
 
+const int kKeyboardServiceFactory_createKeyboardService_name = 0;
+
+const String KeyboardServiceFactoryName =
+      'keyboard::KeyboardServiceFactory';
+
+abstract class KeyboardServiceFactory {
+  void createKeyboardService(Object keyEventDispatcher, Object serviceRequest);
+
+}
+
+
+class KeyboardServiceFactoryProxyImpl extends bindings.Proxy {
+  KeyboardServiceFactoryProxyImpl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
+
+  KeyboardServiceFactoryProxyImpl.fromHandle(core.MojoHandle handle) :
+      super.fromHandle(handle);
+
+  KeyboardServiceFactoryProxyImpl.unbound() : super.unbound();
+
+  static KeyboardServiceFactoryProxyImpl newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For KeyboardServiceFactoryProxyImpl"));
+    return new KeyboardServiceFactoryProxyImpl.fromEndpoint(endpoint);
+  }
+
+  String get name => KeyboardServiceFactoryName;
+
+  void handleResponse(bindings.ServiceMessage message) {
+    switch (message.header.type) {
+      default:
+        proxyError("Unexpected message type: ${message.header.type}");
+        close(immediate: true);
+        break;
+    }
+  }
+
+  String toString() {
+    var superString = super.toString();
+    return "KeyboardServiceFactoryProxyImpl($superString)";
+  }
+}
+
+
+class _KeyboardServiceFactoryProxyCalls implements KeyboardServiceFactory {
+  KeyboardServiceFactoryProxyImpl _proxyImpl;
+
+  _KeyboardServiceFactoryProxyCalls(this._proxyImpl);
+    void createKeyboardService(Object keyEventDispatcher, Object serviceRequest) {
+      if (!_proxyImpl.isBound) {
+        _proxyImpl.proxyError("The Proxy is closed.");
+        return;
+      }
+      var params = new KeyboardServiceFactoryCreateKeyboardServiceParams();
+      params.keyEventDispatcher = keyEventDispatcher;
+      params.serviceRequest = serviceRequest;
+      _proxyImpl.sendMessage(params, kKeyboardServiceFactory_createKeyboardService_name);
+    }
+  
+}
+
+
+class KeyboardServiceFactoryProxy implements bindings.ProxyBase {
+  final bindings.Proxy impl;
+  KeyboardServiceFactory ptr;
+  final String name = KeyboardServiceFactoryName;
+
+  KeyboardServiceFactoryProxy(KeyboardServiceFactoryProxyImpl proxyImpl) :
+      impl = proxyImpl,
+      ptr = new _KeyboardServiceFactoryProxyCalls(proxyImpl);
+
+  KeyboardServiceFactoryProxy.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) :
+      impl = new KeyboardServiceFactoryProxyImpl.fromEndpoint(endpoint) {
+    ptr = new _KeyboardServiceFactoryProxyCalls(impl);
+  }
+
+  KeyboardServiceFactoryProxy.fromHandle(core.MojoHandle handle) :
+      impl = new KeyboardServiceFactoryProxyImpl.fromHandle(handle) {
+    ptr = new _KeyboardServiceFactoryProxyCalls(impl);
+  }
+
+  KeyboardServiceFactoryProxy.unbound() :
+      impl = new KeyboardServiceFactoryProxyImpl.unbound() {
+    ptr = new _KeyboardServiceFactoryProxyCalls(impl);
+  }
+
+  factory KeyboardServiceFactoryProxy.connectToService(
+      bindings.ServiceConnector s, String url) {
+    KeyboardServiceFactoryProxy p = new KeyboardServiceFactoryProxy.unbound();
+    s.connectToService(url, p);
+    return p;
+  }
+
+  static KeyboardServiceFactoryProxy newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For KeyboardServiceFactoryProxy"));
+    return new KeyboardServiceFactoryProxy.fromEndpoint(endpoint);
+  }
+
+  Future close({bool immediate: false}) => impl.close(immediate: immediate);
+
+  Future responseOrError(Future f) => impl.responseOrError(f);
+
+  Future get errorFuture => impl.errorFuture;
+
+  int get version => impl.version;
+
+  Future<int> queryVersion() => impl.queryVersion();
+
+  void requireVersion(int requiredVersion) {
+    impl.requireVersion(requiredVersion);
+  }
+
+  String toString() {
+    return "KeyboardServiceFactoryProxy($impl)";
+  }
+}
+
+
+class KeyboardServiceFactoryStub extends bindings.Stub {
+  KeyboardServiceFactory _impl = null;
+
+  KeyboardServiceFactoryStub.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [this._impl])
+      : super.fromEndpoint(endpoint);
+
+  KeyboardServiceFactoryStub.fromHandle(core.MojoHandle handle, [this._impl])
+      : super.fromHandle(handle);
+
+  KeyboardServiceFactoryStub.unbound() : super.unbound();
+
+  static KeyboardServiceFactoryStub newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For KeyboardServiceFactoryStub"));
+    return new KeyboardServiceFactoryStub.fromEndpoint(endpoint);
+  }
+
+  static const String name = KeyboardServiceFactoryName;
+
+
+
+  dynamic handleMessage(bindings.ServiceMessage message) {
+    if (bindings.ControlMessageHandler.isControlMessage(message)) {
+      return bindings.ControlMessageHandler.handleMessage(this,
+                                                          0,
+                                                          message);
+    }
+    assert(_impl != null);
+    switch (message.header.type) {
+      case kKeyboardServiceFactory_createKeyboardService_name:
+        var params = KeyboardServiceFactoryCreateKeyboardServiceParams.deserialize(
+            message.payload);
+        _impl.createKeyboardService(params.keyEventDispatcher, params.serviceRequest);
+        break;
+      default:
+        throw new bindings.MojoCodecError("Unexpected message name");
+        break;
+    }
+    return null;
+  }
+
+  KeyboardServiceFactory get impl => _impl;
+  set impl(KeyboardServiceFactory d) {
+    assert(_impl == null);
+    _impl = d;
+  }
+
+  String toString() {
+    var superString = super.toString();
+    return "KeyboardServiceFactoryStub($superString)";
+  }
+
+  int get version => 0;
+}
+
 
diff --git a/mojo/services/keyboard/interfaces/BUILD.gn b/mojo/services/keyboard/interfaces/BUILD.gn
index 6aa9389..b3ca11d 100644
--- a/mojo/services/keyboard/interfaces/BUILD.gn
+++ b/mojo/services/keyboard/interfaces/BUILD.gn
@@ -9,4 +9,10 @@
   sources = [
     "keyboard.mojom",
   ]
+
+  import_dirs = [ get_path_info("../../", "abspath") ]
+
+  deps = [
+    "../../native_viewport/interfaces",
+  ]
 }
diff --git a/mojo/services/keyboard/interfaces/keyboard.mojom b/mojo/services/keyboard/interfaces/keyboard.mojom
index ee43bb0..3c1c8f6 100644
--- a/mojo/services/keyboard/interfaces/keyboard.mojom
+++ b/mojo/services/keyboard/interfaces/keyboard.mojom
@@ -5,6 +5,8 @@
 [DartPackage="mojo_services"]
 module keyboard;
 
+import "native_viewport/interfaces/native_viewport.mojom";
+
 struct CompletionData {
   int64 id;
   int32 position;
@@ -50,3 +52,10 @@
   SetText(string text);
   SetSelection(int32 start, int32 end);
 };
+
+[ServiceName="keyboard::KeyboardServiceFactory"]
+interface KeyboardServiceFactory {
+  CreateKeyboardService(
+      mojo.NativeViewportEventDispatcher& keyEventDispatcher,
+      KeyboardService& serviceRequest);
+};
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 284dda4..9b5ff8f 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -42,6 +42,10 @@
     }
   }
 
+  if (is_linux) {
+    deps += [ "//services/keyboard" ]
+  }
+
   if (is_linux && !is_fnl) {
     deps += [ "//services/python" ]
   }
diff --git a/services/keyboard/BUILD.gn b/services/keyboard/BUILD.gn
index a6b73fb..2b01eb2 100644
--- a/services/keyboard/BUILD.gn
+++ b/services/keyboard/BUILD.gn
@@ -2,19 +2,43 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/android/config.gni")
-import("//build/config/android/rules.gni")
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
 
-android_library("keyboard") {
-  java_files = [
-    "src/org/chromium/mojo/keyboard/InputConnectionAdaptor.java",
-    "src/org/chromium/mojo/keyboard/KeyboardServiceImpl.java",
-    "src/org/chromium/mojo/keyboard/KeyboardServiceState.java",
-  ]
+  android_library("keyboard") {
+    java_files = [
+      "src/org/chromium/mojo/keyboard/InputConnectionAdaptor.java",
+      "src/org/chromium/mojo/keyboard/KeyboardServiceImpl.java",
+      "src/org/chromium/mojo/keyboard/KeyboardServiceState.java",
+    ]
 
-  deps = [
-    "//mojo/public/java:bindings",
-    "//mojo/public/java:system",
-    "//mojo/services/keyboard/interfaces:interfaces_java",
-  ]
+    deps = [
+      "//mojo/public/java:bindings",
+      "//mojo/public/java:system",
+      "//mojo/services/keyboard/interfaces:interfaces_java",
+    ]
+  }
+}
+
+if (is_linux) {
+  import("//mojo/public/mojo_application.gni")
+
+  mojo_native_application("keyboard") {
+    sources = [
+      "linux/keyboard_service_impl.cc",
+      "linux/main.cc",
+    ]
+
+    deps = [
+      "//base",
+      "//mojo/application",
+      "//mojo/public/cpp/application",
+      "//mojo/public/cpp/bindings:callback",
+      "//mojo/public/cpp/system",
+      "//mojo/services/keyboard/interfaces",
+      "//mojo/services/native_viewport/interfaces",
+      "//mojo/services/native_viewport/cpp:args",
+    ]
+  }
 }
diff --git a/services/keyboard/linux/keyboard_service_impl.cc b/services/keyboard/linux/keyboard_service_impl.cc
new file mode 100644
index 0000000..f8b6afc
--- /dev/null
+++ b/services/keyboard/linux/keyboard_service_impl.cc
@@ -0,0 +1,86 @@
+// 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 "services/keyboard/linux/keyboard_service_impl.h"
+
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/services/input_events/interfaces/input_key_codes.mojom.h"
+
+namespace keyboard {
+
+LinuxKeyboardServiceImpl::LinuxKeyboardServiceImpl(
+    mojo::InterfaceRequest<keyboard::KeyboardService> request,
+    mojo::InterfaceRequest<NativeViewportEventDispatcher> dispatcher)
+    : event_dispatcher_binding_(this, dispatcher.Pass()),
+      binding_(this, request.Pass()) {
+}
+
+LinuxKeyboardServiceImpl::~LinuxKeyboardServiceImpl() {
+}
+
+void LinuxKeyboardServiceImpl::Show(
+    keyboard::KeyboardClientPtr client,
+    keyboard::KeyboardType type) {
+  client_ = client.Pass();
+}
+
+void LinuxKeyboardServiceImpl::ShowByRequest() {
+}
+
+void LinuxKeyboardServiceImpl::Hide() {
+  client_ = nullptr;
+}
+
+void LinuxKeyboardServiceImpl::SetText(const mojo::String& text) {
+  text_ = text;
+}
+
+void LinuxKeyboardServiceImpl::SetSelection(int32_t start, int32_t end) {
+  // Not applicable for physical keyboards
+}
+
+// |mojo::NativeViewportEventDispatcher| implementation:
+void LinuxKeyboardServiceImpl::OnEvent(
+    mojo::EventPtr event,
+    const OnEventCallback& callback) {
+  if (event->action == mojo::EventType::KEY_PRESSED &&
+      event->key_data->is_char) {
+    if (client_) {
+      switch(event->key_data->windows_key_code) {
+        case mojo::KeyboardCode::BACK: // backspace
+          client_->DeleteSurroundingText(1, 0);
+          break;
+        case mojo::KeyboardCode::DELETE:
+          client_->DeleteSurroundingText(0, 1);
+          break;
+        case mojo::KeyboardCode::HOME:
+          client_->SetSelection(0, 0);
+          break;
+        case mojo::KeyboardCode::END:
+          client_->SetSelection(text_.size()-1, text_.size()-1);
+          break;
+        case mojo::KeyboardCode::TAB:
+          // TODO: Advance focus, in reverse if shifted
+          break;
+        case mojo::KeyboardCode::RETURN:
+          client_->Submit(keyboard::SubmitAction::DONE);
+          break;
+        default:
+          base::string16 character;
+          character.push_back(event->key_data->character);
+          std::string s = base::UTF16ToUTF8(character);
+          text_ += s;
+          client_->CommitText(mojo::String(s), 1);
+          break;
+      }
+    }
+  }
+  callback.Run();
+}
+
+}  // namespace keyboard
diff --git a/services/keyboard/linux/keyboard_service_impl.h b/services/keyboard/linux/keyboard_service_impl.h
new file mode 100644
index 0000000..fd97ba9
--- /dev/null
+++ b/services/keyboard/linux/keyboard_service_impl.h
@@ -0,0 +1,49 @@
+// 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 SERVICES_KEYBOARD_LINUX_KEYBOARD_SERVICE_IMPL_H_
+#define SERVICES_KEYBOARD_LINUX_KEYBOARD_SERVICE_IMPL_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/application/interface_factory.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+#include "mojo/services/keyboard/interfaces/keyboard.mojom.h"
+#include "mojo/services/native_viewport/interfaces/native_viewport.mojom.h"
+
+namespace keyboard {
+
+class LinuxKeyboardServiceImpl : public keyboard::KeyboardService,
+                                 public mojo::NativeViewportEventDispatcher {
+ public:
+  LinuxKeyboardServiceImpl(
+      mojo::InterfaceRequest<keyboard::KeyboardService> request,
+      mojo::InterfaceRequest<NativeViewportEventDispatcher> dispatcher);
+  ~LinuxKeyboardServiceImpl() override;
+
+  // |KeyboardService| overrides:
+  void Show(keyboard::KeyboardClientPtr client,
+            keyboard::KeyboardType type) override;
+  void ShowByRequest() override;
+  void Hide() override;
+  void SetText(const mojo::String& text) override;
+  void SetSelection(int32_t start, int32_t end) override;
+
+  // |NativeViewportEventDispatcher| overrides:
+  void OnEvent(mojo::EventPtr event,
+               const OnEventCallback& callback) override;
+
+ private:
+  mojo::Binding<mojo::NativeViewportEventDispatcher> event_dispatcher_binding_;
+  mojo::StrongBinding<keyboard::KeyboardService> binding_;
+
+  keyboard::KeyboardClientPtr client_;
+  std::string text_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinuxKeyboardServiceImpl);
+};
+
+}  // namespace keyboard
+
+#endif // defined(SERVICES_KEYBOARD_LINUX_KEYBOARD_SERVICE_IMPL_H_)
diff --git a/services/keyboard/linux/main.cc b/services/keyboard/linux/main.cc
new file mode 100644
index 0000000..0b263fd
--- /dev/null
+++ b/services/keyboard/linux/main.cc
@@ -0,0 +1,72 @@
+// 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 "base/macros.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "mojo/application/application_runner_chromium.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/cpp/application/interface_factory.h"
+#include "mojo/services/native_viewport/interfaces/native_viewport.mojom.h"
+#include "services/keyboard/linux/keyboard_service_impl.h"
+
+namespace keyboard {
+
+class KeyboardServiceFactoryImpl : public keyboard::KeyboardServiceFactory {
+public:
+  explicit KeyboardServiceFactoryImpl(
+      mojo::InterfaceRequest<KeyboardServiceFactory> request)
+    : binding_(this, request.Pass()) {}
+
+  // |InterfaceFactory<KeyboardService>| implementation:
+  void CreateKeyboardService(
+      mojo::InterfaceRequest<mojo::NativeViewportEventDispatcher> dispatcher,
+      mojo::InterfaceRequest<KeyboardService> request) override {
+    new LinuxKeyboardServiceImpl(request.Pass(), dispatcher.Pass());
+  }
+
+private:
+  mojo::StrongBinding<keyboard::KeyboardServiceFactory> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyboardServiceFactoryImpl);
+};
+
+class KeyboardServiceApp
+  : public mojo::ApplicationDelegate,
+    public mojo::InterfaceFactory<KeyboardServiceFactory> {
+ public:
+  KeyboardServiceApp() {}
+  ~KeyboardServiceApp() override {}
+
+ private:
+
+  // |ApplicationDelegate| override:
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
+    connection->AddService<KeyboardServiceFactory>(this);
+    return true;
+  }
+
+  // |InterfaceFactory<KeyboardService>| implementation:
+  void Create(
+      mojo::ApplicationConnection* connection,
+      mojo::InterfaceRequest<KeyboardServiceFactory> request) override {
+    new KeyboardServiceFactoryImpl(request.Pass());
+  }
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(KeyboardServiceApp);
+};
+
+}  // namespace keyboard
+
+MojoResult MojoMain(MojoHandle application_request) {
+  mojo::ApplicationRunnerChromium runner(
+      new keyboard::KeyboardServiceApp());
+  return runner.Run(application_request);
+}
diff --git a/services/keyboard_native/main.cc b/services/keyboard_native/main.cc
index 1ad2537..b3d9d5a 100644
--- a/services/keyboard_native/main.cc
+++ b/services/keyboard_native/main.cc
@@ -17,16 +17,17 @@
 
 namespace keyboard {
 
-class KeyboardServiceFactory : public mojo::InterfaceFactory<KeyboardService> {
+class NativeKeyboardServiceFactory
+  : public mojo::InterfaceFactory<KeyboardService> {
  public:
-  explicit KeyboardServiceFactory(
+  explicit NativeKeyboardServiceFactory(
       mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request) {
     if (service_provider_request.is_pending()) {
       service_provider_impl_.Bind(service_provider_request.Pass());
       service_provider_impl_.AddService<KeyboardService>(this);
     }
   }
-  ~KeyboardServiceFactory() override {}
+  ~NativeKeyboardServiceFactory() override {}
 
   void OnViewCreated(mojo::View* view, mojo::Shell* shell) {
     view_observer_delegate_.OnViewCreated(view, shell);
@@ -68,8 +69,8 @@
   void OnEmbed(mojo::View* root,
                mojo::InterfaceRequest<mojo::ServiceProvider> services,
                mojo::ServiceProviderPtr exposed_services) override {
-    KeyboardServiceFactory* keyboard_service_factory =
-        new KeyboardServiceFactory(services.Pass());
+    NativeKeyboardServiceFactory* keyboard_service_factory =
+        new NativeKeyboardServiceFactory(services.Pass());
     keyboard_service_factory->OnViewCreated(root, shell_);
   }