Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
615 lines
19 KiB
JavaScript
615 lines
19 KiB
JavaScript
/* jshint loopfunc: true */
|
|
/* global Service, SettingsListener, applications,
|
|
UtilityTray, MozActivity */
|
|
|
|
'use strict';
|
|
|
|
(function(exports) {
|
|
|
|
function QuickSettings() {}
|
|
|
|
QuickSettings.prototype = {
|
|
/**
|
|
* Indicate setting status of geolocation.enabled
|
|
* @memberof QuickSettings.prototype
|
|
* @type {Boolean}
|
|
*/
|
|
geolocationEnabled: false,
|
|
|
|
/**
|
|
* Timeout to wait for a wifi auto-connect.
|
|
* @memberof QuickSettings.prototype
|
|
* @type {Integer}
|
|
*/
|
|
WIFI_STATUSCHANGE_TIMEOUT: 2000,
|
|
|
|
/**
|
|
* Indicate setting status of airplane mode
|
|
* @memberof QuickSettings.prototype
|
|
* @type {Boolean}
|
|
*/
|
|
airplaneModeSwitching: false,
|
|
|
|
/**
|
|
* ID of elements to create references
|
|
* @memberof QuickSettings.prototype
|
|
* @type {Array}
|
|
*/
|
|
ELEMENTS: ['wifi', 'data', 'bluetooth', 'airplane-mode', 'full-app'],
|
|
|
|
/**
|
|
* Setting key for the roaming dialog.
|
|
* @memberof QuickSettings.prototype
|
|
* @type {String}
|
|
*/
|
|
WARNING_DIALOG_ENABLED_KEY:
|
|
'ril.data.roaming_enabled.warningDialog.enabled',
|
|
|
|
/**
|
|
* Setting key for data enabled.
|
|
* @memberof QuickSettings.prototype
|
|
* @type {String}
|
|
*/
|
|
DATA_KEY: 'ril.data.enabled',
|
|
|
|
/**
|
|
* Setting key for data roaming enabled.
|
|
* @memberof QuickSettings.prototype
|
|
* @type {String}
|
|
*/
|
|
DATA_ROAMING_KEY: 'ril.data.roaming_enabled',
|
|
|
|
/**
|
|
* Settings states.
|
|
* @memberof QuickSettings.prototype
|
|
* @type {Object}
|
|
*/
|
|
settings: {
|
|
wifi: false,
|
|
airplaneMode: false,
|
|
data: false,
|
|
bluetooth: false
|
|
},
|
|
|
|
/**
|
|
* Starts listening for events.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
start: function qs_init() {
|
|
var settings = window.navigator.mozSettings;
|
|
if (!settings) {
|
|
return;
|
|
}
|
|
|
|
this.getAllElements();
|
|
this.monitorDataChange();
|
|
|
|
window.addEventListener('dataiconchanged', this);
|
|
this._handle_dataiconchanged();
|
|
|
|
this.overlay.addEventListener('click', this);
|
|
window.addEventListener('utilitytrayshow', this);
|
|
|
|
this.monitorBluetoothChange();
|
|
this.monitorWifiChange();
|
|
this.monitorGeoChange();
|
|
this.monitorAirplaneModeChange();
|
|
},
|
|
|
|
_handle_dataiconchanged: function() {
|
|
var networkTypeValues = Service.query('dataIcon');
|
|
if (!networkTypeValues) {
|
|
return;
|
|
}
|
|
var sprite = networkTypeValues.data_sprite;
|
|
if (sprite) {
|
|
document.getElementById('quick-settings-data')
|
|
.style.backgroundImage = 'url("' + sprite + '")';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Monitors current connectivity and updates the icon.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
monitorDataChange: function() {
|
|
var conns = window.navigator.mozMobileConnections;
|
|
|
|
if (!conns) {
|
|
// hide data icon without mozMobileConnection object
|
|
this.overlay.classList.add('non-mobile');
|
|
} else {
|
|
var LABEL_TO_ICON = {
|
|
'4G': '4g',
|
|
'H+': 'hspa-plus',
|
|
'H': 'hspa',
|
|
'3G': '3g',
|
|
'E': 'edge',
|
|
'2G': '2g',
|
|
'undefined': 'data'
|
|
};
|
|
var label = {
|
|
'lte': '4G', // 4G LTE
|
|
'ehrpd': '4G', // 4G CDMA
|
|
'hspa+': 'H+', // 3.5G HSPA+
|
|
'hsdpa': 'H',
|
|
'hsupa': 'H',
|
|
'hspa': 'H', // 3.5G HSDPA
|
|
// 3G CDMA
|
|
'evdo0': '3G',
|
|
'evdoa': '3G',
|
|
'evdob': '3G',
|
|
'1xrtt': '3G',
|
|
'umts': '3G', // 3G
|
|
'edge': 'E', // EDGE
|
|
'is95a': '2G',
|
|
'is95b': '2G', // 2G CDMA
|
|
'gprs': '2G'
|
|
};
|
|
|
|
for (var i = 0; i < conns.length; i++) {
|
|
var conn = conns[i];
|
|
conn.addEventListener('datachange', function qs_onDataChange() {
|
|
var dataType;
|
|
// if there is any data connection got established,
|
|
// we would just use that
|
|
for (var j = 0; j < conns.length; j++) {
|
|
dataType = label[conns[j].data.type] || dataType;
|
|
}
|
|
this.data.dataset.network = dataType;
|
|
this.data.dataset.icon = LABEL_TO_ICON[String(dataType)];
|
|
this.setAccessibilityAttributes(this.data, 'dataButton', dataType);
|
|
}.bind(this));
|
|
}
|
|
|
|
/*
|
|
* monitor data setting
|
|
* TODO prevent quickly tapping on it
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
SettingsListener.observe('ril.data.enabled', true, function(value) {
|
|
this.setSettingEnabled('data', value);
|
|
this.setAccessibilityAttributes(this.data, 'dataButton',
|
|
this.data.dataset.network);
|
|
}.bind(this));
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Monitor bluetooth setting and initialization/disable ready event
|
|
* - when settings changed, update UI and lock toogle to prevent quickly
|
|
* tapping on it.
|
|
* - when got bluetooth initialization/disable ready, active toogle, so
|
|
* return the control to user.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
monitorBluetoothChange: function() {
|
|
// Bluetooth module is loaded after quicksettings.
|
|
window.addEventListener('bluetooth-enabled', this);
|
|
window.addEventListener('bluetooth-disabled', this);
|
|
},
|
|
|
|
/**
|
|
* Monitor wifi setting and initialization/disable ready event
|
|
* - when settings changed, update UI and lock toogle to prevent quickly
|
|
* tapping on it.
|
|
* - when got bluetooth initialization/disable ready, active toogle, so
|
|
* return the control to user.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
monitorWifiChange: function() {
|
|
var self = this;
|
|
var wifiFirstSet = true;
|
|
SettingsListener.observe('wifi.enabled', true, function(value) {
|
|
if (self.settings.wifi === value) {
|
|
return;
|
|
}
|
|
|
|
self.setSettingEnabled('wifi', value);
|
|
// Set to the initializing state to block user interaction until the
|
|
// operation completes. (unless we are being called for the first time,
|
|
// where Wifi is already initialize
|
|
if (!wifiFirstSet) {
|
|
self.wifi.dataset.initializing = 'true';
|
|
}
|
|
wifiFirstSet = false;
|
|
|
|
self.setAccessibilityAttributes(self.wifi, 'wifiButton');
|
|
});
|
|
window.addEventListener('wifi-enabled', this);
|
|
window.addEventListener('wifi-disabled', this);
|
|
window.addEventListener('wifi-statuschange', this);
|
|
},
|
|
|
|
/**
|
|
* Monitor geolocation setting
|
|
* TODO prevent quickly tapping on it
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
monitorGeoChange: function() {
|
|
var self = this;
|
|
SettingsListener.observe('geolocation.enabled', true, function(value) {
|
|
self.geolocationEnabled = value;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Monitor airplane mode setting
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
monitorAirplaneModeChange: function() {
|
|
var self = this;
|
|
SettingsListener.observe('airplaneMode.status', false, function(value) {
|
|
delete self.airplaneMode.dataset.enabling;
|
|
delete self.airplaneMode.dataset.disabling;
|
|
// reset airplaneModeSwitching
|
|
self.airplaneModeSwitching = false;
|
|
|
|
self.data.dataset.airplaneMode = (value === 'enabled');
|
|
switch (value) {
|
|
case 'enabled':
|
|
self.data.classList.add('quick-settings-airplane-mode');
|
|
self.setSettingEnabled('airplaneMode', true);
|
|
break;
|
|
case 'disabled':
|
|
self.data.classList.remove('quick-settings-airplane-mode');
|
|
self.setSettingEnabled('airplaneMode', false);
|
|
break;
|
|
case 'enabling':
|
|
self.airplaneMode.dataset.enabling = 'true';
|
|
self.airplaneModeSwitching = true;
|
|
break;
|
|
case 'disabling':
|
|
self.airplaneMode.dataset.disabling = 'true';
|
|
self.airplaneModeSwitching = true;
|
|
break;
|
|
}
|
|
self.setAccessibilityAttributes(self.airplaneMode, 'airplaneMode');
|
|
});
|
|
},
|
|
|
|
/**
|
|
* General event handler.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
handleEvent: function qs_handleEvent(evt) {
|
|
evt.preventDefault();
|
|
var enabled = false;
|
|
switch (evt.type) {
|
|
case 'dataiconchanged':
|
|
this._handle_dataiconchanged();
|
|
break;
|
|
case 'click':
|
|
switch (evt.target) {
|
|
case this.wifi:
|
|
// do nothing if wifi isn't ready or
|
|
// airplaneMode is switching to another mode.
|
|
if (this.wifi.dataset.initializing ||
|
|
this.airplaneModeSwitching) {
|
|
return;
|
|
}
|
|
enabled = this.settings.wifi;
|
|
SettingsListener.getSettingsLock().set({
|
|
'wifi.enabled': !enabled
|
|
});
|
|
SettingsListener.getSettingsLock().set({
|
|
'wifi.connect_via_settings': !enabled
|
|
});
|
|
if (!enabled) {
|
|
this.toggleAutoConfigWifi = true;
|
|
}
|
|
break;
|
|
|
|
case this.data:
|
|
if (this.data.dataset.airplaneMode !== 'true') {
|
|
// TODO should ignore the action if initialization isn't done
|
|
enabled = this.settings.data;
|
|
if (enabled) {
|
|
var cset = {};
|
|
cset[this.DATA_KEY] = !enabled;
|
|
this.setMozSettings(cset);
|
|
} else {
|
|
//Data is not active we want to enable it
|
|
this.showDataRoamingEnabledPromptIfNeeded();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case this.bluetooth:
|
|
// do nothing if bluetooth isn't ready or
|
|
// airplaneMode is switching to another mode.
|
|
if (this.bluetooth.dataset.initializing ||
|
|
this.airplaneModeSwitching) {
|
|
return;
|
|
}
|
|
|
|
enabled = this.settings.bluetooth;
|
|
if (enabled) {
|
|
window.dispatchEvent(
|
|
new CustomEvent('request-disable-bluetooth'));
|
|
} else {
|
|
window.dispatchEvent(
|
|
new CustomEvent('request-enable-bluetooth'));
|
|
}
|
|
this.bluetooth.dataset.initializing = 'true';
|
|
break;
|
|
|
|
case this.airplaneMode:
|
|
if (this.airplaneModeSwitching) {
|
|
return;
|
|
}
|
|
var toggle = this.settings.airplaneMode ?
|
|
'request-airplane-mode-disable' :
|
|
'request-airplane-mode-enable';
|
|
window.dispatchEvent(new CustomEvent(toggle));
|
|
break;
|
|
|
|
case this.fullApp:
|
|
// XXX: This should be replaced probably by Web Activities
|
|
var host = document.location.host;
|
|
var domain = host.replace(/(^[\w\d]+\.)?([\w\d]+\.[a-z]+)/, '$2');
|
|
var protocol = document.location.protocol + '//';
|
|
applications.getByManifestURL(protocol + 'settings.' +
|
|
domain + '/manifest.webapp').launch();
|
|
|
|
UtilityTray.hide();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'utilitytrayshow':
|
|
break;
|
|
|
|
// unlock bluetooth toggle
|
|
case 'bluetooth-enabled':
|
|
this.setSettingEnabled('bluetooth', true);
|
|
delete this.bluetooth.dataset.initializing;
|
|
this.setAccessibilityAttributes(this.bluetooth, 'bluetoothButton');
|
|
break;
|
|
case 'bluetooth-disabled':
|
|
this.setSettingEnabled('bluetooth', false);
|
|
delete this.bluetooth.dataset.initializing;
|
|
this.setAccessibilityAttributes(this.bluetooth, 'bluetoothButton');
|
|
break;
|
|
// unlock wifi toggle
|
|
case 'wifi-enabled':
|
|
delete this.wifi.dataset.initializing;
|
|
this.setSettingEnabled('wifi', true);
|
|
this.setAccessibilityAttributes(this.wifi, 'wifiButton');
|
|
if (this.toggleAutoConfigWifi) {
|
|
// Check whether it found a wifi to connect after a timeout.
|
|
this.wifiStatusTimer = setTimeout(this.autoConfigWifi.bind(this),
|
|
this.WIFI_STATUSCHANGE_TIMEOUT);
|
|
}
|
|
break;
|
|
case 'wifi-disabled':
|
|
delete this.wifi.dataset.initializing;
|
|
this.setSettingEnabled('wifi', false);
|
|
this.setAccessibilityAttributes(this.wifi, 'wifiButton');
|
|
if (this.toggleAutoConfigWifi) {
|
|
clearTimeout(this.wifiStatusTimer);
|
|
this.wifiStatusTimer = null;
|
|
this.toggleAutoConfigWifi = false;
|
|
}
|
|
break;
|
|
|
|
case 'wifi-statuschange':
|
|
if (this.toggleAutoConfigWifi && !this.wifi.dataset.initializing) {
|
|
this.autoConfigWifi();
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Gets all relevant elements with an id prefixed by quick-settings-.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
getAllElements: function qs_getAllElements() {
|
|
var toCamelCase = function toCamelCase(str) {
|
|
return str.replace(/\-(.)/g, function replacer(str, p1) {
|
|
return p1.toUpperCase();
|
|
});
|
|
};
|
|
|
|
this.ELEMENTS.forEach(function createElementRef(name) {
|
|
this[toCamelCase(name)] =
|
|
document.getElementById('quick-settings-' + name);
|
|
}, this);
|
|
|
|
this.overlay = document.getElementById('quick-settings');
|
|
},
|
|
|
|
/**
|
|
* XXX Break down obj keys in a for each loop because mozSettings
|
|
* does not currently supports multiple keys in one set()
|
|
* https://bugzilla.mozilla.org/show_bug.cgi?id=779381
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
setMozSettings: function qs_setter(keypairs) {
|
|
var setlock = SettingsListener.getSettingsLock();
|
|
for (var key in keypairs) {
|
|
var obj = {};
|
|
obj[key] = keypairs[key];
|
|
setlock.set(obj);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Set aria-label and aria-pressed attributes for the appropriate buttons.
|
|
* @param {Object} button Element.
|
|
* @param {String} label Button label.
|
|
* @param {?String} type Optional type attribute for l10n.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
setAccessibilityAttributes: function(button, label, type) {
|
|
label = 'quick-settings-' + label +
|
|
(button.dataset.enabled === undefined ? '-off' : '-on');
|
|
if (button.dataset.initializing !== undefined) {
|
|
label += '-initializing';
|
|
}
|
|
navigator.mozL10n.setAttributes(button, label, { type: type || '' });
|
|
button.setAttribute('aria-pressed', button.dataset.enabled !== undefined);
|
|
},
|
|
|
|
/**
|
|
* Auto-config wifi if user enabled wifi from quick settings bar.
|
|
* If there are no known networks around, wifi settings page
|
|
* will be opened. Otherwise nothing will be done.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
autoConfigWifi: function qs_autoConfigWifi() {
|
|
clearTimeout(this.wifiStatusTimer);
|
|
this.wifiStatusTimer = null;
|
|
this.toggleAutoConfigWifi = false;
|
|
|
|
var wifiManager = window.navigator.mozWifiManager;
|
|
var status = wifiManager.connection.status;
|
|
|
|
if (status == 'disconnected') {
|
|
SettingsListener.getSettingsLock().set({
|
|
'wifi.connect_via_settings': false
|
|
});
|
|
var activity = new MozActivity({
|
|
name: 'configure',
|
|
data: {
|
|
target: 'device',
|
|
section: 'wifi'
|
|
}
|
|
});
|
|
return activity;
|
|
} else if (status == 'connectingfailed') {
|
|
SettingsListener.getSettingsLock().set({
|
|
'wifi.connect_via_settings': false
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Checks if we are currently roaming or not.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
checkDataRoaming: function qs_checkDataRoaming() {
|
|
var lock = SettingsListener.getSettingsLock();
|
|
var reqSetting = lock.get(this.DATA_ROAMING_KEY);
|
|
var self = this;
|
|
return new Promise(function(resolve, reject) {
|
|
reqSetting.onerror = function() {
|
|
resolve(true);
|
|
};
|
|
reqSetting.onsuccess = function() {
|
|
resolve(reqSetting.result[self.DATA_ROAMING_KEY]);
|
|
};
|
|
});
|
|
},
|
|
|
|
setSettingEnabled: function qa_setSettingEnabled(settingKey, enabled) {
|
|
this.settings[settingKey] = enabled;
|
|
if (enabled) {
|
|
this[settingKey].dataset.enabled = 'true';
|
|
} else {
|
|
delete this[settingKey].dataset.enabled;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Prompts the user if they are requesting to enable data roaming.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
showDataRoamingEnabledPromptIfNeeded:
|
|
function qs_showDataRoamingEnabledPromptIfNeeded() {
|
|
var dialog = document.querySelector('#quick-setting-data-enabled-dialog'),
|
|
enableBtn = document.querySelector('.quick-setting-data-ok-btn'),
|
|
cancelBtn = document.querySelector('.quick-setting-data-cancel-btn');
|
|
var self = this;
|
|
var connections = window.navigator.mozMobileConnections;
|
|
var dataType;
|
|
var sim;
|
|
|
|
if (!connections) {
|
|
return;
|
|
}
|
|
// In DualSim only one of them will have data active
|
|
for (var i = 0; i < connections.length && !dataType; i++) {
|
|
dataType = connections[i].data.type;
|
|
sim = connections[i];
|
|
}
|
|
if (!dataType) {
|
|
//No connection available
|
|
return;
|
|
}
|
|
|
|
this.checkDataRoaming().then(function(roaming) {
|
|
if (!roaming && sim.data.roaming) {
|
|
disabledDefaultDialogIfNeeded();
|
|
} else {
|
|
var cset = {};
|
|
cset[self.DATA_KEY] = true;
|
|
self.setMozSettings(cset);
|
|
return;
|
|
}
|
|
});
|
|
|
|
// Hides the warning dialog to prevent to show it in settings app again
|
|
var disabledDefaultDialogIfNeeded = function() {
|
|
self.getDataRoamingWarning().then(function(warningEnabled) {
|
|
if (warningEnabled === null || warningEnabled) {
|
|
var cset = {};
|
|
cset[self.WARNING_DIALOG_ENABLED_KEY] = false;
|
|
self.setMozSettings(cset);
|
|
}
|
|
enableDialog(true);
|
|
});
|
|
};
|
|
|
|
var enableSetting = function() {
|
|
var cset = {};
|
|
cset[self.DATA_KEY] = true;
|
|
cset[self.DATA_ROAMING_KEY] = true;
|
|
self.setMozSettings(cset);
|
|
enableDialog(false);
|
|
};
|
|
|
|
var cancel = function() {
|
|
enableDialog(false);
|
|
};
|
|
|
|
function enableDialog(enabled) {
|
|
if (enabled) {
|
|
UtilityTray.hide();
|
|
enableBtn.addEventListener('click', enableSetting);
|
|
cancelBtn.addEventListener('click', cancel);
|
|
dialog.classList.add('visible');
|
|
} else {
|
|
enableBtn.removeEventListener('click', enableSetting);
|
|
cancelBtn.removeEventListener('click', cancel);
|
|
dialog.classList.remove('visible');
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Checks whether or not we should prompt the user when enabling
|
|
* data roaming.
|
|
* @memberof QuickSettings.prototype
|
|
*/
|
|
getDataRoamingWarning: function qs_getDataRoamingWarning() {
|
|
var lock = SettingsListener.getSettingsLock();
|
|
var reqSetting = lock.get(this.WARNING_DIALOG_ENABLED_KEY);
|
|
var self = this;
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
reqSetting.onerror = function() {
|
|
resolve(true);
|
|
};
|
|
|
|
reqSetting.onsuccess = function() {
|
|
resolve(reqSetting.result[self.WARNING_DIALOG_ENABLED_KEY]);
|
|
};
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.QuickSettings = QuickSettings;
|
|
|
|
}(window));
|