Commit 2ddc71f2 authored by Darren Shen's avatar Darren Shen Committed by Commit Bot

[VK] Add input method APIs for getting / setting input method settings.

In ChromeOS, each input method has its own settings, which are currently
stored in the extension local storage. This is not good for several
reasons, so we want to move it to the ChromeOS prefs service:

- Putting it in prefs allows us to eventually sync these settings
  across machines.

- When we eventually deprecate the VK extension, there will be no
  more local storage.

- With the work in 895886, Chrome OS need to access these settings anyway.
  It is much easier for the extension to query Chrome OS than the
  other way around, due to how extension APIs work.

We add a new prefs entry for all the input method settings. Each input
method has a dictionary of key/value pairs to use. For the input method
to get/set these settings, we add private APIs in
chrome.inputMethodPrivate to get/set these values.

Bug: 895886
Change-Id: If1366ead35a8274eadae97c7e4cc37a95526d777
Reviewed-on: https://chromium-review.googlesource.com/c/1343471
Commit-Queue: Darren Shen <shend@chromium.org>
Reviewed-by: default avatarBen Wells <benwells@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarShu Chen <shuchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611903}
parent c25c01ff
......@@ -33,6 +33,7 @@
#include "chromeos/chromeos_switches.h"
#include "components/browser_sync/profile_sync_service.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_system.h"
#include "ui/base/ime/chromeos/extension_ime_util.h"
......@@ -62,6 +63,8 @@ namespace OnImeMenuItemsChanged =
extensions::api::input_method_private::OnImeMenuItemsChanged;
namespace GetSurroundingText =
extensions::api::input_method_private::GetSurroundingText;
namespace GetSetting = extensions::api::input_method_private::GetSetting;
namespace SetSetting = extensions::api::input_method_private::SetSetting;
namespace {
......@@ -345,6 +348,40 @@ InputMethodPrivateGetSurroundingTextFunction::Run() {
#endif
}
ExtensionFunction::ResponseAction InputMethodPrivateGetSettingFunction::Run() {
#if !defined(OS_CHROMEOS)
EXTENSION_FUNCTION_VALIDATE(false);
#else
const auto params = GetSetting::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params.get());
const base::DictionaryValue* inputMethods =
Profile::FromBrowserContext(browser_context())
->GetPrefs()
->GetDictionary(prefs::kLanguageInputMethodSpecificSettings);
const base::Value* result =
inputMethods->FindPath({params->engine_id, params->key});
return RespondNow(
OneArgument(result ? std::make_unique<base::Value>(result->Clone())
: std::make_unique<base::Value>()));
#endif
}
ExtensionFunction::ResponseAction InputMethodPrivateSetSettingFunction::Run() {
#if !defined(OS_CHROMEOS)
EXTENSION_FUNCTION_VALIDATE(false);
#else
const auto params = SetSetting::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params.get());
DictionaryPrefUpdate update(
Profile::FromBrowserContext(browser_context())->GetPrefs(),
prefs::kLanguageInputMethodSpecificSettings);
update->SetPath({params->engine_id, params->key}, params->value->Clone());
return RespondNow(NoArguments());
#endif
}
InputMethodAPI::InputMethodAPI(content::BrowserContext* context)
: context_(context) {
EventRouter::Get(context_)->RegisterObserver(this, OnChanged::kEventName);
......
......@@ -210,6 +210,38 @@ class InputMethodPrivateGetSurroundingTextFunction
DISALLOW_COPY_AND_ASSIGN(InputMethodPrivateGetSurroundingTextFunction);
};
class InputMethodPrivateGetSettingFunction : public UIThreadExtensionFunction {
public:
InputMethodPrivateGetSettingFunction() = default;
protected:
~InputMethodPrivateGetSettingFunction() override = default;
// ExtensionFunction:
ResponseAction Run() override;
private:
DECLARE_EXTENSION_FUNCTION("inputMethodPrivate.getSetting",
INPUTMETHODPRIVATE_GETSETTING)
DISALLOW_COPY_AND_ASSIGN(InputMethodPrivateGetSettingFunction);
};
class InputMethodPrivateSetSettingFunction : public UIThreadExtensionFunction {
public:
InputMethodPrivateSetSettingFunction() = default;
protected:
~InputMethodPrivateSetSettingFunction() override = default;
// ExtensionFunction:
ResponseAction Run() override;
private:
DECLARE_EXTENSION_FUNCTION("inputMethodPrivate.setSetting",
INPUTMETHODPRIVATE_SETSETTING)
DISALLOW_COPY_AND_ASSIGN(InputMethodPrivateSetSettingFunction);
};
class InputMethodAPI : public BrowserContextKeyedAPI,
public extensions::EventRouter::Observer {
public:
......
......@@ -162,3 +162,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionInputMethodApiTest, ImeMenuAPITest) {
engine_handler->Enable("test2");
ASSERT_TRUE(list_listenter.WaitUntilSatisfied()) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionInputMethodApiTest, Settings) {
ASSERT_TRUE(RunExtensionTest("input_method/settings")) << message_;
}
......@@ -345,6 +345,7 @@ void Preferences::RegisterProfilePrefs(
registry->RegisterStringPref(prefs::kLanguagePreloadEngines,
hardware_keyboard_id);
registry->RegisterStringPref(prefs::kLanguageEnabledImes, "");
registry->RegisterDictionaryPref(prefs::kLanguageInputMethodSpecificSettings);
registry->RegisterIntegerPref(
prefs::kLanguageRemapSearchKeyTo,
......
......@@ -336,6 +336,62 @@
]
}
]
}, {
"name": "getSetting",
"type": "function",
"description": "Gets the current value of a setting for a particular input method",
"parameters": [
{
"name": "engineID",
"type": "string",
"description": "The ID of the engine (e.g. 'zh-t-i0-pinyin', 'xkb:us::eng')"
},
{
"name": "key",
"type": "string",
"description": "The setting to get"
},
{
"type": "function",
"name": "callback",
"description": "Callback to receive the setting",
"parameters": [
{
"name": "setting",
"type": "any",
"optional": true,
"description": "The value for the requested setting, or null if there's no value"
}
]
}
]
}, {
"name": "setSetting",
"type": "function",
"description": "Sets the value of a setting for a particular input method",
"parameters": [
{
"name": "engineID",
"type": "string",
"description": "The ID of the engine (e.g. 'zh-t-i0-pinyin', 'xkb:us::eng')"
},
{
"name": "key",
"type": "string",
"description": "The setting to set"
},
{
"name": "value",
"type": "any",
"description": "The new value of the setting"
},
{
"type": "function",
"name": "callback",
"description": "Callback to notify that the new value has been set",
"parameters": []
}
]
}
],
"events": [
......
......@@ -549,6 +549,12 @@ const char kLanguageEnabledImesSyncable[] =
// A boolean pref set to true if the IME menu is activated.
const char kLanguageImeMenuActivated[] = "settings.language.ime_menu_activated";
// A dictionary of input method IDs and their settings. Each value is itself a
// dictionary of key / value string pairs, with each pair representing a setting
// and its value.
const char kLanguageInputMethodSpecificSettings[] =
"settings.language.input_method_specific_settings";
// A boolean pref to indicate whether we still need to add the globally synced
// input methods. False after the initial post-OOBE sync.
const char kLanguageShouldMergeInputMethods[] =
......
......@@ -210,6 +210,7 @@ extern const char kLanguagePreloadEnginesSyncable[];
extern const char kLanguageEnabledImes[];
extern const char kLanguageEnabledImesSyncable[];
extern const char kLanguageImeMenuActivated[];
extern const char kLanguageInputMethodSpecificSettings[];
extern const char kLanguageShouldMergeInputMethods[];
extern const char kLanguageSendFunctionKeys[];
extern const char kLanguageXkbAutoRepeatEnabled[];
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.test.runTests([
// Test getting the value for a key that is not set.
function getUnsetKey() {
chrome.inputMethodPrivate.getSetting('test', 'key', (val) => {
chrome.test.assertEq(null, val);
chrome.test.succeed();
});
},
// Test setting and getting a string value.
function getSetString() {
chrome.inputMethodPrivate.setSetting('test', 'key-string', 'value1', () => {
chrome.inputMethodPrivate.getSetting('test', 'key-string', (val) => {
chrome.test.assertEq("value1", val);
chrome.test.succeed();
});
});
},
// Test setting and getting an int value.
function getSetInt() {
chrome.inputMethodPrivate.setSetting('test', 'key-int', 42, () => {
chrome.inputMethodPrivate.getSetting('test', 'key-int', (val) => {
chrome.test.assertEq(42, val);
chrome.test.succeed();
});
});
},
// Test setting and getting a bool value.
function getSetBool() {
chrome.inputMethodPrivate.setSetting('test', 'key-bool', true, () => {
chrome.inputMethodPrivate.getSetting('test', 'key-bool', (val) => {
chrome.test.assertEq(true, val);
chrome.test.succeed();
});
});
},
// Test updating a key with a new value.
function updateKey() {
chrome.inputMethodPrivate.setSetting('test', 'key-update', 42, () => {
chrome.inputMethodPrivate.setSetting('test', 'key-update', 'new', () => {
chrome.inputMethodPrivate.getSetting('test', 'key-update', (val) => {
chrome.test.assertEq('new', val);
chrome.test.succeed();
});
});
});
},
// Test setting and getting a multiple keys.
function getSetMultiple() {
chrome.inputMethodPrivate.setSetting('test', 'key1', 'value1', () => {
chrome.inputMethodPrivate.setSetting('test', 'key2', 'value2', () => {
chrome.inputMethodPrivate.getSetting('test', 'key1', (val) => {
chrome.test.assertEq("value1", val);
chrome.inputMethodPrivate.getSetting('test', 'key2', (val) => {
chrome.test.assertEq("value2", val);
chrome.test.succeed();
});
});
});
});
},
// Test setting and getting the same key from different IMEs.
function getSetSameKeyDifferentIMEs() {
chrome.inputMethodPrivate.setSetting('ime1', 'key', 'value1', () => {
chrome.inputMethodPrivate.setSetting('ime2', 'key', 'value2', () => {
chrome.inputMethodPrivate.getSetting('ime1', 'key', (val) => {
chrome.test.assertEq("value1", val);
chrome.inputMethodPrivate.getSetting('ime2', 'key', (val) => {
chrome.test.assertEq("value2", val);
chrome.test.succeed();
});
});
});
});
}
]);
{
"name": "chrome.inputMethodPrivate settings",
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9fDu8apG3Dz72XTT3Ym1SfGt06tdowTlYQ+3lGlCbVpfnMOmewgRgYxzUtUPso9aQERZcmI2+7UtbWjtk6/usl9Hr7a1JBQwfaUoUygEe56ajUeZhe/ErkH5CXT84U0pokfPr5vMvc7RVPduU+UBiF0DnGb/hSpzz/1UhJ5H9AwIDAQAB",
"version": "0.1",
"manifest_version": 2,
"description": "API test for manipulating input method settings using chrome.inputMethodPrivate",
"app": {
"background": {
"scripts": ["background.js"]
}
},
"permissions": ["inputMethodPrivate"]
}
......@@ -1355,6 +1355,8 @@ enum HistogramValue {
AUTOTESTPRIVATE_SETASSISTANTENABLED = 1292,
AUTOTESTPRIVATE_ISARCPROVISIONED = 1293,
CRYPTOTOKENPRIVATE_CANPROXYTOWEBAUTHN = 1294,
INPUTMETHODPRIVATE_GETSETTING = 1295,
INPUTMETHODPRIVATE_SETSETTING = 1296,
// Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY
......
......@@ -17338,6 +17338,8 @@ Called by update_net_error_codes.py.-->
<int value="1292" label="AUTOTESTPRIVATE_SETASSISTANTENABLED"/>
<int value="1293" label="AUTOTESTPRIVATE_ISARCPROVISIONED"/>
<int value="1294" label="CRYPTOTOKENPRIVATE_CANPROXYTOWEBAUTHN"/>
<int value="1295" label="INPUTMETHODPRIVATE_GETSETTING"/>
<int value="1296" label="INPUTMETHODPRIVATE_SETSETTING"/>
</enum>
<enum name="ExtensionIconState">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment