/* globals LockScreenAgent, LazyLoader */ /* global Service */ 'use strict'; (function(exports) { var AppWindow = window.AppWindow; /** * This window is inherit the AppWindow, and modifies some properties * different from the later. * * @constructor LockScreenWindow * @augments AppWindow */ var LockScreenWindow = function() { // Before we make lockscreen as an app (Bug 898348 ), which would // own its own manifest, we must mock a manifest for him. this.configs = { url: window.location.href, manifest: { orientation: ['default'] }, name: 'Lockscreen', // No manifestURL + no chrome would cause a default chrome app manifestURL: window.location.href.replace('system', 'lockscreen') + '/manifest.webapp', origin: window.location.origin.replace('system', 'lockscreen'), inputWindow: { resizeMode: false } }; this.iframe = this.createFrame(); if (!this.iframe || !this.iframe.parentNode) { // XXX: Lockscreen DOM elements are not copied. return; } LazyLoader.load(['js/lockscreen_agent.js']).then(() => { this.lockScreenAgent = new LockScreenAgent(this.iframe); this.lockScreenAgent.start(); }).catch((err) => { console.error(err); }); AppWindow.call(this, this.configs); window.dispatchEvent(new CustomEvent('lockscreen-frame-bootstrap', { detail: this })); }; /** * @borrows AppWindow.prototype as LockScreenWindow.prototype * @memberof LockScreenWindow */ LockScreenWindow.prototype = Object.create(AppWindow.prototype); LockScreenWindow.prototype.constructor = LockScreenWindow; LockScreenWindow.prototype.isLockscreen = true; LockScreenWindow.SUB_COMPONENTS = { 'transitionController': 'AppTransitionController', 'statusbar': 'AppStatusbar' }; LockScreenWindow.REGISTERED_EVENTS = AppWindow.REGISTERED_EVENTS; /** * We still need this before we put the lockreen inside an iframe. * * @type LockScreen * @memberof LockScreenWindow */ LockScreenWindow.prototype.lockscreen = null; LockScreenWindow.prototype.HIERARCHY_MANAGER = 'LockScreenWindowManager'; /** * We would maintain our own events by other components. * * @type string * @memberof LockScreenWindow */ LockScreenWindow.prototype.eventPrefix = 'lockscreen-app'; /** * Different animation from the original window. * * @type string * @memberof LockScreenWindow */ LockScreenWindow.prototype.openAnimation = 'immediate'; /** * Different animation from the original window. * * @type string * @memberof LockScreenWindow */ LockScreenWindow.prototype.closeAnimation = 'fade-out'; LockScreenWindow.prototype._DEBUG = false; /** * LockScreenWindow has its own styles. * * @type string * @memberof LockScreenWindow */ LockScreenWindow.prototype.CLASS_LIST = 'appWindow lockScreenWindow'; LockScreenWindow.prototype.CLASS_NAME = 'LockScreenWindow'; LockScreenWindow.prototype._resize = function aw__resize() { var height, width; // We want the lockscreen to go below the Statusbar height = Service.query('LayoutManager.height') || window.innerHeight; width = Service.query('LayoutManager.width') || window.innerWidth; this.width = width; this.height = height; this.element.style.width = this.width + 'px'; this.element.style.height = this.height + 'px'; this.resized = true; /** * Fired when the app is resized. * * @event LockScreenWindow#lockscreen-appresize */ this.publish('resize'); }; /** * Create the iframe and load it. * * @this {LockScreenWindow} * @memberof LockScreenWindow */ LockScreenWindow.prototype.createFrame = function lsw_createFrame() { // XXX: Before we can make LockScreen as a real app, // we need these. var frame = document.getElementById('lockscreen-frame'); if (!frame) { // XXX: This means we failed to build the system app. // So from now on we will try to go without lockscreen. frame = document.createElement('div'); } frame.setVisible = function() {}; // XXX: real mozbrowser iframes would own these methods. frame.addNextPaintListener = function(cb) { cb(); }; frame.removeNextPaintListener = function() {}; frame.getScreenshot = function() { // Mock the request. return { get onsuccess() {return null;}, set onsuccess(cb) { var mockEvent = { target: {result: null} }; cb(mockEvent); } }; }; frame.removeAttribute('hidden'); return frame; }; LockScreenWindow.prototype.getNotificationContainer = function lsw_getNotificationContainer() { // XXX: After we make LockScreen as an app, needn't this anymore. return document.getElementById( 'notifications-lockscreen-container'); }; LockScreenWindow.prototype._resize = function lsw__resize() { var height, width; this.debug('force RESIZE...'); if (this.inputWindow && typeof this.inputWindow.isActive === 'function' && this.inputWindow.isActive()) { /** * The event is dispatched on the app window only when keyboard is up. * * @access private * @event LockScreenWindow~_withkeyboard */ this.broadcast('withkeyboard'); } else { /** * The event is dispatched on the LockScreen window only * when keyboard is hidden. * * @access private * @event LockScreenWindow~_withoutkeyboard */ this.broadcast('withoutkeyboard'); } height = this.layoutHeight(); width = this.layoutWidth(); this.width = width; this.height = height; this.element.style.width = this.width + 'px'; this.element.style.height = this.height + 'px'; this.browser.element.style.width = ''; this.browser.element.style.height = ''; this.resized = true; if (this.screenshotOverlay) { this.screenshotOverlay.style.visibility = ''; } /** * Fired when the app is resized. * * @event LockScreenWindow#lockscreen-appresize */ this.publish('resize'); this.debug('W:', this.width, 'H:', this.height); }; // XXX Bug 1085226: Before we make LockScreen use real keyboard, we need this. LockScreenWindow.prototype.layoutHeight = function lwm_layoutHeight() { // Whether we can resize or not (depends on if the content // is inside an iframe or not). if (!this.configs.inputWindow.resizeMode) { return window.innerHeight; } var softwareButtonHeight = this.isActive() ? 0 : (Service.query('SoftwareButtonManager.height') || 0); var inputWindowHeight = 0; if (this.states.instance && this.states.instance.inputWindow && typeof this.states.instance.inputWindow.isActive === 'function' && this.states.instance.inputWindow.isActive()) { inputWindowHeight = this.configs.inputWindow.height; } var height = window.innerHeight - inputWindowHeight - softwareButtonHeight; // Normalizing the height so that it always translates to an integral // number of device pixels var dpx = window.devicePixelRatio; if ((height * dpx) % 1 !== 0) { height = Math.ceil(height * dpx) / dpx; } return height; }; LockScreenWindow.prototype.layoutWidth = function() { return window.innerWidth; }; LockScreenWindow.prototype.lockOrientation = function() { // XXX: When we turn the screen on, try to lock the orientation // until it works. It may fail at the moment the screenchange // event has been fired, so we may need to try it several times. var tryLockOrientation = () => { if (screen.mozLockOrientation('portrait-primary')) { if (!this.orientationLockID) { throw new Error('No orientation ID. This function should only' + 'be invoked as a interval callback'); } window.clearInterval(this.orientationLockID); this.orientationLockID = null; } }; if (Service.query('isOnRealDevice')) { if (this.orientationLockID) { // The previous one still present and was not cleared, // so do nothing. return; } this.orientationLockID = window.setInterval(tryLockOrientation, 4); // 4ms is the minimum interval according to W3C#setTimeout standard. } }; exports.LockScreenWindow = LockScreenWindow; })(window);