Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
476 lines
15 KiB
JavaScript
Executable file
476 lines
15 KiB
JavaScript
Executable file
'use strict';
|
|
/* global Service, LockScreenWindow, LockScreenInputWindow */
|
|
/* global LazyLoader */
|
|
|
|
(function(exports) {
|
|
/**
|
|
* Manage LockScreenWindow 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 LockScreenWindowManager would only manager 1 secure app at once,
|
|
* but there're already some designations for multiple apps.
|
|
*
|
|
* @constructor LockScreenWindowManager
|
|
*/
|
|
var LockScreenWindowManager = function() {};
|
|
|
|
LockScreenWindowManager.prototype.setup =
|
|
function lswm_setup() {
|
|
/**
|
|
* @memberof LockScreenWindowManager#
|
|
* @prop {DOMElement} windows - the `#windows` element, which is the same
|
|
* element that the would AppWindowManager use.
|
|
* @prop {DOMElement} screen - the `#screen` element.
|
|
*/
|
|
this.elements = {
|
|
windows: null,
|
|
screen: null
|
|
};
|
|
|
|
/**
|
|
* @memberof LockScreenWindowManager#
|
|
*/
|
|
this.states = {
|
|
ready: false,
|
|
FTUOccurs: false,
|
|
enabled: true,
|
|
instance: null,
|
|
windowCreating: false
|
|
};
|
|
|
|
/**
|
|
* @memberof LockScreenWindowManager#
|
|
*/
|
|
this.configs = {
|
|
inputWindow: {
|
|
// Before we put things inside an iframe, do not resize LW.
|
|
resizeMode: false,
|
|
get height() {
|
|
return 300;
|
|
}
|
|
},
|
|
listens: ['lockscreen-request-unlock',
|
|
'lockscreen-appcreated',
|
|
'lockscreen-appterminated',
|
|
'lockscreen-appclose',
|
|
'screenchange',
|
|
'system-resize',
|
|
'ftuopen',
|
|
'ftudone',
|
|
'overlaystart',
|
|
'showlockscreenwindow',
|
|
'secure-appclosed',
|
|
'lockscreen-request-inputpad-open',
|
|
'lockscreen-request-inputpad-close'
|
|
]
|
|
};
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.name = 'LockScreenWindowManager';
|
|
LockScreenWindowManager.prototype.EVENT_PREFIX = 'lockscreenwindowmanager';
|
|
/**
|
|
* This function will be invoked by hierarchyManager.
|
|
*/
|
|
LockScreenWindowManager.prototype.getActiveWindow = function() {
|
|
return this.isActive() ? this.states.instance : null;
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.locked = function() {
|
|
return this.isActive();
|
|
};
|
|
|
|
/**
|
|
* To initialize the class instance (register events, observe settings, etc.)
|
|
*/
|
|
LockScreenWindowManager.prototype.start =
|
|
function lwm_start() {
|
|
this.setup();
|
|
this.startEventListeners();
|
|
this.startObserveSettings();
|
|
this.initElements();
|
|
Service.register('unlock', this);
|
|
Service.register('lock', this);
|
|
Service.request('registerHierarchy', this);
|
|
Service.registerState('locked', this);
|
|
};
|
|
|
|
LockScreenWindowManager.prototype._handle_home = function() {
|
|
if (this.isActive()) {
|
|
// XXX: I don't want to change the order of event registration
|
|
// at this early-refactoring stage, so do this to minimize the
|
|
// risk and complete the work.
|
|
window.dispatchEvent(
|
|
new CustomEvent('lockscreen-notify-homepressed'));
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
LockScreenWindowManager.prototype._handle_holdhome = function() {
|
|
if (this.isActive()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.respondToHierarchyEvent = function(evt) {
|
|
if (this['_handle_' + evt.type]) {
|
|
return this['_handle_' + evt.type](evt);
|
|
} else {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @listens lockscreen-appcreated - when a lockscreen app got created, it
|
|
* would fire this event.
|
|
* @listens lockscreen-appterminated - when a lockscreen app got really
|
|
* closed, it would fire this event.
|
|
* @listens lockscreen-apprequestclose - when a lockscreen app has been
|
|
* called to close itself, the event
|
|
* would be fired
|
|
* @listens screenchange - means to initialize the lockscreen and its window
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.handleEvent =
|
|
function lwm_handleEvent(evt) {
|
|
var app = null;
|
|
switch (evt.type) {
|
|
case 'overlaystart':
|
|
if (this.isActive()) {
|
|
this.states.instance.setVisible(false);
|
|
}
|
|
break;
|
|
case 'showlockscreenwindow':
|
|
if (this.isActive()) {
|
|
this.states.instance.setVisible(true);
|
|
}
|
|
break;
|
|
case 'ftuopen':
|
|
this.states.FTUOccurs = true;
|
|
// Need immediatly unlocking (hide window).
|
|
this.closeApp(true);
|
|
break;
|
|
case 'ftudone':
|
|
this.states.FTUOccurs = false;
|
|
break;
|
|
case 'lockscreen-request-unlock':
|
|
this.responseUnlock(evt.detail);
|
|
break;
|
|
case 'lockscreen-appcreated':
|
|
app = evt.detail;
|
|
this.registerApp(app);
|
|
break;
|
|
case 'lockscreen-appterminated':
|
|
app = evt.detail;
|
|
this.unregisterApp(app);
|
|
break;
|
|
case 'secure-appclosed':
|
|
this.states.instance.lockOrientation();
|
|
break;
|
|
case 'system-resize':
|
|
if (this.states.instance && this.states.instance.isActive()) {
|
|
var p = this.states.instance.resize();
|
|
if (typeof evt.detail.waitUntil === 'function') {
|
|
evt.detail.waitUntil(p);
|
|
}
|
|
}
|
|
break;
|
|
case 'screenchange':
|
|
// The screenchange may be invoked by proximity sensor,
|
|
// or the power button. If it's caused by the proximity sensor,
|
|
// we should not open the LockScreen, because the user may stay
|
|
// in another app, not the LockScreen.
|
|
if ('proximity' !== evt.detail.screenOffBy &&
|
|
!this.states.FTUOccurs &&
|
|
this.states.ready) {
|
|
// The app would be inactive while screen off.
|
|
this.states.enabled && this.openApp();
|
|
if (evt.detail.screenEnabled && this.states.instance &&
|
|
this.isActive() &&
|
|
!Service.query('SecureWindowManager.isActive')) {
|
|
// In theory listen to 'visibilitychange' event can solve this
|
|
// issue, since it would be fired at the correct moment that
|
|
// we can lock the orientation successfully, but this event
|
|
// would not be received when user press the button twice
|
|
// quickly, so we need to keep this workaround.
|
|
this.states.instance.lockOrientation();
|
|
}
|
|
}
|
|
break;
|
|
case 'lockscreen-request-inputpad-open':
|
|
this.onInputpadOpen();
|
|
break;
|
|
case 'lockscreen-request-inputpad-close':
|
|
this.onInputpadClose();
|
|
break;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.initElements =
|
|
function lwm_initElements() {
|
|
var selectors = { windows: 'windows', screen: 'screen'};
|
|
for (var name in selectors) {
|
|
var id = selectors[name];
|
|
this.elements[name] = document.getElementById(id);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Hook observers of settings to allow or ban window opening.
|
|
*
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.startObserveSettings =
|
|
function lwm_startObserveSettings() {
|
|
var enabledListener = this.handleEnable.bind(this);
|
|
|
|
// FIXME(ggp) this is currently used by Find My Device to force locking.
|
|
// Should be replaced by a proper IAC API in bug 992277.
|
|
var lockListener = (event) => {
|
|
if (true === event.settingValue) {
|
|
this.openApp();
|
|
}
|
|
};
|
|
|
|
window.SettingsListener.observe('lockscreen.enabled',
|
|
true, enabledListener);
|
|
|
|
// We are only interested in changes to the setting, rather
|
|
// than its value, so just observe it instead of using SettingsListener
|
|
navigator.mozSettings.addObserver('lockscreen.lock-immediately',
|
|
lockListener);
|
|
};
|
|
|
|
/**
|
|
* Hook listeners of events this manager interested in.
|
|
*
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.startEventListeners =
|
|
function lwm_startEventListeners() {
|
|
this.configs.listens.forEach((function _initEvent(type) {
|
|
self.addEventListener(type, this);
|
|
}).bind(this));
|
|
};
|
|
|
|
/**
|
|
* Remove listeners of events this manager interested in.
|
|
*
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.stopEventListeners =
|
|
function lwm_stopEventListeners() {
|
|
this.configs.listens.forEach((function _unbind(ename) {
|
|
self.removeEventListener(ename, this);
|
|
}).bind(this));
|
|
};
|
|
|
|
/**
|
|
* Close the lockscreen app.
|
|
* If it's not enabled, would do nothing.
|
|
*
|
|
* @param {boolean} instant - true if instantly close.
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.closeApp =
|
|
function lwm_closeApp(instant) {
|
|
if (!this.states.enabled || !this.isActive()) {
|
|
return;
|
|
}
|
|
this.states.instance.close(instant ? 'immediate': undefined);
|
|
this.elements.screen.classList.remove('locked');
|
|
this.toggleLockedSetting(false);
|
|
this.publish(this.EVENT_PREFIX + '-deactivated', this);
|
|
};
|
|
|
|
/**
|
|
* Open the lockscreen app.
|
|
* If it's necessary, would create a new window.
|
|
* If it's not enabled, would do nothing.
|
|
*
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.openApp =
|
|
function lwm_openApp() {
|
|
if (!this.states.instance) {
|
|
var app = this.createWindow();
|
|
app && app.open();
|
|
} else {
|
|
this.states.instance.open();
|
|
}
|
|
this.elements.screen.classList.add('locked');
|
|
this.toggleLockedSetting(true);
|
|
this.publish(this.EVENT_PREFIX + '-activated', this);
|
|
};
|
|
|
|
/**
|
|
* Message passing method. Would publish to the whole System app.
|
|
*
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.publish =
|
|
function lwm_publish(ne, detail) {
|
|
var event = new CustomEvent(ne, { detail: detail });
|
|
window.dispatchEvent(event);
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.registerApp =
|
|
function lwm_registerApp(app) {
|
|
this.states.instance = app;
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.unregisterApp =
|
|
function lwm_unregisterApp(app) {
|
|
this.states.instance = null;
|
|
};
|
|
|
|
/**
|
|
* When screenchange hanneped, create LockScreen and LockScreenWindow
|
|
* if it is needed.
|
|
*
|
|
* @private
|
|
* @return {LockScreenWindow}
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.createWindow =
|
|
function lwm_createWindow() {
|
|
if (this.states.windowCreating) {
|
|
return false;
|
|
}
|
|
this.states.windowCreating = true;
|
|
var app = new LockScreenWindow();
|
|
// XXX: Before we can use real InputWindow and InputWindowManager,
|
|
// we need this to
|
|
LazyLoader.load(['js/lockscreen_input_window.js']).then(() => {
|
|
app.inputWindow = new LockScreenInputWindow();
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
});
|
|
this.states.windowCreating = false;
|
|
return app;
|
|
};
|
|
|
|
/**
|
|
* First time we launch, we must check the init value of enabled,
|
|
* to see if we need to open the window.
|
|
*
|
|
* @private
|
|
* @this {LockScreenWindowManager}
|
|
* @memberof LockScreenWindowManager
|
|
*/
|
|
LockScreenWindowManager.prototype.handleEnable =
|
|
function(enabled) {
|
|
this.states.ready = true;
|
|
if (typeof(enabled) === String) {
|
|
enabled = (enabled === 'true');
|
|
}
|
|
this.states.enabled = enabled;
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.unlock =
|
|
function lwm_unlock(detail) {
|
|
// XXX:
|
|
// There is a self-routing here:
|
|
// Service.request('unlock') ->
|
|
// LockscreenWindowManager#unlock ->
|
|
// ['lockscreen-request-unlock'] ->
|
|
// LockscreenWindowManager#responseUnlock |
|
|
// VisibilityManager#firing showwindow
|
|
//
|
|
// We should just call responseUnlock here,
|
|
// but VisibilityManager needs this event to notify
|
|
// AppWindowManager to showwindow correctly;
|
|
// The reason not using lockscreen-appclosing/lockscreen-appclosed
|
|
// is the race of mozActivity launch coming from lockscreen
|
|
// and homescreen will race to be opened and cause performance issue.
|
|
//
|
|
// We should adjust LockScreenWindow to use lockscreen-appclosing/closed
|
|
// to have the activitiy/notification info hence we could change
|
|
// VisibilityManager later to avoid this workaround.
|
|
this.publish('lockscreen-request-unlock', detail);
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.responseUnlock =
|
|
function lwm_responseUnlock(detail) {
|
|
var forcibly = (detail && detail.forcibly) ? true : false;
|
|
this.closeApp(forcibly);
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.lock =
|
|
function lwm_lock(detail) {
|
|
this.openApp();
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.getInstance =
|
|
function lwm_getInstance() {
|
|
return this.states.instance;
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.isActive =
|
|
function lwm_isActive() {
|
|
if (null === this.states.instance) {
|
|
return false;
|
|
} else {
|
|
return this.states.instance.isActive();
|
|
}
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.onInputpadOpen =
|
|
function lwm_onInputpadOpen() {
|
|
this.states.instance.inputWindow.open();
|
|
this.states.instance.inputWindow.setVisible(true);
|
|
this.states.instance.resize();
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.onInputpadClose =
|
|
function lwm_onInputpadClose() {
|
|
this.states.instance.inputWindow.close();
|
|
this.states.instance.resize();
|
|
};
|
|
|
|
LockScreenWindowManager.prototype.toggleLockedSetting =
|
|
function lswm_toggleLockedSetting(value) {
|
|
if (!window.navigator.mozSettings) {
|
|
return;
|
|
}
|
|
window.SettingsListener.getSettingsLock().set({
|
|
'lockscreen.locked': value
|
|
});
|
|
};
|
|
|
|
/** @exports LockScreenWindowManager */
|
|
exports.LockScreenWindowManager = LockScreenWindowManager;
|
|
})(window);
|