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 "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/strings/stringprintf.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "chrome/app/chrome_command_ids.h"
13#include "chrome/browser/chromeos/input_method/input_method_util.h"
14#include "chrome/browser/chromeos/profiles/profile_helper.h"
15#include "chrome/browser/extensions/extension_tab_util.h"
16#include "chrome/browser/lifetime/application_lifetime.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/browser_finder.h"
20#include "chrome/browser/ui/browser_window.h"
21#include "chrome/browser/ui/tabs/tab_strip_model.h"
22#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
23#include "chrome/common/extensions/manifest_url_handler.h"
24#include "chrome/grit/chromium_strings.h"
25#include "chrome/grit/generated_resources.h"
26#include "chromeos/ime/component_extension_ime_manager.h"
27#include "chromeos/ime/extension_ime_util.h"
28#include "chromeos/ime/input_method_manager.h"
29#include "components/user_manager/user_manager.h"
30#include "components/user_manager/user_type.h"
31#include "content/public/browser/navigation_controller.h"
32#include "content/public/browser/user_metrics.h"
33#include "content/public/browser/web_contents.h"
34#include "extensions/browser/extension_registry.h"
35#include "extensions/common/extension.h"
36#include "ui/base/l10n/l10n_util.h"
37
38using base::UserMetricsAction;
39
40namespace chromeos {
41namespace options {
42
43CrosLanguageOptionsHandler::CrosLanguageOptionsHandler() {
44}
45
46CrosLanguageOptionsHandler::~CrosLanguageOptionsHandler() {
47}
48
49void CrosLanguageOptionsHandler::GetLocalizedValues(
50    base::DictionaryValue* localized_strings) {
51  ::options::LanguageOptionsHandlerCommon::GetLocalizedValues(
52      localized_strings);
53
54  RegisterTitle(localized_strings, "languagePage",
55                IDS_OPTIONS_SETTINGS_LANGUAGES_AND_INPUT_DIALOG_TITLE);
56  localized_strings->SetString("okButton", l10n_util::GetStringUTF16(IDS_OK));
57  localized_strings->SetString("configure",
58      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
59  localized_strings->SetString("inputMethod",
60      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
61  localized_strings->SetString("pleaseAddAnotherInputMethod",
62      l10n_util::GetStringUTF16(
63          IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD));
64  localized_strings->SetString("inputMethodInstructions",
65      l10n_util::GetStringUTF16(
66          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS));
67  localized_strings->SetString("switchInputMethodsHint",
68      l10n_util::GetStringUTF16(
69          IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT));
70  localized_strings->SetString("selectPreviousInputMethodHint",
71      l10n_util::GetStringUTF16(
72          IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT));
73  localized_strings->SetString("restartButton",
74      l10n_util::GetStringUTF16(
75          IDS_OPTIONS_SETTINGS_LANGUAGES_SIGN_OUT_BUTTON));
76  localized_strings->SetString("extensionImeLable",
77      l10n_util::GetStringUTF16(
78          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_IME));
79  localized_strings->SetString("extensionImeDescription",
80      l10n_util::GetStringUTF16(
81          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_EXTENSION_DESCRIPTION));
82  localized_strings->SetString("noInputMethods",
83      l10n_util::GetStringUTF16(
84          IDS_OPTIONS_SETTINGS_LANGUAGES_NO_INPUT_METHODS));
85
86  // GetSupportedInputMethods() never returns NULL.
87  localized_strings->Set("languageList", GetAcceptLanguageList().release());
88  localized_strings->Set("inputMethodList", GetInputMethodList());
89
90  input_method::InputMethodManager* manager =
91      input_method::InputMethodManager::Get();
92  input_method::InputMethodDescriptors ext_ime_descriptors;
93  manager->GetActiveIMEState()->GetInputMethodExtensions(&ext_ime_descriptors);
94
95  base::ListValue* ext_ime_list = ConvertInputMethodDescriptorsToIMEList(
96      ext_ime_descriptors);
97  AddImeProvider(ext_ime_list);
98  localized_strings->Set("extensionImeList", ext_ime_list);
99
100  ComponentExtensionIMEManager* component_extension_manager =
101      input_method::InputMethodManager::Get()
102          ->GetComponentExtensionIMEManager();
103  localized_strings->Set(
104      "componentExtensionImeList",
105      ConvertInputMethodDescriptorsToIMEList(
106          component_extension_manager->GetAllIMEAsInputMethodDescriptor()));
107}
108
109void CrosLanguageOptionsHandler::RegisterMessages() {
110  ::options::LanguageOptionsHandlerCommon::RegisterMessages();
111
112  web_ui()->RegisterMessageCallback("inputMethodDisable",
113      base::Bind(&CrosLanguageOptionsHandler::InputMethodDisableCallback,
114                 base::Unretained(this)));
115  web_ui()->RegisterMessageCallback("inputMethodEnable",
116      base::Bind(&CrosLanguageOptionsHandler::InputMethodEnableCallback,
117                 base::Unretained(this)));
118  web_ui()->RegisterMessageCallback("inputMethodOptionsOpen",
119      base::Bind(&CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback,
120                 base::Unretained(this)));
121  web_ui()->RegisterMessageCallback("uiLanguageRestart",
122      base::Bind(&CrosLanguageOptionsHandler::RestartCallback,
123                 base::Unretained(this)));
124}
125
126// static
127base::ListValue* CrosLanguageOptionsHandler::GetInputMethodList() {
128  input_method::InputMethodManager* manager =
129      input_method::InputMethodManager::Get();
130  // GetSupportedInputMethods() never return NULL.
131  scoped_ptr<input_method::InputMethodDescriptors> descriptors(
132      manager->GetSupportedInputMethods());
133
134  base::ListValue* input_method_list = new base::ListValue();
135
136  for (size_t i = 0; i < descriptors->size(); ++i) {
137    const input_method::InputMethodDescriptor& descriptor =
138        (*descriptors)[i];
139    const std::string display_name =
140        manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId(
141            descriptor.id());
142    base::DictionaryValue* dictionary = new base::DictionaryValue();
143    dictionary->SetString("id", descriptor.id());
144    dictionary->SetString("displayName", display_name);
145
146    // One input method can be associated with multiple languages, hence
147    // we use a dictionary here.
148    base::DictionaryValue* languages = new base::DictionaryValue();
149    for (size_t i = 0; i < descriptor.language_codes().size(); ++i) {
150      languages->SetBoolean(descriptor.language_codes().at(i), true);
151    }
152    dictionary->Set("languageCodeSet", languages);
153
154    input_method_list->Append(dictionary);
155  }
156
157  return input_method_list;
158}
159
160base::ListValue*
161    CrosLanguageOptionsHandler::ConvertInputMethodDescriptorsToIMEList(
162        const input_method::InputMethodDescriptors& descriptors) {
163  scoped_ptr<base::ListValue> ime_ids_list(new base::ListValue());
164  for (size_t i = 0; i < descriptors.size(); ++i) {
165    const input_method::InputMethodDescriptor& descriptor = descriptors[i];
166    scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
167    dictionary->SetString("id", descriptor.id());
168    dictionary->SetString("displayName", descriptor.name());
169    dictionary->SetString("optionsPage", descriptor.options_page_url().spec());
170    scoped_ptr<base::DictionaryValue> language_codes(
171        new base::DictionaryValue());
172    for (size_t i = 0; i < descriptor.language_codes().size(); ++i)
173      language_codes->SetBoolean(descriptor.language_codes().at(i), true);
174    dictionary->Set("languageCodeSet", language_codes.release());
175    ime_ids_list->Append(dictionary.release());
176  }
177  return ime_ids_list.release();
178}
179
180base::string16 CrosLanguageOptionsHandler::GetProductName() {
181  return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
182}
183
184void CrosLanguageOptionsHandler::SetApplicationLocale(
185    const std::string& language_code) {
186  Profile* profile = Profile::FromWebUI(web_ui());
187  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
188
189  // Secondary users and public session users cannot change the locale.
190  user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
191  if (user &&
192      user->email() == user_manager->GetPrimaryUser()->email() &&
193      user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
194    profile->ChangeAppLocale(language_code,
195                             Profile::APP_LOCALE_CHANGED_VIA_SETTINGS);
196  }
197}
198
199void CrosLanguageOptionsHandler::RestartCallback(const base::ListValue* args) {
200  content::RecordAction(UserMetricsAction("LanguageOptions_SignOut"));
201  chrome::AttemptUserExit();
202}
203
204void CrosLanguageOptionsHandler::InputMethodDisableCallback(
205    const base::ListValue* args) {
206  const std::string input_method_id =
207      base::UTF16ToASCII(ExtractStringValue(args));
208  const std::string action = base::StringPrintf(
209      "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str());
210  content::RecordComputedAction(action);
211}
212
213void CrosLanguageOptionsHandler::InputMethodEnableCallback(
214    const base::ListValue* args) {
215  const std::string input_method_id =
216      base::UTF16ToASCII(ExtractStringValue(args));
217  const std::string action = base::StringPrintf(
218      "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str());
219  content::RecordComputedAction(action);
220}
221
222void CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback(
223    const base::ListValue* args) {
224  const std::string input_method_id =
225      base::UTF16ToASCII(ExtractStringValue(args));
226  const std::string extension_id =
227      extension_ime_util::GetExtensionIDFromInputMethodID(input_method_id);
228  if (extension_id.empty())
229    return;
230
231  const input_method::InputMethodDescriptor* ime =
232      input_method::InputMethodManager::Get()
233          ->GetActiveIMEState()
234          ->GetInputMethodFromId(input_method_id);
235  if (!ime)
236    return;
237
238  Browser* browser = chrome::FindBrowserWithWebContents(
239      web_ui()->GetWebContents());
240  content::OpenURLParams params(ime->options_page_url(),
241      content::Referrer(),
242      SINGLETON_TAB,
243      ui::PAGE_TRANSITION_LINK,
244      false);
245  browser->OpenURL(params);
246}
247
248void CrosLanguageOptionsHandler::AddImeProvider(base::ListValue* list) {
249  Profile* profile = Profile::FromWebUI(web_ui());
250  const extensions::ExtensionSet& enabled_extensions =
251      extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
252  for (size_t i = 0; i < list->GetSize(); ++i) {
253    base::DictionaryValue* entry;
254    list->GetDictionary(i, &entry);
255
256    std::string input_method_id;
257    entry->GetString("id", &input_method_id);
258
259    std::string extension_id =
260        extension_ime_util::GetExtensionIDFromInputMethodID(input_method_id);
261    const extensions::Extension* extension =
262        enabled_extensions.GetByID(extension_id);
263    if (extension)
264      entry->SetString("extensionName", extension->name());
265  }
266}
267
268}  // namespace options
269}  // namespace chromeos
270