|
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/. */ |
|
4 |
|
5 this.EXPORTED_SYMBOLS = ['PrefsEngine', 'PrefRec']; |
|
6 |
|
7 const Cc = Components.classes; |
|
8 const Ci = Components.interfaces; |
|
9 const Cu = Components.utils; |
|
10 |
|
11 const WEAVE_SYNC_PREFS = "services.sync.prefs.sync."; |
|
12 |
|
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"); |
|
20 |
|
21 const PREFS_GUID = CommonUtils.encodeBase64URL(Services.appinfo.ID); |
|
22 |
|
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 }; |
|
30 |
|
31 Utils.deferGetSet(PrefRec, "cleartext", ["value"]); |
|
32 |
|
33 |
|
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, |
|
43 |
|
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 }, |
|
51 |
|
52 _wipeClient: function _wipeClient() { |
|
53 SyncEngine.prototype._wipeClient.call(this); |
|
54 this.justWiped = true; |
|
55 }, |
|
56 |
|
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 }; |
|
66 |
|
67 |
|
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, |
|
76 |
|
77 __prefs: null, |
|
78 get _prefs() { |
|
79 if (!this.__prefs) |
|
80 this.__prefs = new Preferences(); |
|
81 return this.__prefs; |
|
82 }, |
|
83 |
|
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 }, |
|
93 |
|
94 _isSynced: function _isSyncedPref(pref) { |
|
95 return (pref.indexOf(WEAVE_SYNC_PREFS) == 0) |
|
96 || this._prefs.get(WEAVE_SYNC_PREFS + pref, false); |
|
97 }, |
|
98 |
|
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 }, |
|
109 |
|
110 _setAllPrefs: function PrefStore__setAllPrefs(values) { |
|
111 let enabledPref = "lightweightThemes.isThemeSelected"; |
|
112 let enabledBefore = this._prefs.get(enabledPref, false); |
|
113 let prevTheme = LightweightThemeManager.currentTheme; |
|
114 |
|
115 for (let [pref, value] in Iterator(values)) { |
|
116 if (!this._isSynced(pref)) |
|
117 continue; |
|
118 |
|
119 // Pref has gone missing, best we can do is reset it. |
|
120 if (value == null) { |
|
121 this._prefs.reset(pref); |
|
122 continue; |
|
123 } |
|
124 |
|
125 try { |
|
126 this._prefs.set(pref, value); |
|
127 } catch(ex) { |
|
128 this._log.trace("Failed to set pref: " + pref + ": " + ex); |
|
129 } |
|
130 } |
|
131 |
|
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 }, |
|
141 |
|
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 }, |
|
148 |
|
149 changeItemID: function PrefStore_changeItemID(oldID, newID) { |
|
150 this._log.trace("PrefStore GUID is constant!"); |
|
151 }, |
|
152 |
|
153 itemExists: function FormStore_itemExists(id) { |
|
154 return (id === PREFS_GUID); |
|
155 }, |
|
156 |
|
157 createRecord: function createRecord(id, collection) { |
|
158 let record = new PrefRec(collection, id); |
|
159 |
|
160 if (id == PREFS_GUID) { |
|
161 record.value = this._getAllPrefs(); |
|
162 } else { |
|
163 record.deleted = true; |
|
164 } |
|
165 |
|
166 return record; |
|
167 }, |
|
168 |
|
169 create: function PrefStore_create(record) { |
|
170 this._log.trace("Ignoring create request"); |
|
171 }, |
|
172 |
|
173 remove: function PrefStore_remove(record) { |
|
174 this._log.trace("Ignoring remove request"); |
|
175 }, |
|
176 |
|
177 update: function PrefStore_update(record) { |
|
178 // Silently ignore pref updates that are for other apps. |
|
179 if (record.id != PREFS_GUID) |
|
180 return; |
|
181 |
|
182 this._log.trace("Received pref updates, applying..."); |
|
183 this._setAllPrefs(record.value); |
|
184 }, |
|
185 |
|
186 wipe: function PrefStore_wipe() { |
|
187 this._log.trace("Ignoring wipe request"); |
|
188 } |
|
189 }; |
|
190 |
|
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, |
|
199 |
|
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 }, |
|
206 |
|
207 loadChangedIDs: function loadChangedIDs() { |
|
208 // Don't read changed IDs from disk at start up. |
|
209 }, |
|
210 |
|
211 clearChangedIDs: function clearChangedIDs() { |
|
212 this.modified = false; |
|
213 }, |
|
214 |
|
215 __prefs: null, |
|
216 get _prefs() { |
|
217 if (!this.__prefs) { |
|
218 this.__prefs = new Preferences(); |
|
219 } |
|
220 return this.__prefs; |
|
221 }, |
|
222 |
|
223 startTracking: function () { |
|
224 Services.prefs.addObserver("", this, false); |
|
225 }, |
|
226 |
|
227 stopTracking: function () { |
|
228 this.__prefs = null; |
|
229 Services.prefs.removeObserver("", this); |
|
230 }, |
|
231 |
|
232 observe: function (subject, topic, data) { |
|
233 Tracker.prototype.observe.call(this, subject, topic, data); |
|
234 |
|
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 }; |