VulpesOS/gaia/apps/costcontrol/js/common.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

456 lines
14 KiB
JavaScript
Executable file

/* global _, debug, ConfigManager, Toolkit, SimManager */
/* exported addAlarmTimeout, setNextReset, addNetworkUsageAlarm,
getTopUpTimeout, Common, sendBalanceThresholdNotification
*/
'use strict';
function addAlarmTimeout(type, delay) {
var handlerContainer = document.getElementById('message-handler');
return handlerContainer.contentWindow.addAlarmTimeout(type, delay);
}
function setNextReset(when, callback) {
var handlerContainer = document.getElementById('message-handler');
return handlerContainer ?
handlerContainer.contentWindow.setNextReset(when, callback) :
window.setNextReset(when, callback);
}
function getTopUpTimeout(callback) {
var handlerContainer = document.getElementById('message-handler');
return handlerContainer ?
handlerContainer.contentWindow.getTopUpTimeout(callback) :
window.getTopUpTimeout(callback);
}
function addNetworkUsageAlarm(dataInterface, dataLimit, onsuccess, onerror) {
var handlerContainer = document.getElementById('message-handler');
if (handlerContainer) {
handlerContainer.contentWindow
.addNetworkUsageAlarm(dataInterface, dataLimit, onsuccess, onerror);
} else {
window.addNetworkUsageAlarm(dataInterface, dataLimit, onsuccess, onerror);
}
}
function sendBalanceThresholdNotification(remaining, settings, callback) {
var handlerContainer = document.getElementById('message-handler');
if (handlerContainer) {
handlerContainer.contentWindow
.sendBalanceThresholdNotification(remaining, settings, callback);
}
}
function resetTelephony(callback) {
ConfigManager.setOption({
lastTelephonyReset: new Date(),
lastTelephonyActivity: {
calltime: 0,
smscount: 0,
timestamp: new Date()
}
}, callback);
}
var Common = {
COST_CONTROL_APP: 'app://costcontrol.gaiamobile.org',
DATA_USAGE_WARNING: 0.8,
allApps: null,
allAppsLoaded: false,
allNetworkInterfaces: null,
allNetworkInterfaceLoaded: false,
//XXX: Group of apps, whose traffic will be added to the system app.
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1079609
specialApps: [
'app://search.gaiamobile.org/manifest.webapp'
],
SYSTEM_MANIFEST: 'app://system.gaiamobile.org/manifest.webapp',
BROWSER_APP: {
manifestURL: 'app://browser.gaiamobile.org/manifest.webapp',
origin: '',
manifest: {
icons: {
'84': '/shared/resources/branding/browser_84.png',
'126': '/shared/resources/branding/browser_126.png',
'142': '/shared/resources/branding/browser_142.png',
'189': '/shared/resources/branding/browser_189.png',
'284': '/shared/resources/branding/browser_284.png'
},
name: 'browser'
}
},
startFTE: function(mode) {
var iframe = document.getElementById('fte_view');
window.addEventListener('message', function handler(e) {
if (e.origin !== Common.COST_CONTROL_APP) {
return;
}
if (e.data.type === 'fte_ready') {
window.removeEventListener('message', handler);
iframe.classList.remove('non-ready');
// PERFORMANCE MARKERS
// Designates that the app's *core* chrome or navigation interface
// exists in the DOM and is marked as ready to be displayed.
window.performance.mark('navigationLoaded');
// Designates that the app's *core* chrome or navigation interface
// has its events bound and is ready for user interaction.
window.performance.mark('navigationInteractive');
// Designates that the app is visually loaded (e.g.: all of the
// "above-the-fold" content exists in the DOM and is marked as
// ready to be displayed).
window.performance.mark('visuallyLoaded');
// Designates that the app has its events bound for the minimum
// set of functionality to allow the user to interact with the
// "above-the-fold" content.
window.performance.mark('contentInteractive');
// Start up ended when FTE ready
window.performance.mark('fullyLoaded');
}
});
iframe.src = '/fte.html' + '#' + mode;
},
closeFTE: function() {
var iframe = window.parent.document.getElementById('fte_view');
iframe.classList.add('non-ready');
iframe.src = '';
},
startApp: function() {
parent.postMessage({
type: 'fte_finished',
data: ''
}, Common.COST_CONTROL_APP);
},
closeApplication: function() {
return setTimeout(function _close() {
debug('Closing.');
window.close();
});
},
modalAlert: function(message) {
alert(message);
},
get localize() {
return navigator.mozL10n.setAttributes;
},
// Returns whether exists an nsIDOMNetworkStatsInterfaces object
// that meet the argument function criteria
getInterface: function getInterface(findFunction) {
if (!Common.allNetworkInterfaceLoaded) {
debug('Network interfaces are not ready yet');
var header = _('data-usage');
var msg = _('loading-interface-data');
this.modalAlert(header + '\n' + msg);
return;
}
if (Common.allNetworkInterfaces) {
return Common.allNetworkInterfaces.find(findFunction);
}
},
getDataSIMInterface: function _getDataSIMInterface(iccId) {
if (!iccId) {
console.warn('Undefined icc identifier, unable get data interface');
return;
}
if (iccId) {
var findCurrentInterface = function(networkInterface) {
if (networkInterface.id === iccId) {
return networkInterface;
}
};
return this.getInterface(findCurrentInterface);
}
return undefined;
},
getWifiInterface: function _getWifiInterface() {
var findWifiInterface = function(networkInterface) {
if (networkInterface.type === navigator.mozNetworkStats.WIFI) {
return networkInterface;
}
};
return this.getInterface(findWifiInterface);
},
loadApps: function() {
return new Promise(function(resolve, reject) {
if (Common.allAppsLoaded) {
resolve(Common.allApps);
return;
}
var request = window.navigator.mozApps.mgmt.getAll();
request.onsuccess = function(event) {
var appList = event.target.result;
// XXX : The data traffic of the filtered apps will be automatically
// counted as residual data. This traffic is added to the system app
// on the drawApps method located on "js/views/datausage.js"
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1084010#c0
Common.allApps = appList.filter(function(app) {
return Common.specialApps.indexOf(app.manifestURL) === -1;
});
Common.allApps.push(Common.BROWSER_APP);
Common.allAppsLoaded = true;
resolve(Common.allApps);
};
request.onerror = function() {
reject(new Error('Apps could not be loaded'));
};
});
},
loadNetworkInterfaces: function(onsuccess, onerror) {
var networks = navigator.mozNetworkStats.getAvailableNetworks();
networks.onsuccess = function() {
Common.allNetworkInterfaces = networks.result;
Common.allNetworkInterfaceLoaded = true;
if (onsuccess) {
onsuccess();
}
};
networks.onerror = function() {
console.error('Error when trying to load network interfaces');
if (onerror) {
onerror();
}
};
},
getApp: function(manifestURL) {
return this.allApps.find(function(app) {
return app.manifestURL === manifestURL;
});
},
getAppManifest: function(app) {
return app.manifest || app.updateManifest;
},
getLocalizedAppName: function(app) {
// If is System App returns label others
if (app.manifestURL === Common.SYSTEM_MANIFEST) {
return _('data-usage-other-apps');
}
// Browser app does not exist, we have to provide the localized app name
if (app.manifestURL === Common.BROWSER_APP.manifestURL) {
return _('data-usage-browser-app');
}
var manifest = this.getAppManifest(app);
var userLang = document.documentElement.lang;
var locales = manifest.locales;
var localized = locales && locales[userLang] && locales[userLang].name;
return localized || manifest.name;
},
getAppIcon: function(app) {
var manifest = this.getAppManifest(app);
var icons = manifest.icons;
var defaultImage = '../style/images/app/icons/default.png';
if (!icons || !Object.keys(icons).length) {
return defaultImage;
}
// The preferred size is 30 by the default. If we use HDPI device, we may
// use the image larger than 30 * 1.5 = 45 pixels.
var preferredIconSize = 30 * (window.devicePixelRatio || 1);
var preferredSize = Number.MAX_VALUE;
var max = 0;
for (var size in icons) {
size = parseInt(size, 10);
if (size > max) {
max = size;
}
if (size >= preferredIconSize && size < preferredSize) {
preferredSize = size;
}
}
// If there is an icon matching the preferred size, we return the result,
// if there isn't, we will return the maximum available size.
if (preferredSize === Number.MAX_VALUE) {
preferredSize = max;
}
var url = icons[preferredSize];
if (url) {
return !(/^(http|https|data):/.test(url)) ? app.origin + url : url;
} else {
return defaultImage;
}
},
getDataLimit: function _getDataLimit(settings) {
var multiplier = (settings.dataLimitUnit === 'MB') ?
1000000 : 1000000000;
return settings.dataLimitValue * multiplier;
},
resetData: function _resetData(mode, onsuccess, onerror) {
// Get all availabe Interfaces
var wifiInterface = Common.getWifiInterface();
// Ask reset for all available Interfaces
var wifiClearRequest, mobileClearRequest;
// onerror callback builder
var getOnErrorFor = function(networkInterface) {
return function() {
if (wifiClearRequest) {
wifiClearRequest.onerror = undefined;
}
if (mobileClearRequest) {
mobileClearRequest.onerror = undefined;
}
(typeof onerror === 'function') && onerror(networkInterface);
};
};
if ((mode === 'all' || mode === 'wifi') && wifiInterface) {
wifiClearRequest = navigator.mozNetworkStats.clearStats(wifiInterface);
wifiClearRequest.onerror = getOnErrorFor('wi-Fi');
}
if (mode === 'all' || mode === 'mobile') {
SimManager.requestDataSimIcc(function(dataSim) {
var currentSimcardInterface = Common.getDataSIMInterface(dataSim.iccId);
if (currentSimcardInterface) {
mobileClearRequest = navigator.mozNetworkStats
.clearStats(currentSimcardInterface);
mobileClearRequest.onerror = getOnErrorFor('simcard');
mobileClearRequest.onsuccess = function _restoreDataLimitAlarm() {
ConfigManager.requestSettings(dataSim.iccId,
function _onSettings(settings) {
if (settings.dataLimit) {
// Restore network alarm
addNetworkUsageAlarm(currentSimcardInterface,
Common.getDataLimit(settings),
function _addNetworkUsageAlarmOK() {
ConfigManager.setOption({ 'dataUsageNotified': false });
});
}
});
};
}
});
}
// Set last Reset
if (mode === 'all') {
ConfigManager.setOption({ lastCompleteDataReset: new Date() });
} else {
// Else clausure prevents running the update event twice
ConfigManager.setOption({ lastDataReset: new Date() });
}
// call onsuccess
if (typeof onsuccess === 'function') {
onsuccess();
}
},
resetAll: function _resetAll(callback) {
function logResetDataError(networkInterface) {
console.log('Error when trying to reset ' + networkInterface +
' interface');
}
Common.resetData('all', thenResetTelephony, logResetDataError);
function thenResetTelephony() {
resetTelephony(callback);
}
},
// Next automatic reset date based on user preferences
updateNextReset: function _updateNextReset(trackingPeriod, value, callback) {
if (trackingPeriod === 'never') {
setNextReset(null, callback); // remove any alarm
return;
}
var nextReset, today = new Date();
// Recalculate with month period
if (trackingPeriod === 'monthly') {
var month, year;
var monthday = parseInt(value, 10);
month = today.getMonth();
year = today.getFullYear();
if (today.getDate() >= monthday) {
month = (month + 1) % 12;
if (month === 0) {
year++;
}
}
nextReset = new Date(year, month, monthday);
if (monthday !== nextReset.getDate()) {
var LAST_DAY_OF_PREVIOUS_MONTH = 0;
// If monthday is not equal to nextReset day, it means that the selected
// reset day does not exist (e.g. 30 Feb). In this case, the reset day
// must be the last day of the previous month
nextReset.setDate(LAST_DAY_OF_PREVIOUS_MONTH);
}
// Recalculate with week period
} else if (trackingPeriod === 'weekly') {
var oneDay = 24 * 60 * 60 * 1000;
var weekday = parseInt(value, 10);
var daysToTarget = weekday - today.getDay();
if (daysToTarget <= 0) {
daysToTarget = 7 + daysToTarget;
}
nextReset = new Date();
nextReset.setTime(nextReset.getTime() + oneDay * daysToTarget);
Toolkit.toMidnight(nextReset);
}
// remove oldAlarm and set the new one
setNextReset(nextReset, callback);
},
localizeWeekdaySelector: function _localizeWeekdaySelector(selector) {
var weekStartsOnMonday =
parseInt(navigator.mozL10n.get('firstDayOfTheWeek'), 10) === 1;
debug('Week starts on monday?', weekStartsOnMonday);
var monday = selector.querySelector('.monday');
var sunday = selector.querySelector('.sunday');
var list = monday.parentNode;
if (weekStartsOnMonday) {
debug('Monday, Tuesday...');
list.insertBefore(monday, list.childNodes[0]); // monday is the first
list.appendChild(sunday); // sunday is the last
} else {
debug('Sunday, Monday...');
list.insertBefore(sunday, list.childNodes[0]); // sunday is the first
list.insertBefore(monday, sunday.nextSibling); // monday is the second
}
}
};