Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 this.EXPORTED_SYMBOLS = ['PrefsEngine', 'PrefRec'];
7 const Cc = Components.classes;
8 const Ci = Components.interfaces;
9 const Cu = Components.utils;
11 const WEAVE_SYNC_PREFS = "services.sync.prefs.sync.";
13 Cu.import("resource://services-sync/engines.js");
14 Cu.import("resource://services-sync/record.js");
15 Cu.import("resource://services-sync/util.js");
16 Cu.import("resource://services-sync/constants.js");
17 Cu.import("resource://services-common/utils.js");
18 Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
19 Cu.import("resource://gre/modules/Preferences.jsm");
21 const PREFS_GUID = CommonUtils.encodeBase64URL(Services.appinfo.ID);
23 this.PrefRec = function PrefRec(collection, id) {
24 CryptoWrapper.call(this, collection, id);
25 }
26 PrefRec.prototype = {
27 __proto__: CryptoWrapper.prototype,
28 _logName: "Sync.Record.Pref",
29 };
31 Utils.deferGetSet(PrefRec, "cleartext", ["value"]);
34 this.PrefsEngine = function PrefsEngine(service) {
35 SyncEngine.call(this, "Prefs", service);
36 }
37 PrefsEngine.prototype = {
38 __proto__: SyncEngine.prototype,
39 _storeObj: PrefStore,
40 _trackerObj: PrefTracker,
41 _recordObj: PrefRec,
42 version: 2,
44 getChangedIDs: function getChangedIDs() {
45 // No need for a proper timestamp (no conflict resolution needed).
46 let changedIDs = {};
47 if (this._tracker.modified)
48 changedIDs[PREFS_GUID] = 0;
49 return changedIDs;
50 },
52 _wipeClient: function _wipeClient() {
53 SyncEngine.prototype._wipeClient.call(this);
54 this.justWiped = true;
55 },
57 _reconcile: function _reconcile(item) {
58 // Apply the incoming item if we don't care about the local data
59 if (this.justWiped) {
60 this.justWiped = false;
61 return true;
62 }
63 return SyncEngine.prototype._reconcile.call(this, item);
64 }
65 };
68 function PrefStore(name, engine) {
69 Store.call(this, name, engine);
70 Svc.Obs.add("profile-before-change", function () {
71 this.__prefs = null;
72 }, this);
73 }
74 PrefStore.prototype = {
75 __proto__: Store.prototype,
77 __prefs: null,
78 get _prefs() {
79 if (!this.__prefs)
80 this.__prefs = new Preferences();
81 return this.__prefs;
82 },
84 _getSyncPrefs: function _getSyncPrefs() {
85 let syncPrefs = Cc["@mozilla.org/preferences-service;1"]
86 .getService(Ci.nsIPrefService)
87 .getBranch(WEAVE_SYNC_PREFS)
88 .getChildList("", {});
89 // Also sync preferences that determine which prefs get synced.
90 return syncPrefs.concat(
91 syncPrefs.map(function (pref) { return WEAVE_SYNC_PREFS + pref; }));
92 },
94 _isSynced: function _isSyncedPref(pref) {
95 return (pref.indexOf(WEAVE_SYNC_PREFS) == 0)
96 || this._prefs.get(WEAVE_SYNC_PREFS + pref, false);
97 },
99 _getAllPrefs: function () {
100 let values = {};
101 for each (let pref in this._getSyncPrefs()) {
102 if (this._isSynced(pref)) {
103 // Missing prefs get the null value.
104 values[pref] = this._prefs.get(pref, null);
105 }
106 }
107 return values;
108 },
110 _setAllPrefs: function PrefStore__setAllPrefs(values) {
111 let enabledPref = "lightweightThemes.isThemeSelected";
112 let enabledBefore = this._prefs.get(enabledPref, false);
113 let prevTheme = LightweightThemeManager.currentTheme;
115 for (let [pref, value] in Iterator(values)) {
116 if (!this._isSynced(pref))
117 continue;
119 // Pref has gone missing, best we can do is reset it.
120 if (value == null) {
121 this._prefs.reset(pref);
122 continue;
123 }
125 try {
126 this._prefs.set(pref, value);
127 } catch(ex) {
128 this._log.trace("Failed to set pref: " + pref + ": " + ex);
129 }
130 }
132 // Notify the lightweight theme manager of all the new values
133 let enabledNow = this._prefs.get(enabledPref, false);
134 if (enabledBefore && !enabledNow) {
135 LightweightThemeManager.currentTheme = null;
136 } else if (enabledNow && LightweightThemeManager.usedThemes[0] != prevTheme) {
137 LightweightThemeManager.currentTheme = null;
138 LightweightThemeManager.currentTheme = LightweightThemeManager.usedThemes[0];
139 }
140 },
142 getAllIDs: function PrefStore_getAllIDs() {
143 /* We store all prefs in just one WBO, with just one GUID */
144 let allprefs = {};
145 allprefs[PREFS_GUID] = true;
146 return allprefs;
147 },
149 changeItemID: function PrefStore_changeItemID(oldID, newID) {
150 this._log.trace("PrefStore GUID is constant!");
151 },
153 itemExists: function FormStore_itemExists(id) {
154 return (id === PREFS_GUID);
155 },
157 createRecord: function createRecord(id, collection) {
158 let record = new PrefRec(collection, id);
160 if (id == PREFS_GUID) {
161 record.value = this._getAllPrefs();
162 } else {
163 record.deleted = true;
164 }
166 return record;
167 },
169 create: function PrefStore_create(record) {
170 this._log.trace("Ignoring create request");
171 },
173 remove: function PrefStore_remove(record) {
174 this._log.trace("Ignoring remove request");
175 },
177 update: function PrefStore_update(record) {
178 // Silently ignore pref updates that are for other apps.
179 if (record.id != PREFS_GUID)
180 return;
182 this._log.trace("Received pref updates, applying...");
183 this._setAllPrefs(record.value);
184 },
186 wipe: function PrefStore_wipe() {
187 this._log.trace("Ignoring wipe request");
188 }
189 };
191 function PrefTracker(name, engine) {
192 Tracker.call(this, name, engine);
193 Svc.Obs.add("profile-before-change", this);
194 Svc.Obs.add("weave:engine:start-tracking", this);
195 Svc.Obs.add("weave:engine:stop-tracking", this);
196 }
197 PrefTracker.prototype = {
198 __proto__: Tracker.prototype,
200 get modified() {
201 return Svc.Prefs.get("engine.prefs.modified", false);
202 },
203 set modified(value) {
204 Svc.Prefs.set("engine.prefs.modified", value);
205 },
207 loadChangedIDs: function loadChangedIDs() {
208 // Don't read changed IDs from disk at start up.
209 },
211 clearChangedIDs: function clearChangedIDs() {
212 this.modified = false;
213 },
215 __prefs: null,
216 get _prefs() {
217 if (!this.__prefs) {
218 this.__prefs = new Preferences();
219 }
220 return this.__prefs;
221 },
223 startTracking: function () {
224 Services.prefs.addObserver("", this, false);
225 },
227 stopTracking: function () {
228 this.__prefs = null;
229 Services.prefs.removeObserver("", this);
230 },
232 observe: function (subject, topic, data) {
233 Tracker.prototype.observe.call(this, subject, topic, data);
235 switch (topic) {
236 case "profile-before-change":
237 this.stopTracking();
238 break;
239 case "nsPref:changed":
240 // Trigger a sync for MULTI-DEVICE for a change that determines
241 // which prefs are synced or a regular pref change.
242 if (data.indexOf(WEAVE_SYNC_PREFS) == 0 ||
243 this._prefs.get(WEAVE_SYNC_PREFS + data, false)) {
244 this.score += SCORE_INCREMENT_XLARGE;
245 this.modified = true;
246 this._log.trace("Preference " + data + " changed");
247 }
248 break;
249 }
250 }
251 };