b2g/chrome/content/settings.js

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:ddac26b9007d
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 "use strict;"
8
9 const Cc = Components.classes;
10 const Ci = Components.interfaces;
11 const Cu = Components.utils;
12 const Cr = Components.results;
13
14 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
15 Cu.import('resource://gre/modules/Services.jsm');
16
17 #ifdef MOZ_WIDGET_GONK
18 XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
19 Cu.import("resource://gre/modules/systemlibs.js");
20 return libcutils;
21 });
22 #endif
23
24 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
25 "@mozilla.org/uuid-generator;1",
26 "nsIUUIDGenerator");
27
28 // Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
29 // is resolved this helper could be removed.
30 var SettingsListener = {
31 _callbacks: {},
32
33 init: function sl_init() {
34 if ('mozSettings' in navigator && navigator.mozSettings) {
35 navigator.mozSettings.onsettingchange = this.onchange.bind(this);
36 }
37 },
38
39 onchange: function sl_onchange(evt) {
40 var callback = this._callbacks[evt.settingName];
41 if (callback) {
42 callback(evt.settingValue);
43 }
44 },
45
46 observe: function sl_observe(name, defaultValue, callback) {
47 var settings = window.navigator.mozSettings;
48 if (!settings) {
49 window.setTimeout(function() { callback(defaultValue); });
50 return;
51 }
52
53 if (!callback || typeof callback !== 'function') {
54 throw new Error('Callback is not a function');
55 }
56
57 var req = settings.createLock().get(name);
58 req.addEventListener('success', (function onsuccess() {
59 callback(typeof(req.result[name]) != 'undefined' ?
60 req.result[name] : defaultValue);
61 }));
62
63 this._callbacks[name] = callback;
64 }
65 };
66
67 SettingsListener.init();
68
69 // =================== Console ======================
70
71 SettingsListener.observe('debug.console.enabled', true, function(value) {
72 Services.prefs.setBoolPref('consoleservice.enabled', value);
73 Services.prefs.setBoolPref('layout.css.report_errors', value);
74 });
75
76 // =================== Languages ====================
77 SettingsListener.observe('language.current', 'en-US', function(value) {
78 Services.prefs.setCharPref('general.useragent.locale', value);
79
80 let prefName = 'intl.accept_languages';
81 if (Services.prefs.prefHasUserValue(prefName)) {
82 Services.prefs.clearUserPref(prefName);
83 }
84
85 let intl = '';
86 try {
87 intl = Services.prefs.getComplexValue(prefName,
88 Ci.nsIPrefLocalizedString).data;
89 } catch(e) {}
90
91 // Bug 830782 - Homescreen is in English instead of selected locale after
92 // the first run experience.
93 // In order to ensure the current intl value is reflected on the child
94 // process let's always write a user value, even if this one match the
95 // current localized pref value.
96 if (!((new RegExp('^' + value + '[^a-z-_] *[,;]?', 'i')).test(intl))) {
97 value = value + ', ' + intl;
98 } else {
99 value = intl;
100 }
101 Services.prefs.setCharPref(prefName, value);
102
103 if (shell.hasStarted() == false) {
104 shell.start();
105 }
106 });
107
108 // =================== RIL ====================
109 (function RILSettingsToPrefs() {
110 let strPrefs = ['ril.mms.mmsc', 'ril.mms.mmsproxy'];
111 strPrefs.forEach(function(key) {
112 SettingsListener.observe(key, "", function(value) {
113 Services.prefs.setCharPref(key, value);
114 });
115 });
116
117 ['ril.mms.mmsport'].forEach(function(key) {
118 SettingsListener.observe(key, null, function(value) {
119 if (value != null) {
120 Services.prefs.setIntPref(key, value);
121 }
122 });
123 });
124
125 // DSDS default service IDs
126 ['mms', 'sms', 'telephony', 'voicemail'].forEach(function(key) {
127 SettingsListener.observe('ril.' + key + '.defaultServiceId', 0,
128 function(value) {
129 if (value != null) {
130 Services.prefs.setIntPref('dom.' + key + '.defaultServiceId', value);
131 }
132 });
133 });
134 })();
135
136 //=================== DeviceInfo ====================
137 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
138 Components.utils.import('resource://gre/modules/ctypes.jsm');
139 (function DeviceInfoToSettings() {
140 // MOZ_B2G_VERSION is set in b2g/confvars.sh, and is output as a #define value
141 // from configure.in, defaults to 1.0.0 if this value is not exist.
142 #filter attemptSubstitution
143 let os_version = '@MOZ_B2G_VERSION@';
144 let os_name = '@MOZ_B2G_OS_NAME@';
145 #unfilter attemptSubstitution
146
147 let appInfo = Cc["@mozilla.org/xre/app-info;1"]
148 .getService(Ci.nsIXULAppInfo);
149
150 // Get the hardware info and firmware revision from device properties.
151 let hardware_info = null;
152 let firmware_revision = null;
153 let product_model = null;
154 #ifdef MOZ_WIDGET_GONK
155 hardware_info = libcutils.property_get('ro.hardware');
156 firmware_revision = libcutils.property_get('ro.firmware_revision');
157 product_model = libcutils.property_get('ro.product.model');
158 #endif
159
160 let software = os_name + ' ' + os_version;
161 let setting = {
162 'deviceinfo.os': os_version,
163 'deviceinfo.software': software,
164 'deviceinfo.platform_version': appInfo.platformVersion,
165 'deviceinfo.platform_build_id': appInfo.platformBuildID,
166 'deviceinfo.hardware': hardware_info,
167 'deviceinfo.firmware_revision': firmware_revision,
168 'deviceinfo.product_model': product_model
169 }
170 window.navigator.mozSettings.createLock().set(setting);
171 })();
172
173 // =================== DevTools ====================
174
175 let developerHUD;
176 SettingsListener.observe('devtools.overlay', false, (value) => {
177 if (value) {
178 if (!developerHUD) {
179 let scope = {};
180 Services.scriptloader.loadSubScript('chrome://b2g/content/devtools.js', scope);
181 developerHUD = scope.developerHUD;
182 }
183 developerHUD.init();
184 } else {
185 if (developerHUD) {
186 developerHUD.uninit();
187 }
188 }
189 });
190
191 // =================== Debugger / ADB ====================
192
193 #ifdef MOZ_WIDGET_GONK
194 let AdbController = {
195 DEBUG: false,
196 locked: undefined,
197 remoteDebuggerEnabled: undefined,
198 lockEnabled: undefined,
199 disableAdbTimer: null,
200 disableAdbTimeoutHours: 12,
201 umsActive: false,
202
203 debug: function(str) {
204 dump("AdbController: " + str + "\n");
205 },
206
207 setLockscreenEnabled: function(value) {
208 this.lockEnabled = value;
209 if (this.DEBUG) {
210 this.debug("setLockscreenEnabled = " + this.lockEnabled);
211 }
212 this.updateState();
213 },
214
215 setLockscreenState: function(value) {
216 this.locked = value;
217 if (this.DEBUG) {
218 this.debug("setLockscreenState = " + this.locked);
219 }
220 this.updateState();
221 },
222
223 setRemoteDebuggerState: function(value) {
224 this.remoteDebuggerEnabled = value;
225 if (this.DEBUG) {
226 this.debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled);
227 }
228 this.updateState();
229 },
230
231 startDisableAdbTimer: function() {
232 if (this.disableAdbTimer) {
233 this.disableAdbTimer.cancel();
234 } else {
235 this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
236 try {
237 this.disableAdbTimeoutHours =
238 Services.prefs.getIntPref("b2g.adb.timeout-hours");
239 } catch (e) {
240 // This happens if the pref doesn't exist, in which case
241 // disableAdbTimeoutHours will still be set to the default.
242 }
243 }
244 if (this.disableAdbTimeoutHours <= 0) {
245 if (this.DEBUG) {
246 this.debug("Timer to disable ADB not started due to zero timeout");
247 }
248 return;
249 }
250
251 if (this.DEBUG) {
252 this.debug("Starting timer to disable ADB in " +
253 this.disableAdbTimeoutHours + " hours");
254 }
255 let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000;
256 this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds,
257 Ci.nsITimer.TYPE_ONE_SHOT);
258 },
259
260 stopDisableAdbTimer: function() {
261 if (this.DEBUG) {
262 this.debug("Stopping timer to disable ADB");
263 }
264 if (this.disableAdbTimer) {
265 this.disableAdbTimer.cancel();
266 this.disableAdbTimer = null;
267 }
268 },
269
270 notify: function(aTimer) {
271 if (aTimer == this.disableAdbTimer) {
272 this.disableAdbTimer = null;
273 // The following dump will be the last thing that shows up in logcat,
274 // and will at least give the user a clue about why logcat was
275 // disconnected, if the user happens to be using logcat.
276 dump("AdbController: ADB timer expired - disabling ADB\n");
277 navigator.mozSettings.createLock().set(
278 {'devtools.debugger.remote-enabled': false});
279 }
280 },
281
282 updateState: function() {
283 this.umsActive = false;
284 this.storages = navigator.getDeviceStorages('sdcard');
285 this.updateStorageState(0);
286 },
287
288 updateStorageState: function(storageIndex) {
289 if (storageIndex >= this.storages.length) {
290 // We've iterated through all of the storage objects, now we can
291 // really do updateStateInternal.
292 this.updateStateInternal();
293 return;
294 }
295 let storage = this.storages[storageIndex];
296 if (this.DEBUG) {
297 this.debug("Checking availability of storage: '" +
298 storage.storageName);
299 }
300
301 let req = storage.available();
302 req.onsuccess = function(e) {
303 if (this.DEBUG) {
304 this.debug("Storage: '" + storage.storageName + "' is '" +
305 e.target.result);
306 }
307 if (e.target.result == 'shared') {
308 // We've found a storage area that's being shared with the PC.
309 // We can stop looking now.
310 this.umsActive = true;
311 this.updateStateInternal();
312 return;
313 }
314 this.updateStorageState(storageIndex + 1);
315 }.bind(this);
316 req.onerror = function(e) {
317 dump("AdbController: error querying storage availability for '" +
318 this.storages[storageIndex].storageName + "' (ignoring)\n");
319 this.updateStorageState(storageIndex + 1);
320 }.bind(this);
321 },
322
323 updateStateInternal: function() {
324 if (this.DEBUG) {
325 this.debug("updateStateInternal: called");
326 }
327
328 if (this.remoteDebuggerEnabled === undefined ||
329 this.lockEnabled === undefined ||
330 this.locked === undefined) {
331 // Part of initializing the settings database will cause the observers
332 // to trigger. We want to wait until both have been initialized before
333 // we start changing ther adb state. Without this then we can wind up
334 // toggling adb off and back on again (or on and back off again).
335 //
336 // For completeness, one scenario which toggles adb is using the unagi.
337 // The unagi has adb enabled by default (prior to b2g starting). If you
338 // have the phone lock disabled and remote debugging enabled, then we'll
339 // receive an unlock event and an rde event. However at the time we
340 // receive the unlock event we haven't yet received the rde event, so
341 // we turn adb off momentarily, which disconnects a logcat that might
342 // be running. Changing the defaults (in AdbController) just moves the
343 // problem to a different phone, which has adb disabled by default and
344 // we wind up turning on adb for a short period when we shouldn't.
345 //
346 // By waiting until both values are properly initialized, we avoid
347 // turning adb on or off accidentally.
348 if (this.DEBUG) {
349 this.debug("updateState: Waiting for all vars to be initialized");
350 }
351 return;
352 }
353
354 // Check if we have a remote debugging session going on. If so, we won't
355 // disable adb even if the screen is locked.
356 let isDebugging = RemoteDebugger.isDebugging;
357 if (this.DEBUG) {
358 this.debug("isDebugging=" + isDebugging);
359 }
360
361 // If USB Mass Storage, USB tethering, or a debug session is active,
362 // then we don't want to disable adb in an automatic fashion (i.e.
363 // when the screen locks or due to timeout).
364 let sysUsbConfig = libcutils.property_get("sys.usb.config");
365 let rndisActive = (sysUsbConfig.split(",").indexOf("rndis") >= 0);
366 let usbFuncActive = rndisActive || this.umsActive || isDebugging;
367
368 let enableAdb = this.remoteDebuggerEnabled &&
369 (!(this.lockEnabled && this.locked) || usbFuncActive);
370
371 let useDisableAdbTimer = true;
372 try {
373 if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
374 // Marionette is enabled. Marionette requires that adb be on (and also
375 // requires that remote debugging be off). The fact that marionette
376 // is enabled also implies that we're doing a non-production build, so
377 // we want adb enabled all of the time.
378 enableAdb = true;
379 useDisableAdbTimer = false;
380 }
381 } catch (e) {
382 // This means that the pref doesn't exist. Which is fine. We just leave
383 // enableAdb alone.
384 }
385 if (this.DEBUG) {
386 this.debug("updateState: enableAdb = " + enableAdb +
387 " remoteDebuggerEnabled = " + this.remoteDebuggerEnabled +
388 " lockEnabled = " + this.lockEnabled +
389 " locked = " + this.locked +
390 " usbFuncActive = " + usbFuncActive);
391 }
392
393 // Configure adb.
394 let currentConfig = libcutils.property_get("persist.sys.usb.config");
395 let configFuncs = currentConfig.split(",");
396 let adbIndex = configFuncs.indexOf("adb");
397
398 if (enableAdb) {
399 // Add adb to the list of functions, if not already present
400 if (adbIndex < 0) {
401 configFuncs.push("adb");
402 }
403 } else {
404 // Remove adb from the list of functions, if present
405 if (adbIndex >= 0) {
406 configFuncs.splice(adbIndex, 1);
407 }
408 }
409 let newConfig = configFuncs.join(",");
410 if (newConfig != currentConfig) {
411 if (this.DEBUG) {
412 this.debug("updateState: currentConfig = " + currentConfig);
413 this.debug("updateState: newConfig = " + newConfig);
414 }
415 try {
416 libcutils.property_set("persist.sys.usb.config", newConfig);
417 } catch(e) {
418 dump("Error configuring adb: " + e);
419 }
420 }
421 if (useDisableAdbTimer) {
422 if (enableAdb && !usbFuncActive) {
423 this.startDisableAdbTimer();
424 } else {
425 this.stopDisableAdbTimer();
426 }
427 }
428 }
429 };
430
431 SettingsListener.observe("lockscreen.locked", false,
432 AdbController.setLockscreenState.bind(AdbController));
433 SettingsListener.observe("lockscreen.enabled", false,
434 AdbController.setLockscreenEnabled.bind(AdbController));
435 #endif
436
437 // Keep the old setting to not break people that won't have updated
438 // gaia and gecko.
439 SettingsListener.observe('devtools.debugger.remote-enabled', false, function(value) {
440 Services.prefs.setBoolPref('devtools.debugger.remote-enabled', value);
441 // This preference is consulted during startup
442 Services.prefs.savePrefFile(null);
443 try {
444 value ? RemoteDebugger.start() : RemoteDebugger.stop();
445 } catch(e) {
446 dump("Error while initializing devtools: " + e + "\n" + e.stack + "\n");
447 }
448
449 #ifdef MOZ_WIDGET_GONK
450 AdbController.setRemoteDebuggerState(value);
451 #endif
452 });
453
454 SettingsListener.observe('debugger.remote-mode', false, function(value) {
455 if (['disabled', 'adb-only', 'adb-devtools'].indexOf(value) == -1) {
456 dump('Illegal value for debugger.remote-mode: ' + value + '\n');
457 return;
458 }
459
460 Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
461 value == 'adb-devtools');
462 // This preference is consulted during startup
463 Services.prefs.savePrefFile(null);
464
465 try {
466 (value == 'adb-devtools') ? RemoteDebugger.start()
467 : RemoteDebugger.stop();
468 } catch(e) {
469 dump("Error while initializing devtools: " + e + "\n" + e.stack + "\n");
470 }
471
472 #ifdef MOZ_WIDGET_GONK
473 AdbController.setRemoteDebuggerState(value != 'disabled');
474 #endif
475 });
476
477 // =================== Device Storage ====================
478 SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) {
479 if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) {
480 // We clear the pref because it used to be erroneously written as a bool
481 // and we need to clear it before we can change it to have the correct type.
482 Services.prefs.clearUserPref('device.storage.writable.name');
483 }
484 Services.prefs.setCharPref('device.storage.writable.name', value);
485 });
486
487 // =================== Privacy ====================
488 SettingsListener.observe('privacy.donottrackheader.value', 1, function(value) {
489 Services.prefs.setIntPref('privacy.donottrackheader.value', value);
490 // If the user specifically disallows tracking, we set the value of
491 // app.update.custom (update tracking ID) to an empty string.
492 if (value == 1) {
493 Services.prefs.setCharPref('app.update.custom', '');
494 return;
495 }
496 // Otherwise, we assure that the update tracking ID exists.
497 setUpdateTrackingId();
498 });
499
500 // =================== Crash Reporting ====================
501 SettingsListener.observe('app.reportCrashes', 'ask', function(value) {
502 if (value == 'always') {
503 Services.prefs.setBoolPref('app.reportCrashes', true);
504 } else if (value == 'never') {
505 Services.prefs.setBoolPref('app.reportCrashes', false);
506 } else {
507 Services.prefs.clearUserPref('app.reportCrashes');
508 }
509 // This preference is consulted during startup.
510 Services.prefs.savePrefFile(null);
511 });
512
513 // ================ Updates ================
514 /**
515 * For tracking purposes some partners require us to add an UUID to the
516 * update URL. The update tracking ID will be an empty string if the
517 * do-not-track feature specifically disallows tracking and it is reseted
518 * to a different ID if the do-not-track value changes from disallow to allow.
519 */
520 function setUpdateTrackingId() {
521 try {
522 let dntEnabled = Services.prefs.getBoolPref('privacy.donottrackheader.enabled');
523 let dntValue = Services.prefs.getIntPref('privacy.donottrackheader.value');
524 // If the user specifically decides to disallow tracking (1), we just bail out.
525 if (dntEnabled && (dntValue == 1)) {
526 return;
527 }
528
529 let trackingId =
530 Services.prefs.getPrefType('app.update.custom') ==
531 Ci.nsIPrefBranch.PREF_STRING &&
532 Services.prefs.getCharPref('app.update.custom');
533
534 // If there is no previous registered tracking ID, we generate a new one.
535 // This should only happen on first usage or after changing the
536 // do-not-track value from disallow to allow.
537 if (!trackingId) {
538 trackingId = uuidgen.generateUUID().toString().replace(/[{}]/g, "");
539 Services.prefs.setCharPref('app.update.custom', trackingId);
540 }
541 } catch(e) {
542 dump('Error getting tracking ID ' + e + '\n');
543 }
544 }
545 setUpdateTrackingId();
546
547
548 // ================ Debug ================
549 (function Composer2DSettingToPref() {
550 //layers.composer.enabled can be enabled in three ways
551 //In order of precedence they are:
552 //
553 //1. mozSettings "layers.composer.enabled"
554 //2. a gecko pref "layers.composer.enabled"
555 //3. presence of ro.display.colorfill at the Gonk level
556
557 var req = navigator.mozSettings.createLock().get('layers.composer2d.enabled');
558 req.onsuccess = function() {
559 if (typeof(req.result['layers.composer2d.enabled']) === 'undefined') {
560 var enabled = false;
561 if (Services.prefs.getPrefType('layers.composer2d.enabled') == Ci.nsIPrefBranch.PREF_BOOL) {
562 enabled = Services.prefs.getBoolPref('layers.composer2d.enabled');
563 } else {
564 #ifdef MOZ_WIDGET_GONK
565 enabled = (libcutils.property_get('ro.display.colorfill') === '1');
566 #endif
567 }
568 navigator.mozSettings.createLock().set({'layers.composer2d.enabled': enabled });
569 }
570
571 SettingsListener.observe("layers.composer2d.enabled", true, function(value) {
572 Services.prefs.setBoolPref("layers.composer2d.enabled", value);
573 });
574 };
575 req.onerror = function() {
576 dump("Error configuring layers.composer2d.enabled setting");
577 };
578
579 })();
580
581 // ================ Accessibility ============
582 SettingsListener.observe("accessibility.screenreader", false, function(value) {
583 if (value && !("AccessFu" in this)) {
584 Cu.import('resource://gre/modules/accessibility/AccessFu.jsm');
585 AccessFu.attach(window);
586 }
587 });
588
589 // ================ Theming ============
590 (function themingSettingsListener() {
591 let themingPrefs = ['ui.menu', 'ui.menutext', 'ui.infobackground', 'ui.infotext',
592 'ui.window', 'ui.windowtext', 'ui.highlight'];
593
594 themingPrefs.forEach(function(pref) {
595 SettingsListener.observe('gaia.' + pref, null, function(value) {
596 if (value) {
597 Services.prefs.setCharPref(pref, value);
598 }
599 });
600 });
601 })();
602
603 // =================== AsyncPanZoom ======================
604 SettingsListener.observe('apz.displayport.heuristics', 'default', function(value) {
605 // first reset everything to default
606 Services.prefs.clearUserPref('apz.velocity_bias');
607 Services.prefs.clearUserPref('apz.use_paint_duration');
608 Services.prefs.clearUserPref('apz.x_skate_size_multiplier');
609 Services.prefs.clearUserPref('apz.y_skate_size_multiplier');
610 Services.prefs.clearUserPref('apz.allow-checkerboarding');
611 // and then set the things that we want to change
612 switch (value) {
613 case 'default':
614 break;
615 case 'center-displayport':
616 Services.prefs.setCharPref('apz.velocity_bias', '0.0');
617 break;
618 case 'perfect-paint-times':
619 Services.prefs.setBoolPref('apz.use_paint_duration', false);
620 Services.prefs.setCharPref('apz.velocity_bias', '0.32'); // 16/50 (assumes 16ms paint times instead of 50ms)
621 break;
622 case 'taller-displayport':
623 Services.prefs.setCharPref('apz.y_skate_size_multiplier', '3.5');
624 break;
625 case 'faster-paint':
626 Services.prefs.setCharPref('apz.x_skate_size_multiplier', '1.0');
627 Services.prefs.setCharPref('apz.y_skate_size_multiplier', '1.5');
628 break;
629 case 'no-checkerboard':
630 Services.prefs.setBoolPref('apz.allow-checkerboarding', false);
631 break;
632 }
633 });
634
635 // =================== Various simple mapping ======================
636 let settingsToObserve = {
637 'ril.mms.retrieval_mode': {
638 prefName: 'dom.mms.retrieval_mode',
639 defaultValue: 'manual'
640 },
641 'ril.sms.strict7BitEncoding.enabled': {
642 prefName: 'dom.sms.strict7BitEncoding',
643 defaultValue: false
644 },
645 'ril.sms.requestStatusReport.enabled': {
646 prefName: 'dom.sms.requestStatusReport',
647 defaultValue: false
648 },
649 'ril.mms.requestStatusReport.enabled': {
650 prefName: 'dom.mms.requestStatusReport',
651 defaultValue: false
652 },
653 'ril.mms.requestReadReport.enabled': {
654 prefName: 'dom.mms.requestReadReport',
655 defaultValue: true
656 },
657 'ril.cellbroadcast.disabled': false,
658 'ril.radio.disabled': false,
659 'wap.UAProf.url': '',
660 'wap.UAProf.tagname': 'x-wap-profile',
661 'devtools.eventlooplag.threshold': 100,
662 'privacy.donottrackheader.enabled': false,
663 'apz.force-enable': {
664 prefName: 'dom.browser_frames.useAsyncPanZoom',
665 defaultValue: false
666 },
667 'layers.enable-tiles': true,
668 'layers.simple-tiles': false,
669 'layers.progressive-paint': false,
670 'layers.draw-tile-borders': false,
671 'layers.dump': false,
672 'debug.fps.enabled': {
673 prefName: 'layers.acceleration.draw-fps',
674 defaultValue: false
675 },
676 'debug.paint-flashing.enabled': {
677 prefName: 'nglayout.debug.paint_flashing',
678 defaultValue: false
679 },
680 'layers.draw-borders': false,
681 'app.update.interval': 86400,
682 'app.update.url': {
683 resetToPref: true
684 },
685 'app.update.channel': {
686 resetToPref: true
687 },
688 'debug.log-animations.enabled': {
689 prefName: 'layers.offmainthreadcomposition.log-animations',
690 defaultValue: false
691 }
692 };
693
694 for (let key in settingsToObserve) {
695 let setting = settingsToObserve[key];
696
697 // Allow setting to contain flags redefining prefName and defaultValue.
698 let prefName = setting.prefName || key;
699 let defaultValue = setting.defaultValue;
700 if (defaultValue === undefined) {
701 defaultValue = setting;
702 }
703
704 let prefs = Services.prefs;
705
706 // If requested, reset setting value and defaultValue to the pref value.
707 if (setting.resetToPref) {
708 switch (prefs.getPrefType(prefName)) {
709 case Ci.nsIPrefBranch.PREF_BOOL:
710 defaultValue = prefs.getBoolPref(prefName);
711 break;
712
713 case Ci.nsIPrefBranch.PREF_INT:
714 defaultValue = prefs.getIntPref(prefName);
715 break;
716
717 case Ci.nsIPrefBranch.PREF_STRING:
718 defaultValue = prefs.getCharPref(prefName);
719 break;
720 }
721
722 let setting = {};
723 setting[key] = defaultValue;
724 window.navigator.mozSettings.createLock().set(setting);
725 }
726
727 // Figure out the right setter function for this type of pref.
728 let setPref;
729 switch (typeof defaultValue) {
730 case 'boolean':
731 setPref = prefs.setBoolPref.bind(prefs);
732 break;
733
734 case 'number':
735 setPref = prefs.setIntPref.bind(prefs);
736 break;
737
738 case 'string':
739 setPref = prefs.setCharPref.bind(prefs);
740 break;
741 }
742
743 SettingsListener.observe(key, defaultValue, function(value) {
744 setPref(prefName, value);
745 });
746 };
747

mercurial