1// Copyright (c) 2012 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
5#include "chrome/browser/chromeos/extensions/input_method_api.h"
6
7#include "base/lazy_instance.h"
8#include "base/values.h"
9#include "chrome/browser/chromeos/extensions/input_method_event_router.h"
10#include "chrome/browser/chromeos/input_method/input_method_util.h"
11#include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
12#include "chromeos/ime/extension_ime_util.h"
13#include "chromeos/ime/input_method_descriptor.h"
14#include "chromeos/ime/input_method_manager.h"
15#include "extensions/browser/extension_function_registry.h"
16#include "extensions/browser/extension_system.h"
17#include "extensions/common/value_builder.h"
18
19namespace {
20
21// Prefix, which is used by XKB.
22const char kXkbPrefix[] = "xkb:";
23
24}  // namespace
25
26namespace extensions {
27
28ExtensionFunction::ResponseAction GetCurrentInputMethodFunction::Run() {
29#if !defined(OS_CHROMEOS)
30  EXTENSION_FUNCTION_VALIDATE(false);
31#else
32  chromeos::input_method::InputMethodManager* manager =
33      chromeos::input_method::InputMethodManager::Get();
34  return RespondNow(OneArgument(
35      new base::StringValue(manager->GetCurrentInputMethod().id())));
36#endif
37}
38
39ExtensionFunction::ResponseAction SetCurrentInputMethodFunction::Run() {
40#if !defined(OS_CHROMEOS)
41  EXTENSION_FUNCTION_VALIDATE(false);
42#else
43  std::string new_input_method;
44  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &new_input_method));
45  chromeos::input_method::InputMethodManager* manager =
46      chromeos::input_method::InputMethodManager::Get();
47  const std::vector<std::string>& input_methods =
48      manager->GetActiveInputMethodIds();
49  for (size_t i = 0; i < input_methods.size(); ++i) {
50    const std::string& input_method = input_methods[i];
51    if (input_method == new_input_method) {
52      manager->ChangeInputMethod(new_input_method);
53      return RespondNow(NoArguments());
54    }
55  }
56  return RespondNow(Error("Invalid input method id."));
57#endif
58}
59
60ExtensionFunction::ResponseAction GetInputMethodsFunction::Run() {
61#if !defined(OS_CHROMEOS)
62  EXTENSION_FUNCTION_VALIDATE(false);
63#else
64  base::ListValue* output = new base::ListValue();
65  chromeos::input_method::InputMethodManager* manager =
66      chromeos::input_method::InputMethodManager::Get();
67  chromeos::input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
68  scoped_ptr<chromeos::input_method::InputMethodDescriptors> input_methods =
69      manager->GetActiveInputMethods();
70  for (size_t i = 0; i < input_methods->size(); ++i) {
71    const chromeos::input_method::InputMethodDescriptor& input_method =
72        (*input_methods)[i];
73    base::DictionaryValue* val = new base::DictionaryValue();
74    val->SetString("id", input_method.id());
75    val->SetString("name", util->GetInputMethodLongName(input_method));
76    val->SetString("indicator", util->GetInputMethodShortName(input_method));
77    output->Append(val);
78  }
79  return RespondNow(OneArgument(output));
80#endif
81}
82
83// static
84const char InputMethodAPI::kOnInputMethodChanged[] =
85    "inputMethodPrivate.onChanged";
86
87InputMethodAPI::InputMethodAPI(content::BrowserContext* context)
88    : context_(context) {
89  EventRouter::Get(context_)->RegisterObserver(this, kOnInputMethodChanged);
90  ExtensionFunctionRegistry* registry =
91      ExtensionFunctionRegistry::GetInstance();
92  registry->RegisterFunction<GetCurrentInputMethodFunction>();
93  registry->RegisterFunction<SetCurrentInputMethodFunction>();
94  registry->RegisterFunction<GetInputMethodsFunction>();
95}
96
97InputMethodAPI::~InputMethodAPI() {
98}
99
100// static
101std::string InputMethodAPI::GetInputMethodForXkb(const std::string& xkb_id) {
102  std::string xkb_prefix =
103      chromeos::extension_ime_util::GetInputMethodIDByEngineID(kXkbPrefix);
104  size_t prefix_length = xkb_prefix.length();
105  DCHECK(xkb_id.substr(0, prefix_length) == xkb_prefix);
106  return xkb_id.substr(prefix_length);
107}
108
109void InputMethodAPI::Shutdown() {
110  // UnregisterObserver may have already been called in OnListenerAdded,
111  // but it is safe to call it more than once.
112  EventRouter::Get(context_)->UnregisterObserver(this);
113}
114
115void InputMethodAPI::OnListenerAdded(
116    const extensions::EventListenerInfo& details) {
117  DCHECK(!input_method_event_router_.get());
118  input_method_event_router_.reset(
119      new chromeos::ExtensionInputMethodEventRouter(context_));
120  EventRouter::Get(context_)->UnregisterObserver(this);
121}
122
123static base::LazyInstance<BrowserContextKeyedAPIFactory<InputMethodAPI> >
124    g_factory = LAZY_INSTANCE_INITIALIZER;
125
126// static
127BrowserContextKeyedAPIFactory<InputMethodAPI>*
128InputMethodAPI::GetFactoryInstance() {
129  return g_factory.Pointer();
130}
131
132}  // namespace extensions
133