'use strict'; /* global Service */ (function(exports) { /** * Manage SecureWindow apps. This is a subset of the AppWindow manager, * and will not handle most cases the later one would handle. Only those * meaningful cases, like secure app open, close, requesting kill all apps * or turn the secure mode on/off, would be handled. However, if we need * to handle cases in the future, we would extend this manager. * * So far the SecureWindowManager would only manager 1 secure app at once, * but there're already some designations for multiple apps. * * @constructor SecureWindowManager */ var SecureWindowManager = function() { this.initElements(); this.initEvents(); Service.request('registerHierarchy', this); Service.registerState('isActive', this); }; SecureWindowManager.prototype = { name: 'SecureWindowManager', /** * @memberof SecureWindowManager# * @prop {DOMElement} windows - the `#windows` element, which is the same * element that the would AppWindowManager use. * @prop {DOMElement} screen - the `#screen` element. */ elements: { windows: null, screen: null }, /** * @memberof SecureWindowManager# * @prop {boolean} killMode - If this mode is on, all closing app would be * closed immediately, and with no animation. */ states: { activeApp: null, runningApps: {}, killMode: false // If this closing mode is instantly kill. }, /** * @memberof SecureWindowManager# */ configs: { killAnimation: 'immediate', listens: ['secure-killapps', 'secure-closeapps', 'secure-appcreated', 'secure-appopened', 'secure-appterminated', 'secure-apprequestclose', 'permissiondialoghide', 'sleepmenuhide', ] } }; SecureWindowManager.prototype.HIERARCHY_MANAGER = 'SecureWindowManager'; SecureWindowManager.prototype.setHierarchy = function(active) { if (this.states.activeApp) { this.states.activeApp.setVisibleForScreenReader(active); } }; SecureWindowManager.prototype.setFocus = function(active) { if (!this.states.activeApp) { return false; } if (active) { this.states.activeApp.focus(); } return true; }; SecureWindowManager.prototype.getActiveWindow = function() { return this.isActive() ? this.states.activeApp : null; }; SecureWindowManager.prototype._handle_home = function() { if (0 !== Object.keys(this.states.runningApps).length) { this.elements.screen.classList.remove('secure-app'); this.softKillApps(); } return true; }; SecureWindowManager.prototype.respondToHierarchyEvent = function(evt) { if (this['_handle_' + evt.type]) { return this['_handle_' + evt.type](evt); } else { return true; } }; /** * @listens secure-killapps - means to kill remain apps, and make it ready to * turn the secure mode off. * @listens secure-closeapps - means to close remain apps. It's similar to * the event above, but would show the closing * animation. * @listens secure-appcreated - when a secure app got created, it would fire * this event. * @listens secure-appterminated - when a secure app got really closed, it * would fire this event. * @listens secure-apprequestclose - when a secure app has been called to * close itself, the event would be fired * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.handleEvent = function swm_handleEvent(evt) { var app = null; switch (evt.type) { case 'secure-killapps': if (0 !== Object.keys(this.states.runningApps).length) { this.states.killMode = true; this.killApps(); } break; case 'secure-closeapps': if (0 !== Object.keys(this.states.runningApps).length) { this.softKillApps(); } break; case 'secure-appcreated': app = evt.detail; if (this.allowed(app.config)) { this.registerApp(app); this.activateApp(app); } else { console.error('Disallowed app: ', app.instanceID); } break; case 'secure-appopened': this.elements.screen.classList.add('secure-app'); this.setFocus(true); break; case 'secure-appterminated': app = evt.detail; this.unregisterApp(app); this.deactivateApp(); // If this is the last app in the list. if (0 === Object.keys(this.states.runningApps).length) { this.states.killMode = false; } break; case 'secure-apprequestclose': // Mimic the AppWindowManager, // because the SecureWindow app would send it, too. app = evt.detail; // Default animation or kill animation. app.close(this.states.killMode ? this.configs.killAnimation : null); this.elements.screen.classList.remove('secure-app'); break; case 'sleepmenuhide': case 'permissiondialoghide': this.setFocus(true); // See bug 1224281 break; } }; /** * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.initElements = function swm_initElements() { var selectors = { windows: 'windows', screen: 'screen'}; for (var name in selectors) { var id = selectors[name]; this.elements[name] = document.getElementById(id); } }; /** * Hook listeners of events this manager interested in. * * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.initEvents = function swm_initEvents() { this.configs.listens.forEach((function _initEvent(type) { self.addEventListener(type, this); }).bind(this)); }; /** * Close/Kill all manager secure apps, which has been registered * while they're created and opened. * * If the `configs.killMode` is on (by event `secure-killapps`), * the closing would be instantly. Otherwise, app will close with * default animation. * * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.killApps = function swm_killApps() { for (var origin in this.states.runningApps) { this.states.runningApps[origin].kill(); } }; /** * Soft kill all running secure apps. This allows the secure apps * enough time to gracefully shutdown before being killed. * * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.softKillApps = function swm_softKillApps() { for (var origin in this.states.runningApps) { this.states.runningApps[origin].softKill(); } }; /** * Message passing method. Would publish to the whole System app. * * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.publish = function swm_publish(ne, source) { if ('string' === typeof ne) { ne = new CustomEvent(ne); } if (!source) { source = window; } source.dispatchEvent(ne); }; /** * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.registerApp = function swm_registerApp(app) { this.states.runningApps[app.instanceID] = app; }; /** * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.unregisterApp = function swm_unregisterApp(app) { delete this.states.runningApps[app.instanceID]; }; /** * Set an app as the active app. * * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.activateApp = function swm_activateApp(app) { this.states.activeApp = app; if (app.isFullScreen()) { this.elements.screen.classList.add('fullscreen-app'); } else { this.elements.screen.classList.remove('fullscreen-app'); } }; /** * Deactivate the current active app. * * @private * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.deactivateApp = function swm_deactivateApp() { if (this.states.activeApp && this.states.activeApp.isFullScreen()) { this.elements.screen.classList.remove('fullscreen-app'); } this.states.activeApp = null; }; /** * See if the app is a secure app and can be managed by the manager. * * @param {AppConfig} - the configuration of the app. * @return {boolean} - if this app's config represent it's a secure app * and can be managed by the manager. * @this {SecureWindowManager} * @memberof SecureWindowManager */ SecureWindowManager.prototype.allowed = function swm_allowed(config) { if ('certified' !== config.manifest.type) { return false; } return true; }; SecureWindowManager.prototype.isActive = function swm_isActive() { if (!this.states.activeApp) { return false; } else { return this.states.activeApp.isActive(); } }; /** @exports SecureWindowManager */ exports.SecureWindowManager = SecureWindowManager; })(window);