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
538
gaia/apps/costcontrol/js/app.js
Executable file
538
gaia/apps/costcontrol/js/app.js
Executable file
|
|
@ -0,0 +1,538 @@
|
|||
/* global BalanceTab, ConfigManager, Common, NonReadyScreen, SimManager,
|
||||
debug, CostControl, TelephonyTab, ViewManager, LazyLoader,
|
||||
AirplaneModeHelper, setNextReset, asyncStorage */
|
||||
/* exported CostControlApp */
|
||||
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* The application is in charge of display detailed information about the usage.
|
||||
* Application has three tabs configured independently plus a settings view.
|
||||
*
|
||||
* This module is only in charge of manage the different tabs but the specific
|
||||
* behaviour is delegated to each tab (in /js/views directory).
|
||||
*
|
||||
* It is important to explain how the URL schema works. Cost Control
|
||||
* uses the concept of card to refer a tab or a view. There are two main layers:
|
||||
* the tab layer and the overlay layer. The first one is used to display tabs,
|
||||
* the second one is used to display settings or other overlaying dialogs.
|
||||
*
|
||||
* The URL schema is:
|
||||
* #tab-id[#overlay-id]
|
||||
*
|
||||
* So changing the hash to:
|
||||
* #balance-tab#settings-view
|
||||
* makes Cost Control to change to the balance view and show the settings.
|
||||
*
|
||||
* We can close the overlay layer by setting only the balance layer:
|
||||
* #datausage-tab
|
||||
* this makes Cost Control to change to the datausage tab at the same time it
|
||||
* closes the card in the overlay layer.
|
||||
*
|
||||
* If you want to preserve a layer but changing the other, use the empty string
|
||||
* as the id of the layer you want to preserve.
|
||||
* For instance, you want to only close the overlay layer but not affecting the
|
||||
* tab layer:
|
||||
* #
|
||||
*
|
||||
* Or you want to change tab layer but without affecting the overlay, use:
|
||||
* #telephony-tab#
|
||||
*
|
||||
* Remember: you cannot close the tab layer!
|
||||
*/
|
||||
|
||||
var CostControlApp = (function() {
|
||||
|
||||
var costcontrol,
|
||||
initialized = false,
|
||||
hashFromLastRun,
|
||||
hashFromNotification;
|
||||
var vmanager;
|
||||
|
||||
// Set the application in waiting for SIM mode. During this mode, the
|
||||
// application shows a dialog informing about the current situation of the
|
||||
// SIM. Once ready, callback is executed.
|
||||
function waitForSIMReady(callback) {
|
||||
SimManager.requestDataSimIcc(function _onIccId(dataSim) {
|
||||
var dataSimIcc = dataSim.icc;
|
||||
var cardState = dataSimIcc.cardState;
|
||||
|
||||
// SIM not ready
|
||||
if (cardState !== 'ready') {
|
||||
showNonReadyScreen(cardState);
|
||||
debug('SIM not ready:', cardState);
|
||||
dataSimIcc.oncardstatechange = function() {
|
||||
waitForSIMReady(callback);
|
||||
};
|
||||
|
||||
// SIM is ready
|
||||
} else {
|
||||
hideNotReadyScreen();
|
||||
debug('SIM ready. ICCID:', dataSim.iccId);
|
||||
dataSimIcc.oncardstatechange = undefined;
|
||||
callback && callback();
|
||||
}
|
||||
|
||||
// In case we can not get a valid ICCID.
|
||||
}, function _errorNoSim() {
|
||||
console.warn('Error when trying to get the ICC, SIM not detected.');
|
||||
LazyLoader.load(['/shared/js/airplane_mode_helper.js'], function() {
|
||||
AirplaneModeHelper.ready(function() {
|
||||
var fakeState = null;
|
||||
if (AirplaneModeHelper.getStatus() === 'enabled') {
|
||||
console.warn('The airplaneMode is enabled.');
|
||||
fakeState = 'airplaneMode';
|
||||
window.addEventListener('airplaneModeDisabled',
|
||||
function _onAirplanemodeDisabled(evt) {
|
||||
if (evt.detail && evt.detail.serviceId === 'data') {
|
||||
waitForSIMReady(startApp);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
showNonReadyScreen(fakeState);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Displays a faked modal dialog that can be automatically close when the SIM
|
||||
// is ready. A second call if it is already shown will only update the
|
||||
// message.
|
||||
var nonReadyScreen;
|
||||
function showNonReadyScreen(cardState) {
|
||||
|
||||
if (isApplicationLocalized) {
|
||||
realshowNonReadyScreen(cardState);
|
||||
} else {
|
||||
window.addEventListener('localized', function _onlocalized() {
|
||||
window.removeEventListener('localized', _onlocalized);
|
||||
realshowNonReadyScreen(cardState);
|
||||
});
|
||||
}
|
||||
|
||||
function realshowNonReadyScreen(messageId) {
|
||||
debug('Showing non-ready screen.');
|
||||
if (!nonReadyScreen) {
|
||||
nonReadyScreen =
|
||||
new NonReadyScreen(document.getElementById('non-ready-screen'));
|
||||
}
|
||||
nonReadyScreen.updateForState(cardState);
|
||||
vmanager.changeViewTo(nonReadyScreen.id);
|
||||
}
|
||||
}
|
||||
|
||||
function hideNotReadyScreen(status) {
|
||||
debug('Hiding non-ready screen.');
|
||||
if (vmanager.getCurrentView() === 'non-ready-screen') {
|
||||
vmanager.closeCurrentView();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX: See the module documentation for details about URL schema
|
||||
var tabmanager, settingsVManager;
|
||||
|
||||
function _onHashChange(evt) {
|
||||
var parser = document.createElement('a');
|
||||
parser.href = evt.oldURL;
|
||||
var oldHash = parser.hash.split('#');
|
||||
parser.href = evt.newURL;
|
||||
var newHash = parser.hash.split('#');
|
||||
|
||||
if (newHash.length > 3) {
|
||||
console.error('Cost Control bad URL schema');
|
||||
return;
|
||||
}
|
||||
|
||||
debug('URL schema before normalizing:', newHash);
|
||||
|
||||
var normalized = false;
|
||||
if (!newHash[1] && oldHash[1]) {
|
||||
newHash[1] = oldHash[1];
|
||||
normalized = true;
|
||||
}
|
||||
|
||||
if (newHash.length === 3 && newHash[2] === '') {
|
||||
if (oldHash.length === 3) {
|
||||
newHash[2] = oldHash[2];
|
||||
} else {
|
||||
newHash = newHash.slice(0, 2);
|
||||
}
|
||||
normalized = true;
|
||||
}
|
||||
|
||||
if (normalized) {
|
||||
debug('URL schema after normalization:', newHash);
|
||||
window.location.hash = newHash.join('#');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newHash[1]) {
|
||||
tabmanager.changeViewTo(newHash[1]);
|
||||
}
|
||||
|
||||
if (newHash.length < 3) {
|
||||
vmanager.closeCurrentView();
|
||||
} else {
|
||||
vmanager.changeViewTo(newHash[2], '#tabpanel');
|
||||
}
|
||||
}
|
||||
|
||||
function setupCardHandler() {
|
||||
// View managers for dialogs and settings
|
||||
tabmanager = new ViewManager(
|
||||
['balance-tab', 'telephony-tab', { id: 'datausage-tab', tab: 'right' }]
|
||||
);
|
||||
settingsVManager = new ViewManager();
|
||||
|
||||
// View handler
|
||||
window.addEventListener('hashchange', _onHashChange);
|
||||
}
|
||||
|
||||
function loadMessageHandler() {
|
||||
var messageHandlerFrame = document.getElementById('message-handler');
|
||||
var thereIsNextReset = ConfigManager.option('nextReset');
|
||||
var alreadyLoaded = messageHandlerFrame.src
|
||||
.contains('message_handler.html');
|
||||
|
||||
if (alreadyLoaded && thereIsNextReset) {
|
||||
setNextReset(ConfigManager.option('nextReset'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (thereIsNextReset) {
|
||||
window.addEventListener('messagehandlerready', function _setNextReset() {
|
||||
window.removeEventListener('messagehandlerready', _setNextReset);
|
||||
setNextReset(ConfigManager.option('nextReset'));
|
||||
});
|
||||
}
|
||||
messageHandlerFrame.src = 'message_handler.html';
|
||||
}
|
||||
|
||||
function _onDataSimChange() {
|
||||
// Before restarting the app, it's necessary remove the cached values of
|
||||
// costcontrol and config to force an update.
|
||||
CostControl.reset();
|
||||
ConfigManager.setConfig(null);
|
||||
SimManager.requestDataSimIcc(startApp);
|
||||
}
|
||||
|
||||
function startApp(callback) {
|
||||
// If customMode is not ready and it was activated on previous execution,
|
||||
// we have to change the setup plan to no plan.
|
||||
if (!ConfigManager.supportCustomizeMode) {
|
||||
SimManager.requestDataSimIcc(function(dataSim) {
|
||||
ConfigManager.requestSettings(dataSim.iccId, function(settings) {
|
||||
if (settings.trackingPeriod === 'custom') {
|
||||
ConfigManager.setOption({ trackingPeriod: 'never' });
|
||||
// Removing manually if a nextReset alarm exists
|
||||
// XXX: This is not part of configuration by SIM so we bypass
|
||||
// ConfigManager
|
||||
asyncStorage.getItem('nextResetAlarm', function(id) {
|
||||
// There is already an alarm, remove it
|
||||
debug('Current nextResetAlarm', id + '.', id ? 'Removing.' : '');
|
||||
if (id) {
|
||||
navigator.mozAlarms.remove(id);
|
||||
}
|
||||
asyncStorage.setItem('nextResetAlarm', null, function() {
|
||||
ConfigManager.setOption({ nextReset: null });
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (SimManager.isMultiSim()) {
|
||||
window.addEventListener('dataSlotChange', _onDataSimChange);
|
||||
}
|
||||
CostControl.getInstance(function _onCostControlReady(instance) {
|
||||
if (ConfigManager.option('fte')) {
|
||||
startFTE();
|
||||
return;
|
||||
}
|
||||
|
||||
loadMessageHandler();
|
||||
|
||||
costcontrol = instance;
|
||||
if (!initialized) {
|
||||
setupApp(callback);
|
||||
} else {
|
||||
loadSettings();
|
||||
updateUI(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var isApplicationLocalized = false;
|
||||
window.addEventListener('localized', function _onLocalize() {
|
||||
isApplicationLocalized = true;
|
||||
if (initialized) {
|
||||
updateUI();
|
||||
loadSettings();
|
||||
}
|
||||
});
|
||||
|
||||
function setupApp(callback) {
|
||||
setupCardHandler();
|
||||
|
||||
// Configure settings buttons
|
||||
var settingsButtons = document.querySelectorAll('.settings-button');
|
||||
Array.prototype.forEach.call(settingsButtons,
|
||||
function _eachSettingsButton(button) {
|
||||
button.addEventListener('click', function _showSettings() {
|
||||
window.location.hash = '##settings-view';
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// Handle 'open activity' sent by the user via the widget
|
||||
navigator.mozSetMessageHandler('activity',
|
||||
function _handleActivity(activityRequest) {
|
||||
var name = activityRequest.source.name;
|
||||
switch (name) {
|
||||
case 'costcontrol/balance':
|
||||
window.location.hash = '#balance-tab';
|
||||
break;
|
||||
case 'costcontrol/telephony':
|
||||
window.location.hash = '#telephony-tab';
|
||||
break;
|
||||
case 'costcontrol/data_usage':
|
||||
window.location.hash = '#datausage-tab';
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// When a notification is received
|
||||
window.navigator.mozSetMessageHandler('notification',
|
||||
function _onNotification(notification) {
|
||||
if (!notification.clicked) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug('Notification was clicked!');
|
||||
|
||||
navigator.mozApps.getSelf().onsuccess = function _onAppReady(evt) {
|
||||
var app = evt.target.result;
|
||||
app.launch();
|
||||
|
||||
var type = notification.data;
|
||||
debug('Notification type:', type);
|
||||
handleNotification(type);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Check card state when visible
|
||||
document.addEventListener('visibilitychange',
|
||||
function _onVisibilityChange(evt) {
|
||||
if (!document.hidden && initialized) {
|
||||
waitForSIMReady();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
updateUI(callback);
|
||||
ConfigManager.observe('plantype', updateUI, true);
|
||||
|
||||
initialized = true;
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
// Load settings in background
|
||||
function loadSettings() {
|
||||
window.performance.mark('loadSettingsStart');
|
||||
document.getElementById('settings-view-placeholder').src = 'settings.html';
|
||||
}
|
||||
|
||||
function handleNotification(type) {
|
||||
switch (type) {
|
||||
case 'topUpError':
|
||||
BalanceTab.topUpWithCode(true);
|
||||
break;
|
||||
case 'lowBalance':
|
||||
case 'zeroBalance':
|
||||
window.location.hash = '#balance-tab';
|
||||
hashFromNotification = '#balance-tab';
|
||||
break;
|
||||
case 'dataUsage':
|
||||
hashFromNotification = '#datausage-tab';
|
||||
tabmanager.changeViewTo('datausage-tab');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var currentMode;
|
||||
function updateUI(callback) {
|
||||
SimManager.requestDataSimIcc(function(dataSim) {
|
||||
ConfigManager.requestSettings(dataSim.iccId,
|
||||
function _onSettings(settings) {
|
||||
var mode = ConfigManager.getApplicationMode();
|
||||
var newHash = window.location.hash;
|
||||
var tabs = document.getElementById('tabs');
|
||||
var dataUsageTab = document.getElementById('datausage-tab');
|
||||
|
||||
debug('App UI mode: ', mode);
|
||||
|
||||
// Layout
|
||||
if (mode !== currentMode) {
|
||||
currentMode = mode;
|
||||
// Stand alone mode when data usage only
|
||||
if (mode === 'DATA_USAGE_ONLY') {
|
||||
tabs.hidden = true;
|
||||
dataUsageTab.classList.add('standalone');
|
||||
newHash = '#datausage-tab';
|
||||
|
||||
// Two tabs mode
|
||||
} else {
|
||||
dataUsageTab.classList.remove('standalone');
|
||||
tabs.hidden = false;
|
||||
document.getElementById('balance-tab-filter')
|
||||
.hidden = (mode !== 'PREPAID');
|
||||
|
||||
document.getElementById('telephony-tab-filter')
|
||||
.hidden = (mode !== 'POSTPAID');
|
||||
|
||||
// If it was showing the left tab, force changing to the
|
||||
// proper left view
|
||||
if (!isDataUsageTabShown()) {
|
||||
newHash = (mode === 'PREPAID') ? '#balance-tab#' :
|
||||
'#telephony-tab#';
|
||||
}
|
||||
}
|
||||
window.location.hash = hashFromNotification ||
|
||||
hashFromLastRun ||
|
||||
newHash;
|
||||
hashFromLastRun = hashFromNotification = null;
|
||||
|
||||
// XXX: Break initialization to allow Gecko to render the animation on
|
||||
// time.
|
||||
requestAnimationFrame(function continueLoading() {
|
||||
document.getElementById('main').classList.remove('non-ready');
|
||||
|
||||
if (mode === 'PREPAID') {
|
||||
if (typeof TelephonyTab !== 'undefined') {
|
||||
TelephonyTab.finalize();
|
||||
}
|
||||
if (typeof BalanceTab !== 'undefined') {
|
||||
BalanceTab.initialize();
|
||||
}
|
||||
} else if (mode === 'POSTPAID') {
|
||||
if (typeof BalanceTab !== 'undefined') {
|
||||
BalanceTab.finalize();
|
||||
}
|
||||
if (typeof TelephonyTab !== 'undefined') {
|
||||
TelephonyTab.initialize();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
(typeof callback === 'function') && callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isDataUsageTabShown() {
|
||||
return window.location.hash.split('#')[1] === 'datausage-tab';
|
||||
}
|
||||
|
||||
function onFteFinished(e) {
|
||||
if (e.origin !== Common.COST_CONTROL_APP) {
|
||||
return;
|
||||
}
|
||||
var type = e.data.type;
|
||||
if (type === 'fte_finished') {
|
||||
window.removeEventListener('message', onFteFinished);
|
||||
document.getElementById('splash_section').hidden = 'true';
|
||||
|
||||
// Only hide the FTE view when everything in the UI is ready
|
||||
ConfigManager.requestAll(function() {
|
||||
startApp(Common.closeFTE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function startFTE() {
|
||||
window.addEventListener('message', onFteFinished);
|
||||
var mode = ConfigManager.getApplicationMode();
|
||||
Common.startFTE(mode);
|
||||
}
|
||||
|
||||
function initApp() {
|
||||
// The location hash keeps its current value even if the app is killed by
|
||||
// the oom killer.
|
||||
hashFromLastRun = window.location.hash;
|
||||
window.location.hash = '';
|
||||
vmanager = new ViewManager();
|
||||
waitForSIMReady(startApp);
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
var SCRIPTS_NEEDED = [
|
||||
'js/utils/debug.js',
|
||||
'js/common.js',
|
||||
'js/views/NonReadyScreen.js',
|
||||
'js/utils/toolkit.js',
|
||||
'js/view_manager.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() {
|
||||
vmanager = new ViewManager();
|
||||
showNonReadyScreen(null);
|
||||
});
|
||||
} else {
|
||||
SCRIPTS_NEEDED = [
|
||||
'js/sim_manager.js',
|
||||
'js/utils/debug.js',
|
||||
'shared/js/date_time_helper.js',
|
||||
'js/utils/chart.js',
|
||||
'js/utils/formatting.js',
|
||||
'js/utils/toolkit.js',
|
||||
'js/settings/networkUsageAlarm.js',
|
||||
'js/common.js',
|
||||
'js/costcontrol.js',
|
||||
'js/config/config_manager.js',
|
||||
'js/views/NonReadyScreen.js',
|
||||
'js/view_manager.js'
|
||||
];
|
||||
LazyLoader.load(SCRIPTS_NEEDED, initApp);
|
||||
}
|
||||
// Tell audio channel manager that we want to adjust the notification
|
||||
// channel if the user press the volumeup/volumedown buttons in Usage.
|
||||
if (navigator.mozAudioChannelManager) {
|
||||
navigator.mozAudioChannelManager.volumeControlChannel = 'notification';
|
||||
}
|
||||
},
|
||||
reset: function() {
|
||||
costcontrol = null;
|
||||
initialized = false;
|
||||
vmanager = null;
|
||||
tabmanager = null;
|
||||
settingsVManager = null;
|
||||
currentMode = null;
|
||||
isApplicationLocalized = false;
|
||||
window.removeEventListener('dataSlotChange', _onDataSimChange);
|
||||
window.removeEventListener('hashchange', _onHashChange);
|
||||
window.removeEventListener('message', onFteFinished);
|
||||
window.location.hash = '';
|
||||
nonReadyScreen = null;
|
||||
},
|
||||
showBalanceTab: function _showBalanceTab() {
|
||||
window.location.hash = '#balance-tab';
|
||||
},
|
||||
showDataUsageTab: function _showDataUsageTab() {
|
||||
window.location.hash = '#datausage-tab';
|
||||
},
|
||||
showAppDetailView: function _showAppDetailView() {
|
||||
window.location.hash = '##appdetail-view';
|
||||
},
|
||||
_onHashChange: _onHashChange
|
||||
};
|
||||
}());
|
||||
Loading…
Reference in a new issue