1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/sync/modules/engines/prefs.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,251 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +this.EXPORTED_SYMBOLS = ['PrefsEngine', 'PrefRec']; 1.9 + 1.10 +const Cc = Components.classes; 1.11 +const Ci = Components.interfaces; 1.12 +const Cu = Components.utils; 1.13 + 1.14 +const WEAVE_SYNC_PREFS = "services.sync.prefs.sync."; 1.15 + 1.16 +Cu.import("resource://services-sync/engines.js"); 1.17 +Cu.import("resource://services-sync/record.js"); 1.18 +Cu.import("resource://services-sync/util.js"); 1.19 +Cu.import("resource://services-sync/constants.js"); 1.20 +Cu.import("resource://services-common/utils.js"); 1.21 +Cu.import("resource://gre/modules/LightweightThemeManager.jsm"); 1.22 +Cu.import("resource://gre/modules/Preferences.jsm"); 1.23 + 1.24 +const PREFS_GUID = CommonUtils.encodeBase64URL(Services.appinfo.ID); 1.25 + 1.26 +this.PrefRec = function PrefRec(collection, id) { 1.27 + CryptoWrapper.call(this, collection, id); 1.28 +} 1.29 +PrefRec.prototype = { 1.30 + __proto__: CryptoWrapper.prototype, 1.31 + _logName: "Sync.Record.Pref", 1.32 +}; 1.33 + 1.34 +Utils.deferGetSet(PrefRec, "cleartext", ["value"]); 1.35 + 1.36 + 1.37 +this.PrefsEngine = function PrefsEngine(service) { 1.38 + SyncEngine.call(this, "Prefs", service); 1.39 +} 1.40 +PrefsEngine.prototype = { 1.41 + __proto__: SyncEngine.prototype, 1.42 + _storeObj: PrefStore, 1.43 + _trackerObj: PrefTracker, 1.44 + _recordObj: PrefRec, 1.45 + version: 2, 1.46 + 1.47 + getChangedIDs: function getChangedIDs() { 1.48 + // No need for a proper timestamp (no conflict resolution needed). 1.49 + let changedIDs = {}; 1.50 + if (this._tracker.modified) 1.51 + changedIDs[PREFS_GUID] = 0; 1.52 + return changedIDs; 1.53 + }, 1.54 + 1.55 + _wipeClient: function _wipeClient() { 1.56 + SyncEngine.prototype._wipeClient.call(this); 1.57 + this.justWiped = true; 1.58 + }, 1.59 + 1.60 + _reconcile: function _reconcile(item) { 1.61 + // Apply the incoming item if we don't care about the local data 1.62 + if (this.justWiped) { 1.63 + this.justWiped = false; 1.64 + return true; 1.65 + } 1.66 + return SyncEngine.prototype._reconcile.call(this, item); 1.67 + } 1.68 +}; 1.69 + 1.70 + 1.71 +function PrefStore(name, engine) { 1.72 + Store.call(this, name, engine); 1.73 + Svc.Obs.add("profile-before-change", function () { 1.74 + this.__prefs = null; 1.75 + }, this); 1.76 +} 1.77 +PrefStore.prototype = { 1.78 + __proto__: Store.prototype, 1.79 + 1.80 + __prefs: null, 1.81 + get _prefs() { 1.82 + if (!this.__prefs) 1.83 + this.__prefs = new Preferences(); 1.84 + return this.__prefs; 1.85 + }, 1.86 + 1.87 + _getSyncPrefs: function _getSyncPrefs() { 1.88 + let syncPrefs = Cc["@mozilla.org/preferences-service;1"] 1.89 + .getService(Ci.nsIPrefService) 1.90 + .getBranch(WEAVE_SYNC_PREFS) 1.91 + .getChildList("", {}); 1.92 + // Also sync preferences that determine which prefs get synced. 1.93 + return syncPrefs.concat( 1.94 + syncPrefs.map(function (pref) { return WEAVE_SYNC_PREFS + pref; })); 1.95 + }, 1.96 + 1.97 + _isSynced: function _isSyncedPref(pref) { 1.98 + return (pref.indexOf(WEAVE_SYNC_PREFS) == 0) 1.99 + || this._prefs.get(WEAVE_SYNC_PREFS + pref, false); 1.100 + }, 1.101 + 1.102 + _getAllPrefs: function () { 1.103 + let values = {}; 1.104 + for each (let pref in this._getSyncPrefs()) { 1.105 + if (this._isSynced(pref)) { 1.106 + // Missing prefs get the null value. 1.107 + values[pref] = this._prefs.get(pref, null); 1.108 + } 1.109 + } 1.110 + return values; 1.111 + }, 1.112 + 1.113 + _setAllPrefs: function PrefStore__setAllPrefs(values) { 1.114 + let enabledPref = "lightweightThemes.isThemeSelected"; 1.115 + let enabledBefore = this._prefs.get(enabledPref, false); 1.116 + let prevTheme = LightweightThemeManager.currentTheme; 1.117 + 1.118 + for (let [pref, value] in Iterator(values)) { 1.119 + if (!this._isSynced(pref)) 1.120 + continue; 1.121 + 1.122 + // Pref has gone missing, best we can do is reset it. 1.123 + if (value == null) { 1.124 + this._prefs.reset(pref); 1.125 + continue; 1.126 + } 1.127 + 1.128 + try { 1.129 + this._prefs.set(pref, value); 1.130 + } catch(ex) { 1.131 + this._log.trace("Failed to set pref: " + pref + ": " + ex); 1.132 + } 1.133 + } 1.134 + 1.135 + // Notify the lightweight theme manager of all the new values 1.136 + let enabledNow = this._prefs.get(enabledPref, false); 1.137 + if (enabledBefore && !enabledNow) { 1.138 + LightweightThemeManager.currentTheme = null; 1.139 + } else if (enabledNow && LightweightThemeManager.usedThemes[0] != prevTheme) { 1.140 + LightweightThemeManager.currentTheme = null; 1.141 + LightweightThemeManager.currentTheme = LightweightThemeManager.usedThemes[0]; 1.142 + } 1.143 + }, 1.144 + 1.145 + getAllIDs: function PrefStore_getAllIDs() { 1.146 + /* We store all prefs in just one WBO, with just one GUID */ 1.147 + let allprefs = {}; 1.148 + allprefs[PREFS_GUID] = true; 1.149 + return allprefs; 1.150 + }, 1.151 + 1.152 + changeItemID: function PrefStore_changeItemID(oldID, newID) { 1.153 + this._log.trace("PrefStore GUID is constant!"); 1.154 + }, 1.155 + 1.156 + itemExists: function FormStore_itemExists(id) { 1.157 + return (id === PREFS_GUID); 1.158 + }, 1.159 + 1.160 + createRecord: function createRecord(id, collection) { 1.161 + let record = new PrefRec(collection, id); 1.162 + 1.163 + if (id == PREFS_GUID) { 1.164 + record.value = this._getAllPrefs(); 1.165 + } else { 1.166 + record.deleted = true; 1.167 + } 1.168 + 1.169 + return record; 1.170 + }, 1.171 + 1.172 + create: function PrefStore_create(record) { 1.173 + this._log.trace("Ignoring create request"); 1.174 + }, 1.175 + 1.176 + remove: function PrefStore_remove(record) { 1.177 + this._log.trace("Ignoring remove request"); 1.178 + }, 1.179 + 1.180 + update: function PrefStore_update(record) { 1.181 + // Silently ignore pref updates that are for other apps. 1.182 + if (record.id != PREFS_GUID) 1.183 + return; 1.184 + 1.185 + this._log.trace("Received pref updates, applying..."); 1.186 + this._setAllPrefs(record.value); 1.187 + }, 1.188 + 1.189 + wipe: function PrefStore_wipe() { 1.190 + this._log.trace("Ignoring wipe request"); 1.191 + } 1.192 +}; 1.193 + 1.194 +function PrefTracker(name, engine) { 1.195 + Tracker.call(this, name, engine); 1.196 + Svc.Obs.add("profile-before-change", this); 1.197 + Svc.Obs.add("weave:engine:start-tracking", this); 1.198 + Svc.Obs.add("weave:engine:stop-tracking", this); 1.199 +} 1.200 +PrefTracker.prototype = { 1.201 + __proto__: Tracker.prototype, 1.202 + 1.203 + get modified() { 1.204 + return Svc.Prefs.get("engine.prefs.modified", false); 1.205 + }, 1.206 + set modified(value) { 1.207 + Svc.Prefs.set("engine.prefs.modified", value); 1.208 + }, 1.209 + 1.210 + loadChangedIDs: function loadChangedIDs() { 1.211 + // Don't read changed IDs from disk at start up. 1.212 + }, 1.213 + 1.214 + clearChangedIDs: function clearChangedIDs() { 1.215 + this.modified = false; 1.216 + }, 1.217 + 1.218 + __prefs: null, 1.219 + get _prefs() { 1.220 + if (!this.__prefs) { 1.221 + this.__prefs = new Preferences(); 1.222 + } 1.223 + return this.__prefs; 1.224 + }, 1.225 + 1.226 + startTracking: function () { 1.227 + Services.prefs.addObserver("", this, false); 1.228 + }, 1.229 + 1.230 + stopTracking: function () { 1.231 + this.__prefs = null; 1.232 + Services.prefs.removeObserver("", this); 1.233 + }, 1.234 + 1.235 + observe: function (subject, topic, data) { 1.236 + Tracker.prototype.observe.call(this, subject, topic, data); 1.237 + 1.238 + switch (topic) { 1.239 + case "profile-before-change": 1.240 + this.stopTracking(); 1.241 + break; 1.242 + case "nsPref:changed": 1.243 + // Trigger a sync for MULTI-DEVICE for a change that determines 1.244 + // which prefs are synced or a regular pref change. 1.245 + if (data.indexOf(WEAVE_SYNC_PREFS) == 0 || 1.246 + this._prefs.get(WEAVE_SYNC_PREFS + data, false)) { 1.247 + this.score += SCORE_INCREMENT_XLARGE; 1.248 + this.modified = true; 1.249 + this._log.trace("Preference " + data + " changed"); 1.250 + } 1.251 + break; 1.252 + } 1.253 + } 1.254 +};