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.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,563 @@
/* global _, debug, BalanceView, AirplaneModeHelper, setNextReset, SimManager,
ConfigManager, Common, CostControl, MozActivity, LazyLoader,
Formatting
*/
/* exported activity */
'use strict';
/*
* The widget is in charge of show balance, telephony data and data usage
* statistics depending on the SIM inserted.
*
* It has three areas of drawing: balance, telephony and data usage.
* The update is done by demand when the widget is shown or in reaction of
* a balance update or timeout.
*/
var Widget = (function() {
var costcontrol, activity;
function checkSIMStatus(dataSim) {
var dataSimIcc = dataSim.icc;
var cardState = checkCardState(dataSimIcc);
if (cardState !== 'ready') {
debug('SIM not ready:', dataSimIcc.cardState);
initialized = false;
dataSimIcc.oncardstatechange = checkSIMStatus.bind(null, dataSim);
// SIM ready
} else {
debug('SIM ready. ICCID:', dataSim.iccId);
dataSimIcc.oncardstatechange = undefined;
var SCRIPTS_NEEDED_TO_START = [
'js/costcontrol.js',
'js/config/config_manager.js'
];
LazyLoader.load(SCRIPTS_NEEDED_TO_START, startWidget);
}
}
// Check the card status. Return 'ready' if all OK or take actions for
// special situations such as 'pin/puk locked' or 'absent'.
function checkCardState(dataSimIcc) {
var state, cardState;
state = cardState = dataSimIcc.cardState;
// SIM is absent
if (!cardState || cardState === 'absent') {
debug('There is no SIM');
Widget.showSimError('no-sim3');
// SIM is not initialized correctly
} else if (cardState === 'unknown') {
debug('Unknow state fo the sim');
Widget.showSimError('unknown');
// SIM is locked
} else if (
cardState === 'pinRequired' ||
cardState === 'pukRequired'
) {
Widget.showSimError('sim2-locked');
state = 'locked';
}
return state;
}
function loadMessageHandler() {
if (ConfigManager.option('nextReset')) {
window.addEventListener('messagehandlerready', function _setNextReset() {
window.removeEventListener('messagehandlerready', _setNextReset);
LazyLoader.load('js/settings/networkUsageAlarm.js', function() {
Common.loadNetworkInterfaces(function() {
setNextReset(ConfigManager.option('nextReset'));
});
});
});
}
document.getElementById('message-handler').src = 'message_handler.html';
}
function startWidget() {
CostControl.getInstance(function _onCostControlReady(instance) {
costcontrol = instance;
loadMessageHandler();
setupWidget();
});
}
var initialized, widget, leftPanel, rightPanel, fte, views = {};
var balanceView;
function _openBalanceTab() {
activity = new MozActivity({ name: 'costcontrol/balance' });
}
function _openTelephonyTab() {
activity = new MozActivity({ name: 'costcontrol/telephony' });
}
function _openDataUsageTab() {
activity = new MozActivity({ name: 'costcontrol/data_usage' });
}
function _onVisibilityChange(evt) {
AirplaneModeHelper.ready(function() {
if (!document.hidden && initialized &&
(AirplaneModeHelper.getStatus() === 'disabled')) {
SimManager.requestDataSimIcc(function(dataSimIcc) {
checkCardState(dataSimIcc.icc);
updateUI();
});
}
});
}
function _onHashChange() {
if (window.location.hash.split('#')[1] === 'update') {
updateUI(true); // update only data usage
}
}
function _onLocalize() {
if (initialized) {
updateUI();
}
}
function setupWidget() {
var mode = ConfigManager.getApplicationMode();
var isDataUsageOnly = (mode === 'DATA_USAGE_ONLY');
var isBalanceEnabled = !isDataUsageOnly;
// HTML entities
widget = document.getElementById('cost-control');
leftPanel = document.getElementById('left-panel');
rightPanel = document.getElementById('right-panel');
fte = document.getElementById('fte-view');
views.dataUsage = document.getElementById('datausage-view');
views.limitedDataUsage = document.getElementById('datausage-limit-view');
views.telephony = document.getElementById('telephony-view');
views.balance = document.getElementById('balance-view');
if (isBalanceEnabled) {
// Use observers to handle not on-demand updates
ConfigManager.observe('lastBalance', onBalance, true);
ConfigManager.observe('waitingForBalance', onErrors, true);
ConfigManager.observe('errors', onErrors, true);
LazyLoader.load('js/views/BalanceView.js', function() {
// Subviews
var balanceConfig = ConfigManager.configuration.balance;
balanceView = new BalanceView(
document.getElementById('balance-credit'),
document.querySelector('#balance-credit + .meta'),
balanceConfig ? balanceConfig.minimum_delay : undefined
);
});
// Open application with the proper view
views.balance.addEventListener('click', _openBalanceTab);
views.telephony.addEventListener('click', _openTelephonyTab);
}
// Use observers to handle not on-demand updates
ConfigManager.observe('lastCompleteDataReset', onReset, true);
ConfigManager.observe('lastTelephonyReset', onReset, true);
// Update UI when visible
document.addEventListener('visibilitychange', _onVisibilityChange);
// Update data usage on network activity
window.addEventListener('hashchange', _onHashChange);
window.addEventListener('localized', _onLocalize);
// Open application with the proper view
leftPanel.addEventListener('click', _openDataUsageTab);
LazyLoader.load([
'shared/js/date_time_helper.js',
'js/utils/formatting.js'
], function() {
updateUI();
});
if (SimManager.isMultiSim()) {
window.addEventListener('dataSlotChange', function _onDataSimChange() {
// Before updating the widget, it's necessary remove the cached values
// of costcontrol and config to force an update
CostControl.reset();
Widget.reset();
ConfigManager.setConfig(null);
SimManager.requestDataSimIcc(checkSIMStatus);
});
}
initialized = true;
}
// BALANCE ACTIONS
// On balance update received
function onBalance(balance, old, key, settings) {
debug('Balance received:', balance);
setBalanceMode('default');
updateBalance(balance, settings.lowLimit && settings.lowLimitThreshold);
debug('Balance updated!');
}
// On balance update fail
function onErrors(errors, old, key, settings) {
if (!errors || !errors.BALANCE_TIMEOUT) {
return;
}
debug('Balance timeout!');
setBalanceMode('warning');
errors.BALANCE_TIMEOUT = false;
ConfigManager.setOption({errors: errors});
}
// On reset telephony or data usage
function onReset(value, old, key, settings) {
updateUI();
}
// USER INTERFACE
// Reuse fte panel to display errors
function _showSimError(status, updateTextOnly) {
// Wait to l10n resources are ready
navigator.mozL10n.ready(function showErrorStatus() {
var widget = document.getElementById('cost-control');
var fte = document.getElementById('fte-view');
var leftPanel = document.getElementById('left-panel');
var rightPanel = document.getElementById('right-panel');
if (!updateTextOnly) {
widget.hidden = false;
fte.hidden = false;
leftPanel.hidden = true;
rightPanel.hidden = true;
}
var className = 'widget-' + status;
Common.localize(fte.querySelector('p:first-child'), className +
'-heading');
Common.localize(fte.querySelector('p:last-child'), className +
'-meta');
});
}
function setupFte(provider, mode) {
widget.hidden = false;
fte.hidden = false;
leftPanel.hidden = true;
rightPanel.hidden = true;
fte.addEventListener('click', function launchFte(evt) {
fte.removeEventListener('click', launchFte);
evt.stopImmediatePropagation();
activity = new MozActivity({ name: 'costcontrol/balance' });
});
var keyLookup = {
PREPAID: 'widget-authed-sim2',
POSTPAID: 'widget-authed-sim2',
DATA_USAGE_ONLY: 'widget-nonauthed-sim2'
};
var simKey = keyLookup[mode];
Common.localize(
fte.querySelector('p:first-child'),
simKey + '-heading',
{provider: provider}
);
Common.localize(fte.querySelector('p:last-child'), simKey +
'-meta');
}
var hashMark = 0;
function updateUI(updateOnlyDataUsage) {
ConfigManager.requestAll(function _onInfo(configuration, settings) {
var mode = ConfigManager.getApplicationMode();
debug('Widget UI mode:', mode);
var isPrepaid = (mode === 'PREPAID');
var isDataUsageOnly = (mode === 'DATA_USAGE_ONLY');
// Show fte mode widget
if (settings.fte) {
setupFte(configuration.provider, mode);
debug('Widget in FTE mode');
return;
}
// Layout
widget.hidden = true;
fte.hidden = true;
leftPanel.hidden = false;
rightPanel.hidden = false;
var isLimited = settings.dataLimit;
views.dataUsage.hidden = isLimited;
views.limitedDataUsage.hidden = !isLimited;
// Always data usage
rightPanel.hidden = isDataUsageOnly;
// And the other view if applies...
if (isDataUsageOnly) {
widget.classList.add('full');
widget.hidden = false;
} else {
widget.classList.remove('full');
views.balance.hidden = !isPrepaid;
views.telephony.hidden = isPrepaid;
widget.hidden = false;
}
// Content for data statistics
var requestObj = { type: 'datausage' };
costcontrol.request(requestObj, function _onDataStatistics(result) {
debug(result);
var stats = result.data;
var data = Formatting.roundData(stats.mobile.total);
if (isLimited) {
// UI elements
var dataLimit = views.limitedDataUsage.querySelector('#data-limit');
var dataAvailable =
views.limitedDataUsage.querySelector('#data-available');
var current = stats.mobile.total;
var limit = Common.getDataLimit(settings);
debug(limit);
// State
views.limitedDataUsage.classList.remove('nearby-limit');
views.limitedDataUsage.classList.remove('reached-limit');
// Limit trespassed
var limitTrespassed = (current > limit);
if (limitTrespassed) {
views.limitedDataUsage.classList.add('reached-limit');
// Warning percentage of the limit reached
} else if (current >= limit * Common.DATA_USAGE_WARNING) {
views.limitedDataUsage.classList.add('nearby-limit');
}
// Texts
var limitText = Formatting.roundData(limit);
limitText = _('magnitude', {
value: limitText[0],
unit: limitText[1]
});
navigator.mozL10n.setAttributes(dataLimit, 'data-limit',
{ value: limitText });
var rawValue = Math.abs(limit - current);
var text = Formatting.roundData(rawValue);
if (!limitTrespassed) {
navigator.mozL10n.setAttributes(dataAvailable, 'data-available2',
{ value: parseFloat(text[0]), unit: text[1] });
} else {
navigator.mozL10n.setAttributes(dataAvailable, 'over-limit',
{ value: parseFloat(text[0]), unit: text[1] });
}
} else {
// Texts
document.getElementById('mobile-usage-value').textContent =
_('magnitude', { value: data[0], unit: data[1] });
var meta = views.dataUsage.querySelector('.meta');
meta.innerHTML = '';
meta.appendChild(Formatting.formatTimeHTML(stats.timestamp));
}
// inform driver in system we are finished to update the widget
hashMark = 1 - hashMark; // toogle between 0 and 1
window.location.hash = '#updateDone#' + hashMark;
});
// Content for balance or telephony
if (!isDataUsageOnly && !updateOnlyDataUsage) {
if (mode === 'PREPAID') {
updateBalance(settings.lastBalance,
settings.lowLimit && settings.lowLimitThreshold);
requestObj = { type: 'balance' };
costcontrol.request(requestObj, function _onRequest(result) {
debug(result);
var status = result.status;
var balance = result.data;
setBalanceMode(status === 'error' ? 'warning' : 'updating');
updateBalance(balance,
settings.lowLimit && settings.lowLimitThreshold);
});
} else if (mode === 'POSTPAID') {
requestObj = { type: 'telephony' };
costcontrol.request(requestObj, function _onRequest(result) {
var dataActivity = result.data;
document.getElementById('telephony-calltime').textContent =
_('magnitude', {
value: Formatting.computeTelephonyMinutes(dataActivity),
unit: 'min'
}
);
document.getElementById('telephony-smscount').textContent =
_('magnitude', {
value: dataActivity.smscount,
unit: 'SMS'
}
);
var meta = views.telephony.querySelector('.meta');
meta.innerHTML = '';
meta.appendChild(Formatting.formatTimeHTML(dataActivity.timestamp));
});
}
}
});
}
// Update the balance in balance view
function updateBalance(balance, limit) {
if (!balance) {
debug('Balance not available');
balanceView.update();
return;
}
var isUpdating = views.balance.classList.contains('updating');
balanceView.update(balance, isUpdating);
// Limits: reaching zero / low limit
if (balance.balance === 0) {
views.balance.classList.add('no-credit');
} else {
views.balance.classList.remove('no-credit');
if (limit && balance.balance < limit) {
views.balance.classList.add('low-credit');
} else {
views.balance.classList.remove('low-credit');
}
}
}
// Set warning / updating modes
var lastBalanceMode;
function setBalanceMode(mode) {
if (mode === lastBalanceMode) {
return;
}
lastBalanceMode = mode;
views.balance.classList.remove('updating');
views.balance.classList.remove('warning');
if (mode === 'warning') {
views.balance.classList.add('warning');
}
if (mode === 'updating') {
views.balance.classList.add('updating');
}
}
window.addEventListener('airplaneModeDisabled',
function _onAirplanemodeDisabled(evt) {
if (evt.detail && evt.detail.serviceId === 'data') {
SimManager.requestDataSimIcc(checkSIMStatus);
}
});
function initWidget() {
var isWaitingForIcc = false;
function waitForIccAndCheckSim() {
if (!isWaitingForIcc) {
var iccManager = window.navigator.mozIccManager;
iccManager.addEventListener('iccdetected',
function _oniccdetected() {
isWaitingForIcc = false;
iccManager.removeEventListener('iccdetected', _oniccdetected);
if (AirplaneModeHelper.getStatus() === 'disabled') {
SimManager.requestDataSimIcc(checkSIMStatus);
}
}
);
isWaitingForIcc = true;
}
}
SimManager.requestDataSimIcc(checkSIMStatus, function _errorNoSim() {
AirplaneModeHelper.ready(function() {
waitForIccAndCheckSim();
var errorMessageId = (AirplaneModeHelper.getStatus() === 'enabled') ?
'airplane-mode' : 'no-sim3';
console.warn('Error when trying to get the ICC ID');
Widget.showSimError(errorMessageId);
});
});
AirplaneModeHelper.addEventListener('statechange',
function _onAirplaneModeChange(state) {
if (state === 'enabled') {
Widget.showSimError('airplane-mode');
} else if (isWaitingForIcc) {
var updateTextOnly = true;
Widget.showSimError('no-sim3', updateTextOnly);
}
}
);
}
return {
init: function() {
var SCRIPTS_NEEDED = [
'js/common.js',
'js/utils/toolkit.js'
];
// Check if the mandatory APIs to work exist.
if (!window.navigator.mozMobileConnections ||
!window.navigator.mozIccManager ||
!window.navigator.mozNetworkStats) {
LazyLoader.load(SCRIPTS_NEEDED, function _showError() {
Widget.showSimError('no-sim3');
});
} else {
SCRIPTS_NEEDED = [
'js/sim_manager.js',
'js/common.js',
'js/utils/toolkit.js',
'js/utils/debug.js'
];
LazyLoader.load(SCRIPTS_NEEDED, initWidget);
}
},
showSimError: _showSimError,
reset: function() {
document.removeEventListener('visibilitychange', _onVisibilityChange);
window.removeEventListener('hashchange', _onHashChange);
window.removeEventListener('localized', _onLocalize);
leftPanel.removeEventListener('click', _openDataUsageTab);
if (views.balance) {
views.balance.removeEventListener('click', _openBalanceTab);
}
if (views.telephony) {
views.telephony.removeEventListener('click', _openTelephonyTab);
}
}
};
}());
Widget.init();