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,349 @@
'use strict';
/* jshint node: true */
var utils = require('utils');
// Resources helper constructor
var Resources = function(gaia, settings, appDomain) {
this.gaia = gaia;
this.settings = settings;
this.fileList = [];
this.json = {};
this.appPrefix = 'app://';
this.appURL = this.appPrefix + appDomain + '/resources/';
};
// Parse and get resources for a given JSON configuration of one operator.
// Also create an output JSON configuration for the processed resources.
Resources.prototype.getResources = function(conf) {
var operatorJSON = {};
operatorJSON.default_contacts = this.addFile(conf.default_contacts);
operatorJSON.support_contacts = this.addFile(conf.support_contacts);
operatorJSON.network_type = this.addFile(conf.network_type);
operatorJSON.known_networks = this.addFile(conf.known_networks);
operatorJSON.sms = this.addFile(conf.sms);
operatorJSON.wallpaper = this.getWallpaperResource(conf.wallpaper);
operatorJSON.ringtone = this.getRingtoneResource(conf.ringtone);
operatorJSON.power = this.getPowerResource(conf.power);
operatorJSON.search = this.getSearchResource(conf.search);
operatorJSON.keyboard_settings = this.getKeyboardResource(conf.keyboard);
operatorJSON.topsites = this.getResourceWithIcon(conf.topsites, 'topSites',
'tilePath', 'tile');
operatorJSON.browser = this.getResourceWithIcon(conf.bookmarks, 'bookmarks',
'iconPath', 'iconUri');
if ('nfc' in conf) {
operatorJSON.nfc = this.getNfcResource(conf.nfc);
}
if ('data_ftu' in conf) {
operatorJSON.data_ftu = conf.data_ftu;
}
if ('data_roaming' in conf) {
operatorJSON.data_roaming = conf.data_roaming;
}
conf['mcc-mnc'].forEach(function(mcc) {
if (Object.keys(operatorJSON).length !== 0) {
this.json[mcc] = operatorJSON;
}
}.bind(this));
};
// Get file object for a given path.
Resources.prototype.getFile = function(path) {
var distDir = this.gaia.distributionDir;
var file = utils.getFile(distDir, path);
if (!file.exists()) {
throw new Error('Invalid single variant configuration: ' +
file.path + ' not found');
}
return file;
};
// Add new resource entry in the output JSON configuration (key / value)
// and add the resource path to the resources list.
Resources.prototype.addEntry = function(resources, name) {
if (resources instanceof Array) {
this.fileList.push.apply(this.fileList, resources);
} else {
this.fileList.push(resources);
}
return '/resources/' + name;
};
// Add file to resources object
Resources.prototype.addFile = function(path, key) {
if (path) {
var file = this.getFile(path);
return this.addEntry(file, file.leafName);
}
};
// Create a new JSON file and add to resources.
Resources.prototype.createJSON = function(name, content) {
var obj = { filename: name,
content: content };
return this.addEntry(obj, obj.filename);
};
// Create new wallpaper JSON from a wallpaper file path.
Resources.prototype.getWallpaperResource = function(wallpaper) {
if (wallpaper) {
var uri;
if (wallpaper.startsWith(this.appPrefix)) {
uri = wallpaper;
} else {
var file = this.getFile(wallpaper);
if (!file) {
return;
}
uri = '/resources/' + file.leafName;
this.addEntry(file, file.leafName);
}
var content = { uri: uri,
default: this.settings['wallpaper.image'] };
var jsonName = 'wallpaper-' + utils.getHash(wallpaper) + '.json';
return this.createJSON(jsonName, content);
}
};
// Create ringtone JSON and add file.
Resources.prototype.getRingtoneResource = function(ringtone) {
if (ringtone) {
var jsonName = 'ringtone-' +
utils.getHash(JSON.stringify(ringtone)) + '.json';
var ringtoneName = ringtone.name;
if (!ringtoneName) {
throw new Error('Missing name for ringtone in single variant conf.');
}
var uri;
if (ringtone.path.startsWith(this.appPrefix)) {
uri = ringtone.path;
} else {
var file = this.getFile(ringtone.path);
if (!file) {
throw new Error('Missing path for ringtone in single variant conf.');
}
uri = '/resources/' + file.leafName;
this.addEntry(file, file.leafName);
}
var content = { uri: uri,
name: ringtoneName,
default: this.settings['dialer.ringtone.id'] };
return this.createJSON(jsonName, content);
}
};
// Create power JSON and add files.
Resources.prototype.getPowerResource = function (power) {
if (power) {
var jsonName = 'power-' + utils.getHash(JSON.stringify(power)) + '.json';
var powerJSON = power;
var poweron = power.poweron;
var poweronFile;
if (poweron) {
var poweronType = poweron.video ? 'video' : null ||
poweron.image ? 'image' : null;
if (!poweronType) {
throw new Error('Invalid poweron type, only video or image are ' +
'valid.');
}
if (poweron[poweronType].startsWith(this.appPrefix)) {
powerJSON.poweron[poweronType] = poweron[poweronType];
} else {
poweronFile = this.getFile(poweron[poweronType]);
this.addEntry(poweronFile, poweronFile.leafName);
powerJSON.poweron[poweronType] = this.appURL + poweronFile.leafName;
}
}
var poweroff = power.poweroff;
var poweroffFile;
if (poweroff) {
var poweroffType = poweroff.video ? 'video' : null ||
poweroff.image ? 'image' : null;
if (!poweroffType) {
throw new Error('Invalid poweroff type, only video or image are ' +
'valid.');
}
if (poweroff[poweroffType].startsWith(this.appPrefix)) {
powerJSON.poweroff[poweroffType] = poweroff[poweroffType];
} else {
poweroffFile = this.getFile(poweroff[poweroffType]);
this.addEntry(poweroffFile, poweroffFile.leafName);
powerJSON.poweroff[poweroffType] = this.appURL + poweroffFile.leafName;
}
}
return this.createJSON(jsonName, powerJSON);
}
};
// Create search JSON and add files.
Resources.prototype.getSearchResource = function (searchPath) {
if (searchPath) {
var file = this.getFile(searchPath);
var searchContent = utils.getJSON(file);
searchContent.forEach(function(engine) {
if (!engine.iconPath.startsWith(this.appPrefix)) {
var searchFile = this.getFile(engine.iconPath);
this.addEntry(searchFile, searchFile.leafName);
engine.iconUrl = this.appURL + searchFile.leafName;
delete engine.iconPath;
}
}.bind(this));
return this.createJSON(file.leafName, searchContent);
}
};
// Create keyboard JSON.
Resources.prototype.getKeyboardResource = function (keyboard) {
if (keyboard) {
var file = utils.getFile(this.gaia.distributionDir, keyboard);
if (!file.exists()) {
throw new Error('Invalid single variant configuration: ' +
file.path + ' not found');
}
var defaults = {
'keyboard.vibration': this.settings['keyboard.vibration'],
'keyboard.autocorrect': this.settings['keyboard.autocorrect'],
'keyboard.clicksound': this.settings['keyboard.clicksound'],
'keyboard.wordsuggestion': this.settings['keyboard.wordsuggestion']
};
var content = { values: utils.getJSON(file),
defaults: defaults };
for (var value in content.values) {
if (!value.startsWith('keyboard.')) {
throw new Error('Invalid keyboard property \'' + value + '\' in file ' +
file.path + ', keyboard properties must start ' +
'with \'keyboard.\'');
}
}
var jsonName = 'keyboard-' + utils.getHash(keyboard) + '.json';
return this.createJSON(jsonName, content);
}
};
Resources.prototype.getResourceWithIcon = function(aFilePath, aRootKey,
aIconPathKey, aIconOutKey) {
if (aFilePath) {
var file = this.getFile(aFilePath);
var json = utils.getJSON(file);
json[aRootKey].forEach(function(elem) {
if (elem[aIconPathKey]) {
var iconFile = this.getFile(elem[aIconPathKey]);
var icon = utils.getFileAsDataURI(iconFile);
elem[aIconOutKey] = icon;
delete elem[aIconPathKey];
}
}.bind(this));
return this.createJSON(file.leafName, json);
}
};
// Create nfc JSON.
Resources.prototype.getNfcResource = function(nfc) {
var content = { isEnabled: nfc,
default: this.settings['nfc.enabled'] };
var jsonName = 'nfc-' + utils.getHash(JSON.stringify(content)) + '.json';
return this.createJSON(jsonName, content);
};
// OperatorAppBuilder constructor object.
var OperatorAppBuilder = function() {
};
// set destination directory, application directory and get settings in order
// to set default values.
OperatorAppBuilder.prototype.setOptions = function(options) {
this.stageDir = utils.getFile(options.STAGE_APP_DIR);
this.gaia = utils.gaia.getInstance(options);
var settingsFile = utils.getFile(options.PROFILE_DIR, 'settings.json');
if (!settingsFile.exists()) {
throw new Error('file not found: ' + settingsFile.path);
}
this.settings = utils.getJSON(settingsFile);
this.appDir = utils.getFile(options.APP_DIR);
this.appDomain = this.appDir.leafName + '.' + options.GAIA_DOMAIN;
};
// Get resources and copy files and configuration JSON to build_stage folder.
OperatorAppBuilder.prototype.generateCustomizeResources = function() {
if (!this.gaia.distributionDir) {
return;
}
var variantFile = utils.getFile(this.gaia.distributionDir, 'variant.json');
if (variantFile.exists()) {
var resources = this.getSingleVariantResources(variantFile);
var resourceDirFile = utils.getFile(this.stageDir.path, 'resources');
utils.ensureFolderExists(resourceDirFile);
var customizationFile = utils.getFile(this.stageDir.path,
'resources', 'customization.json');
utils.writeContent(customizationFile, JSON.stringify(resources.json));
resources.fileList.forEach(function(file) {
if (!file.filename && !file.content) {
utils.copyFileTo(file.path, resourceDirFile.path, file.leafName);
} else {
var resourceFile = utils.getFile(resourceDirFile.path, file.filename);
utils.writeContent(resourceFile, JSON.stringify(file.content));
}
});
} else {
utils.log('operatorvariant',
'Single variant resources will not be added since ' +
variantFile.path + ' not found');
}
};
// Use Resources object to get the resources for each operator.
OperatorAppBuilder.prototype.getSingleVariantResources = function(svConfFile) {
var svConf = utils.getJSON(svConfFile);
var resources = new Resources(this.gaia, this.settings, this.appDomain);
svConf.operators.forEach(function(operator) {
resources.getResources(operator);
});
return resources;
};
OperatorAppBuilder.prototype.execute = function(options) {
utils.copyToStage(options);
this.setOptions(options);
this.generateCustomizeResources(options);
};
exports.execute = function(options) {
(new OperatorAppBuilder()).execute(options);
};

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<script type="text/javascript" src="/shared/js/lazy_loader.js"></script>
<script type="text/javascript" src="/shared/js/bookmarks_database.js"></script>
<script type="text/javascript" src="js/resources.js"></script>
<script type="text/javascript" src="js/operator_variant.js"></script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,32 @@
/* global Customizer */
/* global BookmarksDatabase */
'use strict';
var BrowserCustomizer = function() {
Customizer.call(this, 'browser', 'json');
this.set = function(aData) {
if (!aData || ! aData.bookmarks) {
return;
}
var self = this;
aData.bookmarks.forEach(function(bookmark) {
if (!bookmark.uri || !bookmark.title) {
return;
}
var data = {
type: 'url',
name: bookmark.title,
url: bookmark.uri,
icon: bookmark.iconUri
};
BookmarksDatabase.add(data);
}, self);
};
};
var browserCustomizer = new BrowserCustomizer();
browserCustomizer.init();

View file

@ -0,0 +1,34 @@
/* global Resources */
/* exported Customizer */
'use strict';
// Extend this class for creating a new customizer and provide
// a set() method. It is expected set() returns nothing and accept
// an unique parameter which is an object of the type specified
// in the constructor of the customizer.
var Customizer = (function(setting, resourceType, onerror) {
var self = this;
this.init = function() {
window.addEventListener('customization', function eventHandler(event) {
if (event.detail.setting === setting) {
window.removeEventListener('customization', eventHandler);
var value = event.detail.value;
self.simPresentOnFirstBoot = event.detail.simPresentOnFirstBoot;
// If resourceType === 'data' the value received contains directly the
// value that the customizer will proccess.
// In other case the value will have the resource to be loaded by the
// customizer.
if (resourceType === 'data') {
self.set(value);
} else {
Resources.load(value, resourceType, self.set.bind(self),
function onerrorRetrieving(status) {
console.error('Customizer.js: Error retrieving the resource.');
onerror && onerror(status);
});
}
}
});
};
});

View file

@ -0,0 +1,20 @@
/* global Customizer */
'use strict';
var DataFTUCustomizer = (function() {
Customizer.call(this, 'data_ftu', 'data');
this.set = function(aIsEnabled) {
try {
navigator.mozSettings.createLock().set({
'ftu.ril.data.enabled': aIsEnabled
});
} catch (e) {
console.log('DataFTUCustomizer. Error recovering datas. ' +
'We will use default values. ' + e);
}
};
});
var dataFTUCustomizer = new DataFTUCustomizer();
dataFTUCustomizer.init();

View file

@ -0,0 +1,31 @@
/* global Customizer */
'use strict';
var DataRoamingCustomizer = (function() {
Customizer.call(this, 'data_roaming', 'data');
this.set = function(isEnabled) {
if (typeof isEnabled !== 'boolean') {
console.error('DataRoamingCustomizer. Invalid type for input value.');
return;
}
if (!this.simPresentOnFirstBoot) {
console.log('DataRoamingCustomizer. No first RUN with configured SIM.');
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('DataRoamingCustomizer. Settings is not available');
return;
}
settings.createLock().set({
'ril.data.roaming_enabled': isEnabled
});
};
});
var dataRoamingCustomizer = new DataRoamingCustomizer();
dataRoamingCustomizer.init();

View file

@ -0,0 +1,22 @@
/* global Customizer, mozContact */
'use strict';
var DefaultContactsCustomizer = (function() {
Customizer.call(this, 'default_contacts', 'json');
this.set = function(contacts) {
function errorHandler(contact, evt) {
console.error('Saving default contact failed: ' + evt && evt.target &&
evt.target.error && evt.target.error.name);
console.error('Error while saving ' + JSON.stringify(contact));
}
for (var i = 0; i < contacts.length; ++i) {
var contact = new mozContact(contacts[i]);
var savingContact = navigator.mozContacts.save(contact);
savingContact.onerror = errorHandler.bind(null, contact);
}
};
});
var defaultContactsCustomizer = new DefaultContactsCustomizer();
defaultContactsCustomizer.init();

View file

@ -0,0 +1,56 @@
/* global Customizer */
'use strict';
var KeyboardSettingsCustomizer = (function() {
Customizer.call(this, 'keyboard_settings', 'json');
this.set = function(keybrdParams) {
if (!this.simPresentOnFirstBoot) {
console.log('KeyboardSettingsCustomizer. ' +
'Skipping configuration since there was no SIM at first run');
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('KeyboardSettingsCustomizer. Settings is not available');
return;
}
function setKeyboard() {
try {
var settingsValue = {};
for (var key in keybrdParams.values) {
// we don't want falsy/truely values. We only accept explicit values
// for keyboard settings. Any other value is considered a
// configuration error.
if (typeof keybrdParams.values[key] == 'boolean') {
settingsValue[key] = keybrdParams.values[key];
}
}
settings.createLock().set(settingsValue);
} catch (e) {
console.log('KeyboardSettingsCustomizer. Error recovering datas. ' + e);
}
}
// First of all, we should verify the parameters
if (!keybrdParams || !keybrdParams.values) {
console.error('KeyboardCustomizer -> Configuration error: ' +
'Defaults parameters or new values have not been received');
return;
}
// If we have not new values to set we have already done
var numNewValues = Object.keys(keybrdParams.values).length;
if (numNewValues === 0) {
console.log('KeyboardCustomizer -> New values has not received');
return;
}
setKeyboard();
};
});
var keyboardSettingsCustomizer = new KeyboardSettingsCustomizer();
keyboardSettingsCustomizer.init();

View file

@ -0,0 +1,124 @@
/* global Customizer */
'use strict';
var KnownNetworksCustomizer = (function() {
Customizer.call(this, 'known_networks', 'json');
function isValidWepKey(password) {
switch (password.length) {
case 5:
case 13:
case 16:
case 29:
return true;
case 10:
case 26:
case 32:
case 58:
return !/[^a-fA-F0-9]/.test(password);
default:
return false;
}
}
function getNetwork(aNetParams) {
if (!aNetParams || !aNetParams.ssid) {
return;
}
var net = {};
net.ssid = aNetParams.ssid;
if (!aNetParams.keyType) {
return net;
}
net.keyManagement = aNetParams.keyType;
net.security = [aNetParams.keyType];
net.capabilities = aNetParams.capabilities ? [aNetParams.capabilities] : [];
switch (aNetParams.keyType) {
case 'WPA-PSK':
if (aNetParams.password && aNetParams.password.length >= 8) {
net.psk = aNetParams.password;
}
break;
case 'WPA-EAP':
if (!aNetParams.eap) {
break;
}
net.eap = aNetParams.eap;
switch (aNetParams.eap) {
case 'SIM':
break;
case 'PEAP':
case 'TLS':
case 'TTLS':
var properties = ['password', 'identity', 'phase2', 'pin',
'serverCertificate'];
for (var i = 0, l = properties.length; i < l; i++) {
if (aNetParams[properties[i]]) {
net[properties[i]] = aNetParams[properties[i]];
}
}
break;
}
break;
case 'WEP':
if (aNetParams.password && isValidWepKey(aNetParams.password)) {
net.wep = aNetParams.password;
}
break;
}
return net;
}
this.set = function(aNetworksParams) {
try {
if (!aNetworksParams) {
return;
}
var wifiManager = navigator.mozWifiManager;
if (!wifiManager) {
return;
}
var req = wifiManager.getKnownNetworks();
req.onerror = function onError() {
console.log('Error configuring SV knownNetworks. ' + req.error.name);
wifiManager = null;
};
req.onsuccess = function onSuccess() {
var allKnownNetArr = req.result;
var numKnownNet = allKnownNetArr.length;
var allKnownNet = {};
for (var i = 0; i < numKnownNet; i++) {
allKnownNet[allKnownNetArr[i].ssid] = allKnownNetArr[i];
if (aNetworksParams[allKnownNetArr[i].ssid]) {
delete aNetworksParams[allKnownNetArr[i].ssid];
}
}
allKnownNetArr = null;
for (var key in aNetworksParams) {
var netParams = aNetworksParams[key];
if (!allKnownNet[netParams.ssid]) {
var network = getNetwork(netParams);
if (network) {
network.dontConnect = true;
network = new window.MozWifiNetwork(network);
wifiManager.associate(network);
allKnownNet[network.ssid] = network;
}
}
}
wifiManager = null;
};
} catch (e) {
console.log('KnownNetworksCustomizer. Error recovering wifis. ' + e);
}
};
});
var knownNetworksCustomizer = new KnownNetworksCustomizer();
knownNetworksCustomizer.init();

View file

@ -0,0 +1,38 @@
/* global Customizer */
'use strict';
var NetworkTypeCustomizer = (function() {
Customizer.call(this, 'network_type', 'json');
this.set = function(aDatas) {
try {
if (!aDatas) {
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('NetworkTypeCustomizer. Settings is not available');
return;
}
var settingsValue = {};
for (var key in aDatas) {
settingsValue[key] = aDatas[key];
}
if (Object.keys(settingsValue).length) {
settings.createLock().set({
'operatorResources.data.icon': settingsValue
});
}
} catch (e) {
console.error('NetworkTypeCustomizer. Error recovering datas. ' +
'We will use default values. ' + e);
}
};
});
var networkTypeCustomizer = new NetworkTypeCustomizer();
networkTypeCustomizer.init();

View file

@ -0,0 +1,43 @@
/* global Customizer */
'use strict';
var NfcCustomizer = (function() {
Customizer.call(this, 'nfc', 'json');
this.set = function(nfcParams) {
if (!this.simPresentOnFirstBoot) {
console.log('NfcCustomizer. No first RUN with configured SIM.');
return;
}
const NFC_SETTING = 'nfc.enabled';
var settings = navigator.mozSettings;
if (!settings) {
console.error('NfcCustomizer. Settings is not available');
return;
}
var nfcLock = settings.createLock();
var nfc = nfcLock.get(NFC_SETTING);
// We only change the nfc value if the user does not changed it previously
// The user has changed the value if the actual value of nfc is
// different from default value.
nfc.onsuccess = function nc_onsuccess() {
var value = nfc.result[NFC_SETTING];
if (value === undefined || value === nfcParams.default) {
nfcLock.set({ 'nfc.enabled': nfcParams.isEnabled });
}
};
nfc.onerror = function wc_onerror() {
console.error('Error retrieving ' + NFC_SETTING + '. ' +
nfc.error.name);
};
};
});
var nfcCustomizer = new NfcCustomizer();
nfcCustomizer.init();

View file

@ -0,0 +1,45 @@
/* global Customizer */
'use strict';
var PowerCustomizer = (function() {
Customizer.call(this, 'power', 'json');
this.set = function(aDatas) {
if (!aDatas) {
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('PowerCustomizer. Settings is not available');
return;
}
var settingsValue = {};
if (aDatas.poweron) {
if (aDatas.poweron.video) {
settingsValue['poweron.video'] = aDatas.poweron.video;
}
if (aDatas.poweron.image) {
settingsValue['poweron.image'] = aDatas.poweron.image;
}
}
if (aDatas.poweroff) {
if (aDatas.poweroff.video) {
settingsValue['poweroff.video'] = aDatas.poweroff.video;
}
if (aDatas.poweroff.image) {
settingsValue['poweroff.image'] = aDatas.poweroff.image;
}
}
if (Object.keys(settingsValue).length) {
settings.createLock().set({
'operatorResources.power': settingsValue
});
}
};
});
var powerCustomizer = new PowerCustomizer();
powerCustomizer.init();

View file

@ -0,0 +1,37 @@
/* global Customizer, Resources */
'use strict';
var RingtoneCustomizer = (function() {
Customizer.call(this, 'ringtone', 'json');
this.set = function(ringtoneParams) {
if (!this.simPresentOnFirstBoot) {
console.log('RingtoneCustomizer. No first RUN with configured SIM.');
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('RingtoneCustomizer. Settings is not available');
return;
}
function setRingtone() {
Resources.load(ringtoneParams.uri, 'blob', function onsuccess(blob) {
settings.createLock().set({
'dialer.ringtone': blob,
'dialer.ringtone.name': ringtoneParams.name
});
}, function onerror(status) {
console.error('RingtoneCustomizer.js: Error retrieving the resource.' +
ringtoneParams.uri);
});
}
setRingtone();
};
});
var ringtoneCustomizer = new RingtoneCustomizer();
ringtoneCustomizer.init();

View file

@ -0,0 +1,25 @@
/* global Customizer */
'use strict';
var SearchCustomizer = (function() {
Customizer.call(this, 'search', 'json');
this.set = function(aData) {
if (!aData) {
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('SearchCustomizer. Settings is not available');
return;
}
settings.createLock().set({
'search.providers': aData
});
};
});
var searchCustomizer = new SearchCustomizer();
searchCustomizer.init();

View file

@ -0,0 +1,45 @@
/* global Customizer */
'use strict';
var SmsCustomizer = (function() {
Customizer.call(this, 'sms', 'json');
function getPosInteger(num, txtError) {
if (!num) {
return null;
}
var intPos = Math.floor(num);
if (isNaN(intPos) || intPos < 0) {
intPos = null;
}
return intPos;
}
this.set = function(smsParams) {
if (!smsParams) {
console.error('SmsCustomizer. Configuration parameters not received');
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('SmsCustomizer. Settings is not available');
return;
}
var maxConcatFloor = getPosInteger(smsParams.smsMaxConcat);
// Zero is wrong value too.
if (!maxConcatFloor) {
console.error('Incorrect value for max concatenated message:' +
smsParams.smsMaxConcat);
return;
}
settings.createLock().set({
'operatorResource.sms.maxConcat': maxConcatFloor
});
};
});
var smsCustomizer = new SmsCustomizer();
smsCustomizer.init();

View file

@ -0,0 +1,27 @@
/* global Customizer */
'use strict';
var SupportContactsCustomizer = (function() {
Customizer.call(this, 'support_contacts', 'json');
this.set = function(contacts) {
if (contacts) {
var settings = navigator.mozSettings;
if (!settings) {
console.error('SupportContactsCustomizer. Settings is not available');
return;
}
settings.createLock().set({
'support.onlinesupport.title': contacts.onlinesupport.title,
'support.onlinesupport.href': contacts.onlinesupport.href,
'support.callsupport1.title': contacts.callsupport1.title,
'support.callsupport1.href': contacts.callsupport1.href,
'support.callsupport2.title': contacts.callsupport2.title,
'support.callsupport2.href': contacts.callsupport2.href
});
}
};
});
var supportContactsCustomizer = new SupportContactsCustomizer();
supportContactsCustomizer.init();

View file

@ -0,0 +1,39 @@
/* global Customizer */
'use strict';
var TopSitesCustomizer = (function() {
Customizer.call(this, 'topsites', 'json');
this.set = function(topSiteConfig) {
if (!topSiteConfig ||
!topSiteConfig.topSites ||
!topSiteConfig.topSites.length) {
return;
}
this.getStore('places').then(store => {
topSiteConfig.topSites.forEach(site => {
store.get(site.url).then(place => {
if (!place) {
site.frecency = -1;
store.put(site, site.url);
}
});
});
});
};
this.getStore = function(name) {
return new Promise(resolve => {
navigator.getDataStores(name).then(stores => {
resolve(stores[0]);
});
});
};
});
var topSitesCustomizer = new TopSitesCustomizer();
topSitesCustomizer.init();

View file

@ -0,0 +1,38 @@
/* global Customizer, Resources */
'use strict';
var WallpaperCustomizer = (function() {
Customizer.call(this, 'wallpaper', 'json');
this.set = function(wallpaperParams) {
if (!this.simPresentOnFirstBoot) {
console.log('WallpaperCustomizer. No first RUN with configured SIM.');
return;
}
var settings = navigator.mozSettings;
if (!settings) {
console.error('WallpaperCustomizer. Settings is not available');
return;
}
function setWallpaper() {
Resources.load(wallpaperParams.uri, 'blob', function onsuccess(blob) {
settings.createLock().set({
'wallpaper.image': blob
});
}, function onerror(status) {
console.error('WallpaperCustomizer.js: Error retrieving the resource.' +
wallpaperParams.uri);
});
}
setWallpaper();
};
});
var wallpaperCustomizer = new WallpaperCustomizer();
wallpaperCustomizer.init();

View file

@ -0,0 +1,136 @@
/* global LazyLoader, Resources */
'use strict';
var OperatorVariantManager = {
SETTING_FTU_SIM_PRESENT: 'ftu.simPresentOnFirstBoot',
// Settings 'ftu.simPresentOnFirstBoot' only had false value if the user
// powered the phone on without SIM
// In other case we would have true or undefined depending on what process was
// executed first, so our variable is true by default.
simPresentOnFirstBoot: true,
// This file is created during the BUILD process
CUSTOMIZATION_FILE: '/resources/customization.json',
// If you want to add another customizer, you only need to add the js file
// with the implementation here
CUSTOMIZERS: [
// Base class, dont remove!
'/js/customizers/customizer.js',
// Extended classes from 'Customizer'
'/js/customizers/keyboard_settings_customizer.js',
'/js/customizers/wallpaper_customizer.js',
'/js/customizers/network_type_customizer.js',
'/js/customizers/ringtone_customizer.js',
'/js/customizers/support_contacts_customizer.js',
'/js/customizers/sms_customizer.js',
'/js/customizers/default_contacts_customizer.js',
'/js/customizers/power_customizer.js',
'/js/customizers/known_networks_customizer.js',
'/js/customizers/data_ftu_customizer.js',
'/js/customizers/nfc_customizer.js',
'/js/customizers/search_customizer.js',
'/js/customizers/default_search_customizer.js',
'/js/customizers/topsites_customizer.js',
'/js/customizers/data_roaming_customizer.js',
'/js/customizers/browser_customizer.js'
],
init: function ovm_init() {
navigator.mozSetMessageHandler('first-run-with-sim', (msg) => {
var self = this;
self.mcc_mnc = self.getMccMnc(msg.mcc, msg.mnc);
if (self.mcc_mnc) {
var settings = navigator.mozSettings;
if (!settings) {
console.log(
'Settings is not available. Cannot make the configuration changes');
return;
}
var req = settings.createLock().get(self.SETTING_FTU_SIM_PRESENT);
req.onsuccess = function osv_success(e) {
var simOnFirstBoot = req.result[self.SETTING_FTU_SIM_PRESENT];
self.simPresentOnFirstBoot = !simOnFirstBoot ||
req.result[self.SETTING_FTU_SIM_PRESENT] === self.mcc_mnc;
LazyLoader.load(
self.CUSTOMIZERS,
self.loadVariantAndCustomize.bind(self)
);
};
req.onerror = function osv_error(e) {
console.error('Error retrieving ftu.simPresentOnFirstBoot. ', e);
};
}
});
},
getMccMnc: function ovm_getMccMnc(aMcc, aMnc) {
if ((aMcc !== undefined) && (aMcc !== null) &&
(aMnc !== undefined) && (aMnc !== null)) {
return this.normalizeCode(aMcc) + '-' + this.normalizeCode(aMnc);
}
return undefined;
},
// Given a number returns a three characters string padding with zeroes
// to the left until the desired length (3) is reached
normalizeCode: function ovm_normalizeCode(aCode) {
var ncode = '' + aCode;
while (ncode.length < 3) {
ncode = '0' + ncode;
}
return ncode;
},
// Loads the variant file and start customization event dispatching.
loadVariantAndCustomize: function ovm_loadVariantAndCustomize() {
this.getVariantSettings(this.dispatchCustomizationEvents.bind(this));
},
getVariantSettings: function ovm_getVariantSettings(onsuccess, onerror) {
var filePath = this.CUSTOMIZATION_FILE;
Resources.load(filePath, 'json', function(data) {
onsuccess && onsuccess(data);
}, onerror);
},
// For each variant setting dispatch a customization event
dispatchCustomizationEvents: function ovm_dispatchEvents(customizationList) {
if (!customizationList) {
console.log('No customizers were found. Please review the content of ' +
this.CUSTOMIZATION_FILE + '.');
return;
}
function scheduleEvent(event) {
setTimeout(function() {
window.dispatchEvent(event);
}, 0);
}
var customizationSettings = customizationList[this.mcc_mnc];
if (!customizationSettings) {
console.error('There is no variant customization available for ' +
this.mcc_mnc);
return;
}
for (var setting in customizationSettings) {
if (customizationSettings.hasOwnProperty(setting)) {
var customizationEvent = new CustomEvent('customization', {
detail: {
setting: setting,
value: customizationSettings[setting],
simPresentOnFirstBoot: this.simPresentOnFirstBoot
}
});
scheduleEvent(customizationEvent);
}
}
}
};
OperatorVariantManager.init();

View file

@ -0,0 +1,55 @@
/* exported Resources */
'use strict';
var Resources = {
load: function r_load(url, type, onsuccess, onerror) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = type;
var mimetype = this.getMimetype(url);
if (mimetype) {
xhr.overrideMimeType(mimetype);
}
xhr.onload = function() {
if (xhr.status === 200) {
onsuccess && onsuccess(xhr.response);
} else {
console.error('Resources.js: Failed to fetch file ' + url + '. ' +
xhr.statusText);
onerror && onerror(xhr.statusText);
}
};
// Workaround due to https://bugzilla.mozilla.org/show_bug.cgi?id=827243
try {
xhr.send();
} catch (e) {
// TODO Remove when 827243 will be fixed.
console.error('Resources.js: Failed to fetch file ' + url + '. ' +
xhr.statusText);
onerror && onerror('404: due to bug 827243');
}
},
getMimetype: function r_getMimetype(fileName) {
var fileExtension = fileName.split('.').pop();
var mimetype = false;
if (fileExtension) {
switch (fileExtension) {
case 'ogg':
mimetype = 'audio/ogg';
break;
case 'json':
mimetype = 'application/json';
break;
case 'mp3':
mimetype = 'audio/mpeg';
break;
case 'mp4':
mimetype = 'audio/mp4';
break;
}
}
return mimetype;
}
};

View file

@ -0,0 +1,18 @@
{
"name": "operatorvariant",
"tags": {
"dictionaries": ["jsdoc"]
},
"source": {
"include": ["apps/operatorvariant/js/**/*.js"]
},
"plugins": [
"plugins/markdown",
"plugins/summarize"
],
"opts": {
"private": true,
"recurse": true,
"destination": "docs/operatorvariant"
}
}

View file

@ -0,0 +1,31 @@
{
"name": "OperatorVariant",
"description": "Operator variant configurator",
"role": "system",
"launch_path": "/index.html",
"package_path": "/application.zip",
"developer": {
"name": "The Gaia Team",
"url": "https://github.com/mozilla-b2g/gaia"
},
"type": "certified",
"messages": [
{ "first-run-with-sim": "/index.html" }
],
"permissions": {
"settings": { "access": "readwrite" },
"contacts":{ "access": "readwrite" },
"webapps-manage":{},
"wifi-manage":{}
},
"datastores-access": {
"bookmarks_store": {
"readonly": false,
"description": "Stores bookmarks"
},
"places": {
"readonly": false,
"description": "Stores data about browsing history."
}
}
}

View file

@ -0,0 +1,10 @@
{
"webide": {
"prepackage": {
"command": "make",
"env": ["APP=operatorvariant"],
"cwd": "../.."
},
"packageDir": "../../build_stage/operatorvariant/"
}
}

View file

@ -0,0 +1,31 @@
'use strict';
/* jshint node: true, mocha: true */
/* global suiteSetup */
var helper = require('helper');
suite('Operatorvariant tests', function() {
suiteSetup(helper.cleanupWorkspace);
teardown(helper.cleanupWorkspace);
test('APP=operatorvariant make', function(done) {
// Create settings for operatorvariant
helper.exec('make settings' , function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
helper.exec('APP=operatorvariant make', function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var zipPath = process.cwd() +
'/profile/webapps/operatorvariant.gaiamobile.org/application.zip';
var checkList = ['manifest.webapp'];
checkList.forEach(function(filePath) {
helper.checkFilePathInZip(zipPath, filePath);
});
done();
});
});
});
});

View file

@ -0,0 +1,17 @@
{
"extends": "../../../../.jshintrc",
"predef": [
"assert",
"suite",
"test",
"setup",
"teardown",
"suiteSetup",
"suiteTeardown",
"require",
"requireApp",
"sinon",
"mocha",
"loadBodyHTML"
]
}

View file

@ -0,0 +1,53 @@
/* global MockNavigatorDatastore, MockDatastore,
browserCustomizer, BookmarksDatabase */
'use strict';
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/browser_customizer.js');
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
require('/shared/js/bookmarks_database.js');
suite('BrowserCustomizer >', function() {
var realDatastore = null,
bookmarkDBSpy = null,
url = 'http://mozilla.org',
name = 'mozilla',
data = {
bookmarks: [ {
id: '0',
uri: url,
title: name
}]
};
suiteSetup(function() {
bookmarkDBSpy = sinon.spy(BookmarksDatabase, 'add');
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
});
suiteTeardown(function() {
navigator.getDataStores = realDatastore;
bookmarkDBSpy.restore();
});
setup(function() {
bookmarkDBSpy.reset();
});
teardown(function() {
MockDatastore._inError = false;
MockDatastore._records = Object.create(null);
});
test('First run with valid SIM. Set bookmarks.', function() {
browserCustomizer.simPresentOnFirstBoot = true;
browserCustomizer.set(data);
assert.deepEqual(bookmarkDBSpy.args[0][0], {
type: 'url',
name: name,
url: url,
icon: undefined
}, 'Arguments not equal');
});
});

View file

@ -0,0 +1,130 @@
/* global requireApp, suite, suiteSetup, sinon, Resources, setup, Customizer,
test, assert, suite, teardown, suiteTeardown */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/resources.js');
requireApp('operatorvariant/js/customizers/customizer.js');
suite(' Customizer > ', function() {
var realSettings;
var eventName = 'test-event';
var resourceType = 'blob';
var resourcePath = 'resources/wallpaper.jpg';
suite(' init > ', function() {
var resourceLoaderSpy;
var customizer;
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
resourceLoaderSpy = sinon.spy(Resources, 'load');
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
});
setup(function() {
customizer = new Customizer(eventName, resourceType);
customizer.set = function () {};
resourceLoaderSpy.reset();
});
teardown(function() {
navigator.mozSettings.mTeardown();
customizer = null;
});
suiteTeardown(function() {
resourceLoaderSpy.restore();
});
test(' resource loaded ', function() {
// Init for adding the listener
customizer.init();
// Check that listener is working as expected
var eventContent = {
detail: {
setting: eventName,
value: resourcePath,
simPresentOnFirstBoot: 'A Random Value'
}
};
var customizationEvent = new CustomEvent('customization', eventContent);
// Once we dispatch the event, handler should
// manage this properly
window.dispatchEvent(customizationEvent);
assert.isTrue(resourceLoaderSpy.calledOnce);
assert.equal(customizer.simPresentOnFirstBoot,
eventContent.detail.simPresentOnFirstBoot);
// A new event should not be handled, because
// we are removing the listener when the event
// is handled.
window.dispatchEvent(customizationEvent);
assert.isTrue(resourceLoaderSpy.calledOnce);
});
});
suite(' set > ', function() {
test(' resource available ', function(done) {
var eventContent = {
detail: {
setting: eventName,
value: resourcePath,
simPresentOnFirstBoot: 'a value'
}
};
var onerror = function() {
assert.ok(false, 'Resource not loaded properly');
done();
};
var customizerSuccessful =
new Customizer(eventName, resourceType, onerror);
customizerSuccessful.set = function() {
assert.equal(customizerSuccessful.simPresentOnFirstBoot,
eventContent.detail.simPresentOnFirstBoot);
done();
};
// Init for adding the listener
customizerSuccessful.init();
// Check that listener is working as expected
var customizationEvent = new CustomEvent('customization', eventContent);
// Once we dispatch the event, handler should
// manage this properly
window.dispatchEvent(customizationEvent);
});
test(' resource unavailable ', function(done) {
var eventContent = {
detail: {
setting: eventName,
value: 'wrong/path/file.jpg',
simPresentOnFirstBoot: 'Another value'
}
};
var customizerError = new Customizer(eventName, resourceType, function() {
assert.equal(customizerError.simPresentOnFirstBoot,
eventContent.detail.simPresentOnFirstBoot);
done();
});
customizerError.set = function() {
assert.ok(false, 'Resource available when it should not');
done();
};
// Init for adding the listener
customizerError.init();
// Check that listener is working as expected
var customizationEvent = new CustomEvent('customization', eventContent);
// Once we dispatch the event, handler should
// manage this properly
window.dispatchEvent(customizationEvent);
});
});
});

View file

@ -0,0 +1,38 @@
/* global requireApp, suite, suiteSetup, suiteTeardown, setup, teardown, test,
assert, sinon, dataFTUCustomizer */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/data_ftu_customizer.js');
suite('Data FTU customizer >', function() {
var createLockSpy;
var realSettings;
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
createLockSpy = sinon.spy(navigator.mozSettings, 'createLock');
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
createLockSpy.restore();
});
setup(function() {
createLockSpy.reset();
});
teardown(function() {
navigator.mozSettings.mTeardown();
});
test(' set > ', function() {
dataFTUCustomizer.set(true);
assert.isTrue(createLockSpy.calledOnce);
});
});

View file

@ -0,0 +1,113 @@
/* global dataRoamingCustomizer */
'use strict';
require('/test/unit/mock_navigator_moz_settings.js');
require('/js/customizers/customizer.js');
require('/js/customizers/data_roaming_customizer.js');
suite('DataRoaming customizer >', function() {
var TINY_TIMEOUT = 20;
var DATA_ROAMING_SETTING = 'ril.data.roaming_enabled';
var realSettings;
var testCases = [
{
title: 'Set true value. SIM present on first boot > ',
inputValue: true,
currentValue: false,
expectedValue: true,
simPresentOnFirstBoot: true
},
{
title: 'Set false value. SIM present on first boot > ',
inputValue: false,
currentValue: false,
expectedValue: false,
simPresentOnFirstBoot: true
},
{
title:
'Set false value, setting no defined when SIM present on first boot > ',
inputValue: false,
expectedValue: false,
simPresentOnFirstBoot: true
},
{
title:
'Set true value, setting no defined when SIM present on first boot > ',
inputValue: true,
expectedValue: true,
simPresentOnFirstBoot: true
},
{
title: 'Set to wrong value,(default false) SIM present on first boot > ',
inputValue: 12,
currentValue: false,
expectedValue: false,
simPresentOnFirstBoot: true
},
{
title: 'set true value. Previous RUN with no SIM (or unconfigured one)> ',
inputValue: true,
expectedValue: undefined,
simPresentOnFirstBoot: false
},
{
title: 'set false value. Previous RUN with no SIM (or unconfigured one)>',
inputValue: false,
expectedValue: undefined,
simPresentOnFirstBoot: false
},
{
title: 'Set false value. Expected value do not change >',
inputValue: false,
simPresentOnFirstBoot: false,
currentValue: true,
expectedValue: true
},
{
title: 'Set true value. Expected value do not change >',
inputValue: true,
simPresentOnFirstBoot: false,
currentValue: false,
expectedValue: false
}
];
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
});
setup(function() {
this.sinon.useFakeTimers();
});
teardown(function() {
navigator.mozSettings.mTeardown();
this.sinon.clock.restore();
});
testCases.forEach(function(testCase) {
test(testCase.title, function() {
if (testCase.currentValue !== undefined) {
window.MockNavigatorSettings.mSettings[DATA_ROAMING_SETTING] =
testCase.currentValue;
}
dataRoamingCustomizer.simPresentOnFirstBoot =
testCase.simPresentOnFirstBoot;
dataRoamingCustomizer.set(testCase.inputValue);
this.sinon.clock.tick(TINY_TIMEOUT);
var mSettings = window.MockNavigatorSettings.mSettings;
assert.strictEqual(mSettings[DATA_ROAMING_SETTING],
testCase.expectedValue,
DATA_ROAMING_SETTING + ' has a incorrect value');
});
});
});

View file

@ -0,0 +1,45 @@
/* global requireApp, suite, suiteSetup, MockNavigatorContacts,
MockMozContact, sinon, suiteTeardown, setup, test, defaultContactsCustomizer,
assert*/
'use strict';
requireApp('operatorvariant/test/unit/mock_mozContact.js');
requireApp('operatorvariant/test/unit/mock_navigator_contacts.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/default_contacts_customizer.js');
var mozContact;
suite('Default contacts customizer >', function() {
var realMozContacts, saveContactSpy;
var contactsMockup = [
{'givenName': ['Foo']},
{'givenName': ['Bar']}
];
suiteSetup(function() {
realMozContacts = navigator.mozContacts;
navigator.mozContacts = window.MockNavigatorContacts;
mozContact = MockMozContact;
saveContactSpy = sinon.spy(MockNavigatorContacts, 'save');
});
suiteTeardown(function() {
navigator.mozContacts = realMozContacts;
mozContact = null;
saveContactSpy.restore();
});
setup(function() {
saveContactSpy.reset();
});
test(' set ', function() {
defaultContactsCustomizer.set(contactsMockup);
// As contactsMockup has 2 contacts, this method
// should be called twice
assert.equal(saveContactSpy.callCount, contactsMockup.length);
});
});

View file

@ -0,0 +1,124 @@
/* global keyboardSettingsCustomizer, requireApp, suite, suiteSetup,
suiteTeardown, setup, teardown, test, assert */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/keyboard_settings_customizer.js');
suite('Keyboard settings customizer >', function() {
const TINY_TIMEOUT = 20;
var realSettings;
var testCases = [
{
title: 'First run with valid SIM - options with valid values > ',
inputValues: {
'values': {
'keyboard.vibration': false,
'keyboard.autocorrect': true,
'keyboard.clicksound': false,
'keyboard.wordsuggestion': true
}
},
actualValues: {
'keyboard.vibration': true,
'keyboard.autocorrect': true,
'keyboard.clicksound': false,
'keyboard.wordsuggestion': true
},
expectedValues: {
'keyboard.vibration': false,
'keyboard.autocorrect': true,
'keyboard.clicksound': false,
'keyboard.wordsuggestion': true
},
simPresentOnFirstBoot: true
},
{
title: 'First Run with valid SIM - set invalid values > ',
inputValues: {
'values': {
'keyboard.vibration': [],
'keyboard.wordsuggestion': 'aFakeValue',
'keyboard.clicksound': {}
}
},
'actualValues': {
'keyboard.vibration': true,
'keyboard.autocorrect': true,
'keyboard.clicksound': false,
'keyboard.wordsuggestion': true
},
expectedValues: {
'keyboard.vibration': true,
'keyboard.autocorrect': true,
'keyboard.clicksound': false,
'keyboard.wordsuggestion': true
},
simPresentOnFirstBoot: true
},
{
title: 'first run without valid SIM > ',
inputValues: {
'values': {
'keyboard.vibration': false,
'keyboard.autocorrect': true,
'keyboard.clicksound': false,
'keyboard.wordsuggestion': true
}
},
'actualValues': {
'keyboard.vibration': true,
'keyboard.autocorrect': true,
'keyboard.clicksound': undefined,
'keyboard.wordsuggestion': true
},
expectedValues: {
'keyboard.vibration': true,
'keyboard.autocorrect': true,
'keyboard.clicksound': undefined,
'keyboard.wordsuggestion': true
},
simPresentOnFirstBoot: false
}
];
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
});
setup(function() {
this.sinon.useFakeTimers();
});
teardown(function() {
navigator.mozSettings.mTeardown();
this.sinon.clock.restore();
});
testCases.forEach(function(testCase) {
test(testCase.title, function() {
var actualValues = testCase.actualValues;
for (var avKey in actualValues) {
window.MockNavigatorSettings.mSettings[avKey] = actualValues[avKey];
}
keyboardSettingsCustomizer.simPresentOnFirstBoot =
testCase.simPresentOnFirstBoot;
keyboardSettingsCustomizer.set(testCase.inputValues);
this.sinon.clock.tick(TINY_TIMEOUT);
var mSettings = window.MockNavigatorSettings.mSettings;
for (var evKey in testCase.expectedValues) {
assert.strictEqual(mSettings[evKey], testCase.expectedValues[evKey],
evKey + ' has a incorrect value');
}
});
});
});

View file

@ -0,0 +1,341 @@
/* global knownNetworksCustomizer, MockWindowMozWifiNetwork */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_wifi_manager.js');
requireApp('operatorvariant/test/unit/mock_window_moz_wifi_network.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/known_networks_customizer.js');
suite('Known networks customizer >', function() {
var realWifiManager;
var realWifiNetwork;
suiteSetup(function() {
realWifiManager = navigator.mozWifiManager;
navigator.mozWifiManager = window.MockNavigatorMozWifiManager;
realWifiNetwork = window.MozWifiNetwork;
window.MozWifiNetwork = MockWindowMozWifiNetwork;
});
suiteTeardown(function() {
navigator.mozWifiManager = realWifiManager;
window.MozWifiNetwork = realWifiNetwork;
window.MockNavigatorMozWifiManager = null;
});
setup(function() {
navigator.mozWifiManager.mSetup();
});
var testCases = [
{
'title': 'Wrong Wifi datas ',
'inputKeysValues': {
'bad': {
'bsid': '00:3a:9a:d1:e3:c0'
}
},
'expectedResult': []
},
{
'title': 'Wifi without key type ',
'inputKeysValues': {
'onlyId': {
'ssid': 'onlyId'
}
},
'expectedResult': [
{
'ssid': 'onlyId'
}
]
},
{
'title': 'Existing wifi ',
'inputKeysValues': {
'firstWifiAdd': {
'ssid': 'existing-Wifi',
'keyType': 'WEP',
'password': '1234567891234'
},
'existing-Wifi': {
'ssid': 'existing-Wifi',
'keyType': 'WPA-PSK',
'password': '123456789'
}
},
'expectedResult': [
{
'ssid': 'existing-Wifi',
'keyManagement': 'WEP',
'security': ['WEP'],
'capabilities': [],
'wep': '1234567891234'
}
]
},
{
'title': 'Wifi WEP without key ',
'inputKeysValues': {
'wep-without-key': {
'ssid': 'wep-without-key',
'keyType': 'WEP'
}
},
'expectedResult': [
{
'ssid': 'wep-without-key',
'keyManagement': 'WEP',
'security': ['WEP'],
'capabilities': []
}
]
},
{
'title': 'Wifi WEP with wrong key ',
'inputKeysValues': {
'wep-wrong-key': {
'ssid': 'wep-wrong-key',
'keyType': 'WEP',
'password': 'wrong1'
}
},
'expectedResult': [
{
'ssid': 'wep-wrong-key',
'keyManagement': 'WEP',
'security': ['WEP'],
'capabilities': []
}
]
},
{
'title': 'Wifi WEP OK ',
'inputKeysValues': {
'wep-ok': {
'ssid': 'wep-ok',
'keyType': 'WEP',
'password': '1234567891234'
}
},
'expectedResult': [
{
'ssid': 'wep-ok',
'keyManagement': 'WEP',
'security': ['WEP'],
'capabilities': [],
'wep': '1234567891234'
}
]
},
{
'title': 'Wifi WEP OK with WPS ',
'inputKeysValues': {
'wep-ok-wps': {
'ssid': 'wep-ok-wps',
'keyType': 'WEP',
'password': '1234567891234',
'capabilities': 'WPS'
}
},
'expectedResult': [
{
'ssid': 'wep-ok-wps',
'keyManagement': 'WEP',
'security': ['WEP'],
'capabilities': ['WPS'],
'wep': '1234567891234'
}
]
},
{
'title': 'Wifi WPA-PSK without key ',
'inputKeysValues': {
'wpa-psk-nokey': {
'ssid': 'wpa-psk-nokey',
'keyType': 'WPA-PSK'
}
},
'expectedResult': [
{
'ssid': 'wpa-psk-nokey',
'keyManagement': 'WPA-PSK',
'security': ['WPA-PSK'],
'capabilities': []
}
]
},
{
'title': 'Wifi WPA-PSK key OK ',
'inputKeysValues': {
'wpa-psk-ok': {
'ssid': 'wpa-psk-ok',
'keyType': 'WPA-PSK',
'password': '123456789'
}
},
'expectedResult': [
{
'ssid': 'wpa-psk-ok',
'keyManagement': 'WPA-PSK',
'security': ['WPA-PSK'],
'capabilities': [],
'psk': '123456789'
}
]
},
{
'title': 'Wifi WPA-PSK wrong key ',
'inputKeysValues': {
'wpa-psk-ko-key': {
'ssid': 'wpa-psk-ko-key',
'keyType': 'WPA-PSK',
'password': '1234',
'capabilities': 'WPS'
}
},
'expectedResult': [
{
'ssid': 'wpa-psk-ko-key',
'keyManagement': 'WPA-PSK',
'security': ['WPA-PSK'],
'capabilities': ['WPS']
}
]
},
{
'title': 'Wifi WPA-PSK wrong key ',
'inputKeysValues': {
'wpa-psk-ko-key': {
'ssid': 'wpa-psk-ko-key',
'keyType': 'WPA-PSK',
'password': '1234'
}
},
'expectedResult': [
{
'ssid': 'wpa-psk-ko-key',
'keyManagement': 'WPA-PSK',
'security': ['WPA-PSK'],
'capabilities': []
}
]
},
{
'title': 'Wifi WPA-EAP without eap ',
'inputKeysValues': {
'wpa-eap-no-eap': {
'ssid': 'wpa-eap-no-eap',
'keyType': 'WPA-EAP'
}
},
'expectedResult': [
{
'ssid': 'wpa-eap-no-eap',
'keyManagement': 'WPA-EAP',
'security': ['WPA-EAP'],
'capabilities': []
}
]
},
{
'title': 'Wifi WPA-EAP wrong eap ',
'inputKeysValues': {
'wpa-eap-ko-eap': {
'ssid': 'wpa-eap-ko-eap',
'keyType': 'WPA-EAP',
'eap': 'wrong'
}
},
'expectedResult': [
{
'ssid': 'wpa-eap-ko-eap',
'keyManagement': 'WPA-EAP',
'security': ['WPA-EAP'],
'capabilities': [],
'eap': 'wrong'
}
]
},
{
'title': 'Wifi WPA-EAP eap=SIM ',
'inputKeysValues': {
'wpa-eap-sim': {
'ssid': 'wpa-eap-sim',
'keyType': 'WPA-EAP',
'eap': 'SIM'
}
},
'expectedResult': [
{
'ssid': 'wpa-eap-sim',
'keyManagement': 'WPA-EAP',
'security': ['WPA-EAP'],
'capabilities': [],
'eap': 'SIM'
}
]
},
{
'title': 'Wifi WPA-EAP eap ok and not SIM with key ok ',
'inputKeysValues': {
'wpa-eap-peap': {
'ssid': 'wpa-eap-peap',
'keyType': 'WPA-EAP',
'capabilities': 'WPS',
'eap': 'PEAP',
'password': '123456789',
'identity': 'HI\\cjc'
}
},
'expectedResult': [
{
'ssid': 'wpa-eap-peap',
'keyManagement': 'WPA-EAP',
'security': ['WPA-EAP'],
'capabilities': ['WPS'],
'eap': 'PEAP',
'password': '123456789',
'identity': 'HI\\cjc'
}
]
},
{
'title': 'Wifi WPA-EAP eap ok and not SIM with phase2 ok ',
'inputKeysValues': {
'wpa-eap-peap-phase2': {
'ssid': 'wpa-eap-peap-phase2',
'keyType': 'WPA-EAP',
'capabilities': 'WPS',
'eap': 'PEAP',
'password': '123456789',
'identity': 'HI\\cjc',
'phase2': 'PAP'
}
},
'expectedResult': [
{
'ssid': 'wpa-eap-peap-phase2',
'keyManagement': 'WPA-EAP',
'security': ['WPA-EAP'],
'capabilities': ['WPS'],
'eap': 'PEAP',
'password': '123456789',
'identity': 'HI\\cjc',
'phase2': 'PAP'
}
]
}
];
testCases.forEach(function(testCase) {
test(testCase.title, function() {
knownNetworksCustomizer.set(testCase.inputKeysValues);
var knownNet = navigator.mozWifiManager.getKnownNetworks().result;
assert.deepEqual(knownNet, testCase.expectedResult,
'Known networks not equals');
});
});
});

View file

@ -0,0 +1,13 @@
'use strict';
function MockFileReader() {}
MockFileReader.prototype.readAsDataURL = function readAsText(file) {
if (this.onloadend) {
this.result = file;
this.onloadend();
}
};
window.MockFileReader = MockFileReader;

View file

@ -0,0 +1,13 @@
'use strict';
var MockMozContact = (function() {});
MockMozContact.prototype.init = function(obj) {
var self = this;
Object.keys(obj).forEach(function(k) {
self[k] = obj[k];
});
};
MockMozContact.prototype.save = function() {};

View file

@ -0,0 +1,19 @@
'use strict';
var MockNavigatorContacts = (function() {
var contacts = [];
return {
save: function(contact) {
contacts.push(contact);
return {};
},
get contacts() {
return contacts;
},
resetContacts: function() {
contacts = [];
}
};
})();
window.MockNavigatorContacts = MockNavigatorContacts;

View file

@ -0,0 +1,91 @@
'use strict';
var MockNavigatorSettings = (function() {
var observers = {};
// Set default message size with 300KB
var settings = {
'dom.mms.operatorSizeLimitation' : 300
};
var removedObservers = {};
function mns_mLockSet(obj) {
for (var key in obj) {
settings[key] = obj[key];
}
return {};
}
function mns_mLockGet(key) {
var resultObj = {};
resultObj[key] = settings[key];
var settingsRequest = {
result: resultObj,
addEventListener: function(name, cb) {
settingsRequest['on' + name] = cb;
}
};
setTimeout(function() {
if (settingsRequest.onsuccess) {
settingsRequest.onsuccess();
}
});
return settingsRequest;
}
function mns_addObserver(name, cb) {
observers[name] = observers[name] || [];
observers[name].push(cb);
}
function mns_removeObserver(name, cb) {
removedObservers[name] = removedObservers[name] || [];
removedObservers[name].push(cb);
}
function mns_createLock() {
return {
set: mns_mLockSet,
get: mns_mLockGet
};
}
function mns_mTriggerObservers(name, args) {
var theseObservers = observers[name];
if (! theseObservers) {
return;
}
theseObservers.forEach(function(func) {
func(args);
});
}
function mns_teardown() {
observers = {};
settings = {};
removedObservers = {};
}
return {
addObserver: mns_addObserver,
removeObserver: mns_removeObserver,
createLock: mns_createLock,
mTriggerObservers: mns_mTriggerObservers,
mTeardown: mns_teardown,
get mObservers() {
return observers;
},
get mSettings() {
return settings;
},
get mRemovedObservers() {
return removedObservers;
}
};
})();
window.MockNavigatorSettings = MockNavigatorSettings;

View file

@ -0,0 +1,56 @@
/* exported MockNavigatorMozWifiManager */
'use strict';
var MockNavigatorMozWifiManager = (function() {
var networks;
var knownNetworks = [];
function mwm_setNetworks(aNetworks) {
networks = aNetworks;
}
function mwm_associate(network) {
if (network.dontConnect) {
delete network.dontConnect;
}
knownNetworks.push(network);
}
function mwm_getKnownNetworks() {
/*jshint validthis: true */
var self = this;
return {
result: self.knownNetworks,
set onsuccess(callback) {
this.result = self.knownNetworks;
callback && callback(this);
},
get onsuccess() {
}
};
}
function mwm_mSetup() {
networks = undefined;
knownNetworks = [];
}
return {
get networks() {
return networks;
},
get knownNetworks() {
return knownNetworks;
},
setNetworks: mwm_setNetworks,
connection: {
network: null
},
associate: mwm_associate,
getKnownNetworks: mwm_getKnownNetworks,
mSetup: mwm_mSetup
};
})();
window.MockNavigatorMozWifiManager = MockNavigatorMozWifiManager;

View file

@ -0,0 +1,9 @@
/* exported MockWindowMozWifiNetwork */
'use strict';
function MockWindowMozWifiNetwork(network) {
for (var elem in network) {
this[elem] = network[elem];
}
}

View file

@ -0,0 +1,89 @@
'use strict';
(function() {
var lastInstance;
// To avoid race conditions between defining the XHR and sending the data
var storedResponse;
function MockXMLHttpRequest() {
lastInstance = this;
}
var throwAtNextSend = false,
objectToThrow = null;
function mxhr_mThrowAtNextSend(e) {
throwAtNextSend = true;
objectToThrow = e || new Error('throwing an exception');
}
function mxhr_mTeardown() {
throwAtNextSend = false;
objectToThrow = null;
delete MockXMLHttpRequest.mLastOpenedUrl;
lastInstance = null;
storedResponse = undefined;
}
function mxhr_send() {
if (throwAtNextSend) {
throwAtNextSend = false;
throw objectToThrow;
}
if (storedResponse) {
mxhr_mOnLoad(storedResponse);
}
}
function mxhr_open(method, url, opts) {
MockXMLHttpRequest.mLastOpenedUrl = url;
}
function mxhr_mSendError() {
lastInstance && lastInstance.onerror && lastInstance.onerror();
}
function mxhr_mOnLoad(states) {
storedResponse = {};
storedResponse.status = 200;
for (var keyS in states) {
storedResponse[keyS] = states[keyS];
}
if (lastInstance) {
lastInstance.status = 200;
for (var keySR in storedResponse) {
lastInstance[keySR] = storedResponse[keySR];
}
lastInstance.onload && lastInstance.onload();
storedResponse = undefined;
}
}
function mxhr_mSendReadyState(states) {
if (lastInstance) {
lastInstance.readyState = XMLHttpRequest.DONE;
lastInstance.status = 200;
for (var key in states) {
lastInstance[key] = states[key];
}
lastInstance.onreadystatechange && lastInstance.onreadystatechange();
}
}
MockXMLHttpRequest.prototype = {
open: mxhr_open,
send: mxhr_send,
DONE: XMLHttpRequest.prototype.DONE,
overrideMimeType: function() {}
};
MockXMLHttpRequest.mThrowAtNextSend = mxhr_mThrowAtNextSend;
MockXMLHttpRequest.mTeardown = mxhr_mTeardown;
MockXMLHttpRequest.mSendError = mxhr_mSendError;
MockXMLHttpRequest.mSendOnLoad = mxhr_mOnLoad;
MockXMLHttpRequest.mSendReadyState = mxhr_mSendReadyState;
MockXMLHttpRequest.DONE = XMLHttpRequest.DONE;
window.MockXMLHttpRequest = MockXMLHttpRequest;
})();

View file

@ -0,0 +1,55 @@
/* global networkTypeCustomizer, requireApp, suite, suiteSetup,
suiteTeardown, setup, teardown, test, assert */
'use strict';
requireApp(
'operatorvariant/shared/test/unit/mocks/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/network_type_customizer.js');
suite('Network type customizer >', function() {
var realSettings;
var TINY_TIMEOUT = 10;
var SETTING_DATA_ICON = 'operatorResources.data.icon';
var testCases = [
{
title: 'set > ',
values: {
'lte': '4GChng',
'ehrpd': '4GChng',
'hspa+': 'H+Chng',
'hsdpa': 'HChng', 'hsupa': 'HChng', 'hspa': 'HChng'
}
}
];
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
});
setup(function() {
window.MockNavigatorSettings.mSettings[SETTING_DATA_ICON] = '{}';
this.sinon.useFakeTimers();
});
teardown(function() {
navigator.mozSettings.mTeardown();
this.sinon.clock.restore();
});
testCases.forEach(function(testCase) {
test(testCase.title, function() {
networkTypeCustomizer.set(testCase.values);
this.sinon.clock.tick(TINY_TIMEOUT);
var mSettings = window.MockNavigatorSettings.mSettings;
assert.deepEqual(mSettings[SETTING_DATA_ICON], testCase.values);
});
});
});

View file

@ -0,0 +1,129 @@
/* global requireApp, suite, teardown, suiteSetup, suiteTeardown, setup, test,
assert, nfcCustomizer */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/nfc_customizer.js');
suite('NFC customizer >', function() {
const TINY_TIMEOUT = 20;
const NFC_SETTING = 'nfc.enabled';
var realSettings;
var testCases = [
{
title: 'set true value. It has not changed previously > ',
inputValue: {
'isEnabled': true,
'default': false
},
currentValue: false,
expectedValue: true,
simPresentOnFirstBoot: true
},
{
title: 'set false value. It has not changed previously > ',
inputValue: {
'isEnabled': false,
'default': false
},
currentValue: false,
expectedValue: false,
simPresentOnFirstBoot: true
},
{
title: 'set true value. It has changed previously > ',
inputValue: {
'isEnabled': true,
'default': false
},
currentValue: true,
expectedValue: true,
simPresentOnFirstBoot: true
},
{
title: 'set false value. It has changed previously > ',
inputValue: {
'isEnabled': false,
'default': false
},
currentValue: true,
expectedValue: true,
simPresentOnFirstBoot: true
},
{
title: 'set true value. Previously value undefined > ',
inputValue: {
'isEnabled': true,
'default': false
},
currentValue: undefined,
expectedValue: true,
simPresentOnFirstBoot: true
},
{
title: 'set false value. Previous value undefined > ',
inputValue: {
'isEnabled': false,
'default': false
},
currentValue: undefined,
expectedValue: false,
simPresentOnFirstBoot: true
},
{
title: 'set true value. Previous RUN with no SIM (or unconfigured one)> ',
inputValue: {
'isEnabled': true,
'default': false
},
expectedValue: undefined,
simPresentOnFirstBoot: false
},
{
title: 'set false value. Previous RUN with no SIM (or unconfigured one)>',
inputValue: {
'isEnabled': false,
'default': false
},
expectedValue: undefined,
simPresentOnFirstBoot: false
}
];
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
});
setup(function() {
this.sinon.useFakeTimers();
});
teardown(function() {
navigator.mozSettings.mTeardown();
this.sinon.clock.restore();
});
testCases.forEach(function(testCase) {
test(testCase.title, function() {
if (testCase.currentValue !== undefined) {
window.MockNavigatorSettings.mSettings[NFC_SETTING] =
testCase.currentValue;
}
nfcCustomizer.simPresentOnFirstBoot = testCase.simPresentOnFirstBoot;
nfcCustomizer.set(testCase.inputValue);
this.sinon.clock.tick(TINY_TIMEOUT);
var mSettings = window.MockNavigatorSettings.mSettings;
assert.strictEqual(mSettings[NFC_SETTING], testCase.expectedValue,
NFC_SETTING + ' has a incorrect value');
});
});
});

View file

@ -0,0 +1,123 @@
/* global require, requireApp, suite, suiteSetup, suiteTeardown, setup,
teardown, test, assert, OperatorVariantManager
*/
'use strict';
requireApp('operatorvariant/test/unit/mock_xmlhttprequest.js');
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/shared/test/unit/mocks/' +
'mock_navigator_moz_set_message_handler.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
requireApp('operatorvariant/js/resources.js');
requireApp('operatorvariant/js/operator_variant.js');
suite(' OperatorVariantManager > ', function() {
const TEST_NETWORK_MCC = '214';
const TEST_NETWORK_MNC = '7';
const TEST_MCC_MNC = '214-007';
var realSettings;
var realSetMessageHandler;
var realLazyLoader;
var realXHR;
var customizationList = {
'214-007': {
'support_contacts': '/resources/support_contacts.json',
'wallpaper': '/resources/wallpaper.jpg',
'default_contacts': '/resources/contacts.json',
'ringtone': '/resources/ringtone.ogg'
}
};
const MSG_NAME = 'first-run-with-sim';
const FIRST_RUN_SETTING = 'ftu.simPresentOnFirstBoot';
var message = {
mcc: '214',
mnc: '007'
};
suiteSetup(function() {
realXHR = window.XMLHttpRequest;
window.XMLHttpRequest = window.MockXMLHttpRequest;
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
realSetMessageHandler = navigator.mozSetMessageHandler;
navigator.mozSetMessageHandler = window.MockNavigatormozSetMessageHandler;
realLazyLoader = window.LazyLoader;
window.LazyLoader = window.MockLazyLoader;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
navigator.mozSetMessageHandler = realSetMessageHandler;
window.LazyLoader = realLazyLoader;
window.XMLHttpRequest = realXHR;
});
setup(function() {
navigator.mozSetMessageHandler.mSetup();
OperatorVariantManager.init();
});
teardown(function() {
navigator.mozSettings.mTeardown();
navigator.mozSetMessageHandler.mTeardown();
window.XMLHttpRequest.mTeardown();
});
test(' normalize ', function() {
assert.equal(OperatorVariantManager.normalizeCode('7'), '007');
assert.equal(OperatorVariantManager.normalizeCode('07'), '007');
assert.equal(OperatorVariantManager.normalizeCode('007'), '007');
});
test(' getMccMnc ', function() {
assert.equal(
OperatorVariantManager.getMccMnc(TEST_NETWORK_MCC, TEST_NETWORK_MNC),
TEST_MCC_MNC
);
});
test(' dispatchCustomizationEvents ', function(done) {
var eventsDispatched = {};
var eventsToDispatch = customizationList[TEST_MCC_MNC];
// Run the initialization with the setting set to true, the expected value
// is true
window.MockNavigatorSettings.mSettings[FIRST_RUN_SETTING] = TEST_MCC_MNC;
navigator.mozSetMessageHandler.mTrigger(MSG_NAME, message);
assert.isTrue(OperatorVariantManager.simPresentOnFirstBoot,
'The simPresentOnFirstBoot value should be true');
window.addEventListener('customization', function customizer(event) {
var setting = event.detail.setting;
var value = event.detail.value;
// Check that the value is the expected
assert.equal(value, eventsToDispatch[setting]);
// Check that we got true as ftu.simPresentOnFirstBoot on the event.
assert.isTrue(event.detail.simPresentOnFirstBoot,
'event simPresentOnFirstBoot should be true');
// Check that we have only one event dispatched per setting
if (eventsDispatched[setting]) {
assert.ok(false, 'The setting ' + setting +
' was dispatched several times.');
done();
return;
}
eventsDispatched[setting] = true;
// Check that the number of events dispatched is the expected
if (Object.keys(eventsToDispatch).length ==
Object.keys(eventsDispatched).length) {
window.removeEventListener('customization', customizer);
done();
}
});
OperatorVariantManager.dispatchCustomizationEvents(customizationList);
});
});

View file

@ -0,0 +1,44 @@
/* global sinon, requireApp, suite, suiteSetup, suiteTeardown, setup, teardown,
test, assert, powerCustomizer */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/power_customizer.js');
suite('power on/off customizer >', function() {
var createLockSpy;
var realSettings;
const POWER_KEYS_VALUES = {
'poweron': {
'video': 'app://operatorresources/resources/power/power_on.mp4',
'image': 'app://operatorresources/resources/power/power_on.png'
}
};
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
createLockSpy = sinon.spy(navigator.mozSettings, 'createLock');
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
createLockSpy.restore();
});
setup(function() {
createLockSpy.reset();
});
teardown(function() {
navigator.mozSettings.mTeardown();
});
test(' set > ', function() {
powerCustomizer.set(POWER_KEYS_VALUES);
assert.isTrue(createLockSpy.calledOnce);
});
});

Binary file not shown.

View file

@ -0,0 +1,23 @@
{
"214-01": {
"support_contacts": "/ftu/test/unit/resources/support_contacts.json",
"wallpaper": "/resources/wallpaper.jpg",
"default_contacts": "/resources/contacts.json",
"ringtone": "/resources/ringtone.ogg",
"power": "/ftu/test/unit/resources/power.json"
},
"214-02": {
"support_contacts": "/ftu/test/unit/resources/support_contacts.json",
"wallpaper": "/resources/wallpaper.jpg",
"default_contacts": "/resources/contacts.json",
"ringtone": "/resources/ringtone.ogg",
"power": "/ftu/test/unit/resources/power.json"
},
"214-007": {
"support_contacts": "/test/unit/resources/support_contacts.json",
"wallpaper": "/resources/wallpaper.jpg",
"default_contacts": "/resources/contacts.json",
"ringtone": "/resources/ringtone.ogg",
"power": "/test/unit/resources/power.json"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

View file

@ -0,0 +1,29 @@
/* global requireApp, suite, test, assert, Resources */
'use strict';
requireApp('operatorvariant/js/resources.js');
var resourcePath = '/test/unit/resources/wallpaper.jpg';
suite(' Resources > ', function() {
test(' load properly ', function(done) {
var onerror = function errorHandler() {
assert.ok(false, 'Resource not loaded properly');
done();
};
Resources.load(resourcePath, 'blob', function() {
done();
}, onerror);
});
test(' error while loading ', function(done) {
var onerror = function errorHandler() {
done();
};
Resources.load('/wrong/path/file.jpg', 'blob', function() {
assert.ok(false, 'Resource loaded when it should not.');
done();
}, onerror);
});
});

View file

@ -0,0 +1,72 @@
/* global requireApp, suite, suiteSetup, suiteTeardown, setup, teardown,
test, sinon, Resources, ringtoneCustomizer */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/resources.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/ringtone_customizer.js');
suite('RingtoneCustomizer >', function() {
var ringtoneParams = {
uri: '/test/unit/resources/5secs.ogg',
name: 'ringtone'
};
var TINY_TIMEOUT = 20;
var realSettings;
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
});
setup(function() {
this.sinon.useFakeTimers();
});
teardown(function() {
navigator.mozSettings.mTeardown();
this.sinon.clock.restore();
});
test(' First run with valid SIM. Set > ', function() {
var resourcesSpy = sinon.spy(Resources, 'load');
ringtoneCustomizer.simPresentOnFirstBoot = true;
ringtoneCustomizer.set(ringtoneParams);
this.sinon.clock.tick(TINY_TIMEOUT);
sinon.assert.calledOnce(resourcesSpy);
sinon.assert.calledWith(resourcesSpy, ringtoneParams.uri, 'blob');
resourcesSpy.restore();
});
test(' set the ringtone > ', function() {
var createLockSpy = sinon.spy(navigator.mozSettings, 'createLock');
this.sinon.stub(Resources, 'load', function(uri, type, onsuccess) {
onsuccess('ABC');
});
ringtoneCustomizer.simPresentOnFirstBoot = true;
ringtoneCustomizer.set(ringtoneParams);
sinon.assert.calledOnce(createLockSpy);
createLockSpy.restore();
});
test(' First run outwith valid SIM. Not set > ', function() {
var createLockSpy = sinon.spy(navigator.mozSettings, 'createLock');
this.sinon.stub(Resources, 'load', function(uri, type, onsuccess) {
onsuccess('ABC');
});
ringtoneCustomizer.simPresentOnFirstBoot = false;
ringtoneCustomizer.set(ringtoneParams);
sinon.assert.notCalled(createLockSpy);
createLockSpy.restore();
});
});

View file

@ -0,0 +1,80 @@
/* global requireApp, suite, suiteSetup, suiteTeardown, setup, teardown, test,
assert, sinon, smsCustomizer */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/sms_customizer.js');
suite('SMS customizer >', function() {
const SMS_MAX_CONCAT = 'operatorResource.sms.maxConcat';
var createLockSpy;
var realSettings;
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
createLockSpy = sinon.spy(navigator.mozSettings, 'createLock');
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
createLockSpy.restore();
});
setup(function() {
createLockSpy.reset();
});
teardown(function() {
navigator.mozSettings.mTeardown();
});
test(' set valid value (integer) > ', function() {
var sttngs = navigator.mozSettings.mSettings;
smsCustomizer.set({
smsMaxConcat: 10
});
assert.isTrue(createLockSpy.calledOnce);
assert.strictEqual(sttngs[SMS_MAX_CONCAT], 10);
});
test(' set valid value (decimal) > ', function() {
var sttngs = navigator.mozSettings.mSettings;
smsCustomizer.set({
smsMaxConcat: 10.5
});
assert.isTrue(createLockSpy.calledOnce);
assert.strictEqual(sttngs[SMS_MAX_CONCAT], 10);
});
test(' set invalid value (NaN) > ', function() {
var sttngs = navigator.mozSettings.mSettings;
smsCustomizer.set({
smsMaxConcat: 'a'
});
assert.isTrue(createLockSpy.notCalled);
assert.isUndefined(sttngs.SMS_MAX_CONCAT);
});
test(' set invalid value (negative value) > ', function() {
var sttngs = navigator.mozSettings.mSettings;
smsCustomizer.set({
smsMaxConcat: -1
});
assert.isTrue(createLockSpy.notCalled);
assert.isUndefined(sttngs.SMS_MAX_CONCAT);
});
});

View file

@ -0,0 +1,52 @@
/* global requireApp, suite, suiteSetup, suiteTeardown, setup, teardown, test,
assert, sinon, supportContactsCustomizer */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/support_contacts_customizer.js');
suite('Support contacts customizer >', function() {
var createLockSpy;
var realSettings;
const SUPPORT_CONTACTS_KEYS_VALUES = {
'onlinesupport': {
'title': 'Mozilla Support',
'href': 'http://test.mozilla.org/support'
},
'callsupport1': {
'title': 'Call Support (Primary)',
'href': 'tel:14155550001'
},
'callsupport2': {
'title': 'Call Support (Secondary)',
'href': 'tel:14155550002'
}
};
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
createLockSpy = sinon.spy(navigator.mozSettings, 'createLock');
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
createLockSpy.restore();
});
setup(function() {
createLockSpy.reset();
});
teardown(function() {
navigator.mozSettings.mTeardown();
});
test(' set > ', function() {
supportContactsCustomizer.set(SUPPORT_CONTACTS_KEYS_VALUES);
assert.isTrue(createLockSpy.calledOnce);
});
});

View file

@ -0,0 +1,52 @@
/* global MockNavigatorDatastore */
/* global MockDatastore */
/* global topSitesCustomizer */
'use strict';
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/topsites_customizer.js');
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
suite('TopSitesCustomizer >', function() {
var realDatastore = null;
suiteSetup(function() {
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
});
suiteTeardown(function() {
navigator.getDataStores = realDatastore;
});
teardown(function() {
MockDatastore._inError = false;
MockDatastore._records = Object.create(null);
});
test('First run with valid SIM. Set places', function(done) {
var url = 'http://example.org';
var title = 'Example';
var tile = 'atile';
var data = {
topSites: [{
url: url,
title: title,
tile: tile,
}]
};
MockDatastore.addEventListener('change', function() {
assert.deepEqual(MockDatastore._records[url], {
url: url,
title: title,
tile: tile,
frecency: -1
}, 'Arguments not equal');
done();
});
topSitesCustomizer.simPresentOnFirstBoot = true;
topSitesCustomizer.set(data);
});
});

View file

@ -0,0 +1,105 @@
/* global requireApp, suite, suiteSetup, suiteTeardown, setup, teardown, test,
assert, sinon, MockXMLHttpRequest, wallpaperCustomizer, Resources */
'use strict';
requireApp('operatorvariant/test/unit/mock_navigator_moz_settings.js');
requireApp('operatorvariant/test/unit/mock_xmlhttprequest.js');
requireApp('operatorvariant/test/unit/mock_file_reader.js');
requireApp('operatorvariant/js/resources.js');
requireApp('operatorvariant/js/customizers/customizer.js');
requireApp('operatorvariant/js/customizers/wallpaper_customizer.js');
suite('WallpaperCustomizer >', function() {
const WALLPAPER_SETTING = 'wallpaper.image';
const TINY_TIMEOUT = 20;
var realFileReader;
var realSettings;
var realXHR;
var resourcesSpy;
suiteSetup(function() {
realSettings = navigator.mozSettings;
navigator.mozSettings = window.MockNavigatorSettings;
realXHR = window.XMLHttpRequest;
window.XMLHttpRequest = window.MockXMLHttpRequest;
realFileReader = window.FileReader;
window.FileReader = window.MockFileReader;
});
suiteTeardown(function() {
navigator.mozSettings = realSettings;
window.XMLHttpRequest = realXHR;
window.FileReader = realFileReader;
});
setup(function() {
this.sinon.useFakeTimers();
resourcesSpy = sinon.spy(Resources, 'load');
});
teardown(function() {
window.XMLHttpRequest.mTeardown();
navigator.mozSettings.mTeardown();
this.sinon.clock.restore();
resourcesSpy.restore();
});
function sendResponseText(text) {
MockXMLHttpRequest.mSendOnLoad({
responseText: text,
response: text
});
}
var configuredValue = 'data:application/object;base64,configuredValue';
var userValue = 'data:application/object;base64,userValue';
var defaultValue = 'data:application/object;base64,defaultValue';
test('First run with valid SIM. Set ', function() {
var settings = navigator.mozSettings.mSettings;
var inputParam = {
uri: '/test/unit/resources/wallpaper.png',
default: defaultValue
};
wallpaperCustomizer.simPresentOnFirstBoot = true;
wallpaperCustomizer.set(inputParam);
sendResponseText(configuredValue);
this.sinon.clock.tick(TINY_TIMEOUT);
sinon.assert.calledOnce(resourcesSpy);
sinon.assert.calledWith(resourcesSpy,
inputParam.uri, 'blob');
//Verify if value has been correctly changed
assert.strictEqual(settings[WALLPAPER_SETTING], configuredValue,
WALLPAPER_SETTING + ' has a incorrect value');
});
test('Previous run withot SIM. Not set ', function() {
var settings = navigator.mozSettings.mSettings;
settings[WALLPAPER_SETTING] = userValue;
var inputParam = {
uri: '/test/unit/resources/wallpaper.png',
default: defaultValue
};
wallpaperCustomizer.simPresentOnFirstBoot = false;
wallpaperCustomizer.set(inputParam);
sendResponseText(configuredValue);
this.sinon.clock.tick(TINY_TIMEOUT);
sinon.assert.notCalled(resourcesSpy);
//Verify if value has been correctly changed
assert.strictEqual(settings[WALLPAPER_SETTING], userValue,
WALLPAPER_SETTING + ' has a incorrect value');
});
});