services/sync/modules/engines/prefs.js

changeset 0
6474c204b198
     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 +};

mercurial