12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/file_util.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/component_loader.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/extension.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension_file_util.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension_l10n_util.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension_manifest_constants.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct WhitelistedComponentExtensionIME {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* id;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* path;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} whitelisted_component_extension[] = {
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  {
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // ChromeOS Keyboards extension.
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "jhffeifommiaekmbkkjlpmilogcfdohp",
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "/usr/share/chromeos-assets/input_methods/keyboard_layouts",
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  },
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  {
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // ChromeOS Hangul Input.
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "bdgdidmhaijohebebipajioienkglgfo",
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "/usr/share/chromeos-assets/input_methods/hangul",
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  },
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OFFICIAL_BUILD)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Official Google Japanese Input.
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "fpfbhcjppmaeaijcidgiibchfbnhbelj",
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "/usr/share/chromeos-assets/input_methods/nacl_mozc",
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  },
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
464311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    // Google Chinese Input (zhuyin)
474311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    "goedamlknlnjaengojinmfgpmdjmkooo",
484311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    "/usr/share/chromeos-assets/input_methods/zhuyin",
494311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  },
504311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  {
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Google Chinese Input (pinyin)
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "nmblnjkfdkabgdofidlkienfnnbjhnab",
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "/usr/share/chromeos-assets/input_methods/pinyin",
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  },
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  {
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Google Chinese Input (cangjie)
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "gjhclobljhjhgoebiipblnmdodbmpdgd",
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "/usr/share/chromeos-assets/input_methods/cangjie",
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  },
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  {
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Google input tools.
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "gjaehgfemfahhmlgpdfknkhdnemmolop",
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "/usr/share/chromeos-assets/input_methods/input_tools",
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  },
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Open-sourced Pinyin Chinese Input Method.
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "cpgalbafkoofkjmaeonnfijgpfennjjn",
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "/usr/share/chromeos-assets/input_methods/pinyin",
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  },
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  {
724311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    // Open-sourced Zhuyin Chinese Input Method.
734311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    "ekbifjdfhkmdeeajnolmgdlmkllopefi",
744311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    "/usr/share/chromeos-assets/input_methods/zhuyin",
754311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  },
764311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  {
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Open-sourced Cangjie Chinese Input Method.
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "aeebooiibjahgpgmhkeocbeekccfknbj",
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    "/usr/share/chromeos-assets/input_methods/cangjie",
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  },
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  {
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Open-sourced Mozc Japanese Input.
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "bbaiamgfapehflhememkfglaehiobjnk",
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "/usr/share/chromeos-assets/input_methods/nacl_mozc",
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  },
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)extensions::ComponentLoader* GetComponentLoader() {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::ExtensionSystem* extension_system =
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile);
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionService* extension_service = extension_system->extension_service();
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return extension_service->component_loader();
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl()
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : is_initialized_(false),
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      weak_ptr_factory_(this) {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return component_extension_list_;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ComponentExtensionIMEManagerImpl::Load(const std::string& extension_id,
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            const std::string& manifest,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const base::FilePath& file_path) {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (loaded_extension_id_.find(extension_id) != loaded_extension_id_.end())
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string loaded_extension_id =
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetComponentLoader()->Add(manifest, file_path);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(loaded_extension_id, extension_id);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  loaded_extension_id_.insert(extension_id);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ComponentExtensionIMEManagerImpl::Unload(const std::string& extension_id,
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              const base::FilePath& file_path) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (loaded_extension_id_.find(extension_id) == loaded_extension_id_.end())
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetComponentLoader()->Remove(extension_id);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  loaded_extension_id_.erase(extension_id);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest(
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& file_path) {
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string error;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DictionaryValue> manifest(
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_file_util::LoadManifest(file_path, &error));
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!manifest.get())
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed at getting manifest";
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension_l10n_util::LocalizeExtension(file_path,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              manifest.get(),
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              &error))
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Localization failed";
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return manifest.Pass();
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ComponentExtensionIMEManagerImpl::InitializeAsync(
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& callback) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!is_initialized_);
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<ComponentExtensionIME>* component_extension_ime_list
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      = new std::vector<ComponentExtensionIME>;
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  content::BrowserThread::PostTaskAndReply(
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      content::BrowserThread::FILE,
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(component_extension_ime_list)),
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          &ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          weak_ptr_factory_.GetWeakPtr(),
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Owned(component_extension_ime_list),
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          callback));
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ComponentExtensionIMEManagerImpl::IsInitialized() {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return is_initialized_;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ComponentExtensionIMEManagerImpl::ReadEngineComponent(
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DictionaryValue& dict,
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ComponentExtensionEngine* out) {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(out);
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dict.GetString(extension_manifest_keys::kType, &type))
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type != "ime")
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dict.GetString(extension_manifest_keys::kId, &out->engine_id))
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dict.GetString(extension_manifest_keys::kName, &out->display_name))
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
188a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
189a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  std::set<std::string> languages;
190a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  const base::Value* language_value = NULL;
191a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (dict.Get(extension_manifest_keys::kLanguage, &language_value)) {
192a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    if (language_value->GetType() == base::Value::TYPE_STRING) {
193a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      std::string language_str;
194a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      language_value->GetAsString(&language_str);
195a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      languages.insert(language_str);
196a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    } else if (language_value->GetType() == base::Value::TYPE_LIST) {
197a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      const base::ListValue* language_list = NULL;
198a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      language_value->GetAsList(&language_list);
199a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      for (size_t j = 0; j < language_list->GetSize(); ++j) {
200a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch        std::string language_str;
201a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch        if (language_list->GetString(j, &language_str))
202a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch          languages.insert(language_str);
203a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      }
204a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
205a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
206a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  DCHECK(!languages.empty());
207a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  out->language_codes.assign(languages.begin(), languages.end());
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const ListValue* layouts = NULL;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dict.GetList(extension_manifest_keys::kLayouts, &layouts))
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < layouts->GetSize(); ++i) {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string buffer;
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (layouts->GetString(i, &buffer))
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      out->layouts.push_back(buffer);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo(
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DictionaryValue& manifest,
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& extension_id,
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ComponentExtensionIME* out) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!manifest.GetString(extension_manifest_keys::kDescription,
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          &out->description))
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string url_string;
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!manifest.GetString(extension_manifest_keys::kOptionsPage, &url_string))
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;  // It's okay to return true on no option page case.
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL url = extensions::Extension::GetResourceURL(
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      extensions::Extension::GetBaseURLFromExtensionId(extension_id),
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      url_string);
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!url.is_valid())
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  out->options_page_url = url;
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo(
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<ComponentExtensionIME>* out_imes) {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(out_imes);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) {
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ComponentExtensionIME component_ime;
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    component_ime.path = base::FilePath(
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        whitelisted_component_extension[i].path);
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::FilePath manifest_path =
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        component_ime.path.Append("manifest.json");
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!base::PathExists(component_ime.path) ||
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        !base::PathExists(manifest_path))
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!file_util::ReadFileToString(manifest_path, &component_ime.manifest))
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<DictionaryValue> manifest = GetManifest(component_ime.path);
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!manifest.get())
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!ReadExtensionInfo(*manifest.get(),
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           whitelisted_component_extension[i].id,
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           &component_ime))
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    component_ime.id = whitelisted_component_extension[i].id;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ListValue* component_list;
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!manifest->GetList(extension_manifest_keys::kInputComponents,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           &component_list))
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < component_list->GetSize(); ++i) {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const DictionaryValue* dictionary;
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!component_list->GetDictionary(i, &dictionary))
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ComponentExtensionEngine engine;
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ReadEngineComponent(*dictionary, &engine);
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      component_ime.engines.push_back(engine);
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    out_imes->push_back(component_ime);
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo(
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<ComponentExtensionIME>* result,
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& callback) {
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(result);
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  component_extension_list_ = *result;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  is_initialized_ = true;
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run();
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
302