VulpesOS/gaia/apps/system/js/quick_settings.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

615 lines
19 KiB
JavaScript
Executable file

/* 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));