mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 997328 - Update SharedPreferences.jsm to use scopes and mirror GeckoSharedPrefs. r=nalexander
This commit is contained in:
parent
ebb50c6ecf
commit
82f9072526
@ -50,6 +50,9 @@ public final class GeckoSharedPrefs {
|
||||
// Name for app-scoped prefs
|
||||
public static final String APP_PREFS_NAME = "GeckoApp";
|
||||
|
||||
// Used when fetching profile-scoped prefs.
|
||||
public static final String PROFILE_PREFS_NAME_PREFIX = "GeckoProfile-";
|
||||
|
||||
// The prefs key that holds the current migration
|
||||
private static final String PREFS_VERSION_KEY = "gecko_shared_prefs_migration";
|
||||
|
||||
@ -73,9 +76,6 @@ public final class GeckoSharedPrefs {
|
||||
DISABLE_MIGRATIONS
|
||||
}
|
||||
|
||||
// Used when fetching profile-scoped prefs.
|
||||
private static final String PROFILE_PREFS_NAME_PREFIX = "GeckoProfile-";
|
||||
|
||||
public static SharedPreferences forApp(Context context) {
|
||||
return forApp(context, EnumSet.noneOf(Flags.class));
|
||||
}
|
||||
|
@ -7,13 +7,13 @@ package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Map;
|
||||
@ -27,6 +27,28 @@ public final class SharedPreferencesHelper
|
||||
{
|
||||
public static final String LOGTAG = "GeckoAndSharedPrefs";
|
||||
|
||||
private enum Scope {
|
||||
APP("app"),
|
||||
PROFILE("profile"),
|
||||
GLOBAL("global");
|
||||
|
||||
public final String key;
|
||||
|
||||
private Scope(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public static Scope forKey(String key) {
|
||||
for (Scope scope : values()) {
|
||||
if (scope.key.equals(key)) {
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("SharedPreferences scope must be valid.");
|
||||
}
|
||||
}
|
||||
|
||||
protected final Context mContext;
|
||||
|
||||
// mListeners is not synchronized because it is only updated in
|
||||
@ -61,12 +83,45 @@ public final class SharedPreferencesHelper
|
||||
"SharedPreferences:Observe");
|
||||
}
|
||||
|
||||
private SharedPreferences getSharedPreferences(String branch) {
|
||||
if (branch == null) {
|
||||
return GeckoSharedPrefs.forApp(mContext);
|
||||
} else {
|
||||
return mContext.getSharedPreferences(branch, Context.MODE_PRIVATE);
|
||||
private SharedPreferences getSharedPreferences(JSONObject message) throws JSONException {
|
||||
final Scope scope = Scope.forKey(message.getString("scope"));
|
||||
switch (scope) {
|
||||
case APP:
|
||||
return GeckoSharedPrefs.forApp(mContext);
|
||||
case PROFILE:
|
||||
final String profileName = message.optString("profileName", null);
|
||||
if (profileName == null) {
|
||||
return GeckoSharedPrefs.forProfile(mContext);
|
||||
} else {
|
||||
return GeckoSharedPrefs.forProfileName(mContext, profileName);
|
||||
}
|
||||
case GLOBAL:
|
||||
final String branch = message.optString("branch", null);
|
||||
if (branch == null) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
} else {
|
||||
return mContext.getSharedPreferences(branch, Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getBranch(Scope scope, String profileName, String branch) {
|
||||
switch (scope) {
|
||||
case APP:
|
||||
return GeckoSharedPrefs.APP_PREFS_NAME;
|
||||
case PROFILE:
|
||||
if (profileName == null) {
|
||||
profileName = GeckoProfile.get(mContext).getName();
|
||||
}
|
||||
|
||||
return GeckoSharedPrefs.PROFILE_PREFS_NAME_PREFIX + profileName;
|
||||
case GLOBAL:
|
||||
return branch;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,13 +134,7 @@ public final class SharedPreferencesHelper
|
||||
* and an Object value.
|
||||
*/
|
||||
private void handleSet(JSONObject message) throws JSONException {
|
||||
if (!message.has("branch")) {
|
||||
Log.e(LOGTAG, "No branch specified for SharedPreference:Set; aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
String branch = message.isNull("branch") ? null : message.getString("branch");
|
||||
SharedPreferences.Editor editor = getSharedPreferences(branch).edit();
|
||||
SharedPreferences.Editor editor = getSharedPreferences(message).edit();
|
||||
|
||||
JSONArray jsonPrefs = message.getJSONArray("preferences");
|
||||
|
||||
@ -116,13 +165,7 @@ public final class SharedPreferencesHelper
|
||||
* "string"].
|
||||
*/
|
||||
private JSONArray handleGet(JSONObject message) throws JSONException {
|
||||
if (!message.has("branch")) {
|
||||
Log.e(LOGTAG, "No branch specified for SharedPreference:Get; aborting.");
|
||||
return null;
|
||||
}
|
||||
|
||||
String branch = message.isNull("branch") ? null : message.getString("branch");
|
||||
SharedPreferences prefs = getSharedPreferences(branch);
|
||||
SharedPreferences prefs = getSharedPreferences(message);
|
||||
JSONArray jsonPrefs = message.getJSONArray("preferences");
|
||||
JSONArray jsonValues = new JSONArray();
|
||||
|
||||
@ -159,10 +202,14 @@ public final class SharedPreferencesHelper
|
||||
|
||||
private static class ChangeListener
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public final Scope scope;
|
||||
public final String branch;
|
||||
public final String profileName;
|
||||
|
||||
public ChangeListener(final String branch) {
|
||||
public ChangeListener(final Scope scope, final String branch, final String profileName) {
|
||||
this.scope = scope;
|
||||
this.branch = branch;
|
||||
this.profileName = profileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -172,7 +219,9 @@ public final class SharedPreferencesHelper
|
||||
}
|
||||
try {
|
||||
final JSONObject msg = new JSONObject();
|
||||
msg.put("scope", this.scope.key);
|
||||
msg.put("branch", this.branch);
|
||||
msg.put("profileName", this.profileName);
|
||||
msg.put("key", key);
|
||||
|
||||
// Truly, this is awful, but the API impedence is strong: there
|
||||
@ -197,24 +246,29 @@ public final class SharedPreferencesHelper
|
||||
* disable listening.
|
||||
*/
|
||||
private void handleObserve(JSONObject message) throws JSONException {
|
||||
if (!message.has("branch")) {
|
||||
final SharedPreferences prefs = getSharedPreferences(message);
|
||||
final boolean enable = message.getBoolean("enable");
|
||||
|
||||
final Scope scope = Scope.forKey(message.getString("scope"));
|
||||
final String profileName = message.optString("profileName", null);
|
||||
final String branch = getBranch(scope, profileName, message.optString("branch", null));
|
||||
|
||||
if (branch == null) {
|
||||
Log.e(LOGTAG, "No branch specified for SharedPreference:Observe; aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
String branch = message.isNull("branch") ? null : message.getString("branch");
|
||||
SharedPreferences prefs = getSharedPreferences(branch);
|
||||
boolean enable = message.getBoolean("enable");
|
||||
|
||||
// mListeners is only modified in this one observer, which is called
|
||||
// from Gecko serially.
|
||||
if (enable && !this.mListeners.containsKey(branch)) {
|
||||
SharedPreferences.OnSharedPreferenceChangeListener listener = new ChangeListener(branch);
|
||||
SharedPreferences.OnSharedPreferenceChangeListener listener
|
||||
= new ChangeListener(scope, branch, profileName);
|
||||
this.mListeners.put(branch, listener);
|
||||
prefs.registerOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
if (!enable && this.mListeners.containsKey(branch)) {
|
||||
SharedPreferences.OnSharedPreferenceChangeListener listener = this.mListeners.remove(branch);
|
||||
SharedPreferences.OnSharedPreferenceChangeListener listener
|
||||
= this.mListeners.remove(branch);
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import org.mozilla.gecko.FennecTalosAssert;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.util.Log;
|
||||
|
||||
public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<Activity> {
|
||||
public enum Type {
|
||||
@ -21,6 +22,8 @@ public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<A
|
||||
TALOS
|
||||
}
|
||||
|
||||
private static final String DEFAULT_ROOT_PATH = "/mnt/sdcard/tests";
|
||||
|
||||
protected Assert mAsserter;
|
||||
protected String mLogFile;
|
||||
|
||||
@ -66,6 +69,10 @@ public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<A
|
||||
protected void setUp() throws Exception {
|
||||
// Load config file from root path (set up by Python script).
|
||||
mRootPath = FennecInstrumentationTestRunner.getFennecArguments().getString("deviceroot");
|
||||
if (mRootPath == null) {
|
||||
Log.w("Robocop", "Did not find deviceroot in arguments; falling back to: " + DEFAULT_ROOT_PATH);
|
||||
mRootPath = DEFAULT_ROOT_PATH;
|
||||
}
|
||||
String configFile = FennecNativeDriver.getFile(mRootPath + "/robotium.config");
|
||||
mConfig = FennecNativeDriver.convertTextToTable(configFile);
|
||||
mLogFile = (String) mConfig.get("logfile");
|
||||
|
@ -28,7 +28,7 @@ function makeObserver() {
|
||||
};
|
||||
|
||||
add_task(function test_get_set() {
|
||||
let branch = new SharedPreferences("test");
|
||||
let branch = SharedPreferences.forAndroid("test");
|
||||
|
||||
branch.setBoolPref("boolKey", true);
|
||||
branch.setCharPref("charKey", "string value");
|
||||
@ -52,7 +52,7 @@ add_task(function test_get_set() {
|
||||
});
|
||||
|
||||
add_task(function test_default() {
|
||||
let branch = new SharedPreferences();
|
||||
let branch = SharedPreferences.forAndroid();
|
||||
|
||||
branch.setBoolPref("boolKey", true);
|
||||
branch.setCharPref("charKey", "string value");
|
||||
@ -76,8 +76,8 @@ add_task(function test_default() {
|
||||
});
|
||||
|
||||
add_task(function test_multiple_branches() {
|
||||
let branch1 = new SharedPreferences("test1");
|
||||
let branch2 = new SharedPreferences("test2");
|
||||
let branch1 = SharedPreferences.forAndroid("test1");
|
||||
let branch2 = SharedPreferences.forAndroid("test2");
|
||||
|
||||
branch1.setBoolPref("boolKey", true);
|
||||
branch2.setBoolPref("boolKey", false);
|
||||
@ -93,7 +93,7 @@ add_task(function test_multiple_branches() {
|
||||
});
|
||||
|
||||
add_task(function test_add_remove_observer() {
|
||||
let branch = new SharedPreferences("test");
|
||||
let branch = SharedPreferences.forAndroid("test");
|
||||
|
||||
branch.setBoolPref("boolKey", false);
|
||||
do_check_eq(branch.getBoolPref("boolKey"), false);
|
||||
@ -145,7 +145,7 @@ add_task(function test_add_remove_observer() {
|
||||
});
|
||||
|
||||
add_task(function test_observer_ignores() {
|
||||
let branch = new SharedPreferences("test");
|
||||
let branch = SharedPreferences.forAndroid("test");
|
||||
|
||||
branch.setCharPref("charKey", "first value");
|
||||
do_check_eq(branch.getCharPref("charKey"), "first value");
|
||||
@ -176,7 +176,7 @@ add_task(function test_observer_ignores() {
|
||||
});
|
||||
|
||||
add_task(function test_observer_ignores_branches() {
|
||||
let branch = new SharedPreferences("test");
|
||||
let branch = SharedPreferences.forAndroid("test");
|
||||
|
||||
branch.setCharPref("charKey", "first value");
|
||||
do_check_eq(branch.getCharPref("charKey"), "first value");
|
||||
@ -186,9 +186,9 @@ add_task(function test_observer_ignores_branches() {
|
||||
|
||||
try {
|
||||
// These should all be ignored.
|
||||
let branch2 = new SharedPreferences("test2");
|
||||
let branch2 = SharedPreferences.forAndroid("test2");
|
||||
branch2.setCharPref("charKey", "a wrong value");
|
||||
let branch3 = new SharedPreferences("test.2");
|
||||
let branch3 = SharedPreferences.forAndroid("test.2");
|
||||
branch3.setCharPref("charKey", "a different wrong value");
|
||||
|
||||
// This should not be ignored.
|
||||
@ -208,4 +208,24 @@ add_task(function test_observer_ignores_branches() {
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function test_scopes() {
|
||||
let forApp = SharedPreferences.forApp();
|
||||
let forProfile = SharedPreferences.forProfile();
|
||||
let forProfileName = SharedPreferences.forProfileName("testProfile");
|
||||
let forAndroidDefault = SharedPreferences.forAndroid();
|
||||
let forAndroidBranch = SharedPreferences.forAndroid("testBranch");
|
||||
|
||||
forApp.setCharPref("charKey", "forApp");
|
||||
forProfile.setCharPref("charKey", "forProfile");
|
||||
forProfileName.setCharPref("charKey", "forProfileName");
|
||||
forAndroidDefault.setCharPref("charKey", "forAndroidDefault");
|
||||
forAndroidBranch.setCharPref("charKey", "forAndroidBranch");
|
||||
|
||||
do_check_eq(forApp.getCharPref("charKey"), "forApp");
|
||||
do_check_eq(forProfile.getCharPref("charKey"), "forProfile");
|
||||
do_check_eq(forProfileName.getCharPref("charKey"), "forProfileName");
|
||||
do_check_eq(forAndroidDefault.getCharPref("charKey"), "forAndroidDefault");
|
||||
do_check_eq(forAndroidBranch.getCharPref("charKey"), "forAndroidBranch");
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
|
@ -27,7 +27,7 @@ const EVENT_HEALTH_RESPONSE = "HealthReport:Response";
|
||||
|
||||
// about:healthreport prefs are stored in Firefox's default Android
|
||||
// SharedPreferences.
|
||||
let sharedPrefs = new SharedPreferences();
|
||||
let sharedPrefs = SharedPreferences.forApp();
|
||||
|
||||
let healthReportWrapper = {
|
||||
init: function () {
|
||||
@ -190,4 +190,4 @@ let healthReportWrapper = {
|
||||
};
|
||||
|
||||
window.addEventListener("load", healthReportWrapper.init.bind(healthReportWrapper), false);
|
||||
window.addEventListener("unload", healthReportWrapper.uninit.bind(healthReportWrapper), false);
|
||||
window.addEventListener("unload", healthReportWrapper.uninit.bind(healthReportWrapper), false);
|
||||
|
@ -457,7 +457,7 @@ let HomePanels = (function () {
|
||||
_assertPanelExists(id);
|
||||
|
||||
let authKey = PREFS_PANEL_AUTH_PREFIX + id;
|
||||
let sharedPrefs = new SharedPreferences();
|
||||
let sharedPrefs = SharedPreferences.forProfile();
|
||||
sharedPrefs.setBoolPref(authKey, isAuthenticated);
|
||||
}
|
||||
});
|
||||
|
@ -13,26 +13,74 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
|
||||
let Scope = Object.freeze({
|
||||
APP: "app",
|
||||
PROFILE: "profile",
|
||||
GLOBAL: "global"
|
||||
});
|
||||
|
||||
/**
|
||||
* Public API to getting a SharedPreferencesImpl instance. These scopes mirror GeckoSharedPrefs.
|
||||
*/
|
||||
let SharedPreferences = {
|
||||
forApp: function() {
|
||||
return new SharedPreferencesImpl({ scope: Scope.APP });
|
||||
},
|
||||
|
||||
forProfile: function() {
|
||||
return new SharedPreferencesImpl({ scope: Scope.PROFILE });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get SharedPreferences for the named profile; if the profile name is null,
|
||||
* returns the preferences for the current profile (just like |forProfile|).
|
||||
*/
|
||||
forProfileName: function(profileName) {
|
||||
return new SharedPreferencesImpl({ scope: Scope.PROFILE, profileName: profileName });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get SharedPreferences for the given Android branch; if the branch is null,
|
||||
* returns the default preferences branch for the application, which is the
|
||||
* output of |PreferenceManager.getDefaultSharedPreferences|.
|
||||
*/
|
||||
forAndroid: function(branch) {
|
||||
return new SharedPreferencesImpl({ scope: Scope.GLOBAL, branch: branch });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an interface to an Android SharedPreferences branch.
|
||||
*
|
||||
* branch {String} should be a string describing a preferences branch,
|
||||
* like "UpdateService" or "background.data", or null to access the
|
||||
* default preferences branch for the application.
|
||||
* options {Object} with the following valid keys:
|
||||
* - scope {String} (required) specifies the scope of preferences that should be accessed.
|
||||
* - branch {String} (only when using Scope.GLOBAL) should be a string describing a preferences branch,
|
||||
* like "UpdateService" or "background.data", or null to access the
|
||||
* default preferences branch for the application.
|
||||
* - profileName {String} (optional, only valid when using Scope.PROFILE)
|
||||
*/
|
||||
function SharedPreferences(branch) {
|
||||
if (!(this instanceof SharedPreferences)) {
|
||||
return new SharedPreferences(branch);
|
||||
function SharedPreferencesImpl(options = {}) {
|
||||
if (!(this instanceof SharedPreferencesImpl)) {
|
||||
return new SharedPreferencesImpl(level);
|
||||
}
|
||||
this._branch = branch || null;
|
||||
this._observers = {};
|
||||
};
|
||||
|
||||
SharedPreferences.prototype = Object.freeze({
|
||||
if (options.scope == null || options.scope == undefined) {
|
||||
throw "Shared Preferences must specifiy a scope.";
|
||||
}
|
||||
|
||||
this._scope = options.scope;
|
||||
this._profileName = options.profileName;
|
||||
this._branch = options.branch;
|
||||
this._observers = {};
|
||||
}
|
||||
|
||||
SharedPreferencesImpl.prototype = Object.freeze({
|
||||
_set: function _set(prefs) {
|
||||
sendMessageToJava({
|
||||
type: "SharedPreferences:Set",
|
||||
preferences: prefs,
|
||||
scope: this._scope,
|
||||
profileName: this._profileName,
|
||||
branch: this._branch,
|
||||
});
|
||||
},
|
||||
@ -64,6 +112,8 @@ SharedPreferences.prototype = Object.freeze({
|
||||
sendMessageToJava({
|
||||
type: "SharedPreferences:Get",
|
||||
preferences: prefs,
|
||||
scope: this._scope,
|
||||
profileName: this._profileName,
|
||||
branch: this._branch,
|
||||
}, (data) => {
|
||||
result = data.values;
|
||||
@ -159,6 +209,8 @@ SharedPreferences.prototype = Object.freeze({
|
||||
sendMessageToJava({
|
||||
type: "SharedPreferences:Observe",
|
||||
enable: true,
|
||||
scope: this._scope,
|
||||
profileName: this._profileName,
|
||||
branch: this._branch,
|
||||
});
|
||||
},
|
||||
@ -169,7 +221,9 @@ SharedPreferences.prototype = Object.freeze({
|
||||
}
|
||||
|
||||
let msg = JSON.parse(data);
|
||||
if (msg.branch != this._branch) {
|
||||
if (msg.scope !== this._scope ||
|
||||
((this._scope === Scope.PROFILE) && (msg.profileName !== this._profileName)) ||
|
||||
((this._scope === Scope.GLOBAL) && (msg.branch !== this._branch))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -192,6 +246,8 @@ SharedPreferences.prototype = Object.freeze({
|
||||
sendMessageToJava({
|
||||
type: "SharedPreferences:Observe",
|
||||
enable: false,
|
||||
scope: this._scope,
|
||||
profileName: this._profileName,
|
||||
branch: this._branch,
|
||||
});
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user