VulpesOS/gaia/apps/ftu/js/wifi.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

485 lines
16 KiB
JavaScript
Executable file

/* global utils, UIManager, WifiHelper, WifiUI:true */
/* exported WifiManager, WifiUI */
(function(exports) {
'use strict';
const WIFI_STATUS = {
connecting: 'connecting',
associated: 'associated',
connected: 'connected',
connectingfailed: 'connectingfailed',
disconnected: 'disconnected'
};
var WifiManager = {
STATUS: Object.freeze(WIFI_STATUS),
init: function wn_init() {
this.api = WifiHelper.getWifiManager();
this.changeStatus();
// Ensure that wifi is on.
if (navigator.mozSettings) {
var lock = window.navigator.mozSettings.createLock();
this.enable(lock);
this.enableDebugging(lock);
}
this.gCurrentNetwork = this.api ? this.api.connection.network : null;
if (this.gCurrentNetwork !== null) {
this.api.forget(this.gCurrentNetwork);
this.gCurrentNetwork = null;
}
},
getNetworks: function wn_getNetworks(callback) {
this.networks ? callback(this.networks) : this.scan(callback);
},
scan: function wn_scan(callback) {
if (this._scanning) {
return;
}
this._scanning = true;
utils.overlay.show('scanningNetworks', 'spinner');
var SCAN_TIMEOUT = 10000;
var self = this;
self.onScan = callback;
var req = this.api ? this.api.getNetworks() : null;
if (!req) {
// When no wifi API is available (ie. shimless B2G-desktop),
// we will yield to the event loop before calling the callback
// to prevent a race condition with the wifi overlay.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=957769#c5
setTimeout(function() {
self._scanning = false;
callback();
});
return;
}
var handleRequest = function handleRequest() {
self._scanning = false;
clearTimeout(self.scanTimeout);
self.scanTimeout = null;
self.onScan(self.networks);
self.onScan = null;
};
req.onsuccess = function onScanSuccess() {
self.networks = req.result;
handleRequest();
};
req.onerror = function onScanError() {
console.error('Error reading networks: ' + req.error.name);
self.networks = [];
handleRequest();
};
// Timeout in case of scanning errors not thrown by the API
// We can't block the user in the screen (bug 889623)
if (!self.scanTimeout) {
self.scanTimeout = setTimeout(function() {
self._scanning = false;
console.warn('Timeout while reading networks');
self.onScan();
}, SCAN_TIMEOUT);
}
},
enable: function wn_enable(lock) {
lock.set({'wifi.enabled': true});
},
enableDebugging: function wn_enableDebugging(lock) {
// For bug 819947: turn on wifi debugging output to help track down a bug
// in wifi. We turn on wifi output only while the FTU app is active.
this._prevDebuggingValue = false;
var req = lock.get('wifi.debugging.enabled');
req.onsuccess = function wn_getDebuggingSuccess() {
this._prevDebuggingValue = req.result['wifi.debugging.enabled'];
};
lock.set({ 'wifi.debugging.enabled': true });
},
finish: function wn_finish() {
if (!this._prevDebuggingValue && navigator.mozSettings) {
var resetLock = window.navigator.mozSettings.createLock();
resetLock.set({'wifi.debugging.enabled': false});
}
},
getNetwork: function wm_gn(ssid) {
var list = this.networks;
for (var i = 0; i < list.length; i++) {
if (list[i].ssid === ssid) {
return list[i];
}
}
return null;
},
connect: function wn_connect(ssid, password, user) {
var network = this.getNetwork(ssid);
if (!network) {
console.error('Network not found');
return;
}
this.ssid = ssid;
// TODO: Hardcoded for resolving bug 1019146, replace hardcoded eap
// method with user selected eap method after bug 1036829.
WifiHelper.setPassword(network, password, user, 'PEAP');
this.gCurrentNetwork = network;
this.api.associate(network);
},
changeStatus: function wn_cs(callback) {
/**
* mozWifiManager status
* see dom/wifi/nsIWifi.idl -- the 4 possible statuses are:
* - connecting:
* fires when we start the process of connecting to a network.
* - associated:
* fires when we have connected to an access point but do not yet
* have an IP address.
* - connected:
* fires once we are fully connected to an access point.
* - connectingfailed:
* fires when we fail to connect to an access point.
* - disconnected:
* fires when we were connected to a network but have been
* disconnected.
*/
var self = this;
if (WifiManager.api) {
WifiManager.api.onstatuschange = function(event) {
if (event.status === WifiManager.STATUS.disconnected && self.onScan) {
self.scan(self.onScan);
} else {
WifiUI.updateNetworkStatus(event.network.ssid, event.status);
}
};
}
}
};
var WifiUI = {
joinNetwork: function wui_jn() {
var password = document.getElementById('wifi_password').value;
var user = document.getElementById('wifi_user').value;
var ssid = document.getElementById('wifi_ssid').value;
WifiUI.connect(ssid, password, user);
window.history.back();
},
joinHiddenNetwork: function wui_jhn() {
var password = UIManager.hiddenWifiPassword.value;
var user = UIManager.hiddenWifiIdentity.value;
var ssid = UIManager.hiddenWifiSsid.value;
var security = UIManager.hiddenWifiSecurity.value;
var network;
if (ssid.length) {
if (!Array.isArray(WifiManager.networks)) {
WifiManager.networks = [];
}
network = new window.MozWifiNetwork({
ssid: ssid,
capabilities: [],
security: [security],
relSignalStrength: 0,
hidden: true
});
WifiManager.networks.push(network);
this.renderNetworks(WifiManager.networks);
WifiUI.connect(ssid, password, user);
}
// like in Settings: if we don't provide correct
// network data it just get back to the wifi screen
window.history.back();
},
_selectNetworkItem: function(ssid, isSelected=true) {
var elem = document.getElementById(ssid);
if (!elem) {
return;
}
if (isSelected) {
// We should update the state to 'connecting' in here to show the change
// to the user, instead of waiting for the api (takes longer).
// But currently
// there's no feedback from the api when connecting to a hidden wifi fails
// so we skip the visual changes
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1107431#c25
elem.setAttribute('data-wifi-selected', true);
} else {
var icon = elem.querySelector('aside');
elem.removeAttribute('data-wifi-selected');
elem.classList.remove('connected');
icon.classList.remove('connecting');
icon.classList.remove('connected');
var security = elem.dataset.security;
var securityLevelDOM = elem.querySelector('p[data-security-level]');
securityLevelDOM.setAttribute('data-l10n-id',
security ? security : 'securityOpen');
}
},
connect: function wui_connect(ssid, password, user) {
// First we check if there is a previous selected network
// and we remove their status
// And then end we update the selected network
var newWifi = document.getElementById(ssid);
Array.from(document.querySelectorAll('li[data-wifi-selected]'))
.forEach((networkSelected) => {
this._selectNetworkItem(networkSelected,
networkSelected === newWifi);
});
// Finally we try to connect to the network
WifiManager.connect(ssid, password, user);
},
chooseNetwork: function wui_cn(event) {
// Retrieve SSID from dataset
var ssid = event.target.dataset.ssid;
var selectedNetwork = WifiManager.getNetwork(ssid);
if (!selectedNetwork) {
console.error('Network not found');
return;
}
// Do we need to type password?
if (WifiHelper.isOpen(selectedNetwork)) {
WifiUI.connect(ssid);
return;
}
// Remove refresh option
UIManager.activationScreen.classList.add('no-options');
// Update title
UIManager.mainTitle.textContent = ssid;
// Update network values
var ssidHeader = document.getElementById('wifi_ssid');
var userInput = document.getElementById('wifi_user');
var passwordInput = document.getElementById('wifi_password');
var showPassword = document.querySelector(
'gaia-checkbox[name=show_password]');
var joinButton = UIManager.wifiJoinButton;
joinButton.disabled = true;
passwordInput.addEventListener('input', function validatePassword() {
// disable the "Join" button if the password is on wrong format
joinButton.disabled =
!WifiHelper.isValidInput(WifiHelper.getKeyManagement(selectedNetwork),
passwordInput.value, userInput.value);
});
// Show / Hide password
passwordInput.type = 'password';
passwordInput.value = '';
showPassword.checked = false;
showPassword.addEventListener('change', e => {
passwordInput.type = e.target.checked ? 'text' : 'password';
});
// Update form
passwordInput.value = '';
ssidHeader.value = ssid;
// Activate secondary menu
UIManager.navBar.classList.add('secondary-menu');
// Update changes in form
if (WifiHelper.isEap(selectedNetwork)) {
userInput.parentNode.classList.remove('hidden');
} else {
userInput.parentNode.classList.add('hidden');
}
// Change hash
window.location.hash = '#configure_network';
},
addHiddenNetwork: function wui_addHiddenNetwork() {
// Remove refresh option
UIManager.activationScreen.classList.add('no-options');
// Update title
UIManager.mainTitle.setAttribute('data-l10n-id', 'authentication');
UIManager.navBar.classList.add('secondary-menu');
// Clean input contents
UIManager.hiddenWifiSsid.value = '';
UIManager.hiddenWifiPassword.value = '';
UIManager.hiddenWifiIdentity.value = '';
// Reset join button state
UIManager.wifiJoinButton.disabled = true;
window.location.hash = '#hidden-wifi-authentication';
},
handleHiddenWifiSecurity: function wui_handleSecurity(securityType) {
// no need for password if network is open
if (securityType === '') {
UIManager.hiddenWifiPasswordBox.classList.add('hidden');
} else {
UIManager.hiddenWifiPasswordBox.classList.remove('hidden');
}
// need of username is security is WPA-EAP
if (securityType.indexOf('EAP') !== -1) {
UIManager.hiddenWifiIdentityBox.classList.remove('hidden');
} else {
UIManager.hiddenWifiIdentityBox.classList.add('hidden');
}
},
renderNetworks: function wui_rn(networks) {
var networksDOM = document.getElementById('networks');
networksDOM.innerHTML = '';
var networksList;
if (!networks || networks.length === 0) {
var noResult = '<div id="no-result-container">' +
' <div id="no-result-message">' +
' <p data-l10n-id="noWifiFound3"></p>' +
' </div>' +
'</div>';
networksDOM.innerHTML = noResult;
} else {
networksList = document.createElement('ul');
networksList.id = 'networks-list';
networksList.setAttribute('role', 'listbox');
networksList.setAttribute('data-l10n-id', 'networksList');
var networksShown = [];
networks.sort(function(a, b) {
return b.relSignalStrength - a.relSignalStrength;
});
// Add detected networks
for (var i = 0, max = networks.length; i < max; i++) {
// Retrieve the network
var network = networks[i];
// Check if is shown
if (networksShown.indexOf(network.ssid) === -1) {
// Create dom elements
var li = document.createElement('li');
var icon = document.createElement('aside');
var ssidp = document.createElement('p');
ssidp.setAttribute('dir', 'auto');
var small = document.createElement('p');
small.dataset.securityLevel = true;
// Set Icon
icon.classList.add('pack-end');
icon.classList.add('wifi-icon');
var level = Math.min(Math.floor(network.relSignalStrength / 20), 4);
icon.classList.add('level-' + level);
document.l10n.setAttributes(icon, 'wifiLevel', {level: level});
icon.setAttribute('role', 'presentation');
// Set SSID
ssidp.textContent = network.ssid;
li.dataset.ssid = network.ssid;
// Show authentication method
var keys = WifiHelper.getSecurity(network);
li.dataset.security = keys;
if (!WifiHelper.isOpen(network)) {
small.textContent = keys.join(', ');
icon.classList.add('secured');
} else {
small.setAttribute('data-l10n-id', 'securityOpen');
}
// Show connection status
icon.classList.add('wifi-signal');
var connectionStatus = WifiHelper.getNetworkStatus(network) ||
WifiManager.STATUS.disconnected;
li.dataset.status = connectionStatus;
if (connectionStatus === WifiManager.STATUS.connected) {
small.setAttribute('data-l10n-id', 'shortStatus-connected');
small.removeAttribute('aria-label');
icon.classList.add('connected');
li.classList.add('connected');
li.dataset.wifiSelected = true;
}
// Update list of shown networks
networksShown.push(network.ssid);
// Append the elements to li
li.setAttribute('id', network.ssid);
li.setAttribute('role', 'option');
li.setAttribute('aria-live', true);
li.setAttribute('aria-relevant', 'text');
li.appendChild(ssidp);
li.appendChild(small);
li.appendChild(icon);
// Append to DOM
if (WifiHelper.isConnected(network)) {
networksList.insertBefore(li, networksList.firstChild);
} else {
networksList.appendChild(li);
}
}
}
networksList.dataset.type = 'list';
networksDOM.appendChild(networksList);
}
utils.overlay.hide();
},
updateNetworkStatus: function wui_uns(ssid, status) {
var element = document.getElementById(ssid);
// Check if element exists and it's the selected network
if (!element) {
return;
}
if (status === WifiManager.STATUS.connecting && ssid !== WifiManager.ssid) {
// bogus event, see bug 1179703/1216221
return;
}
// Update the element
element.dataset.status = status;
if (status !== WifiManager.STATUS.disconnected) {
element.querySelector('p[data-security-level]').setAttribute(
'data-l10n-id', 'shortStatus-' + status);
} else {
var security = element.dataset.security || 'Open';
element.querySelector('p[data-security-level]').setAttribute(
'data-l10n-id', 'security' + security);
element.classList.remove('connected');
}
// Animate icon if connecting, stop animation if
// failed/connected/disconnected
var icon = element.querySelector('aside');
switch (status) {
case WifiManager.STATUS.connecting:
case WifiManager.STATUS.associated:
icon.classList.add('connecting');
break;
case WifiManager.STATUS.connected:
icon.classList.remove('connecting');
var networksList = document.getElementById('networks-list');
icon.classList.add('connected');
element.classList.add('connected');
networksList.removeChild(element);
networksList.insertBefore(element, networksList.firstChild);
break;
default:
icon.classList.remove('connecting');
icon.classList.remove('connected');
break;
}
}
};
exports.WifiManager = WifiManager;
exports.WifiUI = WifiUI;
})(window);