diff options
Diffstat (limited to 'apps/system/js')
60 files changed, 0 insertions, 15816 deletions
diff --git a/apps/system/js/accessibility.js b/apps/system/js/accessibility.js deleted file mode 100644 index c2fa111..0000000 --- a/apps/system/js/accessibility.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -SettingsListener.observe('accessibility.invert', false, function(value) { - var screen = document.getElementById('screen'); - if (value) - screen.classList.add('accessibility-invert'); - else - screen.classList.remove('accessibility-invert'); -}); - -SettingsListener.observe('accessibility.screenreader', false, function(value) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, - {type: 'accessibility-screenreader', enabled: value}); - window.dispatchEvent(event); -}); diff --git a/apps/system/js/activities.js b/apps/system/js/activities.js deleted file mode 100644 index f4db861..0000000 --- a/apps/system/js/activities.js +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var Activities = { - init: function act_init() { - window.addEventListener('mozChromeEvent', this); - }, - - handleEvent: function act_handleEvent(evt) { - switch (evt.type) { - case 'mozChromeEvent': - var detail = evt.detail; - switch (detail.type) { - case 'activity-choice': - this.chooseActivity(detail); - break; - } - break; - } - }, - - chooseActivity: function chooseActivity(detail) { - this._id = detail.id; - - var choices = detail.choices; - if (choices.length === 1) { - this.choose('0'); - } else { - // Since the mozChromeEvent could be triggered by a 'click', and gecko - // event are synchronous make sure to exit the event loop before - // showing the list. - setTimeout((function nextTick() { - var activityName = navigator.mozL10n.get('activity-' + detail.name); - ListMenu.request(this._listItems(choices), activityName, - this.choose.bind(this), this.cancel.bind(this)); - }).bind(this)); - } - }, - - choose: function act_choose(choice) { - var returnedChoice = { - id: this._id, - type: 'activity-choice', - value: choice - }; - - this._sendEvent(returnedChoice); - delete this._id; - }, - - cancel: function act_cancel(value) { - var returnedChoice = { - id: this._id, - type: 'activity-choice', - value: -1 - }; - - this._sendEvent(returnedChoice); - delete this._id; - }, - - _sendEvent: function act_sendEvent(value) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, value); - window.dispatchEvent(event); - }, - - _listItems: function act_listItems(choices) { - var items = []; - - choices.forEach(function(choice, index) { - var app = Applications.getByManifestURL(choice.manifest); - items.push({ - label: new ManifestHelper(app.manifest).name, - icon: choice.icon, - value: index - }); - }); - - return items; - } -}; - -Activities.init(); diff --git a/apps/system/js/airplane_mode.js b/apps/system/js/airplane_mode.js deleted file mode 100644 index 781a53f..0000000 --- a/apps/system/js/airplane_mode.js +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var AirplaneMode = { - enabled: false, - - init: function apm_init() { - if (!window.navigator.mozSettings) - return; - - var mobileDataEnabled = false; - SettingsListener.observe('ril.data.enabled', false, function(value) { - mobileDataEnabled = value; - }); - - var bluetoothEnabled = false; - SettingsListener.observe('bluetooth.enabled', false, function(value) { - bluetoothEnabled = value; - }); - - var wifiEnabled = false; - SettingsListener.observe('wifi.enabled', false, function(value) { - wifiEnabled = value; - }); - - var geolocationEnabled = false; - SettingsListener.observe('geolocation.enabled', false, function(value) { - geolocationEnabled = value; - }); - - var bluetooth = window.navigator.mozBluetooth; - var wifiManager = window.navigator.mozWifiManager; - var mobileData = window.navigator.mozMobileConnection && - window.navigator.mozMobileConnection.data; - var fmRadio = window.navigator.mozFMRadio; - - var restoreMobileData = false; - var restoreBluetooth = false; - var restoreWifi = false; - var restoreGeolocation = false; - // Note that we don't restore Wifi tethering when leaving airplane mode - // because Wifi tethering can't be switched on before data connection is - // established. - - var self = this; - SettingsListener.observe('ril.radio.disabled', false, function(value) { - if (value) { - // Entering airplane mode. - self.enabled = true; - - // Turn off mobile data - // We toggle the mozSettings value here just for the sake of UI, - // platform ril disconnects mobile data when - // 'ril.radio.disabled' is true. - if (mobileData) { - restoreMobileData = mobileDataEnabled; - if (mobileDataEnabled) { - SettingsListener.getSettingsLock().set({ - 'ril.data.enabled': false - }); - } - } - - // Turn off Bluetooth. - if (bluetooth) { - restoreBluetooth = bluetoothEnabled; - if (bluetoothEnabled) { - SettingsListener.getSettingsLock().set({ - 'bluetooth.enabled': false - }); - } - } - - // Turn off Wifi. - if (wifiManager) { - restoreWifi = wifiEnabled; - if (wifiEnabled) { - SettingsListener.getSettingsLock().set({ - 'wifi.enabled': false - }); - } - - // Turn off Wifi tethering. - SettingsListener.getSettingsLock().set({ - 'tethering.wifi.enabled': false - }); - } - - // Turn off Geolocation. - restoreGeolocation = geolocationEnabled; - if (geolocationEnabled) { - SettingsListener.getSettingsLock().set({ - 'geolocation.enabled': false - }); - } - - // Turn off FM Radio. - if (fmRadio && fmRadio.enabled) - fmRadio.disable(); - - } else { - self.enabled = false; - // Don't attempt to turn on mobile data if it's already on - if (mobileData && !mobileDataEnabled && restoreMobileData) { - SettingsListener.getSettingsLock().set({ - 'ril.data.enabled': true - }); - } - - // Don't attempt to turn on Bluetooth if it's already on - if (bluetooth && !bluetooth.enabled && restoreBluetooth) { - SettingsListener.getSettingsLock().set({ - 'bluetooth.enabled': true - }); - } - - // Don't attempt to turn on Wifi if it's already on - if (wifiManager && !wifiManager.enabled && restoreWifi) { - SettingsListener.getSettingsLock().set({ - 'wifi.enabled': true - }); - } - - // Don't attempt to turn on Geolocation if it's already on - if (!geolocationEnabled && restoreGeolocation) { - SettingsListener.getSettingsLock().set({ - 'geolocation.enabled': true - }); - } - } - }); - } -}; - -AirplaneMode.init(); - diff --git a/apps/system/js/app_install_manager.js b/apps/system/js/app_install_manager.js deleted file mode 100644 index 146a01b..0000000 --- a/apps/system/js/app_install_manager.js +++ /dev/null @@ -1,443 +0,0 @@ -'use strict'; - -var AppInstallManager = { - mapDownloadErrorsToMessage: { - 'NETWORK_ERROR': 'download-failed', - 'DOWNLOAD_ERROR': 'download-failed', - 'MISSING_MANIFEST': 'install-failed', - 'INVALID_MANIFEST': 'install-failed', - 'INSTALL_FROM_DENIED': 'install-failed', - 'INVALID_SECURITY_LEVEL': 'install-failed', - 'INVALID_PACKAGE': 'install-failed', - 'APP_CACHE_DOWNLOAD_ERROR': 'download-failed' - }, - - init: function ai_init() { - this.dialog = document.getElementById('app-install-dialog'); - this.msg = document.getElementById('app-install-message'); - this.size = document.getElementById('app-install-size'); - this.authorName = document.getElementById('app-install-author-name'); - this.authorUrl = document.getElementById('app-install-author-url'); - this.installButton = document.getElementById('app-install-install-button'); - this.cancelButton = document.getElementById('app-install-cancel-button'); - this.installCancelDialog = - document.getElementById('app-install-cancel-dialog'); - this.downloadCancelDialog = - document.getElementById('app-download-cancel-dialog'); - this.confirmCancelButton = - document.getElementById('app-install-confirm-cancel-button'); - this.resumeButton = document.getElementById('app-install-resume-button'); - - this.notifContainer = - document.getElementById('install-manager-notification-container'); - this.appInfos = {}; - - window.addEventListener('mozChromeEvent', - (function ai_handleChromeEvent(e) { - if (e.detail.type == 'webapps-ask-install') { - this.handleAppInstallPrompt(e.detail); - } - }).bind(this)); - - window.addEventListener('applicationinstall', - this.handleApplicationInstall.bind(this)); - - - this.installButton.onclick = this.handleInstall.bind(this); - this.cancelButton.onclick = this.showInstallCancelDialog.bind(this); - this.confirmCancelButton.onclick = this.handleInstallCancel.bind(this); - this.resumeButton.onclick = this.hideInstallCancelDialog.bind(this); - this.notifContainer.onclick = this.showDownloadCancelDialog.bind(this); - - this.downloadCancelDialog.querySelector('.confirm').onclick = - this.handleConfirmDownloadCancel.bind(this); - this.downloadCancelDialog.querySelector('.cancel').onclick = - this.handleCancelDownloadCancel.bind(this); - - // bind these handlers so that we can have only one instance and check - // them later on - ['handleDownloadSuccess', - 'handleDownloadError', - 'handleProgress', - 'handleApplicationReady' - ].forEach(function(name) { - this[name] = this[name].bind(this); - }, this); - - window.addEventListener('applicationready', - this.handleApplicationReady); - }, - - handleApplicationReady: function ai_handleApplicationReady(e) { - window.removeEventListener('applicationready', - this.handleApplicationReady); - - var apps = e.detail.applications; - - Object.keys(apps) - .filter(function(key) { return apps[key].installState === 'pending'; }) - .map(function(key) { return apps[key]; }) - .forEach(this.prepareForDownload, this); - }, - - handleApplicationInstall: function ai_handleApplicationInstallEvent(e) { - var app = e.detail.application; - - if (app.installState === 'installed') { - this.showInstallSuccess(app); - return; - } - - this.prepareForDownload(app); - }, - - handleAppInstallPrompt: function ai_handleInstallPrompt(detail) { - var _ = navigator.mozL10n.get; - var app = detail.app; - // updateManifest is used by packaged apps until they are installed - var manifest = app.manifest ? app.manifest : app.updateManifest; - - if (!manifest) - return; - - this.dialog.classList.add('visible'); - - var id = detail.id; - - if (manifest.size) { - this.size.textContent = this.humanizeSize(manifest.size); - } else { - this.size.textContent = _('unknown'); - } - - // Wrap manifest to get localized properties - manifest = new ManifestHelper(manifest); - var msg = _('install-app', {'name': manifest.name}); - this.msg.textContent = msg; - - if (manifest.developer) { - this.authorName.textContent = manifest.developer.name || _('unknown'); - this.authorUrl.textContent = manifest.developer.url || ''; - } else { - this.authorName.textContent = _('unknown'); - this.authorUrl.textContent = ''; - } - - this.installCallback = (function ai_installCallback() { - this.dispatchResponse(id, 'webapps-install-granted'); - }).bind(this); - - this.installCancelCallback = (function ai_cancelCallback() { - this.dispatchResponse(id, 'webapps-install-denied'); - }).bind(this); - - }, - - handleInstall: function ai_handleInstall(evt) { - if (evt) - evt.preventDefault(); - if (this.installCallback) - this.installCallback(); - this.installCallback = null; - this.dialog.classList.remove('visible'); - }, - - prepareForDownload: function ai_prepareForDownload(app) { - var manifestURL = app.manifestURL; - this.appInfos[manifestURL] = {}; - - // these methods are already bound to |this| - app.ondownloadsuccess = this.handleDownloadSuccess; - app.ondownloaderror = this.handleDownloadError; - app.onprogress = this.handleProgress; - }, - - showInstallSuccess: function ai_showInstallSuccess(app) { - var manifest = app.manifest || app.updateManifest; - var name = new ManifestHelper(manifest).name; - var _ = navigator.mozL10n.get; - var msg = _('app-install-success', { appName: name }); - SystemBanner.show(msg); - }, - - handleDownloadSuccess: function ai_handleDownloadSuccess(evt) { - var app = evt.application; - this.showInstallSuccess(app); - this.onDownloadStop(app); - this.onDownloadFinish(app); - }, - - handleDownloadError: function ai_handleDownloadError(evt) { - var app = evt.application; - var _ = navigator.mozL10n.get; - var manifest = app.manifest || app.updateManifest; - var name = new ManifestHelper(manifest).name; - - var errorName = app.downloadError.name; - - switch (errorName) { - case 'INSUFFICIENT_STORAGE': - var title = _('not-enough-space'), - buttonText = _('ok'), - message = _('not-enough-space-message'); - - ModalDialog.alert(title, message, {title: buttonText}); - break; - default: - // showing the real error to a potential developer - console.info('downloadError event, error code is', errorName); - - var key = this.mapDownloadErrorsToMessage[errorName] || 'generic-error'; - var msg = _('app-install-' + key, { appName: name }); - SystemBanner.show(msg); - } - - this.onDownloadStop(app); - }, - - onDownloadStart: function ai_onDownloadStart(app) { - if (! this.hasNotification(app)) { - StatusBar.incSystemDownloads(); - this.addNotification(app); - this.requestWifiLock(app); - } - }, - - onDownloadStop: function ai_onDownloadStop(app) { - if (this.hasNotification(app)) { - StatusBar.decSystemDownloads(); - this.removeNotification(app); - this.releaseWifiLock(app); - } - }, - - hasNotification: function ai_hasNotification(app) { - var appInfo = this.appInfos[app.manifestURL]; - return appInfo && !!appInfo.installNotification; - }, - - onDownloadFinish: function ai_onDownloadFinish(app) { - delete this.appInfos[app.manifestURL]; - - // check if these are our handlers before removing them - if (app.ondownloadsuccess === this.handleDownloadSuccess) { - app.ondownloadsuccess = null; - } - - if (app.ondownloaderror === this.handleDownloadError) { - app.ondownloaderror = null; - } - - if (app.onprogress === this.handleProgress) { - app.onprogress = null; - } - }, - - addNotification: function ai_addNotification(app) { - // should be unique (this is used already in applications.js) - var manifestURL = app.manifestURL, - manifest = app.manifest || app.updateManifest, - appInfo = this.appInfos[manifestURL]; - - if (appInfo.installNotification) { - return; - } - - var newNotif = - '<div class="fake-notification">' + - '<div class="message"></div>' + - '<progress></progress>' + - '</div>'; - - this.notifContainer.insertAdjacentHTML('afterbegin', newNotif); - - var newNode = this.notifContainer.firstElementChild; - newNode.dataset.manifest = manifestURL; - - var _ = navigator.mozL10n.get; - - var message = _('downloadingAppMessage', { - appName: new ManifestHelper(manifest).name - }); - - newNode.querySelector('.message').textContent = message; - - var size = manifest.size, - progressNode = newNode.querySelector('progress'); - if (size) { - progressNode.max = size; - appInfo.hasMax = true; - } - - appInfo.installNotification = newNode; - NotificationScreen.incExternalNotifications(); - }, - - getNotificationProgressNode: function ai_getNotificationProgressNode(app) { - var appInfo = this.appInfos[app.manifestURL]; - var progressNode = appInfo && - appInfo.installNotification && - appInfo.installNotification.querySelector('progress'); - return progressNode || null; - }, - - handleProgress: function ai_handleProgress(evt) { - var app = evt.application, - appInfo = this.appInfos[app.manifestURL]; - - this.onDownloadStart(app); - - - var progressNode = this.getNotificationProgressNode(app); - var message; - var _ = navigator.mozL10n.get; - - if (isNaN(app.progress) || app.progress == null) { - // now we get NaN if there is no progress information but let's - // handle the null and undefined cases as well - message = _('downloadingAppProgressIndeterminate'); - progressNode.value = undefined; // switch to indeterminate state - } else if (appInfo.hasMax) { - message = _('downloadingAppProgress', - { - progress: this.humanizeSize(app.progress), - max: this.humanizeSize(progressNode.max) - }); - progressNode.value = app.progress; - } else { - message = _('downloadingAppProgressNoMax', - { progress: this.humanizeSize(app.progress) }); - } - progressNode.textContent = message; - }, - - removeNotification: function ai_removeNotification(app) { - var manifestURL = app.manifestURL, - appInfo = this.appInfos[manifestURL], - node = appInfo.installNotification; - - if (!node) { - return; - } - - node.parentNode.removeChild(node); - delete appInfo.installNotification; - NotificationScreen.decExternalNotifications(); - }, - - requestWifiLock: function ai_requestWifiLock(app) { - var appInfo = this.appInfos[app.manifestURL]; - if (! appInfo.wifiLock) { - // we don't want 2 locks for the same app - appInfo.wifiLock = navigator.requestWakeLock('wifi'); - } - }, - - releaseWifiLock: function ai_releaseWifiLock(app) { - var appInfo = this.appInfos[app.manifestURL]; - - if (appInfo.wifiLock) { - try { - appInfo.wifiLock.unlock(); - } catch (e) { - // this can happen if the lock is already unlocked - console.error('error during unlock', e); - } - - delete appInfo.wifiLock; - } - }, - - dispatchResponse: function ai_dispatchResponse(id, type) { - var event = document.createEvent('CustomEvent'); - - event.initCustomEvent('mozContentEvent', true, true, { - id: id, - type: type - }); - - window.dispatchEvent(event); - }, - - humanizeSize: function ai_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]); - }, - - showInstallCancelDialog: function ai_showInstallCancelDialog(evt) { - if (evt) - evt.preventDefault(); - this.installCancelDialog.classList.add('visible'); - this.dialog.classList.remove('visible'); - }, - - hideInstallCancelDialog: function ai_hideInstallCancelDialog(evt) { - if (evt) - evt.preventDefault(); - this.dialog.classList.add('visible'); - this.installCancelDialog.classList.remove('visible'); - }, - - showDownloadCancelDialog: function ai_showDownloadCancelDialog(e) { - var currentNode = e.target; - - if (!currentNode.classList.contains('fake-notification')) { - // tapped outside of a notification - return; - } - - var manifestURL = currentNode.dataset.manifest, - app = Applications.getByManifestURL(manifestURL), - manifest = app.manifest || app.updateManifest, - dialog = this.downloadCancelDialog; - - var title = dialog.querySelector('h1'); - - title.textContent = navigator.mozL10n.get('stopDownloading', { - app: new ManifestHelper(manifest).name - }); - - dialog.classList.add('visible'); - dialog.dataset.manifest = manifestURL; - UtilityTray.hide(); - }, - - handleInstallCancel: function ai_handleInstallCancel() { - if (this.installCancelCallback) - this.installCancelCallback(); - this.installCancelCallback = null; - this.installCancelDialog.classList.remove('visible'); - }, - - handleConfirmDownloadCancel: function ai_handleConfirmDownloadCancel(e) { - e && e.preventDefault(); - var dialog = this.downloadCancelDialog, - manifestURL = dialog.dataset.manifest; - if (manifestURL) { - var app = Applications.getByManifestURL(manifestURL); - app && app.cancelDownload(); - } - - this.hideDownloadCancelDialog(); - }, - - handleCancelDownloadCancel: function ai_handleCancelDownloadCancel(e) { - e && e.preventDefault(); - this.hideDownloadCancelDialog(); - }, - - hideDownloadCancelDialog: function() { - var dialog = this.downloadCancelDialog; - dialog.classList.remove('visible'); - delete dialog.dataset.manifest; - } -}; - -AppInstallManager.init(); diff --git a/apps/system/js/applications.js b/apps/system/js/applications.js deleted file mode 100644 index f1e286f..0000000 --- a/apps/system/js/applications.js +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -// Application module handles the information of apps on behalf of other -// modules. - -var Applications = { - installedApps: {}, - ready: false, - init: function a_init() { - var self = this; - var apps = navigator.mozApps; - - var getAllApps = function getAllApps() { - navigator.mozApps.mgmt.getAll().onsuccess = function mozAppGotAll(evt) { - var apps = evt.target.result; - apps.forEach(function(app) { - self.installedApps[app.manifestURL] = app; - // TODO Followup for retrieving homescreen & comms app - }); - - self.ready = true; - self.fireApplicationReadyEvent(); - }; - }; - - // We need to wait for the chrome shell to let us know when it's ok to - // launch activities. This prevents race conditions. - // The event does not fire again when we reload System app in on - // B2G Desktop, so we save the information into sessionStorage. - if (window.sessionStorage.getItem('webapps-registry-ready')) { - getAllApps(); - } else { - window.addEventListener('mozChromeEvent', function mozAppReady(event) { - if (event.detail.type != 'webapps-registry-ready') - return; - - window.sessionStorage.setItem('webapps-registry-ready', 'yes'); - window.removeEventListener('mozChromeEvent', mozAppReady); - - getAllApps(); - }); - } - - apps.mgmt.oninstall = function a_install(evt) { - var newapp = evt.application; - self.installedApps[newapp.manifestURL] = newapp; - - self.fireApplicationInstallEvent(newapp); - }; - - apps.mgmt.onuninstall = function a_uninstall(evt) { - var deletedapp = evt.application; - delete self.installedApps[deletedapp.manifestURL]; - - self.fireApplicationUninstallEvent(deletedapp); - }; - }, - - getByManifestURL: function a_getByManifestURL(manifestURL) { - if (manifestURL in this.installedApps) { - return this.installedApps[manifestURL]; - } - - return null; - }, - - fireApplicationReadyEvent: function a_fireAppReadyEvent() { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('applicationready', - /* canBubble */ true, /* cancelable */ false, - { applications: this.installedApps }); - window.dispatchEvent(evt); - }, - - // We need to dispatch the following events because - // mozApps is not doing so right now. - // ref: https://bugzilla.mozilla.org/show_bug.cgi?id=731746 - - fireApplicationInstallEvent: function a_fireApplicationInstallEvent(app) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('applicationinstall', - /* canBubble */ true, /* cancelable */ false, - { application: app }); - window.dispatchEvent(evt); - }, - - fireApplicationUninstallEvent: function a_fireApplicationUninstallEvent(app) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('applicationuninstall', - /* canBubble */ true, /* cancelable */ false, - { application: app }); - window.dispatchEvent(evt); - } -}; - -Applications.init(); diff --git a/apps/system/js/attention_screen.js b/apps/system/js/attention_screen.js deleted file mode 100644 index c14dbe8..0000000 --- a/apps/system/js/attention_screen.js +++ /dev/null @@ -1,289 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - -var AttentionScreen = { - get mainScreen() { - delete this.mainScreen; - return this.mainScreen = document.getElementById('screen'); - }, - - get attentionScreen() { - delete this.attentionScreen; - return this.attentionScreen = document.getElementById('attention-screen'); - }, - - get bar() { - delete this.bar; - return this.bar = document.getElementById('attention-bar'); - }, - - isVisible: function as_isVisible() { - return this.attentionScreen.classList.contains('displayed'); - }, - - isFullyVisible: function as_isFullyVisible() { - return (this.isVisible() && - !this.mainScreen.classList.contains('active-statusbar')); - }, - - init: function as_init() { - window.addEventListener('mozbrowseropenwindow', this.open.bind(this), true); - window.addEventListener('mozbrowserclose', this.close.bind(this), true); - window.addEventListener('mozbrowsererror', this.close.bind(this), true); - window.addEventListener('keyboardchange', this.resize.bind(this), true); - window.addEventListener('keyboardhide', this.resize.bind(this), true); - - this.bar.addEventListener('click', this.show.bind(this)); - window.addEventListener('home', this.hide.bind(this)); - window.addEventListener('holdhome', this.hide.bind(this)); - window.addEventListener('appwillopen', this.hide.bind(this)); - }, - - resize: function as_resize(evt) { - if (evt.type == 'keyboardchange') { - if (!this.isFullyVisible()) - return; - - this.attentionScreen.style.height = - window.innerHeight - evt.detail.height + 'px'; - } else if (evt.type == 'keyboardhide') { - // We still need to reset the height property even when the attention - // screen is not fully visible, or it will overrides the height - // we defined with #attention-screen.status-mode - this.attentionScreen.style.height = ''; - } - }, - - // show the attention screen overlay with newly created frame - open: function as_open(evt) { - if (evt.detail.features != 'attention') - return; - - // stopPropagation means we are not allowing - // Popup Manager to handle this event - evt.stopPropagation(); - - // Canceling any full screen web content - if (document.mozFullScreen) - document.mozCancelFullScreen(); - - // Check if the app has the permission to open attention screens - var manifestURL = evt.target.getAttribute('mozapp'); - var app = Applications.getByManifestURL(manifestURL); - - if (!app || !this._hasAttentionPermission(app)) - return; - - // Hide sleep menu/list menu if it is shown now - ListMenu.hide(); - SleepMenu.hide(); - - // We want the user attention, so we need to turn the screen on - // if it's off. The lockscreen will grab the focus when we do that - // so we need to do it before adding the new iframe to the dom - if (!ScreenManager.screenEnabled) - ScreenManager.turnScreenOn(); - - var attentionFrame = evt.detail.frameElement; - attentionFrame.dataset.frameType = 'attention'; - attentionFrame.dataset.frameName = evt.detail.name; - attentionFrame.dataset.frameOrigin = evt.target.dataset.frameOrigin; - - // We would like to put the dialer call screen on top of all other - // attention screens by ensure it is the last iframe in the DOM tree - if (this._hasTelephonyPermission(app)) { - this.attentionScreen.appendChild(attentionFrame); - } else { - this.attentionScreen.insertBefore(attentionFrame, - this.bar.nextElementSibling); - } - - this._updateAttentionFrameVisibility(); - - // Make the overlay visible if we are not displayed yet. - // alternatively, if the newly appended frame is the visible frame - // and we are in the status bar mode, expend to full screen mode. - if (!this.isVisible()) { - this.attentionScreen.classList.add('displayed'); - this.mainScreen.classList.add('attention'); - this.dispatchEvent('attentionscreenshow', { - origin: attentionFrame.dataset.frameOrigin - }); - } else if (!this.isFullyVisible() && - this.attentionScreen.lastElementChild === attentionFrame) { - this.show(); - } - }, - - // Make sure visibililty state of all attention screens are set correctly - _updateAttentionFrameVisibility: function as_updateAtteFrameVisibility() { - var frames = this.attentionScreen.querySelectorAll('iframe'); - var i = frames.length - 1; - - // In case someone call this function w/o checking for frame first - if (i < 0) - return; - - // set the last one in the DOM to visible - // The setTimeout() and the closure is used to workaround - // https://bugzilla.mozilla.org/show_bug.cgi?id=810431 - setTimeout(function(frame) { - frame.setVisible(true); - frame.focus(); - }, 0, frames[i]); - - while (i--) { - // The setTimeout() and the closure is used to workaround - // https://bugzilla.mozilla.org/show_bug.cgi?id=810431 - setTimeout(function(frame) { - frame.setVisible(false); - frame.blur(); - }, 0, frames[i]); - } - }, - - // close the attention screen overlay - close: function as_close(evt) { - if (!'frameType' in evt.target.dataset || - evt.target.dataset.frameType !== 'attention' || - (evt.type === 'mozbrowsererror' && evt.detail.type !== 'fatal')) - return; - - // Remove the frame - var origin = evt.target.dataset.frameOrigin; - this.attentionScreen.removeChild(evt.target); - - // We've just removed the focused window leaving the system - // without any focused window, let's fix this. - window.focus(); - - // if there are other attention frames, - // we need to update the visibility and show() the overlay. - if (this.attentionScreen.querySelectorAll('iframe').length) { - this._updateAttentionFrameVisibility(); - - this.dispatchEvent('attentionscreenclose', { origin: origin }); - - if (!this.isFullyVisible()) - this.show(); - - return; - } - - // There is no iframes left; - // we should close the attention screen overlay. - - // If the the attention screen is closed during active-statusbar - // mode, we would need to leave that mode. - if (!this.isFullyVisible()) { - this.mainScreen.classList.remove('active-statusbar'); - this.attentionScreen.classList.remove('status-mode'); - this.dispatchEvent('status-inactive', - { origin: this.attentionScreen.lastElementChild.dataset.frameOrigin }); - } - - this.attentionScreen.classList.remove('displayed'); - this.mainScreen.classList.remove('attention'); - this.dispatchEvent('attentionscreenhide', { origin: origin }); - }, - - // expend the attention screen overlay to full screen - show: function as_show() { - // leaving "status-mode". - this.attentionScreen.classList.remove('status-mode'); - // there shouldn't be a transition from "status-mode" to "active-statusbar" - this.attentionScreen.style.transition = 'none'; - - var self = this; - setTimeout(function nextTick() { - self.attentionScreen.style.transition = ''; - - // leaving "active-statusbar" mode, - // with a transform: translateY() slide down transition. - self.mainScreen.classList.remove('active-statusbar'); - self.dispatchEvent('status-inactive', { - origin: self.attentionScreen.lastElementChild.dataset.frameOrigin - }); - }); - }, - - // shrink the attention screen overlay to status bar - // invoked when we get a "home" event - hide: function as_hide() { - if (!this.isFullyVisible()) - return; - - // entering "active-statusbar" mode, - // with a transform: translateY() slide up transition. - this.mainScreen.classList.add('active-statusbar'); - - // The only way to hide attention screen is the home/holdhome event. - // So we don't fire any origin information here. - // The expected behavior is restore homescreen visibility to 'true' - // in the Window Manager. - this.dispatchEvent('status-active'); - - var attentionScreen = this.attentionScreen; - attentionScreen.addEventListener('transitionend', function trWait() { - attentionScreen.removeEventListener('transitionend', trWait); - - // transition completed, entering "status-mode" (40px height iframe) - attentionScreen.classList.add('status-mode'); - }); - }, - - dispatchEvent: function as_dispatchEvent(name, detail) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent(name, true, true, detail); - window.dispatchEvent(evt); - }, - - // If an app with an active attention screen is switched to, - // we would need to cover it with it's attention screen. - // Invoked when displayedApp in Window Manager changes - // XXX should be replaced with a call that listens to appwillopen - // TBD: display the attention screen underneath other attention screens. - showForOrigin: function as_showForOrigin(origin) { - if (!this.isVisible() || this.isFullyVisible()) - return; - - var attentionFrame = this.attentionScreen.lastElementChild; - var frameOrigin = attentionFrame.dataset.frameOrigin; - if (origin === frameOrigin) { - this.show(); - } - }, - - getAttentionScreenOrigins: function as_getAttentionScreenOrigins() { - var attentionScreen = this.attentionScreen; - var frames = this.attentionScreen.querySelectorAll('iframe'); - var attentiveApps = []; - Array.prototype.forEach.call(frames, function pushFrame(frame) { - attentiveApps.push(frame.dataset.frameOrigin); - }); - return attentiveApps; - }, - - _hasAttentionPermission: function as_hasAttentionPermission(app) { - var mozPerms = navigator.mozPermissionSettings; - if (!mozPerms) - return false; - - var value = mozPerms.get('attention', app.manifestURL, app.origin, false); - - return (value === 'allow'); - }, - - _hasTelephonyPermission: function as_hasAttentionPermission(app) { - var mozPerms = navigator.mozPermissionSettings; - if (!mozPerms) - return false; - - var value = mozPerms.get('telephony', app.manifestURL, app.origin, false); - - return (value === 'allow'); - } -}; - -AttentionScreen.init(); diff --git a/apps/system/js/authentication_dialog.js b/apps/system/js/authentication_dialog.js deleted file mode 100644 index 3a893ee..0000000 --- a/apps/system/js/authentication_dialog.js +++ /dev/null @@ -1,178 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -// This module listens to mozbrowserusernameandpasswordrequired event. -// It's for http authentication only. -// XXX: ftp authentication will be implemented here but not supported yet. - -var AuthenticationDialog = { - // Used for element id access. - // e.g., 'authentication-dialog-alert-ok' - prefix: 'authentication-dialog-', - - // DOM - elements: {}, - - // Get all elements when inited. - getAllElements: function ad_getAllElements() { - var elementsID = [ - 'http-authentication', 'http-username-input', 'http-password-input', - 'http-authentication-message', 'http-authentication-ok', - 'http-authentication-cancel', 'title' - ]; - - var toCamelCase = function toCamelCase(str) { - return str.replace(/\-(.)/g, function replacer(str, p1) { - return p1.toUpperCase(); - }); - }; - - elementsID.forEach(function createElementRef(name) { - this.elements[toCamelCase(name)] = - document.getElementById(this.prefix + name); - }, this); - - this.screen = document.getElementById('screen'); - this.overlay = document.getElementById('dialog-overlay'); - }, - - // Save the events returned by - // mozbrowserusernameandpasswordrequired for later use. - // The events are stored according to webapp origin - // e.g., 'http://uitest.gaiamobile.org': evt - currentEvents: {}, - - init: function ad_init() { - // Get all elements initially. - this.getAllElements(); - var elements = this.elements; - - // Bind events - window.addEventListener('mozbrowserusernameandpasswordrequired', this); - window.addEventListener('appopen', this); - window.addEventListener('appwillclose', this); - window.addEventListener('appterminated', this); - window.addEventListener('resize', this); - window.addEventListener('keyboardchange', this); - window.addEventListener('keyboardhide', this); - - for (var id in elements) { - if (elements[id].tagName.toLowerCase() == 'button') { - elements[id].addEventListener('click', this); - } - } - }, - - // Default event handler - handleEvent: function ad_handleEvent(evt) { - var elements = this.elements; - switch (evt.type) { - case 'mozbrowserusernameandpasswordrequired': - if (evt.target.dataset.frameType != 'window') - return; - - evt.preventDefault(); - var origin = evt.target.dataset.frameOrigin; - this.currentEvents[origin] = evt; - - if (origin == WindowManager.getDisplayedApp()) - this.show(origin); - break; - - case 'click': - if (evt.currentTarget === elements.httpAuthenticationCancel) { - this.cancelHandler(); - } else { - this.confirmHandler(); - } - break; - - case 'appopen': - if (this.currentEvents[evt.detail.origin]) - this.show(evt.detail.origin); - break; - - case 'appwillclose': - // Do nothing if the app is closed at background. - if (evt.detail.origin !== this.currentOrigin) - return; - - // Reset currentOrigin - this.hide(); - break; - - case 'appterminated': - if (this.currentEvents[evt.detail.origin]) - delete this.currentEvents[evt.detail.origin]; - - break; - - case 'resize': - case 'keyboardhide': - if (!this.currentOrigin) - return; - - this.setHeight(window.innerHeight - StatusBar.height); - break; - - case 'keyboardchange': - this.setHeight(window.innerHeight - - evt.detail.height - StatusBar.height); - break; - } - }, - - setHeight: function ad_setHeight(height) { - if (this.isVisible()) - this.overlay.style.height = height + 'px'; - }, - - show: function ad_show(origin) { - this.currentOrigin = origin; - var evt = this.currentEvents[origin]; - var elements = this.elements; - this.screen.classList.add('authentication-dialog'); - elements.httpAuthentication.classList.add('visible'); - elements.title.textContent = evt.detail.host; - elements.httpAuthenticationMessage.textContent = evt.detail.realm; - elements.httpUsernameInput.value = ''; - elements.httpPasswordInput.value = ''; - - this.setHeight(window.innerHeight - StatusBar.height); - }, - - hide: function ad_hide() { - this.elements.httpUsernameInput.blur(); - this.elements.httpPasswordInput.blur(); - this.currentOrigin = null; - this.elements.httpAuthentication.classList.remove('visible'); - this.screen.classList.remove('authentication-dialog'); - }, - - confirmHandler: function ad_confirmHandler() { - var elements = this.elements; - var evt = this.currentEvents[this.currentOrigin]; - evt.detail.authenticate(elements.httpUsernameInput.value, - elements.httpPasswordInput.value); - elements.httpAuthentication.classList.remove('visible'); - delete this.currentEvents[this.currentOrigin]; - this.screen.classList.remove('authentication-dialog'); - }, - - cancelHandler: function ad_cancelHandler() { - var evt = this.currentEvents[this.currentOrigin]; - var elements = this.elements; - evt.detail.cancel(); - elements.httpAuthentication.classList.remove('visible'); - delete this.currentEvents[this.currentOrigin]; - this.screen.classList.remove('authentication-dialog'); - }, - - isVisible: function ad_isVisible() { - return this.screen.classList.contains('authentication-dialog'); - } -}; - -AuthenticationDialog.init(); diff --git a/apps/system/js/background_service.js b/apps/system/js/background_service.js deleted file mode 100644 index 117b556..0000000 --- a/apps/system/js/background_service.js +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -/* - Allow web apps to inject a tiny persistent background iframe - as the phone starts. -*/ -var BackgroundServiceManager = (function bsm() { - /* We keep the references to background page iframes here. - The iframes will be append to body */ - var frames = {}; - - /* The name of the background window open by background_page in - manifest. */ - var AUTO_OPEN_BG_PAGE_NAME = 'background'; - - /* Init */ - var init = function bsm_init() { - var applications = Applications.installedApps; - Object.keys(applications).forEach(function bsm_each(manifestURL) { - var app = applications[manifestURL]; - if (!app.manifest.background_page) - return; - - // XXX: this work as if background_page is always a path not a full URL. - var url = app.origin + app.manifest.background_page; - open(manifestURL, AUTO_OPEN_BG_PAGE_NAME, url); - }); - }; - - /* mozbrowseropenwindow */ - window.addEventListener('mozbrowseropenwindow', function bsm_winopen(evt) { - if (evt.detail.features !== 'background') - return; - - // stopPropagation means we are not allowing - // Popup Manager to handle this event - evt.stopPropagation(); - - var manifestURL = evt.target.getAttribute('mozapp'); - var detail = evt.detail; - - open(manifestURL, detail.name, detail.url, detail.frameElement); - }, true); - - /* mozbrowserclose */ - window.addEventListener('mozbrowserclose', function bsm_winclose(evt) { - if (!'frameType' in evt.target.dataset || - evt.target.dataset.frameType !== 'background') - return; - - var manifestURL = evt.target.getAttribute('mozapp'); - - close(manifestURL, evt.target.dataset.frameName); - }, true); - - /* mozbrowsererror */ - window.addEventListener('mozbrowsererror', function bsm_winclose(evt) { - if (!'frameType' in evt.target.dataset || - evt.target.dataset.frameType !== 'background' || - evt.detail.type !== 'fatal') - return; - - var target = evt.target; - var manifestURL = target.getAttribute('mozapp'); - - // This bg service has just crashed, clean up the frame - var name = target.dataset.frameName; - close(manifestURL, name); - }, true); - - /* OnInstall */ - window.addEventListener('applicationinstall', function bsm_oninstall(evt) { - var app = evt.detail.application; - var origin = app.origin; - if (!app.manifest.background_page) - return; - - // XXX: this work as if background_page is always a path not a full URL. - var url = origin + app.manifest.background_page; - open(manifestURL, AUTO_OPEN_BG_PAGE_NAME, url); - }); - - /* OnUninstall */ - window.addEventListener('applicationuninstall', function bsm_oninstall(evt) { - var app = evt.detail.application; - close(app.manifestURL); - }); - - /* Check if the app has the permission to open a background page */ - var hasBackgroundPermission = function bsm_checkPermssion(app) { - var mozPerms = navigator.mozPermissionSettings; - if (!mozPerms) - return false; - - var value = mozPerms.get('backgroundservice', app.manifestURL, - app.origin, false); - - return (value === 'allow'); - }; - - /* The open function is responsible of containing the iframe */ - var open = function bsm_open(manifestURL, name, url, frame) { - var app = Applications.getByManifestURL(manifestURL); - if (!app || !hasBackgroundPermission(app)) - return false; - - if (frames[manifestURL] && frames[manifestURL][name]) { - console.error('Window with the same name is there but Gecko ' + - ' failed to use it. See bug 766873. origin: "' + origin + - '", name: "' + name + '".'); - return false; - } - - if (!frame) { - frame = document.createElement('iframe'); - - // If we have a frame element, it's provided by mozbrowseropenwindow, and - // it has the mozbrowser, mozapp, and src attributes set already. - frame.setAttribute('mozbrowser', 'mozbrowser'); - frame.setAttribute('mozapp', manifestURL); - frame.setAttribute('name', name); - - var appName = app.manifest.name; - frame.setAttribute('remote', 'true'); - console.info('%%%%% Launching', appName, 'bg service as remote (OOP)'); - frame.src = url; - } - frame.className = 'backgroundWindow'; - frame.dataset.frameType = 'background'; - frame.dataset.frameName = name; - - if (!frames[manifestURL]) - frames[manifestURL] = {}; - frames[manifestURL][name] = frame; - - document.body.appendChild(frame); - - // Background services should load in the background. - // - // (The funky setTimeout(0) is to work around - // https://bugzilla.mozilla.org/show_bug.cgi?id=810431 .) - setTimeout(function() { frame.setVisible(false) }, 0); - - return true; - }; - - /* The close function will remove the iframe from DOM and - delete the reference */ - var close = function bsm_close(manifestURL, name) { - if (!frames[manifestURL]) - return false; - - if (typeof name == 'undefined') { - // Close all windows - Object.keys(frames[manifestURL]).forEach(function closeEach(name) { - document.body.removeChild(frames[manifestURL][name]); - frames[manifestURL][name] = null; - }); - delete frames[manifestURL]; - return true; - } - - // Close one window - var frame = frames[manifestURL][name]; - if (!frame) - return false; - - document.body.removeChild(frame); - delete frames[manifestURL][name]; - - if (!Object.keys(frames[manifestURL]).length) - delete frames[manifestURL]; - return true; - }; - - /* start initialization */ - if (Applications.ready) { - init(); - } else { - window.addEventListener('applicationready', - function bsm_appListReady(event) { - window.removeEventListener('applicationready', bsm_appListReady); - init(); - }); - } - - /* Return the public APIs */ - return { - 'open': open, - 'close': close - }; -}()); - diff --git a/apps/system/js/battery_manager.js b/apps/system/js/battery_manager.js deleted file mode 100644 index d2eacf8..0000000 --- a/apps/system/js/battery_manager.js +++ /dev/null @@ -1,277 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var BatteryManager = { - TOASTER_TIMEOUT: 5000, - TRANSITION_SPEED: 1.8, - TRANSITION_FRACTION: 0.30, - - AUTO_SHUTDOWN_LEVEL: 0.02, - EMPTY_BATTERY_LEVEL: 0.1, - - _battery: window.navigator.battery, - _notification: null, - - getAllElements: function bm_getAllElements() { - this.screen = document.getElementById('screen'); - this.overlay = document.getElementById('system-overlay'); - this.notification = document.getElementById('battery'); - }, - - checkBatteryDrainage: function bm_checkBatteryDrainage() { - var battery = this._battery; - if (!battery) - return; - - if (battery.level <= this.AUTO_SHUTDOWN_LEVEL) - SleepMenu.startPowerOff(false); - }, - - init: function bm_init() { - this.getAllElements(); - var battery = this._battery; - if (battery) { - // When the device is booted, check if the battery is drained. - // If so, SleepMenu.startPowerOff() would be called. - this.checkBatteryDrainage(); - - battery.addEventListener('levelchange', this); - battery.addEventListener('chargingchange', this); - } - window.addEventListener('screenchange', this); - this._toasterGD = new GestureDetector(this.notification); - ['mousedown', 'swipe'].forEach(function(evt) { - this.notification.addEventListener(evt, this); - }, this); - - this._screenOn = true; - this._wasEmptyBatteryNotificationDisplayed = false; - - this.displayIfNecessary(); - }, - - handleEvent: function bm_handleEvent(evt) { - switch (evt.type) { - case 'screenchange': - this._screenOn = evt.detail.screenEnabled; - this.displayIfNecessary(); - break; - - case 'levelchange': - var battery = this._battery; - if (!battery) - return; - - this.checkBatteryDrainage(); - this.displayIfNecessary(); - - PowerSaveHandler.onBatteryChange(); - break; - case 'chargingchange': - PowerSaveHandler.onBatteryChange(); - - var battery = this._battery; - // We turn the screen on if needed in order to let - // the user knows the device is charging - - if (battery && battery.charging) { - this.hide(); - this._wasEmptyBatteryNotificationDisplayed = false; - - if (!this._screenOn) { - ScreenManager.turnScreenOn(); - } - } else { - this.displayIfNecessary(); - } - break; - - case 'mousedown': - this.mousedown(evt); - break; - case 'swipe': - this.swipe(evt); - break; - } - }, - - _shouldWeDisplay: function bm_shouldWeDisplay() { - var battery = this._battery; - if (!battery) { - return false; - } - - return (!this._wasEmptyBatteryNotificationDisplayed && - !battery.charging && - battery.level <= this.EMPTY_BATTERY_LEVEL && - this._screenOn); - }, - - displayIfNecessary: function bm_display() { - if (! this._shouldWeDisplay()) { - return; - } - - // we know it's here, it's checked in shouldWeDisplay() - var level = this._battery.level; - - this.overlay.classList.add('battery'); - - this._toasterGD.startDetecting(); - this._wasEmptyBatteryNotificationDisplayed = true; - - if (this._toasterTimeout) { - clearTimeout(this._toasterTimeout); - } - - this._toasterTimeout = setTimeout(this.hide.bind(this), - this.TOASTER_TIMEOUT); - }, - - hide: function bm_hide() { - var overlayCss = this.overlay.classList; - if (overlayCss.contains('battery')) { - this.overlay.classList.remove('battery'); - this._toasterTimeout = null; - this._toasterGD.stopDetecting(); - } - }, - - // Swipe handling - mousedown: function bm_mousedown(evt) { - evt.preventDefault(); - this._containerWidth = this.overlay.clientWidth; - }, - - swipe: function bm_swipe(evt) { - var detail = evt.detail; - var distance = detail.start.screenX - detail.end.screenX; - var fastEnough = Math.abs(detail.vx) > this.TRANSITION_SPEED; - var farEnough = Math.abs(distance) > - this._containerWidth * this.TRANSITION_FRACTION; - - // If the swipe distance is too short or swipe speed is too slow, - // do nothing. - if (!(farEnough || fastEnough)) - return; - - var self = this; - this.notification.addEventListener('animationend', function animationend() { - self.notification.removeEventListener('animationend', animationend); - self.notification.classList.remove('disappearing'); - self.hide(); - }); - this.notification.classList.add('disappearing'); - } -}; - -var PowerSaveHandler = (function PowerSaveHandler() { - - var _powerSaveResume = {}; - var _powerSaveEnabled = false; - var _states = { - 'wifi.enabled' : false, - 'ril.data.enabled' : false, - 'bluetooth.enabled' : false, - 'geolocation.enabled' : false - }; - - function init() { - SettingsListener.observe('powersave.enabled', false, - function sl_getPowerSave(value) { - var enabled = value; - if (enabled) { - enablePowerSave(); - } else { - disablePowerSave(); - } - _powerSaveEnabled = enabled; - }); - - // Monitor the states of various modules - for (var j in _states) { - SettingsListener.observe(j, true, function getState(state, value) { - _states[state] = value; - }.bind(null, j)); - } - } - - // XXX Break down obj keys in a for each loop because mozSettings - // does not currently supports multiple keys in one set() - // https://bugzilla.mozilla.org/show_bug.cgi?id=779381 - function setMozSettings(keypairs) { - var setlock = SettingsListener.getSettingsLock(); - for (var key in keypairs) { - var obj = {}; - obj[key] = keypairs[key]; - setlock.set(obj); - } - } - - function enablePowerSave() { - // Keep the original states of various modules - for (var j in _states) { - _powerSaveResume[j] = _states[j]; - } - - var settingsToSet = { - // Turn off Wifi - 'wifi.enabled' : false, - // Turn off Data - 'ril.data.enabled' : false, - // Turn off Bluetooth - 'bluetooth.enabled' : false, - // Turn off Geolocation - 'geolocation.enabled' : false - }; - - setMozSettings(settingsToSet); - } - - function disablePowerSave() { - - var settingsToSet = {}; - - for (var state in _powerSaveResume) { - if (_powerSaveResume[state] == true) - settingsToSet[state] = true; - } - - setMozSettings(settingsToSet); - } - - function onBatteryChange() { - var battery = BatteryManager._battery; - - if (battery.charging) { - if (_powerSaveEnabled) - setMozSettings({'powersave.enabled' : false}); - - return; - } - - SettingsListener.observe('powersave.threshold', 0, - function getThreshold(value) { - if (battery.level <= value && !_powerSaveEnabled) { - setMozSettings({'powersave.enabled' : true}); - return; - } - - if (value != 0 && battery.level > value && _powerSaveEnabled) { - setMozSettings({'powersave.enabled' : false}); - return; - } - }); - } - - return { - init: init, - onBatteryChange: onBatteryChange - }; -})(); - -// init PowerSaveHandler first, since it will be used by BatteryManager -PowerSaveHandler.init(); -BatteryManager.init(); diff --git a/apps/system/js/bluetooth.js b/apps/system/js/bluetooth.js deleted file mode 100644 index 3a77cc7..0000000 --- a/apps/system/js/bluetooth.js +++ /dev/null @@ -1,136 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var Bluetooth = { - - /* this property store a reference of the default adapter */ - defaultAdapter: null, - - /* keep a global connected property here */ - connected: false, - - init: function bt_init() { - if (!window.navigator.mozSettings) - return; - - var bluetooth = window.navigator.mozBluetooth; - - SettingsListener.observe('bluetooth.enabled', true, function(value) { - if (!bluetooth) { - // roll back the setting value to notify the UIs - // that Bluetooth interface is not available - if (value) { - SettingsListener.getSettingsLock().set({ - 'bluetooth.enabled': false - }); - } - return; - } - }); - - var self = this; - // when bluetooth adapter is ready, emit event to notify QuickSettings - // and try to get defaultAdapter at this moment - bluetooth.onadapteradded = function bt_onAdapterAdded() { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('bluetooth-adapter-added', - /* canBubble */ true, /* cancelable */ false, null); - window.dispatchEvent(evt); - self.initDefaultAdapter(); - }; - // if bluetooth is enabled in booting time, try to get adapter now - this.initDefaultAdapter(); - - // when bluetooth is really disabled, emit event to notify QuickSettings - bluetooth.ondisabled = function bt_onDisabled() { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('bluetooth-disabled', - /* canBubble */ true, /* cancelable */ false, null); - window.dispatchEvent(evt); - }; - - /* for v1, we only support two use cases for bluetooth connection: - * 1. connecting with a headset - * 2. transfering a file to/from another device - * So we need to monitor their event messages to know we are (aren't) - * connected, then summarize to an event and dispatch to StatusBar - */ - - // In headset connected case: - navigator.mozSetMessageHandler('bluetooth-hfp-status-changed', - this.updateConnected.bind(this) - ); - - /* In file transfering case: - * since System Message can't be listened in two js files within a app, - * so we listen here but dispatch events to bluetooth_transfer.js - * when getting bluetooth file transfer start/complete system messages - */ - var self = this; - navigator.mozSetMessageHandler('bluetooth-opp-transfer-start', - function bt_fileTransferUpdate(transferInfo) { - self.updateConnected(); - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('bluetooth-opp-transfer-start', - /* canBubble */ true, /* cancelable */ false, - {transferInfo: transferInfo}); - window.dispatchEvent(evt); - } - ); - - navigator.mozSetMessageHandler('bluetooth-opp-transfer-complete', - function bt_fileTransferUpdate(transferInfo) { - self.updateConnected(); - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('bluetooth-opp-transfer-complete', - /* canBubble */ true, /* cancelable */ false, - {transferInfo: transferInfo}); - window.dispatchEvent(evt); - } - ); - - }, - - // Get adapter for BluetoothTransfer when everytime bluetooth is enabled - initDefaultAdapter: function bt_initDefaultAdapter() { - var bluetooth = window.navigator.mozBluetooth; - var self = this; - - if (!bluetooth || !bluetooth.enabled || - !('getDefaultAdapter' in bluetooth)) - return; - - var req = bluetooth.getDefaultAdapter(); - req.onsuccess = function bt_gotDefaultAdapter(evt) { - self.defaultAdapter = req.result; - }; - }, - - updateConnected: function bt_updateConnected() { - var bluetooth = window.navigator.mozBluetooth; - - if (!bluetooth || !('isConnected' in bluetooth)) - return; - - var wasConnected = this.connected; - this.connected = - bluetooth.isConnected(0x111E) || bluetooth.isConnected(0x1105); - - if (wasConnected !== this.connected) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('bluetoothconnectionchange', - /* canBubble */ true, /* cancelable */ false, - {deviceConnected: this.connected}); - window.dispatchEvent(evt); - } - }, - - // This function is called by external (BluetoothTransfer) for re-use adapter - getAdapter: function bt_getAdapter() { - return this.defaultAdapter; - } -}; - -Bluetooth.init(); diff --git a/apps/system/js/bluetooth_transfer.js b/apps/system/js/bluetooth_transfer.js deleted file mode 100644 index 47483f7..0000000 --- a/apps/system/js/bluetooth_transfer.js +++ /dev/null @@ -1,511 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - -var BluetoothTransfer = { - bannerContainer: null, - pairList: { - index: [] - }, - _deviceStorage: navigator.getDeviceStorage('sdcard'), - _debug: false, - - get transferStatusList() { - delete this.transferStatusList; - return this.transferStatusList = - document.getElementById('bluetooth-transfer-status-list'); - }, - - get banner() { - delete this.banner; - return this.banner = document.getElementById('system-banner'); - }, - - init: function bt_init() { - // Bind message handler for transferring file callback - navigator.mozSetMessageHandler('bluetooth-opp-receiving-file-confirmation', - this.onReceivingFileConfirmation.bind(this) - ); - - // Listen to 'bluetooth-opp-transfer-start' from bluetooth.js - window.addEventListener('bluetooth-opp-transfer-start', - this.onUpdateProgress.bind(this, 'start') - ); - - navigator.mozSetMessageHandler('bluetooth-opp-update-progress', - this.onUpdateProgress.bind(this, 'progress') - ); - - // Listen to 'bluetooth-opp-transfer-complete' from bluetooth.js - window.addEventListener('bluetooth-opp-transfer-complete', - this.onTransferComplete.bind(this) - ); - this.bannerContainer = this.banner.firstElementChild; - }, - - getDeviceName: function bt_getDeviceName(address) { - var _ = navigator.mozL10n.get; - var length = this.pairList.index.length; - for (var i = 0; i < length; i++) { - if (this.pairList.index[i].address == address) - return this.pairList.index[i].name; - } - return _('unknown-device'); - }, - - getPairedDevice: function bt_getPairedDevice(callback) { - var adapter = Bluetooth.getAdapter(); - if (adapter == null) { - var msg = 'Cannot get Bluetooth adapter.'; - this.debug(msg); - return; - } - var self = this; - var req = adapter.getPairedDevices(); - req.onsuccess = function bt_getPairedSuccess() { - self.pairList.index = req.result; - var length = self.pairList.index.length; - if (length == 0) { - var msg = - 'There is no paired device! Please pair your bluetooth device first.'; - self.debug(msg); - return; - } - if (callback) { - callback(); - } - }; - req.onerror = function() { - var msg = 'Can not get paired devices from adapter.'; - self.debug(msg); - }; - }, - - debug: function bt_debug(msg) { - if (!this._debug) - return; - - console.log('[System Bluetooth Transfer]: ' + msg); - }, - - humanizeSize: function bt_humanizeSize(bytes) { - var _ = navigator.mozL10n.get; - var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - var size, e; - if (bytes) { - e = Math.floor(Math.log(bytes) / Math.log(1024)); - size = (bytes / Math.pow(1024, e)).toFixed(2); - } else { - e = 0; - size = '0.00'; - } - return _('fileSize', { - size: size, - unit: _('byteUnit-' + units[e]) - }); - }, - - onReceivingFileConfirmation: function bt_onReceivingFileConfirmation(evt) { - // Prompt appears when a transfer request from a paired device is received. - var _ = navigator.mozL10n.get; - - var fileSize = evt.fileLength; - var self = this; - var icon = 'style/bluetooth_transfer/images/icon_bluetooth.png'; - - // Check storage is available or not before the prompt. - this.checkStorageSpace(fileSize, - function checkStorageSpaceComplete(isStorageAvailable, errorMessage) { - if (isStorageAvailable) { - NotificationHelper.send(_('notification-fileTransfer-title'), - _('notification-fileTransfer-description'), - icon, - function() { - UtilityTray.hide(); - self.showReceivePrompt(evt); - }); - } else { - self.showStorageUnavaliablePrompt(errorMessage); - } - }); - }, - - showReceivePrompt: function bt_showReceivePrompt(evt) { - var _ = navigator.mozL10n.get; - - var address = evt.address; - var fileName = evt.fileName; - var fileSize = this.humanizeSize(evt.fileLength); - var cancel = { - title: _('deny'), - callback: this.declineReceive.bind(this, address) - }; - - var confirm = { - title: _('transfer'), - callback: this.acceptReceive.bind(this, address) - }; - - var deviceName = ''; - var self = this; - this.getPairedDevice(function getPairedDeviceComplete() { - deviceName = self.getDeviceName(address); - CustomDialog.show(_('acceptFileTransfer'), - _('wantToReceiveFile', - { deviceName: deviceName, - fileName: fileName, - fileSize: fileSize }), - cancel, confirm); - }); - }, - - declineReceive: function bt_declineReceive(address) { - CustomDialog.hide(); - var adapter = Bluetooth.getAdapter(); - if (adapter != null) { - adapter.confirmReceivingFile(address, false); - } else { - var msg = 'Cannot get adapter from system Bluetooth monitor.'; - this.debug(msg); - } - }, - - acceptReceive: function bt_acceptReceive(address, fileSize) { - CustomDialog.hide(); - var adapter = Bluetooth.getAdapter(); - if (adapter != null) { - adapter.confirmReceivingFile(address, true); - } else { - var msg = 'Cannot get adapter from system Bluetooth monitor.'; - this.debug(msg); - } - }, - - showStorageUnavaliablePrompt: function bt_showStorageUnavaliablePrompt(msg) { - var _ = navigator.mozL10n.get; - var confirm = { - title: _('confirm'), - callback: function() { - CustomDialog.hide(); - } - }; - - var body = msg; - CustomDialog.show(_('cannotReceiveFile'), body, confirm); - }, - - checkStorageSpace: function bt_checkStorageSpace(fileSize, callback) { - if (!callback) - return; - - var _ = navigator.mozL10n.get; - var storage = this._deviceStorage; - - var availreq = storage.available(); - availreq.onsuccess = function(e) { - switch (availreq.result) { - case 'available': - // skip down to the code below - break; - case 'unavailable': - callback(false, _('sdcard-not-exist')); - return; - case 'shared': - callback(false, _('sdcard-in-use')); - return; - default: - callback(false, _('unknown-error')); - return; - } - - // If we get here, then the sdcard is available, so we need to find out - // if there is enough free space on it - var freereq = storage.freeSpace(); - freereq.onsuccess = function() { - if (freereq.result >= fileSize) - callback(true, ''); - else - callback(false, _('sdcard-no-space2')); - }; - freereq.onerror = function() { - callback(false, _('cannotGetStorageState')); - }; - }; - - availreq.onerror = function(e) { - callback(false, _('cannotGetStorageState')); - }; - }, - - onUpdateProgress: function bt_onUpdateProgress(mode, evt) { - switch (mode) { - case 'start': - var transferInfo = evt.detail.transferInfo; - this.initProgress(transferInfo); - break; - - case 'progress': - var address = evt.address; - var processedLength = evt.processedLength; - var fileLength = evt.fileLength; - var progress = 0; - if (fileLength == 0) { - //XXX: May need to handle unknow progress - } else if (processedLength > fileLength) { - // According Bluetooth spec., - // the processed length is a referenced value only. - // XXX: If processed length is bigger than file length, - // show an unknown progress - } else { - progress = processedLength / fileLength; - } - this.updateProgress(progress, evt); - break; - } - }, - - initProgress: function bt_initProgress(evt) { - var _ = navigator.mozL10n.get; - // Create progress dynamically in notification center - var address = evt.address; - var transferMode = - (evt.received == true) ? - _('bluetooth-receiving-progress') : _('bluetooth-sending-progress'); - var content = - '<img src="style/bluetooth_transfer/images/transfer.png" />' + - '<div class="bluetooth-transfer-progress">' + transferMode + '</div>' + - // XXX: Bug 804533 - [Bluetooth] - // Need sending/receiving icon for Bluetooth file transfer - '<progress value="0" max="1"></progress>'; - - var transferTask = document.createElement('div'); - transferTask.id = 'bluetooth-transfer-status'; - transferTask.className = 'notification'; - transferTask.setAttribute('data-id', address); - transferTask.innerHTML = content; - transferTask.addEventListener('click', - this.onCancelTransferTask.bind(this)); - this.transferStatusList.appendChild(transferTask); - }, - - updateProgress: function bt_updateProgress(value, evt) { - var address = evt.address; - var id = 'div[data-id="' + address + '"] progress'; - var progressEl = this.transferStatusList.querySelector(id); - progressEl.value = value; - }, - - removeProgress: function bt_removeProgress(evt) { - var address = evt.address; - var id = 'div[data-id="' + address + '"]'; - var finishedTask = this.transferStatusList.querySelector(id); - finishedTask.removeEventListener('click', - this.onCancelTransferTask.bind(this)); - this.transferStatusList.removeChild(finishedTask); - }, - - showBanner: function bt_showBanner(isComplete) { - var _ = navigator.mozL10n.get; - var status = (isComplete) ? 'complete' : 'failed'; - this.banner.addEventListener('animationend', function animationend() { - this.banner.removeEventListener('animationend', animationend); - this.banner.classList.remove('visible'); - }.bind(this)); - this.bannerContainer.textContent = _('bluetooth-file-transfer-result', - { status: status }); - this.banner.classList.add('visible'); - }, - - onCancelTransferTask: function bt_onCancelTransferTask(evt) { - var id = evt.target.dataset.id; - // Show confirm dialog for user to cancel transferring task - UtilityTray.hide(); - this.showCancelTransferPrompt(id); - }, - - showCancelTransferPrompt: function bt_showCancelTransferPrompt(address) { - var _ = navigator.mozL10n.get; - - var cancel = { - title: _('continue'), - callback: this.continueTransfer.bind(this) - }; - - var confirm = { - title: _('cancel'), - callback: this.cancelTransfer.bind(this, address) - }; - - CustomDialog.show(_('cancelFileTransfer'), _('cancelFileTransfer'), - cancel, confirm); - }, - - continueTransfer: function bt_continueTransfer() { - CustomDialog.hide(); - }, - - cancelTransfer: function bt_cancelTransfer(address) { - CustomDialog.hide(); - var adapter = Bluetooth.getAdapter(); - if (adapter != null) { - adapter.stopSendingFile(address); - } else { - var msg = 'Cannot get adapter from system Bluetooth monitor.'; - this.debug(msg); - } - }, - - onTransferComplete: function bt_onTransferComplete(evt) { - var transferInfo = evt.detail.transferInfo; - var _ = navigator.mozL10n.get; - // Remove transferring progress - this.removeProgress(transferInfo); - var fileName = - (transferInfo.fileName) ? transferInfo.fileName : _('unknown-file'); - var icon = 'style/bluetooth_transfer/images/icon_bluetooth.png'; - // Show banner and notification - if (transferInfo.success == true) { - // Show completed message of transferred result on the banner - this.showBanner(true); - if (transferInfo.received) { - // Received file can be opened only - // TODO: Need to modify the icon after visual provide - NotificationHelper.send(_('transferFinished-receivedSuccessful-title'), - fileName, - icon, - this.openReceivedFile.bind(this, transferInfo)); - } else { - NotificationHelper.send(_('transferFinished-sentSuccessful-title'), - fileName, - icon); - } - } else { - // Show failed message of transferred result on the banner - this.showBanner(false); - if (transferInfo.received) { - NotificationHelper.send(_('transferFinished-receivedFailed-title'), - fileName, - icon); - } else { - NotificationHelper.send(_('transferFinished-sentFailed-title'), - fileName, - icon); - } - } - }, - - openReceivedFile: function bt_openReceivedFile(evt) { - // Launch the gallery with an open activity to view this specific photo - // XXX: The prefix file path should be refined when API is ready to provide - var filePath = 'downloads/bluetooth/' + evt.fileName; - var contentType = evt.contentType; - var storageType = 'sdcard'; - var self = this; - var storage = navigator.getDeviceStorage(storageType); - var getreq = storage.get(filePath); - - getreq.onerror = function() { - var msg = 'failed to get file:' + - filePath + getreq.error.name + - a.error.name; - self.debug(msg); - }; - - getreq.onsuccess = function() { - var file = getreq.result; - // When we got the file by storage type of "sdcard" - // use the file.type to replace the empty fileType which is given by API - var fileType = ''; - var fileName = file.name; - if (contentType != '' && contentType != 'image/*') { - fileType = contentType; - } else { - var fileNameExtension = - fileName.substring(fileName.lastIndexOf('.') + 1); - if (file.type != '') { - fileType = file.type; - // Refine the file type to "audio/ogg" when the file format is *.ogg - if (fileType == 'video/ogg' && - (fileNameExtension.indexOf('ogg') != -1)) { - fileType == 'audio/ogg'; - } - } else { - // Parse Filename Extension to find out MIMETYPE - // Following formats are supported by Gallery and Music APPs - var imageFormatList = ['jpg', 'jpeg', 'png']; - var audioFormatList = ['mp3', 'ogg', 'aac', 'mp4', 'm4a']; - var imageFormatIndex = imageFormatList.indexOf(fileNameExtension); - switch (imageFormatIndex) { - case 0: - case 1: - // The file type of format *.jpg, *.jpeg should be "image/jpeg" - fileType = 'image/jpeg'; - break; - case 2: - // The file type of format *.png should be "image/png" - fileType = 'image/png'; - break; - } - - var audioFormatIndex = audioFormatList.indexOf(fileNameExtension); - switch (audioFormatIndex) { - case 0: - // The file type of format *.mp3 should be "audio/mpeg" - fileType = 'audio/mpeg'; - break; - case 1: - // The file type of format *.ogg should be "audio/ogg" - fileType = 'audio/ogg'; - break; - case 2: - case 3: - case 4: - // The file type of format *.acc, *.mp4, *.m4a - // should be "audio/mp4" - fileType = 'audio/mp4'; - break; - } - } - } - - var a = new MozActivity({ - name: 'open', - data: { - type: fileType, - blob: file, - // XXX: https://bugzilla.mozilla.org/show_bug.cgi?id=812098 - // Pass the file name for Music APP since it can not open blob - filename: file.name - } - }); - - a.onerror = function(e) { - var msg = 'open activity error:' + a.error.name; - self.debug(msg); - // Cannot identify MIMETYPE - // So, show cannot open file dialog with unknow media type - UtilityTray.hide(); - self.showUnknownMediaPrompt(fileName); - }; - a.onsuccess = function(e) { - var msg = 'open activity onsuccess'; - self.debug(msg); - }; - }; - }, - - showUnknownMediaPrompt: function bt_showUnknownMediaPrompt(fileName) { - var _ = navigator.mozL10n.get; - var confirm = { - title: _('confirm'), - callback: function() { - CustomDialog.hide(); - } - }; - - var body = _('unknownMediaTypeToOpen') + ' ' + fileName; - CustomDialog.show(_('cannotOpenFile'), body, confirm); - } -}; - -BluetoothTransfer.init(); diff --git a/apps/system/js/bootstrap.js b/apps/system/js/bootstrap.js deleted file mode 100644 index 21e2238..0000000 --- a/apps/system/js/bootstrap.js +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -window.addEventListener('load', function startup() { - function safelyLaunchFTU() { - WindowManager.retrieveHomescreen(WindowManager.retrieveFTU); - } - - if (Applications.ready) { - safelyLaunchFTU(); - } else { - window.addEventListener('applicationready', function appListReady(event) { - window.removeEventListener('applicationready', appListReady); - safelyLaunchFTU(); - }); - } - - window.addEventListener('ftudone', function doneWithFTU() { - window.removeEventListener('ftudone', doneWithFTU); - - var lock = window.navigator.mozSettings.createLock(); - lock.set({ - 'gaia.system.checkForUpdates': true - }); - }); - - SourceView.init(); - Shortcuts.init(); - ScreenManager.turnScreenOn(); - - // We need to be sure to get the focus in order to wake up the screen - // if the phone goes to sleep before any user interaction. - // Apparently it works because no other window has the focus at this point. - window.focus(); - - // This is code copied from - // http://dl.dropbox.com/u/8727858/physical-events/index.html - // It appears to workaround the Nexus S bug where we're not - // getting orientation data. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=753245 - // It seems it needs to be in both window_manager.js and bootstrap.js. - function dumbListener2(event) {} - window.addEventListener('devicemotion', dumbListener2); - - window.setTimeout(function() { - window.removeEventListener('devicemotion', dumbListener2); - }, 2000); -}); - -/* === Shortcuts === */ -/* For hardware key handling that doesn't belong to anywhere */ -var Shortcuts = { - init: function rm_init() { - window.addEventListener('keyup', this); - }, - - handleEvent: function rm_handleEvent(evt) { - if (!ScreenManager.screenEnabled || evt.keyCode !== evt.DOM_VK_F6) - return; - - document.location.reload(); - } -}; - -/* === Localization === */ -/* set the 'lang' and 'dir' attributes to <html> when the page is translated */ -window.addEventListener('localized', function onlocalized() { - document.documentElement.lang = navigator.mozL10n.language.code; - document.documentElement.dir = navigator.mozL10n.language.direction; -}); - -// Define the default background to use for all homescreens -SettingsListener.observe( - 'wallpaper.image', - 'resources/images/backgrounds/default.png', - function setWallpaper(value) { - document.getElementById('screen').style.backgroundImage = - 'url(' + value + ')'; - } -); diff --git a/apps/system/js/call_forwarding.js b/apps/system/js/call_forwarding.js deleted file mode 100644 index ee46def..0000000 --- a/apps/system/js/call_forwarding.js +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -(function() { - - // Must be in sync with nsIDOMMozMobileCFInfo interface. - var _cfReason = { - CALL_FORWARD_REASON_UNCONDITIONAL: 0, - CALL_FORWARD_REASON_MOBILE_BUSY: 1, - CALL_FORWARD_REASON_NO_REPLY: 2, - CALL_FORWARD_REASON_NOT_REACHABLE: 3 - }; - var _cfAction = { - CALL_FORWARD_ACTION_DISABLE: 0, - CALL_FORWARD_ACTION_ENABLE: 1, - CALL_FORWARD_ACTION_QUERY_STATUS: 2, - CALL_FORWARD_ACTION_REGISTRATION: 3, - CALL_FORWARD_ACTION_ERASURE: 4 - }; - - var settings = window.navigator.mozSettings; - if (!settings) { - return; - } - var mobileconnection = window.navigator.mozMobileConnection; - if (!mobileconnection) { - return; - } - - mobileconnection.addEventListener('cfstatechange', function(event) { - if (event && - event.reason == _cfReason.CALL_FORWARD_REASON_UNCONDITIONAL) { - var enabled = false; - if (event.success && - (event.action == _cfAction.CALL_FORWARD_ACTION_REGISTRATION || - event.action == _cfAction.CALL_FORWARD_ACTION_ENABLE)) { - enabled = true; - } - settings.createLock().set({'ril.cf.enabled': enabled}); - } - }); - -})(); diff --git a/apps/system/js/captive_portal.js b/apps/system/js/captive_portal.js deleted file mode 100644 index b23cb0d..0000000 --- a/apps/system/js/captive_portal.js +++ /dev/null @@ -1,73 +0,0 @@ -/* -*Mode: js; js-indent-level: 2; indent-tabs-mode: nil -**/ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - -var CaptivePortalLogin = (function() { - var eventId; - var isManualConnect = false; - var settings = window.navigator.mozSettings; - var notification = null; - var wifiManager = window.navigator.mozWifiManager; - var _ = window.navigator.mozL10n.get; - var captiveNotification_onTap = null; - - function handleLogin(id, url) { - //captive portal login needed - eventId = id; - var currentNetwork = wifiManager.connection.network; - var networkName = (currentNetwork && currentNetwork.ssid) ? - currentNetwork.ssid : ''; - var message = _('captive-wifi-available', { networkName: networkName}); - if (!isManualConnect) { - notification = NotificationScreen.addNotification({ - id: id, title: '', text: message, icon: null - }); - captiveNotification_onTap = function() { - notification.removeEventListener('tap', captiveNotification_onTap); - captiveNotification_onTap = null; - NotificationScreen.removeNotification(id); - new MozActivity({ - name: 'view', - data: { type: 'url', url: url } - }); - }; - notification.addEventListener('tap', captiveNotification_onTap); - } else { - settings.createLock().set({'wifi.connect_via_settings': false}); - new MozActivity({ - name: 'view', - data: { type: 'url', url: url } - }); - } - } - - function handleLoginAbort(id) { - if (id === eventId && notification) { - if (notification.parentNode) { - if (captiveNotification_onTap) { - notification.removeEventListener('tap', captiveNotification_onTap); - captiveNotification_onTap = null; - } - NotificationScreen.removeNotification(id); - notification = null; - } - } - } - - window.addEventListener('mozChromeEvent', function handleChromeEvent(e) { - switch (e.detail.type) { - case 'captive-portal-login': - handleLogin(e.detail.id, e.detail.url); - break; - case 'captive-portal-login-abort': - handleLoginAbort(e.detail.id); - break; - } - }); - - // Using settings API to know whether user is manually selecting - // wifi AP from settings app. - SettingsListener.observe('wifi.connect_via_settings', true, function(value) { - isManualConnect = value; - }); -})(); diff --git a/apps/system/js/cards_view.js b/apps/system/js/cards_view.js deleted file mode 100644 index 8bce02b..0000000 --- a/apps/system/js/cards_view.js +++ /dev/null @@ -1,676 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -// -// CardsView is responsible for managing opened apps -// - -'use strict'; - -var CardsView = (function() { - - //display icon of an app on top of app's card - var DISPLAY_APP_ICON = false; - var USER_DEFINED_ORDERING = false; - // If 'true', scrolling moves the list one card - // at time, and snaps the list so the current card - // is centered in the view - // If 'false', use free, physics-based scrolling - // (Gaia default) - var SNAPPING_SCROLLING = true; - // if 'true' user can close the app - // by dragging it upwards - var MANUAL_CLOSING = true; - - var cardsView = document.getElementById('cards-view'); - var screenElement = document.getElementById('screen'); - var cardsList = cardsView.firstElementChild; - var displayedApp; - var runningApps; - // Unkillable apps which have attention screen now - var attentionScreenApps = []; - // Card which we are re-ordering now - var reorderedCard = null; - var currentDisplayed = 0; - // Timer between scrolling CardList further, - // when reordering Cards - var scrollWhileSortingTimer; - // We don't allow user to scroll CardList - // before the timer ticks while in reordering - // mode - var allowScrollingWhileSorting = false; - // Initial margin of the reordered card - var dragMargin = 0; - // Are we reordering or removing the card now? - var draggingCardUp = false; - // Are we moving card left or right? - var sortingDirection; - // List of sorted apps - var userSortedApps = []; - var HVGA = document.documentElement.clientWidth < 480; - var cardsViewShown = false; - - // init events - var gd = new GestureDetector(cardsView); - gd.startDetecting(); - - // A list of all the URLs we've created via URL.createObjectURL which we - // haven't yet revoked. - var screenshotObjectURLs = []; - - /* - * Returns an icon URI - * - * @param{String} the app's origin - */ - function getIconURI(origin) { - var icons = runningApps[origin].manifest.icons; - if (!icons) { - return null; - } - - var sizes = Object.keys(icons).map(function parse(str) { - return parseInt(str, 10); - }); - - sizes.sort(function(x, y) { return y - x; }); - - var index = sizes[(HVGA) ? sizes.length - 1 : 0]; - var iconPath = icons[index]; - - if (iconPath.indexOf('data:') !== 0) { - iconPath = origin + iconPath; - } - - return iconPath; - } - - // Build and display the card switcher overlay - // Note that we rebuild the switcher each time we need it rather - // than trying to keep it in sync with app launches. Performance is - // not an issue here given that the user has to hold the HOME button down - // for one second before the switcher will appear. - function showCardSwitcher() { - if (cardSwitcherIsShown()) - return; - - // events to handle - window.addEventListener('lock', CardsView); - - // Close utility tray if it is opened. - UtilityTray.hide(true); - - // Apps info from WindowManager - displayedApp = WindowManager.getDisplayedApp(); - currentDisplayed = 0; - runningApps = WindowManager.getRunningApps(); - - // Switch to homescreen - WindowManager.launch(null); - cardsViewShown = true; - - // If user is not able to sort apps manualy, - // display most recetly active apps on the far left - if (!USER_DEFINED_ORDERING) { - var sortable = []; - for (var origin in runningApps) - sortable.push({origin: origin, app: runningApps[origin]}); - - sortable.sort(function(a, b) { - return b.app.launchTime - a.app.launchTime; - }); - runningApps = {}; - - // I assume that object properties are enumerated in - // the same order they were defined. - // There is nothing about that in spec, but I've never - // seen any unexpected behavior. - sortable.forEach(function(element) { - runningApps[element.origin] = element.app; - }); - - // First add an item to the cardsList for each running app - for (var origin in runningApps) { - addCard(origin, runningApps[origin], function showCards() { - screenElement.classList.add('cards-view'); - cardsView.classList.add('active'); - }); - } - - } else { // user ordering - - // first run - if (userSortedApps.length === 0) { - for (var origin in runningApps) { - userSortedApps.push(origin); - } - } else { - for (var origin in runningApps) { - // if we have some new app opened - if (userSortedApps.indexOf(origin) === -1) { - userSortedApps.push(origin); - } - } - } - - userSortedApps.forEach(function(origin) { - addCard(origin, runningApps[origin], function showCards() { - screenElement.classList.add('cards-view'); - cardsView.classList.add('active'); - }); - }); - - cardsView.addEventListener('contextmenu', CardsView); - - } - - if (SNAPPING_SCROLLING) { - cardsView.style.overflow = 'hidden'; //disabling native scrolling - } - - if (SNAPPING_SCROLLING || MANUAL_CLOSING) { - cardsView.addEventListener('mousedown', CardsView); - } - - // Make sure we're in portrait mode - screen.mozLockOrientation('portrait-primary'); - - // If there is a displayed app, take keyboard focus away - if (displayedApp) - runningApps[displayedApp].frame.blur(); - - function addCard(origin, app, displayedAppCallback) { - // Display card switcher background first to make user focus on the - // frame closing animation without disturbing by homescreen display. - if (displayedApp == origin && displayedAppCallback) { - setTimeout(displayedAppCallback); - } - // Not showing homescreen - if (app.frame.classList.contains('homescreen')) { - return; - } - - // Build a card representation of each window. - // And add it to the card switcher - var card = document.createElement('li'); - card.classList.add('card'); - card.dataset.origin = origin; - - //display app icon on the tab - if (DISPLAY_APP_ICON) { - var iconURI = getIconURI(origin); - if (iconURI) { - var appIcon = document.createElement('img'); - appIcon.classList.add('appIcon'); - appIcon.src = iconURI; - card.appendChild(appIcon); - } - } - - var title = document.createElement('h1'); - title.textContent = app.name; - card.appendChild(title); - - var frameForScreenshot = app.iframe; - - if (PopupManager.getPopupFromOrigin(origin)) { - var popupFrame = PopupManager.getPopupFromOrigin(origin); - frameForScreenshot = popupFrame; - - var subtitle = document.createElement('p'); - subtitle.textContent = - PopupManager.getOpenedOriginFromOpener(origin); - card.appendChild(subtitle); - card.classList.add('popup'); - } else if (getOffOrigin(app.frame.dataset.url ? - app.frame.dataset.url : app.frame.src, origin)) { - var subtitle = document.createElement('p'); - subtitle.textContent = getOffOrigin(app.frame.dataset.url ? - app.frame.dataset.url : app.frame.src, origin); - card.appendChild(subtitle); - } - - if (TrustedUIManager.hasTrustedUI(origin)) { - var popupFrame = TrustedUIManager.getDialogFromOrigin(origin); - frameForScreenshot = popupFrame.frame; - var header = document.createElement('section'); - header.setAttribute('role', 'region'); - header.classList.add('skin-organic'); - header.innerHTML = '<header><button><span class="icon icon-close">'; - header.innerHTML += '</span></button><h1>' + popupFrame.name; - header.innerHTML += '</h1></header>'; - card.appendChild(header); - card.classList.add('trustedui'); - } else if (attentionScreenApps.indexOf(origin) == -1) { - var closeButton = document.createElement('div'); - closeButton.classList.add('close-card'); - card.appendChild(closeButton); - } - - cardsList.appendChild(card); - // rect is the final size (considering CSS transform) of the card. - var rect = card.getBoundingClientRect(); - - // And then switch it with screenshots when one will be ready - // (instead of -moz-element backgrounds) - frameForScreenshot.getScreenshot(rect.width, rect.height).onsuccess = - function gotScreenshot(screenshot) { - if (screenshot.target.result) { - var objectURL = URL.createObjectURL(screenshot.target.result); - screenshotObjectURLs.push(objectURL); - card.style.backgroundImage = 'url(' + objectURL + ')'; - } - }; - - // Set up event handling - // A click elsewhere in the card switches to that task - card.addEventListener('tap', runApp); - } - } - - function runApp(e) { - // Handle close events - if (e.target.classList.contains('close-card')) { - var element = e.target.parentNode; - cardsList.removeChild(element); - closeApp(element, true); - return; - } - - var origin = this.dataset.origin; - alignCard(currentDisplayed, function cardAligned() { - WindowManager.launch(origin); - }); - } - - function closeApp(element, removeImmediately) { - // Stop the app itself - WindowManager.kill(element.dataset.origin); - - // Fix for non selectable cards when we remove the last card - // Described in https://bugzilla.mozilla.org/show_bug.cgi?id=825293 - if (cardsList.children.length === currentDisplayed) { - currentDisplayed--; - } - - // If there are no cards left, then dismiss the task switcher. - if (!cardsList.children.length) - hideCardSwitcher(removeImmediately); - } - - function getOriginObject(url) { - var parser = document.createElement('a'); - parser.href = url; - - return { - protocol: parser.protocol, - hostname: parser.hostname, - port: parser.port - }; - } - - function getOffOrigin(src, origin) { - // Use src and origin as cache key - var cacheKey = JSON.stringify(Array.prototype.slice.call(arguments)); - if (!getOffOrigin.cache[cacheKey]) { - var native = getOriginObject(origin); - var current = getOriginObject(src); - if (current.protocol == 'http:') { - // Display http:// protocol anyway - getOffOrigin.cache[cacheKey] = current.protocol + '//' + - current.hostname; - } else if (native.protocol == current.protocol && - native.hostname == current.hostname && - native.port == current.port) { - // Same origin policy - getOffOrigin.cache[cacheKey] = ''; - } else if (current.protocol == 'app:') { - // Avoid displaying app:// protocol - getOffOrigin.cache[cacheKey] = ''; - } else { - getOffOrigin.cache[cacheKey] = current.protocol + '//' + - current.hostname; - } - } - - return getOffOrigin.cache[cacheKey]; - } - - getOffOrigin.cache = {}; - - function hideCardSwitcher(removeImmediately) { - if (!cardSwitcherIsShown()) - return; - - // events to handle - window.removeEventListener('lock', CardsView); - - // Make the cardsView overlay inactive - cardsView.classList.remove('active'); - cardsViewShown = false; - - // Release our screenshot blobs. - screenshotObjectURLs.forEach(function(url) { - URL.revokeObjectURL(url); - }); - screenshotObjectURLs = []; - - // And remove all the cards from the document after the transition - function removeCards() { - cardsView.removeEventListener('transitionend', removeCards); - screenElement.classList.remove('cards-view'); - - while (cardsList.firstElementChild) { - cardsList.removeChild(cardsList.firstElementChild); - } - } - if (removeImmediately) { - removeCards(); - } else { - cardsView.addEventListener('transitionend', removeCards); - } - } - - function cardSwitcherIsShown() { - return cardsViewShown; - } - - //scrolling cards - var initialCardViewPosition; - var initialTouchPosition = {}; - var threshold = window.innerWidth / 4; - // Distance after which dragged card starts moving - var moveCardThreshold = window.innerHeight / 6; - var removeCardThreshold = window.innerHeight / 4; - - function alignCard(number, callback) { - if (!cardsList.children[number]) - return; - - var scrollLeft = cardsView.scrollLeft; - var targetScrollLeft = cardsList.children[number].offsetLeft; - - if (Math.abs(scrollLeft - targetScrollLeft) < 4) { - cardsView.scrollLeft = cardsList.children[number].offsetLeft; - if (callback) - callback(); - return; - } - - cardsView.scrollLeft = scrollLeft + (targetScrollLeft - scrollLeft) / 2; - - window.mozRequestAnimationFrame(function newFrameCallback() { - alignCard(number, callback); - }); - } - - function onStartEvent(evt) { - evt.stopPropagation(); - evt.target.setCapture(true); - cardsView.addEventListener('mousemove', CardsView); - cardsView.addEventListener('swipe', CardsView); - - initialCardViewPosition = cardsView.scrollLeft; - initialTouchPosition = { - x: evt.touches ? evt.touches[0].pageX : evt.pageX, - y: evt.touches ? evt.touches[0].pageY : evt.pageY - }; - } - - function onMoveEvent(evt) { - evt.stopPropagation(); - var touchPosition = { - x: evt.touches ? evt.touches[0].pageX : evt.pageX, - y: evt.touches ? evt.touches[0].pageY : evt.pageY - }; - - if (evt.target.classList.contains('card') && MANUAL_CLOSING) { - var differenceY = initialTouchPosition.y - touchPosition.y; - if (differenceY > moveCardThreshold) { - // We don't want user to scroll the CardsView when one of the card is - // already dragger upwards - draggingCardUp = true; - evt.target.style.MozTransform = 'scale(0.6) translate(0, -' + - differenceY + 'px)'; - } - } - - // If we are not reordering or removing Cards now - // and Snapping Scrolling is enabled, we want to scroll - // the CardList - if (SNAPPING_SCROLLING && reorderedCard === null && !draggingCardUp) { - var differenceX = initialTouchPosition.x - touchPosition.x; - cardsView.scrollLeft = initialCardViewPosition + differenceX; - } - - // If re are in reordering mode (there is a DOM element in) - // reorderedCard variable) we are able to put this element somewere - // among the others - if (USER_DEFINED_ORDERING && reorderedCard !== null) { - var differenceX = touchPosition.x - initialTouchPosition.x; - // Probably there is more clever solution for calculating - // position of transformed DOM element, but this was my - // first thought and it seems to work - var moveOffset = (cardsList.children[currentDisplayed].offsetLeft / 0.6) + - differenceX - (dragMargin / 0.6); - - reorderedCard.style.MozTransform = - 'scale(0.6) translate(' + moveOffset + 'px, 0)'; - - if (Math.abs(differenceX) > threshold) { - // We don't want to jump to the next page immediately, - // We are waiting half a second for user to decide if - // he wants to leave the Card here or scroll further - if (allowScrollingWhileSorting) { - allowScrollingWhileSorting = false; - - scrollWhileSortingTimer = setTimeout(function() { - allowScrollingWhileSorting = true; - }, 500); - - if (differenceX > 0 && - currentDisplayed <= cardsList.children.length) { - currentDisplayed++; - sortingDirection = 'right'; - alignCard(currentDisplayed); - } else if (differenceX < 0 && currentDisplayed > 0) { - currentDisplayed--; - sortingDirection = 'left'; - alignCard(currentDisplayed); - } - } - } - } - } - - function onEndEvent(evt) { - evt.stopPropagation(); - var element = evt.target; - var eventDetail = evt.detail; - var direction = eventDetail.direction; - - document.releaseCapture(); - cardsView.removeEventListener('mousemove', CardsView); - cardsView.removeEventListener('swipe', CardsView); - - var touchPosition = { - x: eventDetail.end.pageX, - y: eventDetail.end.pageY - }; - - if (SNAPPING_SCROLLING && !draggingCardUp && reorderedCard === null) { - if (Math.abs(eventDetail.dx) > threshold) { - if ( - direction === 'left' && - currentDisplayed < cardsList.children.length - 1 - ) { - currentDisplayed++; - alignCard(currentDisplayed); - } else if (direction === 'right' && currentDisplayed > 0) { - currentDisplayed--; - alignCard(currentDisplayed); - } - } else { - alignCard(currentDisplayed); - } - } - - // if the element we start dragging on - // is a card and we are not in reordering mode - if ( - element.classList.contains('card') && - MANUAL_CLOSING && - reorderedCard === null - ) { - - draggingCardUp = false; - // Prevent user from closing the app with a attention screen - if (-eventDetail.dy > removeCardThreshold && - attentionScreenApps.indexOf(element.dataset.origin) == -1 - ) { - - // remove the app also from the ordering list - if ( - userSortedApps.indexOf(element.dataset.origin) !== -1 && - USER_DEFINED_ORDERING - ) { - userSortedApps.splice( - userSortedApps.indexOf(element.dataset.origin), - 1 - ); - } - - // Without removing the listener before closing card - // sometimes the 'click' event fires, even if 'mouseup' - // uses stopPropagation() - element.removeEventListener('tap', runApp); - - // Remove the icon from the task list - cardsList.removeChild(element); - - closeApp(element); - - return; - } else { - element.style.MozTransform = ''; - } - } - - if (USER_DEFINED_ORDERING && reorderedCard !== null) { - // Position of the card depends on direction of scrolling - if (sortingDirection === 'right') { - if (currentDisplayed <= cardsList.children.length) { - cardsList.insertBefore( - reorderedCard, - cardsList.children[currentDisplayed + 1] - ); - } else { - cardsList.appendChild(reorderedCard); - } - } else if (sortingDirection === 'left') { - cardsList.insertBefore( - reorderedCard, - cardsList.children[currentDisplayed] - ); - } - reorderedCard.style.MozTransform = ''; - reorderedCard.dataset['edit'] = 'false'; - reorderedCard = null; - - alignCard(currentDisplayed); - - // remove the app origin from ordering array - userSortedApps.splice( - userSortedApps.indexOf(element.dataset.origin), - 1 - ); - // and put in on the new position - userSortedApps.splice(currentDisplayed, 0, element.dataset.origin); - } - } - - function manualOrderStart(evt) { - evt.preventDefault(); - reorderedCard = evt.target; - allowScrollingWhileSorting = true; - if (reorderedCard.classList.contains('card')) { - dragMargin = reorderedCard.offsetLeft; - reorderedCard.dataset['edit'] = true; - sortingDirection = 'left'; - } - } - - window.addEventListener('applicationuninstall', - function removeUninstaledApp(evt) { - var origin = evt.detail.application.origin; - if (userSortedApps.indexOf(origin) !== -1) { - userSortedApps.splice(userSortedApps.indexOf(origin), 1); - } - }, - false); - - function cv_handleEvent(evt) { - switch (evt.type) { - case 'mousedown': - onStartEvent(evt); - break; - - case 'mousemove': - onMoveEvent(evt); - break; - - case 'swipe': - onEndEvent(evt); - break; - - case 'contextmenu': - manualOrderStart(evt); - break; - - case 'home': - if (!cardSwitcherIsShown()) - return; - - evt.stopImmediatePropagation(); - hideCardSwitcher(); - break; - - case 'lock': - case 'attentionscreenshow': - attentionScreenApps = AttentionScreen.getAttentionScreenOrigins(); - hideCardSwitcher(); - break; - - case 'attentionscreenhide': - attentionScreenApps = AttentionScreen.getAttentionScreenOrigins(); - break; - - case 'holdhome': - if (LockScreen.locked) - return; - - SleepMenu.hide(); - showCardSwitcher(); - break; - - case 'appwillopen': - hideCardSwitcher(); - break; - } - } - - // Public API of CardsView - return { - showCardSwitcher: showCardSwitcher, - hideCardSwitcher: hideCardSwitcher, - cardSwitcherIsShown: cardSwitcherIsShown, - handleEvent: cv_handleEvent - }; -})(); - -window.addEventListener('attentionscreenshow', CardsView); -window.addEventListener('attentionscreenhide', CardsView); -window.addEventListener('holdhome', CardsView); -window.addEventListener('home', CardsView); -window.addEventListener('appwillopen', CardsView); - diff --git a/apps/system/js/context_menu.js b/apps/system/js/context_menu.js deleted file mode 100644 index 816ef71..0000000 --- a/apps/system/js/context_menu.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var ContextMenu = { - init: function cm_init() { - window.addEventListener('mozbrowsercontextmenu', this, true); - }, - - handleEvent: function cm_handleEvent(evt) { - var detail = evt.detail; - if (detail.contextmenu.items.length == 0) - return; - - var onsuccess = function(action) { - detail.contextMenuItemSelected(action); - }; - - ListMenu.request(detail.contextmenu.items, '', onsuccess); - } -}; - -ContextMenu.init(); diff --git a/apps/system/js/cost_control.js b/apps/system/js/cost_control.js deleted file mode 100644 index 0f07962..0000000 --- a/apps/system/js/cost_control.js +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -(function() { - - 'use strict'; - - var host = document.location.host; - var domain = host.replace(/(^[\w\d]+\.)?([\w\d]+\.[a-z]+)/, '$2'); - var protocol = document.location.protocol + '//'; - var origin = protocol + 'costcontrol.' + domain; - - var widgetContainer = document.getElementById('cost-control-widget'); - - var widgetFrame; - function _ensureWidget() { - if (!Applications.ready) - return; - - // Check widget is there - widgetFrame = widgetContainer.querySelector('iframe'); - if (widgetFrame && !widgetFrame.dataset.killed) - return; - - // Create the widget - if (!widgetFrame) { - widgetFrame = document.createElement('iframe'); - widgetFrame.addEventListener('mozbrowsererror', - function ccdriver_onError(e) { - e.target.dataset.killed = true; - } - ); - } - - widgetFrame.dataset.frameType = 'widget'; - widgetFrame.dataset.frameOrigin = origin; - delete widgetFrame.dataset.killed; - - widgetFrame.setAttribute('mozbrowser', true); - widgetFrame.setAttribute('remote', 'true'); - widgetFrame.setAttribute('mozapp', origin + '/manifest.webapp'); - - widgetFrame.src = origin + '/widget.html'; - widgetContainer.appendChild(widgetFrame); - - _adjustWidgetPosition(); - } - - function _showWidget() { - _ensureWidget(); - widgetFrame.setVisible(true); - } - - function _hideWidget() { - if (widgetFrame) { - widgetFrame.setVisible(false); - } - } - - function _adjustWidgetPosition() { - // TODO: Remove this when weird bug #809031 (Bugzilla) is solved - // See cost_control.css as well to remove the last rule - var offsetY = document.getElementById('notification-bar').clientHeight; - offsetY += - document.getElementById('notifications-container').clientHeight; - widgetFrame.style.transform = 'translate(0, ' + offsetY + 'px)'; - } - - // Listen to utilitytray show - window.addEventListener('utilitytrayshow', _showWidget); - window.addEventListener('utilitytrayhide', _hideWidget); - - window.addEventListener('applicationready', function _onReady() { - asyncStorage.getItem('ftu.enabled', function _onValue(enabled) { - if (enabled !== false) { - window.addEventListener('ftudone', function ftudone(e) { - window.removeEventListener('ftudone', ftudone); - _ensureWidget(); - widgetFrame.setVisible(false); - }); - } else { - _ensureWidget(); - widgetFrame.setVisible(false); - } - }); - }); - - window.addEventListener('resize', _adjustWidgetPosition); -}()); diff --git a/apps/system/js/crash_reporter.js b/apps/system/js/crash_reporter.js deleted file mode 100644 index 4068291..0000000 --- a/apps/system/js/crash_reporter.js +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -// This file calls getElementById without waiting for an onload event, so it -// must have a defer attribute or be included at the end of the <body>. - -var CrashReporter = (function() { - var _ = navigator.mozL10n.get; - var settings = navigator.mozSettings; - var screen = document.getElementById('screen'); - - // The name of the app that just crashed. - var crashedAppName = ''; - - // Whether or not to show a "Report" button in the banner. - var showReportButton = false; - - // Only show the "Report" button if the user hasn't set a preference to - // always/never report crashes. - SettingsListener.observe('app.reportCrashes', 'ask', - function handleCrashSetting(value) { - showReportButton = (value != 'always' && value != 'never'); - }); - - // This function should only ever be called once. - function showDialog(crashID, isChrome) { - var title = isChrome ? _('crash-dialog-os2') : - _('crash-dialog-app', { name: crashedAppName }); - document.getElementById('crash-dialog-title').textContent = title; - - // "Don't Send Report" button in dialog - var noButton = document.getElementById('dont-send-report'); - noButton.addEventListener('click', function onNoButtonClick() { - settings.createLock().set({'app.reportCrashes': 'never'}); - removeDialog(); - }); - - // "Send Report" button in dialog - var yesButton = document.getElementById('send-report'); - yesButton.addEventListener('click', function onYesButtonClick() { - submitCrash(crashID); - if (checkbox.checked) { - settings.createLock().set({'app.reportCrashes': 'always'}); - } - removeDialog(); - }); - - var checkbox = document.getElementById('always-send'); - checkbox.addEventListener('click', function onCheckboxClick() { - // Disable the "Don't Send Report" button if the "Always send..." - // checkbox is checked - noButton.disabled = this.checked; - }); - - // "What's in a crash report?" link - var crashInfoLink = document.getElementById('crash-info-link'); - crashInfoLink.addEventListener('click', function onLearnMoreClick() { - var dialog = document.getElementById('crash-dialog'); - document.getElementById('crash-reports-done'). - addEventListener('click', function onDoneClick() { - this.removeEventListener('click', onDoneClick); - dialog.classList.remove('learn-more'); - }); - dialog.classList.add('learn-more'); - }); - - screen.classList.add('crash-dialog'); - } - - // We can get rid of the dialog after it is shown once. - function removeDialog() { - screen.classList.remove('crash-dialog'); - var dialog = document.getElementById('crash-dialog'); - dialog.parentNode.removeChild(dialog); - } - - function showBanner(crashID, isChrome) { - var message = isChrome ? _('crash-banner-os2') : - _('crash-banner-app', { name: crashedAppName }); - - var button = null; - if (showReportButton) { - button = { - label: _('crash-banner-report'), - callback: function reportCrash() { - submitCrash(crashID); - } - }; - } - - SystemBanner.show(message, button); - } - - function submitCrash(crashID) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, { - type: 'submit-crash', - crashID: crashID - }); - window.dispatchEvent(event); - } - - // - Show a dialog only the first time there's a crash to report. - // - On subsequent crashes, show a banner letting the user know there was a - // crash. - // - If the user hasn't set a pref, add a "Report" button to the banner. - function handleCrash(crashID, isChrome) { - // Check to see if we should show a dialog. - var dialogReq = settings.createLock().get('crashReporter.dialogShown'); - dialogReq.onsuccess = function dialogShownSuccess() { - var dialogShown = dialogReq.result['crashReporter.dialogShown']; - if (!dialogShown) { - settings.createLock().set({'crashReporter.dialogShown': true}); - showDialog(crashID, isChrome); - } else { - showBanner(crashID, isChrome); - } - }; - } - - // We depend on window_manager.js calling this function before - // we get a 'handle-crash' event from shell.js - function setAppName(name) { - crashedAppName = name; - } - - // We will be notified of system crashes from shell.js - window.addEventListener('mozChromeEvent', function handleChromeEvent(e) { - if (e.detail.type == 'handle-crash') { - handleCrash(e.detail.crashID, e.detail.chrome); - } - }); - - return { - setAppName: setAppName - }; -})(); - diff --git a/apps/system/js/gridview.js b/apps/system/js/gridview.js deleted file mode 100644 index 399bf3e..0000000 --- a/apps/system/js/gridview.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var GridView = { - grid: null, - - get visible() { - return this.grid && this.grid.style.display === 'block'; - }, - - hide: function gv_hide() { - if (this.grid) - this.grid.style.visibility = 'hidden'; - }, - - show: function gv_show() { - var grid = this.grid; - if (!grid) { - grid = document.createElement('div'); - grid.id = 'debug-grid'; - grid.dataset.zIndexLevel = 'debug-grid'; - - this.grid = grid; - document.getElementById('screen').appendChild(grid); - } - - grid.style.visibility = 'visible'; - }, - - toggle: function gv_toggle() { - this.visible ? this.hide() : this.show(); - } -}; - -SettingsListener.observe('debug.grid.enabled', false, function(value) { - !!value ? GridView.show() : GridView.hide(); -}); - diff --git a/apps/system/js/hardware_buttons.js b/apps/system/js/hardware_buttons.js deleted file mode 100644 index 3363463..0000000 --- a/apps/system/js/hardware_buttons.js +++ /dev/null @@ -1,318 +0,0 @@ -// hardware_buttons.js: -// -// Gecko code in b2g/chrome/content/shell.js sends mozChromeEvents -// when the user presses or releases a hardware button such as Home, Sleep, -// and Volume Up and Down. -// -// This module listens for those low-level mozChromeEvents, processes them -// and generates higher-level events to handle autorepeat on the volume keys -// long presses on Home and Sleep, and the Home+Sleep key combination. -// -// Other system app modules should listen for the high-level button events -// generated by this module. -// -// The low-level input events processed by this module have type set -// to "mozChromeEvent" and detail.type set to one of: -// -// home-button-press -// home-button-release -// sleep-button-press -// sleep-button-release -// volume-up-button-press -// volume-up-button-release -// volume-down-button-press -// volume-down-button-release -// -// The high-level events generated by this module are simple Event objects -// that are not cancelable and do not bubble. The are dispatched at the -// window object. The type property is set to one of these: -// -// Event Type Meaning -// -------------------------------------------------------------- -// home short press and release of home button -// holdhome long press and hold of home button -// sleep short press and release of sleep button -// wake sleep or home pressed while sleeping -// holdsleep long press and hold of sleep button -// volumeup volume up pressed and released or autorepeated -// volumedown volume down pressed and released or autorepeated -// home+sleep home and sleep pressed at same time (used for screenshots) -// home+volume home and either volume key at the same time (view source) -// -// Because these events are fired at the window object, they cannot be -// captured. Many modules listen for the home event. Those that want -// to respond to it and prevent others from responding should call -// stopImmediatePropagation(). Overlays that want to prevent the window -// manager from showing the homescreen on the home event should call that -// method. Note, however, that this only works for scripts that run and -// register their event handlers before window_manager.js does. -// -'use strict'; - -(function() { - var HOLD_INTERVAL = 750; // How long for press and hold Home or Sleep - var REPEAT_DELAY = 700; // How long before volume autorepeat begins - var REPEAT_INTERVAL = 100; // How fast the autorepeat is. - - // Dispatch a high-level event of the specified type - function fire(type) { - window.dispatchEvent(new Event(type)); - } - - // We process events with a finite state machine. - // Each state object has a process() method for handling events. - // And optionally has enter() and exit() methods called when the FSM - // enters and exits that state - var state; - - // This function transitions to a new state - function setState(s, type) { - // Exit the current state() - if (state && state.exit) - state.exit(type); - state = s; - // Enter the new state - if (state && state.enter) - state.enter(type); - } - - // This event handler listens for hardware button events and passes the - // event type to the process() method of the current state for processing - window.addEventListener('mozChromeEvent', function(e) { - var type = e.detail.type; - switch (type) { - case 'home-button-press': - case 'home-button-release': - case 'sleep-button-press': - case 'sleep-button-release': - case 'volume-up-button-press': - case 'volume-up-button-release': - case 'volume-down-button-press': - case 'volume-down-button-release': - state.process(type); - break; - } - }); - - // The base state is the default, when no hardware buttons are pressed - var baseState = { - process: function(type) { - switch (type) { - case 'home-button-press': - // If the phone is sleeping, then pressing Home wakes it - // (on press, not release) - if (!ScreenManager.screenEnabled) { - fire('wake'); - setState(wakeState, type); - } else { - setState(homeState, type); - } - return; - case 'sleep-button-press': - // If the phone is sleeping, then pressing Sleep wakes it - // (on press, not release) - if (!ScreenManager.screenEnabled) { - fire('wake'); - setState(wakeState, type); - } else { - setState(sleepState, type); - } - return; - case 'volume-up-button-press': - case 'volume-down-button-press': - setState(volumeState, type); - return; - case 'home-button-release': - case 'sleep-button-release': - case 'volume-up-button-release': - case 'volume-down-button-release': - // Ignore button releases that occur in this state. - // These can happen after home+sleep and home+volume. - return; - } - console.error('Unexpected hardware key: ', type); - } - }; - - // We enter the home state when the user presses the Home button - // We can fire home, holdhome, or homesleep events from this state - var homeState = { - timer: null, - enter: function() { - this.timer = setTimeout(function() { - fire('holdhome'); - navigator.vibrate(50); - setState(baseState); - }, HOLD_INTERVAL); - }, - exit: function() { - if (this.timer) { - clearTimeout(this.timer); - this.timer = null; - } - }, - process: function(type) { - switch (type) { - case 'home-button-release': - fire('home'); - navigator.vibrate(50); - setState(baseState, type); - return; - case 'sleep-button-press': - fire('home+sleep'); - setState(baseState, type); - return; - case 'volume-up-button-press': - case 'volume-down-button-press': - fire('home+volume'); - setState(baseState, type); - return; - } - console.error('Unexpected hardware key: ', type); - setState(baseState, type); - } - }; - - // We enter the sleep state when the user presses the Sleep button - // We can fire sleep, holdsleep, or homesleep events from this state - var sleepState = { - timer: null, - enter: function() { - this.timer = setTimeout(function() { - fire('holdsleep'); - setState(baseState); - }, HOLD_INTERVAL); - }, - exit: function() { - if (this.timer) { - clearTimeout(this.timer); - this.timer = null; - } - }, - process: function(type) { - switch (type) { - case 'sleep-button-release': - fire('sleep'); - setState(baseState, type); - return; - case 'home-button-press': - fire('home+sleep'); - setState(baseState, type); - return; - case 'volume-up-button-press': - case 'volume-down-button-press': - setState(volumeState, type); - return; - } - console.error('Unexpected hardware key: ', type); - setState(baseState, type); - } - }; - - // We enter the volume state when the user presses the volume up or - // volume down buttons. - // We can fire volumeup and volumedown events from this state - var volumeState = { - direction: null, - timer: null, - repeating: false, - repeat: function() { - this.repeating = true; - if (this.direction === 'volume-up-button-press') - fire('volumeup'); - else - fire('volumedown'); - this.timer = setTimeout(this.repeat.bind(this), REPEAT_INTERVAL); - }, - enter: function(type) { - var self = this; - this.direction = type; // Is volume going up or down? - this.repeating = false; - this.timer = setTimeout(this.repeat.bind(this), REPEAT_DELAY); - }, - exit: function() { - if (this.timer) { - clearTimeout(this.timer); - this.timer = null; - } - }, - process: function(type) { - switch (type) { - case 'home-button-press': - fire('home+volume'); - setState(baseState, type); - return; - case 'sleep-button-press': - setState(sleepState, type); - return; - case 'volume-up-button-release': - if (this.direction === 'volume-up-button-press') { - if (!this.repeating) - fire('volumeup'); - setState(baseState, type); - return; - } - break; - case 'volume-down-button-release': - if (this.direction === 'volume-down-button-press') { - if (!this.repeating) - fire('volumedown'); - setState(baseState, type); - return; - } - break; - default: - // Ignore anything else (such as sleep button release) - return; - } - console.error('Unexpected hardware key: ', type); - setState(baseState, type); - } - }; - - // We enter this state when the user presses Home or Sleep on a sleeping - // phone. We give immediate feedback by waking the phone up on the press - // rather than waiting for the release, but this means we need a special - // state so that we don't actually send a home or sleep event on the - // key release. Note, however, that this state does set a timer so that - // it can send holdhome or holdsleep events. (This means that pressing and - // holding sleep will bring up the power menu, even on a sleeping phone.) - var wakeState = { - timer: null, - delegateState: null, - enter: function(type) { - if (type === 'home-button-press') - this.delegateState = homeState; - else - this.delegateState = sleepState; - this.timer = setTimeout(function() { - if (type === 'home-button-press') { - fire('holdhome'); - } else if (type === 'sleep-button-press') { - fire('holdsleep'); - } - setState(baseState, type); - }, HOLD_INTERVAL); - }, - exit: function() { - if (this.timer) { - clearTimeout(this.timer); - this.timer = null; - } - }, - process: function(type) { - switch (type) { - case 'home-button-release': - case 'sleep-button-release': - setState(baseState, type); - return; - default: - this.delegateState.process(type); - return; - } - } - }; - - // Kick off the FSM in the base state - setState(baseState); -}()); diff --git a/apps/system/js/icc_cache.js b/apps/system/js/icc_cache.js deleted file mode 100644 index 1f1d0df..0000000 --- a/apps/system/js/icc_cache.js +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -(function() { - /** - * Constants - */ - var DEBUG = false; - - /** - * Debug method - */ - function debug(msg, optObject) { - if (DEBUG) { - var output = '[DEBUG] STKCACHE: ' + msg; - if (optObject) { - output += JSON.stringify(optObject); - } - console.log(output); - } - } - - if (!window.navigator.mozMobileConnection) { - return; - } - - var icc = window.navigator.mozMobileConnection.icc; - // Remove previous menu - var resetApplications = window.navigator.mozSettings.createLock().set({ - 'icc.applications': '{}' - }); - resetApplications.onsuccess = function icc_resetApplications() { - debug('STK Cache Reseted'); - // Register to receive STK commands - window.navigator.mozSetMessageHandler('icc-stkcommand', - function handleSTKCommand(command) { - debug('STK Proactive Command:', command); - if (command.typeOfCommand == icc.STK_CMD_SET_UP_MENU) { - debug('STK_CMD_SET_UP_MENU:', command.options); - var reqApplications = window.navigator.mozSettings.createLock().set({ - 'icc.applications': JSON.stringify(command.options) - }); - reqApplications.onsuccess = function icc_getApplications() { - debug('Cached'); - icc.sendStkResponse(command, { - resultCode: icc.STK_RESULT_OK - }); - } - } else { - // Unsolicited command? -> Open settings - debug('CMD: ', command); - var application = document.location.protocol + '//' + - document.location.host.replace('system', 'settings'); - debug('application: ', application); - var reqIccData = window.navigator.mozSettings.createLock().set({ - 'icc.data': JSON.stringify(command) - }); - reqIccData.onsuccess = function icc_getIccData() { - if (WindowManager.getRunningApps()[application]) { - debug('Settings is running. Ignoring'); - return; // If settings is opened, we don't manage it - } - - debug('Locating settings . . .'); - navigator.mozApps.mgmt.getAll().onsuccess = function gotApps(evt) { - var apps = evt.target.result; - apps.forEach(function appIterator(app) { - if (app.origin != application) - return; - - var reqIccData = window.navigator.mozSettings.createLock().set({ - 'icc.data': JSON.stringify(command) - }); - reqIccData.onsuccess = function icc_getIccData() { - debug('Launching ', app.origin); - app.launch(); - } - }, this); - } - } - } - }); - } -})(); diff --git a/apps/system/js/identity.js b/apps/system/js/identity.js deleted file mode 100644 index 8030377..0000000 --- a/apps/system/js/identity.js +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -// When bug 794999 is resolved, switch to use the abstract Trusted UI Component - -'use strict'; - -const kIdentityScreen = 'https://login.native-persona.org/sign_in#NATIVE'; -const kIdentityFrame = - 'https://login.native-persona.org/communication_iframe'; - -var Identity = (function() { - var iframe; - - return { - trustedUILayers: {}, - - init: function() { - window.addEventListener('mozChromeEvent', this); - }, - - handleEvent: function onMozChromeEvent(e) { - var chromeEventId = e.detail.id; - var requestId = e.detail.requestId; - switch (e.detail.type) { - // Chrome asks Gaia to show the identity dialog. - case 'open-id-dialog': - if (!chromeEventId) - return; - - // When opening the dialog, we record the chrome event id, which - // we will need to send back to the TrustedUIManager when asking - // to close. - this.trustedUILayers[requestId] = chromeEventId; - - if (!e.detail.showUI && iframe) { - this._dispatchEvent({ - id: chromeEventId, - frame: iframe - }); - return; - } - var frame = document.createElement('iframe'); - frame.setAttribute('mozbrowser', 'true'); - frame.setAttribute('remote', true); - frame.classList.add('screen'); - frame.src = e.detail.showUI ? kIdentityScreen : kIdentityFrame; - frame.addEventListener('mozbrowserloadstart', - function loadStart(evt) { - // After creating the new frame containing the identity flow, we - // send it back to chrome so the identity callbacks can be injected. - this._dispatchEvent({ - id: chromeEventId, - frame: evt.target - }); - }.bind(this)); - - - if (e.detail.showUI) { - // The identity flow is shown within the trusted UI. - TrustedUIManager.open(navigator.mozL10n.get('persona-signin'), - frame, - this.trustedUILayers[requestId]); - } else { - var container = document.getElementById('screen'); - container.appendChild(frame); - frame.classList.add('communication-frame'); - iframe = frame; - } - break; - - case 'received-id-assertion': - if (e.detail.showUI) { - TrustedUIManager.close(this.trustedUILayers[requestId], - (function dialogClosed() { - delete this.trustedUILayers[requestId]; - }).bind(this)); - } - this._dispatchEvent({ id: chromeEventId }); - break; - } - }, - _dispatchEvent: function su_dispatchEvent(obj) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, obj); - window.dispatchEvent(event); - } - }; -})(); - -// Make sure L10n is ready before init -if (navigator.mozL10n.readyState == 'complete' || - navigator.mozL10n.readyState == 'interactive') { - Identity.init(); -} else { - window.addEventListener('localized', Identity.init.bind(Identity)); -} - diff --git a/apps/system/js/keyboard_manager.js b/apps/system/js/keyboard_manager.js deleted file mode 100644 index 62aeca7..0000000 --- a/apps/system/js/keyboard_manager.js +++ /dev/null @@ -1,86 +0,0 @@ -'use strict'; - -var KeyboardManager = (function() { - function getKeyboardURL() { - // TODO: Retrieve it from Settings, allowing 3rd party keyboards - var host = document.location.host; - var domain = host.replace(/(^[\w\d]+\.)?([\w\d]+\.[a-z]+)/, '$2'); - var protocol = document.location.protocol; - - return protocol + '//keyboard.' + domain + '/'; - } - - function generateKeyboard(container, keyboardURL, manifestURL) { - var keyboard = document.createElement('iframe'); - keyboard.src = keyboardURL; - keyboard.setAttribute('mozbrowser', 'true'); - keyboard.setAttribute('mozpasspointerevents', 'true'); - keyboard.setAttribute('mozapp', manifestURL); - //keyboard.setAttribute('remote', 'true'); - - container.appendChild(keyboard); - return keyboard; - } - - // Generate a <iframe mozbrowser> containing the keyboard. - var container = document.getElementById('keyboard-frame'); - var keyboardURL = getKeyboardURL() + 'index.html'; - var manifestURL = getKeyboardURL() + 'manifest.webapp'; - var keyboard = generateKeyboard(container, keyboardURL, manifestURL); - - // Listen for mozbrowserlocationchange of keyboard iframe. - var previousHash = ''; - - var urlparser = document.createElement('a'); - keyboard.addEventListener('mozbrowserlocationchange', function(e) { - urlparser.href = e.detail; - if (previousHash == urlparser.hash) - return; - previousHash = urlparser.hash; - - var type = urlparser.hash.split('='); - switch (type[0]) { - case '#show': - var updateHeight = function updateHeight() { - container.removeEventListener('transitionend', updateHeight); - if (container.classList.contains('hide')) { - // The keyboard has been closed already, let's not resize the - // application and ends up with half apps. - return; - } - - var detail = { - 'detail': { - 'height': parseInt(type[1]) - } - }; - - dispatchEvent(new CustomEvent('keyboardchange', detail)); - } - - if (container.classList.contains('hide')) { - container.classList.remove('hide'); - container.addEventListener('transitionend', updateHeight); - return; - } - - updateHeight(); - break; - - case '#hide': - // inform window manager to resize app first or - // it may show the underlying homescreen - dispatchEvent(new CustomEvent('keyboardhide')); - container.classList.add('hide'); - break; - } - }); - - // For Bug 812115: hide the keyboard when the app is closed here, - // since it would take a longer round-trip to receive focuschange - window.addEventListener('appwillclose', function closeKeyboard() { - dispatchEvent(new CustomEvent('keyboardhide')); - container.classList.add('hide'); - }); -})(); - diff --git a/apps/system/js/list_menu.js b/apps/system/js/list_menu.js deleted file mode 100644 index 303fafe..0000000 --- a/apps/system/js/list_menu.js +++ /dev/null @@ -1,180 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var ListMenu = { - get element() { - delete this.element; - return this.element = document.getElementById('listmenu'); - }, - - get container() { - delete this.container; - return this.container = document.querySelector('#listmenu menu'); - }, - - get visible() { - return this.element.classList.contains('visible'); - }, - - // Listen to click event only - init: function lm_init() { - window.addEventListener('click', this, true); - window.addEventListener('screenchange', this, true); - window.addEventListener('home', this); - window.addEventListener('holdhome', this); - }, - - // Pass an array of list items and handler for clicking on the items - // Modified to fit contextmenu use case, loop into the menu items - request: function lm_request(listItems, title, successCb, errorCb) { - this.container.innerHTML = ''; - this.currentLevel = 0; - this.internalList = []; - this.setTitle(title); - this.buildMenu(listItems); - this.internalList.forEach(function render_item(item) { - this.container.appendChild(item); - }, this); - - this.onreturn = successCb || function() {}; - this.oncancel = errorCb || function() {}; - - this.show(); - }, - - buildMenu: function lm_buildMenu(items) { - var containerDiv = document.createElement('ul'); - var _ = navigator.mozL10n.get; - - if (this.currentLevel === 0) { - containerDiv.classList.add('list-menu-root'); - containerDiv.id = 'list-menu-root'; - } else { - containerDiv.id = 'list-menu-' + this.internalList.length; - } - this.internalList.push(containerDiv); - - items.forEach(function traveseItems(item) { - var item_div = document.createElement('li'); - var button = document.createElement('a'); - button.setAttribute('role', 'button'); - if (item.type && item.type == 'menu') { - // XXX: We disallow multi-level menu at this moment - // See https://bugzilla.mozilla.org/show_bug.cgi?id=824928 - // for UX design and dev implementation tracking - return; - } else if (item.type && item.type == 'menuitem') { - button.dataset.value = item.id; - button.textContent = item.label; - } else { - button.dataset.value = item.value; - button.textContent = item.label; - } - - item_div.appendChild(button); - if (item.icon) { - button.style.backgroundImage = 'url(' + item.icon + ')'; - button.classList.add('icon'); - } - containerDiv.appendChild(item_div); - }, this); - - if (this.currentLevel > 0) { - var back = document.createElement('li'); - var button = document.createElement('a'); - button.setAttribute('role', 'button'); - button.textContent = _('back'); - button.href = '#' + this.currentParent; - back.classList.add('back'); - back.appendChild(button); - containerDiv.appendChild(back); - } else { - var cancel = document.createElement('li'); - var button = document.createElement('button'); - button.textContent = _('cancel'); - button.dataset.action = 'cancel'; - cancel.appendChild(button); - containerDiv.appendChild(cancel); - } - - containerDiv.dataset.level = this.currentLevel; - this.currentChild = containerDiv.id; - }, - - setTitle: function lm_setTitle(title) { - if (!title) - return; - - var titleElement = document.createElement('h3'); - titleElement.textContent = title; - this.container.appendChild(titleElement); - }, - - show: function lm_show() { - if (this.visible) - return; - - this.container.classList.remove('slidedown'); - this.element.classList.add('visible'); - }, - - hide: function lm_hide() { - if (!this.visible) - return; - - var self = this; - var container = this.container; - container.addEventListener('transitionend', function list_hide() { - container.removeEventListener('transitionend', list_hide); - self.element.classList.remove('visible'); - }); - - setTimeout(function() { - container.classList.add('slidedown'); - }); - }, - - handleEvent: function lm_handleEvent(evt) { - switch (evt.type) { - case 'screenchange': - if (!evt.detail.screenEnabled) { - this.hide(); - this.oncancel(); - } - break; - - case 'click': - if (!this.visible) - return; - - var cancel = evt.target.dataset.action; - if (cancel && cancel == 'cancel') { - this.hide(); - this.oncancel(); - return; - } - - var value = evt.target.dataset.value; - if (!value) { - return; - } - - this.hide(); - this.onreturn(value); - break; - - case 'home': - case 'holdhome': - if (!this.visible) - return; - - this.hide(); - this.oncancel(); - break; - } - } -}; - -ListMenu.init(); diff --git a/apps/system/js/lockscreen.js b/apps/system/js/lockscreen.js deleted file mode 100644 index f2275c9..0000000 --- a/apps/system/js/lockscreen.js +++ /dev/null @@ -1,1019 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var LockScreen = { - /* - * Boolean return true when initialized. - */ - ready: false, - - /* - * Boolean return the status of the lock screen. - * Must not multate directly - use unlock()/lockIfEnabled() - * Listen to 'lock' and 'unlock' event to properly handle status changes - */ - locked: true, - - /* - * Boolean return whether if the lock screen is enabled or not. - * Must not multate directly - use setEnabled(val) - * Only Settings Listener should change this value to sync with data - * in Settings API. - */ - enabled: true, - - /* - * Boolean returns wether we want a sound effect when unlocking. - */ - unlockSoundEnabled: true, - - /* - * Boolean return whether if the lock screen is enabled or not. - * Must not multate directly - use setPassCodeEnabled(val) - * Only Settings Listener should change this value to sync with data - * in Settings API. - * Will be ignored if 'enabled' is set to false. - */ - passCodeEnabled: false, - - /* - * Four digit Passcode - * XXX: should come for Settings - */ - passCode: '0000', - - /* - * The time to request for passcode input since device is off. - */ - passCodeRequestTimeout: 0, - - /* - * Store the first time the screen went off since unlocking. - */ - _screenOffTime: 0, - - /* - * Check the timeout of passcode lock - */ - _passCodeTimeoutCheck: false, - - /* - * Current passcode entered by the user - */ - passCodeEntered: '', - - /** - * Are we currently switching panels ? - */ - _switchingPanel: false, - - /* - * Timeout after incorrect attempt - */ - kPassCodeErrorTimeout: 500, - - /* - * Airplane mode - */ - airplaneMode: false, - - /* - * Timeout ID for backing from triggered state to normal state - */ - triggeredTimeoutId: 0, - - /* - * Interval ID for elastic of curve and arrow - */ - elasticIntervalId: 0, - - /* - * elastic animation interval - */ - ELASTIC_INTERVAL: 5000, - - /* - * timeout for triggered state after swipe up - */ - TRIGGERED_TIMEOUT: 7000, - - /* - * Max value for handle swiper up - */ - HANDLE_MAX: 70, - - /* init */ - init: function ls_init() { - if (this.ready) { // already initialized: just trigger a translation - this.updateTime(); - this.updateConnState(); - return; - } - this.ready = true; - - this.getAllElements(); - - this.lockIfEnabled(true); - this.writeSetting(this.enabled); - - /* Status changes */ - window.addEventListener('volumechange', this); - window.addEventListener('screenchange', this); - - /* Gesture */ - this.area.addEventListener('mousedown', this); - this.areaCamera.addEventListener('click', this); - this.areaUnlock.addEventListener('click', this); - this.iconContainer.addEventListener('mousedown', this); - - /* Unlock & camera panel clean up */ - this.overlay.addEventListener('transitionend', this); - - /* Passcode input pad*/ - this.passcodePad.addEventListener('click', this); - - /* switching panels */ - window.addEventListener('home', this); - - /* blocking holdhome and prevent Cards View from show up */ - window.addEventListener('holdhome', this, true); - - /* mobile connection state on lock screen */ - var conn = window.navigator.mozMobileConnection; - if (conn && conn.voice) { - conn.addEventListener('voicechange', this); - conn.addEventListener('cardstatechange', this); - conn.addEventListener('iccinfochange', this); - this.updateConnState(); - this.connstate.hidden = false; - } - - var self = this; - if (navigator && navigator.mozCellBroadcast) { - navigator.mozCellBroadcast.onreceived = function onReceived(event) { - var msg = event.message; - if (conn && - conn.voice.network.mcc === MobileOperator.BRAZIL_MCC && - msg.messageId === MobileOperator.BRAZIL_CELLBROADCAST_CHANNEL) { - self.cellbroadcastLabel = msg.body; - self.updateConnState(); - } - }; - } - - SettingsListener.observe('lockscreen.enabled', true, function(value) { - self.setEnabled(value); - }); - - SettingsListener.observe('ring.enabled', true, function(value) { - self.mute.hidden = value; - }); - - SettingsListener.observe('vibration.enabled', true, function(value) { - if (value) { - self.mute.classList.add('vibration'); - } else { - self.mute.classList.remove('vibration'); - } - }); - - SettingsListener.observe('ril.radio.disabled', false, function(value) { - self.airplaneMode = value; - self.updateConnState(); - }); - - SettingsListener.observe('wallpaper.image', - 'resources/images/backgrounds/default.png', - function(value) { - self.updateBackground(value); - self.overlay.classList.remove('uninit'); - }); - - SettingsListener.observe( - 'lockscreen.passcode-lock.code', '0000', function(value) { - self.passCode = value; - }); - - SettingsListener.observe( - 'lockscreen.passcode-lock.enabled', false, function(value) { - self.setPassCodeEnabled(value); - }); - - SettingsListener.observe('lockscreen.unlock-sound.enabled', - true, function(value) { - self.setUnlockSoundEnabled(value); - }); - - SettingsListener.observe('lockscreen.passcode-lock.timeout', - 0, function(value) { - self.passCodeRequestTimeout = value; - }); - }, - - /* - * Set enabled state. - * If enabled state is somehow updated when the lock screen is enabled - * This function will unlock it. - */ - setEnabled: function ls_setEnabled(val) { - if (typeof val === 'string') { - this.enabled = val == 'false' ? false : true; - } else { - this.enabled = val; - } - - if (!this.enabled && this.locked) { - this.unlock(); - } - }, - - setPassCodeEnabled: function ls_setPassCodeEnabled(val) { - if (typeof val === 'string') { - this.passCodeEnabled = val == 'false' ? false : true; - } else { - this.passCodeEnabled = val; - } - }, - - setUnlockSoundEnabled: function ls_setUnlockSoundEnabled(val) { - if (typeof val === 'string') { - this.unlockSoundEnabled = val == 'false' ? false : true; - } else { - this.unlockSoundEnabled = val; - } - }, - - handleEvent: function ls_handleEvent(evt) { - switch (evt.type) { - case 'screenchange': - // XXX: If the screen is not turned off by ScreenManager - // we would need to lock the screen again - // when it's being turned back on - if (!evt.detail.screenEnabled) { - // Don't update the time after we're already locked otherwise turning - // the screen off again will bypass the passcode before the timeout. - if (!this.locked) { - this._screenOffTime = new Date().getTime(); - } - - // Remove camera once screen turns off - if (this.camera.firstElementChild) - this.camera.removeChild(this.camera.firstElementChild); - - } else { - var _screenOffInterval = new Date().getTime() - this._screenOffTime; - if (_screenOffInterval > this.passCodeRequestTimeout * 1000) { - this._passCodeTimeoutCheck = true; - } else { - this._passCodeTimeoutCheck = false; - } - } - - this.lockIfEnabled(true); - break; - case 'voicechange': - case 'cardstatechange': - case 'iccinfochange': - this.updateConnState(); - - case 'click': - if (evt.target === this.areaUnlock || evt.target === this.areaCamera) { - this.handleIconClick(evt.target); - break; - } - - if (!evt.target.dataset.key) - break; - - // Cancel the default action of <a> - evt.preventDefault(); - this.handlePassCodeInput(evt.target.dataset.key); - break; - - case 'mousedown': - var leftTarget = this.areaCamera; - var rightTarget = this.areaUnlock; - var handle = this.areaHandle; - var overlay = this.overlay; - var target = evt.target; - - // Reset timer when touch while overlay triggered - if (overlay.classList.contains('triggered')) { - clearTimeout(this.triggeredTimeoutId); - this.triggeredTimeoutId = setTimeout(this.unloadPanel.bind(this), - this.TRIGGERED_TIMEOUT); - break; - } - - overlay.classList.remove('elastic'); - this.setElasticEnabled(false); - - this._touch = { - touched: false, - leftTarget: leftTarget, - rightTarget: rightTarget, - overlayWidth: this.overlay.offsetWidth, - handleWidth: this.areaHandle.offsetWidth, - maxHandleOffset: rightTarget.offsetLeft - handle.offsetLeft - - (handle.offsetWidth - rightTarget.offsetWidth) / 2 - }; - window.addEventListener('mouseup', this); - window.addEventListener('mousemove', this); - - this._touch.touched = true; - this._touch.initX = evt.pageX; - this._touch.initY = evt.pageY; - overlay.classList.add('touched'); - break; - - case 'mousemove': - this.handleMove(evt.pageX, evt.pageY); - break; - - case 'mouseup': - window.removeEventListener('mousemove', this); - window.removeEventListener('mouseup', this); - - this.handleMove(evt.pageX, evt.pageY); - this.handleGesture(); - delete this._touch; - this.overlay.classList.remove('touched'); - - break; - - case 'transitionend': - if (evt.target !== this.overlay) - return; - - if (this.overlay.dataset.panel !== 'camera' && - this.camera.firstElementChild) { - this.camera.removeChild(this.camera.firstElementChild); - } - - if (!this.locked) - this.switchPanel(); - break; - - case 'home': - if (this.locked) { - this.switchPanel(); - evt.stopImmediatePropagation(); - } - break; - - case 'holdhome': - if (!this.locked) - return; - - evt.stopImmediatePropagation(); - evt.stopPropagation(); - break; - } - }, - - handleMove: function ls_handleMove(pageX, pageY) { - var touch = this._touch; - - if (!touch.touched) { - // Do nothing if the user have not move the finger to the handle yet - if (document.elementFromPoint(pageX, pageY) !== this.areaHandle) - return; - - touch.touched = true; - touch.initX = pageX; - touch.initY = pageY; - - var overlay = this.overlay; - overlay.classList.add('touched'); - } - - var dy = pageY - touch.initY; - var ty = Math.max(- this.HANDLE_MAX, dy); - var base = - ty / this.HANDLE_MAX; - // mapping position 20-100 to opacity 0.1-0.5 - var opacity = base <= 0.2 ? 0.1 : base * 0.5; - touch.ty = ty; - - this.iconContainer.style.transform = 'translateY(' + ty + 'px)'; - this.areaCamera.style.opacity = - this.areaUnlock.style.opacity = opacity; - }, - - handleGesture: function ls_handleGesture() { - var touch = this._touch; - if (touch.ty < -50) { - this.areaHandle.style.transform = - this.areaHandle.style.opacity = - this.iconContainer.style.transform = - this.iconContainer.style.opacity = - this.areaCamera.style.transform = - this.areaCamera.style.opacity = - this.areaUnlock.style.transform = - this.areaUnlock.style.opacity = ''; - this.overlay.classList.add('triggered'); - - this.triggeredTimeoutId = - setTimeout(this.unloadPanel.bind(this), this.TRIGGERED_TIMEOUT); - } else if (touch.ty > -10) { - touch.touched = false; - this.unloadPanel(); - this.playElastic(); - - var self = this; - var container = this.iconContainer; - container.addEventListener('animationend', function prompt() { - container.removeEventListener('animationend', prompt); - self.overlay.classList.remove('elastic'); - self.setElasticEnabled(true); - }); - } else { - this.unloadPanel(); - this.setElasticEnabled(true); - } - }, - - handleIconClick: function ls_handleIconClick(target) { - var self = this; - switch (target) { - case this.areaCamera: - var panelOrFullApp = function panelOrFullApp() { - if (self.passCodeEnabled) { - // Go to secure camera panel - self.switchPanel('camera'); - return; - } - - self.unlock(); - - var a = new MozActivity({ - name: 'record', - data: { - type: 'photos' - } - }); - a.onerror = function ls_activityError() { - console.log('MozActivity: camera launch error.'); - }; - }; - - panelOrFullApp(); - break; - - case this.areaUnlock: - var passcodeOrUnlock = function passcodeOrUnlock() { - if (!self.passCodeEnabled || !self._passCodeTimeoutCheck) { - self.unlock(); - } else { - self.switchPanel('passcode'); - } - }; - passcodeOrUnlock(); - break; - } - }, - - handlePassCodeInput: function ls_handlePassCodeInput(key) { - switch (key) { - case 'e': // Emergency Call - this.switchPanel('emergency-call'); - break; - - case 'c': - this.switchPanel(); - break; - - case 'b': - if (this.overlay.dataset.passcodeStatus) - return; - - this.passCodeEntered = - this.passCodeEntered.substr(0, this.passCodeEntered.length - 1); - this.updatePassCodeUI(); - - break; - default: - if (this.overlay.dataset.passcodeStatus) - return; - - this.passCodeEntered += key; - this.updatePassCodeUI(); - - if (this.passCodeEntered.length === 4) - this.checkPassCode(); - break; - } - }, - - lockIfEnabled: function ls_lockIfEnabled(instant) { - if (this.enabled) { - this.lock(instant); - } else { - this.unlock(instant); - } - }, - - unlock: function ls_unlock(instant) { - var currentApp = WindowManager.getDisplayedApp(); - WindowManager.setOrientationForApp(currentApp); - - var currentFrame = WindowManager.getAppFrame(currentApp).firstChild; - var wasAlreadyUnlocked = !this.locked; - this.locked = false; - this.setElasticEnabled(false); - this.mainScreen.focus(); - - var repaintTimeout = 0; - var nextPaint = (function() { - clearTimeout(repaintTimeout); - currentFrame.removeNextPaintListener(nextPaint); - - if (instant) { - this.overlay.classList.add('no-transition'); - this.switchPanel(); - } else { - this.overlay.classList.remove('no-transition'); - } - - this.mainScreen.classList.remove('locked'); - - if (!wasAlreadyUnlocked) { - // Any changes made to this, - // also need to be reflected in apps/system/js/storage.js - this.dispatchEvent('unlock'); - this.writeSetting(false); - - if (instant) - return; - - if (this.unlockSoundEnabled) { - var unlockAudio = new Audio('./resources/sounds/unlock.ogg'); - unlockAudio.play(); - } - } - }).bind(this); - - this.dispatchEvent('will-unlock'); - currentFrame.addNextPaintListener(nextPaint); - repaintTimeout = setTimeout(function ensureUnlock() { - nextPaint(); - }, 400); - }, - - lock: function ls_lock(instant) { - var wasAlreadyLocked = this.locked; - this.locked = true; - - this.updateTime(); - - this.switchPanel(); - - this.setElasticEnabled(ScreenManager.screenEnabled); - - this.overlay.focus(); - if (instant) - this.overlay.classList.add('no-transition'); - else - this.overlay.classList.remove('no-transition'); - - this.mainScreen.classList.add('locked'); - - screen.mozLockOrientation('portrait-primary'); - - if (!wasAlreadyLocked) { - if (document.mozFullScreen) - document.mozCancelFullScreen(); - - // Any changes made to this, - // also need to be reflected in apps/system/js/storage.js - this.dispatchEvent('lock'); - this.writeSetting(true); - } - }, - - loadPanel: function ls_loadPanel(panel, callback) { - this._loadingPanel = true; - switch (panel) { - case 'passcode': - case 'main': - if (callback) - setTimeout(callback); - break; - - case 'emergency-call': - // create the <iframe> and load the emergency call - var frame = document.createElement('iframe'); - - frame.src = './emergency-call/index.html'; - frame.onload = function emergencyCallLoaded() { - if (callback) - callback(); - }; - this.panelEmergencyCall.appendChild(frame); - - break; - - case 'camera': - // create the <iframe> and load the camera - var frame = document.createElement('iframe'); - - frame.src = './camera/index.html'; - var mainScreen = this.mainScreen; - frame.onload = function cameraLoaded() { - mainScreen.classList.add('lockscreen-camera'); - if (callback) - callback(); - }; - this.overlay.classList.remove('no-transition'); - this.camera.appendChild(frame); - - break; - } - }, - - unloadPanel: function ls_unloadPanel(panel, toPanel, callback) { - switch (panel) { - case 'passcode': - // Reset passcode panel only if the status is not error - if (this.overlay.dataset.passcodeStatus == 'error') - break; - - delete this.overlay.dataset.passcodeStatus; - this.passCodeEntered = ''; - this.updatePassCodeUI(); - break; - - case 'camera': - this.mainScreen.classList.remove('lockscreen-camera'); - break; - - case 'emergency-call': - var ecPanel = this.panelEmergencyCall; - ecPanel.addEventListener('transitionend', function unloadPanel() { - ecPanel.removeEventListener('transitionend', unloadPanel); - ecPanel.removeChild(ecPanel.firstElementChild); - }); - break; - - case 'main': - default: - var self = this; - var unload = function unload() { - self.areaHandle.style.transform = - self.areaUnlock.style.transform = - self.areaCamera.style.transform = - self.iconContainer.style.transform = - self.iconContainer.style.opacity = - self.areaHandle.style.opacity = - self.areaUnlock.style.opacity = - self.areaCamera.style.opacity = ''; - self.overlay.classList.remove('triggered'); - self.areaHandle.classList.remove('triggered'); - self.areaCamera.classList.remove('triggered'); - self.areaUnlock.classList.remove('triggered'); - - clearTimeout(self.triggeredTimeoutId); - self.setElasticEnabled(false); - }; - - if (toPanel !== 'camera') { - unload(); - break; - } - - this.overlay.addEventListener('transitionend', - function ls_unloadDefaultPanel(evt) { - if (evt.target !== this) - return; - - self.overlay.removeEventListener('transitionend', - ls_unloadDefaultPanel); - unload(); - } - ); - - break; - } - - if (callback) - setTimeout(callback); - }, - - switchPanel: function ls_switchPanel(panel) { - if (this._switchingPanel) { - return; - } - - var overlay = this.overlay; - var self = this; - panel = panel || 'main'; - - this._switchingPanel = true; - this.loadPanel(panel, function panelLoaded() { - self.unloadPanel(overlay.dataset.panel, panel, - function panelUnloaded() { - if (overlay.dataset.panel !== panel) - self.dispatchEvent('lockpanelchange'); - - overlay.dataset.panel = panel; - self._switchingPanel = false; - }); - }); - }, - - updateTime: function ls_updateTime() { - if (!this.locked) - return; - - var d = new Date(); - var f = new navigator.mozL10n.DateTimeFormat(); - var _ = navigator.mozL10n.get; - - var timeFormat = _('shortTimeFormat') || '%H:%M'; - var dateFormat = _('longDateFormat') || '%A %e %B'; - var time = f.localeFormat(d, timeFormat); - this.clockNumbers.textContent = time.match(/([012]?\d).[0-5]\d/g); - this.clockMeridiem.textContent = (time.match(/AM|PM/i) || []).join(''); - this.date.textContent = f.localeFormat(d, dateFormat); - - var self = this; - window.setTimeout(function ls_clockTimeout() { - self.updateTime(); - }, (59 - d.getSeconds()) * 1000); - }, - - updateConnState: function ls_updateConnState() { - var conn = window.navigator.mozMobileConnection; - if (!conn) - return; - - var voice = conn.voice; - var iccInfo = conn.iccInfo; - var connstateLine1 = this.connstate.firstElementChild; - var connstateLine2 = this.connstate.lastElementChild; - var _ = navigator.mozL10n.get; - - var updateConnstateLine1 = function updateConnstateLine1(l10nId) { - connstateLine1.dataset.l10nId = l10nId; - connstateLine1.textContent = _(l10nId) || ''; - }; - - var self = this; - var updateConnstateLine2 = function updateConnstateLine2(l10nId) { - if (l10nId) { - self.connstate.classList.add('twolines'); - connstateLine2.dataset.l10nId = l10nId; - connstateLine2.textContent = _(l10nId) || ''; - } else { - self.connstate.classList.remove('twolines'); - delete(connstateLine2.dataset.l10nId); - connstateLine2.textContent = ''; - } - }; - - // Reset line 2 - updateConnstateLine2(); - - if (this.airplaneMode) { - updateConnstateLine1('airplaneMode'); - return; - } - - // Possible value of voice.state are: - // 'notSearching', 'searching', 'denied', 'registered', - // where the latter three mean the phone is trying to grab the network. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=777057 - if (voice.state == 'notSearching') { - updateConnstateLine1('noNetwork'); - return; - } - - if (!voice.connected && !voice.emergencyCallsOnly) { - // "Searching" - // voice.state can be any of the latter three values. - // (it's possible that the phone is briefly 'registered' - // but not yet connected.) - updateConnstateLine1('searching'); - return; - } - - if (voice.emergencyCallsOnly) { - updateConnstateLine1('emergencyCallsOnly'); - - switch (conn.cardState) { - case 'absent': - updateConnstateLine2('emergencyCallsOnly-noSIM'); - break; - - case 'pinRequired': - updateConnstateLine2('emergencyCallsOnly-pinRequired'); - break; - - case 'pukRequired': - updateConnstateLine2('emergencyCallsOnly-pukRequired'); - break; - - case 'networkLocked': - updateConnstateLine2('emergencyCallsOnly-networkLocked'); - break; - - default: - updateConnstateLine2(); - break; - } - return; - } - - var operatorInfos = MobileOperator.userFacingInfo(conn); - if (this.cellbroadcastLabel) { - connstateLine2.textContent = this.cellbroadcastLabel; - } else if (operatorInfos.carrier) { - connstateLine2.textContent = operatorInfos.carrier + ' ' + - operatorInfos.region; - } - - var operator = operatorInfos.operator; - - if (voice.roaming) { - var l10nArgs = { operator: operator }; - connstateLine1.dataset.l10nId = 'roaming'; - connstateLine1.dataset.l10nArgs = JSON.stringify(l10nArgs); - connstateLine1.textContent = _('roaming', l10nArgs); - - return; - } - - delete connstateLine1.dataset.l10nId; - connstateLine1.textContent = operator; - }, - - updatePassCodeUI: function lockscreen_updatePassCodeUI() { - var overlay = this.overlay; - if (overlay.dataset.passcodeStatus) - return; - if (this.passCodeEntered) { - overlay.classList.add('passcode-entered'); - } else { - overlay.classList.remove('passcode-entered'); - } - var i = 4; - while (i--) { - var span = this.passcodeCode.childNodes[i]; - if (this.passCodeEntered.length > i) { - span.dataset.dot = true; - } else { - delete span.dataset.dot; - } - } - }, - - checkPassCode: function lockscreen_checkPassCode() { - if (this.passCodeEntered === this.passCode) { - var self = this; - this.overlay.dataset.passcodeStatus = 'success'; - this.passCodeError = 0; - - var transitionend = function() { - self.passcodeCode.removeEventListener('transitionend', transitionend); - self.unlock(); - }; - this.passcodeCode.addEventListener('transitionend', transitionend); - } else { - this.overlay.dataset.passcodeStatus = 'error'; - if ('vibrate' in navigator) - navigator.vibrate([50, 50, 50]); - - var self = this; - setTimeout(function error() { - delete self.overlay.dataset.passcodeStatus; - self.passCodeEntered = ''; - self.updatePassCodeUI(); - }, this.kPassCodeErrorTimeout); - } - }, - - updateBackground: function ls_updateBackground(background_datauri) { - this._imgPreload([background_datauri, 'style/lockscreen/images/mask.png'], - function(images) { - - // Bug 829075 : We need a <canvas> in the DOM to prevent banding on - // Otoro-like devices - var canvas = document.createElement('canvas'); - canvas.classList.add('lockscreen-wallpaper'); - canvas.width = images[0].width; - canvas.height = images[0].height; - - var ctx = canvas.getContext('2d'); - ctx.drawImage(images[0], 0, 0); - ctx.drawImage(images[1], 0, 0); - - var panels_selector = '.lockscreen-panel[data-wallpaper]'; - var panels = document.querySelectorAll(panels_selector); - for (var i = 0, il = panels.length; i < il; i++) { - var copied_canvas; - var panel = panels[i]; - - // Remove previous <canvas> if they exist - var old_canvas = panel.querySelector('canvas'); - if (old_canvas) { - old_canvas.parentNode.removeChild(old_canvas); - } - - // For the first panel, we can use the existing <canvas> - if (!copied_canvas) { - copied_canvas = canvas; - } else { - // Otherwise, copy the node and content - copied_canvas = canvas.cloneNode(); - copied_canvas.getContext('2d').drawImage(canvas, 0, 0); - } - - panel.insertBefore(copied_canvas, panel.firstChild); - } - }); - }, - - _imgPreload: function ls_imgPreload(img_paths, callback) { - var loaded = 0; - var images = []; - var il = img_paths.length; - var inc = function() { - loaded += 1; - if (loaded === il && callback) { - callback(images); - } - }; - for (var i = 0; i < il; i++) { - images[i] = new Image(); - images[i].onload = inc; - images[i].src = img_paths[i]; - } - }, - - getAllElements: function ls_getAllElements() { - // ID of elements to create references - var elements = ['connstate', 'mute', 'clock-numbers', 'clock-meridiem', - 'date', 'area', 'area-unlock', 'area-camera', 'icon-container', - 'area-handle', 'passcode-code', - 'passcode-pad', 'camera', 'accessibility-camera', - 'accessibility-unlock', 'panel-emergency-call']; - - var toCamelCase = function toCamelCase(str) { - return str.replace(/\-(.)/g, function replacer(str, p1) { - return p1.toUpperCase(); - }); - }; - - elements.forEach((function createElementRef(name) { - this[toCamelCase(name)] = document.getElementById('lockscreen-' + name); - }).bind(this)); - - this.overlay = document.getElementById('lockscreen'); - this.mainScreen = document.getElementById('screen'); - }, - - dispatchEvent: function ls_dispatchEvent(name) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent(name, true, true, null); - window.dispatchEvent(evt); - }, - - writeSetting: function ls_writeSetting(value) { - if (!window.navigator.mozSettings) - return; - - SettingsListener.getSettingsLock().set({ - 'lockscreen.locked': value - }); - }, - - setElasticEnabled: function ls_setElasticEnabled(value) { - clearInterval(this.elasticIntervalId); - if (value) { - this.elasticIntervalId = - setInterval(this.playElastic.bind(this), this.ELASTIC_INTERVAL); - } - }, - - playElastic: function ls_playElastic() { - if (this._touch && this._touch.touched) - return; - - var overlay = this.overlay; - var container = this.iconContainer; - - overlay.classList.add('elastic'); - container.addEventListener('animationend', function animationend(e) { - container.removeEventListener(e.type, animationend); - overlay.classList.remove('elastic'); - }); - } -}; - -// Bug 836195 - [Homescreen] Dock icons drop down in the UI -// consistently when using a lockcode and visiting camera -LockScreen.init(); - -navigator.mozL10n.ready(LockScreen.init.bind(LockScreen)); - diff --git a/apps/system/js/modal_dialog.js b/apps/system/js/modal_dialog.js deleted file mode 100644 index 33f3201..0000000 --- a/apps/system/js/modal_dialog.js +++ /dev/null @@ -1,443 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -// The modal dialog listen to mozbrowsershowmodalprompt event. -// Blocking the current app and then show cutom modal dialog -// (alert/confirm/prompt) - -var ModalDialog = { - // Used for element id access. - // e.g., 'modal-dialog-alert-ok' - prefix: 'modal-dialog-', - - // DOM - elements: {}, - - // Get all elements when inited. - getAllElements: function md_getAllElements() { - var elementsID = ['alert', 'alert-ok', 'alert-message', - 'prompt', 'prompt-ok', 'prompt-cancel', 'prompt-input', 'prompt-message', - 'confirm', 'confirm-ok', 'confirm-cancel', 'confirm-message', - 'select-one', 'select-one-cancel', 'select-one-menu', 'select-one-title', - 'alert-title', 'confirm-title', 'prompt-title']; - - var toCamelCase = function toCamelCase(str) { - return str.replace(/\-(.)/g, function replacer(str, p1) { - return p1.toUpperCase(); - }); - }; - - // Loop and add element with camel style name to Modal Dialog attribute. - elementsID.forEach(function createElementRef(name) { - this.elements[toCamelCase(name)] = - document.getElementById(this.prefix + name); - }, this); - - this.screen = document.getElementById('screen'); - this.overlay = document.getElementById('dialog-overlay'); - }, - - // Save the events returned by mozbrowsershowmodalprompt for later use. - // The events are stored according to webapp origin - // e.g., 'http://uitest.gaiamobile.org': evt - currentEvents: {}, - - init: function md_init() { - // Get all elements initially. - this.getAllElements(); - var elements = this.elements; - - // Bind events - window.addEventListener('mozbrowsershowmodalprompt', this); - window.addEventListener('appopen', this); - window.addEventListener('appwillclose', this); - window.addEventListener('appterminated', this); - window.addEventListener('resize', this); - window.addEventListener('keyboardchange', this); - window.addEventListener('keyboardhide', this); - window.addEventListener('home', this); - window.addEventListener('holdhome', this); - - for (var id in elements) { - var tagName = elements[id].tagName.toLowerCase(); - if (tagName == 'button' || tagName == 'ul') { - elements[id].addEventListener('click', this); - } - } - }, - - // Default event handler - handleEvent: function md_handleEvent(evt) { - var elements = this.elements; - switch (evt.type) { - case 'mozbrowsershowmodalprompt': - var frameType = evt.target.dataset.frameType; - if (frameType != 'window' && frameType != 'inline-activity') - return; - - evt.preventDefault(); - var origin = evt.target.dataset.frameOrigin; - this.currentEvents[origin] = evt; - - // Show modal dialog only if - // the frame is currently displayed. - if (origin == WindowManager.getDisplayedApp() || - frameType == 'inline-activity') - this.show(evt.target, origin); - break; - - case 'click': - if (evt.currentTarget === elements.confirmCancel || - evt.currentTarget === elements.promptCancel || - evt.currentTarget === elements.selectOneCancel) { - this.cancelHandler(); - } else if (evt.currentTarget === elements.selectOneMenu) { - this.selectOneHandler(evt.target); - } else { - this.confirmHandler(); - } - break; - - case 'appopen': - this.show(evt.target, evt.detail.origin); - break; - - case 'home': - case 'holdhome': - // Inline activity, which origin is different from foreground app - if (this.isVisible() && - this.currentOrigin != WindowManager.getDisplayedApp()) - this.cancelHandler(); - break; - - case 'appwillclose': - // Do nothing if the app is closed at background. - if (evt.detail.origin !== this.currentOrigin) - return; - - // Reset currentOrigin - this.hide(); - break; - - case 'appterminated': - if (this.currentEvents[evt.detail.origin]) - delete this.currentEvents[evt.detail.origin]; - - break; - - case 'resize': - case 'keyboardhide': - if (!this.currentOrigin) - return; - - this.setHeight(window.innerHeight - StatusBar.height); - break; - - case 'keyboardchange': - this.setHeight(window.innerHeight - - evt.detail.height - StatusBar.height); - break; - } - }, - - setHeight: function md_setHeight(height) { - if (this.isVisible()) - this.overlay.style.height = height + 'px'; - }, - - // Show relative dialog and set message/input value well - show: function md_show(target, origin) { - if (!(origin in this.currentEvents)) - return; - - var _ = navigator.mozL10n.get; - var evt = this.currentEvents[origin]; - this.currentOrigin = origin; - - var message = evt.detail.message || ''; - var elements = this.elements; - this.screen.classList.add('modal-dialog'); - - function escapeHTML(str) { - var span = document.createElement('span'); - span.textContent = str; - // Escape space for displaying multiple space in message. - span.innerHTML = span.innerHTML.replace(/\n/g, '<br/>'); - return span.innerHTML; - } - - var type = evt.detail.promptType || evt.detail.type; - if (type !== 'selectone') { - message = escapeHTML(message); - } - - switch (type) { - case 'alert': - elements.alertMessage.innerHTML = message; - elements.alert.classList.add('visible'); - this.setTitle('alert', ''); - elements.alertOk.textContent = evt.yesText ? evt.yesText : _('ok'); - break; - - case 'prompt': - elements.prompt.classList.add('visible'); - elements.promptInput.value = evt.detail.initialValue; - elements.promptMessage.innerHTML = message; - this.setTitle('prompt', ''); - elements.promptOk.textContent = evt.yesText ? evt.yesText : _('ok'); - elements.promptCancel.textContent = evt.noText ? - evt.noText : _('cancel'); - break; - - case 'confirm': - elements.confirm.classList.add('visible'); - elements.confirmMessage.innerHTML = message; - this.setTitle('confirm', ''); - elements.confirmOk.textContent = evt.yesText ? evt.yesText : _('ok'); - elements.confirmCancel.textContent = evt.noText ? - evt.noText : _('cancel'); - break; - - case 'selectone': - this.buildSelectOneDialog(message); - elements.selectOne.classList.add('visible'); - break; - } - - this.setHeight(window.innerHeight - StatusBar.height); - }, - - hide: function md_hide() { - var evt = this.currentEvents[this.currentOrigin]; - var type = evt.detail.promptType; - if (type == 'prompt') { - this.elements.promptInput.blur(); - } - this.currentOrigin = null; - this.screen.classList.remove('modal-dialog'); - this.elements[type].classList.remove('visible'); - }, - - setTitle: function md_setTitle(type, title) { - this.elements[type + 'Title'].textContent = title; - }, - - // When user clicks OK button on alert/confirm/prompt - confirmHandler: function md_confirmHandler() { - this.screen.classList.remove('modal-dialog'); - var elements = this.elements; - - var evt = this.currentEvents[this.currentOrigin]; - - var type = evt.detail.promptType || evt.detail.type; - switch (type) { - case 'alert': - elements.alert.classList.remove('visible'); - break; - - case 'prompt': - evt.detail.returnValue = elements.promptInput.value; - elements.prompt.classList.remove('visible'); - break; - - case 'confirm': - evt.detail.returnValue = true; - elements.confirm.classList.remove('visible'); - break; - } - - if (evt.isPseudo && evt.callback) { - evt.callback(evt.detail.returnValue); - } - - if (evt.detail.unblock) - evt.detail.unblock(); - - delete this.currentEvents[this.currentOrigin]; - }, - - // When user clicks cancel button on confirm/prompt or - // when the user try to escape the dialog with the escape key - cancelHandler: function md_cancelHandler() { - var evt = this.currentEvents[this.currentOrigin]; - this.screen.classList.remove('modal-dialog'); - var elements = this.elements; - - var type = evt.detail.promptType || evt.detail.type; - switch (type) { - case 'alert': - elements.alert.classList.remove('visible'); - break; - - case 'prompt': - /* return null when click cancel */ - evt.detail.returnValue = null; - elements.prompt.classList.remove('visible'); - break; - - case 'confirm': - /* return false when click cancel */ - evt.detail.returnValue = false; - elements.confirm.classList.remove('visible'); - break; - - case 'selectone': - /* return null when click cancel */ - evt.detail.returnValue = null; - elements.selectOne.classList.remove('visible'); - break; - } - - if (evt.isPseudo && evt.cancelCallback) { - evt.cancelCallback(evt.detail.returnValue); - } - - if (evt.detail.unblock) - evt.detail.unblock(); - - delete this.currentEvents[this.currentOrigin]; - }, - - // When user selects an option on selectone dialog - selectOneHandler: function md_confirmHandler(target) { - this.screen.classList.remove('modal-dialog'); - var elements = this.elements; - - var evt = this.currentEvents[this.currentOrigin]; - - evt.detail.returnValue = target.id; - elements.selectOne.classList.remove('visible'); - - if (evt.isPseudo && evt.callback) { - evt.callback(evt.detail.returnValue); - } - - if (evt.detail.unblock) - evt.detail.unblock(); - - delete this.currentEvents[this.currentOrigin]; - }, - - buildSelectOneDialog: function md_buildSelectOneDialog(data) { - var elements = this.elements; - elements.selectOneTitle.textContent = data.title; - elements.selectOneMenu.innerHTML = ''; - - if (!data.options) { - return; - } - - var itemsHTML = []; - for (var i = 0; i < data.options.length; i++) { - itemsHTML.push('<li><button id="'); - itemsHTML.push(data.options[i].id); - itemsHTML.push('">'); - itemsHTML.push(data.options[i].text); - itemsHTML.push('</button></li>'); - } - - elements.selectOneMenu.innerHTML = itemsHTML.join(''); - }, - - /** - * Method about customized alert - * @param {String} title the title of the dialog. null or empty for - * no title. - * @param {String} text message for the dialog. - * @param {Object} confirm {title, callback} object when confirm. - */ - alert: function md_alert(title, text, confirm) { - this.showWithPseudoEvent({ - type: 'alert', - text: text, - callback: confirm.callback, - title: title, - yesText: confirm.title - }); - }, - - /** - * Method about customized confirm - * @param {String} title the title of the dialog. null or empty for - * no title. - * @param {String} text message for the dialog. - * @param {Object} confirm {title, callback} object when confirm. - * @param {Object} cancel {title, callback} object when cancel. - */ - confirm: function md_confirm(title, text, confirm, cancel) { - this.showWithPseudoEvent({ - type: 'confirm', - text: text, - callback: confirm.callback, - cancel: cancel.callback, - title: title, - yesText: confirm.title, - noText: cancel.title - }); - }, - - /** - * Method about customized prompt - * @param {String} title the title of the dialog. null or empty for - * no title. - * @param {String} text message for the dialog. - * @param {String} default_value message in the text field. - * @param {Object} confirm {title, callback} object when confirm. - * @param {Object} cancel {title, callback} object when cancel. - */ - prompt: function md_prompt(title, text, default_value, confirm, cancel) { - this.showWithPseudoEvent({ - type: 'prompt', - text: text, - initialValue: default_value, - callback: confirm.callback, - cancel: cancel.callback, - title: title, - yesText: confirm.title, - noText: cancel.title - }); - }, - - selectOne: function md_selectOne(data, callback) { - this.showWithPseudoEvent({ - type: 'selectone', - text: data, - callback: callback - }); - }, - - showWithPseudoEvent: function md_showWithPseudoEvent(config) { - var pseudoEvt = { - isPseudo: true, - detail: { - unblock: null - } - }; - - pseudoEvt.detail.message = config.text; - pseudoEvt.callback = config.callback; - pseudoEvt.detail.promptType = config.type; - pseudoEvt.cancelCallback = config.cancel; - pseudoEvt.yesText = config.yesText; - pseudoEvt.noText = config.noText; - if (config.type == 'prompt') { - pseudoEvt.detail.initialValue = config.initialValue; - } - - // Create a virtual mapping in this.currentEvents, - // since system-app uses the different way to call ModalDialog. - this.currentEvents['system'] = pseudoEvt; - this.show(null, 'system'); - if (config.title) - this.setTitle(config.type, config.title); - }, - - isVisible: function md_isVisible() { - return this.screen.classList.contains('modal-dialog'); - } -}; - -ModalDialog.init(); - diff --git a/apps/system/js/mouse2touch.js b/apps/system/js/mouse2touch.js deleted file mode 100644 index b9d6a89..0000000 --- a/apps/system/js/mouse2touch.js +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -/* -* Mouse2Touch is a shim that listens to MouseEvent but passes -* fake TouchEvent object to touch event handler -* -* XXX: remove this if we are not going to support testing on -* non-touch devices, e.g. B2G Desktop, Nightly, or, -* make the creation of this object optional if we can reliably detect -* touch support by evaluate (document instanceof DocumentTouch) -* -*/ -var Mouse2Touch = (function m2t() { - var Mouse2TouchEvent = { - 'mousedown': 'touchstart', - 'mousemove': 'touchmove', - 'mouseup': 'touchend' - }; - - var Touch2MouseEvent = { - 'touchstart': 'mousedown', - 'touchmove': 'mousemove', - 'touchend': 'mouseup' - }; - - var ForceOnWindow = { - 'touchmove': true, - 'touchend': true - }; - - var addEventHandler = function m2t_addEventHandlers(target, - name, - listener) { - target = ForceOnWindow[name] ? window : target; - name = Touch2MouseEvent[name] || name; - target.addEventListener(name, { - handleEvent: function m2t_handleEvent(evt) { - if (Mouse2TouchEvent[evt.type]) { - var original = evt; - evt = { - type: Mouse2TouchEvent[original.type], - target: original.target, - touches: [original], - preventDefault: function() { - original.preventDefault(); - } - }; - evt.changedTouches = evt.touches; - } - return listener.handleEvent(evt); - } - }, true); - }; - - var removeEventHandler = function m2t_removeEventHandler(target, - name, - listener) { - target = ForceOnWindow[name] ? window : target; - name = Touch2MouseEvent[name] || name; - target.removeEventListener(name, listener); - }; - - return { - addEventHandler: addEventHandler, - removeEventHandler: removeEventHandler - }; -})(); diff --git a/apps/system/js/notifications.js b/apps/system/js/notifications.js deleted file mode 100644 index dae4ab4..0000000 --- a/apps/system/js/notifications.js +++ /dev/null @@ -1,410 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -(function appCacheIcons() { - // Caching the icon for notification if appCache is in effect - var appCache = window.applicationCache; - if (!appCache) - return; - - var addIcons = function addIcons(app) { - var icons = app.manifest.icons; - if (icons) { - Object.keys(icons).forEach(function iconIterator(key) { - var url = app.origin + icons[key]; - appCache.mozAdd(url); - }); - } - }; - - var removeIcons = function removeIcons(app) { - var icons = app.manifest.icons; - if (icons) { - Object.keys(icons).forEach(function iconIterator(key) { - var url = app.origin + icons[key]; - appCache.mozRemove(url); - }); - } - }; - - window.addEventListener('applicationinstall', function bsm_oninstall(evt) { - addIcons(evt.detail.application); - }); - - window.addEventListener('applicationuninstall', function bsm_oninstall(evt) { - removeIcons(evt.detail.application); - }); -}()); - -var NotificationScreen = { - TOASTER_TIMEOUT: 5000, - TRANSITION_SPEED: 1.8, - TRANSITION_FRACTION: 0.30, - - _notification: null, - _containerWidth: null, - _toasterTimeout: null, - _toasterGD: null, - - lockscreenPreview: true, - silent: false, - alerts: true, - vibrates: true, - - init: function ns_init() { - window.addEventListener('mozChromeEvent', this); - this.container = - document.getElementById('desktop-notifications-container'); - this.lockScreenContainer = - document.getElementById('notifications-lockscreen-container'); - this.toaster = document.getElementById('notification-toaster'); - this.toasterIcon = document.getElementById('toaster-icon'); - this.toasterTitle = document.getElementById('toaster-title'); - this.toasterDetail = document.getElementById('toaster-detail'); - this.clearAllButton = document.getElementById('notification-clear'); - - this._toasterGD = new GestureDetector(this.toaster); - ['tap', 'mousedown', 'swipe'].forEach(function(evt) { - this.container.addEventListener(evt, this); - this.toaster.addEventListener(evt, this); - }, this); - - this.clearAllButton.addEventListener('click', this.clearAll.bind(this)); - - // will hold the count of external contributors to the notification - // screen - this.externalNotificationsCount = 0; - - window.addEventListener('utilitytrayshow', this); - window.addEventListener('unlock', this.clearLockScreen.bind(this)); - window.addEventListener('mozvisibilitychange', this); - window.addEventListener('appopen', this.handleAppopen.bind(this)); - - this._sound = 'style/notifications/ringtones/notifier_exclamation.ogg'; - - var self = this; - SettingsListener.observe('notification.ringtone', '', function(value) { - self._sound = value; - }); - }, - - handleEvent: function ns_handleEvent(evt) { - switch (evt.type) { - case 'mozChromeEvent': - var detail = evt.detail; - if (detail.type !== 'desktop-notification') - return; - - this.addNotification(detail); - break; - case 'tap': - var target = evt.target; - this.tap(target); - break; - case 'mousedown': - this.mousedown(evt); - break; - case 'swipe': - this.swipe(evt); - break; - case 'utilitytrayshow': - this.updateTimestamps(); - StatusBar.updateNotificationUnread(false); - break; - case 'mozvisibilitychange': - //update timestamps in lockscreen notifications - if (!document.mozHidden) { - this.updateTimestamps(); - } - break; - } - }, - - handleAppopen: function ns_handleAppopen(evt) { - var manifestURL = evt.detail.manifestURL, - selector = '[data-manifest-u-r-l="' + manifestURL + '"]'; - - var nodes = this.container.querySelectorAll(selector); - - for (var i = nodes.length - 1; i >= 0; i--) { - this.closeNotification(nodes[i]); - } - }, - - // Swipe handling - mousedown: function ns_mousedown(evt) { - if (!evt.target.dataset.notificationID) - return; - - evt.preventDefault(); - this._notification = evt.target; - this._containerWidth = this.container.clientWidth; - }, - - swipe: function ns_swipe(evt) { - var detail = evt.detail; - var distance = detail.start.screenX - detail.end.screenX; - var fastEnough = Math.abs(detail.vx) > this.TRANSITION_SPEED; - var farEnough = Math.abs(distance) > - this._containerWidth * this.TRANSITION_FRACTION; - - // We only remove the notification if the swipe was - // - left to right - // - far or fast enough - if ((distance > 0) || - !(farEnough || fastEnough)) { - // Werent far or fast enough to delete, restore - delete this._notification; - return; - } - - this._notification.classList.add('disappearing'); - - var notification = this._notification; - this._notification = null; - - var toaster = this.toaster; - var self = this; - notification.addEventListener('transitionend', function trListener() { - notification.removeEventListener('transitionend', trListener); - - self.closeNotification(notification); - - if (notification != toaster) - return; - - // Putting back the toaster in a clean state for the next notification - toaster.style.display = 'none'; - setTimeout(function nextLoop() { - toaster.style.MozTransition = ''; - toaster.style.MozTransform = ''; - toaster.classList.remove('displayed'); - toaster.classList.remove('disappearing'); - - setTimeout(function nextLoop() { - toaster.style.display = 'block'; - }); - }); - }); - }, - - tap: function ns_tap(notificationNode) { - var notificationID = notificationNode.dataset.notificationID; - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, { - type: 'desktop-notification-click', - id: notificationID - }); - window.dispatchEvent(event); - - this.removeNotification(notificationNode.dataset.notificationID, false); - - if (notificationNode == this.toaster) { - this.toaster.classList.remove('displayed'); - } else { - UtilityTray.hide(); - } - }, - - updateTimestamps: function ns_updateTimestamps() { - var timestamps = document.getElementsByClassName('timestamp'); - for (var i = 0, l = timestamps.length; i < l; i++) { - timestamps[i].textContent = - this.prettyDate(new Date(timestamps[i].dataset.timestamp)); - } - }, - - /** - * Display a human-readable relative timestamp. - */ - prettyDate: function prettyDate(time) { - var date; - if (navigator.mozL10n) { - date = navigator.mozL10n.DateTimeFormat().fromNow(time, true); - } else { - date = time.toLocaleFormat(); - } - return date; - }, - - addNotification: function ns_addNotification(detail) { - var notificationNode = document.createElement('div'); - notificationNode.className = 'notification'; - - notificationNode.dataset.notificationID = detail.id; - notificationNode.dataset.manifestURL = detail.manifestURL; - - if (detail.icon) { - var icon = document.createElement('img'); - icon.src = detail.icon; - notificationNode.appendChild(icon); - this.toasterIcon.src = detail.icon; - this.toasterIcon.hidden = false; - } else { - this.toasterIcon.hidden = true - } - - var time = document.createElement('span'); - var timestamp = new Date(); - time.classList.add('timestamp'); - time.dataset.timestamp = timestamp; - time.textContent = this.prettyDate(timestamp); - notificationNode.appendChild(time); - - var title = document.createElement('div'); - title.textContent = detail.title; - notificationNode.appendChild(title); - - this.toasterTitle.textContent = detail.title; - - var message = document.createElement('div'); - message.classList.add('detail'); - message.textContent = detail.text; - notificationNode.appendChild(message); - - this.toasterDetail.textContent = detail.text; - - this.container.insertBefore(notificationNode, - this.container.firstElementChild); - new GestureDetector(notificationNode).startDetecting(); - - // We turn the screen on if needed in order to let - // the user see the notification toaster - if (typeof(ScreenManager) !== 'undefined' && - !ScreenManager.screenEnabled) { - ScreenManager.turnScreenOn(); - } - - this.updateStatusBarIcon(true); - - // Notification toaster - if (this.lockscreenPreview || !LockScreen.locked) { - this.toaster.dataset.notificationID = detail.id; - - this.toaster.classList.add('displayed'); - this._toasterGD.startDetecting(); - - if (this._toasterTimeout) - clearTimeout(this._toasterTimeout); - - this._toasterTimeout = setTimeout((function() { - this.toaster.classList.remove('displayed'); - this._toasterTimeout = null; - this._toasterGD.stopDetecting(); - }).bind(this), this.TOASTER_TIMEOUT); - } - - // Adding it to the lockscreen if locked and the privacy setting - // does not prevent it. - if (typeof(LockScreen) !== 'undefined' && - LockScreen.locked && this.lockscreenPreview) { - var lockScreenNode = notificationNode.cloneNode(true); - this.lockScreenContainer.insertBefore(lockScreenNode, - this.lockScreenContainer.firstElementChild); - } - - if (this.alerts && !this.silent) { - var ringtonePlayer = new Audio(); - ringtonePlayer.src = this._sound; - ringtonePlayer.mozAudioChannelType = 'notification'; - ringtonePlayer.play(); - window.setTimeout(function smsRingtoneEnder() { - ringtonePlayer.pause(); - ringtonePlayer.src = ''; - }, 2000); - } - - if (this.vibrates) { - if (document.mozHidden) { - window.addEventListener('mozvisibilitychange', function waitOn() { - window.removeEventListener('mozvisibilitychange', waitOn); - navigator.vibrate([200, 200, 200, 200]); - }); - } else { - navigator.vibrate([200, 200, 200, 200]); - } - } - - return notificationNode; - }, - - closeNotification: function ns_closeNotification(notificationNode) { - var notificationID = notificationNode.dataset.notificationID; - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, { - type: 'desktop-notification-close', - id: notificationID - }); - window.dispatchEvent(event); - - this.removeNotification(notificationNode.dataset.notificationID); - }, - - removeNotification: function ns_removeNotification(notificationID) { - var notifSelector = '[data-notification-i-d="' + notificationID + '"]'; - var notificationNode = this.container.querySelector(notifSelector); - - notificationNode.parentNode.removeChild(notificationNode); - this.updateStatusBarIcon(); - }, - - clearAll: function ns_clearAll() { - while (this.container.firstElementChild) { - this.closeNotification(this.container.firstElementChild); - } - }, - - clearLockScreen: function ns_clearLockScreen() { - while (this.lockScreenContainer.firstElementChild) { - var element = this.lockScreenContainer.firstElementChild; - this.lockScreenContainer.removeChild(element); - } - }, - - updateStatusBarIcon: function ns_updateStatusBarIcon(unread) { - var nbTotalNotif = this.container.children.length + - this.externalNotificationsCount; - StatusBar.updateNotification(nbTotalNotif); - - if (unread) - StatusBar.updateNotificationUnread(true); - }, - - incExternalNotifications: function ns_incExternalNotifications() { - this.externalNotificationsCount++; - this.updateStatusBarIcon(true); - }, - - decExternalNotifications: function ns_decExternalNotifications() { - this.externalNotificationsCount--; - if (this.externalNotificationsCount < 0) { - this.externalNotificationsCount = 0; - } - this.updateStatusBarIcon(); - } - -}; - -NotificationScreen.init(); - -SettingsListener.observe( - 'lockscreen.notifications-preview.enabled', true, function(value) { - - NotificationScreen.lockscreenPreview = value; -}); - -SettingsListener.observe('alert-sound.enabled', true, function(value) { - NotificationScreen.alerts = value; -}); - -SettingsListener.observe('ring.enabled', true, function(value) { - NotificationScreen.silent = !value; -}); - -SettingsListener.observe('alert-vibration.enabled', true, function(value) { - NotificationScreen.vibrates = value; -}); diff --git a/apps/system/js/operator_variant/operator_variant.js b/apps/system/js/operator_variant/operator_variant.js deleted file mode 100644 index 13ad257..0000000 --- a/apps/system/js/operator_variant/operator_variant.js +++ /dev/null @@ -1,168 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -(function OperatorVariant() { - /** - * Get the mcc/mnc info that has been stored in the settings. - */ - - var settings = window.navigator.mozSettings; - if (!settings) - return; - - var iccSettings = { mcc: -1, mnc: -1 }; - - // Read the mcc/mnc settings, then trigger callback. - function getICCSettings(callback) { - var transaction = settings.createLock(); - var mccKey = 'operatorvariant.mcc'; - var mncKey = 'operatorvariant.mnc'; - - var mccRequest = transaction.get(mccKey); - mccRequest.onsuccess = function() { - iccSettings.mcc = parseInt(mccRequest.result[mccKey], 10) || 0; - var mncRequest = transaction.get(mncKey); - mncRequest.onsuccess = function() { - iccSettings.mnc = parseInt(mncRequest.result[mncKey], 10) || 0; - callback(); - }; - }; - } - - - /** - * Compare the cached mcc/mnc info with the one in the SIM card, - * and retrieve/apply APN settings if they differ. - */ - - var mobileConnection = window.navigator.mozMobileConnection; - if (!mobileConnection) - return; - - // Check the mcc/mnc information on the SIM card. - function checkICCInfo() { - if (!mobileConnection.iccInfo || mobileConnection.cardState !== 'ready') - return; - - // ensure that the iccSettings have been retrieved - if ((iccSettings.mcc < 0) || (iccSettings.mnc < 0)) - return; - - // XXX sometimes we get 0/0 for mcc/mnc, even when cardState === 'ready'... - var mcc = parseInt(mobileConnection.iccInfo.mcc, 10) || 0; - var mnc = parseInt(mobileConnection.iccInfo.mnc, 10) || 0; - if (!mcc || !mnc) - return; - - // same SIM card => do nothing - if ((mcc == iccSettings.mcc) && (mnc == iccSettings.mnc)) - return; - - // new SIM card => cache iccInfo, load and apply new APN settings - iccSettings.mcc = mcc; - iccSettings.mnc = mnc; - retrieveOperatorVariantSettings(applyOperatorVariantSettings); - }; - - // Load and query APN database, then trigger callback on results. - function retrieveOperatorVariantSettings(callback) { - var OPERATOR_VARIANT_FILE = 'shared/resources/apn.json'; - - var xhr = new XMLHttpRequest(); - xhr.open('GET', OPERATOR_VARIANT_FILE, true); - xhr.responseType = 'json'; - xhr.onreadystatechange = function() { - if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status === 0)) { - var apn = xhr.response; - var mcc = iccSettings.mcc; - var mnc = iccSettings.mnc; - // get a list of matching APNs - var compatibleAPN = apn[mcc] ? (apn[mcc][mnc] || []) : []; - callback(compatibleAPN); - } - }; - xhr.send(); - } - - // Store APN settings for the first carrier matching the mcc/mnc info. - function applyOperatorVariantSettings(result) { - var apnPrefNames = { - 'default': { - 'ril.data.carrier': 'carrier', - 'ril.data.apn': 'apn', - 'ril.data.user': 'user', - 'ril.data.passwd': 'password', - 'ril.data.httpProxyHost': 'proxy', - 'ril.data.httpProxyPort': 'port' - }, - 'supl': { - 'ril.supl.carrier': 'carrier', - 'ril.supl.apn': 'apn', - 'ril.supl.user': 'user', - 'ril.supl.passwd': 'password', - 'ril.supl.httpProxyHost': 'proxy', - 'ril.supl.httpProxyPort': 'port' - }, - 'mms': { - 'ril.mms.carrier': 'carrier', - 'ril.mms.apn': 'apn', - 'ril.mms.user': 'user', - 'ril.mms.passwd': 'password', - 'ril.mms.httpProxyHost': 'proxy', - 'ril.mms.httpProxyPort': 'port', - 'ril.mms.mmsc': 'mmsc', - 'ril.mms.mmsproxy': 'mmsproxy', - 'ril.mms.mmsport': 'mmsport' - }, - 'operatorvariant': { - 'ril.iccInfo.mbdn': 'voicemail', - 'ril.sms.strict7BitEncoding.enabled': 'enableStrict7BitEncodingForSms', - 'ril.cellbroadcast.searchlist': 'cellBroadcastSearchList' - } - }; - - var booleanPrefNames = [ - 'ril.sms.strict7BitEncoding.enabled' - ]; - - // store relevant APN settings - var transaction = settings.createLock(); - for (var type in apnPrefNames) { - var apn = {}; - for (var i = 0; i < result.length; i++) { - if (result[i] && result[i].type.indexOf(type) != -1) { - apn = result[i]; - break; - } - } - var prefNames = apnPrefNames[type]; - for (var key in prefNames) { - var name = apnPrefNames[type][key]; - var item = {}; - if (booleanPrefNames.indexOf(key) != -1) { - item[key] = apn[name] || false; - } else { - item[key] = apn[name] || ''; - } - transaction.set(item); - } - } - - // store the current mcc/mnc info in the settings - transaction.set({ - 'operatorvariant.mcc': iccSettings.mcc, - 'operatorvariant.mnc': iccSettings.mnc - }); - } - - - /** - * Check the APN settings on startup and when the SIM card is changed. - */ - - getICCSettings(checkICCInfo); - mobileConnection.addEventListener('iccinfochange', checkICCInfo); -})(); - diff --git a/apps/system/js/payment.js b/apps/system/js/payment.js deleted file mode 100644 index a953f5c..0000000 --- a/apps/system/js/payment.js +++ /dev/null @@ -1,151 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -// TODO: Blocked by [Payment] UX and visuals for the payment request -// confirmation screen https://github.com/mozilla-b2g/gaia/issues/2692 - -'use strict'; - -const kPaymentConfirmationScreen = '../payment.html'; - -var Payment = { - chromeEventId: null, - trustedUILayers: {}, - - init: function init() { - window.addEventListener('mozChromeEvent', this); - }, - - handleEvent: function onMozChromeEvent(e) { - // We save the mozChromeEvent identifiers to send replies back from content - // with this exact value. - this.chromeEventId = e.detail.id; - if (!this.chromeEventId) - return; - - var requestId = e.detail.requestId; - - switch (e.detail.type) { - // Chrome asks Gaia to show the payment request confirmation dialog. - case 'open-payment-confirmation-dialog': - var requests = e.detail.paymentRequests; - if (!requests) - return; - - var returnSelection = (function returnSelection(selection) { - if (!selection) - return; - - this._dispatchEvent({ - id: this.chromeEventId, - userSelection: selection - }); - }).bind(this); - - // If there is only one request, we skip the confirmation dialog and - // send the request type back to the chrome as a user selection, so - // the payment flow can continue. - if (requests.length == 1) { - returnSelection(requests[0].type); - return; - } - - var frame = document.createElement('iframe'); - frame.setAttribute('mozbrowser', 'true'); - frame.setAttribute('remote', true); - frame.classList.add('screen'); - frame.src = kPaymentConfirmationScreen; - frame.addEventListener('mozbrowserloadend', function addReqs(evt) { - var frame = evt.target; - if (!frame || !requests) - return; - - // TODO: Temp layout until issue #2692 is solved. - var frameDocument = frame.contentWindow.document; - var requestsList = frameDocument.getElementById('requests') - .getElementsByTagName('ul')[0]; - for (var i in requests) { - var requestElement = frameDocument.createElement('li'); - var button = frameDocument.createElement('button'); - button.setAttribute('value', requests[i].type); - var requestText = 'Pay with ' + requests[i].providerName + '\n' + - requests[i].productName + '\n' + - requests[i].productDescription + '\n' + - requests[i].productPrice[0].amount + ' ' + - requests[i].productPrice[0].currency; - button.appendChild(frameDocument.createTextNode(requestText)); - button.onclick = function selectRequest() { - // We send the selected request back to Chrome so it can start - // the appropriate payment flow. - returnSelection(this.getAttribute('value')); - }; - requestElement.appendChild(button); - requestsList.appendChild(requestElement); - } - }); - - this._openTrustedUI(frame); - break; - - // Chrome asks Gaia to show the payment flow according to the - // payment request selected by the user. - case 'open-payment-flow-dialog': - if (!e.detail.uri) - return; - - // TODO: For now, known payment providers (BlueVia and Mozilla Market) - // only accepts the JWT by GET, so we just add it to the URI. - e.detail.uri += e.detail.jwt; - - this.trustedUILayers[requestId] = this.chromeEventId; - - var frame = document.createElement('iframe'); - frame.setAttribute('mozbrowser', 'true'); - frame.classList.add('screen'); - frame.src = e.detail.uri; - frame.addEventListener('mozbrowserloadstart', (function loadStart(evt) { - // After creating the new frame containing the payment provider buy - // flow, we send it back to chrome so the payment callbacks can be - // injected. - this._dispatchEvent({ - id: this.chromeEventId, - frame: evt.target - }); - }).bind(this)); - - // The payment flow is shown within the trusted UI - this._openTrustedUI(frame); - break; - - case 'close-payment-flow-dialog': - TrustedUIManager.close(this.trustedUILayers[requestId], - (function dialogClosed() { - this._dispatchEvent({ id: this.chromeEventId }); - delete this.trustedUILayers[requestId]; - }).bind(this)); - break; - } - }, - - _openTrustedUI: function _openTrustedUI(frame) { - // The payment flow is shown within the trusted UI with the name of - // the mozPay caller application as title. - var title = WindowManager.getCurrentDisplayedApp().name; - title = title ? title : navigator.mozL10n.get('payment-flow'); - TrustedUIManager.open(title, frame, this.chromeEventId); - }, - - _dispatchEvent: function _dispatchEvent(obj) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, obj); - window.dispatchEvent(event); - } -}; - -// Make sure L10n is ready before init -if (navigator.mozL10n.readyState == 'complete' || - navigator.mozL10n.readyState == 'interactive') { - Payment.init(); -} else { - window.addEventListener('localized', Payment.init.bind(Payment)); -} diff --git a/apps/system/js/permission_manager.js b/apps/system/js/permission_manager.js deleted file mode 100644 index f3c013c..0000000 --- a/apps/system/js/permission_manager.js +++ /dev/null @@ -1,203 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var PermissionManager = (function() { - var _ = navigator.mozL10n.get; - - window.addEventListener('mozChromeEvent', function pm_chromeEventHandler(e) { - var detail = e.detail; - switch (detail.type) { - case 'permission-prompt': - overlay.dataset.type = detail.permission; - handlePermissionPrompt(detail); - break; - case 'fullscreenoriginchange': - delete overlay.dataset.type; - handleFullscreenOriginChange(detail); - break; - } - }); - - var fullscreenRequest = undefined; - - var handleFullscreenOriginChange = function(detail) { - // If there's already a fullscreen request visible, cancel it, - // we'll show the request for the new domain. - if (fullscreenRequest != undefined) { - cancelRequest(fullscreenRequest); - fullscreenRequest = undefined; - } - if (detail.fullscreenorigin != WindowManager.getDisplayedApp()) { - // The message to be displayed on the approval UI. - var message = _('fullscreen-request', { 'origin': detail.fullscreenorigin }); - fullscreenRequest = requestPermission(message, - /* yesCallback */ null, - /* noCallback */ function() { - document.mozCancelFullScreen(); - }); - } - }; - - var handlePermissionPrompt = function pm_handlePermissionPrompt(detail) { - remember.checked = detail.remember ? true : false; - var str = ''; - - var permissionID = 'perm-' + detail.permission.replace(':', '-'); - if (detail.isApp) { // App - str = _(permissionID + '-appRequest', { 'app': detail.appName }); - } else { // Web content - str = _(permissionID + '-webRequest', { 'site': detail.origin }); - } - - requestPermission(str, function pm_permYesCB() { - dispatchResponse(detail.id, 'permission-allow', remember.checked); - }, function pm_permNoCB() { - dispatchResponse(detail.id, 'permission-deny', remember.checked); - }); - }; - - var dispatchResponse = function pm_dispatchResponse(id, type, remember) { - var event = document.createEvent('CustomEvent'); - remember = remember ? true : false; - - event.initCustomEvent('mozContentEvent', true, true, { - id: id, - type: type, - remember: remember - }); - window.dispatchEvent(event); - }; - - // A queue of pending requests. Callers of requestPermission() must be - // careful not to create an infinite loop! - var pending = []; - - // Div over in which the permission UI resides. - var overlay = document.getElementById('permission-screen'); - var dialog = document.getElementById('permission-dialog'); - var message = document.getElementById('permission-message'); - - // "Yes"/"No" buttons on the permission UI. - var yes = document.getElementById('permission-yes'); - var no = document.getElementById('permission-no'); - - // Remember the choice checkbox - var remember = document.getElementById('permission-remember-checkbox'); - var rememberSection = document.getElementById('permission-remember-section'); - - // The ID of the next permission request. This is incremented by one - // on every request, modulo some large number to prevent overflow problems. - var nextRequestID = 0; - - // The ID of the request currently visible on the screen. This has the value - // "undefined" when there is no request visible on the screen. - var currentRequestId = undefined; - - var hidePermissionPrompt = function() { - overlay.classList.remove('visible'); - currentRequestId = undefined; - // Cleanup the event handlers. - yes.removeEventListener('click', clickHandler); - yes.callback = null; - no.removeEventListener('click', clickHandler); - no.callback = null; - }; - - // Show the next request, if we have one. - var showNextPendingRequest = function() { - if (pending.length == 0) - return; - var request = pending.shift(); - showPermissionPrompt(request.id, - request.message, - request.yescallback, - request.nocallback); - }; - - // This is the event listener function for the yes/no buttons. - var clickHandler = function(evt) { - var callback = null; - if (evt.target === yes && yes.callback) { - callback = yes.callback; - } else if (evt.target === no && no.callback) { - callback = no.callback; - } - hidePermissionPrompt(); - - // Call the appropriate callback, if it is defined. - if (callback) - window.setTimeout(callback, 0); - - showNextPendingRequest(); - }; - - var requestPermission = function(msg, - yescallback, nocallback) { - var id = nextRequestID; - nextRequestID = (nextRequestID + 1) % 1000000; - - if (currentRequestId != undefined) { - // There is already a permission request being shown, queue this one. - pending.push({ - id: id, - message: msg, - yescallback: yescallback, - nocallback: nocallback - }); - return id; - } - - showPermissionPrompt(id, msg, yescallback, nocallback); - - return id; - }; - - var showPermissionPrompt = function(id, msg, - yescallback, nocallback) { - // Put the message in the dialog. - // Note plain text since this may include text from - // untrusted app manifests, for example. - message.textContent = msg; - - currentRequestId = id; - - // Make the screen visible - overlay.classList.add('visible'); - - // Set event listeners for the yes and no buttons - yes.addEventListener('click', clickHandler); - yes.callback = yescallback; - - no.addEventListener('click', clickHandler); - no.callback = nocallback; - }; - - // Cancels a request with a specfied id. Request can either be - // currently showing, or pending. If there are further pending requests, - // the next is shown. - var cancelRequest = function(id) { - if (currentRequestId === id) { - // Request is currently being displayed. Hide the permission prompt, - // and show the next request, if we have any. - hidePermissionPrompt(); - showNextPendingRequest(); - } else { - // The request is currently not being displayed. Search through the - // list of pending requests, and remove it from the list if present. - for (var i = 0; i < pending.length; i++) { - if (pending[i].id === id) { - pending.splice(i, 1); - break; - } - } - } - }; - - rememberSection.addEventListener('click', function onLabelClick() { - remember.checked = !remember.checked; - }); - -}()); - diff --git a/apps/system/js/popup_manager.js b/apps/system/js/popup_manager.js deleted file mode 100644 index 583c9c8..0000000 --- a/apps/system/js/popup_manager.js +++ /dev/null @@ -1,313 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - -var PopupManager = { - _currentPopup: {}, - _currentOrigin: '', - _endTimes: 0, - _startTimes: 0, - - throbber: document.getElementById('popup-throbber'), - - overlay: document.getElementById('dialog-overlay'), - - popupContainer: document.getElementById('popup-container'), - - container: document.getElementById('frame-container'), - - screen: document.getElementById('screen'), - - closeButton: document.getElementById('popup-close'), - - errorTitle: document.getElementById('popup-error-title'), - - errorMessage: document.getElementById('popup-error-message'), - - errorReload: document.getElementById('popup-error-reload'), - - errorBack: document.getElementById('popup-error-back'), - - init: function pm_init() { - this.title = document.getElementById('popup-title'); - window.addEventListener('mozbrowseropenwindow', this); - window.addEventListener('mozbrowserclose', this); - window.addEventListener('appwillclose', this); - window.addEventListener('appopen', this); - window.addEventListener('appterminated', this); - window.addEventListener('home', this); - window.addEventListener('keyboardhide', this); - window.addEventListener('keyboardchange', this); - this.closeButton.addEventListener('click', this); - this.errorReload.addEventListener('click', this); - this.errorBack.addEventListener('click', this); - }, - - open: function pm_open(frame, origin) { - // Only one popup per origin at a time. - // If the popup is being shown, we swap frames. - if (this._currentPopup[origin]) { - this.container.removeChild(this._currentPopup[origin]); - delete this._currentPopup[origin]; - } - - this.title.textContent = this.getTitleFromUrl(frame.dataset.url); - - // Reset overlay height - this.setHeight(window.innerHeight - StatusBar.height); - - this._currentPopup[origin] = frame; - - var popup = this._currentPopup[origin]; - var dataset = popup.dataset; - dataset.frameType = 'popup'; - dataset.frameName = name; - dataset.frameOrigin = origin; - - // this seems needed, or an override to origin in close() - this._currentOrigin = origin; - - this.container.appendChild(popup); - - this.screen.classList.add('popup'); - - popup.addEventListener('mozbrowsererror', this); - popup.addEventListener('mozbrowserloadend', this); - popup.addEventListener('mozbrowserloadstart', this); - popup.addEventListener('mozbrowserlocationchange', this); - }, - - close: function pm_close(evt) { - if (evt && (!'frameType' in evt.target.dataset || - evt.target.dataset.frameType !== 'popup')) - return; - - var self = this; - this.popupContainer.addEventListener('transitionend', function wait(event) { - self.popupContainer.removeEventListener('transitionend', wait); - self.screen.classList.remove('popup'); - self.popupContainer.classList.remove('disappearing'); - self.container.removeChild(self._currentPopup[self._currentOrigin]); - delete self._currentPopup[self._currentOrigin]; - }); - - this.popupContainer.classList.add('disappearing'); - - // We just removed the focused window leaving the system - // without any focused window, let's fix this. - window.focus(); - }, - - backHandling: function pm_backHandling() { - if (!this._currentPopup[this._currentOrigin]) - return; - - this.close(); - }, - - isVisible: function pm_isVisible() { - return (this._currentPopup[this._currentOrigin] != null); - }, - - setHeight: function pm_setHeight(height) { - if (this.isVisible()) - this.overlay.style.height = height + 'px'; - }, - - handleEvent: function pm_handleEvent(evt) { - switch (evt.type) { - case 'click': - switch (evt.target) { - case this.closeButton: - this.backHandling(); - break; - - case this.errorBack: - this.backHandling(); - break; - - case this.errorReload: - this.container.classList.remove('error'); - delete this._currentPopup[this._currentOrigin].dataset.error; - this._currentPopup[this._currentOrigin].reload(true); - break; - } - break; - - case 'mozbrowserloadstart': - this.throbber.classList.add('loading'); - break; - - case 'mozbrowserloadend': - this.throbber.classList.remove('loading'); - break; - - case 'mozbrowserlocationchange': - evt.target.dataset.url = evt.detail; - this.show(); - break; - - case 'mozbrowsererror': - this._currentPopup[evt.target.dataset.frameOrigin].dataset.error = true; - this.showError(); - break; - - case 'mozbrowseropenwindow': - var detail = evt.detail; - var openerType = evt.target.dataset.frameType; - var openerOrigin = evt.target.dataset.frameOrigin; - - // Only app frame is allowed to launch popup - if (openerType !== 'window') - return; - - // <a href="" target="_blank"> links should opened outside the app - // itself and fire an activity to be opened into a new browser window. - if (detail.name === '_blank') { - new MozActivity({ name: 'view', - data: { type: 'url', url: detail.url }}); - return; - } - - this.throbber.classList.remove('loading'); - - var frame = detail.frameElement; - frame.dataset.url = detail.url; - - this.container.classList.remove('error'); - this.open(frame, openerOrigin); - - break; - - case 'mozbrowserclose': - this.close(evt); - break; - - case 'home': - // Reset overlay height before hiding - this.setHeight(window.innerHeight - StatusBar.height); - this.hide(this._currentOrigin); - break; - - case 'appwillclose': - if (!this._currentPopup[evt.detail.origin]) - return; - - this.hide(evt.detail.origin); - break; - - case 'appopen': - this._currentOrigin = evt.detail.origin; - this.show(); - break; - - case 'appterminated': - if (!this._currentPopup[evt.detail.origin]) - return; - this.close(evt.detail.origin); - break; - - case 'keyboardchange': - this.setHeight(window.innerHeight - - StatusBar.height - evt.detail.height); - break; - - case 'keyboardhide': - this.setHeight(window.innerHeight - StatusBar.height); - break; - } - }, - - showError: function pm_showError() { - if (!('error' in this._currentPopup[this._currentOrigin].dataset)) { - this.container.classList.remove('error'); - return; - } - - var contentOrigin = - this.getTitleFromUrl(this._currentPopup[this._currentOrigin].dataset.url); - var _ = navigator.mozL10n.get; - - if (AirplaneMode.enabled) { - this.errorTitle.textContent = _('airplane-is-on'); - this.errorMessage.textContent = _('airplane-is-turned-on', - {name: contentOrigin}); - } else if (!navigator.onLine) { - this.errorTitle.textContent = _('network-connection-unavailable'); - this.errorMessage.textContent = _('network-error', {name: contentOrigin}); - } else { - this.errorTitle.textContent = _('error-title', {name: contentOrigin}); - this.errorMessage.textContent = _('error-message', {name: contentOrigin}); - } - this.container.classList.add('error'); - }, - - // This is for card view to request - // Return nothing if the content is the same origin as opener - // Return URL if the content is off-origin - getOpenedOriginFromOpener: function pm_getOpenedOriginOpener(origin) { - var opened = this._getOriginObject(this._currentPopup[origin].dataset.url); - var opener = this._getOriginObject(origin); - // Same origin means: Protocol, Domain, Port - if (opened.protocol == opener.protocol && - opened.hostname == opener.hostname && - opened.port == opener.port) { - return ''; - } else { - return opened.protocol + '//' + opened.hostname; - } - }, - - getTitleFromUrl: function pm_getTitleFromUrl(url) { - var app = WindowManager.getCurrentDisplayedApp(); - var opened = this._getOriginObject(url); - var opener = this._getOriginObject(app.frame.dataset.frameOrigin); - // Same origin means: Protocol, Domain, Port - if (opened.protocol == opener.protocol && - opened.hostname == opener.hostname && - opened.port == opener.port) { - return app.name; - } else { - return opened.protocol + '//' + opened.hostname; - } - }, - - _getOriginObject: function pm__getOriginObject(url) { - var parser = document.createElement('a'); - parser.href = url; - - return { - protocol: parser.protocol, - hostname: parser.hostname, - port: parser.port - }; - }, - - getPopupFromOrigin: function pm_getPopupFromOrigin(origin) { - return this._currentPopup[origin]; - }, - - show: function pm_show() { - if (!this._currentPopup[this._currentOrigin]) - return; - - - this.showError(); - this.screen.classList.add('popup'); - - var popup = this._currentPopup[this._currentOrigin]; - this.title.textContent = this.getTitleFromUrl(popup.dataset.url); - popup.hidden = false; - }, - - hide: function pm_hide(origin) { - if (!this._currentPopup[origin]) - return; - - this.screen.classList.remove('popup'); - this._currentPopup[origin].hidden = true; - } -}; - -PopupManager.init(); - diff --git a/apps/system/js/quick_settings.js b/apps/system/js/quick_settings.js deleted file mode 100644 index 328bb35..0000000 --- a/apps/system/js/quick_settings.js +++ /dev/null @@ -1,279 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var QuickSettings = { - // Indicate setting status of geolocation.enabled - geolocationEnabled: false, - WIFI_STATUSCHANGE_TIMEOUT: 2000, - - init: function qs_init() { - var settings = window.navigator.mozSettings; - var conn = window.navigator.mozMobileConnection; - if (!settings || !conn) - return; - - this.getAllElements(); - - this.overlay.addEventListener('click', this); - window.addEventListener('utilitytrayshow', this); - - var self = this; - - /* - * Monitor data network icon - */ - conn.addEventListener('datachange', function qs_onDataChange() { - var label = { - 'lte': '4G', // 4G LTE - 'ehrpd': '4G', // 4G CDMA - 'hspa+': 'H+', // 3.5G HSPA+ - 'hsdpa': 'H', 'hsupa': 'H', 'hspa': 'H', // 3.5G HSDPA - 'evdo0': '3G', 'evdoa': '3G', 'evdob': '3G', '1xrtt': '3G', // 3G CDMA - 'umts': '3G', // 3G - 'edge': 'E', // EDGE - 'is95a': '2G', 'is95b': '2G', // 2G CDMA - 'gprs': '2G' - }; - self.data.dataset.network = label[conn.data.type]; - }); - - /* monitor data setting - * TODO prevent quickly tapping on it - */ - SettingsListener.observe('ril.data.enabled', true, function(value) { - if (value) { - self.data.dataset.enabled = 'true'; - } else { - delete self.data.dataset.enabled; - } - }); - - /* monitor bluetooth setting and initialization/disable ready event - * - when settings changed, update UI and lock toogle to prevent quickly - * tapping on it. - * - when got bluetooth initialization/disable ready, active toogle, so - * return the control to user. - */ - var btFirstSet = true; - SettingsListener.observe('bluetooth.enabled', true, function(value) { - // check self.bluetooth.dataset.enabled and value are identical - if ((self.bluetooth.dataset.enabled && value) || - (self.bluetooth.dataset.enabled === undefined && !value)) - return; - - if (value) { - self.bluetooth.dataset.enabled = 'true'; - } else { - delete self.bluetooth.dataset.enabled; - } - - // Set to the initializing state to block user interaction until the - // operation completes. (unless we are being called for the first time, - // where Bluetooth is already initialize - if (!btFirstSet) - self.bluetooth.dataset.initializing = 'true'; - btFirstSet = false; - }); - window.addEventListener('bluetooth-adapter-added', this); - window.addEventListener('bluetooth-disabled', this); - - - /* monitor wifi setting and initialization/disable ready event - * - when settings changed, update UI and lock toogle to prevent quickly - * tapping on it. - * - when got bluetooth initialization/disable ready, active toogle, so - * return the control to user. - */ - var wifiFirstSet = true; - SettingsListener.observe('wifi.enabled', true, function(value) { - // check self.wifi.dataset.enabled and value are identical - if ((self.wifi.dataset.enabled && value) || - (self.wifi.dataset.enabled === undefined && !value)) - return; - - if (value) { - self.wifi.dataset.enabled = 'true'; - } else { - delete self.wifi.dataset.enabled; - } - // Set to the initializing state to block user interaction until the - // operation completes. (unless we are being called for the first time, - // where Wifi is already initialize - if (!wifiFirstSet) - self.wifi.dataset.initializing = 'true'; - wifiFirstSet = false; - }); - window.addEventListener('wifi-enabled', this); - window.addEventListener('wifi-disabled', this); - window.addEventListener('wifi-statuschange', this); - - /* monitor geolocation setting - * TODO prevent quickly tapping on it - */ - SettingsListener.observe('geolocation.enabled', true, function(value) { - self.geolocationEnabled = value; - }); - - // monitor airplane mode - SettingsListener.observe('ril.radio.disabled', false, function(value) { - self.data.dataset.airplaneMode = value; - if (value) { - self.data.classList.add('quick-settings-airplane-mode'); - self.airplaneMode.dataset.enabled = 'true'; - } else { - self.data.classList.remove('quick-settings-airplane-mode'); - delete self.airplaneMode.dataset.enabled; - } - }); - }, - - handleEvent: function qs_handleEvent(evt) { - evt.preventDefault(); - switch (evt.type) { - case 'click': - switch (evt.target) { - case this.wifi: - // do nothing if wifi isn't ready - if (this.wifi.dataset.initializing) - return; - var enabled = !!this.wifi.dataset.enabled; - SettingsListener.getSettingsLock().set({ - 'wifi.enabled': !enabled - }); - if (!enabled) - this.toggleAutoConfigWifi = true; - break; - - case this.data: - if (this.data.dataset.airplaneMode !== 'true') { - // TODO should ignore the action if data initialization isn't done - var enabled = !!this.data.dataset.enabled; - - SettingsListener.getSettingsLock().set({ - 'ril.data.enabled': !enabled - }); - } - - break; - - case this.bluetooth: - // do nothing if bluetooth isn't ready - if (this.bluetooth.dataset.initializing) - return; - - var enabled = !!this.bluetooth.dataset.enabled; - SettingsListener.getSettingsLock().set({ - 'bluetooth.enabled': !enabled - }); - break; - - case this.airplaneMode: - var enabled = !!this.airplaneMode.dataset.enabled; - SettingsListener.getSettingsLock().set({ - 'ril.radio.disabled': !enabled - }); - break; - - case this.fullApp: - // XXX: This should be replaced probably by Web Activities - var host = document.location.host; - var domain = host.replace(/(^[\w\d]+\.)?([\w\d]+\.[a-z]+)/, '$2'); - var protocol = document.location.protocol + '//'; - Applications.getByManifestURL(protocol + 'settings.' + - domain + '/manifest.webapp').launch(); - - UtilityTray.hide(); - break; - } - break; - - case 'utilitytrayshow': - break; - - // unlock bluetooth toggle - case 'bluetooth-adapter-added': - case 'bluetooth-disabled': - delete this.bluetooth.dataset.initializing; - break; - // unlock wifi toggle - case 'wifi-enabled': - delete this.wifi.dataset.initializing; - if (this.toggleAutoConfigWifi) { - // Check whether it found a wifi to connect after a timeout. - this.wifiStatusTimer = setTimeout(this.autoConfigWifi.bind(this), - this.WIFI_STATUSCHANGE_TIMEOUT); - } - break; - case 'wifi-disabled': - delete this.wifi.dataset.initializing; - if (this.toggleAutoConfigWifi) { - clearTimeout(this.wifiStatusTimer); - this.wifiStatusTimer = null; - this.toggleAutoConfigWifi = false; - } - break; - - case 'wifi-statuschange': - if (this.toggleAutoConfigWifi && !this.wifi.dataset.initializing) - this.autoConfigWifi(); - break; - } - }, - - getAllElements: function qs_getAllElements() { - // ID of elements to create references - var elements = ['wifi', 'data', 'bluetooth', 'airplane-mode', 'full-app']; - - var toCamelCase = function toCamelCase(str) { - return str.replace(/\-(.)/g, function replacer(str, p1) { - return p1.toUpperCase(); - }); - }; - - elements.forEach(function createElementRef(name) { - this[toCamelCase(name)] = - document.getElementById('quick-settings-' + name); - }, this); - - this.overlay = document.getElementById('quick-settings'); - }, - - // XXX Break down obj keys in a for each loop because mozSettings - // does not currently supports multiple keys in one set() - // https://bugzilla.mozilla.org/show_bug.cgi?id=779381 - setMozSettings: function qs_setter(keypairs) { - var setlock = SettingsListener.getSettingsLock(); - for (var key in keypairs) { - var obj = {}; - obj[key] = keypairs[key]; - setlock.set(obj); - } - }, - - /* Auto-config wifi if user enabled wifi from quick settings bar. - * If there are no known networks around, wifi settings page - * will be opened. Otherwise nothing will be done. - */ - autoConfigWifi: function qs_autoConfigWifi() { - clearTimeout(this.wifiStatusTimer); - this.wifiStatusTimer = null; - this.toggleAutoConfigWifi = false; - - var wifiManager = window.navigator.mozWifiManager; - var status = wifiManager.connection.status; - - if (status == 'disconnected') { - var activity = new MozActivity({ - name: 'configure', - data: { - target: 'device', - section: 'wifi' - } - }); - } - } -}; - -QuickSettings.init(); diff --git a/apps/system/js/remote_debugger.js b/apps/system/js/remote_debugger.js deleted file mode 100644 index 51544bb..0000000 --- a/apps/system/js/remote_debugger.js +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var RemoteDebugger = (function() { - - return { - init: function() { - window.addEventListener('mozChromeEvent', this); - }, - - handleEvent: function onMozChromeEvent(e) { - if (e.detail.type !== 'remote-debugger-prompt') { - return; - } - - // Reusing the ModalDialog infrastructure. - ModalDialog.showWithPseudoEvent({ - text: navigator.mozL10n.get('remoteDebuggerMessage'), - type: 'confirm', - callback: function() { - RemoteDebugger._dispatchEvent(true); - }, - cancel: function() { - RemoteDebugger._dispatchEvent(false); - } - }); - }, - - _dispatchEvent: function su_dispatchEvent(value) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, - { type: 'remote-debugger-prompt', - value: value }); - window.dispatchEvent(event); - } - }; -})(); - -RemoteDebugger.init(); diff --git a/apps/system/js/screen_manager.js b/apps/system/js/screen_manager.js deleted file mode 100644 index 9a69e8c..0000000 --- a/apps/system/js/screen_manager.js +++ /dev/null @@ -1,503 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var ScreenManager = { - /* - * return the current screen status - * Must not mutate directly - use toggleScreen/turnScreenOff/turnScreenOn. - * Listen to 'screenchange' event to properly handle status changes - * This value can be "out of sync" with real mozPower value, - * we do this to give screen some time to flash before actual turn off. - */ - screenEnabled: false, - - /* - * before idle-screen-off, invoke a nice dimming to the brightness - * to notify the user that the screen is about to be turn off. - * The user can cancel the idle-screen-off by touching the screen - * and by pressing a button (trigger onactive callback on Idle API) - * - */ - _inTransition: false, - - /* - * Whether the wake lock is enabled or not - */ - _screenWakeLocked: false, - - /* - * Whether the device light is enabled or not - * sync with setting 'screen.automatic-brightness' - */ - _deviceLightEnabled: true, - - /* - * Preferred brightness without considering device light nor dimming - * sync with setting 'screen.brightness' - */ - _userBrightness: 1, - _savedBrightness: 1, - - /* - * The auto-brightness algorithm will never set the screen brightness - * to a value smaller than this. 0.1 seems like a good screen brightness - * in a completely dark room on a Unagi. - */ - AUTO_BRIGHTNESS_MINIMUM: 0.1, - - /* - * This constant is used in the auto brightness algorithm. We take - * the base 10 logarithm of the incoming lux value from the light - * sensor and multiplied it by this constant. That value is used to - * compute a weighted average with the current brightness and - * finally that average brightess is and then clamped to the range - * [AUTO_BRIGHTNESS_MINIMUM, 1.0]. - * - * Making this value larger will increase the brightness for a given - * ambient light level. At a value of about .25, the screen will be - * at full brightness in sunlight or in a well-lighted work area. - * At a value of about .3, the screen will typically be at maximum - * brightness in outdoor daylight conditions, even when overcast. - */ - AUTO_BRIGHTNESS_CONSTANT: .27, - - /* - * When we change brightness we animate it smoothly. - * This constant is the number of milliseconds between adjustments - */ - BRIGHTNESS_ADJUST_INTERVAL: 20, - - /* - * When brightening or dimming the screen, this is how much we adjust - * the brightness value at a time. - */ - BRIGHTNESS_ADJUST_STEP: 0.04, - - /* - * Wait for _dimNotice milliseconds during idle-screen-off - */ - _dimNotice: 10 * 1000, - - /* - * We track the value of the idle timeout pref in this variable. - */ - _idleTimeout: 0, - _idleTimerId: 0, - - /* - * If the screen off is triggered by promixity during phon call then - * we need wake it up while phone is ended. - */ - _screenOffByProximity: false, - - /* - * Request wakelock during in_call state. - * To ensure turnScreenOff by proximity event is protected by wakelock for - * early suspend only. - */ - _cpuWakeLock: null, - - init: function scm_init() { - window.addEventListener('sleep', this); - window.addEventListener('wake', this); - - this.screen = document.getElementById('screen'); - - var self = this; - var power = navigator.mozPower; - - if (power) { - power.addWakeLockListener(function scm_handleWakeLock(topic, state) { - switch (topic) { - case 'screen': - self._screenWakeLocked = (state == 'locked-foreground'); - - if (self._screenWakeLocked) - // Turn screen on if wake lock is acquire - self.turnScreenOn(); - self._reconfigScreenTimeout(); - break; - - case 'cpu': - power.cpuSleepAllowed = (state != 'locked-foreground' && - state != 'locked-background'); - break; - } - }); - } - - this._firstOn = false; - SettingsListener.observe('screen.timeout', 60, - function screenTimeoutChanged(value) { - if (typeof value !== 'number') - value = parseInt(value); - self._idleTimeout = value; - self._setIdleTimeout(self._idleTimeout); - - if (!self._firstOn) { - self._firstOn = true; - - // During boot up, the brightness was set by bootloader as 0.5, - // Let's set the API value to that so setScreenBrightness() can - // dim nicely to value set by user. - power.screenBrightness = 0.5; - - // Turn screen on with dim. - self.turnScreenOn(false); - } - }); - - SettingsListener.observe('screen.automatic-brightness', true, - function deviceLightSettingChanged(value) { - self.setDeviceLightEnabled(value); - }); - - SettingsListener.observe('screen.brightness', 1, - function brightnessSettingChanged(value) { - self._userBrightness = value; - self.setScreenBrightness(value, false); - }); - - var telephony = window.navigator.mozTelephony; - if (telephony) { - telephony.addEventListener('callschanged', this); - } - }, - - // - // Automatically adjust the screen brightness based on the ambient - // light (in lux) measured by the device light sensor - // - autoAdjustBrightness: function scm_adjustBrightness(lux) { - var currentBrightness = this._targetBrightness; - - if (lux < 1) // Can't take the log of 0 or negative numbers - lux = 1; - - var computedBrightness = - Math.log(lux) / Math.LN10 * this.AUTO_BRIGHTNESS_CONSTANT; - - var clampedBrightness = Math.max(this.AUTO_BRIGHTNESS_MINIMUM, - Math.min(1.0, computedBrightness)); - - // If nothing changed, we're done. - if (clampedBrightness === currentBrightness) - return; - - this.setScreenBrightness(clampedBrightness, false); - }, - - handleEvent: function scm_handleEvent(evt) { - switch (evt.type) { - case 'devicelight': - if (!this._deviceLightEnabled || !this.screenEnabled || - this._inTransition) - return; - this.autoAdjustBrightness(evt.value); - break; - - case 'sleep': - this.turnScreenOff(true); - break; - - case 'wake': - this.turnScreenOn(); - break; - - case 'userproximity': - this._screenOffByProximity = evt.near; - if (evt.near) { - this.turnScreenOff(true); - } else { - this.turnScreenOn(); - } - break; - - case 'callschanged': - var telephony = window.navigator.mozTelephony; - if (!telephony.calls.length) { - if (this._screenOffByProximity) { - this.turnScreenOn(); - } - - window.removeEventListener('userproximity', this); - this._screenOffByProximity = false; - - if (this._cpuWakeLock) { - this._cpuWakeLock.unlock(); - this._cpuWakeLock = null; - } - break; - } - - // If the _cpuWakeLock is already set we are in a multiple - // call setup, turning the screen on to let user see the - // notification. - if (this._cpuWakeLock) { - this.turnScreenOn(); - - break; - } - - // Enable the user proximity sensor once the call is connected. - var call = telephony.calls[0]; - call.addEventListener('statechange', this); - - break; - - case 'statechange': - var call = evt.target; - if (call.state !== 'connected') { - break; - } - - // The call is connected. Remove the statechange listener - // and enable the user proximity sensor. - call.removeEventListener('statechange', this); - - this._cpuWakeLock = navigator.requestWakeLock('cpu'); - window.addEventListener('userproximity', this); - break; - } - }, - - toggleScreen: function scm_toggleScreen() { - if (this.screenEnabled) { - this.turnScreenOff(); - } else { - this.turnScreenOn(); - } - }, - - turnScreenOff: function scm_turnScreenOff(instant) { - if (!this.screenEnabled) - return false; - - var self = this; - - // Remember the current screen brightness. We will restore it when - // we turn the screen back on. - self._savedBrightness = navigator.mozPower.screenBrightness; - - // Remove the cpuWakeLock if screen is not turned off by - // userproximity event. - if (!this._screenOffByProximity && this._cpuWakeLock) { - window.removeEventListener('userproximity', this); - this._cpuWakeLock.unlock(); - this._cpuWakeLock = null; - } - - var screenOff = function scm_screenOff() { - self._setIdleTimeout(0); - - window.removeEventListener('devicelight', self); - - self.screenEnabled = false; - self._inTransition = false; - self.screen.classList.add('screenoff'); - setTimeout(function realScreenOff() { - self.setScreenBrightness(0, true); - // Sometimes the ScreenManager.screenEnabled and mozPower.screenEnabled - // values are out of sync. Since the rest of the world relies only on - // the value of ScreenManager.screenEnabled it can be some situations - // where the screen is off but ScreenManager think it is on... (see - // bug 822463). Ideally a callback should have been used, like - // ScreenManager.getScreenState(function(value) { ...} ); but there - // are too many places to change that for now. - self.screenEnabled = false; - navigator.mozPower.screenEnabled = false; - }, 20); - - self.fireScreenChangeEvent(); - }; - - if (instant) { - if (!WindowManager.isFtuRunning()) { - screenOff(); - } - return true; - } - - this.setScreenBrightness(0.1, false); - this._inTransition = true; - setTimeout(function noticeTimeout() { - if (!self._inTransition) - return; - - screenOff(); - }, self._dimNotice); - - return true; - }, - - turnScreenOn: function scm_turnScreenOn(instant) { - if (this.screenEnabled) { - if (this._inTransition) { - // Cancel the dim out - this._inTransition = false; - this.setScreenBrightness(this._savedBrightness, true); - this._reconfigScreenTimeout(); - } - return false; - } - - // Set the brightness before the screen is on. - this.setScreenBrightness(this._savedBrightness, instant); - - // If we are in a call and there is no cpuWakeLock, - // we would have to get one here. - var telephony = window.navigator.mozTelephony; - if (!this._cpuWakeLock && telephony && telephony.calls.length) { - telephony.calls.some(function checkCallConnection(call) { - if (call.state == 'connected') { - this._cpuWakeLock = navigator.requestWakeLock('cpu'); - window.addEventListener('userproximity', this); - return true; - } - return false; - }, this); - } - - // Actually turn the screen on. - var power = navigator.mozPower; - if (power) - power.screenEnabled = true; - this.screenEnabled = true; - this.screen.classList.remove('screenoff'); - - // Attaching the event listener effectively turn on the hardware - // device light sensor, which _must be_ done after power.screenEnabled. - if (this._deviceLightEnabled) - window.addEventListener('devicelight', this); - - this._reconfigScreenTimeout(); - this.fireScreenChangeEvent(); - - return true; - }, - - _reconfigScreenTimeout: function scm_reconfigScreenTimeout() { - // Remove idle timer if screen wake lock is acquired. - if (this._screenWakeLocked) { - this._setIdleTimeout(0); - // The screen should be turn off with shorter timeout if - // it was never unlocked. - } else if (LockScreen.locked) { - this._setIdleTimeout(10, true); - var self = this; - var stopShortIdleTimeout = function scm_stopShortIdleTimeout() { - window.removeEventListener('unlock', stopShortIdleTimeout); - window.removeEventListener('lockpanelchange', stopShortIdleTimeout); - self._setIdleTimeout(self._idleTimeout, false); - }; - - window.addEventListener('unlock', stopShortIdleTimeout); - window.addEventListener('lockpanelchange', stopShortIdleTimeout); - } else { - this._setIdleTimeout(this._idleTimeout, false); - } - }, - - setScreenBrightness: function scm_setScreenBrightness(brightness, instant) { - this._targetBrightness = brightness; - var power = navigator.mozPower; - if (!power) - return; - - // Make sure we don't have another brightness change scheduled - if (this._transitionBrightnessTimer) { - clearTimeout(this._transitionBrightnessTimer); - this._transitionBrightnessTimer = null; - } - - if (typeof instant !== 'boolean') - instant = true; - - if (instant) { - power.screenBrightness = brightness; - return; - } - - // transitionBrightness() is a looping function that will - // gracefully tune the brightness to _targetBrightness for us. - this.transitionBrightness(); - }, - - transitionBrightness: function scm_transitionBrightness() { - var self = this; - var power = navigator.mozPower; - var screenBrightness = power.screenBrightness; - var delta = this.BRIGHTNESS_ADJUST_STEP; - - // Is this the last time adjustment we need to make? - if (Math.abs(this._targetBrightness - screenBrightness) <= delta) { - power.screenBrightness = this._targetBrightness; - this._transitionBrightnessTimer = null; - return; - } - - if (screenBrightness > this._targetBrightness) - delta *= -1; - - screenBrightness += delta; - power.screenBrightness = screenBrightness; - - this._transitionBrightnessTimer = - setTimeout(function transitionBrightnessTimeout() { - self.transitionBrightness(); - }, this.BRIGHTNESS_ADJUST_INTERVAL); - }, - - setDeviceLightEnabled: function scm_setDeviceLightEnabled(enabled) { - if (!enabled && this._deviceLightEnabled) { - // Disabled -- set the brightness back to preferred brightness - this.setScreenBrightness(this._userBrightness, false); - } - this._deviceLightEnabled = enabled; - - if (!this.screenEnabled) - return; - - // Disable/enable device light sensor accordingly. - // This will also toggle the actual hardware, which - // must be done while the screen is on. - if (enabled) { - window.addEventListener('devicelight', this); - } else { - window.removeEventListener('devicelight', this); - } - }, - - _setIdleTimeout: function scm_setIdleTimeout(time, instant) { - window.clearIdleTimeout(this._idleTimerId); - - // Reset the idled state back to false. - this._idled = false; - - // 0 is the value used to disable idle timer by user and by us. - if (time === 0) - return; - - var self = this; - var idleCallback = function idle_proxy() { - self.turnScreenOff(instant); - }; - var activeCallback = function active_proxy() { - self.turnScreenOn(true); - }; - - this._idleTimerId = window.setIdleTimeout(idleCallback, - activeCallback, time * 1000); - }, - - fireScreenChangeEvent: function scm_fireScreenChangeEvent() { - var evt = new CustomEvent('screenchange', - { bubbles: true, cancelable: false, - detail: { screenEnabled: this.screenEnabled } }); - window.dispatchEvent(evt); - } -}; - -ScreenManager.init(); diff --git a/apps/system/js/screenshot.js b/apps/system/js/screenshot.js deleted file mode 100644 index 9e8e7f6..0000000 --- a/apps/system/js/screenshot.js +++ /dev/null @@ -1,115 +0,0 @@ -// screenshot.js: system screenshot module -// -// This system module takes a screenshot of the currently running app -// or homescreen and stores it with DeviceStorage when the user -// presses the home and sleep buttons at the same time. It communicates -// with gecko code running in b2g/chrome/content/shell.js using a private -// event-based API. It is the gecko code that creates the screenshot. -// -// This script must be used with the defer attribute. -// -// -(function() { - window.addEventListener('home+sleep', takeScreenshot); - - // Assume that the maximum screenshot size is 4 bytes per pixel - // plus a bit extra. In practice, with compression, our PNG files will be - // much smaller than this. - var MAX_SCREENSHOT_SIZE = window.innerWidth * window.innerHeight * 4 + 4096; - - function takeScreenshot() { - // Give feedback that the screenshot request was received - navigator.vibrate(100); - - // We don't need device storage here, but check to see that - // it is available before sending the screenshot request to chrome. - // If device storage is available, the callback will be called. - // Otherwise, an error message notification will be displayed. - getDeviceStorage(function() { - // Let chrome know we'd like a screenshot. - // This is a completely non-standard undocumented API - // for communicating with our chrome code. - var screenshotProps = { - detail: { - type: 'take-screenshot' - } - }; - window.dispatchEvent(new CustomEvent('mozContentEvent', screenshotProps)); - }); - } - - // Display a screenshot success or failure notification. - // Localize the first argument, and localize the third if the second is null - function notify(titleid, body, bodyid) { - var title = navigator.mozL10n.get(titleid) || titleid; - body = body || navigator.mozL10n.get(bodyid); - navigator.mozNotification.createNotification(title, body).show(); - } - - // Get a DeviceStorage object and pass it to the callback. - // Or, if device storage is not available, display a notification. - function getDeviceStorage(callback) { - var storage = navigator.getDeviceStorage('pictures'); - var availreq = storage.available(); - availreq.onsuccess = function() { - var state = availreq.result; - if (state === 'unavailable') { - notify('screenshotFailed', null, 'screenshotNoSDCard'); - } - else if (state === 'shared') { - notify('screenshotFailed', null, 'screenshotSDCardInUse'); - } - else if (state === 'available') { - var freereq = storage.freeSpace(); - freereq.onsuccess = function() { - if (freereq.result < MAX_SCREENSHOT_SIZE) { - notify('screenshotFailed', null, 'screenshotSDCardLow'); - } - else { - callback(storage); - } - }; - freereq.onerror = function() { - notify('screenshotFailed', freereq.error && freereq.error.name); - }; - } - } - availreq.onerror = function() { - notify('screenshotFailed', availreq.error && availreq.error.name); - } - } - - // Handle the event we get from chrome with the screenshot - window.addEventListener('mozChromeEvent', function ss_onMozChromeEvent(e) { - try { - if (e.detail.type === 'take-screenshot-success') { - getDeviceStorage(function(storage) { - var filename = 'screenshots/' + - new Date().toISOString().slice(0, -5).replace(/[:T]/g, '-') + - '.png'; - - var saveRequest = storage.addNamed(e.detail.file, filename); - - saveRequest.onsuccess = function ss_onsuccess() { - // Vibrate again when the screenshot is saved - navigator.vibrate(100); - - // Display filename in a notification - notify('screenshotSaved', filename); - }; - - saveRequest.onerror = function ss_onerror() { - notify('screenshotFailed', saveRequest.error.name); - }; - }); - } - else if (e.detail.type === 'take-screenshot-error') { - notify('screenshotFailed', e.detail.error); - } - } - catch (e) { - console.log('exception in screenshot handler', e); - notify('screenshotFailed', e.toString()); - } - }); -}()); diff --git a/apps/system/js/sim_lock.js b/apps/system/js/sim_lock.js deleted file mode 100644 index 3a3d3e0..0000000 --- a/apps/system/js/sim_lock.js +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var SimLock = { - init: function sl_init() { - // Do not do anything if we can't have access to MobileConnection API - var conn = window.navigator.mozMobileConnection; - if (!conn) - return; - - this.onClose = this.onClose.bind(this); - - // Watch for apps that need a mobile connection - window.addEventListener('appwillopen', this); - - // Display the dialog only after lockscreen is unlocked - // To prevent keyboard being displayed behind it. - window.addEventListener('unlock', this); - - // always monitor card state change - conn.addEventListener('cardstatechange', this.showIfLocked.bind(this)); - }, - - handleEvent: function sl_handleEvent(evt) { - switch (evt.type) { - case 'unlock': - this.showIfLocked(); - break; - case 'appwillopen': - // if an app needs telephony or sms permission, - // we will launch the unlock screen if needed. - - var app = Applications.getByManifestURL( - evt.target.getAttribute('mozapp')); - - if (!app || !app.manifest.permissions) - return; - - // Ignore first time usage app which already ask for SIM code - if (evt.target.classList.contains('ftu')) - return; - - if (!('telephony' in app.manifest.permissions || - 'sms' in app.manifest.permissions)) - return; - - // Ignore second `appwillopen` event when showIfLocked ends up - // eventually opening the app on valid pin code - var origin = evt.target.dataset.frameOrigin; - if (origin == this._lastOrigin) { - delete this._lastOrigin; - return; - } - this._lastOrigin = origin; - - // if sim is locked, cancel app opening in order to display - // it after PIN dialog - if (this.showIfLocked()) - evt.preventDefault(); - - break; - } - }, - - showIfLocked: function sl_showIfLocked() { - var conn = window.navigator.mozMobileConnection; - if (!conn) - return false; - - if (LockScreen.locked) - return false; - - switch (conn.cardState) { - // do nothing in absent and null card states - case null: - case 'absent': - break; - case 'pukRequired': - case 'pinRequired': - SimPinDialog.show('unlock', this.onClose); - return true; - case 'networkLocked': - // XXXX: After unlocking the SIM the cardState is - // 'networkLocked' but it changes inmediately to 'ready' - // if the phone is not SIM-locked. If the cardState - // is still 'networkLocked' after two seconds we unlock - // the network control key lock (network personalization). - setTimeout(function checkState() { - if (conn.cardState == 'networkLocked') { - SimPinDialog.show('unlock', SimLock.onClose); - } - }, 5000); - break; - } - return false; - }, - - onClose: function sl_onClose(reason) { - // Display the app only when PIN code is valid and when we click - // on `X` button - if (this._lastOrigin && (reason == 'success' || reason == 'skip')) - WindowManager.setDisplayedApp(this._lastOrigin); - delete this._lastOrigin; - } - -}; - -SimLock.init(); diff --git a/apps/system/js/simcard_dialog.js b/apps/system/js/simcard_dialog.js deleted file mode 100644 index 4176cbf..0000000 --- a/apps/system/js/simcard_dialog.js +++ /dev/null @@ -1,355 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var SimPinDialog = { - dialogTitle: document.querySelector('#simpin-dialog header h1'), - dialogDone: document.querySelector('#simpin-dialog button[type="submit"]'), - dialogClose: document.querySelector('#simpin-dialog button[type="reset"]'), - - pinArea: document.getElementById('pinArea'), - pukArea: document.getElementById('pukArea'), - nckArea: document.getElementById('nckArea'), - newPinArea: document.getElementById('newPinArea'), - confirmPinArea: document.getElementById('confirmPinArea'), - - pinInput: null, - pukInput: null, - nckInput: null, - newPinInput: null, - confirmPinInput: null, - - errorMsg: document.getElementById('errorMsg'), - errorMsgHeader: document.getElementById('messageHeader'), - errorMsgBody: document.getElementById('messageBody'), - - mobileConnection: null, - - lockType: 'pin', - action: 'unlock', - - // Now we don't have a number-password type for input field - // mimic one by binding one number input and one text input - getNumberPasswordInputField: function spl_wrapNumberInput(name) { - var valueEntered = ''; - var inputField = document.querySelector('input[name="' + name + '"]'); - var displayField = document.querySelector('input[name="' + name + 'Vis"]'); - var codeMaxLength = parseInt(inputField.getAttribute('maxlength'), 10); - var self = this; - - inputField.addEventListener('keypress', function(evt) { - if (evt.target !== inputField) - return; - evt.preventDefault(); - - var code = evt.charCode; - if (code !== 0 && (code < 0x30 || code > 0x39)) - return; - - if (code === 0) { // backspace - valueEntered = valueEntered.substr(0, valueEntered.length - 1); - } else { - if (valueEntered.length >= codeMaxLength) - return; - valueEntered += String.fromCharCode(code); - } - displayField.value = encryption(valueEntered); - if (displayField.value.length >= 4) - self.dialogDone.disabled = false; - else - self.dialogDone.disabled = true; - }); - - function encryption(str) { - return (new Array(str.length + 1)).join('*'); - } - - function setValue(value) { - valueEntered = value; - inputField.value = value; - displayField.value = encryption(valueEntered); - } - - function setFocus() { - inputField.focus(); - } - - function blur() { - inputField.blur(); - } - - return { - get value() { return valueEntered; }, - set value(value) { setValue(value) }, - focus: setFocus, - blur: blur - }; - }, - - handleCardState: function spl_handleCardState() { - var _ = navigator.mozL10n.get; - - var cardState = this.mobileConnection.cardState; - switch (cardState) { - case 'pinRequired': - this.lockType = 'pin'; - this.errorMsg.hidden = true; - this.inputFieldControl(true, false, false, false); - this.pinInput.focus(); - break; - case 'pukRequired': - this.lockType = 'puk'; - this.errorMsgHeader.textContent = _('simCardLockedMsg') || ''; - this.errorMsgHeader.dataset.l10nId = 'simCardLockedMsg'; - this.errorMsgBody.textContent = _('enterPukMsg') || ''; - this.errorMsgBody.dataset.l10nId = 'enterPukMsg'; - this.errorMsg.hidden = false; - this.inputFieldControl(false, true, false, true); - this.pukInput.focus(); - break; - case 'networkLocked': - this.lockType = 'nck'; - this.errorMsg.hidden = true; - this.inputFieldControl(false, false, true, false); - this.nckInput.focus(); - break; - default: - this.skip(); - break; - } - this.dialogTitle.textContent = _(this.lockType + 'Title') || ''; - this.dialogTitle.dataset.l10nId = this.lockType + 'Title'; - }, - - handleError: function spl_handleLockError(evt) { - var retry = (evt.retryCount) ? evt.retryCount : -1; - this.showErrorMsg(retry, evt.lockType); - if (retry === -1) { - this.skip(); - return; - } - if (evt.lockType === 'pin') { - this.pinInput.focus(); - } else if (evt.lockType === 'puk') { - this.pukInput.focus(); - } else { - this.nckInput.focus(); - } - }, - - showErrorMsg: function spl_showErrorMsg(retry, type) { - var _ = navigator.mozL10n.get; - - this.errorMsgHeader.textContent = _(type + 'ErrorMsg'); - this.errorMsgHeader.dataset.l10nId = type + 'ErrorMsg'; - - if (retry !== 1) { - var l10nArgs = { n: retry }; - this.errorMsgBody.dataset.l10nId = type + 'AttemptMsg'; - this.errorMsgBody.dataset.l10nArgs = JSON.stringify(l10nArgs); - this.errorMsgBody.textContent = _(type + 'AttemptMsg', l10nArgs); - } else { - this.errorMsgBody.dataset.l10nId = type + 'LastChanceMsg'; - this.errorMsgBody.textContent = _(type + 'LastChanceMsg'); - } - - this.errorMsg.hidden = false; - }, - - unlockPin: function spl_unlockPin() { - var pin = this.pinInput.value; - if (pin === '') - return; - - var options = {lockType: 'pin', pin: pin }; - this.unlockCardLock(options); - this.clear(); - }, - - unlockPuk: function spl_unlockPuk() { - var _ = navigator.mozL10n.get; - - var puk = this.pukInput.value; - var newPin = this.newPinInput.value; - var confirmPin = this.confirmPinInput.value; - if (puk === '' || newPin === '' || confirmPin === '') - return; - - if (newPin !== confirmPin) { - this.errorMsgHeader.textContent = _('newPinErrorMsg'); - this.errorMsgHeader.dataset.l10nId = 'newPinErrorMsg'; - this.errorMsgBody.textContent = ''; - this.errorMsg.hidden = false; - return; - } - var options = {lockType: 'puk', puk: puk, newPin: newPin }; - this.unlockCardLock(options); - this.clear(); - }, - - unlockNck: function spl_unlockNck() { - var nck = this.nckInput.value; - if (nck === '') - return; - - var options = {lockType: 'nck', pin: nck }; - this.unlockCardLock(options); - this.clear(); - }, - - unlockCardLock: function spl_unlockCardLock(options) { - var req = this.mobileConnection.unlockCardLock(options); - req.onsuccess = this.close.bind(this, 'success'); - }, - - enableLock: function spl_enableLock() { - var pin = this.pinInput.value; - if (pin === '') - return; - - var enabled = SimPinLock.simPinCheckBox.checked; - var options = {lockType: 'pin', pin: pin, enabled: enabled}; - this.setCardLock(options); - this.clear(); - }, - - changePin: function spl_changePin() { - var _ = navigator.mozL10n.get; - - var pin = this.pinInput.value; - var newPin = this.newPinInput.value; - var confirmPin = this.confirmPinInput.value; - if (pin === '' || newPin === '' || confirmPin === '') - return; - - if (newPin !== confirmPin) { - this.errorMsgHeader.textContent = _('newPinErrorMsg'); - this.errorMsgHeader.dataset.l10nId = 'newPinErrorMsg'; - this.errorMsgBody.textContent = ''; - this.errorMsg.hidden = false; - return; - } - var options = {lockType: 'pin', pin: pin, newPin: newPin}; - this.setCardLock(options); - this.clear(); - }, - - setCardLock: function spl_setCardLock(options) { - var req = this.mobileConnection.setCardLock(options); - req.onsuccess = this.close.bind(this, 'success'); - }, - inputFieldControl: function spl_inputField(isPin, isPuk, isNck, isNewPin) { - this.pinArea.hidden = !isPin; - this.pukArea.hidden = !isPuk; - this.nckArea.hidden = !isNck; - this.newPinArea.hidden = !isNewPin; - this.confirmPinArea.hidden = !isNewPin; - }, - - verify: function spl_verify() { - switch (this.action) { - case 'unlock': - if (this.lockType === 'pin') - this.unlockPin(); - else if (this.lockType === 'puk') { - this.unlockPuk(); - } else { - this.unlockNck(); - } - break; - case 'enable': - this.enableLock(); - break; - case 'changePin': - this.changePin(); - break; - } - return false; - }, - - onHide: function spl_onHide(reason) { - this.clear(); - if (this.onclose) - this.onclose(reason); - }, - - clear: function spl_clear() { - this.errorMsg.hidden = true; - this.pinInput.value = ''; - this.pinInput.blur(); - this.pukInput.value = ''; - this.pukInput.blur(); - this.newPinInput.value = ''; - this.confirmPinInput.value = ''; - }, - - onclose: null, - /** - * Show the SIM pin dialog - * @param {String} action Name of the action to execute, - * either: unlock, enable or changePin. - * @param {Function} title Optional function called when dialog is closed. - * Receive a single argument being the reason of - * dialog closing: success, skip, home or holdhome. - */ - show: function spl_show(action, onclose) { - var _ = navigator.mozL10n.get; - - this.systemDialog.show(); - this.dialogDone.disabled = true; - this.action = action; - this.lockType = 'pin'; - switch (action) { - case 'unlock': - this.handleCardState(); - break; - case 'enable': - this.inputFieldControl(true, false, false, false); - this.dialogTitle.textContent = _('pinTitle') || ''; - this.dialogTitle.dataset.l10nId = 'pinTitle'; - break; - case 'changePin': - this.inputFieldControl(true, false, false, true); - this.dialogTitle.textContent = _('newpinTitle') || ''; - this.dialogTitle.dataset.l10nId = 'newpinTitle'; - break; - } - - if (onclose && typeof onclose === 'function') - this.onclose = onclose; - }, - - close: function spl_close(reason) { - this.systemDialog.hide(reason); - }, - - skip: function spl_skip() { - this.close('skip'); - return false; - }, - - init: function spl_init() { - this.systemDialog = SystemDialog('simpin-dialog', { - onHide: this.onHide.bind(this) - }); - - this.mobileConnection = window.navigator.mozMobileConnection; - if (!this.mobileConnection) - return; - - this.mobileConnection.addEventListener('icccardlockerror', - this.handleError.bind(this)); - - this.dialogDone.onclick = this.verify.bind(this); - this.dialogClose.onclick = this.skip.bind(this); - this.pinInput = this.getNumberPasswordInputField('simpin'); - this.pukInput = this.getNumberPasswordInputField('simpuk'); - this.nckInput = this.getNumberPasswordInputField('nckpin'); - this.newPinInput = this.getNumberPasswordInputField('newSimpin'); - this.confirmPinInput = this.getNumberPasswordInputField('confirmNewSimpin'); - } -}; - -SimPinDialog.init(); - diff --git a/apps/system/js/sleep_menu.js b/apps/system/js/sleep_menu.js deleted file mode 100644 index a97b772..0000000 --- a/apps/system/js/sleep_menu.js +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var SleepMenu = { - // Indicate setting status of ril.radio.disabled - isFlightModeEnabled: false, - - // Indicate setting status of volume - isSilentModeEnabled: false, - - elements: {}, - - get visible() { - return this.elements.overlay.classList.contains('visible'); - }, - - getAllElements: function sm_getAllElements() { - this.elements.overlay = document.getElementById('sleep-menu'); - this.elements.container = - document.querySelector('#sleep-menu-container ul'); - this.elements.cancel = document.querySelector('#sleep-menu button'); - }, - - init: function sm_init() { - this.getAllElements(); - window.addEventListener('holdsleep', this.show.bind(this)); - window.addEventListener('click', this, true); - window.addEventListener('screenchange', this, true); - window.addEventListener('home', this); - this.elements.cancel.addEventListener('click', this); - - var self = this; - SettingsListener.observe('ril.radio.disabled', false, function(value) { - self.isFlightModeEnabled = value; - }); - - var settings = navigator.mozSettings; - SettingsListener.observe('audio.volume.notification', 7, function(value) { - settings.createLock().set({'ring.enabled': (value != 0)}); - }); - - SettingsListener.observe('ring.enabled', true, function(value) { - self.isSilentModeEnabled = !value; - }); - }, - - // Generate items - generateItems: function sm_generateItems() { - var items = []; - var _ = navigator.mozL10n.get; - var options = { - airplane: { - label: _('airplane'), - value: 'airplane', - icon: '/style/sleep_menu/images/airplane.png' - }, - airplaneOff: { - label: _('airplaneOff'), - value: 'airplane' - }, - silent: { - label: _('silent'), - value: 'silent', - icon: '/style/sleep_menu/images/vibration.png' - }, - silentOff: { - label: _('normal'), - value: 'silentOff' - }, - restart: { - label: _('restart'), - value: 'restart', - icon: '/style/sleep_menu/images/restart.png' - }, - power: { - label: _('power'), - value: 'power', - icon: '/style/sleep_menu/images/power-off.png' - } - }; - - if (this.isFlightModeEnabled) { - items.push(options.airplaneOff); - } else { - items.push(options.airplane); - } - - if (!this.isSilentModeEnabled) { - items.push(options.silent); - } else { - items.push(options.silentOff); - } - - items.push(options.restart); - items.push(options.power); - - return items; - }, - - show: function sm_show() { - this.elements.container.innerHTML = ''; - this.buildMenu(this.generateItems()); - this.elements.overlay.classList.add('visible'); - }, - - buildMenu: function sm_buildMenu(items) { - items.forEach(function traveseItems(item) { - var item_li = document.createElement('li'); - item_li.dataset.value = item.value; - item_li.textContent = item.label; - this.elements.container.appendChild(item_li); - }, this); - }, - - hide: function lm_hide() { - this.elements.overlay.classList.remove('visible'); - }, - - handleEvent: function sm_handleEvent(evt) { - switch (evt.type) { - case 'screenchange': - if (!evt.detail.screenEnabled) - this.hide(); - break; - - case 'click': - if (!this.visible) - return; - - if (evt.currentTarget === this.elements.cancel) { - this.hide(); - return; - } - - var action = evt.target.dataset.value; - if (!action) { - return; - } - this.hide(); - this.handler(action); - break; - - case 'home': - if (this.visible) { - this.hide(); - } - break; - } - }, - - handler: function sm_handler(action) { - switch (action) { - case 'airplane': - // Airplane mode should turn off - // - // Radio ('ril.radio.disabled'`) - // Data ('ril.data.enabled'`) - // Wifi - // Bluetooth - // Geolocation - // - // It should also save the status of the latter 4 items - // so when leaving the airplane mode we could know which one to turn on. - - if (!window.navigator.mozSettings) - return; - - SettingsListener.getSettingsLock().set({ - 'ril.radio.disabled': !this.isFlightModeEnabled - }); - - break; - - // About silent and silentOff - // * Turn on silent mode will cause: - // * Turn off ringtone no matter if ring is on or off - // * for sms and incoming calls. - // * Turn off silent mode will cause: - // * Turn on ringtone no matter if ring is on or off - // * for sms and incoming calls. - case 'silent': - if (!window.navigator.mozSettings) - return; - - SettingsListener.getSettingsLock().set({ - 'ring.enabled': false - }); - this.isSilentModeEnabled = true; - - break; - - case 'silentOff': - if (!window.navigator.mozSettings) - return; - - SettingsListener.getSettingsLock().set({ - 'ring.enabled': true - }); - this.isSilentModeEnabled = false; - - break; - - case 'restart': - this.startPowerOff(true); - - break; - - case 'power': - this.startPowerOff(false); - - break; - } - }, - - startPowerOff: function sm_startPowerOff(reboot) { - var power = navigator.mozPower; - if (!power) - return; - - // Early return if we are already shutting down. - if (document.getElementById('poweroff-splash')) - return; - - // Show shutdown animation before actually performing shutdown. - // * step1: fade-in poweroff-splash. - // * step2: The 3-rings animation is performed on the screen. - var div = document.createElement('div'); - div.dataset.zIndexLevel = 'poweroff-splash'; - div.id = 'poweroff-splash'; - - // The overall animation ends when the inner span of the bottom ring - // is animated, so we store it for detecting. - var inner; - - for (var i = 1; i <= 3; i++) { - var outer = document.createElement('span'); - outer.className = 'poweroff-ring'; - outer.id = 'poweroff-ring-' + i; - div.appendChild(outer); - - inner = document.createElement('span'); - outer.appendChild(inner); - } - - div.className = 'step1'; - - var nextAnimation = function nextAnimation(e) { - // Switch to next class - if (e.target == div) - div.className = 'step2'; - - if (e.target != inner) - return; - - // Actual poweroff/reboot - setTimeout(function powerOffAnimated() { - if (reboot) { - power.reboot(); - } else { - power.powerOff(); - } - }); - - // Paint screen to black before reboot/poweroff - ScreenManager.turnScreenOff(true); - }; - - div.addEventListener('animationend', nextAnimation); - - document.getElementById('screen').appendChild(div); - } -}; - -SleepMenu.init(); diff --git a/apps/system/js/sound_manager.js b/apps/system/js/sound_manager.js deleted file mode 100644 index 52dfc06..0000000 --- a/apps/system/js/sound_manager.js +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -(function() { - window.addEventListener('volumeup', function() { - if (onBTEarphoneConnected() && onCall()) { - changeVolume(1, 'bt_sco'); - } else { - changeVolume(1); - } - }); - window.addEventListener('volumedown', function() { - if (onBTEarphoneConnected() && onCall()) { - changeVolume(-1, 'bt_sco'); - } else { - changeVolume(-1); - } - }); - - // Store the current active channel; - // change with 'audio-channel-changed' mozChromeEvent - var currentChannel = 'notification'; - - var vibrationEnabled = true; - - // This event is generated in shell.js in response to bluetooth headset. - // Bluetooth headset always assign audio volume to a specific value when - // pressing its volume-up/volume-down buttons. - window.addEventListener('mozChromeEvent', function(e) { - var type = e.detail.type; - if (type == 'bluetooth-volumeset') { - changeVolume(e.detail.value - currentVolume['bt_sco'], 'bt_sco'); - } else if (type == 'audio-channel-changed') { - currentChannel = e.detail.channel; - } - }); - - function onCall() { - if (currentChannel == 'telephony') - return true; - - // XXX: This work should be removed - // once we could get telephony channel change event - // https://bugzilla.mozilla.org/show_bug.cgi?id=819858 - var telephony = window.navigator.mozTelephony; - if (!telephony) - return false; - - return telephony.calls.some(function callIterator(call) { - return (call.state == 'connected'); - }); - } - - function onBTEarphoneConnected() { - var bluetooth = navigator.mozBluetooth; - if (!bluetooth) - return false; - - // 0x111E is for querying earphone type. - return navigator.mozBluetooth.isConnected(0x111E); - }; - - // Platform doesn't provide the maximum value of each channel - // therefore, hard code here. - var MAX_VOLUME = { - 'alarm': 15, - 'notification': 15, - 'telephony': 5, - 'content': 15, - 'bt_sco': 15 - }; - - // Please refer https://wiki.mozilla.org/WebAPI/AudioChannels > Settings - var currentVolume = { - 'alarm': 15, - 'notification': 15, - 'telephony': 5, - 'content': 15, - 'bt_sco': 15 - }; - var pendingRequestCount = 0; - - // We have three virtual states here: - // OFF -> VIBRATION -> MUTE - var muteState = 'OFF'; - - for (var channel in currentVolume) { - (function(channel) { - var setting = 'audio.volume.' + channel; - SettingsListener.observe(setting, 5, function onSettingsChange(volume) { - if (pendingRequestCount) - return; - - var max = MAX_VOLUME[channel]; - currentVolume[channel] = - parseInt(Math.max(0, Math.min(max, volume)), 10); - }); - })(channel); - } - - SettingsListener.observe('vibration.enabled', true, function(vibration) { - if (pendingRequestCount) - return; - - vibrationEnabled = vibration; - }); - - var activeTimeout = 0; - - // When hardware volume key is pressed, we need to decide which channel we - // should toggle. - // This method returns the string for setting key 'audio.volume.*' represents - // that. - // Note: this string does not always equal to currentChannel since some - // different channels are grouped together to listen to the same setting. - function getChannel() { - if (onCall()) - return 'telephony'; - - switch (currentChannel) { - case 'normal': - case 'content': - return 'content'; - case 'telephony': - return 'telephony'; - case 'alarm': - return 'alarm'; - case 'notification': - case 'ringer': - default: - return 'notification'; - } - } - - function getVolumeState(currentVolume, delta, channel) { - if (channel == 'notification') { - if (currentVolume + delta <= 0) { - if (currentVolume == 0 && vibrationEnabled) { - vibrationEnabled = false; - } else if (currentVolume > 0 && !vibrationEnabled) { - vibrationEnabled = true; - } - return 'MUTE'; - } else { - return 'OFF'; - } - } else { - if (currentVolume + delta <= 0) { - return 'MUTE'; - } else { - return 'OFF'; - } - } - } - - function changeVolume(delta, channel) { - channel = channel ? channel : getChannel(); - - muteState = getVolumeState(currentVolume[channel], delta, channel); - - var volume = currentVolume[channel] + delta; - - currentVolume[channel] = volume = - Math.max(0, Math.min(MAX_VOLUME[channel], volume)); - - var overlay = document.getElementById('system-overlay'); - var notification = document.getElementById('volume'); - var overlayClasses = overlay.classList; - var classes = notification.classList; - - switch (muteState) { - case 'OFF': - classes.remove('mute'); - if (vibrationEnabled) { - classes.add('vibration'); - } else { - classes.remove('vibration'); - } - break; - case 'MUTE': - classes.add('mute'); - if (channel == 'notification') { - if (vibrationEnabled) { - classes.add('vibration'); - SettingsListener.getSettingsLock().set({ - 'vibration.enabled': true - }); - } else { - classes.remove('vibration'); - SettingsListener.getSettingsLock().set({ - 'vibration.enabled': false - }); - } - } - break; - } - - var steps = - Array.prototype.slice.call(notification.querySelectorAll('div'), 0); - - for (var i = 0; i < steps.length; i++) { - var step = steps[i]; - if (i < volume) { - step.classList.add('active'); - } else { - step.classList.remove('active'); - } - } - - overlayClasses.add('volume'); - classes.add('visible'); - window.clearTimeout(activeTimeout); - activeTimeout = window.setTimeout(function hideSound() { - overlayClasses.remove('volume'); - classes.remove('visible'); - }, 1500); - - if (!window.navigator.mozSettings) - return; - - pendingRequestCount++; - var req; - - notification.dataset.channel = channel; - - var settingObject = {}; - settingObject['audio.volume.' + channel] = volume; - - req = SettingsListener.getSettingsLock().set(settingObject); - - req.onsuccess = function onSuccess() { - pendingRequestCount--; - }; - - req.onerror = function onError() { - pendingRequestCount--; - }; - } -})(); - diff --git a/apps/system/js/source_view.js b/apps/system/js/source_view.js deleted file mode 100644 index dc6b8e4..0000000 --- a/apps/system/js/source_view.js +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var SourceView = { - get viewer() { - return document.getElementById('appViewsource'); - }, - - get active() { - return !this.viewer ? false : this.viewer.style.visibility === 'visible'; - }, - - init: function sv_init() { - window.addEventListener('home+volume', function() { - if (ScreenManager.screenEnabled) - SourceView.toggle(); - }); - window.addEventListener('locked', function() { - SourceView.hide(); - }); - }, - - show: function sv_show() { - var viewsource = this.viewer; - if (!viewsource) { - var style = '#appViewsource { ' + - ' position: absolute;' + - ' top: -moz-calc(10%);' + - ' left: -moz-calc(10%);' + - ' width: -moz-calc(80% - 2 * 15px);' + - ' height: -moz-calc(80% - 2 * 15px);' + - ' visibility: hidden;' + - ' margin: 15px;' + - ' background-color: white;' + - ' opacity: 0.92;' + - ' color: black;' + - ' z-index: 9999;' + - '}'; - document.styleSheets[0].insertRule(style, 0); - - viewsource = document.createElement('iframe'); - viewsource.id = 'appViewsource'; - document.body.appendChild(viewsource); - } - - var url = WindowManager.getDisplayedApp(); - if (!url) - // Assume the home screen is the visible app. - url = window.location.toString(); - viewsource.src = 'view-source: ' + url; - viewsource.style.visibility = 'visible'; - }, - - hide: function sv_hide() { - var viewsource = this.viewer; - if (viewsource) { - viewsource.style.visibility = 'hidden'; - viewsource.src = 'about:blank'; - } - }, - - toggle: function sv_toggle() { - this.active ? this.hide() : this.show(); - } -}; diff --git a/apps/system/js/statusbar.js b/apps/system/js/statusbar.js deleted file mode 100644 index 1d95d99..0000000 --- a/apps/system/js/statusbar.js +++ /dev/null @@ -1,618 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var StatusBar = { - /* all elements that are children nodes of the status bar */ - ELEMENTS: ['notification', 'time', - 'battery', 'wifi', 'data', 'flight-mode', 'signal', 'network-activity', - 'tethering', 'alarm', 'bluetooth', 'mute', 'headphones', - 'recording', 'sms', 'geolocation', 'usb', 'label', 'system-downloads', - 'call-forwarding'], - - /* Timeout for 'recently active' indicators */ - kActiveIndicatorTimeout: 60 * 1000, - - /* Whether or not status bar is actively updating or not */ - active: true, - - /* Some values that sync from mozSettings */ - settingValues: {}, - - /* Keep the DOM element references here */ - icons: {}, - - /* A mapping table between technology names - we would get from API v.s. the icon we want to show. */ - mobileDataIconTypes: { - 'lte': '4G', // 4G LTE - 'ehrpd': '4G', // 4G CDMA - 'hspa+': 'H+', // 3.5G HSPA+ - 'hsdpa': 'H', 'hsupa': 'H', 'hspa': 'H', // 3.5G HSDPA - 'evdo0': '3G', 'evdoa': '3G', 'evdob': '3G', '1xrtt': '3G', // 3G CDMA - 'umts': '3G', // 3G - 'edge': 'E', // EDGE - 'is95a': '2G', 'is95b': '2G', // 2G CDMA - 'gprs': '2G' - }, - - geolocationActive: false, - geolocationTimer: null, - - recordingActive: false, - recordingTimer: null, - - umsActive: false, - - headphonesActive: false, - - /** - * this keeps how many current installs/updates we do - * it triggers the icon "systemDownloads" - */ - systemDownloadsCount: 0, - - /* For other modules to acquire */ - get height() { - if (this.screen.classList.contains('fullscreen-app') || - document.mozFullScreen) { - return 0; - } else if (this.screen.classList.contains('active-statusbar')) { - return this.attentionBar.offsetHeight; - } else { - return this._cacheHeight || - (this._cacheHeight = this.element.getBoundingClientRect().height); - } - }, - - init: function sb_init() { - this.getAllElements(); - - var settings = { - 'ril.radio.disabled': ['signal', 'data'], - 'ril.data.enabled': ['data'], - 'wifi.enabled': ['wifi'], - 'bluetooth.enabled': ['bluetooth'], - 'tethering.usb.enabled': ['tethering'], - 'tethering.wifi.enabled': ['tethering'], - 'tethering.wifi.connectedClients': ['tethering'], - 'tethering.usb.connectedClients': ['tethering'], - 'ring.enabled': ['mute'], - 'alarm.enabled': ['alarm'], - 'vibration.enabled': ['vibration'], - 'ril.cf.enabled': ['callForwarding'] - }; - - var self = this; - for (var settingKey in settings) { - (function sb_setSettingsListener(settingKey) { - SettingsListener.observe(settingKey, false, - function sb_settingUpdate(value) { - self.settingValues[settingKey] = value; - settings[settingKey].forEach( - function sb_callUpdate(name) { - self.update[name].call(self); - } - ); - } - ); - self.settingValues[settingKey] = false; - })(settingKey); - } - - // Listen to 'screenchange' from screen_manager.js - window.addEventListener('screenchange', this); - - // Listen to 'geolocation-status' and 'recording-status' mozChromeEvent - window.addEventListener('mozChromeEvent', this); - - // Listen to 'bluetoothconnectionchange' from bluetooth.js - window.addEventListener('bluetoothconnectionchange', this); - - // Listen to 'moztimechange' - window.addEventListener('moztimechange', this); - - this.systemDownloadsCount = 0; - this.setActive(true); - }, - - handleEvent: function sb_handleEvent(evt) { - switch (evt.type) { - case 'screenchange': - this.setActive(evt.detail.screenEnabled); - break; - - case 'chargingchange': - case 'levelchange': - case 'statuschange': - this.update.battery.call(this); - break; - - case 'voicechange': - this.update.signal.call(this); - this.update.label.call(this); - break; - - case 'cardstatechange': - this.update.signal.call(this); - this.update.label.call(this); - this.update.data.call(this); - break; - - case 'callschanged': - this.update.signal.call(this); - break; - - case 'iccinfochange': - this.update.label.call(this); - break; - - case 'datachange': - this.update.data.call(this); - break; - - case 'bluetoothconnectionchange': - this.update.bluetooth.call(this); - break; - - case 'moztimechange': - this.update.time.call(this); - break; - - case 'mozChromeEvent': - switch (evt.detail.type) { - case 'geolocation-status': - this.geolocationActive = evt.detail.active; - this.update.geolocation.call(this); - break; - - case 'recording-status': - this.recordingActive = evt.detail.active; - this.update.recording.call(this); - break; - - case 'volume-state-changed': - this.umsActive = evt.detail.active; - this.update.usb.call(this); - break; - - case 'headphones-status-changed': - this.headphonesActive = (evt.detail.state != 'off'); - this.update.headphones.call(this); - break; - } - - break; - - case 'moznetworkupload': - case 'moznetworkdownload': - this.update.networkActivity.call(this); - break; - } - }, - - setActive: function sb_setActive(active) { - this.active = active; - if (active) { - this.update.time.call(this); - - var battery = window.navigator.battery; - if (battery) { - battery.addEventListener('chargingchange', this); - battery.addEventListener('levelchange', this); - battery.addEventListener('statuschange', this); - this.update.battery.call(this); - } - - var conn = window.navigator.mozMobileConnection; - if (conn) { - conn.addEventListener('voicechange', this); - conn.addEventListener('iccinfochange', this); - conn.addEventListener('datachange', this); - this.update.signal.call(this); - this.update.data.call(this); - } - - window.addEventListener('wifi-statuschange', - this.update.wifi.bind(this)); - this.update.wifi.call(this); - - window.addEventListener('moznetworkupload', this); - window.addEventListener('moznetworkdownload', this); - } else { - clearTimeout(this._clockTimer); - - var battery = window.navigator.battery; - if (battery) { - battery.removeEventListener('chargingchange', this); - battery.removeEventListener('levelchange', this); - battery.removeEventListener('statuschange', this); - } - - var conn = window.navigator.mozMobileConnection; - if (conn) { - conn.removeEventListener('voicechange', this); - conn.removeEventListener('iccinfochange', this); - conn.removeEventListener('datachange', this); - } - - window.removeEventListener('moznetworkupload', this); - window.removeEventListener('moznetworkdownload', this); - } - }, - - update: { - label: function sb_updateLabel() { - var conn = window.navigator.mozMobileConnection; - var label = this.icons.label; - var l10nArgs = JSON.parse(label.dataset.l10nArgs || '{}'); - - if (!conn || !conn.voice || !conn.voice.connected || - conn.voice.emergencyCallsOnly) { - delete l10nArgs.operator; - label.dataset.l10nArgs = JSON.stringify(l10nArgs); - - label.dataset.l10nId = ''; - label.textContent = l10nArgs.date; - - return; - } - - var operatorInfos = MobileOperator.userFacingInfo(conn); - l10nArgs.operator = operatorInfos.operator; - - if (operatorInfos.region) { - l10nArgs.operator += ' ' + operatorInfos.region; - } - - label.dataset.l10nArgs = JSON.stringify(l10nArgs); - - label.dataset.l10nId = 'statusbarLabel'; - label.textContent = navigator.mozL10n.get('statusbarLabel', l10nArgs); - }, - - time: function sb_updateTime() { - // Schedule another clock update when a new minute rolls around - var _ = navigator.mozL10n.get; - var f = new navigator.mozL10n.DateTimeFormat(); - var now = new Date(); - var sec = now.getSeconds(); - if (this._clockTimer) - window.clearTimeout(this._clockTimer); - this._clockTimer = - window.setTimeout((this.update.time).bind(this), (59 - sec) * 1000); - - var formated = f.localeFormat(now, _('shortTimeFormat')); - formated = formated.replace(/\s?(AM|PM)\s?/i, '<span>$1</span>'); - this.icons.time.innerHTML = formated; - - var label = this.icons.label; - var l10nArgs = JSON.parse(label.dataset.l10nArgs || '{}'); - l10nArgs.date = f.localeFormat(now, _('statusbarDateFormat')); - label.dataset.l10nArgs = JSON.stringify(l10nArgs); - this.update.label.call(this); - }, - - battery: function sb_updateBattery() { - var battery = window.navigator.battery; - if (!battery) - return; - - var icon = this.icons.battery; - - icon.hidden = false; - icon.dataset.charging = battery.charging; - icon.dataset.level = Math.floor(battery.level * 10) * 10; - }, - - networkActivity: function sb_updateNetworkActivity() { - // Each time we receive an update, make network activity indicator - // show up for 500ms. - - var icon = this.icons.networkActivity; - - clearTimeout(this._networkActivityTimer); - icon.hidden = false; - - this._networkActivityTimer = setTimeout(function hideNetActivityIcon() { - icon.hidden = true; - }, 500); - }, - - signal: function sb_updateSignal() { - var conn = window.navigator.mozMobileConnection; - if (!conn || !conn.voice) - return; - - var voice = conn.voice; - var icon = this.icons.signal; - var flightModeIcon = this.icons.flightMode; - var _ = navigator.mozL10n.get; - - if (this.settingValues['ril.radio.disabled']) { - // "Airplane Mode" - icon.hidden = true; - flightModeIcon.hidden = false; - return; - } - - flightModeIcon.hidden = true; - icon.hidden = false; - - if (conn.cardState === 'absent') { - // no SIM - delete icon.dataset.level; - delete icon.dataset.emergency; - delete icon.dataset.searching; - delete icon.dataset.roaming; - } else if (voice.connected || this.hasActiveCall()) { - // "Carrier" / "Carrier (Roaming)" - icon.dataset.level = Math.ceil(voice.relSignalStrength / 20); // 0-5 - icon.dataset.roaming = voice.roaming; - - delete icon.dataset.emergency; - delete icon.dataset.searching; - } else { - // "No Network" / "Emergency Calls Only (REASON)" / trying to connect - icon.dataset.level = -1; - // logically, we should have "&& !voice.connected" as well but we - // already know this. - icon.dataset.searching = (!voice.emergencyCallsOnly && - voice.state !== 'notSearching'); - icon.dataset.emergency = (voice.emergencyCallsOnly); - delete icon.dataset.roaming; - } - - if (voice.emergencyCallsOnly) { - this.addCallListener(); - } else { - this.removeCallListener(); - } - - }, - - data: function sb_updateSignal() { - var conn = window.navigator.mozMobileConnection; - if (!conn || !conn.data) - return; - - var data = conn.data; - var icon = this.icons.data; - - if (this.settingValues['ril.radio.disabled'] || - !this.settingValues['ril.data.enabled'] || - !this.icons.wifi.hidden || !data.connected) { - icon.hidden = true; - - return; - } - - icon.hidden = false; - icon.dataset.type = - this.mobileDataIconTypes[data.type] || 'circle'; - }, - - - wifi: function sb_updateWifi() { - var wifiManager = window.navigator.mozWifiManager; - if (!wifiManager) - return; - - var icon = this.icons.wifi; - var wasHidden = icon.hidden; - - if (!this.settingValues['wifi.enabled']) { - icon.hidden = true; - if (!wasHidden) - this.update.data.call(this); - - return; - } - - switch (wifiManager.connection.status) { - case 'disconnected': - icon.hidden = true; - - break; - - case 'connecting': - case 'associated': - icon.hidden = false; - icon.dataset.connecting = true; - icon.dataset.level = 0; - - break; - - case 'connected': - icon.hidden = false; - - var relSignalStrength = - wifiManager.connectionInformation.relSignalStrength; - icon.dataset.level = Math.floor(relSignalStrength / 25); - - break; - } - - if (icon.hidden !== wasHidden) - this.update.data.call(this); - }, - - tethering: function sb_updateTethering() { - var icon = this.icons.tethering; - icon.hidden = !(this.settingValues['tethering.usb.enabled'] || - this.settingValues['tethering.wifi.enabled']); - - icon.dataset.active = - (this.settingValues['tethering.wifi.connectedClients'] !== 0) || - (this.settingValues['tethering.usb.connectedClients'] !== 0); - }, - - bluetooth: function sb_updateBluetooth() { - var icon = this.icons.bluetooth; - - icon.hidden = !this.settingValues['bluetooth.enabled']; - icon.dataset.active = Bluetooth.connected; - }, - - alarm: function sb_updateAlarm() { - this.icons.alarm.hidden = !this.settingValues['alarm.enabled']; - }, - - mute: function sb_updateMute() { - this.icons.mute.hidden = - (this.settingValues['ring.enabled'] == true); - }, - - vibration: function sb_vibration() { - var vibrate = (this.settingValues['vibration.enabled'] == true); - if (vibrate) { - this.icons.mute.classList.add('vibration'); - } else { - this.icons.mute.classList.remove('vibration'); - } - }, - - recording: function sb_updateRecording() { - window.clearTimeout(this.recordingTimer); - - var icon = this.icons.recording; - icon.dataset.active = this.recordingActive; - - if (this.recordingActive) { - // Geolocation is currently active, show the active icon. - icon.hidden = false; - return; - } - - // Geolocation is currently inactive. - // Show the inactive icon and hide it after kActiveIndicatorTimeout - this.recordingTimer = window.setTimeout(function hideGeoIcon() { - icon.hidden = true; - }, this.kActiveIndicatorTimeout); - }, - - sms: function sb_updateSms() { - // We are not going to show this for v1 - - // this.icon.sms.hidden = ? - // this.icon.sms.dataset.num = ?; - }, - - geolocation: function sb_updateGeolocation() { - window.clearTimeout(this.geolocationTimer); - - var icon = this.icons.geolocation; - icon.dataset.active = this.geolocationActive; - - if (this.geolocationActive) { - // Geolocation is currently active, show the active icon. - icon.hidden = false; - return; - } - - // Geolocation is currently inactive. - // Show the inactive icon and hide it after kActiveIndicatorTimeout - this.geolocationTimer = window.setTimeout(function hideGeoIcon() { - icon.hidden = true; - }, this.kActiveIndicatorTimeout); - }, - - usb: function sb_updateUsb() { - var icon = this.icons.usb; - icon.hidden = !this.umsActive; - }, - - headphones: function sb_updateHeadphones() { - var icon = this.icons.headphones; - icon.hidden = !this.headphonesActive; - }, - - systemDownloads: function sb_updatesystemDownloads() { - var icon = this.icons.systemDownloads; - icon.hidden = (this.systemDownloadsCount === 0); - }, - - callForwarding: function sb_updateCallForwarding() { - var icon = this.icons.callForwarding; - icon.hidden = !this.settingValues['ril.cf.enabled']; - } - }, - - hasActiveCall: function sb_hasActiveCall() { - var telephony = navigator.mozTelephony; - - // will return true as soon as we begin dialing - return !!(telephony && telephony.active); - }, - - addCallListener: function sb_addCallListener() { - var telephony = navigator.mozTelephony; - if (telephony) { - telephony.addEventListener('callschanged', this); - } - }, - - removeCallListener: function sb_addCallListener() { - var telephony = navigator.mozTelephony; - if (telephony) { - telephony.removeEventListener('callschanged', this); - } - }, - - updateNotification: function sb_updateNotification(count) { - var icon = this.icons.notification; - if (!count) { - icon.hidden = true; - return; - } - - icon.hidden = false; - icon.dataset.num = count; - }, - - updateNotificationUnread: function sb_updateNotificationUnread(unread) { - this.icons.notification.dataset.unread = unread; - }, - - incSystemDownloads: function sb_incSystemDownloads() { - this.systemDownloadsCount++; - this.update.systemDownloads.call(this); - }, - - decSystemDownloads: function sb_decSystemDownloads() { - if (--this.systemDownloadsCount < 0) { - this.systemDownloadsCount = 0; - } - - this.update.systemDownloads.call(this); - }, - - getAllElements: function sb_getAllElements() { - // ID of elements to create references - - var toCamelCase = function toCamelCase(str) { - return str.replace(/\-(.)/g, function replacer(str, p1) { - return p1.toUpperCase(); - }); - }; - - this.ELEMENTS.forEach((function createElementRef(name) { - this.icons[toCamelCase(name)] = - document.getElementById('statusbar-' + name); - }).bind(this)); - - this.element = document.getElementById('statusbar'); - this.screen = document.getElementById('screen'); - this.attentionBar = document.getElementById('attention-bar'); - } -}; - -if (navigator.mozL10n.readyState == 'complete' || - navigator.mozL10n.readyState == 'interactive') { - StatusBar.init(); -} else { - window.addEventListener('localized', StatusBar.init.bind(StatusBar)); -} - - diff --git a/apps/system/js/storage.js b/apps/system/js/storage.js deleted file mode 100644 index ff7b10e..0000000 --- a/apps/system/js/storage.js +++ /dev/null @@ -1,60 +0,0 @@ -var Storage = { - - automounterDisable: 0, - automounterEnable: 1, - automounterDisableWhenUnplugged: 2, - - umsEnabled: 'ums.enabled', - umsMode: 'ums.mode', - - init: function storageInit() { - this.setMode(this.automounterDisable, 'init'); - window.addEventListener('lock', this); - window.addEventListener('unlock', this); - - SettingsListener.observe(this.umsEnabled, false, function umsChanged(val) { - if (LockScreen.locked) { - // covers startup - Storage.setMode(Storage.automounterDisable, 'screen locked'); - } else { - Storage.setMode(Storage.modeFromBool(val), 'change in ums.enabled'); - } - }); - }, - - modeFromBool: function storageModeFromBool(val) { - return val ? this.automounterEnable : this.automounterDisable; - }, - - setMode: function storageSetMode(val, reason) { - if (!window.navigator.mozSettings) - return; - - //console.info('Setting', this.umsMode, 'to', val, 'due to', reason); - var param = {}; - param[this.umsMode] = val; - SettingsListener.getSettingsLock().set(param); - }, - - handleEvent: function storageHandleEvent(e) { - switch (e.type) { - case 'lock': - this.setMode(this.automounterDisableWhenUnplugged, 'screen locked'); - break; - case 'unlock': - if (!window.navigator.mozSettings) - return; - - var req = SettingsListener.getSettingsLock().get(this.umsEnabled); - req.onsuccess = function umsEnabledFetched() { - var mode = Storage.modeFromBool(req.result[Storage.umsEnabled]); - Storage.setMode(mode, 'screen unlocked'); - }; - break; - default: - return; - } - } -}; - -Storage.init(); diff --git a/apps/system/js/system_banner.js b/apps/system/js/system_banner.js deleted file mode 100644 index 89028e2..0000000 --- a/apps/system/js/system_banner.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -var SystemBanner = { - banner: document.getElementById('system-banner'), - - // Shows a banner with a given message. - // Optionally shows a button with a given label/callback. - // buttonParams = { label: ..., callback: ... } - show: function sb_show(message, buttonParams) { - var banner = this.banner; - banner.firstElementChild.textContent = message; - - var button = banner.querySelector('button'); - if (buttonParams) { - banner.dataset.button = true; - button.textContent = buttonParams.label; - button.addEventListener('click', buttonParams.callback); - } - - banner.addEventListener('animationend', function animationend() { - banner.removeEventListener('animationend', animationend); - banner.classList.remove('visible'); - - if (buttonParams) { - banner.dataset.button = false; - button.removeEventListener('click', buttonParams.callback); - button.classList.remove('visible'); - } - }); - - banner.classList.add('visible'); - } -}; diff --git a/apps/system/js/system_dialog.js b/apps/system/js/system_dialog.js deleted file mode 100644 index b0c32d8..0000000 --- a/apps/system/js/system_dialog.js +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - -/** - * System app is made of a top-level `<div ="screen"></div>` DOM element - * which contain all possible screens displayed by the app. - * Multiple screens can be displayed at a time. We store the list of currently - * visible screens into this DOM element class attribute. - */ -var SystemScreen = { - screen: document.getElementById('screen'), - - show: function ss_show(screenName) { - this.screen.classList.add(screenName); - }, - - hide: function ss_show(screenName) { - this.screen.classList.remove(screenName); - }, - - isVisible: function ss_isVisible(screenName) { - return this.screen.classList.contains(screenName); - } -}; - -/** - * System app displays various kind of dialogs. - * A dialog is a system app 'screen' that has a high z-index and is used to be - * displayed on top of other apps. But it doesn't display over the status bar, - * nor the eventually displayed keyboard. - * - * `SystemDialog` except the dialog DOM Element `id`. - * This DOM Element has to have a DOM attribute 'role' set to 'dialog'. - * - * It also supports a second `options` object with following attributes: - * `onHide`: function called when dialog is hidden, either when `hide()` - * method is called, or when dialog is automatically hidden on - * home button press - */ -function SystemDialog(id, options) { - var overlay = document.getElementById('dialog-overlay'); - var dialog = document.getElementById(id); - var screenName = 'dialog'; - - // Listen to keyboard visibility changes and window resizing - // in order to resize the dialog accordingly - function updateHeight(keyboardHeight) { - if (SystemScreen.isVisible(screenName)) { - var height = window.innerHeight - - (keyboardHeight ? keyboardHeight : 0) - - StatusBar.height; - overlay.style.height = height + 'px'; - } - }; - function handleEvent(evt) { - switch (evt.type) { - case 'resize': - case 'keyboardhide': - updateHeight(); - break; - case 'keyboardchange': - updateHeight(evt.detail.height); - break; - case 'home': - case 'holdhome': - // Automatically hide the dialog on home button press - if (SystemScreen.isVisible(screenName)) { - hide(evt.type); - // Prevent WindowManager to shift homescreen to the first page - // when the dialog is on top of the homescreen - var displayedApp = WindowManager.getDisplayedApp(); - var displayedAppFrame = WindowManager.getAppFrame(displayedApp); - if (evt.type == 'home' && - displayedAppFrame.classList.contains('homescreen')) - evt.stopImmediatePropagation(); - } - break; - } - }; - window.addEventListener('resize', handleEvent); - window.addEventListener('keyboardchange', handleEvent); - window.addEventListener('keyboardhide', handleEvent); - window.addEventListener('home', handleEvent); - window.addEventListener('holdhome', handleEvent); - - function show() { - dialog.hidden = false; - dialog.classList.add(id); - SystemScreen.show(screenName); - updateHeight(); - } - - function hide(reason) { - dialog.hidden = true; - dialog.classList.remove(id); - SystemScreen.hide(screenName); - if (typeof(options.onHide) == 'function') - options.onHide(reason); - } - - function isVisible() { - return SystemScreen.isVisible(screenName) && - overlay.classList.contains(id); - } - - return { - show: show, - hide: hide, - isVisible: isVisible - }; -} - diff --git a/apps/system/js/trusted_ui.js b/apps/system/js/trusted_ui.js deleted file mode 100644 index 43bea21..0000000 --- a/apps/system/js/trusted_ui.js +++ /dev/null @@ -1,334 +0,0 @@ -/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil -*- */ -/* vim: set ft=javascript sw=2 ts=2 autoindent cindent expandtab: */ - -'use strict'; - -var TrustedUIManager = { - - get currentStack() { - if (!this._dialogStacks[this._lastDisplayedApp]) { - this._dialogStacks[this._lastDisplayedApp] = []; - } - return this._dialogStacks[this._lastDisplayedApp]; - }, - - _dialogStacks: {}, - _lastDisplayedApp: null, - - overlay: document.getElementById('dialog-overlay'), - - popupContainer: document.getElementById('trustedui-container'), - - popupContainerInner: document.getElementById('trustedui-inner'), - - container: document.getElementById('trustedui-frame-container'), - - dialogTitle: document.getElementById('trustedui-title'), - - screen: document.getElementById('screen'), - - loadingIcon: document.getElementById('statusbar-loading'), - - throbber: document.getElementById('trustedui-throbber'), - - closeButton: document.getElementById('trustedui-close'), - - hasTrustedUI: function trui_hasTrustedUI(origin) { - return (this._dialogStacks[origin] && this._dialogStacks[origin].length); - }, - - getDialogFromOrigin: function trui_getDialogFromOrigin(origin) { - if (!origin || !this.hasTrustedUI(origin)) - return false; - var stack = this._dialogStacks[origin]; - return stack[stack.length - 1]; - }, - - init: function trui_init() { - window.addEventListener('home', this); - window.addEventListener('holdhome', this); - window.addEventListener('appwillopen', this); - window.addEventListener('appopen', this); - window.addEventListener('appwillclose', this); - window.addEventListener('appterminated', this); - window.addEventListener('keyboardhide', this); - window.addEventListener('keyboardchange', this); - window.addEventListener('mozbrowserloadstart', this); - window.addEventListener('mozbrowserloadend', this); - this.closeButton.addEventListener('click', this); - }, - - hideTrustedApp: function trui_hideTrustedApp() { - var self = this; - this.popupContainer.classList.add('closing'); - this.popupContainer.addEventListener('transitionend', function hide() { - this.removeEventListener('transitionend', hide); - self.hide(); - }); - }, - - reopenTrustedApp: function trui_reopenTrustedApp() { - this._hideAllFrames(); - var dialog = this._getTopDialog(); - this._makeDialogVisible(dialog); - this.popupContainer.classList.add('closing'); - this.show(); - this.popupContainer.classList.remove('closing'); - }, - - open: function trui_open(name, frame, chromeEventId, onCancelCB) { - screen.mozLockOrientation('portrait'); - this._hideAllFrames(); - if (this.currentStack.length) { - this._makeDialogHidden(this._getTopDialog()); - this._pushNewDialog(name, frame, chromeEventId, onCancelCB); - } else { - // first time, spin back to home screen first - this.popupContainer.classList.add('up'); - this.popupContainer.classList.remove('closing'); - WindowManager.hideCurrentApp(function openTrustedUI() { - this.popupContainer.classList.remove('up'); - this._pushNewDialog(name, frame, chromeEventId, onCancelCB); - }.bind(this)); - } - }, - - close: function trui_close(chromeEventId, callback) { - var stackSize = this.currentStack.length; - - this._restoreOrientation(); - - if (callback) - callback(); - - if (stackSize === 0) { - // nothing to close. what are you doing? - return; - } else if (stackSize === 1) { - // only one dialog, so transition back to main app - var self = this; - var container = this.popupContainer; - if (!CardsView.cardSwitcherIsShown()) { - WindowManager.restoreCurrentApp(); - container.addEventListener('transitionend', function wait(event) { - this.removeEventListener('transitionend', wait); - self._closeDialog(chromeEventId); - }); - } else { - WindowManager.restoreCurrentApp(this._lastDisplayedApp); - this._closeDialog(chromeEventId); - } - - // The css transition caused by the removal of the trustedui - // class by the hide() method will trigger a 'transitionend' - // event ultimately to be fired. - this.hide(); - - window.focus(); - } else { - this._closeDialog(chromeEventId); - } - }, - - _dispatchCloseEvent: function dispatchCloseEvent(eventId) { - var _ = navigator.mozL10n.get; - if (!eventId) - return; - var event = document.createEvent('customEvent'); - var details = { - id: eventId, - type: 'cancel', - errorMsg: _('dialog-closed') - }; - event.initCustomEvent('mozContentEvent', true, true, details); - window.dispatchEvent(event); - }, - - _getTopDialog: function trui_getTopDialog() { - // get the topmost dialog for the _lastDisplayedApp or null - return this.currentStack[this.currentStack.length - 1]; - }, - - _pushNewDialog: function trui_PushNewDialog(name, frame, chromeEventId, - onCancelCB) { - // add some data attributes to the frame - var dataset = frame.dataset; - dataset.frameType = 'popup'; - dataset.frameName = frame.name; - dataset.frameOrigin = this._lastDisplayedApp; - - // make a shiny new dialog object - var dialog = { - name: name, - frame: frame, - chromeEventId: chromeEventId, - onCancelCB: onCancelCB - }; - - // push and show - this.currentStack.push(dialog); - this.dialogTitle.textContent = dialog.name; - this.container.appendChild(dialog.frame); - this._makeDialogVisible(dialog); - }, - - _makeDialogVisible: function trui_makeDialogVisible(dialog) { - // make sure the trusty ui is visible - this.popupContainer.classList.remove('closing'); - this.show(); - - // ensure the frame is visible and the dialog title is correct. - dialog.frame.classList.add('selected'); - this.dialogTitle.textContent = dialog.name; - }, - - _makeDialogHidden: function trui_makeDialogHidden(dialog) { - if (!dialog) - return; - this._restoreOrientation(); - dialog.frame.classList.remove('selected'); - }, - - _restoreOrientation: function trui_restoreOrientation() { - var app = WindowManager.getDisplayedApp(); - WindowManager.setOrientationForApp(app); - }, - - /** - * close the dialog identified by the chromeEventId - */ - _closeDialog: function trui_closeDialog(chromeEventId) { - if (this.currentStack.length === 0) - return; - - var found = false; - for (var i = 0; i < this.currentStack.length; i++) { - if (this.currentStack[i].chromeEventId === chromeEventId) { - var dialog = this.currentStack.splice(i, 1)[0]; - this.container.removeChild(dialog.frame); - found = true; - break; - } - } - - if (found && this.currentStack.length) { - this._makeDialogVisible(this._getTopDialog()); - } - }, - - hide: function trui_hide() { - this.screen.classList.remove('trustedui'); - }, - - show: function trui_show() { - this.screen.classList.add('trustedui'); - }, - - isVisible: function trui_show() { - return this.screen.classList.contains('trustedui'); - }, - - setHeight: function trui_setHeight(height) { - this.overlay.style.height = height + 'px'; - }, - - /* - * _destroyDialog: internal method called when the dialog is closed - * by user action (canceled), or when 'appterminated' is received. - * In either case, notify the caller. - */ - _destroyDialog: function trui_destroyDialog(origin) { - var stack = this.currentStack; - if (origin) - stack = this._dialogStacks[origin]; - - if (stack.length === 0) - return; - - // If the user closed a trusty UI dialog, they probably meant - // to close every dialog. - for (var i = 0, toClose = stack.length; i < toClose; i++) { - var dialog = this._getTopDialog(); - - // First, send a chrome event saying we've been canceled - this._dispatchCloseEvent(dialog.chromeEventId); - - // Now close and fire the cancel callback, if it exists - this.close(dialog.chromeEventId, dialog.onCancelCB); - } - this.hide(); - this.popupContainer.classList.remove('closing'); - }, - - _hideAllFrames: function trui_hideAllFrames() { - var selectedFrames = this.container.querySelectorAll('iframe.selected'); - for (var i = 0; i < selectedFrames.length; i++) { - selectedFrames[i].classList.remove('selected'); - } - }, - - handleEvent: function trui_handleEvent(evt) { - switch (evt.type) { - case 'home': - case 'holdhome': - if (!this.isVisible()) - return; - - this.hideTrustedApp(); - break; - case 'click': - // Close-button clicked - this._destroyDialog(); - break; - case 'appterminated': - this._destroyDialog(evt.detail.origin); - break; - case 'appwillopen': - // Hiding trustedUI when coming from Activity - if (this.isVisible()) - this.hideTrustedApp(); - - // Ignore homescreen - if (evt.target.classList.contains('homescreen')) - return; - this._lastDisplayedApp = evt.detail.origin; - if (this.currentStack.length) { - // Reopening an app with trustedUI - this.popupContainer.classList.remove('up'); - this._makeDialogVisible(this._getTopDialog()); - WindowManager.hideCurrentApp(); - this.reopenTrustedApp(); - } - break; - case 'appopen': - if (this.currentStack.length) { - screen.mozLockOrientation('portrait'); - } - break; - case 'appwillclose': - if (this.isVisible()) - return; - var dialog = this._getTopDialog(); - this._makeDialogHidden(dialog); - this.hide(); - break; - case 'keyboardchange': - this.setHeight(window.innerHeight - - StatusBar.height - evt.detail.height); - break; - case 'keyboardhide': - this.setHeight(window.innerHeight - StatusBar.height); - break; - case 'mozbrowserloadstart': - this.throbber.classList.add('loading'); - break; - case 'mozbrowserloadend': - this.throbber.classList.remove('loading'); - break; - } - } - -}; - -TrustedUIManager.init(); - diff --git a/apps/system/js/ttlview.js b/apps/system/js/ttlview.js deleted file mode 100644 index 81503af..0000000 --- a/apps/system/js/ttlview.js +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var TTLView = { - element: null, - - get visible() { - return this.element && this.element.style.display === 'block'; - }, - - hide: function tv_hide() { - if (this.element) - this.element.style.visibility = 'hidden'; - }, - - show: function tv_show() { - var element = this.element; - if (!element) { - element = document.createElement('div'); - element.id = 'debug-ttl'; - element.innerHTML = '00000'; - element.dataset.zIndexLevel = 'debug-ttl'; - - this.element = element; - document.getElementById('screen').appendChild(element); - - // this is fired when the app launching is initialized - window.addEventListener('appwillopen', function willopen(e) { - element.innerHTML = '00000'; - }); - - window.addEventListener('apploadtime', function apploadtime(e) { - element.innerHTML = e.detail.time + ' [' + e.detail.type + ']'; - }); - } - - element.style.visibility = 'visible'; - }, - - toggle: function tv_toggle() { - this.visible ? this.hide() : this.show(); - } -}; - -SettingsListener.observe('debug.ttl.enabled', false, function(value) { - !!value ? TTLView.show() : TTLView.hide(); -}); - diff --git a/apps/system/js/updatable.js b/apps/system/js/updatable.js deleted file mode 100644 index 57ce737..0000000 --- a/apps/system/js/updatable.js +++ /dev/null @@ -1,269 +0,0 @@ -'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); -}; diff --git a/apps/system/js/update_manager.js b/apps/system/js/update_manager.js deleted file mode 100644 index 8e37733..0000000 --- a/apps/system/js/update_manager.js +++ /dev/null @@ -1,623 +0,0 @@ -'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 - */ - -var UpdateManager = { - _mgmt: null, - _downloading: false, - _uncompressing: false, - _downloadedBytes: 0, - _errorTimeout: null, - _wifiLock: null, - _systemUpdateDisplayed: false, - _isDataConnectionWarningDialogEnabled: true, - _settings: null, - _conn: null, - NOTIFICATION_BUFFERING_TIMEOUT: 30 * 1000, - TOASTER_TIMEOUT: 1200, - - container: null, - message: null, - toaster: null, - toasterMessage: null, - laterButton: null, - notnowButton: null, - downloadButton: null, - downloadViaDataConnectionButton: null, - downloadDialog: null, - downloadViaDataConnectionDialog: null, - downloadDialogTitle: null, - downloadDialogList: null, - lastUpdatesAvailable: 0, - _notificationTimeout: null, - - updatableApps: [], - systemUpdatable: null, - updatesQueue: [], - downloadsQueue: [], - - init: function um_init() { - 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) { - 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('.message'); - - 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.container.onclick = this.containerClicked.bind(this); - this.laterButton.onclick = this.cancelPrompt.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); - - 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(); - - this._conn = window.navigator.mozMobileConnection; - if (this._conn) { - this._conn.addEventListener('datachange', this); - this.updateDataStatus(); - } - - window.asyncStorage. - getItem('gaia.system.isDataConnectionWarningDialogEnabled', - (function(value) { - value = value || true; - this._isDataConnectionWarningDialogEnabled = true; - this.downloadDialog.dataset.dataConnectionInlineWarning = !value; - }).bind(this)); - }, - - requestDownloads: function um_requestDownloads(evt) { - evt.preventDefault(); - - if (evt.target == this.downloadViaDataConnectionButton) { - window.asyncStorage. - setItem('gaia.system.isDataConnectionWarningDialogEnabled', false); - this._isDataConnectionWarningDialogEnabled = false; - this.downloadDialog.dataset.dataConnectionInlineWarning = true; - this.startDownloads(); - } else { - if (this._isDataConnectionWarningDialogEnabled && - this.downloadDialog.dataset.nowifi) { - this.downloadViaDataConnectionDialog.classList.add('visible'); - } else { - this.startDownloads(); - } - } - }, - - startDownloads: function um_startDownloads() { - this.downloadDialog.classList.remove('visible'); - this.downloadViaDataConnectionDialog.classList.remove('visible'); - - UtilityTray.show(); - - var checkValues = {}; - var dialog = this.downloadDialogList; - var checkboxes = dialog.querySelectorAll('input[type="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() { - CustomDialog.hide(); - - // 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) - return; - - var _ = navigator.mozL10n.get; - var self = this; - this._errorTimeout = setTimeout(function waitForMore() { - SystemBanner.show(_('downloadError')); - self._errorTimeout = null; - }, this.NOTIFICATION_BUFFERING_TIMEOUT); - }, - - containerClicked: function um_containerClicker() { - var _ = navigator.mozL10n.get; - - if (this._downloading) { - var cancel = { - title: _('no'), - callback: this.cancelPrompt.bind(this) - }; - - var confirm = { - title: _('yes'), - callback: this.cancelAllDownloads.bind(this) - }; - - CustomDialog.show(_('cancelAllDownloads'), _('wantToCancelAll'), - cancel, confirm); - } else { - this.showDownloadPrompt(); - } - - UtilityTray.hide(); - }, - - showDownloadPrompt: function um_showDownloadPrompt() { - var _ = navigator.mozL10n.get; - - this._systemUpdateDisplayed = false; - this.downloadDialogTitle.textContent = _('numberOfUpdates', { - n: this.updatesQueue.length - }); - - var updateList = ''; - - // 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'); - - // The user can choose not to update an app - var checkContainer = document.createElement('label'); - if (updatable instanceof SystemUpdatable) { - checkContainer.textContent = _('required'); - checkContainer.classList.add('required'); - this._systemUpdateDisplayed = true; - } else { - var checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.dataset.position = index; - checkbox.checked = true; - - var span = document.createElement('span'); - - checkContainer.appendChild(checkbox); - checkContainer.appendChild(span); - } - listItem.appendChild(checkContainer); - - var name = document.createElement('div'); - name.classList.add('name'); - name.textContent = updatable.name; - listItem.appendChild(name); - - if (updatable.size) { - var sizeItem = document.createElement('div'); - sizeItem.textContent = this._humanizeSize(updatable.size); - listItem.appendChild(sizeItem); - } else { - listItem.classList.add('nosize'); - } - - this.downloadDialogList.appendChild(listItem); - }, this); - - this.downloadDialog.classList.add('visible'); - }, - - updateDownloadButton: function() { - if (this._systemUpdateDisplayed) { - this.downloadButton.disabled = false; - return; - } - - var disabled = true; - - var dialog = this.downloadDialogList; - var checkboxes = dialog.querySelectorAll('input[type="checkbox"]'); - for (var i = 0; i < checkboxes.length; i++) { - if (checkboxes[i].checked) { - disabled = false; - break; - } - } - - this.downloadButton.disabled = disabled; - }, - - cancelPrompt: function um_cancelPrompt() { - CustomDialog.hide(); - this.downloadDialog.classList.remove('visible'); - }, - - cancelDataConnectionUpdatesPrompt: function um_cancelDCUpdatesPrompt() { - CustomDialog.hide(); - this.downloadViaDataConnectionDialog.classList.remove('visible'); - this.downloadDialog.classList.remove('visible'); - }, - - downloadProgressed: function um_downloadProgress(bytes) { - if (bytes > 0) { - this._downloadedBytes += bytes; - this.render(); - } - }, - - startedUncompressing: function um_startedUncompressing() { - this._uncompressing = true; - this.render(); - }, - - render: function um_render() { - var _ = navigator.mozL10n.get; - - this.toasterMessage.innerHTML = - _('updateAvailableInfo', { - n: this.updatesQueue.length - this.lastUpdatesAvailable - }); - - var message = ''; - if (this._downloading) { - if (this._uncompressing && this.downloadsQueue.length === 1) { - message = _('uncompressingMessage'); - } else { - var humanProgress = this._humanizeSize(this._downloadedBytes); - message = _('downloadingUpdateMessage', { - progress: humanProgress - }); - } - } else { - message = _('updateAvailableInfo', { - n: this.updatesQueue.length - }); - } - - this.message.innerHTML = message; - 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; - StatusBar.updateNotificationUnread(true); - 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; - StatusBar.incSystemDownloads(); - 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; - StatusBar.decSystemDownloads(); - 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.decExternalNotifications(); - } - }, - - displayNotificationIfHidden: function() { - if (!this.container.classList.contains('displayed')) { - this.container.classList.add('displayed'); - NotificationScreen.incExternalNotifications(); - } - }, - - 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; - var updatableApp = 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 'datachange': - this.updateDataStatus(); - break; - case 'offline': - this.updateOnlineStatus(); - break; - case 'online': - this.updateOnlineStatus(); - break; - case 'wifi-statuschange': - this.updateWifiStatus(); - break; - } - - if (evt.type !== 'mozChromeEvent') - return; - - var detail = evt.detail; - - if (detail.type && detail.type === 'update-available') { - this.systemUpdatable.size = detail.size; - 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; - - if (online) { - this.laterButton.classList.remove('full'); - } else { - this.laterButton.classList.add('full'); - } - }, - - updateWifiStatus: function su_updateWifiStatus() { - var wifiManager = window.navigator.mozWifiManager; - if (!wifiManager) - return; - - this.downloadDialog.dataset.nowifi = - (wifiManager.connection.status != 'connected'); - }, - - 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 - }); - }, - - _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]); - } -}; - -window.addEventListener('localized', function startup(evt) { - window.removeEventListener('localized', startup); - - UpdateManager.init(); -}); diff --git a/apps/system/js/utility_tray.js b/apps/system/js/utility_tray.js deleted file mode 100644 index 13f124d..0000000 --- a/apps/system/js/utility_tray.js +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var UtilityTray = { - shown: false, - - active: false, - - overlay: document.getElementById('utility-tray'), - - statusbar: document.getElementById('statusbar'), - - screen: document.getElementById('screen'), - - init: function ut_init() { - var touchEvents = ['touchstart', 'touchmove', 'touchend']; - - // XXX: Always use Mouse2Touch here. - // We cannot reliably detect touch support normally - // by evaluate (document instanceof DocumentTouch) on Desktop B2G. - touchEvents.forEach(function bindEvents(name) { - // window.addEventListener(name, this); - Mouse2Touch.addEventHandler(window, name, this); - }, this); - - window.addEventListener('screenchange', this); - window.addEventListener('home', this); - - this.overlay.addEventListener('transitionend', this); - }, - - handleEvent: function ut_handleEvent(evt) { - switch (evt.type) { - case 'home': - if (this.shown) { - this.hide(); - } - break; - - case 'screenchange': - if (this.shown && !evt.detail.screenEnabled) - this.hide(true); - - break; - - case 'touchstart': - if (LockScreen.locked) - return; - if (evt.target !== this.overlay && - evt.target !== this.statusbar) - return; - - this.active = true; - // XXX: required for Mouse2Touch fake events to function - evt.target.setCapture(true); - - this.onTouchStart(evt.touches[0]); - break; - - case 'touchmove': - if (!this.active) - return; - - this.onTouchMove(evt.touches[0]); - break; - - case 'touchend': - if (!this.active) - return; - - this.active = false; - // XXX: required for Mouse2Touch fake events to function - document.releaseCapture(); - - this.onTouchEnd(evt.changedTouches[0]); - break; - - case 'transitionend': - if (!this.shown) - this.screen.classList.remove('utility-tray'); - break; - } - }, - - onTouchStart: function ut_onTouchStart(touch) { - this.startX = touch.pageX; - this.startY = touch.pageY; - this.screen.classList.add('utility-tray'); - this.onTouchMove({ pageY: touch.pageY + this.statusbar.offsetHeight }); - }, - - onTouchMove: function ut_onTouchMove(touch) { - var screenHeight = this.overlay.getBoundingClientRect().height; - var y = touch.pageY; - if (y > this.lastY) - this.opening = true; - else if (y < this.lastY) - this.opening = false; - this.lastY = y; - var dy = -(this.startY - y); - if (this.shown) - dy += screenHeight; - dy = Math.min(screenHeight, dy); - - var style = this.overlay.style; - style.MozTransition = ''; - style.MozTransform = 'translateY(' + dy + 'px)'; - }, - - onTouchEnd: function ut_onTouchEnd(touch) { - this.opening ? this.show() : this.hide(); - }, - - hide: function ut_hide(instant) { - var alreadyHidden = !this.shown; - var style = this.overlay.style; - style.MozTransition = instant ? '' : '-moz-transform 0.2s linear'; - style.MozTransform = 'translateY(0)'; - this.shown = false; - if (instant) - this.screen.classList.remove('utility-tray'); - - if (!alreadyHidden) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('utilitytrayhide', true, true, null); - window.dispatchEvent(evt); - } - }, - - show: function ut_show(dy) { - var alreadyShown = this.shown; - var style = this.overlay.style; - style.MozTransition = '-moz-transform 0.2s linear'; - style.MozTransform = 'translateY(100%)'; - this.shown = true; - this.screen.classList.add('utility-tray'); - - if (!alreadyShown) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('utilitytrayshow', true, true, null); - window.dispatchEvent(evt); - } - } -}; - -UtilityTray.init(); diff --git a/apps/system/js/value_selector/date_picker.js b/apps/system/js/value_selector/date_picker.js deleted file mode 100644 index 9cdd484..0000000 --- a/apps/system/js/value_selector/date_picker.js +++ /dev/null @@ -1,568 +0,0 @@ -/** - * DatePicker is a html/js "widget" which will display - * all the days of a given month and allow selection of - * one specific day. It also implements controls to travel - * between months and jump into arbitrary time. - * - * The DatePicker itself contains no UI for the controls. - * - * Example usage: - * - * // the container will have elements for the month - * // added and removed from it. - * var picker = new DatePicker(container); - * - * // EVENTS: - * - * // called when the user clicks a day in the calendar. - * picker.onvaluechange = function(date) {} - * - * // called when the month of the calendar changes. - * // NOTE: at this time this can only happen programmatically - * // so there is only for control flow. - * picker.onmonthchange = function(date) {} - * - * // display a given year/month/date on the calendar the month - * // is zero based just like the JS date constructor. - * picker.display(2012, 0, 2); - * - * // move to the next month. - * picker.next(); - * - * // move to the previous month - * picker.previous(); - * - */ -var DatePicker = (function() { - 'use strict'; - - const SELECTED = 'selected'; - - var Calc = { - - NEXT_MONTH: 'next-month', - - OTHER_MONTH: 'other-month', - - PRESENT: 'present', - - FUTURE: 'future', - - PAST: 'past', - - get today() { - return new Date(); - }, - - daysInWeek: function() { - //XXX: We need to localize this... - return 7; - }, - - /** - * Checks is given date is today. - * - * @param {Date} date compare. - * @return {Boolean} true when today. - */ - isToday: function(date) { - return Calc.isSameDate(date, Calc.today); - }, - - /** - * Checks if two date objects occur - * on the same date (in the same month, year, day). - * Disregards time. - * - * @param {Date} first date. - * @param {Date} second date. - * @return {Boolean} true when they are the same date. - */ - isSameDate: function(first, second) { - return first.getMonth() == second.getMonth() && - first.getDate() == second.getDate() && - first.getFullYear() == second.getFullYear(); - }, - - /** - * Returns an identifier for a specific - * date in time for a given date - * - * @param {Date} date to get id for. - * @return {String} identifier. - */ - getDayId: function(date) { - return [ - date.getFullYear(), - date.getMonth(), - date.getDate() - ].join('-'); - }, - - /** - * Returns a date object from - * a string id for a date. - * - * @param {String} id identifier for date. - * @return {Date} date output. - */ - dateFromId: function(id) { - var parts = id.split('-'); - return new Date(parts[0], parts[1], parts[2]); - }, - - createDay: function(date, day, month, year) { - return new Date( - typeof year !== 'undefined' ? year : date.getFullYear(), - typeof month !== 'undefined' ? month : date.getMonth(), - typeof day !== 'undefined' ? day : date.getDate() - ); - }, - - /** - * Finds localized week start date of given date. - * - * @param {Date} date any day the week. - * @return {Date} first date in the week of given date. - */ - getWeekStartDate: function(date) { - var currentDay = date.getDay(); - var startDay = date.getDate() - currentDay; - - return Calc.createDay(date, startDay); - }, - - getWeekEndDate: function(date) { - // TODO: There are localization problems - // with this approach as we assume a 7 day week. - var start = Calc.getWeekStartDate(date); - start.setDate(start.getDate() + 7); - start.setMilliseconds(-1); - - return start; - }, - - /** - * Returns an array of dates objects. - * Inclusive. First and last are - * the given instances. - * - * @param {Date} start starting day. - * @param {Date} end ending day. - * @param {Boolean} includeTime include times start/end ? - */ - daysBetween: function(start, end, includeTime) { - if (!(start instanceof Date)) { - throw new Error('start date must be an instanceof Date'); - } - - if (!(end instanceof Date)) { - throw new Error('end date must be an instanceof Date'); - } - - if (start > end) { - var tmp = end; - end = start; - start = tmp; - tmp = null; - } - - var list = []; - var last = start.getDate(); - var cur; - - // for infinite loop protection. - var max = 500; - var macInc = 0; - - while (macInc++ < max) { - var next = new Date( - start.getFullYear(), - start.getMonth(), - ++last - ); - - if (next > end) { - throw new Error( - 'sanity fails next is greater then end' - ); - } - - if (!Calc.isSameDate(next, end)) { - list.push(next); - continue; - } - - break; - } - - if (includeTime) { - list.unshift(start); - list.push(end); - } else { - list.unshift(this.createDay(start)); - list.push(this.createDay(end)); - } - - return list; - }, - - /** - * Checks if date is in the past - * - * @param {Date} date to check. - * @return {Boolean} true when date is in the past. - */ - isPast: function(date) { - return (date.valueOf() < Calc.today.valueOf()); - }, - - /** - * Checks if date is in the future - * - * @param {Date} date to check. - * @return {Boolean} true when date is in the future. - */ - isFuture: function(date) { - return !Calc.isPast(date); - }, - - /** - * Based on the input date - * will return one of the following states - * - * past, present, future - * - * @param {Date} day for compare. - * @param {Date} month comparison month. - * @return {String} state. - */ - relativeState: function(day, month) { - var states; - //var today = Calc.today; - - // 1. the date is today (real time) - if (Calc.isToday(day)) { - return Calc.PRESENT; - } - - // 2. the date is in the past (real time) - if (Calc.isPast(day)) { - states = Calc.PAST; - // 3. the date is in the future (real time) - } else { - states = Calc.FUTURE; - } - - // 4. the date is not in the current month (relative time) - if (day.getMonth() !== month.getMonth()) { - states += ' ' + Calc.OTHER_MONTH; - } - - return states; - } - - }; - - /* expose calc */ - DatePicker.Calc = Calc; - - /** - * Initialize a date picker widget. - * - * @param {HTMLELement} element target of widget creation. - */ - function DatePicker(element) { - this.element = element; - // default time is set so next/previous work - // but we do not render the initial display here. - this._position = new Date(); - - // register events - element.addEventListener('click', this); - - //XXX: When the document is localized again - // we must also re-render the month because - // the week days may have changed? - // This will only happen when we change timezones - // unless we add this information to the locales. - } - - DatePicker.prototype = { - - /** - * Internal value not exposed so we can fire events - * when the getter/setter's are used. - * - * @type Date - */ - _value: null, - - SELECTED: 'selected', - - /** - * Gets current value - * - * @return {Null|Date} date or null. - */ - get value() { - return this._value; - }, - - /** - * Sets the current value of the date picker. - * When value differs from the currently set the - * `onvaluechange` event will be fired with the new/old value. - */ - set value(value) { - var old = this._value; - if (old !== value) { - this._value = value; - this._clearSelectedDay(value); - this.onvaluechange(value, old); - } - }, - - /** - * Clears the currently selected date of its 'selected' class. - * @private - */ - _clearSelectedDay: function(value) { - var target = this.element.querySelector('.' + SELECTED); - if (target) { - target.classList.remove(SELECTED); - } - }, - - handleEvent: function(e) { - switch (e.type) { - case 'click': - var target = e.target; - //XXX: if the html of the date elements changes - // this may also need to be altered as it - // assumes that there is no nesting of elements. - if (target.dataset.date) { - var date = Calc.dateFromId(target.dataset.date); - // order here is important as setting value will - // clear all the past selected dates... - this.value = date; - this._position = date; - // must come after setting selected date - target.classList.add(SELECTED); - } - break; - } - }, - - /** - * Getter is used for date normalization. - */ - get year() { - return this._position.getFullYear(); - }, - - /** - * Getter is used for date normalization. - */ - get month() { - return this._position.getMonth(); - }, - - get date() { - return this._position.getDate(); - }, - - /** - * Find the number of days in the given month/year. - * Month is zero based like the JS date constructor. - * - * @param {Numeric} year year value. - * @param {Numeric} month month value. - * @return {Numeric} number of days in month. - */ - _daysInMonth: function(year, month) { - var end = new Date(year, month + 1); - end.setMilliseconds(-1); - return end.getDate(); - }, - - /** - * Build the container for a day element. - * Each element has classes added to it based - * on what date it is created for. - * - * _today_ is based on today's actual date. - * Each date element also contains a data-date attribute - * with its current date as a string represented in - * the following format: "yyyy-mm-dd". - * - * Possible classes: - * - past - * - present (today) - * - future - * - other-month (day of another month but falls within same week) - * - * @param {Date} date date desired. - * @return {HTMLElement} dom element for day. - */ - _renderDay: function(date) { - var dayContainer = document.createElement('li'); - var dayEl = document.createElement('span'); - - dayContainer.className = Calc.relativeState( - date, - this._position - ); - - dayEl.dataset.date = Calc.getDayId(date); - dayEl.textContent = date.getDate(); - - dayContainer.appendChild(dayEl); - - return dayContainer; - }, - - /** - * Renders a set of dates and returns an ol element - * containing each date. - * - * @private - * @param {Array[Date]} dates array of dates. - * @return {HTMLELement} container for week. - */ - _renderWeek: function(dates) { - var container = document.createElement('ol'); - var i = 0; - var len = dates.length; - - for (; i < len; i++) { - container.appendChild( - this._renderDay(dates[i]) - ); - } - - return container; - }, - - /** - * Finds all dates in a given month by week. - * Includes leading and trailing days that occur - * outside the given year/month combination. - * - * @private - * @param {Numeric} year target year. - * @param {Numeric} month target month. - * @return {Array[Date]} array of dates. - */ - _getMonthDays: function(year, month) { - var date = new Date(year, month); - var dateEnd = new Date(year, month + 1); - dateEnd.setMilliseconds(-1); - - var start = Calc.getWeekStartDate(date); - var end = Calc.getWeekEndDate(dateEnd); - return Calc.daysBetween(start, end); - }, - - /** - * Returns a section element with all - * the days of the given month/year pair. - * - * Each month has a class for the number of weeks - * it contains. - * - * Possible values: - * - weeks-4 - * - weeks-5 - * - weeks-6 - * - * @private - */ - _renderMonth: function(year, month) { - var container = document.createElement('section'); - var days = this._getMonthDays(year, month); - var daysInWeek = Calc.daysInWeek(); - var weeks = days.length / daysInWeek; - var i = 0; - - container.classList.add('weeks-' + weeks); - - for (; i < weeks; i++) { - container.appendChild(this._renderWeek( - days.splice(0, daysInWeek) - )); - } - - return container; - }, - - /** - * Moves calendar one month into the future. - */ - next: function() { - this.display(this.year, this.month + 1, this.date); - }, - - /** - * Moves calendar one month into the past. - */ - previous: function() { - this.display(this.year, this.month - 1, this.date); - }, - - /** - * Primary method to display given month. - * Will remove the current display and replace - * it with the given month. - * - * @param {Numeric} year year to display. - * @param {Numeric} month month to display. - * @param {Numeric} date date to display. - */ - display: function(year, month, date) { - - // reset the date to the last date if overflow - var lastDate = new Date(year, month + 1, 0).getDate(); - if (lastDate < date) - date = lastDate; - - // Should come before render month - this._position = new Date(year, month, date); - - var element = this._renderMonth(year, month); - - if (this.monthDisplay) { - this.monthDisplay.parentNode.removeChild( - this.monthDisplay - ); - } - - this.monthDisplay = element; - this.element.appendChild(this.monthDisplay); - - this.onmonthchange(this._position); - - // Set the date as selected if presented - this._clearSelectedDay(); - if (date) { - var dayId = Calc.getDayId(this._position); - this.value = this._position; - var selector = '[data-date="' + dayId + '"]'; - var dateElement = document.querySelector(selector); - dateElement.classList.add(SELECTED); - } - }, - - /** - * Called when the month is changed. - */ - onmonthchange: function(month, year) {}, - - /** - * Called when the selected day changes. - */ - onvaluechange: function(date) {} - }; - - return DatePicker; -}()); diff --git a/apps/system/js/value_selector/input_parser.js b/apps/system/js/value_selector/input_parser.js deleted file mode 100644 index 5eef320..0000000 --- a/apps/system/js/value_selector/input_parser.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Stateless object for input parser functions.. - * The intent is the methods here will only relate to the parsing - * of input[type="date|time"] - */ - -ValueSelector.InputParser = (function() { - - var InputParser = { - _dateParts: ['year', 'month', 'date'], - _timeParts: ['hours', 'minutes', 'seconds'], - - /** - * Import HTML5 input[type="time"] string value - * - * @param {String} value 23:20:50.52, 17:39:57. - * @return {Object} { hours: 23, minutes: 20, seconds: 50 }. - */ - importTime: function(value) { - var result = { - hours: 0, - minutes: 0, - seconds: 0 - }; - - var parts = value.split(':'); - var part; - var partName; - - var i = 0; - var len = InputParser._timeParts.length; - - for (; i < len; i++) { - partName = InputParser._timeParts[i]; - part = parts[i]; - if (part) { - result[partName] = parseInt(part.slice(0, 2), 10) || 0; - } - } - - return result; - }, - - /** - * Export date to HTML5 input[type="time"] - * - * @param {Date} value export value. - * @return {String} 17:39:57. - */ - exportTime: function(value) { - var hour = value.getHours(); - var minute = value.getMinutes(); - var second = value.getSeconds(); - - var result = ''; - - result += InputParser.padNumber(hour) + ':'; - result += InputParser.padNumber(minute) + ':'; - result += InputParser.padNumber(second); - - return result; - }, - - /** - * Import HTML5 input[type="time"] to object. - * - * @param {String} value 1997-12-19. - * @return {Object} { year: 1997, month: 12, date: 19 }. - */ - importDate: function(value) { - var result = { - year: 0, - month: 0, - date: 0 - }; - - var parts = value.split('-'); - var part; - var partName; - - var i = 0; - var len = InputParser._dateParts.length; - - for (; i < len; i++) { - partName = InputParser._dateParts[i]; - part = parts[i]; - if (part) { - result[partName] = parseInt(part, 10); - } - } - - if (result.month > 0) { - result.month = result.month - 1; - } - - result.date = result.date || 1; - - return result; - }, - - /** - * Export js date to HTML5 input[type="date"] - * - * @param {Date} value export value. - * @return {String} date string (1997-12-19). - */ - exportDate: function(value) { - var year = value.getFullYear(); - var month = value.getMonth() + 1; - var date = value.getDate(); - - var result = ''; - - result += InputParser.padNumber(year) + '-'; - result += InputParser.padNumber(month) + '-'; - result += InputParser.padNumber(date); - - return result; - }, - - /** - * Designed to take a date & time value from - * html5 input types and returns a JS Date. - * - * @param {String} date input date. - * @param {String} time input time. - * - * @return {Date} full date object from date/time. - */ - formatInputDate: function(date, time) { - time = InputParser.importTime(time); - date = InputParser.importDate(date); - - return new Date( - date.year, - date.month, - date.date, - time.hours, - time.minutes, - time.seconds - ); - }, - - /** - * @param {Numeric} numeric value. - * @return {String} Pad the numeric with a leading zero if < 10. - */ - padNumber: function(numeric) { - var value = String(numeric); - if (numeric < 10) { - return '0' + value; - } - - return value; - } - }; - - return InputParser; - -}()); diff --git a/apps/system/js/value_selector/spin_date_picker.js b/apps/system/js/value_selector/spin_date_picker.js deleted file mode 100644 index feb0602..0000000 --- a/apps/system/js/value_selector/spin_date_picker.js +++ /dev/null @@ -1,341 +0,0 @@ -/** - * SpinDatePicker is a html/js "widget" which enables users - * pick a specific date. It display the date in the way based - * on the language setting. - * - * The SpinDatePicker itself contains no UI for the controls. - * - * Example usage: - * - * // All necessary UI elements are contained in the root element. - * var picker = new SpinDatePicker(root); - * picker.value = new Date(); - * // after users pick a date - * var newDate = picker.value; - */ -var SpinDatePicker = (function SpinDatePicker() { - 'use strict'; - - var FIRST_YEAR = 1900; - var LAST_YEAR = 2099; - - function getYearText() { - var yearText = []; - var dateTimeFormat = navigator.mozL10n.DateTimeFormat(); - - for (var i = FIRST_YEAR; i <= LAST_YEAR; i++) { - var date = new Date(i, 0, 1); - yearText.push(dateTimeFormat.localeFormat(date, '%Y')); - } - - return yearText; - } - - function getMonthText() { - var monthText = []; - var date = new Date(0); - var dateTimeFormat = navigator.mozL10n.DateTimeFormat(); - - for (var i = 0; i < 12; i++) { - date.setMonth(i); - monthText.push(dateTimeFormat.localeFormat(date, '%B')); - } - - return monthText; - } - - function getDateText(days) { - var dateText = []; - var date = new Date(0); - var dateTimeFormat = navigator.mozL10n.DateTimeFormat(); - - for (var i = 1; i <= days; i++) { - date.setDate(i); - dateText.push(dateTimeFormat.localeFormat(date, '%d')); - } - - return dateText; - } - - function getDaysInMonth(year, month) { - var date = new Date(year, month + 1, 0); - return date.getDate(); - } - - /** - * Get the order of date components. - * - * @param {String} date format. - */ - function getDateComponentOrder(format) { - var format = navigator.mozL10n.get('dateTimeFormat_%x'); - var order = ''; - var tokens = format.match(/(%E.|%O.|%.)/g); - - if (tokens) { - tokens.forEach(function(token) { - switch (token) { - case '%Y': - case '%y': - case '%Oy': - case 'Ey': - case 'EY': - order += 'Y'; - break; - case '%B': - case '%b': - case '%m': - case '%Om': - order += 'M'; - break; - case '%d': - case '%e': - case '%Od': - case '%Oe': - order += 'D'; - break; - } - }); - } - - if (order.length != 3) - order = 'DMY'; - - return order; - } - - /** - * Initialize a date picker widget. - * - * @param {HTMLELement} element target of widget creation. - */ - function SpinDatePicker(element) { - this.element = element; - - this.yearPicker = null; - this.monthPicker = null; - this.datePickers = { - '28': null, - '29': null, - '30': null, - '31': null - }; - - //XXX: When the document is localized again - // we must also re-render the month because - // the week days may have changed? - // This will only happen when we change timezones - // unless we add this information to the locales. - - var pickerContainer = - element.querySelector('.picker-container'); - var yearPickerContainer = - element.querySelector('.value-picker-year'); - var monthPickerContainer = - element.querySelector('.value-picker-month'); - var tmpDatePickerContainers = - element.querySelectorAll('.value-picker-date'); - var datePickerContainers = { - '28': tmpDatePickerContainers[0], - '29': tmpDatePickerContainers[1], - '30': tmpDatePickerContainers[2], - '31': tmpDatePickerContainers[3] - }; - - var updateCurrentValue = function spd_updateCurrentValue() { - var selectedYear = this.yearPicker.getSelectedIndex() + FIRST_YEAR; - var selectedMonth = this.monthPicker.getSelectedIndex(); - var days = getDaysInMonth(selectedYear, selectedMonth); - var datePicker = this.datePickers[days]; - var selectedDate = datePicker.getSelectedIndex() + 1; - - this._value = new Date(selectedYear, selectedMonth, selectedDate); - }; - - var updateDatePickerVisibility = - function spd_updateDatePickerVisibility() { - var days = getDaysInMonth(this.yearPicker.getSelectedIndex() + - FIRST_YEAR, this.monthPicker.getSelectedIndex()); - for (var i = 28; i <= 31; i++) { - datePickerContainers[i].hidden = true; - this.datePickers[i].setSelectedIndex(this._currentSelectedDateIndex); - } - datePickerContainers[days].hidden = false; - }; - - var onvaluechangeInternal = - function spd_onvaluechangeInternal(newDateValue) { - this.yearPicker.setSelectedIndex(newDateValue.getFullYear() - FIRST_YEAR); - this.monthPicker.setSelectedIndex(newDateValue.getMonth()); - for (var i = 28; i <= 31; i++) { - this.datePickers[i].setSelectedIndex(newDateValue.getDate() - 1); - } - updateDatePickerVisibility.apply(this); - updateCurrentValue.apply(this); - }; - - var onSelectedYearChanged = - function spd_onSelectedYearChanged(selectedYear) { - updateDatePickerVisibility.apply(this); - updateCurrentValue.apply(this); - }; - - var onSelectedMonthChanged = - function spd_onSelectedMonthChanged(selectedMonth) { - updateDatePickerVisibility.apply(this); - updateCurrentValue.apply(this); - }; - - var onSelectedDateChanged = - function spd_onSelectedDateChanged(selectedDate) { - this._currentSelectedDateIndex = selectedDate; - updateCurrentValue.apply(this); - }; - - var unitClassName = 'picker-unit'; - - // year value picker - var yearUnitStyle = { - valueDisplayedText: getYearText(), - className: unitClassName - }; - if (this.yearPicker) - this.yearPicker.uninit(); - this.yearPicker = new ValuePicker(yearPickerContainer, yearUnitStyle); - this.yearPicker.onselectedindexchange = onSelectedYearChanged.bind(this); - - // month value picker - var monthUnitStyle = { - valueDisplayedText: getMonthText(), - className: unitClassName - }; - if (this.monthPicker) - this.monthPicker.uninit(); - this.monthPicker = - new ValuePicker(monthPickerContainer, monthUnitStyle); - this.monthPicker.onselectedindexchange = onSelectedMonthChanged.bind(this); - - // date value picker - for (var i = 28; i <= 31; i++) { - var datePickerContainer = datePickerContainers[i]; - var dateUnitStyle = { - valueDisplayedText: getDateText(i), - className: unitClassName - }; - var datePicker = this.datePickers[i]; - - if (datePicker) - datePicker.uninit(); - datePickerContainer.hidden = false; - this.datePickers[i] = new ValuePicker(datePickerContainer, dateUnitStyle); - this.datePickers[i].onselectedindexchange = - onSelectedDateChanged.bind(this); - } - - // set component order - var dateComponentOrder = getDateComponentOrder(); - var pickerClassList = pickerContainer.classList; - pickerClassList.remove('YMD'); - pickerClassList.remove('DMY'); - pickerClassList.remove('MDY'); - pickerClassList.add(dateComponentOrder); - - // Prevent focus being taken away by us for time picker. - // The event listener on outer box will not be triggered cause - // there is a evt.stopPropagation() in value_picker.js - this.pickerElements = [monthPickerContainer, yearPickerContainer]; - for (var i = 28; i <= 31; i++) { - this.pickerElements.push(datePickerContainers[i]); - } - - this.pickerElements.forEach((function pickerElements_forEach(picker) { - picker.addEventListener('mousedown', this); - }).bind(this)); - - this.onvaluechangeInternal = onvaluechangeInternal.bind(this); - } - - SpinDatePicker.prototype = { - - /** - * Internal value not exposed so we can fire events - * when the getter/setter's are used. - * - * @type Date - */ - _value: null, - - /** - * Gets current value - * - * @return {Null|Date} date or null. - */ - get value() { - return this._value; - }, - - /** - * Sets the current value of the date picker. - * When value differs from the currently set the - * `onvaluechange` event will be fired with the new/old value. - */ - set value(value) { - var old = this._value; - if (old !== value) { - this._value = value; - this.onvaluechangeInternal(value); - } - }, - - /** - * Getter is used for date normalization. - */ - get year() { - return this._value.getFullYear(); - }, - - /** - * Getter is used for date normalization. - */ - get month() { - return this._value.getMonth(); - }, - - get date() { - return this._value.getDate(); - }, - - handleEvent: function vs_handleEvent(evt) { - switch (evt.type) { - case 'mousedown': - // Prevent focus being taken away by us. - evt.preventDefault(); - break; - } - }, - - uninit: function() { - if (this.yearPicker) - this.yearPicker.uninit(); - if (this.monthPicker) - this.monthPicker.uninit(); - if (this.datePickers) { - for (var i = 28; i <= 31; i++) { - var datePicker = this.datePickers[i]; - datePicker.uninit(); - } - } - - this.pickerElements.forEach((function pickerElements_forEach(picker) { - picker.removeEventListener('mousedown', this); - }).bind(this)); - }, - - /** - * Called when the selected date changes. - */ - onvaluechangeInternal: function(date) {} - }; - - return SpinDatePicker; -}()); diff --git a/apps/system/js/value_selector/value_picker.js b/apps/system/js/value_selector/value_picker.js deleted file mode 100644 index 34e686f..0000000 --- a/apps/system/js/value_selector/value_picker.js +++ /dev/null @@ -1,222 +0,0 @@ -var ValuePicker = (function() { - // - // Constructor - // - function VP(e, unitStyle) { - this.element = e; - this._valueDisplayedText = unitStyle.valueDisplayedText; - this._unitClassName = unitStyle.className; - this._lower = 0; - this._upper = unitStyle.valueDisplayedText.length - 1; - this._range = unitStyle.valueDisplayedText.length; - this._currentIndex = 0; - this.init(); - } - - // - // Public methods - // - VP.prototype.getSelectedIndex = function() { - var selectedIndex = this._currentIndex; - return selectedIndex; - }; - - VP.prototype.getSelectedDisplayedText = function() { - var displayedText = this._valueDisplayedText[this._currentIndex]; - return displayedText; - }; - - VP.prototype.setSelectedIndex = function(tunedIndex, ignorePicker) { - if ((tunedIndex % 1) > 0.5) { - tunedIndex = Math.floor(tunedIndex) + 1; - } else { - tunedIndex = Math.floor(tunedIndex); - } - - if (tunedIndex < this._lower) { - tunedIndex = this._lower; - } - - if (tunedIndex > this._upper) { - tunedIndex = this._upper; - } - - if (this._currentIndex != tunedIndex) { - this._currentIndex = tunedIndex; - this.onselectedindexchange(this._currentIndex); - } - this.updateUI(tunedIndex, ignorePicker); - - return tunedIndex; - }; - - VP.prototype.setSelectedIndexByDisplayedText = function(displayedText) { - var newIndex = this._valueDisplayedText.indexOf(displayedText); - if (newIndex != -1) { - if (this._currentIndex != newIndex) { - this._currentIndex = newIndex; - this.onselectedindexchange(this._currentIndex); - } - this.updateUI(newIndex); - } - }; - - // - // Internal methods - // - VP.prototype.init = function() { - this.initUI(); - this.setSelectedIndex(0); // Default Index is zero - this.mousedonwHandler = vp_mousedown.bind(this); - this.mousemoveHandler = vp_mousemove.bind(this); - this.mouseupHandler = vp_mouseup.bind(this); - this.addEventListeners(); - }; - - VP.prototype.initUI = function() { - var lower = this._lower; - var upper = this._upper; - var unitCount = this._valueDisplayedText.length; - for (var i = 0; i < unitCount; ++i) { - this.addPickerUnit(i); - } - // cache the size of picker - this._pickerUnits = this.element.children; - this._pickerUnitsHeight = this._pickerUnits[0].clientHeight; - this._pickerHeight = this._pickerUnits[0].clientHeight * - this._pickerUnits.length; - this._space = this._pickerHeight / this._range; - }; - - VP.prototype.addPickerUnit = function(index) { - var html = this._valueDisplayedText[index]; - var unit = document.createElement('div'); - unit.className = this._unitClassName; - unit.innerHTML = html; - this.element.appendChild(unit); - }; - - VP.prototype.updateUI = function(index, ignorePicker) { - if (true !== ignorePicker) { - this.element.style.top = - (this._lower - index) * this._space + 'px'; - } - }; - - VP.prototype.addEventListeners = function() { - this.element.addEventListener('mousedown', this.mousedonwHandler, false); - }; - - VP.prototype.removeEventListeners = function() { - this.element.removeEventListener('mouseup', this.mouseupHandler, false); - this.element.removeEventListener('mousemove', this.mousemoveHandler, false); - }; - - VP.prototype.uninit = function() { - this.element.removeEventListener('mousedown', this.mousedonwHandler, false); - this.element.removeEventListener('mouseup', this.mouseupHandler, false); - this.element.removeEventListener('mousemove', this.mousemoveHandler, false); - this.element.style.top = '0px'; - this.onselectedindexchange = null; - empty(this.element); - }; - - VP.prototype.onselectedindexchange = function(index) {}; - - function cloneEvent(evt) { - if ('touches' in evt) { - evt = evt.touches[0]; - } - return { x: evt.pageX, y: evt.pageY, timestamp: evt.timeStamp }; - } - - function empty(element) { - while (element.hasChildNodes()) - element.removeChild(element.lastChild); - element.innerHTML = ''; - } - - // - // Tuneable parameters - // - var SPEED_THRESHOLD = 0.1; - var currentEvent, startEvent, currentSpeed; - var tunedIndex = 0; - - function toFixed(value) { - return parseFloat(value.toFixed(1)); - } - - function calcSpeed() { - var movingSpace = startEvent.y - currentEvent.y; - var deltaTime = currentEvent.timestamp - startEvent.timestamp; - var speed = movingSpace / deltaTime; - currentSpeed = parseFloat(speed.toFixed(2)); - } - - function calcTargetIndex(space) { - return tunedIndex - getMovingSpace() / space; - } - - // If the user swap really slow, narrow down the moving space - // So the user can fine tune value. - function getMovingSpace() { - var movingSpace = currentEvent.y - startEvent.y; - var reValue = Math.abs(currentSpeed) > SPEED_THRESHOLD ? - movingSpace : movingSpace / 4; - return reValue; - } - - function vp_mousemove(event) { - event.stopPropagation(); - event.target.setCapture(true); - currentEvent = cloneEvent(event); - - calcSpeed(); - - // move selected index - this.element.style.top = parseFloat(this.element.style.top) + - getMovingSpace() + 'px'; - - tunedIndex = calcTargetIndex(this._space); - var roundedIndex = Math.round(tunedIndex * 10) / 10; - - if (roundedIndex != this._currentIndex) { - this.setSelectedIndex(toFixed(roundedIndex), true); - } - - startEvent = currentEvent; - } - - function vp_mouseup(event) { - event.stopPropagation(); - this.removeEventListeners(); - - // Add animation back - this.element.classList.add('animation-on'); - - // Add momentum if speed is higher than a given threshold. - if (Math.abs(currentSpeed) > SPEED_THRESHOLD) { - var direction = currentSpeed > 0 ? 1 : -1; - tunedIndex += Math.min(Math.abs(currentSpeed) * 5, 5) * direction; - } - tunedIndex = this.setSelectedIndex(toFixed(tunedIndex)); - currentSpeed = 0; - } - - function vp_mousedown(event) { - event.stopPropagation(); - - // Stop animation - this.element.classList.remove('animation-on'); - - startEvent = currentEvent = cloneEvent(event); - tunedIndex = this._currentIndex; - - this.removeEventListeners(); - this.element.addEventListener('mousemove', this.mousemoveHandler, false); - this.element.addEventListener('mouseup', this.mouseupHandler, false); - } - - return VP; -}()); diff --git a/apps/system/js/value_selector/value_selector.js b/apps/system/js/value_selector/value_selector.js deleted file mode 100644 index b3381b3..0000000 --- a/apps/system/js/value_selector/value_selector.js +++ /dev/null @@ -1,526 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var ValueSelector = { - - _containers: {}, - _popups: {}, - _buttons: {}, - _datePicker: null, - - debug: function(msg) { - var debugFlag = false; - if (debugFlag) { - console.log('[ValueSelector] ', msg); - } - }, - - init: function vs_init() { - - var self = this; - - window.navigator.mozKeyboard.onfocuschange = function onfocuschange(evt) { - var typeToHandle = ['select-one', 'select-multiple', 'date', - 'time', 'datetime', 'datetime-local', 'blur']; - - var type = evt.detail.type; - // handle the <select> element and inputs with type of date/time - // in system app for now - if (typeToHandle.indexOf(type) == -1) - return; - - var currentValue = evt.detail.value; - - switch (evt.detail.type) { - case 'select-one': - case 'select-multiple': - self.debug('select triggered' + JSON.stringify(evt.detail)); - self._currentPickerType = evt.detail.type; - self.showOptions(evt.detail); - break; - - case 'date': - self.showDatePicker(currentValue); - break; - - case 'time': - self.showTimePicker(currentValue); - break; - - case 'datetime': - case 'datetime-local': - // TODO - break; - case 'blur': - self.hide(); - break; - } - }; - - this._element = document.getElementById('value-selector'); - this._element.addEventListener('mousedown', this); - this._containers['select'] = - document.getElementById('value-selector-container'); - this._containers['select'].addEventListener('click', this); - ActiveEffectHelper.enableActive(this._containers['select']); - - this._popups['select'] = - document.getElementById('select-option-popup'); - this._popups['select'].addEventListener('submit', this); - this._popups['time'] = - document.getElementById('time-picker-popup'); - this._popups['date'] = - document.getElementById('spin-date-picker-popup'); - - this._buttons['select'] = document.getElementById('select-options-buttons'); - this._buttons['select'].addEventListener('click', this); - - this._buttons['time'] = document.getElementById('time-picker-buttons'); - this._buttons['time'].addEventListener('click', this); - this._buttons['date'] = document.getElementById('spin-date-picker-buttons'); - - this._buttons['date'].addEventListener('click', this); - - this._containers['time'] = document.getElementById('picker-bar'); - this._containers['date'] = document.getElementById('spin-date-picker'); - - ActiveEffectHelper.enableActive(this._buttons['select']); - ActiveEffectHelper.enableActive(this._buttons['time']); - ActiveEffectHelper.enableActive(this._buttons['date']); - - // Prevent focus being taken away by us for time picker. - // The event listener on outer box will not be triggered cause - // there is a evt.stopPropagation() in value_picker.js - var pickerElements = ['value-picker-hours', 'value-picker-minutes', - 'value-picker-hour24-state']; - - pickerElements.forEach((function pickerElements_forEach(id) { - var element = document.getElementById(id); - element.addEventListener('mousedown', this); - }).bind(this)); - - window.addEventListener('appopen', this); - window.addEventListener('appwillclose', this); - - // invalidate the current spin date picker when language setting changes - navigator.mozSettings.addObserver('language.current', - (function language_change(e) { - if (this._datePicker) { - this._datePicker.uninit(); - this._datePicker = null; - }}).bind(this)); - }, - - handleEvent: function vs_handleEvent(evt) { - switch (evt.type) { - case 'appopen': - case 'appwillclose': - this.hide(); - break; - - case 'click': - var currentTarget = evt.currentTarget; - switch (currentTarget) { - case this._buttons['select']: - case this._buttons['time']: - case this._buttons['date']: - var target = evt.target; - if (target.dataset.type == 'cancel') { - this.cancel(); - } else if (target.dataset.type == 'ok') { - this.confirm(); - } - break; - - case this._containers['select']: - this.handleSelect(evt.target); - break; - } - break; - - case 'submit': - // Prevent the form from submit. - case 'mousedown': - // Prevent focus being taken away by us. - evt.preventDefault(); - break; - - default: - this.debug('no event handler defined for' + evt.type); - break; - } - }, - - handleSelect: function vs_handleSelect(target) { - - if (target.dataset === undefined || - (target.dataset.optionIndex === undefined && - target.dataset.optionValue === undefined)) - return; - - if (this._currentPickerType === 'select-one') { - var selectee = this._containers['select']. - querySelectorAll('[aria-checked="true"]'); - for (var i = 0; i < selectee.length; i++) { - selectee[i].removeAttribute('aria-checked'); - } - - target.setAttribute('aria-checked', 'true'); - } else if (target.getAttribute('aria-checked') === 'true') { - target.removeAttribute('aria-checked'); - } else { - target.setAttribute('aria-checked', 'true'); - } - - // setValue here to trigger change event - var singleOptionIndex; - var optionIndices = []; - - var selectee = this._containers['select']. - querySelectorAll('[aria-checked="true"]'); - - if (this._currentPickerType === 'select-one') { - - if (selectee.length > 0) - singleOptionIndex = selectee[0].dataset.optionIndex; - - window.navigator.mozKeyboard.setSelectedOption(singleOptionIndex); - - } else if (this._currentPickerType === 'select-multiple') { - // Multiple select case - for (var i = 0; i < selectee.length; i++) { - - var index = parseInt(selectee[i].dataset.optionIndex); - optionIndices.push(index); - } - - window.navigator.mozKeyboard.setSelectedOptions(optionIndices); - } - - }, - - show: function vs_show(detail) { - this._element.hidden = false; - }, - - showPanel: function vs_showPanel(type) { - for (var p in this._containers) { - if (p === type) { - this._popups[p].hidden = false; - } else { - this._popups[p].hidden = true; - } - } - }, - - hide: function vs_hide() { - this._element.hidden = true; - }, - - cancel: function vs_cancel() { - this.debug('cancel invoked'); - window.navigator.mozKeyboard.removeFocus(); - this.hide(); - }, - - confirm: function vs_confirm() { - - if (this._currentPickerType === 'time') { - - var timeValue = TimePicker.getTimeValue(); - this.debug('output value: ' + timeValue); - - window.navigator.mozKeyboard.setValue(timeValue); - } else if (this._currentPickerType === 'date') { - var dateValue = this._datePicker.value; - // The format should be 2012-09-19 - dateValue = dateValue.toLocaleFormat('%Y-%m-%d'); - this.debug('output value: ' + dateValue); - window.navigator.mozKeyboard.setValue(dateValue); - } - - window.navigator.mozKeyboard.removeFocus(); - this.hide(); - }, - - showOptions: function vs_showOptions(detail) { - - var options = null; - if (detail.choices && detail.choices.choices) - options = detail.choices.choices; - - if (options) - this.buildOptions(options); - - this.show(); - this.showPanel('select'); - }, - - buildOptions: function(options) { - - var optionHTML = ''; - - function escapeHTML(str) { - var span = document.createElement('span'); - span.textContent = str; - return span.innerHTML; - } - - for (var i = 0, n = options.length; i < n; i++) { - - var checked = options[i].selected ? ' aria-checked="true"' : ''; - - // This for attribute is created only to avoid applying - // a general rule in building block - var forAttribute = ' for="gaia-option-' + options[i].optionIndex + '"'; - - optionHTML += '<li data-option-index="' + options[i].optionIndex + '"' + - checked + '>' + - '<label' + forAttribute + '> <span>' + - escapeHTML(options[i].text) + - '</span></label>' + - '</li>'; - } - - var optionsContainer = document.querySelector( - '#value-selector-container ol'); - if (!optionsContainer) - return; - - optionsContainer.innerHTML = optionHTML; - - - // Apply different style when the options are more than 1 page - if (options.length > 5) { - this._containers['select'].classList.add('scrollable'); - } else { - this._containers['select'].classList.remove('scrollable'); - } - - // Change the title for multiple select - var titleL10nId = 'choose-options'; - if (this._currentPickerType === 'select-one') - titleL10nId = 'choose-option'; - - var optionsTitle = document.querySelector( - '#value-selector-container h1'); - - if (optionsTitle) { - optionsTitle.dataset.l10nId = titleL10nId; - optionsTitle.textContent = navigator.mozL10n.get(titleL10nId); - } - }, - - showTimePicker: function vs_showTimePicker(currentValue) { - this._currentPickerType = 'time'; - this.show(); - this.showPanel('time'); - - if (!this._timePickerInitialized) { - TimePicker.initTimePicker(); - this._timePickerInitialized = true; - } - - var time; - if (!currentValue) { - var now = new Date(); - time = { - hours: now.getHours(), - minutes: now.getMinutes() - }; - } else { - var inputParser = ValueSelector.InputParser; - if (!inputParser) - console.error('Cannot get input parser for value selector'); - - time = inputParser.importTime(currentValue); - } - - var timePicker = TimePicker.timePicker; - // Set the value of time picker according to the current value - if (timePicker.is12hFormat) { - var hour = (time.hours % 12); - hour = (hour == 0) ? 12 : hour; - // 24-hour state value selector: AM = 0, PM = 1 - var hour24State = (time.hours >= 12) ? 1 : 0; - timePicker.hour.setSelectedIndexByDisplayedText(hour); - timePicker.hour24State.setSelectedIndex(hour24State); - } else { - timePicker.hour.setSelectedIndex(time.hours); - } - - timePicker.minute.setSelectedIndex(time.minutes); - }, - - showDatePicker: function vs_showDatePicker(currentValue) { - this._currentPickerType = 'date'; - this.show(); - this.showPanel('date'); - - if (!this._datePicker) { - this._datePicker = new SpinDatePicker(this._containers['date']); - } - - // Show current date as default value - var date = new Date(); - if (currentValue) { - var inputParser = ValueSelector.InputParser; - if (!inputParser) - console.error('Cannot get input parser for value selector'); - - date = inputParser.formatInputDate(currentValue, ''); - } - this._datePicker.value = date; - } - -}; - -var TimePicker = { - timePicker: { - hour: null, - minute: null, - hour24State: null, - is12hFormat: false - }, - - get hourSelector() { - delete this.hourSelector; - return this.hourSelector = - document.getElementById('value-picker-hours'); - }, - - get minuteSelector() { - delete this.minuteSelector; - return this.minuteSelector = - document.getElementById('value-picker-minutes'); - }, - - get hour24StateSelector() { - delete this.hour24StateSelector; - return this.hour24StateSelector = - document.getElementById('value-picker-hour24-state'); - }, - - initTimePicker: function tp_initTimePicker() { - var localeTimeFormat = navigator.mozL10n.get('dateTimeFormat_%X'); - var is12hFormat = (localeTimeFormat.indexOf('%p') >= 0); - this.timePicker.is12hFormat = is12hFormat; - this.setTimePickerStyle(); - var startHour = is12hFormat ? 1 : 0; - var endHour = is12hFormat ? (startHour + 12) : (startHour + 12 * 2); - var unitClassName = 'picker-unit'; - var hourDisplayedText = []; - for (var i = startHour; i < endHour; i++) { - var value = i; - hourDisplayedText.push(value); - } - var hourUnitStyle = { - valueDisplayedText: hourDisplayedText, - className: unitClassName - }; - this.timePicker.hour = new ValuePicker(this.hourSelector, hourUnitStyle); - - var minuteDisplayedText = []; - for (var i = 0; i < 60; i++) { - var value = (i < 10) ? '0' + i : i; - minuteDisplayedText.push(value); - } - var minuteUnitStyle = { - valueDisplayedText: minuteDisplayedText, - className: unitClassName - }; - this.timePicker.minute = - new ValuePicker(this.minuteSelector, minuteUnitStyle); - - if (is12hFormat) { - var hour24StateUnitStyle = { - valueDisplayedText: ['AM', 'PM'], - className: unitClassName - }; - this.timePicker.hour24State = - new ValuePicker(this.hour24StateSelector, hour24StateUnitStyle); - } - }, - - setTimePickerStyle: function tp_setTimePickerStyle() { - var style = (this.timePicker.is12hFormat) ? 'format12h' : 'format24h'; - document.getElementById('picker-bar').classList.add(style); - }, - - // return a string for the time value, format: "16:37" - getTimeValue: function tp_getTimeValue() { - var hour = 0; - if (this.timePicker.is12hFormat) { - var hour24Offset = 12 * this.timePicker.hour24State.getSelectedIndex(); - hour = this.timePicker.hour.getSelectedDisplayedText(); - hour = (hour == 12) ? 0 : hour; - hour = hour + hour24Offset; - } else { - hour = this.timePicker.hour.getSelectedIndex(); - } - var minute = this.timePicker.minute.getSelectedDisplayedText(); - - return hour + ':' + minute; - } -}; - -var ActiveEffectHelper = (function() { - - var lastActiveElement = null; - - function _setActive(element, isActive) { - if (isActive) { - element.classList.add('active'); - lastActiveElement = element; - } else { - element.classList.remove('active'); - if (lastActiveElement) { - lastActiveElement.classList.remove('active'); - lastActiveElement = null; - } - } - } - - function _onMouseDown(evt) { - var target = evt.target; - - _setActive(target, true); - target.addEventListener('mouseleave', _onMouseLeave); - } - - function _onMouseUp(evt) { - var target = evt.target; - - _setActive(target, false); - target.removeEventListener('mouseleave', _onMouseLeave); - } - - function _onMouseLeave(evt) { - var target = evt.target; - _setActive(target, false); - target.removeEventListener('mouseleave', _onMouseLeave); - } - - var _events = { - 'mousedown': _onMouseDown, - 'mouseup': _onMouseUp - }; - - function _enableActive(element) { - // Attach event listeners - for (var event in _events) { - var callback = _events[event] || null; - if (callback) - element.addEventListener(event, callback); - } - } - - return { - enableActive: _enableActive - }; - -})(); - -ValueSelector.init(); diff --git a/apps/system/js/voicemail.js b/apps/system/js/voicemail.js deleted file mode 100644 index dea5116..0000000 --- a/apps/system/js/voicemail.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -// Custom voicemail notification -- This can be removed once DesktopNotification -// supports removing notifications via API -var Voicemail = { - - icon: null, - notification: null, - // A random starting point that is unlikely to be used by other notifications - notificationId: 3000 + Math.floor(Math.random() * 999), - - init: function vm_init() { - var voicemail = window.navigator.mozVoicemail; - if (!voicemail) - return; - - voicemail.addEventListener('statuschanged', this); - - this.icon = window.location.protocol + '//' + - window.location.hostname + '/style/icons/voicemail.png'; - }, - - handleEvent: function vm_handleEvent(evt) { - var voicemail = window.navigator.mozVoicemail; - if (!voicemail.status) - return; - - this.updateNotification(voicemail.status); - }, - - updateNotification: function vm_updateNotification(status) { - var _ = window.navigator.mozL10n.get; - var title = status.returnMessage; - var showCount = status.hasMessages && status.messageCount > 0; - - if (!title) { - title = showCount ? _('newVoicemails', { n: status.messageCount }) : - _('newVoicemailsUnknown'); - } - - var text = title; - var voicemailNumber = navigator.mozVoicemail.number; - if (voicemailNumber) { - text = _('dialNumber', { number: voicemailNumber }); - } - - this.hideNotification(); - if (status.hasMessages) { - this.showNotification(title, text, voicemailNumber); - } - }, - - showNotification: function vm_showNotification(title, text, voicemailNumber) { - this.notificationId++; - this.notification = NotificationScreen.addNotification({ - id: this.notificationId, title: title, text: text, icon: this.icon - }); - - if (!voicemailNumber) { - return; - } - - var self = this; - function vmNotification_onTap(event) { - self.notification.removeEventListener('tap', vmNotification_onTap); - - var telephony = window.navigator.mozTelephony; - if (!telephony) { - return; - } - - telephony.dial(voicemailNumber); - } - - this.notification.addEventListener('tap', vmNotification_onTap); - }, - - hideNotification: function vm_hideNotification() { - if (!this.notification) { - return; - } - - if (this.notification.parentNode) { - NotificationScreen.removeNotification(this.notificationId); - } - - this.notification = null; - this.notificationId = 0; - } -}; - -Voicemail.init(); diff --git a/apps/system/js/wifi.js b/apps/system/js/wifi.js deleted file mode 100644 index 3456fdf..0000000 --- a/apps/system/js/wifi.js +++ /dev/null @@ -1,223 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var Wifi = { - wifiWakeLocked: false, - - wifiEnabled: true, - - wifiDisabledByWakelock: false, - - // Without wake lock, wait for kOffTime milliseconds and turn wifi off - // after the conditions are met. - kOffTime: 60 * 1000, - - // if Wifi is enabled but disconnected, try to scan for networks every - // kScanInterval ms. - kScanInterval: 20 * 1000, - - _scanTimer: null, - - init: function wf_init() { - window.addEventListener('screenchange', this); - - var battery = window.navigator.battery; - battery.addEventListener('chargingchange', this); - - if (!window.navigator.mozSettings) - return; - - // If wifi is turned off by us and phone got rebooted, - // bring wifi back. - var name = 'wifi.disabled_by_wakelock'; - var req = SettingsListener.getSettingsLock().get(name); - req.onsuccess = function gotWifiDisabledByWakelock() { - if (!req.result[name]) - return; - - // Re-enable wifi and reset wifi.disabled_by_wakelock - // SettingsListener.getSettingsLock() always return invalid lock - // in our usage here. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=793239 - var lock = navigator.mozSettings.createLock(); - lock.set({ 'wifi.enabled': true }); - lock.set({ 'wifi.disabled_by_wakelock': false }); - }; - - var self = this; - var wifiManager = window.navigator.mozWifiManager; - // when wifi is really enabled, emit event to notify QuickSettings - wifiManager.onenabled = function onWifiEnabled() { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('wifi-enabled', - /* canBubble */ true, /* cancelable */ false, null); - window.dispatchEvent(evt); - }; - - // when wifi is really disabled, emit event to notify QuickSettings - wifiManager.ondisabled = function onWifiDisabled() { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('wifi-disabled', - /* canBubble */ true, /* cancelable */ false, null); - window.dispatchEvent(evt); - }; - - // when wifi status change, emit event to notify StatusBar/UpdateManager - wifiManager.onstatuschange = function onWifiDisabled() { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('wifi-statuschange', - /* canBubble */ true, /* cancelable */ false, null); - window.dispatchEvent(evt); - }; - - // Track the wifi.enabled mozSettings value - SettingsListener.observe('wifi.enabled', true, function(value) { - if (!wifiManager && value) { - self.wifiEnabled = false; - - // roll back the setting value to notify the UIs - // that wifi interface is not available - if (value) { - SettingsListener.getSettingsLock().set({ - 'wifi.enabled': false - }); - } - - return; - } - - self.wifiEnabled = value; - - clearTimeout(self._scanTimer); - if (!value) - return; - - // If wifi is enabled but disconnected. - // we would need to call getNetworks() continuously - // so we could join known wifi network - self._scanTimer = setInterval(function wifi_scan() { - if (wifiManager.connection.status == 'disconnected') - wifiManager.getNetworks(); - }); - }); - - var power = navigator.mozPower; - power.addWakeLockListener(function wifi_handleWakeLock(topic, state) { - if (topic !== 'wifi') - return; - - self.wifiWakeLocked = (state == 'locked-foreground' || - state == 'locked-background'); - - self.maybeToggleWifi(); - }); - }, - - handleEvent: function wifi_handleEvent(evt) { - this.maybeToggleWifi(); - }, - - // Check the status of screen, wifi wake lock and power source - // and turn on/off wifi accordingly - maybeToggleWifi: function wifi_maybeToggleWifi() { - var battery = window.navigator.battery; - var wifiManager = window.navigator.mozWifiManager; - if (!battery || !wifiManager || - (!this.wifiEnabled && !this.wifiDisabledByWakelock)) - return; - - - // Let's quietly turn off wifi if there is no wake lock and - // the screen is off and we are not on a power source. - if (!ScreenManager.screenEnabled && - !this.wifiWakeLocked && !battery.charging) { - // We don't need to do anything if wifi is not enabled currently - if (!this.wifiEnabled) - return; - - // We still need to turn of wifi even if there is no Alarm API - if (!navigator.mozAlarms) { - console.warn('Turning off wifi without sleep timer because' + - ' Alarm API is not available'); - this.sleep(); - - return; - } - - // Set System Message Handler, so we will be notified when alarm goes off. - this.setSystemMessageHandler(); - - // Start with a timer, only turn off wifi till timeout. - var date = new Date(Date.now() + this.kOffTime); - var self = this; - var req = navigator.mozAlarms.add(date, 'ignoreTimezone', 'wifi-off'); - req.onsuccess = function wifi_offAlarmSet() { - self._alarmId = req.result; - }; - req.onerror = function wifi_offAlarmSetFailed() { - console.warn('Fail to set wifi sleep timer on Alarm API. ' + - 'Turn off wifi immediately.'); - self.sleep(); - }; - } - // ... and quietly turn it back on or cancel the timer otherwise - else { - if (this._alarmId) { - navigator.mozAlarms.remove(this._alarmId); - this._alarmId = null; - } - - // If wifi is enabled but disconnected. - // we would need to call getNetworks() so we could join known wifi network - if (this.wifiEnabled && wifiManager.connection.status == 'disconnected') { - wifiManager.getNetworks(); - } - - // We don't need to do anything if we didn't disable wifi at first place. - if (!this.wifiDisabledByWakelock) - return; - - var lock = SettingsListener.getSettingsLock(); - // turn wifi back on. - lock.set({ 'wifi.enabled': true }); - - this.wifiDisabledByWakelock = false; - lock.set({ 'wifi.disabled_by_wakelock': false }); - } - }, - - // Quietly turn off wifi for real, set wifiDisabledByWakelock to true - // so we will turn it back on. - sleep: function wifi_sleep() { - var lock = SettingsListener.getSettingsLock(); - // Actually turn off the wifi - lock.set({ 'wifi.enabled': false }); - - // Remember that it was turned off by us. - this.wifiDisabledByWakelock = true; - - // Keep this value in disk so if the phone reboots we'll - // be able to turn the wifi back on. - lock.set({ 'wifi.disabled_by_wakelock': true }); - }, - - // Register for handling system message, - // this cannot be done during |init()| because of bug 797803 - setSystemMessageHandler: function wifi_setSystemMessageHandler() { - if (this._systemMessageHandlerRegistered) - return; - - this._systemMessageHandlerRegistered = true; - var self = this; - navigator.mozSetMessageHandler('alarm', function gotAlarm(message) { - if (message.data !== 'wifi-off') - return; - - self.sleep(); - }); - } -}; - -Wifi.init(); diff --git a/apps/system/js/window.js b/apps/system/js/window.js deleted file mode 100644 index a9109dd..0000000 --- a/apps/system/js/window.js +++ /dev/null @@ -1,152 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -(function(window){ - - var _ = navigator.mozL10n.get; - - var ENABLE_LOG = false; - - // Use mutation observer to monitor appWindow status change - window.AppLog = function AppLog(app) { - // select the target node - var target = app.frame; - - // create an observer instance - var observer = new MutationObserver(function(mutations) { - mutations.forEach(function(mutation) { - console.log(mutation.target.id, - mutation.target.className, - mutation.attributeName); - }); - }); - - // configuration of the observer: - var config = { attributes: true }; - - // pass in the target node, as well as the observer options - observer.observe(target, config); - } - - window.AppError = function AppError(app) { - var self = this; - this.app = app; - this.app.frame.addEventListener('mozbrowsererror', function (evt) { - if (evt.detail.type != 'other') - return; - - console.warn('app of [' + self.app.origin + '] got a mozbrowsererror event.'); - - if (self.injected) { - self.update(); - } else { - self.render(); - } - self.show(); - self.injected = true; - }); - return this; - }; - - AppError.className = 'appError'; - - AppError.prototype.hide = function() { - this.element.classList.remove('visible'); - } - - AppError.prototype.show = function() { - this.element.classList.add('visible'); - } - - AppError.prototype.render = function() { - this.app.frame.insertAdjacentHTML('beforeend', this.view()); - this.closeButton = this.app.frame.querySelector('.' + AppError.className + ' .close'); - this.reloadButton = this.app.frame.querySelector('.' + AppError.className + ' .reload'); - this.titleElement = this.app.frame.querySelector('.' + AppError.className + ' .title'); - this.messageElement = this.app.frame.querySelector('.' + AppError.className + ' .message'); - this.element = this.app.frame.querySelector('.' + AppError.className); - var self = this; - this.closeButton.onclick = function() { - self.app.kill(); - } - - this.reloadButton.onclick = function() { - self.hide(); - self.app.reload(); - } - } - - AppError.prototype.update = function() { - this.titleElement.textContent = this.getTitle(); - this.messageElement.textContent = this.getMessage(); - } - - AppError.prototype.id = function() { - return AppError.className + '-' + this.app.frame.id; - } - - AppError.prototype.getTitle = function() { - if (AirplaneMode.enabled) { - return _('airplane-is-on'); - } else if (!navigator.onLine) { - return _('network-connection-unavailable'); - } else { - return _('error-title', { name: this.app.name }); - } - } - - AppError.prototype.getMessage = function() { - if (AirplaneMode.enabled) { - return _('airplane-is-turned-on', { name: this.app.name }); - } else if (!navigator.onLine) { - return _('network-error', { name: this.app.name }); - } else { - return _('error-message', { name: this.app.name }); - } - } - - AppError.prototype.view = function() { - return '<div id="' + this.id() + '" class="' + AppError.className + ' visible" role="dialog">' + - '<div class="modal-dialog-message-container inner">' + - '<h3 data-l10n-id="error-title" class="title">' + this.getTitle() + '</h3>' + - '<p>' + - '<span data-l10n-id="error-message" class="message">' + this.getMessage() + '</span>' + - '</p>' + - '</div>' + - '<menu data-items="2">' + - '<button class="close" data-l10n-id="try-again">' + _('close') + '</button>' + - '<button class="reload" data-l10n-id="try-again">' + _('try-again') + '</button>' + - '</menu>' + - '</div>'; - } - - window.AppWindow = function AppWindow(configuration) { - for (var key in configuration) { - this[key] = configuration[key]; - } - - // We keep the appError object here for the purpose that - // we may need to export the error state of AppWindow instance to the other module - // in the future. - this.appError = new AppError(this); - if (ENABLE_LOG) - this.appLog = new AppLog(this); - - return this; - }; - - AppWindow.prototype.reload = function() { - this.iframe.reload(true); - } - - AppWindow.prototype.kill = function() { - // XXX: A workaround because a AppWindow instance shouldn't reference Window Manager directly here. - // In the future we should make every app maintain and execute the events in itself. - // Like resize, setVisibility... - // And Window Manager is in charge of cross app management. - WindowManager.kill(this.origin); - } - -}(this)); diff --git a/apps/system/js/window_manager.js b/apps/system/js/window_manager.js deleted file mode 100644 index e53605e..0000000 --- a/apps/system/js/window_manager.js +++ /dev/null @@ -1,2011 +0,0 @@ -/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -// -// This file calls getElementById without waiting for an onload event, so it -// must have a defer attribute or be included at the end of the <body>. -// -// This module is responsible for launching apps and for allowing -// the user to switch among apps and kill apps. Specifically, it handles: -// launching apps, -// killing apps -// keeping track of the set of running apps (which we call tasks here) -// keeping track of which task is displayed (the foreground task) -// changing the foreground task -// hiding all apps to display the homescreen -// displaying the app switcher to allow the user to switch and kill apps -// performing appropriate transition animations between: -// the homescreen and an app -// the homescreen and the switcher -// an app and the homescreen -// the switcher and the homescreen -// the switcher and the current foreground task -// the switcher and a different task -// Handling Home key events to switch to the homescreen and the switcher -// -// The public API of the module is small. It defines an WindowManager object -// with these methods: -// -// launch(origin): switch to the specified running app -// kill(origin, callback): stop specified app -// reload(origin): reload the given app -// getDisplayedApp(): return the origin of the currently displayed app -// setOrientationForApp(origin): set the phone to orientation to a given app -// getAppFrame(origin): returns the iframe element for the specified origin -// which is assumed to be running. This is only currently used -// for tests and chrome stuff: see the end of the file -// getRunningApps(): get the app references of the running apps. -// -// TODO -// The "origin" does not actually refer to app's origin but rather a identifier -// of the app reference that one gets from |getDisplayedApp()| or -// iterates |getRunningApps|. The string is make up of the specified -// launching entry point, origin, or the website url launched by wrapper. -// It would be ideal if the variable get correctly named and it's rule is being -// properly documented. -// See https://bugzilla.mozilla.org/show_bug.cgi?id=796629 -// - -var WindowManager = (function() { - 'use strict'; - - function debug(str) { - dump('WindowManager: ' + str + '\n'); - } - - // Holds the origin of the home screen, which should be the first - // app we launch through web activity during boot - var homescreen = null; - var homescreenURL = ''; - var homescreenManifestURL = ''; - var ftu = null; - var ftuManifestURL = ''; - var ftuURL = ''; - var isRunningFirstRunApp = false; - // keep the reference of inline activity frame here - var inlineActivityFrames = []; - var activityCallerOrigin = ''; - - // Some document elements we use - var windows = document.getElementById('windows'); - var screenElement = document.getElementById('screen'); - var wrapperHeader = document.querySelector('#wrapper-activity-indicator'); - var wrapperFooter = document.querySelector('#wrapper-footer'); - var kTransitionTimeout = 1000; - - // Set this to true to debugging the transitions and state change - var slowTransition = false; - if (slowTransition) { - windows.classList.add('slow-transition'); - } - - // - // The set of running apps. - // This is a map from app origin to an object like this: - // { - // name: the app's name - // manifest: the app's manifest object - // frame: the iframe element that the app is displayed in - // launchTime: last time when app gets active - // } - // - var runningApps = {}; - var numRunningApps = 0; // appendFrame() and removeFrame() maintain this count - var nextAppId = 0; // to give each app's iframe a unique id attribute - - // The origin of the currently displayed app, or null if there isn't one - var displayedApp = null; - - // Function to hide init starting logo - function handleInitlogo(callback) { - var initlogo = document.getElementById('initlogo'); - initlogo.classList.add('hide'); - initlogo.addEventListener('transitionend', function delInitlogo() { - initlogo.removeEventListener('transitionend', delInitlogo); - initlogo.parentNode.removeChild(initlogo); - if (callback) { - callback(); - } - }); - }; - - // Public function. Return the origin of the currently displayed app - // or null if there is none. - function getDisplayedApp() { - return displayedApp || null; - } - - function requireFullscreen(origin) { - var app = runningApps[origin]; - if (!app) - return false; - - var manifest = app.manifest; - if (manifest.entry_points && manifest.type == 'certified') { - var entryPoint = manifest.entry_points[origin.split('/')[3]]; - if (entryPoint) - return entryPoint.fullscreen; - return false; - } else { - return manifest.fullscreen; - } - } - - // Make the specified app the displayed app. - // Public function. Pass null to make the homescreen visible - function launch(origin) { - // If the origin is indeed valid we make that app as the displayed app. - if (isRunning(origin)) { - setDisplayedApp(origin); - return; - } - - // If the origin is null, make the homescreen visible. - if (origin == null) { - setDisplayedApp(homescreen); - return; - } - - // At this point, we have no choice but to show the homescreen. - // We cannot launch/relaunch a given app based on the "origin" because - // we would need the manifest URL and the specific entry point. - console.warn('No running app is being identified as "' + origin + '". ' + - 'Showing home screen instead.'); - setDisplayedApp(homescreen); - } - - function isRunning(origin) { - return runningApps.hasOwnProperty(origin); - } - - function getAppFrame(origin) { - if (isRunning(origin)) - return runningApps[origin].frame; - else - return null; - } - - // Set the size of the app's iframe to match the size of the screen. - // We have to call this on resize events (which happen when the - // phone orientation is changed). And also when an app is launched - // and each time an app is brought to the front, since the - // orientation could have changed since it was last displayed - function setAppSize(origin, changeActivityFrame) { - var app = runningApps[origin]; - if (!app) - return; - - var frame = app.frame; - var manifest = app.manifest; - - var cssWidth = window.innerWidth + 'px'; - var cssHeight = window.innerHeight - StatusBar.height; - if ('wrapper' in frame.dataset) { - cssHeight -= 10; - } - cssHeight += 'px'; - - if (!screenElement.classList.contains('attention') && - requireFullscreen(origin)) { - cssHeight = window.innerHeight + 'px'; - } - - frame.style.width = cssWidth; - frame.style.height = cssHeight; - - // We will call setInlineActivityFrameSize() - // if changeActivityFrame is not explicitly set to false. - if (changeActivityFrame !== false) - setInlineActivityFrameSize(); - } - - // App's height is relevant to keyboard height - function setAppHeight(keyboardHeight) { - var app = runningApps[displayedApp]; - if (!app) - return; - - var frame = app.frame; - var manifest = app.manifest; - - var cssHeight = - window.innerHeight - StatusBar.height - keyboardHeight + 'px'; - - if (!screenElement.classList.contains('attention') && - requireFullscreen(displayedApp)) { - cssHeight = window.innerHeight - keyboardHeight + 'px'; - } - - frame.style.height = cssHeight; - - setInlineActivityFrameSize(); - } - - // Copy the dimension of the currently displayed app - function setInlineActivityFrameSize() { - if (!inlineActivityFrames.length) - return; - - var app = runningApps[displayedApp]; - var appFrame = app.frame; - var frame = inlineActivityFrames[inlineActivityFrames.length - 1]; - - frame.style.width = appFrame.style.width; - - if (document.mozFullScreen) { - frame.style.height = window.innerHeight + 'px'; - frame.style.top = '0px'; - } else { - if ('wrapper' in appFrame.dataset) { - frame.style.height = window.innerHeight - StatusBar.height + 'px'; - } else { - frame.style.height = appFrame.style.height; - } - frame.style.top = appFrame.offsetTop + 'px'; - } - } - - function setFrameBackgroundBlob(frame, blob, transparent) { - URL.revokeObjectURL(frame.dataset.bgObjectURL); - delete frame.dataset.bgObjectURL; - - var objectURL = URL.createObjectURL(blob); - frame.dataset.bgObjectURL = objectURL; - var backgroundCSS = - '-moz-linear-gradient(top, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.5) 100%),' + - 'url(' + objectURL + '),' + - ((transparent) ? 'transparent' : '#fff'); - - frame.style.background = backgroundCSS; - } - - function clearFrameBackground(frame) { - if (!('bgObjectURL' in frame.dataset)) - return; - - URL.revokeObjectURL(frame.dataset.bgObjectURL); - delete frame.dataset.bgObjectURL; - frame.style.background = ''; - } - - var openFrame = null; - var closeFrame = null; - var openCallback = null; - var closeCallback = null; - var transitionOpenCallback = null; - var transitionCloseCallback = null; - - // Use setOpenFrame() to reset the CSS classes set - // to the current openFrame (before overwriting the reference) - function setOpenFrame(frame) { - if (openFrame) { - removeFrameClasses(openFrame); - } - - openFrame = frame; - } - - // Use setCloseFrame() to reset the CSS classes set - // to the current closeFrame (before overwriting the reference) - function setCloseFrame(frame) { - if (closeFrame) { - removeFrameClasses(closeFrame); - // closeFrame should not be set to active - closeFrame.classList.remove('active'); - } - - closeFrame = frame; - } - - // Remove these visible className from frame so we will not ended - // up having a frozen frame in the middle of the transition - function removeFrameClasses(frame) { - var classNames = ['opening', 'closing', 'opening-switching', - 'opening-card', 'closing-card']; - - var classList = frame.classList; - - classNames.forEach(function removeClass(className) { - classList.remove(className); - }); - } - - windows.addEventListener('transitionend', function frameTransitionend(evt) { - var prop = evt.propertyName; - var frame = evt.target; - if (prop !== 'transform') - return; - - var classList = frame.classList; - - if (classList.contains('inlineActivity')) { - if (classList.contains('active')) { - if (openFrame) - openFrame.firstChild.focus(); - - setOpenFrame(null); - } else { - windows.removeChild(frame); - } - - return; - } - - if (screenElement.classList.contains('switch-app')) { - if (classList.contains('closing')) { - classList.remove('closing'); - classList.add('closing-card'); - - if (openFrame) { - if (openFrame.classList.contains('opening-card')) { - openFrame.classList.remove('opening-card'); - openFrame.classList.add('opening-switching'); - } else { - // Skip the opening-card and opening-switching transition - // because the closing-card transition had already finished here. - if (openFrame.classList.contains('fullscreen-app')) { - screenElement.classList.add('fullscreen-app'); - } - openFrame.classList.add('opening'); - } - } - } else if (classList.contains('closing-card')) { - windowClosed(frame); - setTimeout(closeCallback); - closeCallback = null; - - } else if (classList.contains('opening-switching')) { - // If the opening app need to be full screen, switch to full screen - if (classList.contains('fullscreen-app')) { - screenElement.classList.add('fullscreen-app'); - } - - classList.remove('opening-switching'); - classList.add('opening'); - } else if (classList.contains('opening')) { - windowOpened(frame); - - setTimeout(openCallback); - openCallback = null; - - setCloseFrame(null); - setOpenFrame(null); - screenElement.classList.remove('switch-app'); - } - - return; - } - - if (classList.contains('opening')) { - windowOpened(frame); - - setTimeout(openCallback); - openCallback = null; - - setOpenFrame(null); - } else if (classList.contains('closing')) { - windowClosed(frame); - - setTimeout(closeCallback); - closeCallback = null; - - setCloseFrame(null); - } - }); - - // Executes when the opening transition scale the app - // to full size. - function windowOpened(frame) { - var iframe = frame.firstChild; - - frame.classList.add('active'); - windows.classList.add('active'); - - if ('wrapper' in frame.dataset) { - wrapperFooter.classList.add('visible'); - } - - // Take the focus away from the currently displayed app - var app = runningApps[displayedApp]; - if (app && app.iframe) - app.iframe.blur(); - - // Give the focus to the frame - iframe.focus(); - - if (!TrustedUIManager.isVisible() && !isRunningFirstRunApp) { - // Set homescreen visibility to false - toggleHomescreen(false); - } - - // Set displayedApp to the new value - displayedApp = iframe.dataset.frameOrigin; - - // Set orientation for the new app - setOrientationForApp(displayedApp); - - // Dispatch an 'appopen' event. - var manifestURL = runningApps[displayedApp].manifestURL; - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('appopen', true, false, { - manifestURL: manifestURL, - origin: displayedApp - }); - frame.dispatchEvent(evt); - } - - // Executes when app closing transition finishes. - function windowClosed(frame) { - var iframe = frame.firstChild; - - // If the FTU is closing, make sure we save this state - if (iframe.src == ftuURL) { - isRunningFirstRunApp = false; - document.getElementById('screen').classList.remove('ftu'); - window.asyncStorage.setItem('ftu.enabled', false); - // Done with FTU, letting everyone know - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('ftudone', - /* canBubble */ true, /* cancelable */ false, {}); - window.dispatchEvent(evt); - } - - frame.classList.remove('active'); - windows.classList.remove('active'); - - // set the closed frame visibility to false - if ('setVisible' in iframe) - iframe.setVisible(false); - - screenElement.classList.remove('fullscreen-app'); - } - - // The following things needs to happen when firstpaint happens. - // We centralize all that here but not all of them applies. - windows.addEventListener('mozbrowserfirstpaint', function firstpaint(evt) { - var iframe = evt.target; - var frame = iframe.parentNode; - - // remove the unpainted flag - delete iframe.dataset.unpainted; - - setTimeout(function firstpainted() { - // Save the screenshot - // Remove the background only until we actually got the screenshot, - // because the getScreenshot() call will be pushed back by - // painting/loading in the child process; when we got the screenshot, - // that means the app is mostly loaded. - // (as opposed to plain white firstpaint) - saveAppScreenshot(frame, function screenshotTaken() { - // Remove the default background - frame.classList.remove('default-background'); - - // Remove the screenshot from frame - clearFrameBackground(frame); - }); - }); - }); - - // setFrameBackground() will attach the screenshot background to - // the given frame. - // The callback could be sync or async (depend on whether we need - // the screenshot from database or not) - function setFrameBackground(frame, callback, transparent) { - var iframe = frame.firstChild; - // If the frame is painted, or there is already background image present - // start the transition right away. - if (!('unpainted' in iframe.dataset) || - ('bgObjectURL' in frame.dataset)) { - callback(); - return; - } - - // Get the screenshot from the database - getAppScreenshotFromDatabase(iframe.src || iframe.dataset.frameOrigin, - function(screenshot) { - // If firstpaint is faster than database, we will not transition - // with screenshot. - if (!('unpainted' in iframe.dataset)) { - callback(); - return; - } - - if (!screenshot) { - // put a default background - frame.classList.add('default-background'); - callback(); - return; - } - - // set the screenshot as the background of the frame itself. - // we are safe to do so since there is nothing on it yet. - setFrameBackgroundBlob(frame, screenshot, transparent); - - // start the transition - callback(); - }); - } - - // On-disk database for window manager. - // It's only for app screenshots right now. - var database = null; - var DB_SCREENSHOT_OBJSTORE = 'screenshots'; - - (function openDatabase() { - var DB_VERSION = 2; - var DB_NAME = 'window_manager'; - - var req = window.indexedDB.open(DB_NAME, DB_VERSION); - req.onerror = function() { - console.error('Window Manager: opening database failed.'); - }; - req.onupgradeneeded = function databaseUpgradeneeded() { - database = req.result; - - if (database.objectStoreNames.contains(DB_SCREENSHOT_OBJSTORE)) - database.deleteObjectStore(DB_SCREENSHOT_OBJSTORE); - - var store = database.createObjectStore( - DB_SCREENSHOT_OBJSTORE, { keyPath: 'url' }); - }; - - req.onsuccess = function databaseSuccess() { - database = req.result; - }; - })(); - - function putAppScreenshotToDatabase(url, data) { - if (!database) - return; - - var txn = database.transaction(DB_SCREENSHOT_OBJSTORE, 'readwrite'); - txn.onerror = function() { - console.warn( - 'Window Manager: transaction error while trying to save screenshot.'); - }; - var store = txn.objectStore(DB_SCREENSHOT_OBJSTORE); - var req = store.put({ - url: url, - screenshot: data - }); - req.onerror = function(evt) { - console.warn( - 'Window Manager: put error while trying to save screenshot.'); - }; - } - - function getAppScreenshotFromDatabase(url, callback) { - if (!database) { - console.warn( - 'Window Manager: Neither database nor app frame is ' + - 'ready for getting screenshot.'); - - callback(); - return; - } - - var req = database.transaction(DB_SCREENSHOT_OBJSTORE) - .objectStore(DB_SCREENSHOT_OBJSTORE).get(url); - req.onsuccess = function() { - if (!req.result) { - console.log('Window Manager: No screenshot in database. ' + - 'This is expected from a fresh installed app.'); - callback(); - - return; - } - - callback(req.result.screenshot, true); - } - req.onerror = function(evt) { - console.warn('Window Manager: get screenshot from database failed.'); - callback(); - }; - } - - function deleteAppScreenshotFromDatabase(url) { - var txn = database.transaction(DB_SCREENSHOT_OBJSTORE); - var store = txn.objectStore(DB_SCREENSHOT_OBJSTORE); - - store.delete(url); - } - - function getAppScreenshotFromFrame(frame, callback) { - if (!frame) { - callback(); - return; - } - - var iframe = frame.firstChild; - var req = iframe.getScreenshot(iframe.offsetWidth, iframe.offsetHeight); - - req.onsuccess = function gotScreenshotFromFrame(evt) { - var result = evt.target.result; - callback(result, false); - }; - - req.onerror = function gotScreenshotFromFrameError(evt) { - console.warn('Window Manager: getScreenshot failed.'); - callback(); - }; - } - - // Meta method for get the screenshot from the app frame, - // and save it to database. - function saveAppScreenshot(frame, callback) { - getAppScreenshotFromFrame(frame, function gotScreenshot(screenshot) { - if (callback) - callback(screenshot); - - if (!screenshot) - return; - - var iframe = frame.firstChild; - putAppScreenshotToDatabase(iframe.src || iframe.dataset.frameOrigin, - screenshot); - }); - } - - // Perform an "open" animation for the app's iframe - function openWindow(origin, callback) { - var app = runningApps[origin]; - setOpenFrame(app.frame); - - openCallback = callback || function() {}; - - // set the size of the opening app - setAppSize(origin); - - if (origin === homescreen) { - // We cannot apply background screenshot to home screen app since - // the screenshot is encoded in JPEG and the alpha channel is - // not perserved. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=801676#c33 - // If that resolves, - // setFrameBackground(openFrame, gotBackground, true); - // will simply work here. - - // Call the openCallback only once. We have to use tmp var as - // openCallback can be a method calling the callback - // (like the `removeFrame` callback in `kill()` ). - var tmpCallback = openCallback; - openCallback = null; - tmpCallback(); - - windows.classList.add('active'); - openFrame.classList.add('homescreen'); - openFrame.firstChild.focus(); - setOpenFrame(null); - displayedApp = origin; - - return; - } - - if (requireFullscreen(origin)) - screenElement.classList.add('fullscreen-app'); - - transitionOpenCallback = function startOpeningTransition() { - // We have been canceled by another transition. - if (!openFrame || transitionOpenCallback != startOpeningTransition) - return; - - // Make sure we're not called twice. - transitionOpenCallback = null; - - if (!screenElement.classList.contains('switch-app')) { - openFrame.classList.add('opening'); - } else if (!openFrame.classList.contains('opening')) { - openFrame.classList.add('opening-card'); - } - }; - - if ('unpainted' in openFrame.firstChild.dataset) { - waitForNextPaintOrBackground(openFrame, transitionOpenCallback); - } else { - waitForNextPaint(openFrame, transitionOpenCallback); - } - - // Set the frame to be visible. - if ('setVisible' in openFrame.firstChild) { - if (!AttentionScreen.isFullyVisible()) { - openFrame.firstChild.setVisible(true); - } else { - // If attention screen is fully visible now, - // don't give the open frame visible. - // This is the case that homescreen is restarted behind attention screen - openFrame.firstChild.setVisible(false); - } - } - } - - function waitForNextPaintOrBackground(frame, callback) { - var waiting = true; - function proceed() { - if (waiting) { - waiting = false; - callback(); - } - } - - waitForNextPaint(frame, proceed); - setFrameBackground(frame, proceed); - } - - function waitForNextPaint(frame, callback) { - function onNextPaint() { - clearTimeout(timeout); - callback(); - } - - var iframe = frame.firstChild; - - // Register a timeout in case we don't receive - // nextpaint in an acceptable time frame. - var timeout = setTimeout(function() { - if ('removeNextPaintListener' in iframe) - iframe.removeNextPaintListener(onNextPaint); - callback(); - }, kTransitionTimeout); - - if ('addNextPaintListener' in iframe) - iframe.addNextPaintListener(onNextPaint); - } - - // Perform a "close" animation for the app's iframe - function closeWindow(origin, callback) { - var app = runningApps[origin]; - setCloseFrame(app.frame); - closeCallback = callback || function() {}; - - // Animate the window close. Ensure the homescreen is in the - // foreground since it will be shown during the animation. - var homescreenFrame = ensureHomescreen(); - - // invoke openWindow to show homescreen here - openWindow(homescreen, null); - - // Take keyboard focus away from the closing window - closeFrame.firstChild.blur(); - - // set orientation for homescreen app - setOrientationForApp(homescreen); - - // Set the size of both homescreen app and the closing app - // since the orientation had changed. - setAppSize(homescreen); - setAppSize(origin); - - // Send a synthentic 'appwillclose' event. - // The keyboard uses this and the appclose event to know when to close - // See https://github.com/andreasgal/gaia/issues/832 - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('appwillclose', true, false, { origin: origin }); - closeFrame.dispatchEvent(evt); - - if ('wrapper' in closeFrame.dataset) { - wrapperHeader.classList.remove('visible'); - wrapperFooter.classList.remove('visible'); - } - - transitionCloseCallback = function startClosingTransition() { - // We have been canceled by another transition. - if (!closeFrame || transitionCloseCallback != startClosingTransition) - return; - - // Make sure we're not called twice. - transitionCloseCallback = null; - - // Start the transition - closeFrame.classList.add('closing'); - closeFrame.classList.remove('active'); - }; - - waitForNextPaint(homescreenFrame, transitionCloseCallback); - } - - // Perform a "switching" animation for the closing frame and the opening frame - function switchWindow(origin, callback) { - // This will trigger different transition to both openWindow() - // and closeWindow() transition. - screenElement.classList.add('switch-app'); - - // Ask closeWindow() to start closing the displayedApp - closeWindow(displayedApp, callback); - - // Ask openWindow() to show a card on the right waiting to be opened - openWindow(origin); - } - - // Ensure the homescreen is loaded and return its frame. Restarts - // the homescreen app if it was killed in the background. - // Note: this function would not invoke openWindow(homescreen), - // which should be handled in setDisplayedApp and in closeWindow() - function ensureHomescreen(reset) { - // If the url of the homescreen is not known at this point do nothing. - if (!homescreen || !homescreenManifestURL) { - return null; - } - - if (!isRunning(homescreen)) { - var app = Applications.getByManifestURL(homescreenManifestURL); - appendFrame(null, homescreen, homescreenURL, - app.manifest.name, app.manifest, app.manifestURL); - runningApps[homescreen].iframe.dataset.start = Date.now(); - setAppSize(homescreen); - } else if (reset) { - runningApps[homescreen].iframe.src = homescreenURL; - setAppSize(homescreen); - } - - return runningApps[homescreen].frame; - } - - function retrieveHomescreen(callback) { - var lock = navigator.mozSettings.createLock(); - var setting = lock.get('homescreen.manifestURL'); - setting.onsuccess = function() { - var app = - Applications.getByManifestURL(this.result['homescreen.manifestURL']); - - // XXX This is a one-day workaround to not break everybody and make sure - // work can continue. - if (!app) { - var tmpURL = document.location.toString() - .replace('system', 'homescreen') - .replace('index.html', 'manifest.webapp'); - app = Applications.getByManifestURL(tmpURL); - } - - if (app) { - homescreenManifestURL = app.manifestURL; - homescreen = app.origin; - homescreenURL = app.origin + '/index.html#root'; - - callback(app); - } - } - } - - function skipFTU() { - document.getElementById('screen').classList.remove('ftuStarting'); - handleInitlogo(); - setDisplayedApp(homescreen); - } - - // Check if the FTU was executed or not, if not, get a - // reference to the app and launch it. - function retrieveFTU() { - window.asyncStorage.getItem('ftu.enabled', function getItem(launchFTU) { - document.getElementById('screen').classList.add('ftuStarting'); - if (launchFTU === false) { - skipFTU(); - return; - } - var lock = navigator.mozSettings.createLock(); - var req = lock.get('ftu.manifestURL'); - req.onsuccess = function() { - ftuManifestURL = this.result['ftu.manifestURL']; - if (!ftuManifestURL) { - dump('FTU manifest cannot be found skipping.\n'); - skipFTU(); - return; - } - ftu = Applications.getByManifestURL(ftuManifestURL); - if (!ftu) { - dump('Opps, bogus FTU manifest.\n'); - skipFTU(); - return; - } - ftuURL = ftu.origin + ftu.manifest.entry_points['ftu'].launch_path; - ftu.launch('ftu'); - }; - req.onerror = function() { - dump('Couldn\'t get the ftu manifestURL.\n'); - skipFTU(); - }; - }); - } - - // Hide current app - function hideCurrentApp(callback) { - if (displayedApp == null || displayedApp == homescreen) - return; - - toggleHomescreen(true); - var frame = getAppFrame(displayedApp); - frame.classList.add('back'); - frame.classList.remove('restored'); - if (callback) { - frame.addEventListener('transitionend', function execCallback() { - frame.style.visibility = 'hidden'; - frame.removeEventListener('transitionend', execCallback); - callback(); - }); - } - } - - // If app parameter is passed, - // it means there's a specific app needs to be restored - // instead of current app - function restoreCurrentApp(app) { - if (app) { - // Restore app visibility immediately but don't open it. - var frame = getAppFrame(app); - frame.style.visibility = 'visible'; - frame.classList.remove('back'); - } else { - app = displayedApp; - toggleHomescreen(false); - var frame = getAppFrame(app); - frame.style.visibility = 'visible'; - frame.classList.remove('back'); - frame.classList.add('restored'); - frame.addEventListener('transitionend', function removeRestored() { - frame.removeEventListener('transitionend', removeRestored); - frame.classList.remove('restored'); - }); - } - } - - function toggleHomescreen(visible) { - var homescreenFrame = ensureHomescreen(); - if (homescreenFrame && 'setVisible' in homescreenFrame.firstChild) - homescreenFrame.firstChild.setVisible(visible); - } - - // Switch to a different app - function setDisplayedApp(origin, callback) { - var currentApp = displayedApp, newApp = origin || homescreen; - var isFirstRunApplication = !currentApp && (origin == ftuURL); - - var homescreenFrame = null; - if (!isFirstRunApplication) { - // Returns the frame reference of the home screen app. - // Restarts the homescreen app if it was killed in the background. - homescreenFrame = ensureHomescreen(); - } - - // Cancel transitions waiting to be started. - transitionOpenCallback = null; - transitionCloseCallback = null; - - // Discard any existing activity - stopInlineActivity(true); - - // Before starting a new transition, let's make sure current transitions - // are stopped and the state classes are cleaned up. - // visibility status should also be reset. - if (openFrame && 'setVisible' in openFrame.firstChild) - openFrame.firstChild.setVisible(false); - if (closeFrame && 'setVisible' in closeFrame.firstChild) - closeFrame.firstChild.setVisible(false); - - if (!isFirstRunApplication && newApp == homescreen && !AttentionScreen.isFullyVisible()) { - toggleHomescreen(true); - } - - setOpenFrame(null); - setCloseFrame(null); - screenElement.classList.remove('switch-app'); - screenElement.classList.remove('fullscreen-app'); - - // Dispatch an appwillopen event only when we open an app - if (newApp != currentApp) { - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('appwillopen', true, true, { origin: newApp }); - - var app = runningApps[newApp]; - // Allows listeners to cancel app opening and so stay on homescreen - if (!app.frame.dispatchEvent(evt)) { - if (typeof(callback) == 'function') - callback(); - return; - } - - var iframe = app.iframe; - - // unpainted means that the app is cold booting - // if it is, we're going to listen for Browser API's loadend event - // which indicates that the iframe's document load is complete - // - // if the app is not cold booting (is in memory) we will listen - // to appopen event, which is fired when the transition to the - // app window is complete. - // - // [w] - warm boot (app is in memory, just transition to it) - // [c] - cold boot (app has to be booted, we show it's document load - // time) - var type; - if ('unpainted' in iframe.dataset) { - type = 'mozbrowserloadend'; - } else { - iframe.dataset.start = Date.now(); - type = 'appopen'; - } - - app.frame.addEventListener(type, function apploaded(e) { - e.target.removeEventListener(e.type, apploaded); - - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('apploadtime', true, false, { - time: parseInt(Date.now() - iframe.dataset.start), - type: (e.type == 'appopen') ? 'w' : 'c' - }); - iframe.dispatchEvent(evt); - }); - } - - // Case 1: the app is already displayed - if (currentApp && currentApp == newApp) { - if (newApp == homescreen) { - // relaunch homescreen - openWindow(homescreen, callback); - } else if (callback) { - // Just run the callback right away if it is not homescreen - callback(); - } - } - // Case 2: null --> app - else if (isFirstRunApplication) { - isRunningFirstRunApp = true; - openWindow(newApp, function windowOpened() { - handleInitlogo(function() { - var mainScreen = document.getElementById('screen'); - mainScreen.classList.add('ftu'); - mainScreen.classList.remove('ftuStarting'); - }); - }); - } - // Case 3: null->homescreen || homescreen->app - else if ((!currentApp && newApp == homescreen) || - (currentApp == homescreen && newApp)) { - openWindow(newApp, callback); - } - // Case 4: app->homescreen - else if (currentApp && currentApp != homescreen && newApp == homescreen) { - // For screenshot to catch current window size - closeWindow(currentApp, callback); - } - // Case 5: app-to-app transition - else { - switchWindow(newApp, callback); - } - // Set homescreen as active, - // to control the z-index between homescreen & keyboard iframe - if ((newApp == homescreen) && homescreenFrame) { - homescreenFrame.classList.add('active'); - } else { - homescreenFrame.classList.remove('active'); - } - - // Record the time when app was launched, - // need this to display apps in proper order on CardsView. - // We would also need this to determined the freshness of the frame - // for making screenshots. - if (newApp) - runningApps[newApp].launchTime = Date.now(); - - // If the app has a attention screen open, displaying it - AttentionScreen.showForOrigin(newApp); - } - - function setOrientationForApp(origin) { - if (origin == null) { // No app is currently running. - screen.mozLockOrientation('portrait-primary'); - return; - } - - var app = runningApps[origin]; - if (!app) - return; - var manifest = app.manifest; - - if (manifest.orientation) { - var rv = screen.mozLockOrientation(manifest.orientation); - if (rv === false) { - console.warn('screen.mozLockOrientation() returned false for', - origin, 'orientation', manifest.orientation); - } - } - else { // If no orientation was requested, then let it rotate - screen.mozUnlockOrientation(); - } - } - - var isOutOfProcessDisabled = false; - SettingsListener.observe('debug.oop.disabled', false, function(value) { - isOutOfProcessDisabled = value; - }); - - function createFrame(origFrame, origin, url, name, manifest, manifestURL) { - var iframe = origFrame || document.createElement('iframe'); - iframe.setAttribute('mozallowfullscreen', 'true'); - - var frame = document.createElement('div'); - frame.appendChild(iframe); - frame.className = 'appWindow'; - - iframe.dataset.frameOrigin = origin; - // Save original frame URL in order to restore it on frame load error - iframe.dataset.frameURL = url; - - // Note that we don't set the frame size here. That will happen - // when we display the app in setDisplayedApp() - - // frames are began unpainted. - iframe.dataset.unpainted = true; - - if (!manifestURL) { - frame.setAttribute('data-wrapper', 'true'); - return frame; - } - - // Most apps currently need to be hosted in a special 'mozbrowser' iframe. - // They also need to be marked as 'mozapp' to be recognized as apps by the - // platform. - iframe.setAttribute('mozbrowser', 'true'); - - // These apps currently have bugs preventing them from being - // run out of process. All other apps will be run OOP. - // - var outOfProcessBlackList = [ - 'Browser' - // Requires nested content processes (bug 761935). This is not - // on the schedule for v1. - ]; - - if (!isOutOfProcessDisabled && - outOfProcessBlackList.indexOf(name) === -1) { - // FIXME: content shouldn't control this directly - iframe.setAttribute('remote', 'true'); - } - - iframe.setAttribute('mozapp', manifestURL); - iframe.src = url; - return frame; - } - - function appendFrame(origFrame, origin, url, name, manifest, manifestURL) { - // Create the <iframe mozbrowser mozapp> that hosts the app - var frame = - createFrame(origFrame, origin, url, name, manifest, manifestURL); - var iframe = frame.firstChild; - frame.id = 'appframe' + nextAppId++; - iframe.dataset.frameType = 'window'; - - // Give a name to the frame for differentiating between main frame and - // inline frame. With the name we can get frames of the same app using the - // window.open method. - iframe.name = 'main'; - - // If this frame corresponds to the homescreen, set mozapptype=homescreen - // so we're less likely to kill this frame's process when we're running low - // on memory. - // - // We must do this before we the appendChild() call below. Once - // we add this frame to the document, we can't change its app type. - if (origin === homescreen) { - iframe.setAttribute('mozapptype', 'homescreen'); - } - - // Add the iframe to the document - windows.appendChild(frame); - - // And map the app origin to the info we need for the app - var app = new AppWindow({ - origin: origin, - name: name, - manifest: manifest, - manifestURL: manifestURL, - frame: frame, - iframe: iframe, - launchTime: 0 - }); - runningApps[origin] = app; - - if (requireFullscreen(origin)) { - frame.classList.add('fullscreen-app'); - } - if (origin === ftuURL) { - // Add a way to identify ftu app - // (Used by SimLock) - frame.classList.add('ftu'); - } - - // A frame should start with visible false - if ('setVisible' in iframe) - iframe.setVisible(false); - - numRunningApps++; - - return app; - } - - function startInlineActivity(origin, url, name, manifest, manifestURL) { - // Create the <iframe mozbrowser mozapp> that hosts the app - var frame = createFrame(null, origin, url, name, manifest, manifestURL); - var iframe = frame.firstChild; - frame.classList.add('inlineActivity'); - iframe.dataset.frameType = 'inline-activity'; - - // Give a name to the frame for differentiating between main frame and - // inline frame. With the name we can get frames of the same app using the - // window.open method. - iframe.name = 'inline'; - - // Save the reference - inlineActivityFrames.push(frame); - - // Set the size - setInlineActivityFrameSize(); - - // Add the iframe to the document - windows.appendChild(frame); - - // Open the frame, first, store the reference - openFrame = frame; - - // set the frame to visible state - if ('setVisible' in iframe) - iframe.setVisible(true); - - setFrameBackground(openFrame, function gotBackground() { - // Start the transition when this async/sync callback is called. - openFrame.classList.add('active'); - if (inlineActivityFrames.length == 1) - activityCallerOrigin = displayedApp; - if ('wrapper' in runningApps[displayedApp].frame.dataset) { - wrapperFooter.classList.remove('visible'); - wrapperHeader.classList.remove('visible'); - } - }); - } - - function removeFrame(origin) { - var app = runningApps[origin]; - var frame = app.frame; - - if (frame) { - windows.removeChild(frame); - clearFrameBackground(frame); - } - - if (openFrame == frame) { - setOpenFrame(null); - setTimeout(openCallback); - openCallback = null; - } - if (closeFrame == frame) { - setCloseFrame(null); - setTimeout(closeCallback); - closeCallback = null; - } - - delete runningApps[origin]; - numRunningApps--; - } - - function removeInlineFrame(frame) { - // If frame is transitioning we should remove the reference - if (openFrame == frame) - setOpenFrame(null); - - // If frame is never set visible, we can remove the frame directly - // without closing transition - if (!frame.classList.contains('active')) { - windows.removeChild(frame); - return; - } - // Take keyboard focus away from the closing window - frame.firstChild.blur(); - // Remove the active class and start the closing transition - frame.classList.remove('active'); - } - - // If all is not specified, - // remove the top most frame - function stopInlineActivity(all) { - if (!inlineActivityFrames.length) - return; - - if (!all) { - var frame = inlineActivityFrames.pop(); - removeInlineFrame(frame); - } else { - // stop all activity frames - // Remore the inlineActivityFrame reference - for (var frame of inlineActivityFrames) { - removeInlineFrame(frame); - } - inlineActivityFrames = []; - } - - if (!inlineActivityFrames.length) { - // Give back focus to the displayed app - var app = runningApps[displayedApp]; - if (app && app.iframe) { - app.iframe.focus(); - if ('wrapper' in app.frame.dataset) { - wrapperFooter.classList.add('visible'); - } - } - screenElement.classList.remove('inline-activity'); - } - } - - // Watch activity completion here instead of activity.js - // Because we know when and who to re-launch when activity ends. - window.addEventListener('mozChromeEvent', function(e) { - if (e.detail.type == 'activity-done') { - // Remove the top most frame every time we get an 'activity-done' event. - stopInlineActivity(); - if (!inlineActivityFrames.length) { - setDisplayedApp(activityCallerOrigin); - activityCallerOrigin = ''; - } - } - }); - - // There are two types of mozChromeEvent we need to handle - // in order to launch the app for Gecko - window.addEventListener('mozChromeEvent', function(e) { - var startTime = Date.now(); - - var manifestURL = e.detail.manifestURL; - if (!manifestURL) - return; - - var app = Applications.getByManifestURL(manifestURL); - if (!app) - return; - - var manifest = app.manifest; - var name = new ManifestHelper(manifest).name; - var origin = app.origin; - - // Check if it's a virtual app from a entry point. - // If so, change the app name and origin to the - // entry point. - var entryPoints = manifest.entry_points; - if (entryPoints && manifest.type == 'certified') { - var givenPath = e.detail.url.substr(origin.length); - - // Workaround here until the bug (to be filed) is fixed - // Basicly, gecko is sending the URL without launch_path sometimes - for (var ep in entryPoints) { - var currentEp = entryPoints[ep]; - var path = givenPath; - if (path.indexOf('?') != -1) { - path = path.substr(0, path.indexOf('?')); - } - - //Remove the origin and / to find if if the url is the entry point - if (path.indexOf('/' + ep) == 0 && - (currentEp.launch_path == path)) { - origin = origin + currentEp.launch_path; - name = new ManifestHelper(currentEp).name; - } - } - } - switch (e.detail.type) { - // mozApps API is asking us to launch the app - // We will launch it in foreground - case 'webapps-launch': - if (origin == homescreen) { - // No need to append a frame if is homescreen - setDisplayedApp(); - } else { - if (!isRunning(origin)) { - appendFrame(null, origin, e.detail.url, - name, app.manifest, app.manifestURL); - } - runningApps[origin].iframe.dataset.start = startTime; - setDisplayedApp(origin, null, 'window'); - } - break; - // System Message Handler API is asking us to open the specific URL - // that handles the pending system message. - // We will launch it in background if it's not handling an activity. - case 'open-app': - // If the system message goes to System app, - // we should not be launching that in a frame. - if (e.detail.url === window.location.href) - return; - - if (e.detail.isActivity && e.detail.target.disposition && - e.detail.target.disposition == 'inline') { - // Inline activities behaves more like a dialog, - // let's deal them here. - - startInlineActivity(origin, e.detail.url, - name, manifest, app.manifestURL); - - return; - } - - if (isRunning(origin)) { - // If the app is in foreground, it's too risky to change it's - // URL. We'll ignore this request. - if (displayedApp !== origin) { - var iframe = getAppFrame(origin).firstChild; - - // If the app is opened and it is loaded to the correct page, - // then there is nothing to do. - if (iframe.src !== e.detail.url) { - // Rewrite the URL of the app frame to the requested URL. - // XXX: We could ended opening URls not for the app frame - // in the app frame. But we don't care. - iframe.src = e.detail.url; - } - } - } else if (origin !== homescreen) { - // XXX: We could ended opening URls not for the app frame - // in the app frame. But we don't care. - appendFrame(null, origin, e.detail.url, - name, manifest, app.manifestURL); - - // set the size of the iframe - // so Cards View will get a correct screenshot of the frame - if (!e.detail.isActivity) - setAppSize(origin, false); - } else { - ensureHomescreen(); - } - - // We will only bring web activity handling apps to the foreground - if (!e.detail.isActivity) - return; - - // XXX: the correct way would be for UtilityTray to close itself - // when there is a appwillopen/appopen event. - UtilityTray.hide(); - - setDisplayedApp(origin); - - break; - } - }); - - // If the application tried to close themselves by calling window.close() - // we will handle that here. - // XXX: this event is fired twice: - // https://bugzilla.mozilla.org/show_bug.cgi?id=814583 - window.addEventListener('mozbrowserclose', function(e) { - if (!'frameType' in e.target.dataset) - return; - - switch (e.target.dataset.frameType) { - case 'window': - kill(e.target.dataset.frameOrigin); - break; - - case 'inline-activity': - stopInlineActivity(true); - break; - } - }); - - // Deal with locationchange - window.addEventListener('mozbrowserlocationchange', function(e) { - if (!'frameType' in e.target.dataset) - return; - - e.target.dataset.url = e.detail; - }); - - // Deal with application uninstall event - // if the application is being uninstalled, we ensure it stop running here. - window.addEventListener('applicationuninstall', function(e) { - kill(e.detail.application.origin); - - deleteAppScreenshotFromDatabase(e.detail.application.origin); - }); - - // When an UI layer is overlapping the current app, - // WindowManager should set the visibility of app iframe to false - // And reset to true when the layer is gone. - // We may need to handle windowclosing, windowopened in the future. - var attentionScreenTimer = null; - - var overlayEvents = [ - 'lock', - 'will-unlock', - 'attentionscreenshow', - 'attentionscreenhide', - 'status-active', - 'status-inactive' - ]; - - function overlayEventHandler(evt) { - if (attentionScreenTimer) - clearTimeout(attentionScreenTimer); - switch (evt.type) { - case 'status-active': - case 'attentionscreenhide': - case 'will-unlock': - if (LockScreen.locked) - return; - if (inlineActivityFrames.length) { - setVisibilityForInlineActivity(true); - } else { - setVisibilityForCurrentApp(true); - } - break; - case 'lock': - setVisibilityForCurrentApp(false); - break; - - /* - * Because in-transition is needed in attention screen, - * We set a timer here to deal with visibility change - */ - case 'status-inactive': - if (!AttentionScreen.isVisible()) - return; - case 'attentionscreenshow': - if (evt.detail && evt.detail.origin && - evt.detail.origin != displayedApp) { - attentionScreenTimer = setTimeout(function setVisibility() { - if (inlineActivityFrames.length) { - setVisibilityForInlineActivity(false); - } else { - setVisibilityForCurrentApp(false); - } - }, 3000); - - // Immediatly blur the frame in order to ensure hiding the keyboard - var app = runningApps[displayedApp]; - if (app) - app.iframe.blur(); - } - break; - } - } - - overlayEvents.forEach(function overlayEventIterator(event) { - window.addEventListener(event, overlayEventHandler); - }); - - function setVisibilityForInlineActivity(visible) { - if (!inlineActivityFrames.length) - return; - - var topFrame = inlineActivityFrames[inlineActivityFrames.length - 1].firstChild; - if ('setVisible' in topFrame) { - topFrame.setVisible(visible); - } - - // Restore/give away focus on visiblity change - // so that the app can take back its focus - if (visible) { - topFrame.focus(); - } else { - topFrame.blur(); - } - } - - function setVisibilityForCurrentApp(visible) { - var app = runningApps[displayedApp]; - if (!app) - return; - if ('setVisible' in app.iframe) - app.iframe.setVisible(visible); - - // Restore/give away focus on visiblity change - // so that the app can take back its focus - if (visible) - app.iframe.focus(); - else - app.iframe.blur(); - } - - function handleAppCrash(origin, manifestURL) { - if (origin && manifestURL) { - // When inline activity frame crashes, - // query the localized name from manifest - var app = Applications.getByManifestURL(manifestURL); - CrashReporter.setAppName(getAppName(origin, app.manifest)); - } else { - var app = runningApps[displayedApp]; - CrashReporter.setAppName(app.name); - } - } - - function getAppName(origin, manifest) { - if (!manifest) - return ''; - - if (manifest.entry_points && manifest.type == 'certified') { - var entryPoint = manifest.entry_points[origin.split('/')[3]]; - return new ManifestHelper(entryPoint).name; - } - return new ManifestHelper(manifest).name; - } - - // Deal with crashed apps - window.addEventListener('mozbrowsererror', function(e) { - if (!'frameType' in e.target.dataset) - return; - - var origin = e.target.dataset.frameOrigin; - var manifestURL = e.target.getAttribute('mozapp'); - - if (e.target.dataset.frameType == 'inline-activity') { - stopInlineActivity(true); - handleAppCrash(origin, manifestURL); - return; - } - - if (e.target.dataset.frameType !== 'window') - return; - - /* - detail.type = error (Server Not Found case) - is handled in Modal Dialog - */ - if (e.detail.type !== 'fatal') - return; - - // If the crashing app is currently displayed, we will present - // the user with a banner notification. - if (displayedApp == origin) - handleAppCrash(); - - // If the crashing app is the home screen app and it is the displaying app - // we will need to relaunch it right away. - // Alternatively, if home screen is not the displaying app, - // we will not relaunch it until the foreground app is closed. - // (to be dealt in setDisplayedApp(), not here) - if (displayedApp == homescreen) { - kill(origin, function relaunchHomescreen() { - setDisplayedApp(homescreen); - }); - return; - } - - // Actually remove the frame, and trigger the closing transition - // if the app is currently displaying - kill(origin); - }); - - - function hasPermission(app, permission) { - var mozPerms = navigator.mozPermissionSettings; - if (!mozPerms) - return false; - - var value = mozPerms.get(permission, app.manifestURL, app.origin, false); - - return (value === 'allow'); - } - - // Use a setting in order to be "called" by settings app - navigator.mozSettings.addObserver( - 'clear.remote-windows.data', - function clearRemoteWindowsData(setting) { - var shouldClear = setting.settingValue; - if (!shouldClear) - return; - - // Delete all storage and cookies from our content processes - var request = navigator.mozApps.getSelf(); - request.onsuccess = function() { - request.result.clearBrowserData(); - }; - - // Reset the setting value to false - var lock = navigator.mozSettings.createLock(); - lock.set({'clear.remote-windows.data': false}); - }); - - // Watch for window.open usages in order to open wrapper frames - window.addEventListener('mozbrowseropenwindow', function handleWrapper(evt) { - var detail = evt.detail; - var features; - try { - features = JSON.parse(detail.features); - } catch (e) { - features = {}; - } - - // Handles only call to window.open with `{remote: true}` feature. - if (!features.remote) - return; - - // XXX bug 819882: for now, only allows homescreen to open oop windows - var callerIframe = evt.target; - var callerFrame = callerIframe.parentNode; - var manifestURL = callerIframe.getAttribute('mozapp'); - var callerApp = Applications.getByManifestURL(manifestURL); - if (!callerApp || !callerFrame.classList.contains('homescreen')) - return; - var callerOrigin = callerApp.origin; - - // So, we are going to open a remote window. - // Now, avoid PopupManager listener to be fired. - evt.stopImmediatePropagation(); - - var name = detail.name; - var url = detail.url; - - // Use fake origin for named windows in order to be able to reuse them, - // otherwise always open a new window for '_blank'. - var origin = null; - var app = null; - if (name == '_blank') { - origin = url; - - // Just bring on top if a wrapper window is already running with this url - if (origin in runningApps && - runningApps[origin].windowName == '_blank') { - setDisplayedApp(origin); - return; - } - } else { - origin = 'window:' + name + ',source:' + callerOrigin; - - var runningApp = runningApps[origin]; - if (runningApp && runningApp.windowName === name) { - if (runningApp.iframe.src === url) { - // If the url is already loaded, just display the app - setDisplayedApp(origin); - return; - } else { - // Wrapper context shouldn't be shared between two apps -> killing - kill(origin); - } - } - } - - var title = '', icon = '', remote = false, useAsyncPanZoom = false; - var originName, originURL, searchName, searchURL; - - try { - var features = JSON.parse(detail.features); - var regExp = new RegExp(' ', 'g'); - - title = features.name.replace(regExp, ' ') || url; - icon = features.icon || ''; - - if (features.origin) { - originName = features.origin.name.replace(regExp, ' '); - originURL = decodeURIComponent(features.origin.url); - } - - if (features.search) { - searchName = features.search.name.replace(regExp, ' '); - searchURL = decodeURIComponent(features.search.url); - } - - if (features.useAsyncPanZoom) - useAsyncPanZoom = true; - } catch (ex) { } - - // If we don't reuse an existing app, open a brand new one - var iframe; - if (!app) { - // Bug 807438: Move new window document OOP - // Ignore `event.detail.frameElement` for now in order - // to create a remote system app frame. - // So that new window documents are going to share - // system app content processes data jar. - iframe = document.createElement('iframe'); - iframe.setAttribute('mozbrowser', 'true'); - iframe.setAttribute('remote', 'true'); - - iframe.addEventListener('mozbrowserloadstart', function start() { - iframe.dataset.loading = true; - wrapperHeader.classList.add('visible'); - }); - - iframe.addEventListener('mozbrowserloadend', function end() { - delete iframe.dataset.loading; - wrapperHeader.classList.remove('visible'); - }); - - // `mozasyncpanzoom` only works when added before attaching the iframe - // node to the document. - if (useAsyncPanZoom) { - iframe.dataset.useAsyncPanZoom = true; - iframe.setAttribute('mozasyncpanzoom', 'true'); - } - - var app = appendFrame(iframe, origin, url, title, { - 'name': title - }, null); - - // Set the window name in order to reuse this app if we try to open - // a new window with same name - app.windowName = name; - } else { - iframe = app.iframe; - - // Update app name for the card view - app.manifest.name = title; - } - - iframe.dataset.name = title; - iframe.dataset.icon = icon; - - if (originName) - iframe.dataset.originName = originName; - if (originURL) - iframe.dataset.originURL = originURL; - - if (searchName) - iframe.dataset.searchName = searchName; - if (searchURL) - iframe.dataset.searchURL = searchURL; - - // First load blank page in order to hide previous website - iframe.src = url; - - setDisplayedApp(origin); - }, true); // Use capture in order to catch the event before PopupManager does - - - // Stop running the app with the specified origin - function kill(origin, callback) { - if (!isRunning(origin)) - return; - - // As we can't immediatly remove runningApps entry, - // we flag it as being killed in order to avoid trying to remove it twice. - // (Check required because of bug 814583) - if (runningApps[origin].killed) - return; - runningApps[origin].killed = true; - - // If the app is the currently displayed app, switch to the homescreen - if (origin === displayedApp) { - // when the homescreen is displayed and being - // killed we need to forcibly restart it... - if (origin === homescreen) { - removeFrame(origin); - - // XXX workaround bug 810431. - // we need this here and not in other situations - // as it is expected that homescreen frame is available. - setTimeout(function() { - setDisplayedApp(); - - if (callback) { - callback(); - } - }); - } else { - setDisplayedApp(homescreen, function() { - removeFrame(origin); - if (callback) - setTimeout(callback); - }); - } - - } else { - removeFrame(origin); - } - - // Send a synthentic 'appterminated' event. - // Let other system app module know an app is - // being killed, removed or crashed. - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent('appterminated', true, false, { origin: origin }); - window.dispatchEvent(evt); - } - - // Reload the frame of the running app - function reload(origin) { - if (!isRunning(origin)) - return; - - var app = runningApps[origin]; - app.reload(); - } - - // When a resize event occurs, resize the running app, if there is one - // When the status bar is active it doubles in height so we need a resize - var appResizeEvents = ['resize', 'status-active', 'status-inactive', - 'keyboardchange', 'keyboardhide', - 'attentionscreenhide']; - appResizeEvents.forEach(function eventIterator(event) { - window.addEventListener(event, function on(evt) { - if (event == 'keyboardchange') { - // Cancel fullscreen if keyboard pops - if (document.mozFullScreen) - document.mozCancelFullScreen(); - - setAppHeight(evt.detail.height); - } else if (displayedApp) { - setAppSize(displayedApp); - } - }); - }); - - window.addEventListener('home', function(e) { - // If the lockscreen is active, it will stop propagation on this event - // and we'll never see it here. Similarly, other overlays may use this - // event to hide themselves and may prevent the event from getting here. - // Note that for this to work, the lockscreen and other overlays must - // be included in index.html before this one, so they can register their - // event handlers before we do. - - // If we are currently transitioning, the user would like to cancel - // it instead of toggling homescreen panels. - var inTransition = !!(openFrame || closeFrame); - - if (document.mozFullScreen) { - document.mozCancelFullScreen(); - } - - if (displayedApp !== homescreen || inTransition) { - if (displayedApp != ftuURL) { - setDisplayedApp(homescreen); - } else { - e.preventDefault(); - } - } else { - stopInlineActivity(true); - ensureHomescreen(true); - } - }); - - // Cancel dragstart event to workaround - // https://bugzilla.mozilla.org/show_bug.cgi?id=783076 - // which stops OOP home screen pannable with left mouse button on - // B2G/Desktop. - windows.addEventListener('dragstart', function(evt) { - evt.preventDefault(); - }, true); - - // With all important event handlers in place, we can now notify - // Gecko that we're ready for certain system services to send us - // messages (e.g. the radio). - // Note that shell.js starts listen for the mozContentEvent event at - // mozbrowserloadstart, which sometimes does not happen till window.onload. - window.addEventListener('load', function wm_loaded() { - window.removeEventListener('load', wm_loaded); - - var evt = new CustomEvent('mozContentEvent', - { bubbles: true, cancelable: false, - detail: { type: 'system-message-listener-ready' } }); - window.dispatchEvent(evt); - }); - - // This is code copied from - // http://dl.dropbox.com/u/8727858/physical-events/index.html - // It appears to workaround the Nexus S bug where we're not - // getting orientation data. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=753245 - // It seems it needs to be in both window_manager.js and bootstrap.js. - function dumbListener2(event) {} - window.addEventListener('devicemotion', dumbListener2); - - window.setTimeout(function() { - window.removeEventListener('devicemotion', dumbListener2); - }, 2000); - - // Return the object that holds the public API - return { - isFtuRunning: function() { - return isRunningFirstRunApp; - }, - launch: launch, - kill: kill, - reload: reload, - getDisplayedApp: getDisplayedApp, - setOrientationForApp: setOrientationForApp, - getAppFrame: getAppFrame, - getRunningApps: function() { - return runningApps; - }, - setDisplayedApp: setDisplayedApp, - getCurrentDisplayedApp: function() { - return runningApps[displayedApp]; - }, - hideCurrentApp: hideCurrentApp, - restoreCurrentApp: restoreCurrentApp, - retrieveHomescreen: retrieveHomescreen, - retrieveFTU: retrieveFTU - }; -}()); - diff --git a/apps/system/js/wrapper.js b/apps/system/js/wrapper.js deleted file mode 100644 index 160d70b..0000000 --- a/apps/system/js/wrapper.js +++ /dev/null @@ -1,198 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -'use strict'; - -var Launcher = (function() { - function log(str) { - dump(' -+- Launcher -+-: ' + str + '\n'); - } - - function currentAppFrame() { - return WindowManager.getAppFrame(WindowManager.getDisplayedApp()); - } - - - function currentAppIframe() { - return currentAppFrame().firstChild; - } - - var _ = navigator.mozL10n.get; - - var BUTTONBAR_TIMEOUT = 5000; - var BUTTONBAR_INITIAL_OPEN_TIMEOUT = 1500; - - var footer = document.querySelector('#wrapper-footer'); - window.addEventListener('appopen', function onAppOpen(e) { - if ('wrapper' in currentAppFrame().dataset) { - window.addEventListener('mozbrowserlocationchange', onLocationChange); - onLocationChange(); - onDisplayedApplicationChange(); - } - }); - - window.addEventListener('appwillclose', function onAppClose(e) { - if ('wrapper' in currentAppFrame().dataset) { - window.removeEventListener('mozbrowserlocationchange', onLocationChange); - clearTimeout(buttonBarTimeout); - footer.classList.add('closed'); - isButtonBarDisplayed = false; - } - }); - - window.addEventListener('keyboardchange', function onKeyboardChange(e) { - if ('wrapper' in currentAppFrame().dataset) { - if (footer.classList.contains('visible')) { - footer.classList.remove('visible'); - } - } - }); - - window.addEventListener('keyboardhide', function onKeyboardChange(e) { - if ('wrapper' in currentAppFrame().dataset) { - if (!footer.classList.contains('visible')) { - footer.classList.add('visible'); - } - } - }); - - var buttonBarTimeout; - - var isButtonBarDisplayed = false; - function toggleButtonBar(time) { - clearTimeout(buttonBarTimeout); - footer.classList.toggle('closed'); - isButtonBarDisplayed = !isButtonBarDisplayed; - if (isButtonBarDisplayed) { - buttonBarTimeout = setTimeout(toggleButtonBar, time || BUTTONBAR_TIMEOUT); - } - } - - function clearButtonBarTimeout() { - clearTimeout(buttonBarTimeout); - buttonBarTimeout = setTimeout(toggleButtonBar, BUTTONBAR_TIMEOUT); - } - - document.getElementById('handler'). - addEventListener('mousedown', function open() { toggleButtonBar() }); - - document.getElementById('close-button'). - addEventListener('mousedown', function close() { toggleButtonBar() }); - - var reload = document.getElementById('reload-button'); - reload.addEventListener('click', function doReload(evt) { - clearButtonBarTimeout(); - currentAppIframe().reload(true); - }); - - var back = document.getElementById('back-button'); - back.addEventListener('click', function goBack() { - clearButtonBarTimeout(); - currentAppIframe().goBack(); - }); - - var forward = document.getElementById('forward-button'); - forward.addEventListener('click', function goForward() { - clearButtonBarTimeout(); - currentAppIframe().goForward(); - }); - - function onLocationChange() { - currentAppIframe().getCanGoForward().onsuccess = function forwardSuccess(e) { - if (e.target.result === true) { - delete forward.dataset.disabled; - } else { - forward.dataset.disabled = true; - } - } - - currentAppIframe().getCanGoBack().onsuccess = function backSuccess(e) { - if (e.target.result === true) { - delete back.dataset.disabled; - } else { - back.dataset.disabled = true; - } - } - } - - window.addEventListener('mozbrowserlocationchange', onLocationChange); - - var bookmarkButton = document.getElementById('bookmark-button'); - function onDisplayedApplicationChange() { - toggleButtonBar(BUTTONBAR_INITIAL_OPEN_TIMEOUT); - - var dataset = currentAppIframe().dataset; - if (dataset.originURL || dataset.searchURL) { - delete bookmarkButton.dataset.disabled; - return; - } - - bookmarkButton.dataset.disabled = true; - } - - bookmarkButton.addEventListener('click', function doBookmark(evt) { - if (bookmarkButton.dataset.disabled) - return; - - clearButtonBarTimeout(); - var dataset = currentAppIframe().dataset; - - function selected(value) { - if (!value) - return; - - var name, url; - if (value === 'origin') { - name = dataset.originName; - url = dataset.originURL; - } - - if (value === 'search') { - name = dataset.searchName; - url = dataset.searchURL; - } - - var activity = new MozActivity({ - name: 'save-bookmark', - data: { - type: 'url', - url: url, - name: name, - icon: dataset.icon, - useAsyncPanZoom: dataset.useAsyncPanZoom, - iconable: false - } - }); - - activity.onsuccess = function onsuccess() { - if (value === 'origin') { - delete currentAppIframe().dataset.originURL; - } - - if (value === 'search') { - delete currentAppIframe().dataset.searchURL; - } - - if (!currentAppIframe().dataset.originURL && - !currentAppIframe().dataset.searchURL) { - bookmarkButton.dataset.disabled = true; - } - } - } - - var data = { - title: _('add-to-home-screen'), - options: [] - }; - - if (dataset.originURL) { - data.options.push({ id: 'origin', text: dataset.originName }); - } - - if (dataset.searchURL) { - data.options.push({ id: 'search', text: dataset.searchName }); - } - - ModalDialog.selectOne(data, selected); - }); -}()); |