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,373 @@
/* global debug, SimManager, LazyLoader, asyncStorage, deepCopy */
/* exported ConfigManager */
'use strict';
var ConfigManager = (function() {
var today = new Date();
var DEFAULT_SETTINGS = {
'dataLimit': false,
'dataLimitValue': 1,
'dataLimitUnit': 'GB',
'errors': {
'INCORRECT_TOPUP_CODE': false,
'BALANCE_TIMEOUT': false,
'TOPUP_TIMEOUT': false
},
'fte': true,
'waitingForBalance': null,
'waitingForTopUp': null,
'lastBalance': null,
'lastBalanceRequest': null,
'lastTopUpRequest': null,
'lastDataUsage': {
'timestamp': today,
'start': today,
'end': today,
'today': today,
'wifi': {
'apps': {},
'total': 0
},
'mobile': {
'apps': {},
'total': 0
}
},
'lastTelephonyActivity': {
'timestamp': today,
'calltime': 0,
'smscount': 0
},
'lastTelephonyReset': today,
'lastDataReset': today,
'lastCompleteDataReset': today,
'lowLimit': false,
'lowLimitThreshold': false,
'lowLimitNotified': false,
'zeroBalanceNotified': false,
'dataUsageNotified': false,
'nextReset': null,
'plantype': 'postpaid',
'resetTime': 1,
'trackingPeriod': 'monthly',
'isMobileChartVisible': true,
'isWifiChartVisible': false
};
var CONFIG_CACHE = [];
function getApplicationMode() {
if (noConfigFound) {
return 'DATA_USAGE_ONLY';
}
return settings.plantype.toUpperCase();
}
var configuration, configurationIndex, noConfigFound = false;
function setConfig(newConfiguration) {
configuration = newConfiguration;
debug('Provider configuration done!');
}
// Load the operator configuration according to MCC_MNC pair
function requestConfiguration(currentDataIcc, callback) {
if (!currentDataIcc || !currentDataIcc.iccInfo) {
console.error('No iccInfo available');
return;
}
function returnConfiguration() {
if (typeof callback === 'function') {
callback(configuration);
}
}
if (configuration) {
setTimeout(function() {
returnConfiguration();
});
return;
}
if (configurationIndex) {
loadConfiguration(currentDataIcc, returnConfiguration);
} else {
loadConfigurationIndex(function onIndex() {
loadConfiguration(currentDataIcc, returnConfiguration);
});
}
}
function loadConfiguration(currentDataIcc, callback) {
var configFilePath = getConfigFilePath(currentDataIcc);
if (CONFIG_CACHE[configFilePath]) {
ConfigManager.setConfig(CONFIG_CACHE[configFilePath]);
(typeof callback === 'function') && callback();
} else {
LazyLoader.load(configFilePath, function() {
// configuration variable is set by calling setConfig() inside the
// configuration file.
CONFIG_CACHE[configFilePath] = configuration;
(typeof callback === 'function') && callback();
});
}
}
function getConfigFilePath(currentDataIcc) {
noConfigFound = false;
var mcc = currentDataIcc.iccInfo.mcc;
var mnc = currentDataIcc.iccInfo.mnc;
var key = mcc + '_' + mnc;
var configDir = configurationIndex[key];
if (!configDir) {
configDir = 'default';
noConfigFound = true;
}
return 'js/config/' + configDir + '/config.js';
}
function loadConfigurationIndex(callback) {
LazyLoader.getJSON('/js/config/index.json').then(function(json) {
configurationIndex = json;
if (configurationIndex === null) { // TODO Remove workaround when
// Bug 1069808 is fixed.
console.error('Error loading the configuration index!' +
'Response from LazyLoader was null.');
configurationIndex = {};
}
if (typeof callback === 'function') {
setTimeout(function() {
callback();
});
}
}, function(error) {
console.error('Error loading the configuration index! ' +
'Error code: ' + error);
configurationIndex = {};
});
}
// Let's serialize dates
// XXX: To avoid random error:
// "DataCloneError: The object could not be cloned."
// {file:
// "app://costcontrol.gaiamobile.org/shared/js/async_storage.js" line: 90}]
Date.prototype.toJSON = function() {
return {'__date__': this.toISOString()};
};
function settingsReviver(k, v) {
if (v === null || typeof v !== 'object' || !v.hasOwnProperty('__date__')) {
return v;
}
return new Date(v.__date__);
}
// Load stored settings
var NO_ICCID = 'NOICCID';
var settings;
function requestSettings(iccIdInfo, callback) {
var currentICCID = iccIdInfo || NO_ICCID;
asyncStorage.getItem(currentICCID, function _wrapGetItem(localSettings) {
// No entry: set defaults
try {
settings = JSON.parse(localSettings, settingsReviver);
} catch (e) {
// If we can't parse the settings, use the default ones
}
if (settings === null) {
settings = deepCopy(DEFAULT_SETTINGS);
debug('Storing default settings for ICCID:', currentICCID);
asyncStorage.setItem(currentICCID, JSON.stringify(settings),
callback && callback.bind(null, settings));
} else if (callback) {
callback(settings);
}
});
}
// Provides vendor configuration and settings
function requestAll(callback) {
SimManager.requestDataSimIcc(function(dataSimIcc) {
requestConfiguration(dataSimIcc.icc,
function _afterConfig(configuration) {
requestSettings(dataSimIcc.iccId, function _afterSettings(settings) {
if (callback) {
callback(configuration, settings, dataSimIcc.iccId);
}
});
}
);
});
}
// Produce a optionchange for the given option
function dispatchOptionChange(name, value, oldValue, settings) {
var event = new CustomEvent('optionchange', { detail: {
name: name,
value: value,
oldValue: oldValue,
settings: settings
} });
window.dispatchEvent(event);
debug('Event optionchange dispatched for', name);
}
// Set setting options asynchronously and dispatch an event for every
// affected option.
function setOption(options, callback) {
SimManager.requestDataSimIcc(function(dataSimIcc) {
// If settings is not ready, load and retry
if (!settings) {
requestSettings(dataSimIcc.iccId, function _afterEnsuringSettings() {
setOption(options, callback);
});
return;
}
// Store former values and update with new ones
var formerValue = {};
for (var name in options) {
if (options.hasOwnProperty(name)) {
formerValue[name] = settings[name];
settings[name] = options[name];
}
}
var currentICCID = dataSimIcc.iccId || NO_ICCID;
asyncStorage.setItem(currentICCID, JSON.stringify(settings),
function _onSet() {
requestSettings(dataSimIcc.iccId, function _onSettings(settings) {
for (var name in options) {
if (options.hasOwnProperty(name)) {
dispatchOptionChange(name, settings[name], formerValue[name],
settings);
}
}
if (callback) {
callback();
}
});
}
);
});
}
// Part of the synchronous interface, return or set a setting.
function syncOption(name, value) {
var oldValue = settings[name];
if (value === undefined) {
return oldValue;
}
var update = {};
update[name] = value;
setOption(update);
}
var callbacks;
// Function in charge of dispatch the events to the observers
function callCallbacks(evt) {
debug('Option', evt.detail.name, 'has changed!');
var callbackCollection = callbacks[evt.detail.name] || [];
for (var i = 0; i < callbackCollection.length; i++) {
var callback = callbackCollection[i];
if (callback) {
callback(evt.detail.value, evt.detail.oldValue, evt.detail.name,
evt.detail.settings);
}
}
}
// Installs an observer to call when the setting has changed. It produces
// an initial call to the callback unless you provide true as the last
// parameter.
function syncObserve(name, callback, avoidInitialCall) {
debug('Installing observer for', name);
// XXX: initialize this only if an observer is added
if (callbacks === undefined) {
callbacks = {};
// Keeps the synchronization when the application need to communicate
// instant information. Local storage event is used. The key sync is
// read to determine which option has changed and a settingchange event
// for that option is dispatched.
window.addEventListener('storage', function _onSync(evt) {
if (evt.key === 'sync') {
var name = evt.newValue.split('#')[0];
var oldValue = settings ? settings[name] : undefined;
debug('Synchronization request for', name, 'received!');
SimManager.requestDataSimIcc(function(dataSimIcc) {
requestSettings(dataSimIcc.iccId,
function _onSettings(newSettings) {
settings = newSettings;
dispatchOptionChange(name, settings[name], oldValue, settings);
});
});
}
});
window.addEventListener('optionchange', callCallbacks);
}
if (callbacks[name] === undefined) {
callbacks[name] = [];
}
if (callbacks[name].indexOf(callback) < 0) {
callbacks[name].push(callback);
avoidInitialCall = avoidInitialCall || false;
if (!avoidInitialCall && callback) {
callback(settings[name], null, name, settings);
}
}
}
function syncRemoveObserver(name, callback) {
var callbackCollection = callbacks[name];
if (!callbackCollection) {
return;
}
var index = callbackCollection.indexOf(callback);
if (index > -1) {
callbackCollection.splice(index, 1);
}
}
function defaultValue(name) {
return deepCopy(DEFAULT_SETTINGS[name]);
}
return {
getApplicationMode: getApplicationMode,
setConfig: setConfig,
requestAll: requestAll,
requestSettings: requestSettings,
setOption: setOption,
defaultValue: defaultValue,
// XXX:These methods are the synchronous/cached interface. You need to
// call requestAll() or requestSettings() to force cache renewal.
// If you want to use observe() and option() as a getter, you need to setup
// the cache by calling one of the former methods before. Only once is
// enough.
option: syncOption,
observe: syncObserve,
removeObserver: syncRemoveObserver,
// XXX: Once loaded via requestConfiguration() / requestAll() it is ensured
// it wont change so you can use this to access OEM confguration in a
// synchronous fashion.
get configuration() { return configuration; },
// XXX: Bug 1126178-[CostControl] Remove ConfigManager.supportCustomizeMode
// when the functionality is ready
supportCustomizeMode: false
};
}());

View file

@ -0,0 +1,4 @@
/* global ConfigManager */
'use strict';
ConfigManager.setConfig({});

View file

@ -0,0 +1,9 @@
{
"724_6": "vivo",
"724_10": "vivo",
"724_11": "vivo",
"724_23": "vivo",
"732_123": "movistar_colombia",
"748_07": "movistar_uruguay",
"716_06": "movistar_peru"
}

View file

@ -0,0 +1,22 @@
/* global ConfigManager */
'use strict';
var MovistarColombiaConfig = {
provider: 'Movistar',
is_free: true,
is_roaming_free: true,
credit: { currency: '$' },
balance: {
destination: '611',
text: 'SALDO,A',
senders: ['612', '611'],
regexp: 'Saldo total:\\$([0-9,]+)\\.([0-9]{2})',
minimum_delay: 3 * 60 * 60 * 1000 // 3h
},
topup: {
ussd_destination: '*611#'
},
default_low_limit_threshold: 2000
};
ConfigManager.setConfig(MovistarColombiaConfig);

View file

@ -0,0 +1,19 @@
/* global ConfigManager */
'use strict';
var MovistarPeruConfig = {
provider: 'Movistar',
is_free: true,
credit: { currency: 'S/.' },
balance: {
destination: '600',
text: 'S',
senders: ['515'],
regexp: '([0-9,]+)\\.([0-9]{2})',
zero_regexp: '(Usted no tiene saldo en sus cuentas)',
minimum_delay: 3 * 60 * 60 * 1000 // 3h
},
default_low_limit_threshold: 1
};
ConfigManager.setConfig(MovistarPeruConfig);

View file

@ -0,0 +1,23 @@
/* global ConfigManager */
'use strict';
var MovistarUruguayConfig = {
provider: 'Movistar',
is_free: true,
is_roaming_free: true,
credit: { currency: '$' },
balance: {
destination: '222',
text: 'SALDO',
senders: ['222'],
regexp: 'Recarga \\$([0-9,]+)(?:\\.([0-9]+))?',
zero_regexp: '(Su saldo actual es cero)',
minimum_delay: 3 * 60 * 60 * 1000 // 3h
},
topup: {
ussd_destination: '*222*1*1#'
},
default_low_limit_threshold: 0
};
ConfigManager.setConfig(MovistarUruguayConfig);

View file

@ -0,0 +1,126 @@
/* global Format, ConfigManager */
'use strict';
var VivoConfig = (function() {
var RESERVED = '0';
var OPERATION_TYPE_REQUEST = '01';
var OPERATION_CHECK_BALANCE = '0102';
var MESSAGE_INIT_WIDTH = 32;
var THOUSANDS_PADDING = 4;
var TENS_PADDING = 2;
function getDateTime() {
var now = new Date();
var date = [
Format.padLeft(now.getUTCFullYear(), THOUSANDS_PADDING, '0'),
Format.padLeft(now.getUTCMonth() + 1, TENS_PADDING, '0'),
Format.padLeft(now.getUTCDate(), TENS_PADDING, '0')
].join('');
var time = [
Format.padLeft(now.getUTCHours(), TENS_PADDING, '0'),
Format.padLeft(now.getUTCMinutes(), TENS_PADDING, '0'),
Format.padLeft(now.getUTCSeconds(), TENS_PADDING, '0')
].join('');
return [date, time];
}
/*
* VIVO request messages are formed by the concatenation of fixed length
* fields:
* - 32-length initial padding, all '0' (zero)
* - 3-length system code. Currently only 'OWD' (FirefoOS) is supported
* - 8-length date string in the form of YYYYMMDD
* - 6-length time string in the form of HHMMSS
* - 2-length operation type
* - 1-length total number of SMS for the request
* - 1-length number of the current SMS being transmitted (starting in 1)
* - 1-length reserved character. It is '0'
* - 4-length operation code
*
* Example of balance request (ignore blank spaces):
* 00000000000000000000000000000000 OWD 20130530 132006 01 1 1 0 0102
*
* A request can include parameters in a last field of variable length from
* 0 to 80 characters.
*/
function generateCheckBalanceMessage() {
var messageInit = (new Array(MESSAGE_INIT_WIDTH + 1)).join('0');
var systemCode = 'OWD';
var dateTime = getDateTime();
var date = dateTime[0];
var time = dateTime[1];
var operationType = OPERATION_TYPE_REQUEST;
var totalMessageCount = '1';
var currentMessageCount = '1';
var requestedOperation = OPERATION_CHECK_BALANCE;
return [
messageInit,
systemCode,
date,
time,
operationType,
totalMessageCount,
currentMessageCount,
RESERVED,
requestedOperation
].join('');
}
/*
* TODO:
* A VIVO answer include specific fields from the related request in such
* a way these fields form a unique ID to match each answer with its request.
*
* For example, compare this pair of request, response:
* 00000000000000000000000000000000 OWD 20130530 132006 01 1 1 0 0102
* 20130530 132006 01 1 1 0 0102 60.45
*
* Current value for the regexp used to validate a balance answer is not
* checking the unique ID since this requires to store this ID and make it
* to survive the application closes. Since access to configuration
* properties must be synchronous, we should use some kind of synchronous
* storage. As DOMStorage is discouraged and IndexedDB synchronous API is
* not ready we can not currently implement this constrain.
*/
var balanceRegularExpression = [
'^[0-9]{14}', // we admit any sequence of 14 numbers. See TODO above.
OPERATION_TYPE_REQUEST,
'1', '1',
RESERVED,
OPERATION_CHECK_BALANCE,
'([0-9]+)\\.([0-9]{1,2})' // matches the remaining balance
].join('');
return {
provider: 'Vivo',
is_free: true,
is_roaming_free: true,
credit: { currency: 'R$' },
balance: {
destination: '4850',
get text() {
return generateCheckBalanceMessage();
},
senders: ['4850'],
regexp: balanceRegularExpression,
minimum_delay: 3 * 60 * 60 * 1000 // 3h
},
topup: {
destination: '7000',
ussd_destination: '*321#',
text: '&code',
senders: ['1515', '7000'],
confirmation_regexp:
'Voce recarregou R\\$\\s*([0-9]+)(?:[,\\.]([0-9]+))?',
incorrect_code_regexp:
'(Favor enviar|envie novamente|Verifique) o codigo de recarga'
},
default_low_limit_threshold: 3
};
}());
ConfigManager.setConfig(VivoConfig);