mobile/android/base/SharedPreferencesHelper.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko;
michael@0 7
michael@0 8 import org.mozilla.gecko.EventDispatcher;
michael@0 9 import org.mozilla.gecko.util.GeckoEventListener;
michael@0 10
michael@0 11 import org.json.JSONArray;
michael@0 12 import org.json.JSONException;
michael@0 13 import org.json.JSONObject;
michael@0 14
michael@0 15 import android.content.Context;
michael@0 16 import android.content.SharedPreferences;
michael@0 17 import android.util.Log;
michael@0 18
michael@0 19 import java.util.Map;
michael@0 20 import java.util.HashMap;
michael@0 21
michael@0 22 /**
michael@0 23 * Helper class to get, set, and observe Android Shared Preferences.
michael@0 24 */
michael@0 25 public final class SharedPreferencesHelper
michael@0 26 implements GeckoEventListener
michael@0 27 {
michael@0 28 public static final String LOGTAG = "GeckoAndSharedPrefs";
michael@0 29
michael@0 30 protected final Context mContext;
michael@0 31
michael@0 32 // mListeners is not synchronized because it is only updated in
michael@0 33 // handleObserve, which is called from Gecko serially.
michael@0 34 protected final Map<String, SharedPreferences.OnSharedPreferenceChangeListener> mListeners;
michael@0 35
michael@0 36 public SharedPreferencesHelper(Context context) {
michael@0 37 mContext = context;
michael@0 38
michael@0 39 mListeners = new HashMap<String, SharedPreferences.OnSharedPreferenceChangeListener>();
michael@0 40
michael@0 41 EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher();
michael@0 42 if (dispatcher == null) {
michael@0 43 Log.e(LOGTAG, "Gecko event dispatcher must not be null", new RuntimeException());
michael@0 44 return;
michael@0 45 }
michael@0 46 dispatcher.registerEventListener("SharedPreferences:Set", this);
michael@0 47 dispatcher.registerEventListener("SharedPreferences:Get", this);
michael@0 48 dispatcher.registerEventListener("SharedPreferences:Observe", this);
michael@0 49 }
michael@0 50
michael@0 51 public synchronized void uninit() {
michael@0 52 EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher();
michael@0 53 if (dispatcher == null) {
michael@0 54 Log.e(LOGTAG, "Gecko event dispatcher must not be null", new RuntimeException());
michael@0 55 return;
michael@0 56 }
michael@0 57
michael@0 58 dispatcher.unregisterEventListener("SharedPreferences:Set", this);
michael@0 59 dispatcher.unregisterEventListener("SharedPreferences:Get", this);
michael@0 60 dispatcher.unregisterEventListener("SharedPreferences:Observe", this);
michael@0 61 }
michael@0 62
michael@0 63 private SharedPreferences getSharedPreferences(String branch) {
michael@0 64 if (branch == null) {
michael@0 65 return GeckoSharedPrefs.forApp(mContext);
michael@0 66 } else {
michael@0 67 return mContext.getSharedPreferences(branch, Context.MODE_PRIVATE);
michael@0 68 }
michael@0 69 }
michael@0 70
michael@0 71 /**
michael@0 72 * Set many SharedPreferences in Android.
michael@0 73 *
michael@0 74 * message.branch must exist, and should be a String SharedPreferences
michael@0 75 * branch name, or null for the default branch.
michael@0 76 * message.preferences should be an array of preferences. Each preference
michael@0 77 * must include a String name, a String type in ["bool", "int", "string"],
michael@0 78 * and an Object value.
michael@0 79 */
michael@0 80 private void handleSet(JSONObject message) throws JSONException {
michael@0 81 if (!message.has("branch")) {
michael@0 82 Log.e(LOGTAG, "No branch specified for SharedPreference:Set; aborting.");
michael@0 83 return;
michael@0 84 }
michael@0 85
michael@0 86 String branch = message.isNull("branch") ? null : message.getString("branch");
michael@0 87 SharedPreferences.Editor editor = getSharedPreferences(branch).edit();
michael@0 88
michael@0 89 JSONArray jsonPrefs = message.getJSONArray("preferences");
michael@0 90
michael@0 91 for (int i = 0; i < jsonPrefs.length(); i++) {
michael@0 92 JSONObject pref = jsonPrefs.getJSONObject(i);
michael@0 93 String name = pref.getString("name");
michael@0 94 String type = pref.getString("type");
michael@0 95 if ("bool".equals(type)) {
michael@0 96 editor.putBoolean(name, pref.getBoolean("value"));
michael@0 97 } else if ("int".equals(type)) {
michael@0 98 editor.putInt(name, pref.getInt("value"));
michael@0 99 } else if ("string".equals(type)) {
michael@0 100 editor.putString(name, pref.getString("value"));
michael@0 101 } else {
michael@0 102 Log.w(LOGTAG, "Unknown pref value type [" + type + "] for pref [" + name + "]");
michael@0 103 }
michael@0 104 editor.commit();
michael@0 105 }
michael@0 106 }
michael@0 107
michael@0 108 /**
michael@0 109 * Get many SharedPreferences from Android.
michael@0 110 *
michael@0 111 * message.branch must exist, and should be a String SharedPreferences
michael@0 112 * branch name, or null for the default branch.
michael@0 113 * message.preferences should be an array of preferences. Each preference
michael@0 114 * must include a String name, and a String type in ["bool", "int",
michael@0 115 * "string"].
michael@0 116 */
michael@0 117 private JSONArray handleGet(JSONObject message) throws JSONException {
michael@0 118 if (!message.has("branch")) {
michael@0 119 Log.e(LOGTAG, "No branch specified for SharedPreference:Get; aborting.");
michael@0 120 return null;
michael@0 121 }
michael@0 122
michael@0 123 String branch = message.isNull("branch") ? null : message.getString("branch");
michael@0 124 SharedPreferences prefs = getSharedPreferences(branch);
michael@0 125 JSONArray jsonPrefs = message.getJSONArray("preferences");
michael@0 126 JSONArray jsonValues = new JSONArray();
michael@0 127
michael@0 128 for (int i = 0; i < jsonPrefs.length(); i++) {
michael@0 129 JSONObject pref = jsonPrefs.getJSONObject(i);
michael@0 130 String name = pref.getString("name");
michael@0 131 String type = pref.getString("type");
michael@0 132 JSONObject jsonValue = new JSONObject();
michael@0 133 jsonValue.put("name", name);
michael@0 134 jsonValue.put("type", type);
michael@0 135 try {
michael@0 136 if ("bool".equals(type)) {
michael@0 137 boolean value = prefs.getBoolean(name, false);
michael@0 138 jsonValue.put("value", value);
michael@0 139 } else if ("int".equals(type)) {
michael@0 140 int value = prefs.getInt(name, 0);
michael@0 141 jsonValue.put("value", value);
michael@0 142 } else if ("string".equals(type)) {
michael@0 143 String value = prefs.getString(name, "");
michael@0 144 jsonValue.put("value", value);
michael@0 145 } else {
michael@0 146 Log.w(LOGTAG, "Unknown pref value type [" + type + "] for pref [" + name + "]");
michael@0 147 }
michael@0 148 } catch (ClassCastException e) {
michael@0 149 // Thrown if there is a preference with the given name that is
michael@0 150 // not the right type.
michael@0 151 Log.w(LOGTAG, "Wrong pref value type [" + type + "] for pref [" + name + "]");
michael@0 152 }
michael@0 153 jsonValues.put(jsonValue);
michael@0 154 }
michael@0 155
michael@0 156 return jsonValues;
michael@0 157 }
michael@0 158
michael@0 159 private static class ChangeListener
michael@0 160 implements SharedPreferences.OnSharedPreferenceChangeListener {
michael@0 161 public final String branch;
michael@0 162
michael@0 163 public ChangeListener(final String branch) {
michael@0 164 this.branch = branch;
michael@0 165 }
michael@0 166
michael@0 167 @Override
michael@0 168 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
michael@0 169 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
michael@0 170 Log.v(LOGTAG, "Got onSharedPreferenceChanged");
michael@0 171 }
michael@0 172 try {
michael@0 173 final JSONObject msg = new JSONObject();
michael@0 174 msg.put("branch", this.branch);
michael@0 175 msg.put("key", key);
michael@0 176
michael@0 177 // Truly, this is awful, but the API impedence is strong: there
michael@0 178 // is no way to get a single untyped value from a
michael@0 179 // SharedPreferences instance.
michael@0 180 msg.put("value", sharedPreferences.getAll().get(key));
michael@0 181
michael@0 182 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SharedPreferences:Changed", msg.toString()));
michael@0 183 } catch (JSONException e) {
michael@0 184 Log.e(LOGTAG, "Got exception creating JSON object", e);
michael@0 185 return;
michael@0 186 }
michael@0 187 }
michael@0 188 }
michael@0 189
michael@0 190 /**
michael@0 191 * Register or unregister a SharedPreferences.OnSharedPreferenceChangeListener.
michael@0 192 *
michael@0 193 * message.branch must exist, and should be a String SharedPreferences
michael@0 194 * branch name, or null for the default branch.
michael@0 195 * message.enable should be a boolean: true to enable listening, false to
michael@0 196 * disable listening.
michael@0 197 */
michael@0 198 private void handleObserve(JSONObject message) throws JSONException {
michael@0 199 if (!message.has("branch")) {
michael@0 200 Log.e(LOGTAG, "No branch specified for SharedPreference:Observe; aborting.");
michael@0 201 return;
michael@0 202 }
michael@0 203
michael@0 204 String branch = message.isNull("branch") ? null : message.getString("branch");
michael@0 205 SharedPreferences prefs = getSharedPreferences(branch);
michael@0 206 boolean enable = message.getBoolean("enable");
michael@0 207
michael@0 208 // mListeners is only modified in this one observer, which is called
michael@0 209 // from Gecko serially.
michael@0 210 if (enable && !this.mListeners.containsKey(branch)) {
michael@0 211 SharedPreferences.OnSharedPreferenceChangeListener listener = new ChangeListener(branch);
michael@0 212 this.mListeners.put(branch, listener);
michael@0 213 prefs.registerOnSharedPreferenceChangeListener(listener);
michael@0 214 }
michael@0 215 if (!enable && this.mListeners.containsKey(branch)) {
michael@0 216 SharedPreferences.OnSharedPreferenceChangeListener listener = this.mListeners.remove(branch);
michael@0 217 prefs.unregisterOnSharedPreferenceChangeListener(listener);
michael@0 218 }
michael@0 219 }
michael@0 220
michael@0 221 @Override
michael@0 222 public void handleMessage(String event, JSONObject message) {
michael@0 223 // Everything here is synchronous and serial, so we need not worry about
michael@0 224 // overwriting an in-progress response.
michael@0 225 try {
michael@0 226 if (event.equals("SharedPreferences:Set")) {
michael@0 227 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
michael@0 228 Log.v(LOGTAG, "Got SharedPreferences:Set message.");
michael@0 229 }
michael@0 230 handleSet(message);
michael@0 231 } else if (event.equals("SharedPreferences:Get")) {
michael@0 232 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
michael@0 233 Log.v(LOGTAG, "Got SharedPreferences:Get message.");
michael@0 234 }
michael@0 235 JSONObject obj = new JSONObject();
michael@0 236 obj.put("values", handleGet(message));
michael@0 237 EventDispatcher.sendResponse(message, obj);
michael@0 238 } else if (event.equals("SharedPreferences:Observe")) {
michael@0 239 if (Log.isLoggable(LOGTAG, Log.VERBOSE)) {
michael@0 240 Log.v(LOGTAG, "Got SharedPreferences:Observe message.");
michael@0 241 }
michael@0 242 handleObserve(message);
michael@0 243 } else {
michael@0 244 Log.e(LOGTAG, "SharedPreferencesHelper got unexpected message " + event);
michael@0 245 return;
michael@0 246 }
michael@0 247 } catch (JSONException e) {
michael@0 248 Log.e(LOGTAG, "Got exception in handleMessage handling event " + event, e);
michael@0 249 return;
michael@0 250 }
michael@0 251 }
michael@0 252 }

mercurial