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.
5 #include "chrome/browser/chromeos/extensions/input_method_api.h"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h"
12 #include "base/values.h"
13 #include "chrome/browser/chromeos/extensions/dictionary_event_router.h"
14 #include "chrome/browser/chromeos/extensions/input_method_event_router.h"
15 #include "chrome/browser/chromeos/input_method/input_method_util.h"
16 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
17 #include "chrome/browser/spellchecker/spellcheck_factory.h"
18 #include "chrome/browser/spellchecker/spellcheck_service.h"
19 #include "chrome/browser/sync/profile_sync_service.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.h"
21 #include "chromeos/chromeos_switches.h"
22 #include "extensions/browser/extension_function_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "ui/base/ime/chromeos/extension_ime_util.h"
25 #include "ui/base/ime/chromeos/input_method_descriptor.h"
26 #include "ui/base/ime/chromeos/input_method_manager.h"
27 #include "ui/keyboard/keyboard_util.h"
31 // Prefix, which is used by XKB.
32 const char kXkbPrefix
[] = "xkb:";
36 namespace extensions
{
38 ExtensionFunction::ResponseAction
GetInputMethodConfigFunction::Run() {
39 #if !defined(OS_CHROMEOS)
40 EXTENSION_FUNCTION_VALIDATE(false);
42 base::DictionaryValue
* output
= new base::DictionaryValue();
44 "isPhysicalKeyboardAutocorrectEnabled",
45 !base::CommandLine::ForCurrentProcess()->HasSwitch(
46 chromeos::switches::kDisablePhysicalKeyboardAutocorrect
));
47 // TODO(rsadam): Delete these two flags once callers have been updated.
48 output
->SetBoolean("isVoiceInputEnabled", keyboard::IsVoiceInputEnabled());
49 output
->SetBoolean("isNewMDInputViewEnabled",
50 keyboard::IsMaterialDesignEnabled());
51 return RespondNow(OneArgument(output
));
55 ExtensionFunction::ResponseAction
GetCurrentInputMethodFunction::Run() {
56 #if !defined(OS_CHROMEOS)
57 EXTENSION_FUNCTION_VALIDATE(false);
59 chromeos::input_method::InputMethodManager
* manager
=
60 chromeos::input_method::InputMethodManager::Get();
61 return RespondNow(OneArgument(new base::StringValue(
62 manager
->GetActiveIMEState()->GetCurrentInputMethod().id())));
66 ExtensionFunction::ResponseAction
SetCurrentInputMethodFunction::Run() {
67 #if !defined(OS_CHROMEOS)
68 EXTENSION_FUNCTION_VALIDATE(false);
70 std::string new_input_method
;
71 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &new_input_method
));
72 scoped_refptr
<chromeos::input_method::InputMethodManager::State
> ime_state
=
73 chromeos::input_method::InputMethodManager::Get()->GetActiveIMEState();
74 const std::vector
<std::string
>& input_methods
=
75 ime_state
->GetActiveInputMethodIds();
76 for (size_t i
= 0; i
< input_methods
.size(); ++i
) {
77 const std::string
& input_method
= input_methods
[i
];
78 if (input_method
== new_input_method
) {
79 ime_state
->ChangeInputMethod(new_input_method
, false /* show_message */);
80 return RespondNow(NoArguments());
83 return RespondNow(Error("Invalid input method id."));
87 ExtensionFunction::ResponseAction
GetInputMethodsFunction::Run() {
88 #if !defined(OS_CHROMEOS)
89 EXTENSION_FUNCTION_VALIDATE(false);
91 base::ListValue
* output
= new base::ListValue();
92 chromeos::input_method::InputMethodManager
* manager
=
93 chromeos::input_method::InputMethodManager::Get();
94 chromeos::input_method::InputMethodUtil
* util
= manager
->GetInputMethodUtil();
95 scoped_refptr
<chromeos::input_method::InputMethodManager::State
> ime_state
=
96 manager
->GetActiveIMEState();
97 scoped_ptr
<chromeos::input_method::InputMethodDescriptors
> input_methods
=
98 ime_state
->GetActiveInputMethods();
99 for (size_t i
= 0; i
< input_methods
->size(); ++i
) {
100 const chromeos::input_method::InputMethodDescriptor
& input_method
=
102 base::DictionaryValue
* val
= new base::DictionaryValue();
103 val
->SetString("id", input_method
.id());
104 val
->SetString("name", util
->GetInputMethodLongName(input_method
));
105 val
->SetString("indicator", util
->GetInputMethodShortName(input_method
));
108 return RespondNow(OneArgument(output
));
112 ExtensionFunction::ResponseAction
FetchAllDictionaryWordsFunction::Run() {
113 #if !defined(OS_CHROMEOS)
114 EXTENSION_FUNCTION_VALIDATE(false);
116 SpellcheckService
* spellcheck
= SpellcheckServiceFactory::GetForContext(
119 return RespondNow(Error("Spellcheck service not available."));
121 SpellcheckCustomDictionary
* dictionary
= spellcheck
->GetCustomDictionary();
122 if (!dictionary
->IsLoaded()) {
123 return RespondNow(Error("Custom dictionary not loaded yet."));
126 const std::set
<std::string
>& words
= dictionary
->GetWords();
127 base::ListValue
* output
= new base::ListValue();
128 for (auto it
= words
.begin(); it
!= words
.end(); ++it
) {
129 output
->AppendString(*it
);
131 return RespondNow(OneArgument(output
));
135 ExtensionFunction::ResponseAction
AddWordToDictionaryFunction::Run() {
136 #if !defined(OS_CHROMEOS)
137 EXTENSION_FUNCTION_VALIDATE(false);
140 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &word
));
141 SpellcheckService
* spellcheck
= SpellcheckServiceFactory::GetForContext(
144 return RespondNow(Error("Spellcheck service not available."));
146 SpellcheckCustomDictionary
* dictionary
= spellcheck
->GetCustomDictionary();
147 if (!dictionary
->IsLoaded()) {
148 return RespondNow(Error("Custom dictionary not loaded yet."));
151 if (dictionary
->AddWord(word
))
152 return RespondNow(NoArguments());
154 // - Already in the dictionary.
155 // - Not a UTF8 string.
156 // - Longer than 99 bytes (MAX_CUSTOM_DICTIONARY_WORD_BYTES).
157 // - Leading/trailing whitespace.
159 return RespondNow(Error("Unable to add invalid word to dictionary."));
163 ExtensionFunction::ResponseAction
GetEncryptSyncEnabledFunction::Run() {
164 #if !defined(OS_CHROMEOS)
165 EXTENSION_FUNCTION_VALIDATE(false);
167 ProfileSyncService
* profile_sync_service
=
168 ProfileSyncServiceFactory::GetForProfile(
169 Profile::FromBrowserContext(browser_context()));
170 if (!profile_sync_service
)
171 return RespondNow(Error("Sync service is not ready for current profile."));
172 scoped_ptr
<base::Value
> ret(new base::FundamentalValue(
173 profile_sync_service
->EncryptEverythingEnabled()));
174 return RespondNow(OneArgument(ret
.Pass()));
179 const char InputMethodAPI::kOnDictionaryChanged
[] =
180 "inputMethodPrivate.onDictionaryChanged";
183 const char InputMethodAPI::kOnDictionaryLoaded
[] =
184 "inputMethodPrivate.onDictionaryLoaded";
187 const char InputMethodAPI::kOnInputMethodChanged
[] =
188 "inputMethodPrivate.onChanged";
190 InputMethodAPI::InputMethodAPI(content::BrowserContext
* context
)
191 : context_(context
) {
192 EventRouter::Get(context_
)->RegisterObserver(this, kOnInputMethodChanged
);
193 EventRouter::Get(context_
)->RegisterObserver(this, kOnDictionaryChanged
);
194 EventRouter::Get(context_
)->RegisterObserver(this, kOnDictionaryLoaded
);
195 ExtensionFunctionRegistry
* registry
=
196 ExtensionFunctionRegistry::GetInstance();
197 registry
->RegisterFunction
<GetInputMethodConfigFunction
>();
198 registry
->RegisterFunction
<GetCurrentInputMethodFunction
>();
199 registry
->RegisterFunction
<SetCurrentInputMethodFunction
>();
200 registry
->RegisterFunction
<GetInputMethodsFunction
>();
201 registry
->RegisterFunction
<FetchAllDictionaryWordsFunction
>();
202 registry
->RegisterFunction
<AddWordToDictionaryFunction
>();
203 registry
->RegisterFunction
<GetEncryptSyncEnabledFunction
>();
206 InputMethodAPI::~InputMethodAPI() {
210 std::string
InputMethodAPI::GetInputMethodForXkb(const std::string
& xkb_id
) {
211 std::string xkb_prefix
=
212 chromeos::extension_ime_util::GetInputMethodIDByEngineID(kXkbPrefix
);
213 size_t prefix_length
= xkb_prefix
.length();
214 DCHECK(xkb_id
.substr(0, prefix_length
) == xkb_prefix
);
215 return xkb_id
.substr(prefix_length
);
218 void InputMethodAPI::Shutdown() {
219 EventRouter::Get(context_
)->UnregisterObserver(this);
222 void InputMethodAPI::OnListenerAdded(
223 const extensions::EventListenerInfo
& details
) {
224 if (details
.event_name
== kOnInputMethodChanged
) {
225 if (!input_method_event_router_
.get()) {
226 input_method_event_router_
.reset(
227 new chromeos::ExtensionInputMethodEventRouter(context_
));
229 } else if (details
.event_name
== kOnDictionaryChanged
||
230 details
.event_name
== kOnDictionaryLoaded
) {
231 if (!dictionary_event_router_
.get()) {
232 dictionary_event_router_
.reset(
233 new chromeos::ExtensionDictionaryEventRouter(context_
));
235 if (details
.event_name
== kOnDictionaryLoaded
) {
236 dictionary_event_router_
->DispatchLoadedEventIfLoaded();
241 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<InputMethodAPI
> >
242 g_factory
= LAZY_INSTANCE_INITIALIZER
;
245 BrowserContextKeyedAPIFactory
<InputMethodAPI
>*
246 InputMethodAPI::GetFactoryInstance() {
247 return g_factory
.Pointer();
250 } // namespace extensions