Chromium Code Reviews| Index: chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc |
| diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc |
| index 1c422cb4d055172012bd196d673452fddfa027ab..781ad8f35a28e90654a4f4101e2aff92a98e07e8 100644 |
| --- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc |
| +++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc |
| @@ -4,16 +4,19 @@ |
| #include "chrome/browser/extensions/api/language_settings_private/language_settings_private_api.h" |
| +#include <algorithm> |
| #include <map> |
| #include <memory> |
| #include <string> |
| +#include <unordered_set> |
| #include <utility> |
| #include <vector> |
| -#include "base/containers/hash_tables.h" |
| #include "base/i18n/rtl.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/strings/string16.h" |
| +#include "base/strings/string_split.h" |
| +#include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| @@ -26,6 +29,7 @@ |
| #include "chrome/browser/translate/chrome_translate_client.h" |
| #include "chrome/browser/translate/translate_service.h" |
| #include "chrome/common/extensions/api/language_settings_private.h" |
| +#include "chrome/common/pref_names.h" |
| #include "chrome/common/spellcheck_common.h" |
| #include "components/translate/core/browser/translate_download_manager.h" |
| #include "third_party/icu/source/i18n/unicode/coll.h" |
| @@ -44,9 +48,115 @@ namespace extensions { |
| namespace language_settings_private = api::language_settings_private; |
| #if defined(OS_CHROMEOS) |
| +using chromeos::input_method::InputMethodDescriptor; |
| using chromeos::input_method::InputMethodDescriptors; |
| using chromeos::input_method::InputMethodManager; |
| using chromeos::input_method::InputMethodUtil; |
| + |
| +namespace { |
| + |
| +// Returns the set of IDs of enabled component extension IMEs. |
| +std::unordered_set<std::string> GetEnabledComponentIMEs( |
| + scoped_refptr<InputMethodManager::State> ime_state) { |
| + const std::vector<std::string>& component_imes( |
| + ime_state->GetActiveInputMethodIds()); |
|
Shu Chen
2016/04/20 06:38:33
GetActiveInputMethodIds() can include 3rd-party ex
michaelpg
2016/04/20 08:09:08
Oops. I didn't notice because GetSortedComponentIM
|
| + return std::unordered_set<std::string>(component_imes.begin(), |
| + component_imes.end()); |
| +} |
| + |
| +// Returns the set of IDs of enabled third-party extension IMEs. |
| +std::unordered_set<std::string> GetEnabledExtensionIMEs( |
| + InputMethodManager* manager, |
| + scoped_refptr<InputMethodManager::State> ime_state, |
| + PrefService* prefs) { |
| + std::vector<std::string> enabled_extension_imes = |
| + base::SplitString(prefs->GetString(prefs::kLanguageEnabledExtensionImes), |
| + ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| + return std::unordered_set<std::string>(enabled_extension_imes.begin(), |
| + enabled_extension_imes.end()); |
| +} |
| + |
| +// Sorts the input methods by the order of their associated languages. For |
| +// example, if the enabled language order is: |
| +// - French |
| +// - English |
| +// then the French keyboard should come before the English keyboard. |
| +std::vector<std::string> GetSortedComponentIMEs( |
| + InputMethodManager* manager, |
| + scoped_refptr<InputMethodManager::State> ime_state, |
| + const std::unordered_set<std::string>& component_ime_set, |
| + PrefService* prefs) { |
| + std::vector<std::string> enabled_languages = |
| + base::SplitString(prefs->GetString(prefs::kLanguagePreferredLanguages), |
| + ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| + |
| + // Duplicate set for membership testing. |
| + std::unordered_set<std::string> available_component_imes(component_ime_set); |
| + std::vector<std::string> component_ime_list; |
| + |
| + for (const auto& language_code : enabled_languages) { |
| + // Get all input methods for this language. |
| + std::vector<std::string> input_method_ids; |
| + manager->GetInputMethodUtil()->GetInputMethodIdsFromLanguageCode( |
| + language_code, chromeos::input_method::kAllInputMethods, |
| + &input_method_ids); |
| + // Append the enabled ones to the new list. Also remove them from the set |
| + // so they aren't duplicated for other languages. |
| + for (const auto& input_method_id : input_method_ids) { |
| + if (available_component_imes.count(input_method_id)) { |
| + component_ime_list.push_back(input_method_id); |
| + available_component_imes.erase(input_method_id); |
| + } |
| + } |
| + } |
| + |
| + return component_ime_list; |
| +} |
| + |
| +// Sorts the third-party IMEs by the order of their associated languages. |
| +std::vector<std::string> GetSortedExtensionIMEs( |
| + scoped_refptr<InputMethodManager::State> ime_state, |
| + const std::unordered_set<std::string>& extension_ime_set, |
| + PrefService* prefs) { |
| + std::vector<std::string> extension_ime_list; |
| + std::string preferred_languages = |
| + prefs->GetString(prefs::kLanguagePreferredLanguages); |
| + std::vector<std::string> enabled_languages = |
| + base::SplitString(preferred_languages, ",", base::TRIM_WHITESPACE, |
| + base::SPLIT_WANT_NONEMPTY); |
| + |
| + InputMethodDescriptors descriptors; |
| + ime_state->GetInputMethodExtensions(&descriptors); |
| + |
| + // Filter out the IMEs not in |extension_ime_set|. |
| + auto it = descriptors.begin(); |
| + while (it != descriptors.end()) { |
| + if (extension_ime_set.count(it->id()) == 0) |
| + it = descriptors.erase(it); |
| + else |
| + it++; |
| + } |
| + |
| + // For each language, add any candidate IMEs that support it. |
| + for (const auto& language : enabled_languages) { |
| + auto it = descriptors.begin(); |
| + while (it != descriptors.end() && descriptors.size()) { |
| + if (extension_ime_set.count(it->id()) && |
| + std::find(it->language_codes().begin(), it->language_codes().end(), |
| + language) != it->language_codes().end()) { |
| + extension_ime_list.push_back(it->id()); |
| + // Remove the added descriptor from the candidate list. |
| + it = descriptors.erase(it); |
| + } else { |
| + it++; |
| + } |
| + } |
| + } |
| + |
| + return extension_ime_list; |
| +} |
| + |
| +} // anonymous namespace |
| #endif |
| LanguageSettingsPrivateGetLanguageListFunction:: |
| @@ -89,20 +199,20 @@ LanguageSettingsPrivateGetLanguageListFunction::Run() { |
| // Get the list of available locales (display languages) and convert to a set. |
| const std::vector<std::string>& locales = l10n_util::GetAvailableLocales(); |
| - const base::hash_set<std::string> locale_set( |
| - locales.begin(), locales.end()); |
| + const std::unordered_set<std::string> locale_set(locales.begin(), |
| + locales.end()); |
| // Get the list of spell check languages and convert to a set. |
| std::vector<std::string> spellcheck_languages; |
| chrome::spellcheck_common::SpellCheckLanguages(&spellcheck_languages); |
| - const base::hash_set<std::string> spellcheck_language_set( |
| + const std::unordered_set<std::string> spellcheck_language_set( |
| spellcheck_languages.begin(), spellcheck_languages.end()); |
| // Get the list of translatable languages and convert to a set. |
| std::vector<std::string> translate_languages; |
| translate::TranslateDownloadManager::GetSupportedLanguages( |
| &translate_languages); |
| - const base::hash_set<std::string> translate_language_set( |
| + const std::unordered_set<std::string> translate_language_set( |
| translate_languages.begin(), translate_languages.end()); |
| // Build the language list from the language map. |
| @@ -307,18 +417,14 @@ void PopulateInputMethodListFromDescriptors( |
| if (!ime_state.get()) |
| return; |
| - // Get the list of enabled IDs and convert to a set for membership testing. |
| - const std::vector<std::string>& active_ids_list = |
| - ime_state->GetActiveInputMethodIds(); |
| - const std::set<std::string> active_ids( |
| - active_ids_list.begin(), active_ids_list.end()); |
| - |
| + const std::unordered_set<std::string> active_ids( |
| + GetEnabledComponentIMEs(ime_state)); |
| for (const auto& descriptor : descriptors) { |
| language_settings_private::InputMethod input_method; |
| input_method.id = descriptor.id(); |
| input_method.display_name = util->GetLocalizedDisplayName(descriptor); |
| input_method.language_codes = descriptor.language_codes(); |
| - bool enabled = active_ids.find(input_method.id) != active_ids.end(); |
| + bool enabled = active_ids.count(input_method.id) > 0; |
| if (enabled) |
| input_method.enabled.reset(new bool(true)); |
| if (descriptor.options_page_url().is_valid()) |
| @@ -366,8 +472,8 @@ LanguageSettingsPrivateGetInputMethodListsFunction::Run() { |
| } |
| LanguageSettingsPrivateAddInputMethodFunction:: |
| - LanguageSettingsPrivateAddInputMethodFunction() { |
| -} |
| + LanguageSettingsPrivateAddInputMethodFunction() |
| + : chrome_details_(this) {} |
| LanguageSettingsPrivateAddInputMethodFunction:: |
| ~LanguageSettingsPrivateAddInputMethodFunction() { |
| @@ -375,12 +481,54 @@ LanguageSettingsPrivateAddInputMethodFunction:: |
| ExtensionFunction::ResponseAction |
| LanguageSettingsPrivateAddInputMethodFunction::Run() { |
| - return RespondNow(OneArgument(new base::FundamentalValue(true))); |
| +#if !defined(OS_CHROMEOS) |
| + EXTENSION_FUNCTION_VALIDATE(false); |
| +#else |
| + std::unique_ptr<language_settings_private::AddInputMethod::Params> params = |
| + language_settings_private::AddInputMethod::Params::Create(*args_); |
| + EXTENSION_FUNCTION_VALIDATE(params.get()); |
| + |
| + InputMethodManager* manager = InputMethodManager::Get(); |
| + scoped_refptr<InputMethodManager::State> ime_state = |
| + manager->GetActiveIMEState(); |
| + if (!ime_state.get()) |
| + return RespondNow(NoArguments()); |
| + |
| + std::string new_input_method_id = params->input_method_id; |
| + bool is_extension_ime = |
| + chromeos::extension_ime_util::IsExtensionIME(new_input_method_id); |
| + |
| + PrefService* prefs = chrome_details_.GetProfile()->GetPrefs(); |
| + |
| + // Get the input methods we are adding to. |
| + std::unordered_set<std::string> input_method_set( |
| + is_extension_ime ? GetEnabledExtensionIMEs(manager, ime_state, prefs) |
| + : GetEnabledComponentIMEs(ime_state)); |
| + |
| + // Add the new input method. |
| + input_method_set.insert(new_input_method_id); |
| + |
| + // Sort the new input method list by preferred languages. |
| + std::vector<std::string> input_method_list; |
| + if (is_extension_ime) { |
| + input_method_list = |
| + GetSortedExtensionIMEs(ime_state, input_method_set, prefs); |
| + } else { |
| + input_method_list = |
| + GetSortedComponentIMEs(manager, ime_state, input_method_set, prefs); |
| + } |
| + |
| + std::string input_methods = base::JoinString(input_method_list, ","); |
| + prefs->SetString(is_extension_ime ? prefs::kLanguageEnabledExtensionImes |
| + : prefs::kLanguagePreloadEngines, |
| + input_methods); |
| +#endif |
| + return RespondNow(NoArguments()); |
| } |
| LanguageSettingsPrivateRemoveInputMethodFunction:: |
| - LanguageSettingsPrivateRemoveInputMethodFunction() { |
| -} |
| + LanguageSettingsPrivateRemoveInputMethodFunction() |
| + : chrome_details_(this) {} |
| LanguageSettingsPrivateRemoveInputMethodFunction:: |
| ~LanguageSettingsPrivateRemoveInputMethodFunction() { |
| @@ -388,7 +536,41 @@ LanguageSettingsPrivateRemoveInputMethodFunction:: |
| ExtensionFunction::ResponseAction |
| LanguageSettingsPrivateRemoveInputMethodFunction::Run() { |
| - return RespondNow(OneArgument(new base::FundamentalValue(true))); |
| +#if !defined(OS_CHROMEOS) |
| + EXTENSION_FUNCTION_VALIDATE(false); |
| +#else |
| + std::unique_ptr<language_settings_private::RemoveInputMethod::Params> params = |
| + language_settings_private::RemoveInputMethod::Params::Create(*args_); |
| + EXTENSION_FUNCTION_VALIDATE(params.get()); |
| + |
| + InputMethodManager* manager = InputMethodManager::Get(); |
| + scoped_refptr<InputMethodManager::State> ime_state = |
| + manager->GetActiveIMEState(); |
| + if (!ime_state.get()) |
| + return RespondNow(NoArguments()); |
| + |
| + std::string input_method_id = params->input_method_id; |
| + |
| + // Use the pref for the corresponding input method type. |
| + PrefService* prefs = chrome_details_.GetProfile()->GetPrefs(); |
| + const char* pref_name = |
| + chromeos::extension_ime_util::IsExtensionIME(input_method_id) |
| + ? prefs::kLanguageEnabledExtensionImes |
| + : pref_name = prefs::kLanguagePreloadEngines; |
| + |
| + std::string input_method_ids = prefs->GetString(pref_name); |
| + std::vector<std::string> input_method_list = base::SplitString( |
| + input_method_ids, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| + |
| + // Find and remove the matching input method id. |
| + const auto& pos = std::find(input_method_list.begin(), |
| + input_method_list.end(), input_method_id); |
| + if (pos != input_method_list.end()) { |
| + input_method_list.erase(pos); |
| + prefs->SetString(pref_name, base::JoinString(input_method_list, ",")); |
| + } |
| +#endif |
| + return RespondNow(NoArguments()); |
| } |
| } // namespace extensions |