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:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
563
gaia/apps/costcontrol/js/widget.js
Executable file
563
gaia/apps/costcontrol/js/widget.js
Executable 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();
|
||||
Loading…
Reference in a new issue