Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
961 lines
29 KiB
JavaScript
961 lines
29 KiB
JavaScript
/* global AppUpdatable, LazyLoader, MozActivity, NotificationScreen, Service,
|
|
SettingsListener, SystemBanner, SystemUpdatable */
|
|
|
|
'use strict';
|
|
|
|
/*
|
|
* The UpdateManager is a central component for apps *and* system updates.
|
|
* The user can start or cancel all downloads at once.
|
|
* This component also makes sure of bothering the user to a minimum by
|
|
* showing active notifications for new updates/errors only once.
|
|
*
|
|
* It maintains 2 queues of Updatable objects.
|
|
* - updatesQueue for available updates
|
|
* - downloadsQueue for active downloads
|
|
*/
|
|
|
|
|
|
(function(exports) {
|
|
var UpdateManager = {
|
|
_mgmt: null,
|
|
_downloading: false,
|
|
_uncompressing: false,
|
|
_downloadedBytes: 0,
|
|
_errorTimeout: null,
|
|
_wifiLock: null,
|
|
_systemUpdateDisplayed: false,
|
|
_startedDownloadUsingDataConnection: false,
|
|
_settings: null,
|
|
_hasDialog: false,
|
|
UPDATE_NOTIF_ID: 'update-notification',
|
|
NOTIFICATION_BUFFERING_TIMEOUT: 30 * 1000,
|
|
TOASTER_TIMEOUT: 1200,
|
|
UPDATE_2G_SETT: 'update.2g.enabled',
|
|
UPDATE_2G: false,
|
|
ROAMING_SETTING_KEY: 'ril.data.roaming_enabled',
|
|
DATA_TYPES_NO_ALLOWED: ['edge', 'gprs', '1xrtt', 'is95a', 'is95b'],
|
|
WIFI_PRIORITIZED: true,
|
|
WIFI_PRIORITIZED_KEY: 'app.update.wifi-prioritized',
|
|
connection2G: false,
|
|
|
|
container: null,
|
|
message: null,
|
|
toaster: null,
|
|
toasterMessage: null,
|
|
laterButton: null,
|
|
notnowButton: null,
|
|
downloadButton: null,
|
|
downloadViaDataConnectionButton: null,
|
|
downloadDialog: null,
|
|
downloadViaDataConnectionTitle: null,
|
|
downloadViaDataConnectionDialog: null,
|
|
downloadViaDataConnectionMessage: null,
|
|
downloadDialogTitle: null,
|
|
downloadDialogList: null,
|
|
lastUpdatesAvailable: 0,
|
|
_notificationTimeout: null,
|
|
|
|
updatableApps: [],
|
|
systemUpdatable: null,
|
|
updatesQueue: [],
|
|
downloadsQueue: [],
|
|
|
|
start: function() {
|
|
if (!this._mgmt) {
|
|
this._mgmt = navigator.mozApps.mgmt;
|
|
}
|
|
|
|
this._mgmt.getAll().onsuccess = (function gotAll(evt) {
|
|
var apps = evt.target.result;
|
|
apps.forEach(function appIterator(app) {
|
|
/* jshint nonew: false */
|
|
new AppUpdatable(app);
|
|
});
|
|
}).bind(this);
|
|
|
|
this._settings = navigator.mozSettings;
|
|
|
|
this.systemUpdatable = new SystemUpdatable();
|
|
|
|
this.container = document.getElementById('update-manager-container');
|
|
this.message = this.container.querySelector('.title-container');
|
|
|
|
this.toaster = document.getElementById('update-manager-toaster');
|
|
this.toasterMessage = this.toaster.querySelector('.message');
|
|
|
|
this.laterButton = document.getElementById('updates-later-button');
|
|
this.notnowButton =
|
|
document.getElementById('updates-viaDataConnection-notnow-button');
|
|
this.downloadButton = document.getElementById('updates-download-button');
|
|
this.downloadViaDataConnectionButton =
|
|
document.getElementById('updates-viaDataConnection-download-button');
|
|
this.downloadDialog = document.getElementById('updates-download-dialog');
|
|
this.downloadDialogTitle = this.downloadDialog.querySelector('h1');
|
|
this.downloadDialogList = this.downloadDialog.querySelector('ul');
|
|
this.downloadViaDataConnectionDialog =
|
|
document.getElementById('updates-viaDataConnection-dialog');
|
|
this.downloadViaDataConnectionMessage =
|
|
this.downloadViaDataConnectionDialog.querySelector('p');
|
|
this.downloadViaDataConnectionTitle =
|
|
this.downloadViaDataConnectionDialog.querySelector('h1');
|
|
|
|
this.container.onclick = this.containerClicked.bind(this);
|
|
this.laterButton.onclick = this.cancelPrompt.bind(this);
|
|
this.toaster.onclick = this.toasterClicked.bind(this);
|
|
this.downloadButton.onclick = this.requestDownloads.bind(this);
|
|
this.downloadDialogList.onchange = this.updateDownloadButton.bind(this);
|
|
this.notnowButton.onclick =
|
|
this.cancelDataConnectionUpdatesPrompt.bind(this);
|
|
this.downloadViaDataConnectionButton.onclick =
|
|
this.requestDownloads.bind(this);
|
|
|
|
window.addEventListener('mozChromeEvent', this);
|
|
window.addEventListener('applicationinstall', this);
|
|
window.addEventListener('applicationuninstall', this);
|
|
window.addEventListener('online', this);
|
|
window.addEventListener('offline', this);
|
|
window.addEventListener('lockscreen-appopened', this);
|
|
window.addEventListener('home', this);
|
|
window.addEventListener('holdhome', this);
|
|
|
|
SettingsListener.observe('gaia.system.checkForUpdates', false,
|
|
this.checkForUpdates.bind(this));
|
|
|
|
// We maintain the the edge and nowifi data attributes to show
|
|
// a warning on the download dialog
|
|
window.addEventListener('wifi-statuschange', this);
|
|
this.updateWifiStatus();
|
|
this.updateOnlineStatus();
|
|
},
|
|
|
|
requestDownloads: function um_requestDownloads(evt) {
|
|
evt.preventDefault();
|
|
if (evt.target == this.downloadViaDataConnectionButton) {
|
|
this._startedDownloadUsingDataConnection = true;
|
|
this.startDownloads();
|
|
} else {
|
|
this.promptOrDownload();
|
|
}
|
|
},
|
|
|
|
startDownloads: function um_startDownloads() {
|
|
this.downloadViaDataConnectionDialog.classList.remove('visible');
|
|
this._closeDownloadDialog();
|
|
Service.request('UtilityTray:show');
|
|
|
|
var checkValues = {};
|
|
var dialog = this.downloadDialogList;
|
|
var checkboxes = dialog.querySelectorAll('gaia-checkbox');
|
|
for (var i = 0; i < checkboxes.length; i++) {
|
|
var checkbox = checkboxes[i];
|
|
checkValues[checkbox.dataset.position] = checkbox.checked;
|
|
}
|
|
|
|
this.updatesQueue.forEach(function(updatable, index) {
|
|
// The user opted out of the download
|
|
if (updatable.app && !checkValues[index]) {
|
|
return;
|
|
}
|
|
|
|
updatable.download();
|
|
});
|
|
|
|
this._downloadedBytes = 0;
|
|
this.render();
|
|
},
|
|
|
|
cancelAllDownloads: function um_cancelAllDownloads() {
|
|
Service.request('hideCustomDialog');
|
|
this._hasDialog = false;
|
|
|
|
// We're emptying the array while iterating
|
|
while (this.downloadsQueue.length) {
|
|
var updatable = this.downloadsQueue[0];
|
|
updatable.cancelDownload();
|
|
this.removeFromDownloadsQueue(updatable);
|
|
}
|
|
},
|
|
|
|
requestErrorBanner: function um_requestErrorBanner() {
|
|
if (this._errorTimeout) {/* jshint nonew: false */
|
|
|
|
return;
|
|
}
|
|
|
|
var self = this;
|
|
this._errorTimeout = setTimeout(function waitForMore() {
|
|
LazyLoader.load(['js/system_banner.js']).then(function() {
|
|
var systemBanner = new SystemBanner();
|
|
systemBanner.show('downloadError');
|
|
self._errorTimeout = null;
|
|
})['catch'](function(err) {
|
|
console.error(err);
|
|
});
|
|
}, this.NOTIFICATION_BUFFERING_TIMEOUT);
|
|
},
|
|
|
|
promptOrDownload: function um_promptOrDownload() {
|
|
var self = this;
|
|
|
|
if (self.downloadDialog.dataset.online == 'false') {
|
|
self.showPromptNoConnection();
|
|
return;
|
|
}
|
|
|
|
if (self._wifiAvailable()) {
|
|
self._startedDownloadUsingDataConnection = false;
|
|
self.startDownloads();
|
|
return;
|
|
}
|
|
|
|
var wifiPrioritized = self.getWifiPrioritized();
|
|
var update2GEnabled = self.getUpdate2GEnabled();
|
|
|
|
// We can download the update only if the current connection
|
|
// is not forbidden for download
|
|
var conns = window.navigator.mozMobileConnections;
|
|
if (!conns) {
|
|
// B2G desktop/Mulet
|
|
if (navigator.onLine) {
|
|
self.startDownloads();
|
|
return;
|
|
}
|
|
console.error('mozMobileConnections is not available we can ' +
|
|
'not update the phone.');
|
|
self.showPromptNoConnection();
|
|
return;
|
|
}
|
|
|
|
var dataType;
|
|
// In DualSim only one of them will have data active
|
|
for (var i = 0; i < conns.length && !dataType; i++) {
|
|
dataType = conns[i].data.type;
|
|
}
|
|
if (!dataType) {
|
|
console.error('There are not wifi connection nor data ' +
|
|
'connection. We can not download update');
|
|
self.showForbiddenDownload();
|
|
return;
|
|
}
|
|
|
|
if (self.DATA_TYPES_NO_ALLOWED.indexOf(dataType) >= 0) {
|
|
self.connection2G = true;
|
|
} else {
|
|
self.connection2G = false;
|
|
}
|
|
|
|
// If it's not connected to a wifi we need to verify what kind of
|
|
// connection it has
|
|
Promise.all([wifiPrioritized, update2GEnabled]).then(function(values) {
|
|
var prioritized = values[0];
|
|
var update2G = values[1];
|
|
// If update 2G is available we don't need to know what kind
|
|
// of connection the phone has
|
|
if (update2G) {
|
|
if (prioritized) {
|
|
self.showPromptWifiPrioritized();
|
|
} else {
|
|
self.showPrompt3GAdditionalCostIfNeeded();
|
|
}
|
|
return;
|
|
}
|
|
|
|
//2G connection
|
|
if (self.connection2G && self._systemUpdateDisplayed) {
|
|
self.showForbiddenDownload();
|
|
return;
|
|
}
|
|
|
|
//3G connection
|
|
if (prioritized) {
|
|
self.showPromptWifiPrioritized();
|
|
} else {
|
|
self.showPrompt3GAdditionalCostIfNeeded();
|
|
}
|
|
});
|
|
},
|
|
|
|
containerClicked: function um_containerClicker() {
|
|
if (this._downloading) {
|
|
if (this._uncompressing) {
|
|
// If notification was clicked during uncompression, do nothing.
|
|
return;
|
|
}
|
|
var cancel = {
|
|
title: 'no',
|
|
callback: this.cancelPrompt.bind(this)
|
|
};
|
|
|
|
var confirm = {
|
|
title: 'yes',
|
|
callback: this.cancelAllDownloads.bind(this)
|
|
};
|
|
|
|
Service.request('showCustomDialog',
|
|
'cancelAllDownloads',
|
|
'wantToCancelAll',
|
|
cancel,
|
|
confirm
|
|
);
|
|
this._hasDialog = true;
|
|
} else {
|
|
this.showDownloadPrompt();
|
|
}
|
|
|
|
Service.request('UtilityTray:hide');
|
|
},
|
|
|
|
toasterClicked: function um_toasterClicked() {
|
|
if (this._downloading) {
|
|
return;
|
|
}
|
|
|
|
this.showDownloadPrompt();
|
|
Service.request('UtilityTray:hide');
|
|
},
|
|
|
|
showForbiddenDownload: function um_showForbiddenDownload() {
|
|
//Close any dialog if there is any open
|
|
Service.request('hideCustomDialog');
|
|
var ok = {
|
|
title: 'ok',
|
|
callback: this.cancelPrompt.bind(this)
|
|
};
|
|
|
|
window.dispatchEvent(new CustomEvent('updatepromptshown'));
|
|
|
|
Service.request('showCustomDialog',
|
|
'systemUpdate', 'downloadUpdatesVia2GForbidden3', ok, null);
|
|
this._hasDialog = true;
|
|
},
|
|
|
|
showPromptNoConnection: function um_showPromptNoConnection() {
|
|
//Close any dialog if there is any open
|
|
Service.request('hideCustomDialog');
|
|
var ok = {
|
|
title: 'ok',
|
|
callback: this.cancelPrompt.bind(this)
|
|
};
|
|
|
|
window.dispatchEvent(new CustomEvent('updatepromptshown'));
|
|
|
|
Service.request('showCustomDialog',
|
|
'systemUpdate', 'downloadOfflineWarning2', ok, null);
|
|
this._hasDialog = true;
|
|
},
|
|
|
|
showDownloadPrompt: function um_showDownloadPrompt() {
|
|
var _localize = navigator.mozL10n.setAttributes;
|
|
|
|
this._systemUpdateDisplayed = false;
|
|
_localize(this.downloadDialogTitle, 'numberOfUpdates', {
|
|
n: this.updatesQueue.length
|
|
});
|
|
|
|
// System update should always be on top
|
|
this.updatesQueue.sort(function sortUpdates(updatable, otherUpdatable) {
|
|
if (!updatable.app) {
|
|
return -1;
|
|
}
|
|
if (!otherUpdatable.app) {
|
|
return 1;
|
|
}
|
|
|
|
if (updatable.name < otherUpdatable.name) {
|
|
return -1;
|
|
}
|
|
if (updatable.name > otherUpdatable.name) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
this.downloadDialogList.innerHTML = '';
|
|
this.updatesQueue.forEach(function updatableIterator(updatable, index) {
|
|
var listItem = document.createElement('li');
|
|
var nameDetails;
|
|
|
|
// The user can choose not to update an app
|
|
if (updatable instanceof SystemUpdatable) {
|
|
var checkContainer = document.createElement('label');
|
|
_localize(checkContainer, 'required');
|
|
checkContainer.classList.add('required');
|
|
this._systemUpdateDisplayed = true;
|
|
listItem.appendChild(checkContainer);
|
|
nameDetails = listItem;
|
|
} else {
|
|
var checkbox = document.createElement('gaia-checkbox');
|
|
checkbox.dataset.position = index;
|
|
checkbox.checked = true;
|
|
|
|
var label = document.createElement('label');
|
|
nameDetails = label;
|
|
|
|
checkbox.appendChild(label);
|
|
listItem.appendChild(checkbox);
|
|
}
|
|
|
|
var name = document.createElement('span');
|
|
name.classList.add('name');
|
|
if (updatable.nameL10nId) {
|
|
_localize(name, updatable.nameL10nId, updatable.nameL10nArgs);
|
|
} else {
|
|
name.textContent = updatable.name;
|
|
}
|
|
nameDetails.appendChild(name);
|
|
|
|
if (updatable.size) {
|
|
var sizeItem = document.createElement('span');
|
|
sizeItem.textContent = this._humanizeSize(updatable.size);
|
|
nameDetails.appendChild(sizeItem);
|
|
} else {
|
|
nameDetails.classList.add('nosize');
|
|
}
|
|
|
|
if (updatable.buildID) {
|
|
var buildId = document.createElement('span');
|
|
buildId.classList.add('font-light');
|
|
_localize(buildId, 'build-id', { buildid: updatable.buildID });
|
|
listItem.appendChild(buildId);
|
|
}
|
|
|
|
if (updatable.detailsURL && (updatable.detailsURL !== 'about:blank')) {
|
|
var detailsUrl = document.createElement('a');
|
|
_localize(detailsUrl, 'view-release-notes');
|
|
listItem.appendChild(detailsUrl);
|
|
listItem.onclick = (function(event) {
|
|
event.preventDefault();
|
|
|
|
var activity = new MozActivity({
|
|
name: 'view',
|
|
data: {
|
|
type: 'url',
|
|
url: updatable.detailsURL
|
|
}
|
|
});
|
|
|
|
activity.onsuccess = this.cancelPrompt.bind(this);
|
|
}).bind(this);
|
|
}
|
|
|
|
this.downloadDialogList.appendChild(listItem);
|
|
}, this);
|
|
|
|
window.dispatchEvent(new CustomEvent('updatepromptshown'));
|
|
this._hasDialog = true;
|
|
this.downloadDialog.classList.add('visible');
|
|
this.updateDownloadButton();
|
|
},
|
|
|
|
updateDownloadButton: function() {
|
|
if (this._systemUpdateDisplayed) {
|
|
this.downloadButton.disabled = false;
|
|
return;
|
|
}
|
|
|
|
var disabled = true;
|
|
|
|
var dialog = this.downloadDialogList;
|
|
var checkboxes = dialog.querySelectorAll('gaia-checkbox');
|
|
for (var i = 0; i < checkboxes.length; i++) {
|
|
if (checkboxes[i].checked) {
|
|
disabled = false;
|
|
break;
|
|
}
|
|
}
|
|
this.downloadButton.disabled = disabled;
|
|
},
|
|
|
|
cancelPrompt: function um_cancelPrompt() {
|
|
Service.request('hideCustomDialog');
|
|
this._hasDialog = false;
|
|
this._closeDownloadDialog();
|
|
},
|
|
|
|
cancelDataConnectionUpdatesPrompt: function um_cancelDCUpdatesPrompt() {
|
|
Service.request('hideCustomDialog');
|
|
this._hasDialog = false;
|
|
this.downloadViaDataConnectionDialog.classList.remove('visible');
|
|
this._closeDownloadDialog();
|
|
},
|
|
|
|
getWifiPrioritized: function um_getWifiPrioritized() {
|
|
var wifiPrioritized = this.WIFI_PRIORITIZED;
|
|
var settings = window.navigator.mozSettings;
|
|
var self = this;
|
|
var getRequest = settings.createLock().get(this.WIFI_PRIORITIZED_KEY);
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
getRequest.onerror = function() {
|
|
resolve(wifiPrioritized);
|
|
};
|
|
getRequest.onsuccess = function() {
|
|
var prioritized = getRequest.result[self.WIFI_PRIORITIZED_KEY];
|
|
if (typeof prioritized !== 'boolean') {
|
|
prioritized = wifiPrioritized;
|
|
}
|
|
resolve(prioritized);
|
|
};
|
|
});
|
|
},
|
|
|
|
getUpdate2GEnabled: function um_getUpdate2GEnabled() {
|
|
var update2G = this.UPDATE_2G;
|
|
var settings = window.navigator.mozSettings;
|
|
var self = this;
|
|
var getRequest = settings.createLock().get(this.UPDATE_2G_SETT);
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
getRequest.onerror = function() {
|
|
resolve(update2G);
|
|
};
|
|
getRequest.onsuccess = function() {
|
|
var setting = getRequest.result[self.UPDATE_2G_SETT];
|
|
if (typeof setting !== 'boolean') {
|
|
setting = update2G;
|
|
}
|
|
resolve(setting);
|
|
};
|
|
});
|
|
},
|
|
|
|
showPrompt3GAdditionalCostIfNeeded:
|
|
function um_showPrompt3GAdditionalCostIfNeeded() {
|
|
this._openDownloadViaDataDialog();
|
|
Service.request('hideCustomDialog');
|
|
this._hasDialog = false;
|
|
},
|
|
|
|
showPromptWifiPrioritized:
|
|
function um_showPromptWifiPrioritized(downloadCallback) {
|
|
if (!downloadCallback) {
|
|
downloadCallback = this.showPrompt3GAdditionalCostIfNeeded;
|
|
}
|
|
var notNow = {
|
|
title: 'notNow',
|
|
callback: this.cancelPrompt.bind(this)
|
|
};
|
|
|
|
var download = {
|
|
title: 'download',
|
|
recommend: true,
|
|
callback: downloadCallback.bind(this)
|
|
};
|
|
|
|
var messageL10n = this.connection2G ? 'downloadWifiPrioritizedUsing2G' :
|
|
'downloadWifiPrioritized3';
|
|
|
|
this._closeDownloadDialog();
|
|
|
|
window.dispatchEvent(new CustomEvent('updatepromptshown'));
|
|
|
|
Service.request('UtilityTray:hide');
|
|
Service.request('showCustomDialog',
|
|
'systemUpdate',
|
|
messageL10n,
|
|
notNow,
|
|
download
|
|
);
|
|
this._hasDialog = true;
|
|
},
|
|
|
|
downloadProgressed: function um_downloadProgress(bytes) {
|
|
if (bytes > 0) {
|
|
this._downloadedBytes += bytes;
|
|
this.render();
|
|
}
|
|
},
|
|
|
|
downloaded: function um_downloaded(udatable) {
|
|
if (this._startedDownloadUsingDataConnection) {
|
|
this._startedDownloadUsingDataConnection = false;
|
|
}
|
|
},
|
|
|
|
startedUncompressing: function um_startedUncompressing() {
|
|
this._uncompressing = true;
|
|
this.render();
|
|
},
|
|
|
|
render: function um_render() {
|
|
var _localize = navigator.mozL10n.setAttributes;
|
|
var l10nId = 'updateAvailableInfo';
|
|
|
|
if ((this.updatesQueue.length === 1) &&
|
|
(this.updatesQueue[0] instanceof SystemUpdatable)) {
|
|
l10nId = 'systemUpdateAvailableInfo';
|
|
}
|
|
|
|
_localize(this.toasterMessage, l10nId, {
|
|
n: this.updatesQueue.length - this.lastUpdatesAvailable
|
|
});
|
|
|
|
if (this._downloading) {
|
|
if (this._uncompressing && this.downloadsQueue.length === 1) {
|
|
_localize(this.message, 'uncompressingMessage');
|
|
} else {
|
|
_localize(this.message, 'downloadingUpdateMessage', {
|
|
progress: this._humanizeSize(this._downloadedBytes)
|
|
});
|
|
}
|
|
} else {
|
|
_localize(this.message, l10nId, { n: this.updatesQueue.length });
|
|
}
|
|
|
|
var css = this.container.classList;
|
|
this._downloading ? css.add('downloading') : css.remove('downloading');
|
|
},
|
|
|
|
addToUpdatableApps: function um_addtoUpdatableapps(updatableApp) {
|
|
this.updatableApps.push(updatableApp);
|
|
},
|
|
|
|
removeFromAll: function um_removeFromAll(updatableApp) {
|
|
var removeIndex = this.updatableApps.indexOf(updatableApp);
|
|
if (removeIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
var removedApp = this.updatableApps[removeIndex];
|
|
this.removeFromUpdatesQueue(removedApp);
|
|
|
|
removedApp.uninit();
|
|
this.updatableApps.splice(removeIndex, 1);
|
|
},
|
|
|
|
addToUpdatesQueue: function um_addToUpdatesQueue(updatable) {
|
|
if (this._downloading) {
|
|
return;
|
|
}
|
|
|
|
if (updatable.app &&
|
|
updatable.app.installState !== 'installed') {
|
|
return;
|
|
}
|
|
|
|
if (updatable.app &&
|
|
this.updatableApps.indexOf(updatable) === -1) {
|
|
return;
|
|
}
|
|
|
|
var alreadyThere = this.updatesQueue.some(function lookup(u) {
|
|
return (u.app === updatable.app);
|
|
});
|
|
if (alreadyThere) {
|
|
return;
|
|
}
|
|
|
|
this.updatesQueue.push(updatable);
|
|
|
|
if (this._notificationTimeout === null) {
|
|
this._notificationTimeout = setTimeout(
|
|
this.displayNotificationAndToaster.bind(this),
|
|
this.NOTIFICATION_BUFFERING_TIMEOUT);
|
|
}
|
|
this.render();
|
|
},
|
|
|
|
displayNotificationAndToaster: function um_displayNotificationAndToaster() {
|
|
this._notificationTimeout = null;
|
|
if (this.updatesQueue.length && !this._downloading) {
|
|
this.lastUpdatesAvailable = this.updatesQueue.length;
|
|
this.displayNotificationIfHidden();
|
|
this.toaster.classList.add('displayed');
|
|
var self = this;
|
|
setTimeout(function waitToHide() {
|
|
self.toaster.classList.remove('displayed');
|
|
}, this.TOASTER_TIMEOUT);
|
|
}
|
|
},
|
|
|
|
removeFromUpdatesQueue: function um_removeFromUpdatesQueue(updatable) {
|
|
var removeIndex = this.updatesQueue.indexOf(updatable);
|
|
if (removeIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
this.updatesQueue.splice(removeIndex, 1);
|
|
this.lastUpdatesAvailable = this.updatesQueue.length;
|
|
|
|
if (this.updatesQueue.length === 0) {
|
|
this.hideNotificationIfDisplayed();
|
|
}
|
|
|
|
this.render();
|
|
},
|
|
|
|
addToDownloadsQueue: function um_addToDownloadsQueue(updatable) {
|
|
if (updatable.app &&
|
|
this.updatableApps.indexOf(updatable) === -1) {
|
|
return;
|
|
}
|
|
|
|
var alreadyThere = this.downloadsQueue.some(function lookup(u) {
|
|
return (u.app === updatable.app);
|
|
});
|
|
if (alreadyThere) {
|
|
return;
|
|
}
|
|
|
|
this.downloadsQueue.push(updatable);
|
|
|
|
if (this.downloadsQueue.length === 1) {
|
|
this._downloading = true;
|
|
Service.request('incDownloads');
|
|
this._wifiLock = navigator.requestWakeLock('wifi');
|
|
|
|
this.displayNotificationIfHidden();
|
|
this.render();
|
|
}
|
|
},
|
|
|
|
removeFromDownloadsQueue: function um_removeFromDownloadsQueue(updatable) {
|
|
var removeIndex = this.downloadsQueue.indexOf(updatable);
|
|
if (removeIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
this.downloadsQueue.splice(removeIndex, 1);
|
|
|
|
if (this.downloadsQueue.length === 0) {
|
|
this._downloading = false;
|
|
this._uncompressing = false;
|
|
Service.request('decDownloads');
|
|
this._downloadedBytes = 0;
|
|
this.checkStatuses();
|
|
|
|
if (this._wifiLock) {
|
|
try {
|
|
this._wifiLock.unlock();
|
|
} catch (e) {
|
|
// this can happen if the lock is already unlocked
|
|
console.error('error during unlock', e);
|
|
}
|
|
|
|
this._wifiLock = null;
|
|
}
|
|
|
|
this.render();
|
|
}
|
|
},
|
|
|
|
hideNotificationIfDisplayed: function() {
|
|
if (this.container.classList.contains('displayed')) {
|
|
this.container.classList.remove('displayed');
|
|
NotificationScreen.removeUnreadNotification(this.UPDATE_NOTIF_ID);
|
|
}
|
|
},
|
|
|
|
displayNotificationIfHidden: function() {
|
|
if (!this.container.classList.contains('displayed')) {
|
|
this.container.classList.add('displayed');
|
|
NotificationScreen.addUnreadNotification(this.UPDATE_NOTIF_ID);
|
|
}
|
|
},
|
|
|
|
checkStatuses: function um_checkStatuses() {
|
|
this.updatableApps.forEach(function(updatableApp) {
|
|
var app = updatableApp.app;
|
|
if (app.downloadAvailable) {
|
|
this.addToUpdatesQueue(updatableApp);
|
|
}
|
|
}, this);
|
|
},
|
|
|
|
oninstall: function um_oninstall(evt) {
|
|
var app = evt.application;
|
|
/* jshint nonew: false */
|
|
new AppUpdatable(app);
|
|
},
|
|
|
|
onuninstall: function um_onuninstall(evt) {
|
|
this.updatableApps.some(function appIterator(updatableApp, index) {
|
|
// The application object we get from the event
|
|
// has only origin and manifestURL properties
|
|
if (updatableApp.app.manifestURL === evt.application.manifestURL) {
|
|
this.removeFromAll(updatableApp);
|
|
return true;
|
|
}
|
|
return false;
|
|
}, this);
|
|
},
|
|
|
|
handleEvent: function um_handleEvent(evt) {
|
|
if (!evt.type) {
|
|
return;
|
|
}
|
|
|
|
switch (evt.type) {
|
|
case 'applicationinstall':
|
|
this.oninstall(evt.detail);
|
|
break;
|
|
case 'applicationuninstall':
|
|
this.onuninstall(evt.detail);
|
|
break;
|
|
case 'offline':
|
|
this.updateOnlineStatus();
|
|
break;
|
|
case 'online':
|
|
this.updateOnlineStatus();
|
|
break;
|
|
case 'wifi-statuschange':
|
|
this.updateWifiStatus();
|
|
break;
|
|
case 'lockscreen-appopened':
|
|
if (this.systemUpdatable.showingApplyPrompt) {
|
|
this.systemUpdatable.declineInstallWait();
|
|
}
|
|
this.downloadViaDataConnectionDialog.classList.remove('visible');
|
|
this._closeDownloadDialog();
|
|
// only request while update manager shows a dialog
|
|
if (this._hasDialog) {
|
|
Service.request('hideCustomDialog');
|
|
}
|
|
break;
|
|
case 'home':
|
|
case 'holdhome':
|
|
if (this._hasDialog) {
|
|
this.cancelPrompt();
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (evt.type !== 'mozChromeEvent') {
|
|
return;
|
|
}
|
|
|
|
var detail = evt.detail;
|
|
|
|
if (detail.type && detail.type === 'update-available') {
|
|
this.systemUpdatable.size = detail.size;
|
|
this.systemUpdatable.buildID = detail.buildID;
|
|
this.systemUpdatable.detailsURL = detail.detailsURL;
|
|
this.systemUpdatable.nameL10nArgs = { version: detail.displayVersion };
|
|
this.systemUpdatable.rememberKnownUpdate();
|
|
this.addToUpdatesQueue(this.systemUpdatable);
|
|
}
|
|
},
|
|
|
|
updateOnlineStatus: function su_updateOnlineStatus() {
|
|
var online = (navigator && 'onLine' in navigator) ?
|
|
navigator.onLine : true;
|
|
this.downloadDialog.dataset.online = online;
|
|
},
|
|
|
|
_wifiAvailable: function su_wifiAvailable() {
|
|
var wifiManager = window.navigator.mozWifiManager;
|
|
if (!wifiManager) {
|
|
return;
|
|
}
|
|
return wifiManager.connection.status == 'connected';
|
|
},
|
|
|
|
updateWifiStatus: function su_updateWifiStatus() {
|
|
this.downloadDialog.dataset.nowifi = !this._wifiAvailable();
|
|
},
|
|
|
|
checkForUpdates: function su_checkForUpdates(shouldCheck) {
|
|
if (!shouldCheck) {
|
|
return;
|
|
}
|
|
|
|
this._dispatchEvent('force-update-check');
|
|
|
|
if (!this._settings) {
|
|
return;
|
|
}
|
|
|
|
var lock = this._settings.createLock();
|
|
lock.set({
|
|
'gaia.system.checkForUpdates': false
|
|
});
|
|
},
|
|
|
|
_openDownloadViaDataDialog: function um_downloadViaDataDialog() {
|
|
var _ = navigator.mozL10n.setAttributes;
|
|
var connections = window.navigator.mozMobileConnections;
|
|
var dataType;
|
|
var sim;
|
|
|
|
if (!connections) {
|
|
this.showForbiddenDownload();
|
|
return;
|
|
}
|
|
// In DualSim only one of them will have data active
|
|
for (var i = 0; i < connections.length && !dataType; i++) {
|
|
dataType = connections[i].data.type;
|
|
sim = connections[i];
|
|
}
|
|
|
|
if (!dataType) {
|
|
//No connection available
|
|
self.showForbiddenDownload();
|
|
return;
|
|
}
|
|
var dataRoamingSettingPromise = this._getDataRoamingSetting();
|
|
dataRoamingSettingPromise.then(function(roaming) {
|
|
if (roaming && sim.data.roaming) {
|
|
_(this.downloadViaDataConnectionTitle,
|
|
'downloadUpdatesViaDataRoamingConnection');
|
|
_(this.downloadViaDataConnectionMessage,
|
|
'downloadUpdatesViaDataRoamingConnectionMessage');
|
|
window.dispatchEvent(new CustomEvent('updatepromptshown'));
|
|
this.downloadViaDataConnectionDialog.classList.add('visible');
|
|
return;
|
|
}
|
|
this._startedDownloadUsingDataConnection = true;
|
|
this.startDownloads();
|
|
}.bind(this));
|
|
},
|
|
|
|
_getDataRoamingSetting: function um_getDataRoamingSetting() {
|
|
var lock = this._settings.createLock();
|
|
var reqDataRoaming = lock.get(this.ROAMING_SETTING_KEY);
|
|
var dataRoamingSettingPromise;
|
|
var self = this;
|
|
|
|
dataRoamingSettingPromise = new Promise(function(resolve, reject) {
|
|
reqDataRoaming.onsuccess = function() {
|
|
resolve(reqDataRoaming.result[self.ROAMING_SETTING_KEY]);
|
|
};
|
|
|
|
reqDataRoaming.onerror = function() {
|
|
resolve(false);
|
|
};
|
|
});
|
|
|
|
return dataRoamingSettingPromise;
|
|
},
|
|
|
|
_dispatchEvent: function um_dispatchEvent(type, result) {
|
|
var event = document.createEvent('CustomEvent');
|
|
var data = { type: type };
|
|
if (result) {
|
|
data.result = result;
|
|
}
|
|
|
|
event.initCustomEvent('mozContentEvent', true, true, data);
|
|
window.dispatchEvent(event);
|
|
},
|
|
|
|
// This is going to be part of l10n.js
|
|
_humanizeSize: function um_humanizeSize(bytes) {
|
|
var _ = navigator.mozL10n.get;
|
|
var units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'];
|
|
|
|
if (!bytes) {
|
|
return '0.00 ' + _(units[0]);
|
|
}
|
|
|
|
var e = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
return (bytes / Math.pow(1024, Math.floor(e))).toFixed(2) + ' ' +
|
|
_(units[e]);
|
|
},
|
|
|
|
_closeDownloadDialog: function um_closeDownloadDialog() {
|
|
window.dispatchEvent(new CustomEvent('updateprompthidden'));
|
|
this.downloadDialog.classList.remove('visible');
|
|
}
|
|
};
|
|
exports.UpdateManager = UpdateManager;
|
|
}(window));
|