Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / chromeos / input_method / component_extension_ime_manager_impl.cc
blob8afa4b92b654cf04aa698b0e93eaaa78d0a45f94
1 // Copyright 2013 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/input_method/component_extension_ime_manager_impl.h"
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "chrome/browser/extensions/component_loader.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "extensions/browser/extension_system.h"
15 #include "extensions/common/extension.h"
16 #include "extensions/common/extension_l10n_util.h"
17 #include "extensions/common/file_util.h"
18 #include "extensions/common/manifest_constants.h"
19 #include "ui/base/l10n/l10n_util.h"
21 namespace chromeos {
23 namespace {
25 struct WhitelistedComponentExtensionIME {
26 const char* id;
27 const char* path;
28 } whitelisted_component_extension[] = {
30 // ChromeOS Hangul Input.
31 "bdgdidmhaijohebebipajioienkglgfo",
32 "/usr/share/chromeos-assets/input_methods/hangul",
34 #if defined(OFFICIAL_BUILD)
36 // Official Google XKB Input.
37 "jkghodnilhceideoidjikpgommlajknk",
38 "/usr/share/chromeos-assets/input_methods/google_xkb",
41 // Official Google Keyboards Input.
42 "habcdindjejkmepknlhkkloncjcpcnbf",
43 "/usr/share/chromeos-assets/input_methods/google_keyboards",
46 // Official Google Japanese Input.
47 "fpfbhcjppmaeaijcidgiibchfbnhbelj",
48 "/usr/share/chromeos-assets/input_methods/nacl_mozc",
51 // Google input tools.
52 "gjaehgfemfahhmlgpdfknkhdnemmolop",
53 "/usr/share/chromeos-assets/input_methods/input_tools",
55 #else
57 // Open-sourced ChromeOS xkb extension.
58 "fgoepimhcoialccpbmpnnblemnepkkao",
59 "/usr/share/chromeos-assets/input_methods/xkb",
62 // Open-sourced ChromeOS Keyboards extension.
63 "jhffeifommiaekmbkkjlpmilogcfdohp",
64 "/usr/share/chromeos-assets/input_methods/keyboard_layouts",
67 // Open-sourced Pinyin Chinese Input Method.
68 "cpgalbafkoofkjmaeonnfijgpfennjjn",
69 "/usr/share/chromeos-assets/input_methods/pinyin",
72 // Open-sourced Zhuyin Chinese Input Method.
73 "ekbifjdfhkmdeeajnolmgdlmkllopefi",
74 "/usr/share/chromeos-assets/input_methods/zhuyin",
77 // Open-sourced Cangjie Chinese Input Method.
78 "aeebooiibjahgpgmhkeocbeekccfknbj",
79 "/usr/share/chromeos-assets/input_methods/cangjie",
82 // Open-sourced Mozc Japanese Input.
83 "bbaiamgfapehflhememkfglaehiobjnk",
84 "/usr/share/chromeos-assets/input_methods/nacl_mozc",
86 #endif
89 extensions::ComponentLoader* GetComponentLoader() {
90 // TODO(skuhne, nkostylev): At this time the only thing which makes sense here
91 // is to use the active profile. Nkostylev is working on getting IME settings
92 // to work for multi user by collecting all settings from all users. Once that
93 // is done we might have to re-visit this decision.
94 Profile* profile = ProfileManager::GetActiveUserProfile();
95 extensions::ExtensionSystem* extension_system =
96 extensions::ExtensionSystem::Get(profile);
97 ExtensionService* extension_service = extension_system->extension_service();
98 return extension_service->component_loader();
100 } // namespace
102 ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl()
103 : is_initialized_(false),
104 weak_ptr_factory_(this) {
107 ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() {
110 std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() {
111 DCHECK(thread_checker_.CalledOnValidThread());
112 return component_extension_list_;
115 bool ComponentExtensionIMEManagerImpl::Load(const std::string& extension_id,
116 const std::string& manifest,
117 const base::FilePath& file_path) {
118 DCHECK(thread_checker_.CalledOnValidThread());
119 Profile* profile = ProfileManager::GetActiveUserProfile();
120 extensions::ExtensionSystem* extension_system =
121 extensions::ExtensionSystem::Get(profile);
122 ExtensionService* extension_service = extension_system->extension_service();
123 if (extension_service->GetExtensionById(extension_id, false))
124 return false;
125 const std::string loaded_extension_id =
126 GetComponentLoader()->Add(manifest, file_path);
127 DCHECK_EQ(loaded_extension_id, extension_id);
128 return true;
131 void ComponentExtensionIMEManagerImpl::Unload(const std::string& extension_id,
132 const base::FilePath& file_path) {
133 DCHECK(thread_checker_.CalledOnValidThread());
134 // Remove(extension_id) does nothing when the extension has already been
135 // removed or not been registered.
136 GetComponentLoader()->Remove(extension_id);
139 scoped_ptr<base::DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest(
140 const base::FilePath& file_path) {
141 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
142 std::string error;
143 scoped_ptr<base::DictionaryValue> manifest(
144 extensions::file_util::LoadManifest(file_path, &error));
145 if (!manifest.get())
146 LOG(ERROR) << "Failed at getting manifest";
147 if (!extension_l10n_util::LocalizeExtension(file_path,
148 manifest.get(),
149 &error))
150 LOG(ERROR) << "Localization failed";
152 return manifest.Pass();
155 void ComponentExtensionIMEManagerImpl::InitializeAsync(
156 const base::Closure& callback) {
157 DCHECK(!is_initialized_);
158 DCHECK(thread_checker_.CalledOnValidThread());
160 std::vector<ComponentExtensionIME>* component_extension_ime_list
161 = new std::vector<ComponentExtensionIME>;
162 content::BrowserThread::PostTaskAndReply(
163 content::BrowserThread::FILE,
164 FROM_HERE,
165 base::Bind(&ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo,
166 base::Unretained(component_extension_ime_list)),
167 base::Bind(
168 &ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo,
169 weak_ptr_factory_.GetWeakPtr(),
170 base::Owned(component_extension_ime_list),
171 callback));
174 bool ComponentExtensionIMEManagerImpl::IsInitialized() {
175 return is_initialized_;
178 // static
179 bool ComponentExtensionIMEManagerImpl::ReadEngineComponent(
180 const ComponentExtensionIME& component_extension,
181 const base::DictionaryValue& dict,
182 ComponentExtensionEngine* out) {
183 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
184 DCHECK(out);
185 std::string type;
186 if (!dict.GetString(extensions::manifest_keys::kType, &type))
187 return false;
188 if (type != "ime")
189 return false;
190 if (!dict.GetString(extensions::manifest_keys::kId, &out->engine_id))
191 return false;
192 if (!dict.GetString(extensions::manifest_keys::kName, &out->display_name))
193 return false;
195 std::set<std::string> languages;
196 const base::Value* language_value = NULL;
197 if (dict.Get(extensions::manifest_keys::kLanguage, &language_value)) {
198 if (language_value->GetType() == base::Value::TYPE_STRING) {
199 std::string language_str;
200 language_value->GetAsString(&language_str);
201 languages.insert(language_str);
202 } else if (language_value->GetType() == base::Value::TYPE_LIST) {
203 const base::ListValue* language_list = NULL;
204 language_value->GetAsList(&language_list);
205 for (size_t j = 0; j < language_list->GetSize(); ++j) {
206 std::string language_str;
207 if (language_list->GetString(j, &language_str))
208 languages.insert(language_str);
212 DCHECK(!languages.empty());
213 out->language_codes.assign(languages.begin(), languages.end());
215 const base::ListValue* layouts = NULL;
216 if (!dict.GetList(extensions::manifest_keys::kLayouts, &layouts))
217 return false;
219 for (size_t i = 0; i < layouts->GetSize(); ++i) {
220 std::string buffer;
221 if (layouts->GetString(i, &buffer))
222 out->layouts.push_back(buffer);
225 std::string url_string;
226 if (dict.GetString(extensions::manifest_keys::kInputView,
227 &url_string)) {
228 GURL url = extensions::Extension::GetResourceURL(
229 extensions::Extension::GetBaseURLFromExtensionId(
230 component_extension.id),
231 url_string);
232 if (!url.is_valid())
233 return false;
234 out->input_view_url = url;
237 if (dict.GetString(extensions::manifest_keys::kOptionsPage,
238 &url_string)) {
239 GURL url = extensions::Extension::GetResourceURL(
240 extensions::Extension::GetBaseURLFromExtensionId(
241 component_extension.id),
242 url_string);
243 if (!url.is_valid())
244 return false;
245 out->options_page_url = url;
246 } else {
247 // Fallback to extension level options page.
248 out->options_page_url = component_extension.options_page_url;
251 return true;
254 // static
255 bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo(
256 const base::DictionaryValue& manifest,
257 const std::string& extension_id,
258 ComponentExtensionIME* out) {
259 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
260 if (!manifest.GetString(extensions::manifest_keys::kDescription,
261 &out->description))
262 return false;
263 std::string url_string;
264 if (manifest.GetString(extensions::manifest_keys::kOptionsPage,
265 &url_string)) {
266 GURL url = extensions::Extension::GetResourceURL(
267 extensions::Extension::GetBaseURLFromExtensionId(extension_id),
268 url_string);
269 if (!url.is_valid())
270 return false;
271 out->options_page_url = url;
273 // It's okay to return true on no option page and/or input view page case.
274 return true;
277 // static
278 void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo(
279 std::vector<ComponentExtensionIME>* out_imes) {
280 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
281 DCHECK(out_imes);
282 for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) {
283 ComponentExtensionIME component_ime;
284 component_ime.path = base::FilePath(
285 whitelisted_component_extension[i].path);
287 const base::FilePath manifest_path =
288 component_ime.path.Append("manifest.json");
290 if (!base::PathExists(component_ime.path) ||
291 !base::PathExists(manifest_path))
292 continue;
294 if (!base::ReadFileToString(manifest_path, &component_ime.manifest))
295 continue;
297 scoped_ptr<base::DictionaryValue> manifest =
298 GetManifest(component_ime.path);
299 if (!manifest.get())
300 continue;
302 if (!ReadExtensionInfo(*manifest.get(),
303 whitelisted_component_extension[i].id,
304 &component_ime))
305 continue;
306 component_ime.id = whitelisted_component_extension[i].id;
308 const base::ListValue* component_list;
309 if (!manifest->GetList(extensions::manifest_keys::kInputComponents,
310 &component_list))
311 continue;
313 for (size_t i = 0; i < component_list->GetSize(); ++i) {
314 const base::DictionaryValue* dictionary;
315 if (!component_list->GetDictionary(i, &dictionary))
316 continue;
318 ComponentExtensionEngine engine;
319 ReadEngineComponent(component_ime, *dictionary, &engine);
320 component_ime.engines.push_back(engine);
322 out_imes->push_back(component_ime);
326 void ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo(
327 std::vector<ComponentExtensionIME>* result,
328 const base::Closure& callback) {
329 DCHECK(thread_checker_.CalledOnValidThread());
330 DCHECK(result);
331 component_extension_list_ = *result;
332 is_initialized_ = true;
333 callback.Run();
336 } // namespace chromeos