component_extension_ime_manager_impl.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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. 4 5#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h" 6 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/extensions/extension_system.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/profiles/profile_manager.h" 14#include "chrome/common/extensions/extension.h" 15#include "chrome/common/extensions/extension_file_util.h" 16#include "chrome/common/extensions/extension_l10n_util.h" 17#include "chrome/common/extensions/extension_manifest_constants.h" 18#include "content/public/browser/browser_thread.h" 19#include "ui/base/l10n/l10n_util.h" 20 21namespace chromeos { 22 23namespace { 24 25struct WhitelistedComponentExtensionIME { 26 const char* id; 27 const char* path; 28} whitelisted_component_extension[] = { 29#if defined(OFFICIAL_BUILD) 30 { 31 // Official Google Japanese Input. 32 "fpfbhcjppmaeaijcidgiibchfbnhbelj", 33 "/usr/share/chromeos-assets/input_methods/nacl_mozc", 34 }, 35 { 36 // Google input tools. 37 "gjaehgfemfahhmlgpdfknkhdnemmolop", 38 "/usr/share/chromeos-assets/input_methods/input_tools", 39 }, 40#else 41 { 42 // Open-sourced Mozc Japanese Input. 43 "bbaiamgfapehflhememkfglaehiobjnk", 44 "/usr/share/chromeos-assets/input_methods/nacl_mozc", 45 }, 46#endif 47}; 48 49extensions::ComponentLoader* GetComponentLoader() { 50 Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord(); 51 extensions::ExtensionSystem* extension_system = 52 extensions::ExtensionSystem::Get(profile); 53 ExtensionService* extension_service = extension_system->extension_service(); 54 return extension_service->component_loader(); 55} 56} // namespace 57 58ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl() 59 : is_initialized_(false), 60 weak_ptr_factory_(this) { 61} 62 63ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() { 64} 65 66std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() { 67 DCHECK(thread_checker_.CalledOnValidThread()); 68 return component_extension_list_; 69} 70 71bool ComponentExtensionIMEManagerImpl::Load(const std::string& extension_id, 72 const std::string& manifest, 73 const base::FilePath& file_path) { 74 DCHECK(thread_checker_.CalledOnValidThread()); 75 if (loaded_extension_id_.find(extension_id) != loaded_extension_id_.end()) 76 return false; 77 const std::string loaded_extension_id = 78 GetComponentLoader()->Add(manifest, file_path); 79 DCHECK_EQ(loaded_extension_id, extension_id); 80 loaded_extension_id_.insert(extension_id); 81 return true; 82} 83 84bool ComponentExtensionIMEManagerImpl::Unload(const std::string& extension_id, 85 const base::FilePath& file_path) { 86 DCHECK(thread_checker_.CalledOnValidThread()); 87 if (loaded_extension_id_.find(extension_id) == loaded_extension_id_.end()) 88 return false; 89 GetComponentLoader()->Remove(extension_id); 90 loaded_extension_id_.erase(extension_id); 91 return true; 92} 93 94scoped_ptr<DictionaryValue> ComponentExtensionIMEManagerImpl::GetManifest( 95 const base::FilePath& file_path) { 96 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 97 std::string error; 98 scoped_ptr<DictionaryValue> manifest( 99 extension_file_util::LoadManifest(file_path, &error)); 100 if (!manifest.get()) 101 LOG(ERROR) << "Failed at getting manifest"; 102 if (!extension_l10n_util::LocalizeExtension(file_path, 103 manifest.get(), 104 &error)) 105 LOG(ERROR) << "Localization failed"; 106 107 return manifest.Pass(); 108} 109 110void ComponentExtensionIMEManagerImpl::InitializeAsync( 111 const base::Closure& callback) { 112 DCHECK(!is_initialized_); 113 DCHECK(thread_checker_.CalledOnValidThread()); 114 115 std::vector<ComponentExtensionIME>* component_extension_ime_list 116 = new std::vector<ComponentExtensionIME>; 117 BrowserThread::PostTaskAndReply( 118 BrowserThread::FILE, 119 FROM_HERE, 120 base::Bind(&ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo, 121 base::Unretained(component_extension_ime_list)), 122 base::Bind( 123 &ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo, 124 weak_ptr_factory_.GetWeakPtr(), 125 base::Owned(component_extension_ime_list), 126 callback)); 127} 128 129bool ComponentExtensionIMEManagerImpl::IsInitialized() { 130 return is_initialized_; 131} 132 133// static 134bool ComponentExtensionIMEManagerImpl::ReadEngineComponent( 135 const DictionaryValue& dict, 136 ComponentExtensionEngine* out) { 137 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 138 DCHECK(out); 139 std::string type; 140 if (!dict.GetString(extension_manifest_keys::kType, &type)) 141 return false; 142 if (type != "ime") 143 return false; 144 if (!dict.GetString(extension_manifest_keys::kId, &out->engine_id)) 145 return false; 146 if (!dict.GetString(extension_manifest_keys::kName, &out->display_name)) 147 return false; 148 if (!dict.GetString(extension_manifest_keys::kLanguage, &out->language_code)) 149 return false; 150 151 const ListValue* layouts = NULL; 152 if (!dict.GetList(extension_manifest_keys::kLayouts, &layouts)) 153 return false; 154 155 for (size_t i = 0; i < layouts->GetSize(); ++i) { 156 std::string buffer; 157 if (layouts->GetString(i, &buffer)) 158 out->layouts.push_back(buffer); 159 } 160 return true; 161} 162 163// static 164bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo( 165 const DictionaryValue& manifest, 166 const std::string& extension_id, 167 ComponentExtensionIME* out) { 168 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 169 if (!manifest.GetString(extension_manifest_keys::kDescription, 170 &out->description)) 171 return false; 172 std::string url_string; 173 if (!manifest.GetString(extension_manifest_keys::kOptionsPage, &url_string)) 174 return true; // It's okay to return true on no option page case. 175 176 GURL url = extensions::Extension::GetResourceURL( 177 extensions::Extension::GetBaseURLFromExtensionId(extension_id), 178 url_string); 179 if (!url.is_valid()) 180 return false; 181 out->options_page_url = url; 182 return true; 183} 184 185// static 186void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo( 187 std::vector<ComponentExtensionIME>* out_imes) { 188 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 189 DCHECK(out_imes); 190 for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) { 191 ComponentExtensionIME component_ime; 192 component_ime.path = base::FilePath( 193 whitelisted_component_extension[i].path); 194 195 const base::FilePath manifest_path = 196 component_ime.path.Append("manifest.json"); 197 198 if (!file_util::PathExists(component_ime.path) || 199 !file_util::PathExists(manifest_path)) 200 continue; 201 202 if (!file_util::ReadFileToString(manifest_path, &component_ime.manifest)) 203 continue; 204 205 scoped_ptr<DictionaryValue> manifest = GetManifest(component_ime.path); 206 if (!manifest.get()) 207 continue; 208 209 if (!ReadExtensionInfo(*manifest.get(), 210 whitelisted_component_extension[i].id, 211 &component_ime)) 212 continue; 213 component_ime.id = whitelisted_component_extension[i].id; 214 215 const ListValue* component_list; 216 if (!manifest->GetList(extension_manifest_keys::kInputComponents, 217 &component_list)) 218 continue; 219 220 for (size_t i = 0; i < component_list->GetSize(); ++i) { 221 const DictionaryValue* dictionary; 222 if (!component_list->GetDictionary(i, &dictionary)) 223 continue; 224 225 ComponentExtensionEngine engine; 226 ReadEngineComponent(*dictionary, &engine); 227 component_ime.engines.push_back(engine); 228 } 229 out_imes->push_back(component_ime); 230 } 231} 232 233void ComponentExtensionIMEManagerImpl::OnReadComponentExtensionsInfo( 234 std::vector<ComponentExtensionIME>* result, 235 const base::Closure& callback) { 236 DCHECK(thread_checker_.CalledOnValidThread()); 237 DCHECK(result); 238 component_extension_list_ = *result; 239 is_initialized_ = true; 240 callback.Run(); 241} 242 243} // namespace chromeos 244