Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
445
gaia/apps/system/js/ftu_ping.js
Executable file
445
gaia/apps/system/js/ftu_ping.js
Executable file
|
|
@ -0,0 +1,445 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
/* global MobileOperator, SIMSlotManager, dump, TelemetryRequest,
|
||||
LazyLoader */
|
||||
|
||||
/**
|
||||
* A simple ping that is kicked off on first time use
|
||||
*/
|
||||
(function(exports) {
|
||||
var DEBUG = false;
|
||||
|
||||
const FTU_PING_ACTIVATION = 'ftu.pingActivation';
|
||||
const FTU_PING_ENABLED = 'ftu.pingEnabled';
|
||||
const FTU_PING_MAX_NETWORK_FAILS = 'ftu.pingMaxNetworkFails';
|
||||
const FTU_PING_NETWORK_FAIL_COUNT = 'ftu.pingNetworkFailCount';
|
||||
const FTU_PING_URL = 'ftu.pingURL';
|
||||
const FTU_PING_TIMEOUT = 'ftu.pingTimeout';
|
||||
const FTU_PING_TRY_INTERVAL = 'ftu.pingTryInterval';
|
||||
|
||||
const DEFAULT_TRY_INTERVAL = 60 * 60 * 1000;
|
||||
const DEFAULT_MAX_NETWORK_FAILS = 24;
|
||||
const DEFAULT_PING_TIMEOUT = 60 * 1000;
|
||||
|
||||
// Used by the telemetry server to help identify the payload format
|
||||
const TELEMETRY_VERSION = 1;
|
||||
const TELEMETRY_REASON = 'ftu';
|
||||
|
||||
// Settings to observe value changes for while the ping has not been sent
|
||||
const OBSERVE_SETTINGS = ['deviceinfo.os',
|
||||
'deviceinfo.software',
|
||||
'deviceinfo.product_model',
|
||||
'deviceinfo.firmware_revision',
|
||||
'deviceinfo.hardware'];
|
||||
|
||||
const URL_SETTINGS = ['deviceinfo.platform_build_id',
|
||||
'deviceinfo.platform_version',
|
||||
'app.update.channel'];
|
||||
|
||||
function FtuPing() {
|
||||
}
|
||||
|
||||
FtuPing.prototype = {
|
||||
// whether or not required properties have been loaded
|
||||
_pingReady: false,
|
||||
_pingReadyCallback: null,
|
||||
|
||||
// interval timer for first time ping
|
||||
_pingTimer: null,
|
||||
|
||||
// time between ping tries
|
||||
_tryInterval: DEFAULT_TRY_INTERVAL,
|
||||
|
||||
// URL for first time ping
|
||||
_pingURL: null,
|
||||
|
||||
// Whether or not FTU ping is enabled
|
||||
_pingEnabled: true,
|
||||
|
||||
// The number of times to wait for SIM / voice network data before sending
|
||||
// the ping anyway
|
||||
_maxNetworkFails: DEFAULT_MAX_NETWORK_FAILS,
|
||||
|
||||
// Number of network failures accrued
|
||||
_networkFailCount: 0,
|
||||
|
||||
// Data used in ping
|
||||
_pingData: {},
|
||||
|
||||
// Data used in info
|
||||
_infoData: {},
|
||||
|
||||
// Timeout for ping requests
|
||||
_pingTimeout: DEFAULT_PING_TIMEOUT,
|
||||
_settingObserver: null,
|
||||
|
||||
debug: function fp_debug(msg) {
|
||||
if (DEBUG) {
|
||||
dump('[FtuPing] ' + msg + '\n');
|
||||
}
|
||||
},
|
||||
|
||||
reset: function fp_reset() {
|
||||
this._pingReady = false;
|
||||
this._pingReadyCallback = null;
|
||||
this._pingTimer = null;
|
||||
this._tryInterval = DEFAULT_TRY_INTERVAL;
|
||||
this._pingTimeout = DEFAULT_PING_TIMEOUT;
|
||||
this._settingObserver = null;
|
||||
|
||||
this._pingURL = null;
|
||||
this._pingEnabled = true;
|
||||
|
||||
this._maxNetworkFails = DEFAULT_MAX_NETWORK_FAILS;
|
||||
this._networkFailCount = 0;
|
||||
|
||||
this._pingData = {};
|
||||
},
|
||||
|
||||
initSettings: function fp_initSettings() {
|
||||
var self = this;
|
||||
function getAsyncItems() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
self.getAsyncStorageItems([FTU_PING_ACTIVATION,
|
||||
FTU_PING_ENABLED,
|
||||
FTU_PING_NETWORK_FAIL_COUNT],
|
||||
function(items) {
|
||||
|
||||
self._pingData.activationTime = items[FTU_PING_ACTIVATION];
|
||||
self._pingEnabled = items[FTU_PING_ENABLED];
|
||||
|
||||
if (!self._pingData.activationTime) {
|
||||
self._pingData.activationTime = Date.now();
|
||||
window.asyncStorage.setItem(FTU_PING_ACTIVATION,
|
||||
self._pingData.activationTime);
|
||||
}
|
||||
|
||||
if (self._pingEnabled === null) {
|
||||
self._pingEnabled = true;
|
||||
}
|
||||
|
||||
if (typeof(items[FTU_PING_NETWORK_FAIL_COUNT]) === 'number') {
|
||||
self._networkFailCount = items[FTU_PING_NETWORK_FAIL_COUNT];
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var allSettings = [FTU_PING_URL, FTU_PING_TRY_INTERVAL,
|
||||
FTU_PING_TIMEOUT, FTU_PING_MAX_NETWORK_FAILS].
|
||||
concat(OBSERVE_SETTINGS);
|
||||
allSettings = allSettings.concat(URL_SETTINGS);
|
||||
|
||||
self.getSettings(allSettings, function(settings) {
|
||||
self._pingURL = settings[FTU_PING_URL];
|
||||
self._tryInterval = settings[FTU_PING_TRY_INTERVAL] ||
|
||||
self._tryInterval;
|
||||
self._pingTimeout = settings[FTU_PING_TIMEOUT] || self._pingTimeout;
|
||||
self._maxNetworkFails = settings[FTU_PING_MAX_NETWORK_FAILS] ||
|
||||
self._maxNetworkFails;
|
||||
|
||||
var mozSettings = window.navigator.mozSettings;
|
||||
if (!self._settingObserver) {
|
||||
self._settingObserver = self.onSettingChanged.bind(self);
|
||||
}
|
||||
|
||||
OBSERVE_SETTINGS.forEach(function(observeSetting) {
|
||||
self._pingData[observeSetting] = settings[observeSetting];
|
||||
mozSettings.addObserver(observeSetting, self._settingObserver);
|
||||
});
|
||||
|
||||
URL_SETTINGS.forEach(function(urlSetting) {
|
||||
self._infoData[urlSetting] = settings[urlSetting];
|
||||
mozSettings.addObserver(urlSetting, self._settingObserver);
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
self.reset();
|
||||
|
||||
self._pingData.screenHeight = window.screen.height;
|
||||
self._pingData.screenWidth = window.screen.width;
|
||||
self._pingData.devicePixelRatio = window.devicePixelRatio;
|
||||
|
||||
return Promise.all([getAsyncItems(), getSettings()]);
|
||||
},
|
||||
|
||||
initPreinstalledApps: function fp_initPreinstalledApps(callback) {
|
||||
var preinstalled = this._pingData.preinstalled = {};
|
||||
var self = this;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
window.navigator.mozApps.mgmt.getAll().onsuccess = function(evt) {
|
||||
var apps = evt.target.result;
|
||||
|
||||
apps.forEach(function(app) {
|
||||
var url;
|
||||
try {
|
||||
url = new URL(app.manifestURL);
|
||||
} catch (e) {
|
||||
// Don't die if somehow the manifestURL is invalid
|
||||
}
|
||||
|
||||
// Only report non-gaia apps
|
||||
if (!url || url.hostname.indexOf('gaiamobile.org') === -1) {
|
||||
preinstalled[app.manifestURL] = app.manifest.name;
|
||||
}
|
||||
});
|
||||
|
||||
self.debug(self._pingData.preinstalled);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
getAsyncStorageItems: function fp_getAsyncStorageItems(itemKeys, callback) {
|
||||
var itemsLeft = itemKeys.length;
|
||||
var items = {};
|
||||
itemKeys.forEach(function(key) {
|
||||
window.asyncStorage.getItem(key, function(value) {
|
||||
itemsLeft--;
|
||||
items[key] = value;
|
||||
if (itemsLeft === 0 && callback) {
|
||||
callback(items);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getSettings: function fp_getSettings(settingKeys, callback) {
|
||||
var settingsLeft = settingKeys.length;
|
||||
var settings = {};
|
||||
var lock = window.navigator.mozSettings.createLock();
|
||||
settingKeys.forEach(function(key) {
|
||||
var request = lock.get(key);
|
||||
request.onsuccess = function(evt) {
|
||||
var value = request.result[key];
|
||||
settingsLeft--;
|
||||
settings[key] = value;
|
||||
if (settingsLeft === 0 && callback) {
|
||||
callback(settings);
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
ensurePing: function fp_ensurePing() {
|
||||
var self = this;
|
||||
LazyLoader.load('shared/js/telemetry.js').then(function() {
|
||||
return Promise.all([self.initSettings(), self.initPreinstalledApps()])
|
||||
.then(self.startPing.bind(self));
|
||||
});
|
||||
},
|
||||
|
||||
onSettingChanged: function fp_onSettingChanged(evt) {
|
||||
this._pingData[evt.settingName] = evt.settingValue;
|
||||
},
|
||||
|
||||
startPing: function fp_startPing() {
|
||||
if (this._pingEnabled === false) {
|
||||
this.debug('FTU ping disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._pingURL) {
|
||||
this.debug('No FTU ping URL');
|
||||
return;
|
||||
}
|
||||
if (this._pingTimer !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.debug('Starting FTU ping');
|
||||
this._pingTimer = setInterval(this.tryPing.bind(this), this._tryInterval);
|
||||
},
|
||||
|
||||
maybeThrowNetworkFailure: function fp_maybeThrowNetworkFailure(message) {
|
||||
this._networkFailCount++;
|
||||
window.asyncStorage.setItem(FTU_PING_NETWORK_FAIL_COUNT,
|
||||
this._networkFailCount);
|
||||
|
||||
if (this._networkFailCount < this._maxNetworkFails) {
|
||||
throw message + ' (' + this._networkFailCount + ' of ' +
|
||||
this._maxNetworkFails + ' failures)';
|
||||
} else {
|
||||
this.debug('Warning: ' + message);
|
||||
}
|
||||
},
|
||||
|
||||
checkMobileNetwork: function fp_checkMobileNetwork() {
|
||||
// Wait until we have a valid network connection
|
||||
if (SIMSlotManager.noSIMCardConnectedToNetwork()) {
|
||||
this.maybeThrowNetworkFailure('No SIM cards connected to a network');
|
||||
}
|
||||
|
||||
var conns = window.navigator.mozMobileConnections;
|
||||
if (!conns || conns.length === 0) {
|
||||
this.maybeThrowNetworkFailure('No mobile connections');
|
||||
return;
|
||||
}
|
||||
|
||||
var slots = SIMSlotManager.getSlots().filter(function(slot) {
|
||||
return !slot.isAbsent() && !slot.isLocked();
|
||||
});
|
||||
|
||||
if (slots.length === 0) {
|
||||
this.maybeThrowNetworkFailure('No unlocked or active SIM cards found');
|
||||
return;
|
||||
}
|
||||
|
||||
var conn = slots[0].conn;
|
||||
var iccObj = navigator.mozIccManager.getIccById(conn.iccId);
|
||||
var iccInfo = iccObj ? iccObj.iccInfo : null;
|
||||
var voiceNetwork = conn.voice ? conn.voice.network : null;
|
||||
|
||||
if (!iccInfo && !voiceNetwork) {
|
||||
this.maybeThrowNetworkFailure('No voice network or ICC info');
|
||||
return;
|
||||
}
|
||||
|
||||
this._pingData.network = MobileOperator.userFacingInfo(conn);
|
||||
if (voiceNetwork) {
|
||||
this._pingData.network.mnc = voiceNetwork.mnc;
|
||||
this._pingData.network.mcc = voiceNetwork.mcc;
|
||||
}
|
||||
|
||||
if (iccInfo) {
|
||||
this._pingData.icc = {
|
||||
mnc: iccInfo.mnc,
|
||||
mcc: iccInfo.mcc,
|
||||
spn: iccInfo.spn
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
tryPing: function fp_tryPing() {
|
||||
var self = this;
|
||||
try {
|
||||
this.checkMobileNetwork();
|
||||
if (this._networkFailCount >= this._maxNetworkFails) {
|
||||
this.debug('Max voice network failures reached, pinging anyway!');
|
||||
if (this._pingData.network === undefined) {
|
||||
this._pingData.network = null;
|
||||
}
|
||||
|
||||
if (this._pingData.icc === undefined) {
|
||||
this._pingData.icc = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._pingData['deviceinfo.os']) {
|
||||
this.debug('No OS information, holding off');
|
||||
return false;
|
||||
}
|
||||
var promise = TelemetryRequest.getDeviceID();
|
||||
promise.then(function(deviceID) {
|
||||
self._pingData.pingID = deviceID;
|
||||
self.ping();
|
||||
}).catch(function(error) {
|
||||
self.debug('Generating deviceID: ' + error);
|
||||
});
|
||||
} catch (e) {
|
||||
this.debug('Error while trying FTU ping: ' + e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
ping: function fp_ping() {
|
||||
var pingData = this.assemblePingData();
|
||||
this._pingData.pingTime = Date.now();
|
||||
|
||||
var request = new TelemetryRequest({
|
||||
reason: TELEMETRY_REASON,
|
||||
deviceID: pingData.pingID,
|
||||
ver: TELEMETRY_VERSION,
|
||||
url: this._pingURL,
|
||||
appUpdateChannel: this._infoData['app.update.channel'],
|
||||
appVersion: this._infoData['deviceinfo.platform_version'],
|
||||
appBuildID: this._infoData['deviceinfo.platform_build_id']
|
||||
}, pingData);
|
||||
|
||||
var self = this;
|
||||
request.send({
|
||||
timeout: this._pingTimeout,
|
||||
onload: function() {
|
||||
self.pingSuccess(this.responseText);
|
||||
},
|
||||
ontimeout: function() {
|
||||
self.pingError('Timed out');
|
||||
},
|
||||
onerror: function() {
|
||||
self.pingError(this.statusText);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
pingSuccess: function fp_pingSuccess(result) {
|
||||
if (result !== 'OK') {
|
||||
this.debug('Ping response unexpected: ' + result);
|
||||
return;
|
||||
}
|
||||
|
||||
this._pingEnabled = false;
|
||||
window.asyncStorage.setItem(FTU_PING_ENABLED, false);
|
||||
|
||||
var settings = window.navigator.mozSettings;
|
||||
OBSERVE_SETTINGS.forEach(function(setting) {
|
||||
settings.removeObserver(setting, this._settingObserver);
|
||||
}, this);
|
||||
|
||||
URL_SETTINGS.forEach(function(setting) {
|
||||
settings.removeObserver(setting, this._settingObserver);
|
||||
}, this);
|
||||
|
||||
clearInterval(this._pingTimer);
|
||||
},
|
||||
|
||||
pingError: function fp_pingError(message) {
|
||||
this.debug('Ping error: ' + message);
|
||||
},
|
||||
|
||||
isEnabled: function fp_isEnabled() {
|
||||
return this._pingEnabled;
|
||||
},
|
||||
|
||||
getPingURL: function fp_getPingURL() {
|
||||
return this._pingURL;
|
||||
},
|
||||
|
||||
assemblePingData: function fp_assemblePingData() {
|
||||
this._pingData.pingTime = Date.now();
|
||||
this._pingData.locale = window.navigator.language;
|
||||
return this._pingData;
|
||||
},
|
||||
|
||||
getInfoData: function fp_getInfoData() {
|
||||
return this._infoData;
|
||||
},
|
||||
|
||||
getNetworkFailCount: function fp_getNetworkFailCount() {
|
||||
return this._networkFailCount;
|
||||
},
|
||||
|
||||
getTryInterval: function fp_getTryInterval() {
|
||||
return this._tryInterval;
|
||||
},
|
||||
|
||||
getPingTimeout: function fp_getPingTimeout() {
|
||||
return this._pingTimeout;
|
||||
},
|
||||
|
||||
getMaxNetworkFails: function fp_getMaxNetworkFails() {
|
||||
return this._maxNetworkFails;
|
||||
}
|
||||
};
|
||||
|
||||
exports.FtuPing = FtuPing;
|
||||
}(window));
|
||||
Loading…
Reference in a new issue