diff options
Diffstat (limited to 'apps/system/js/updatable.js')
-rw-r--r-- | apps/system/js/updatable.js | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/apps/system/js/updatable.js b/apps/system/js/updatable.js new file mode 100644 index 0000000..57ce737 --- /dev/null +++ b/apps/system/js/updatable.js @@ -0,0 +1,269 @@ +'use strict'; + +/* + * An Updatable object represents an application *or* system update. + * It takes care of the interaction with the UpdateManager and observes + * the update itself to handle success/error cases. + * + * - name of the update + * - size of the update + * - download() to start the download + * - cancelDownload() to cancel it + */ + +/* === App Updates === */ +function AppUpdatable(app) { + this._mgmt = navigator.mozApps.mgmt; + this.app = app; + + var manifest = app.manifest ? app.manifest : app.updateManifest; + this.name = new ManifestHelper(manifest).name; + + this.size = app.downloadSize; + this.progress = null; + + UpdateManager.addToUpdatableApps(this); + app.ondownloadavailable = this.availableCallBack.bind(this); + if (app.downloadAvailable) { + this.availableCallBack(); + } + if (app.readyToApplyDownload) { + this.applyUpdate(); + } +} + +AppUpdatable.prototype.download = function() { + UpdateManager.addToDownloadsQueue(this); + this.progress = 0; + + this.app.download(); +}; + +AppUpdatable.prototype.cancelDownload = function() { + this.app.cancelDownload(); +}; + +AppUpdatable.prototype.uninit = function() { + this.app.ondownloadavailable = null; + this.clean(); +}; + +AppUpdatable.prototype.clean = function() { + this.app.ondownloaderror = null; + this.app.ondownloadsuccess = null; + this.app.ondownloadapplied = null; + this.app.onprogress = null; + + this.progress = null; +}; + +AppUpdatable.prototype.availableCallBack = function() { + this.size = this.app.downloadSize; + + if (this.app.installState === 'installed') { + UpdateManager.addToUpdatesQueue(this); + + // we add these callbacks only now to prevent interfering + // with other modules (especially the AppInstallManager) + this.app.ondownloaderror = this.errorCallBack.bind(this); + this.app.ondownloadsuccess = this.successCallBack.bind(this); + this.app.ondownloadapplied = this.appliedCallBack.bind(this); + this.app.onprogress = this.progressCallBack.bind(this); + } +}; + +AppUpdatable.prototype.successCallBack = function() { + var app = this.app; + if (WindowManager.getDisplayedApp() !== app.origin) { + this.applyUpdate(); + } else { + var self = this; + window.addEventListener('appwillclose', function waitClose() { + window.removeEventListener('appwillclose', waitClose); + self.applyUpdate(); + }); + } + + UpdateManager.removeFromDownloadsQueue(this); + UpdateManager.removeFromUpdatesQueue(this); +}; + +AppUpdatable.prototype.applyUpdate = function() { + WindowManager.kill(this.app.origin); + this._mgmt.applyDownload(this.app); +}; + +AppUpdatable.prototype.appliedCallBack = function() { + this.clean(); +}; + +AppUpdatable.prototype.errorCallBack = function(e) { + var errorName = e.application.downloadError.name; + console.info('downloadError event, error code is', errorName); + UpdateManager.requestErrorBanner(); + UpdateManager.removeFromDownloadsQueue(this); + this.progress = null; +}; + +AppUpdatable.prototype.progressCallBack = function() { + if (this.progress === null) { + // this is the first progress + UpdateManager.addToDownloadsQueue(this); + this.progress = 0; + } + + var delta = this.app.progress - this.progress; + + this.progress = this.app.progress; + UpdateManager.downloadProgressed(delta); +}; + +/* + * System Updates + * Will be instanciated only once by the UpdateManager + * + */ +function SystemUpdatable() { + var _ = navigator.mozL10n.get; + this.name = _('systemUpdate'); + this.size = 0; + this.downloading = false; + this.paused = false; + + // XXX: this state should be kept on the platform side + // https://bugzilla.mozilla.org/show_bug.cgi?id=827090 + this.checkKnownUpdate(UpdateManager.checkForUpdates.bind(UpdateManager)); + + window.addEventListener('mozChromeEvent', this); +} + +SystemUpdatable.KNOWN_UPDATE_FLAG = 'known-sysupdate'; + +SystemUpdatable.prototype.download = function() { + if (this.downloading) { + return; + } + + this.downloading = true; + this.paused = false; + this._dispatchEvent('update-available-result', 'download'); + UpdateManager.addToDownloadsQueue(this); + this.progress = 0; +}; + +SystemUpdatable.prototype.cancelDownload = function() { + this._dispatchEvent('update-download-cancel'); + this.downloading = false; + this.paused = false; +}; + +SystemUpdatable.prototype.uninit = function() { + window.removeEventListener('mozChromeEvent', this); +}; + +SystemUpdatable.prototype.handleEvent = function(evt) { + if (evt.type !== 'mozChromeEvent') + return; + + var detail = evt.detail; + if (!detail.type) + return; + + switch (detail.type) { + case 'update-error': + this.errorCallBack(); + break; + case 'update-download-started': + // TODO UpdateManager glue + this.paused = false; + break; + case 'update-download-progress': + var delta = detail.progress - this.progress; + this.progress = detail.progress; + + UpdateManager.downloadProgressed(delta); + break; + case 'update-download-stopped': + // TODO UpdateManager glue + this.paused = detail.paused; + if (!this.paused) { + UpdateManager.startedUncompressing(); + } + break; + case 'update-downloaded': + this.downloading = false; + this.showApplyPrompt(); + break; + case 'update-prompt-apply': + this.showApplyPrompt(); + break; + } +}; + +SystemUpdatable.prototype.errorCallBack = function() { + UpdateManager.requestErrorBanner(); + UpdateManager.removeFromDownloadsQueue(this); + this.downloading = false; +}; + +SystemUpdatable.prototype.showApplyPrompt = function() { + var _ = navigator.mozL10n.get; + + // Update will be completed after restart + this.forgetKnownUpdate(); + + var cancel = { + title: _('later'), + callback: this.declineInstall.bind(this) + }; + + var confirm = { + title: _('installNow'), + callback: this.acceptInstall.bind(this) + }; + + UtilityTray.hide(); + CustomDialog.show(_('systemUpdateReady'), _('wantToInstall'), + cancel, confirm); +}; + +SystemUpdatable.prototype.declineInstall = function() { + CustomDialog.hide(); + this._dispatchEvent('update-prompt-apply-result', 'wait'); + + UpdateManager.removeFromDownloadsQueue(this); +}; + +SystemUpdatable.prototype.acceptInstall = function() { + CustomDialog.hide(); + this._dispatchEvent('update-prompt-apply-result', 'restart'); +}; + +SystemUpdatable.prototype.rememberKnownUpdate = function() { + asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); +}; + +SystemUpdatable.prototype.checkKnownUpdate = function(callback) { + if (typeof callback !== 'function') { + return; + } + + asyncStorage.getItem(SystemUpdatable.KNOWN_UPDATE_FLAG, function(value) { + callback(!!value); + }); +}; + +SystemUpdatable.prototype.forgetKnownUpdate = function() { + asyncStorage.removeItem(SystemUpdatable.KNOWN_UPDATE_FLAG); +}; + +SystemUpdatable.prototype._dispatchEvent = function(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); +}; |