Home | History | Annotate | Download | only in chromeos
      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/ui/webui/options/chromeos/cros_language_options_handler.h"
      6 
      7 #include <algorithm>
      8 #include <iterator>
      9 #include <map>
     10 #include <set>
     11 #include <vector>
     12 
     13 #include "base/bind.h"
     14 #include "base/bind_helpers.h"
     15 #include "base/i18n/rtl.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "base/values.h"
     19 #include "chrome/app/chrome_command_ids.h"
     20 #include "chrome/browser/browser_process.h"
     21 #include "chrome/browser/chromeos/customization_document.h"
     22 #include "chrome/browser/chromeos/input_method/input_method_util.h"
     23 #include "chrome/browser/chromeos/login/users/user_manager.h"
     24 #include "chrome/browser/extensions/extension_service.h"
     25 #include "chrome/browser/extensions/extension_tab_util.h"
     26 #include "chrome/browser/lifetime/application_lifetime.h"
     27 #include "chrome/browser/profiles/profile.h"
     28 #include "chrome/browser/ui/browser.h"
     29 #include "chrome/browser/ui/browser_finder.h"
     30 #include "chrome/browser/ui/browser_window.h"
     31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     32 #include "chrome/common/extensions/manifest_url_handler.h"
     33 #include "chromeos/ime/component_extension_ime_manager.h"
     34 #include "chromeos/ime/extension_ime_util.h"
     35 #include "chromeos/ime/input_method_manager.h"
     36 #include "content/public/browser/navigation_controller.h"
     37 #include "content/public/browser/user_metrics.h"
     38 #include "content/public/browser/web_contents.h"
     39 #include "extensions/browser/extension_system.h"
     40 #include "extensions/common/extension.h"
     41 #include "grit/chromium_strings.h"
     42 #include "grit/generated_resources.h"
     43 #include "ui/base/l10n/l10n_util.h"
     44 
     45 using base::UserMetricsAction;
     46 
     47 namespace {
     48 // TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
     49 // see: crbug.com/240586
     50 
     51 bool IsBlacklisted(const std::string& language_code) {
     52   return language_code == "si"; // Sinhala
     53 }
     54 
     55 } // namespace
     56 
     57 namespace chromeos {
     58 namespace options {
     59 
     60 const char kVendorOtherLanguagesListDivider[] =
     61     "VENDOR_OTHER_LANGUAGES_LIST_DIVIDER";
     62 
     63 CrosLanguageOptionsHandler::CrosLanguageOptionsHandler()
     64     : composition_extension_appended_(false),
     65       is_page_initialized_(false) {
     66   input_method::InputMethodManager::Get()->GetComponentExtensionIMEManager()->
     67       AddObserver(this);
     68 }
     69 
     70 CrosLanguageOptionsHandler::~CrosLanguageOptionsHandler() {
     71   input_method::InputMethodManager::Get()->GetComponentExtensionIMEManager()->
     72       RemoveObserver(this);
     73 }
     74 
     75 void CrosLanguageOptionsHandler::GetLocalizedValues(
     76     base::DictionaryValue* localized_strings) {
     77   ::options::LanguageOptionsHandlerCommon::GetLocalizedValues(
     78       localized_strings);
     79 
     80   RegisterTitle(localized_strings, "languagePage",
     81                 IDS_OPTIONS_SETTINGS_LANGUAGES_AND_INPUT_DIALOG_TITLE);
     82   localized_strings->SetString("okButton", l10n_util::GetStringUTF16(IDS_OK));
     83   localized_strings->SetString("configure",
     84       l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
     85   localized_strings->SetString("inputMethod",
     86       l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
     87   localized_strings->SetString("pleaseAddAnotherInputMethod",
     88       l10n_util::GetStringUTF16(
     89           IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD));
     90   localized_strings->SetString("inputMethodInstructions",
     91       l10n_util::GetStringUTF16(
     92           IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS));
     93   localized_strings->SetString("switchInputMethodsHint",
     94       l10n_util::GetStringUTF16(
     95           IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT));
     96   localized_strings->SetString("selectPreviousInputMethodHint",
     97       l10n_util::GetStringUTF16(
     98           IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT));
     99   localized_strings->SetString("restartButton",
    100       l10n_util::GetStringUTF16(
    101           IDS_OPTIONS_SETTINGS_LANGUAGES_SIGN_OUT_BUTTON));
    102   localized_strings->SetString("extensionImeLable",
    103       l10n_util::GetStringUTF16(
    104           IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_IME));
    105   localized_strings->SetString("extensionImeDescription",
    106       l10n_util::GetStringUTF16(
    107           IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_DESCRIPTION));
    108   localized_strings->SetString("noInputMethods",
    109       l10n_util::GetStringUTF16(
    110           IDS_OPTIONS_SETTINGS_LANGUAGES_NO_INPUT_METHODS));
    111 
    112   input_method::InputMethodManager* manager =
    113       input_method::InputMethodManager::Get();
    114   // GetSupportedInputMethods() never return NULL.
    115   scoped_ptr<input_method::InputMethodDescriptors> descriptors(
    116       manager->GetSupportedInputMethods());
    117   localized_strings->Set("languageList", GetAcceptLanguageList(*descriptors));
    118   localized_strings->Set("inputMethodList", GetInputMethodList(*descriptors));
    119 
    120   input_method::InputMethodDescriptors ext_ime_descriptors;
    121   manager->GetInputMethodExtensions(&ext_ime_descriptors);
    122 
    123   base::ListValue* ext_ime_list = ConvertInputMethodDescriptorsToIMEList(
    124       ext_ime_descriptors);
    125   AddImeProvider(ext_ime_list);
    126   localized_strings->Set("extensionImeList", ext_ime_list);
    127 
    128   ComponentExtensionIMEManager* component_extension_manager =
    129       input_method::InputMethodManager::Get()
    130           ->GetComponentExtensionIMEManager();
    131   if (component_extension_manager->IsInitialized()) {
    132     localized_strings->Set(
    133         "componentExtensionImeList",
    134         ConvertInputMethodDescriptorsToIMEList(
    135             component_extension_manager->GetAllIMEAsInputMethodDescriptor()));
    136     composition_extension_appended_ = true;
    137   } else {
    138     // If component extension IME manager is not ready for use, it will be
    139     // added in |InitializePage()|.
    140     localized_strings->Set("componentExtensionImeList",
    141                            new base::ListValue());
    142   }
    143 }
    144 
    145 void CrosLanguageOptionsHandler::RegisterMessages() {
    146   ::options::LanguageOptionsHandlerCommon::RegisterMessages();
    147 
    148   web_ui()->RegisterMessageCallback("inputMethodDisable",
    149       base::Bind(&CrosLanguageOptionsHandler::InputMethodDisableCallback,
    150                  base::Unretained(this)));
    151   web_ui()->RegisterMessageCallback("inputMethodEnable",
    152       base::Bind(&CrosLanguageOptionsHandler::InputMethodEnableCallback,
    153                  base::Unretained(this)));
    154   web_ui()->RegisterMessageCallback("inputMethodOptionsOpen",
    155       base::Bind(&CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback,
    156                  base::Unretained(this)));
    157   web_ui()->RegisterMessageCallback("uiLanguageRestart",
    158       base::Bind(&CrosLanguageOptionsHandler::RestartCallback,
    159                  base::Unretained(this)));
    160 }
    161 
    162 // static
    163 base::ListValue* CrosLanguageOptionsHandler::GetInputMethodList(
    164     const input_method::InputMethodDescriptors& descriptors) {
    165   input_method::InputMethodManager* manager =
    166       input_method::InputMethodManager::Get();
    167 
    168   base::ListValue* input_method_list = new base::ListValue();
    169 
    170   for (size_t i = 0; i < descriptors.size(); ++i) {
    171     const input_method::InputMethodDescriptor& descriptor =
    172         descriptors[i];
    173     const std::string display_name =
    174         manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId(
    175             descriptor.id());
    176     base::DictionaryValue* dictionary = new base::DictionaryValue();
    177     dictionary->SetString("id", descriptor.id());
    178     dictionary->SetString("displayName", display_name);
    179 
    180     // One input method can be associated with multiple languages, hence
    181     // we use a dictionary here.
    182     base::DictionaryValue* languages = new base::DictionaryValue();
    183     for (size_t i = 0; i < descriptor.language_codes().size(); ++i) {
    184       languages->SetBoolean(descriptor.language_codes().at(i), true);
    185     }
    186     dictionary->Set("languageCodeSet", languages);
    187 
    188     input_method_list->Append(dictionary);
    189   }
    190 
    191   return input_method_list;
    192 }
    193 
    194 // static
    195 base::ListValue* CrosLanguageOptionsHandler::GetLanguageListInternal(
    196     const input_method::InputMethodDescriptors& descriptors,
    197     const std::vector<std::string>& base_language_codes,
    198     const bool insert_divider) {
    199   const std::string app_locale = g_browser_process->GetApplicationLocale();
    200 
    201   std::set<std::string> language_codes;
    202   // Collect the language codes from the supported input methods.
    203   for (size_t i = 0; i < descriptors.size(); ++i) {
    204     const input_method::InputMethodDescriptor& descriptor = descriptors[i];
    205     const std::vector<std::string>& languages =
    206         descriptor.language_codes();
    207     for (size_t i = 0; i < languages.size(); ++i)
    208       language_codes.insert(languages[i]);
    209   }
    210 
    211   const StartupCustomizationDocument* startup_manifest =
    212       StartupCustomizationDocument::GetInstance();
    213 
    214   const std::vector<std::string>& configured_locales =
    215       startup_manifest->configured_locales();
    216 
    217   // Languages sort order.
    218   std::map<std::string, int /* index */> language_index;
    219   for (size_t i = 0; i < configured_locales.size(); ++i) {
    220     language_index[configured_locales[i]] = i;
    221   }
    222 
    223   // Map of display name -> {language code, native_display_name}.
    224   // In theory, we should be able to create a map that is sorted by
    225   // display names using ICU comparator, but doing it is hard, thus we'll
    226   // use an auxiliary vector to achieve the same result.
    227   typedef std::pair<std::string, base::string16> LanguagePair;
    228   typedef std::map<base::string16, LanguagePair> LanguageMap;
    229   LanguageMap language_map;
    230 
    231   // The auxiliary vector mentioned above. (except vendor locales)
    232   std::vector<base::string16> display_names;
    233 
    234   // Separate vector of vendor locales.
    235   std::vector<base::string16> configured_locales_display_names(
    236       configured_locales.size());
    237 
    238   size_t configured_locales_count = 0;
    239 
    240   // Build the list of display names, and build the language map.
    241 
    242   // The list of configured locales might have entries not in
    243   // base_language_codes. If there are unsupported language variants,
    244   // but they resolve to backup locale within base_language_codes, also
    245   // add them to the list.
    246   for (std::map<std::string, int>::const_iterator iter = language_index.begin();
    247        iter != language_index.end();
    248        ++iter) {
    249     const std::string& language_id = iter->first;
    250     const int language_idx = iter->second;
    251 
    252     const size_t dash_pos = language_id.find_first_of('-');
    253 
    254     // Ignore non-specific codes.
    255     if (dash_pos == std::string::npos || dash_pos == 0)
    256       continue;
    257 
    258     if (std::find(base_language_codes.begin(),
    259                   base_language_codes.end(),
    260                   language_id) != base_language_codes.end()) {
    261       // Language is supported. No need to replace
    262       continue;
    263     }
    264     std::string resolved_locale;
    265     if (!l10n_util::CheckAndResolveLocale(language_id, &resolved_locale))
    266       continue;
    267 
    268     if (std::find(base_language_codes.begin(),
    269                   base_language_codes.end(),
    270                   resolved_locale) == base_language_codes.end()) {
    271       // Resolved locale is not supported.
    272       continue;
    273     }
    274 
    275     const base::string16 display_name =
    276         l10n_util::GetDisplayNameForLocale(language_id, app_locale, true);
    277     const base::string16 native_display_name =
    278         l10n_util::GetDisplayNameForLocale(
    279             language_id, language_id, true);
    280 
    281     language_map[display_name] =
    282         std::make_pair(language_id, native_display_name);
    283 
    284     configured_locales_display_names[language_idx] = display_name;
    285     ++configured_locales_count;
    286   }
    287 
    288   // Translate language codes, generated from input methods.
    289   for (std::set<std::string>::const_iterator iter = language_codes.begin();
    290        iter != language_codes.end(); ++iter) {
    291      // Exclude the language which is not in |base_langauge_codes| even it has
    292      // input methods.
    293     if (std::find(base_language_codes.begin(),
    294                   base_language_codes.end(),
    295                   *iter) == base_language_codes.end()) {
    296       continue;
    297     }
    298 
    299     const base::string16 display_name =
    300         l10n_util::GetDisplayNameForLocale(*iter, app_locale, true);
    301     const base::string16 native_display_name =
    302         l10n_util::GetDisplayNameForLocale(*iter, *iter, true);
    303 
    304     language_map[display_name] =
    305         std::make_pair(*iter, native_display_name);
    306 
    307     const std::map<std::string, int>::const_iterator index_pos =
    308         language_index.find(*iter);
    309     if (index_pos != language_index.end()) {
    310       base::string16& stored_display_name =
    311           configured_locales_display_names[index_pos->second];
    312       if (stored_display_name.empty()) {
    313         stored_display_name = display_name;
    314         ++configured_locales_count;
    315       }
    316     } else {
    317       display_names.push_back(display_name);
    318     }
    319   }
    320   DCHECK_EQ(display_names.size() + configured_locales_count,
    321             language_map.size());
    322 
    323   // Build the list of display names, and build the language map.
    324   for (size_t i = 0; i < base_language_codes.size(); ++i) {
    325     // Skip this language if it was already added.
    326     if (language_codes.find(base_language_codes[i]) != language_codes.end())
    327       continue;
    328 
    329     // TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
    330     // see: crbug.com/240586
    331     if (IsBlacklisted(base_language_codes[i]))
    332       continue;
    333 
    334     base::string16 display_name =
    335         l10n_util::GetDisplayNameForLocale(
    336             base_language_codes[i], app_locale, false);
    337     base::string16 native_display_name =
    338         l10n_util::GetDisplayNameForLocale(
    339             base_language_codes[i], base_language_codes[i], false);
    340     language_map[display_name] =
    341         std::make_pair(base_language_codes[i], native_display_name);
    342 
    343     const std::map<std::string, int>::const_iterator index_pos =
    344         language_index.find(base_language_codes[i]);
    345     if (index_pos != language_index.end()) {
    346       configured_locales_display_names[index_pos->second] = display_name;
    347       ++configured_locales_count;
    348     } else {
    349       display_names.push_back(display_name);
    350     }
    351   }
    352 
    353   // Sort display names using locale specific sorter.
    354   l10n_util::SortStrings16(app_locale, &display_names);
    355   // Concatenate configured_locales_display_names and display_names.
    356   // Insert special divider in between.
    357   std::vector<base::string16> out_display_names;
    358   for (size_t i = 0; i < configured_locales_display_names.size(); ++i) {
    359     if (configured_locales_display_names[i].size() == 0)
    360       continue;
    361     out_display_names.push_back(configured_locales_display_names[i]);
    362   }
    363 
    364   base::string16 divider16;
    365   if (insert_divider) {
    366     divider16 = base::ASCIIToUTF16(
    367         insert_divider ? "" : kVendorOtherLanguagesListDivider);
    368     out_display_names.push_back(divider16);
    369   }
    370 
    371   std::copy(display_names.begin(),
    372             display_names.end(),
    373             std::back_inserter(out_display_names));
    374 
    375   // Build the language list from the language map.
    376   base::ListValue* language_list = new base::ListValue();
    377   for (size_t i = 0; i < out_display_names.size(); ++i) {
    378     // Sets the directionality of the display language name.
    379     base::string16 display_name(out_display_names[i]);
    380     if (insert_divider && display_name == divider16) {
    381       // Insert divider.
    382       base::DictionaryValue* dictionary = new base::DictionaryValue();
    383       dictionary->SetString("code", kVendorOtherLanguagesListDivider);
    384       language_list->Append(dictionary);
    385       continue;
    386     }
    387     bool markup_removal =
    388         base::i18n::UnadjustStringForLocaleDirection(&display_name);
    389     DCHECK(markup_removal);
    390     bool has_rtl_chars = base::i18n::StringContainsStrongRTLChars(display_name);
    391     std::string directionality = has_rtl_chars ? "rtl" : "ltr";
    392 
    393     const LanguagePair& pair = language_map[out_display_names[i]];
    394     base::DictionaryValue* dictionary = new base::DictionaryValue();
    395     dictionary->SetString("code", pair.first);
    396     dictionary->SetString("displayName", out_display_names[i]);
    397     dictionary->SetString("textDirection", directionality);
    398     dictionary->SetString("nativeDisplayName", pair.second);
    399     language_list->Append(dictionary);
    400   }
    401 
    402   return language_list;
    403 }
    404 
    405 // static
    406 base::ListValue* CrosLanguageOptionsHandler::GetAcceptLanguageList(
    407     const input_method::InputMethodDescriptors& descriptors) {
    408   // Collect the language codes from the supported accept-languages.
    409   const std::string app_locale = g_browser_process->GetApplicationLocale();
    410   std::vector<std::string> accept_language_codes;
    411   l10n_util::GetAcceptLanguagesForLocale(app_locale, &accept_language_codes);
    412   return GetLanguageListInternal(descriptors, accept_language_codes, false);
    413 }
    414 
    415 // static
    416 base::ListValue* CrosLanguageOptionsHandler::GetUILanguageList(
    417     const input_method::InputMethodDescriptors& descriptors) {
    418   // Collect the language codes from the available locales.
    419   return GetLanguageListInternal(
    420       descriptors, l10n_util::GetAvailableLocales(), true);
    421 }
    422 
    423 base::ListValue*
    424     CrosLanguageOptionsHandler::ConvertInputMethodDescriptorsToIMEList(
    425         const input_method::InputMethodDescriptors& descriptors) {
    426   scoped_ptr<base::ListValue> ime_ids_list(new base::ListValue());
    427   for (size_t i = 0; i < descriptors.size(); ++i) {
    428     const input_method::InputMethodDescriptor& descriptor = descriptors[i];
    429     scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
    430     dictionary->SetString("id", descriptor.id());
    431     dictionary->SetString("displayName", descriptor.name());
    432     dictionary->SetString("optionsPage", descriptor.options_page_url().spec());
    433     scoped_ptr<base::DictionaryValue> language_codes(
    434         new base::DictionaryValue());
    435     for (size_t i = 0; i < descriptor.language_codes().size(); ++i)
    436       language_codes->SetBoolean(descriptor.language_codes().at(i), true);
    437     dictionary->Set("languageCodeSet", language_codes.release());
    438     ime_ids_list->Append(dictionary.release());
    439   }
    440   return ime_ids_list.release();
    441 }
    442 
    443 base::string16 CrosLanguageOptionsHandler::GetProductName() {
    444   return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
    445 }
    446 
    447 void CrosLanguageOptionsHandler::SetApplicationLocale(
    448     const std::string& language_code) {
    449   Profile* profile = Profile::FromWebUI(web_ui());
    450   UserManager* user_manager = UserManager::Get();
    451 
    452   // Only the primary user can change the locale.
    453   User* user = user_manager->GetUserByProfile(profile);
    454   if (user && user->email() == user_manager->GetPrimaryUser()->email()) {
    455     profile->ChangeAppLocale(language_code,
    456                              Profile::APP_LOCALE_CHANGED_VIA_SETTINGS);
    457   }
    458 }
    459 
    460 void CrosLanguageOptionsHandler::RestartCallback(const base::ListValue* args) {
    461   content::RecordAction(UserMetricsAction("LanguageOptions_SignOut"));
    462   chrome::AttemptUserExit();
    463 }
    464 
    465 void CrosLanguageOptionsHandler::InputMethodDisableCallback(
    466     const base::ListValue* args) {
    467   const std::string input_method_id =
    468       base::UTF16ToASCII(ExtractStringValue(args));
    469   const std::string action = base::StringPrintf(
    470       "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str());
    471   content::RecordComputedAction(action);
    472 }
    473 
    474 void CrosLanguageOptionsHandler::InputMethodEnableCallback(
    475     const base::ListValue* args) {
    476   const std::string input_method_id =
    477       base::UTF16ToASCII(ExtractStringValue(args));
    478   const std::string action = base::StringPrintf(
    479       "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str());
    480   content::RecordComputedAction(action);
    481 }
    482 
    483 void CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback(
    484     const base::ListValue* args) {
    485   const std::string input_method_id =
    486       base::UTF16ToASCII(ExtractStringValue(args));
    487   const std::string extension_id =
    488       extension_ime_util::GetExtensionIDFromInputMethodID(input_method_id);
    489   if (extension_id.empty())
    490     return;
    491 
    492   const input_method::InputMethodDescriptor* ime =
    493       input_method::InputMethodManager::Get()->GetInputMethodFromId(
    494           input_method_id);
    495   if (!ime)
    496     return;
    497 
    498   Browser* browser = chrome::FindBrowserWithWebContents(
    499       web_ui()->GetWebContents());
    500   content::OpenURLParams params(ime->options_page_url(),
    501       content::Referrer(),
    502       SINGLETON_TAB,
    503       content::PAGE_TRANSITION_LINK,
    504       false);
    505   browser->OpenURL(params);
    506   browser->window()->Show();
    507   content::WebContents* web_contents =
    508       browser->tab_strip_model()->GetActiveWebContents();
    509   web_contents->GetDelegate()->ActivateContents(web_contents);
    510 }
    511 
    512 void CrosLanguageOptionsHandler::OnImeComponentExtensionInitialized() {
    513   if (composition_extension_appended_ || !is_page_initialized_) {
    514     // If an option page is not ready to call JavaScript, appending component
    515     // extension IMEs will be done in InitializePage function later.
    516     return;
    517   }
    518 
    519   ComponentExtensionIMEManager* manager =
    520       input_method::InputMethodManager::Get()
    521           ->GetComponentExtensionIMEManager();
    522 
    523   DCHECK(manager->IsInitialized());
    524   scoped_ptr<base::ListValue> ime_list(
    525       ConvertInputMethodDescriptorsToIMEList(
    526           manager->GetAllIMEAsInputMethodDescriptor()));
    527   web_ui()->CallJavascriptFunction(
    528       "options.LanguageOptions.onComponentManagerInitialized",
    529       *ime_list);
    530   composition_extension_appended_ = true;
    531 }
    532 
    533 void CrosLanguageOptionsHandler::InitializePage() {
    534   is_page_initialized_ = true;
    535   if (composition_extension_appended_)
    536     return;
    537 
    538   ComponentExtensionIMEManager* component_extension_manager =
    539       input_method::InputMethodManager::Get()
    540           ->GetComponentExtensionIMEManager();
    541   if (!component_extension_manager->IsInitialized()) {
    542     // If the component extension IME manager is not available yet, append the
    543     // component extension list in |OnInitialized()|.
    544     return;
    545   }
    546 
    547   scoped_ptr<base::ListValue> ime_list(
    548       ConvertInputMethodDescriptorsToIMEList(
    549           component_extension_manager->GetAllIMEAsInputMethodDescriptor()));
    550   web_ui()->CallJavascriptFunction(
    551       "options.LanguageOptions.onComponentManagerInitialized",
    552       *ime_list);
    553   composition_extension_appended_ = true;
    554 }
    555 
    556 void CrosLanguageOptionsHandler::AddImeProvider(base::ListValue* list) {
    557   Profile* profile = Profile::FromWebUI(web_ui());
    558   ExtensionService* extension_service = profile->GetExtensionService();
    559   for (size_t i = 0; i < list->GetSize(); i++) {
    560     base::DictionaryValue* entry;
    561     list->GetDictionary(i, &entry);
    562 
    563     std::string input_method_id;
    564     entry->GetString("id", &input_method_id);
    565 
    566     std::string extension_id =
    567         extension_ime_util::GetExtensionIDFromInputMethodID(input_method_id);
    568     const extensions::Extension* extension =
    569         extension_service->GetExtensionById(extension_id, false);
    570     if (extension)
    571       entry->SetString("extensionName", extension->name());
    572   }
    573 }
    574 
    575 }  // namespace options
    576 }  // namespace chromeos
    577