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,95 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
const CC = Components.Constructor;
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import('resource://gre/modules/Services.jsm');
function debug(data) {
//dump('desktop-helper: ' + data + '\n');
}
const kChromeRootPath = 'chrome://desktop-helper.js/content/data/';
// XXX Scripts should be loaded based on the permissions of the apps not
// based on the domain.
const kScriptsPerDomain = {
'.gaiamobile.org': [
'ffos_runtime.js',
'lib/bluetooth.js',
'lib/cameras.js',
'lib/mobile_connection.js',
'lib/icc_manager.js',
'lib/telephony.js',
'lib/wifi.js'
]
};
function injectMocks() {
// Track loading of apps to inject mock APIs
Services.obs.addObserver(function(document) {
// Some documents like XBL don't have location and should be ignored
if (!document.location || !document.defaultView)
return;
let currentDomain = document.location.toString();
let window = document.defaultView;
// Do not include mocks for unit test sandboxes
if (window.wrappedJSObject.mocha &&
currentDomain.indexOf('_sandbox.html') !== -1) {
return;
}
debug('+++ loading scripts for app: ' + currentDomain + "\n");
// Inject mocks based on domain
for (let domain in kScriptsPerDomain) {
if (currentDomain.indexOf(domain) == -1)
continue;
let includes = kScriptsPerDomain[domain];
for (let i = 0; i < includes.length; i++) {
debug('loading ' + includes[i] + '...');
Services.scriptloader.loadSubScript(kChromeRootPath + includes[i],
window.wrappedJSObject);
}
}
}, 'document-element-inserted', false);
}
function hotfixAlarms() {
// Replace existing alarm service xpcom factory by a new working one,
// until a working fallback is implemented in platform code (bug 867868)
// Sigh. Seems like there is a registration issue between all the addons.
// This is dirty but delaying this seems to make it.
var timer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
timer.initWithCallback(function() {
Services.scriptloader.loadSubScript('chrome://desktop-helper.js/content/alarms.js', {});
}, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
}
function startup(data, reason) {
try {
hotfixAlarms();
injectMocks();
} catch (e) {
debug('Something went wrong while trying to start desktop-helper: ' + e);
}
}
function shutdown(data, reason) {
}
function install(data, reason) {
}
function uninstall(data, reason) {
}

View file

@ -0,0 +1 @@
content desktop-helper.js content/

View file

@ -0,0 +1,102 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
let Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
function debug(str) {
//dump('AlarmHalService: ' + str + '\n');
}
// -----------------------------------------------------------------------
// AlarmHalService
// -----------------------------------------------------------------------
function AlarmHalService() {
debug('Constructor');
}
AlarmHalService.prototype = {
_timer: Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer),
setAlarm: function setAlarm(seconds, nanoseconds) {
debug('setAlarm: ' + seconds);
this._currentAlarm = seconds;
this._timer.cancel();
this._timer.initWithCallback(this, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
return true;
},
notify: function notify() {
debug('notify: ' + (Date.now() / 1000) + ' < ' + this._currentAlarm + '\n');
if ((Date.now() / 1000) < this._currentAlarm)
return;
debug('fired!!!');
// Let's stop the timer to make sure it does not fire again...
this._timer.cancel();
if (this._alarmFiredCb) {
try {
this._alarmFiredCb();
} catch (e) {}
}
},
_alarmFiredCb: null,
setAlarmFiredCb: function setAlarmFiredCb(callback) {
debug('setAlarmFiredCb!!!');
this._alarmFiredCb = callback;
},
_timezoneChangeDb: null,
setTimezoneChangedCb: function setTimezoneChangedCb(callback) {
debug('setTzFiredCb!!!');
this._timezoneChangedCb = callback;
},
classID: newClassID,
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIAlarmHalService, Ci.nsITimerCallback
])
};
// Unregister the embedded low level component for alarm and
// replace it with our own.
let contract = '@mozilla.org/alarmHalService;1';
var newClassID = Cc['@mozilla.org/uuid-generator;1']
.getService(Ci.nsIUUIDGenerator)
.generateUUID();
// Unregister the old factory.
let oldCid = Cm.contractIDToCID(contract);
let oldFactory = Cm.getClassObjectByContractID(contract, Ci.nsIFactory);
Cm.unregisterFactory(oldCid, oldFactory);
// Register a new one.
let instance = null;
let newFactory = {
createInstance: function(outer, iid) {
if (outer)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (instance === null)
instance = new AlarmHalService();
instance.QueryInterface(iid);
return instance.QueryInterface(iid);
},
lockFactory: function(aLock) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
};
Cm.registerFactory(newClassID, '', contract, newFactory);
// Then let's start the AlarmService!
Cu.import('resource://gre/modules/AlarmService.jsm');

View file

@ -0,0 +1,65 @@
FFOS_RUNTIME = {
/**
* Emulates a dom request
* Returns an object and calls it's onsuccess handler.
*/
domRequest: function(result, timeout) {
timeout = timeout || 1000;
return function() {
var request = { result: result };
setTimeout(function() {
if (request.onsuccess) {
request.onsuccess();
}
}, timeout);
return request;
}
},
/**
* This is so we have a single entry-point for the APP window
* This is needed as the interface to window may be changing soon
*/
getAppWindow: function(callback) {
callback(window);
},
/**
* Proxies console.log statements to the app window
*/
debug: function() {
var args = Array.slice(arguments);
this.getAppWindow(function(win) {
win.console.log.apply(win.console, args);
});
},
/**
* Creates a navigator shim on the window
* @param {String} property name.
* @param {Object} property definition.
* @param {Boolean} if true, makes a navigator setter for this object. Useful for testing.
*/
makeNavigatorShim: function(property, definition, makeSetter) {
try {
window.navigator.__defineGetter__(property, function() {
return definition;
});
if (makeSetter) {
window.navigator.__defineSetter__(property, function(prop) {
definition = prop;
});
}
} catch (e) {
alert('Error intializing shim (' + property + '): ' + e);
}
}
};
var debug = FFOS_RUNTIME.debug;

View file

@ -0,0 +1,34 @@
!function() {
function debug(str) {
//dump('Bluetooth : ' + str + '\n');
}
function MockBluetoothRequest() {
}
MockBluetoothRequest.prototype = {
};
FFOS_RUNTIME.makeNavigatorShim('mozBluetooth', {
enabled: true,
addEventListener: function(type, callback, bubble) {},
onenabled: function(event) {},
ondisabled: function(event) {},
onadapteradded: function() {
debug('onadapteradded');
},
getDefaultAdapter: FFOS_RUNTIME.domRequest({
ondevicefound: function() {},
setDiscoverable: function() {},
getPairedDevices: FFOS_RUNTIME.domRequest([]),
startDiscovery: FFOS_RUNTIME.domRequest(),
name: 'I like blue',
setName: FFOS_RUNTIME.domRequest(),
getConnectedDevices: FFOS_RUNTIME.domRequest()
}),
isConnected: function() {
debug('isConnected');
}
});
}();

View file

@ -0,0 +1,88 @@
!function() {
var CameraManager = {
// The camera stream
stream: false,
capabilities: {
focusModes: '',
pictureSizes: [{
width: 600,
height: 600
}],
previewSizes: [{
width: 600,
height: 600
}],
recorderProfiles: {
cif: {
video: {
width: 600,
height: 600
}
}
}
},
getListOfCameras: function() {
console.log('mozCamera.getListOfCameras');
return [this];
},
/**
* Gets a camera
*/
getCamera: function(options, callback) {
console.log('mozCamera.getCamera');
navigator.mozGetUserMedia({video: true},
function(stream) {
this.stream = stream;
callback(this);
this.onPreviewStateChange('started');
}.bind(this),
function() {
console.log('Could not initialize camera.');
}
);
},
getPreviewStream: function(config, callback) {
console.log('mozCamera.getPreviewStream');
callback(this.stream);
},
getPreviewStreamVideoMode: function(config, callback) {
console.log('mozCamera.getPreviewStreamVideoMode');
callback(this.stream);
},
resumePreview: function() {
console.log('mozCamera.resumePreview');
},
autoFocus: function() {
console.log('mozCamera.autoFocus');
},
takePicture: function(config, onSuccess, onError) {
console.log('mozCamera.takePicture');
var cnvs = document.createElement('canvas');
cnvs.width = config.pictureSize.width;
cnvs.height = config.pictureSize.height;
var ctx = cnvs.getContext('2d');
ctx.drawImage(window.document.querySelector('video'), 0, 0, cnvs.width, cnvs.height);
cnvs.toBlob(function(blob) {
onSuccess(blob);
}, 'image/jpeg');
},
release: function() {
console.log('mozCamera.release');
}
};
FFOS_RUNTIME.makeNavigatorShim('mozCameras', CameraManager);
}();

View file

@ -0,0 +1,103 @@
!function() {
function debug(str) {
//dump('mozIccManager: ' + str + '\n');
}
var iccs = {
111: {
_retryCount: 3,
cardState: 'ready',
iccInfo: {
iccid: true,
msisdn: '5555555555'
},
setCardLock: function() {
debug('setCardLock');
},
getCardLock: FFOS_RUNTIME.domRequest({ enabled: false }),
getCardLockRetryCount: function(type) {
var request = {};
setTimeout(function() {
request.result = {
retryCount: this._retryCount
};
request.onsuccess && request.onsuccess();
}.bind(this));
return request;
},
unlockCardLock: function() {
// simulate invalid input
if (this._retryCount > 1) {
var request = {};
setTimeout(function() {
request.error = {
retryCount: --this._retryCount,
lockType: 'pin'
};
request.onerror && request.onerror();
}.bind(this), 200);
return request;
}
this.cardState = 'ready';
return FFOS_RUNTIME.domRequest()();
},
addEventListener: function() {
debug('addEventListener');
},
removeEventListener: function() {
debug('removeEventListener');
},
},
222: {
_retryCount: 3,
cardState: 'ready',
iccInfo: {
iccid: true
},
setCardLock: function() {
debug('setCardLock');
},
getCardLock: FFOS_RUNTIME.domRequest({ enabled: false }),
getCardLockRetryCount: function(type) {
var request = {};
setTimeout(function() {
request.result = {
retryCount: this._retryCount
};
request.onsuccess && request.onsuccess();
}.bind(this));
return request;
},
unlockCardLock: function() {
this.cardState = 'ready';
return FFOS_RUNTIME.domRequest()();
},
addEventListener: function() {
debug('addEventListener');
},
removeEventListener: function() {
debug('removeEventListener');
},
}
};
var iccManager = {
addEventListener: function() {
debug('addEventListener');
},
removeEventListener: function() {
debug('removeEventListener');
},
getIccById: function(iccId) {
return iccs[iccId];
},
iccIds: [111]
};
if (window._shimDualSim) {
iccManager.iccIds.push(222);
}
FFOS_RUNTIME.makeNavigatorShim('mozIccManager', iccManager, true);
}();

View file

@ -0,0 +1,96 @@
!function() {
function debug(str) {
//dump('mozMobileConnection: ' + str + '\n');
}
var initialized = true;
var fakeNetwork = { shortName: 'Fake Orange F', mcc: '208', mnc: '1' };
var fakeVoice = {
network: fakeNetwork,
state: 'notSearching',
roaming: true,
connected: true,
emergencyCallsOnly: false
};
var fakeNetwork2 = { shortName: 'Verizon Fake', mcc: '208', mnc: '1' };
var fakeVoice2 = {
network: fakeNetwork2,
state: 'notSearching',
roaming: true,
connected: true,
emergencyCallsOnly: false
};
function fakeEventListener(type, callback, bubble) {
if (initialized) {
if (typeof callback === 'function') {
setTimeout(callback.bind(this, { iccId: this.iccId }));
}
return;
}
// simulates a connection to a data network;
setTimeout(function fakeCallback() {
initialized = true;
if (typeof callback === 'function') {
callback({ iccId: this.iccId });
}
}.bind(this), 5000);
}
var mobileConnections = [{
iccId: 111,
addEventListener: fakeEventListener,
removeEventListener: function() {},
getCallWaitingOption: FFOS_RUNTIME.domRequest(true),
getCallForwardingOption: FFOS_RUNTIME.domRequest(1),
setCallWaitingOption: FFOS_RUNTIME.domRequest(),
getCallingLineIdRestriction: FFOS_RUNTIME.domRequest(),
setVoicePrivacyMode: FFOS_RUNTIME.domRequest(),
getVoicePrivacyMode: FFOS_RUNTIME.domRequest(),
setRadioEnabled: FFOS_RUNTIME.domRequest(),
getRadioEnabled: FFOS_RUNTIME.domRequest(),
getRoamingPreference: FFOS_RUNTIME.domRequest(),
setRoamingPreference: FFOS_RUNTIME.domRequest(),
getPreferredNetworkType: FFOS_RUNTIME.domRequest(),
setPreferredNetworkType: FFOS_RUNTIME.domRequest(),
get data() {
return initialized ? { network: fakeNetwork } : null;
},
get voice() {
return initialized ? fakeVoice : null;
}
}];
if (window._shimDualSim) {
mobileConnections.push({
iccId: 222,
addEventListener: fakeEventListener,
removeEventListener: function() {},
getCallWaitingOption: FFOS_RUNTIME.domRequest(true),
getCallForwardingOption: FFOS_RUNTIME.domRequest(1),
setCallWaitingOption: FFOS_RUNTIME.domRequest(),
getCallingLineIdRestriction: FFOS_RUNTIME.domRequest(),
setVoicePrivacyMode: FFOS_RUNTIME.domRequest(),
getVoicePrivacyMode: FFOS_RUNTIME.domRequest(),
setRadioEnabled: FFOS_RUNTIME.domRequest(),
getRadioEnabled: FFOS_RUNTIME.domRequest(),
getRoamingPreference: FFOS_RUNTIME.domRequest(),
setRoamingPreference: FFOS_RUNTIME.domRequest(),
getPreferredNetworkType: FFOS_RUNTIME.domRequest(),
setPreferredNetworkType: FFOS_RUNTIME.domRequest(),
get data() {
return initialized ? { network: fakeNetwork2 } : null;
},
get voice() {
return initialized ? fakeVoice2 : null;
}
});
}
FFOS_RUNTIME.makeNavigatorShim('mozMobileConnections',
mobileConnections, true);
}();

View file

@ -0,0 +1,16 @@
!function() {
function debug(str) {
//dump('mozTelephony: ' + str + '\n');
}
FFOS_RUNTIME.makeNavigatorShim('mozTelephony', {
calls: [],
addEventListener: function() {
debug('addEventListener');
},
removeEventListener: function() {
debug('removeEventListener');
}
}, true);
}();

View file

@ -0,0 +1,132 @@
!function() {
function debug(str) {
//dump('wifi: ' + str + '\n');
}
/**
* fake network list, where each network object looks like:
* {
* ssid : SSID string (human-readable name)
* bssid : network identifier string
* security : array of strings (supported authentication methods)
* relSignalStrength : 0-100 signal level (integer)
* connected : boolean state
* }
*/
var fakeNetworks = [
{
ssid: 'Mozilla-G',
bssid: 'xx:xx:xx:xx:xx:xx',
security: ['WPA-EAP'],
relSignalStrength: 67,
connected: false
},
{
ssid: 'Livebox 6752',
bssid: 'xx:xx:xx:xx:xx:xx',
security: ['WEP'],
relSignalStrength: 32,
connected: false
},
{
ssid: 'Mozilla Guest',
bssid: 'xx:xx:xx:xx:xx:xx',
security: [],
relSignalStrength: 98,
connected: false
},
{
ssid: 'Freebox 8953',
bssid: 'xx:xx:xx:xx:xx:xx',
security: ['WPA2-PSK'],
relSignalStrength: 89,
connected: false
}
];
FFOS_RUNTIME.makeNavigatorShim('mozWifiManager', {
enabled: true,
macAddress: 'xx:xx:xx:xx:xx:xx',
// enables/disables the wifi
setEnabled: function fakeSetEnabled(bool) {
var self = this;
var request = { result: bool };
setTimeout(function() {
if (request.onsuccess) {
request.onsuccess();
}
if (bool) {
self.onenabled();
} else {
self.ondisabled();
}
});
self.enabled = bool;
return request;
},
// returns a list of visible/known networks
getNetworks: FFOS_RUNTIME.domRequest(fakeNetworks),
getKnownNetworks: FFOS_RUNTIME.domRequest(fakeNetworks),
// selects a network
associate: function fakeAssociate(network) {
var self = this;
var connection = { result: network };
var networkEvent = { network: network };
setTimeout(function fakeConnecting() {
self.connection.network = network;
self.connection.status = 'connecting';
self.onstatuschange(networkEvent);
}, 0);
setTimeout(function fakeAssociated() {
self.connection.network = network;
self.connection.status = 'associated';
self.onstatuschange(networkEvent);
}, 1000);
setTimeout(function fakeConnected() {
network.connected = true;
self.connected = network;
self.connection.network = network;
self.connection.status = 'connected';
self.onstatuschange(networkEvent);
}, 2000);
return connection;
},
// forgets a network (disconnect)
forget: function fakeForget(network) {
var self = this;
var networkEvent = { network: network };
setTimeout(function() {
network.connected = false;
self.connected = null;
self.connection.network = null;
self.connection.status = 'disconnected';
self.onstatuschange(networkEvent);
}, 0);
},
// event listeners
onenabled: function(event) {},
ondisabled: function(event) {},
onstatuschange: function(event) {},
// returns a network object for the currently connected network (if any)
connected: null,
connection: {
status: 'disconnected',
network: null
}
}, true);
}();

View file

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>desktop-helper@gaiamobile.org</em:id>
<em:name>desktop-helper.js</em:name>
<em:version>0.1</em:version>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>6.0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
<em:minVersion>6.0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<em:unpack>true</em:unpack>
<em:bootstrap>true</em:bootstrap>
<em:creator>Kevin Grandon</em:creator>
<em:description>Shims to make gaia work on top of Xulrunner runtime</em:description>
<em:homepageURL>https://github.com/mozilla-b2g/gaia/</em:homepageURL>
</Description>
</RDF>