Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
349 lines
11 KiB
JavaScript
Executable file
349 lines
11 KiB
JavaScript
Executable file
/**
|
|
Copyright 2012, Mozilla Foundation
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
/*global Service, UtilityTray, LazyLoader */
|
|
|
|
'use strict';
|
|
|
|
(function(exports) {
|
|
const AVG_ICON_SIZE = 22;
|
|
|
|
var Statusbar = {
|
|
name: 'Statusbar',
|
|
|
|
// The indices indicate icons priority (lower index = highest priority)
|
|
PRIORITIES: [
|
|
'time',
|
|
'emergency-callback',
|
|
'battery',
|
|
'recording',
|
|
'airplane-mode',
|
|
'wifi',
|
|
'mobile-connection',
|
|
'debugging',
|
|
'download',
|
|
'geolocation',
|
|
'network-activity',
|
|
'tethering',
|
|
'bluetooth-transfer',
|
|
'bluetooth',
|
|
'nfc',
|
|
'usb',
|
|
'alarm',
|
|
'bluetooth-headphone',
|
|
'mute',
|
|
'call-forwardings',
|
|
'playing',
|
|
'headphone',
|
|
'operator'
|
|
],
|
|
|
|
/* Whether or not status bar is actively updating or not */
|
|
active: true,
|
|
|
|
_numMinimizedIcons: 9,
|
|
_currentIcons: {},
|
|
get _iconsCount() {
|
|
return Object.keys(this._currentIcons).length;
|
|
},
|
|
|
|
/* For other modules to acquire */
|
|
get height() {
|
|
if (document.mozFullScreen ||
|
|
(Service.query('getTopMostWindow') &&
|
|
Service.query('getTopMostWindow').isFullScreen())) {
|
|
return 0;
|
|
} else {
|
|
return this._cacheHeight ||
|
|
(this._cacheHeight =
|
|
this.element.getBoundingClientRect().height);
|
|
}
|
|
},
|
|
|
|
start: function() {
|
|
this.getAllElements();
|
|
|
|
// cache height.
|
|
this._cacheHeight = this.element.getBoundingClientRect().height;
|
|
|
|
window.addEventListener('apptitlestatechanged', this);
|
|
window.addEventListener('activitytitlestatechanged', this);
|
|
window.addEventListener('homescreentitlestatechanged', this);
|
|
window.addEventListener('appchromecollapsed', this);
|
|
window.addEventListener('appchromeexpanded', this);
|
|
window.addEventListener('iconshown', this);
|
|
window.addEventListener('iconhidden', this);
|
|
window.addEventListener('iconrendered', this);
|
|
|
|
if (Service.query('FtuLauncher.isFinished')) {
|
|
this.finishInit();
|
|
} else {
|
|
window.addEventListener('ftuskip', this);
|
|
window.addEventListener('ftudone', this);
|
|
}
|
|
Service.registerState('height', this);
|
|
Service.register('iconContainer', this);
|
|
},
|
|
|
|
calculateMinimized: function sb_calculateMinimized() {
|
|
var minimizedWidth = this.element.clientWidth / 2;
|
|
var count = minimizedWidth / AVG_ICON_SIZE;
|
|
this._numMinimizedIcons = Math.floor(count);
|
|
},
|
|
|
|
iconContainer: function sb_iconContainer(icon) {
|
|
if (icon.dashPureName === 'operator') {
|
|
return this.statusbarTray;
|
|
}
|
|
return this.statusbarIcons;
|
|
},
|
|
|
|
/**
|
|
* Finish all initializing statusbar event handlers
|
|
*/
|
|
finishInit: function() {
|
|
window.addEventListener(
|
|
'appstatusbar-fullscreen-statusbar-set-appearance', this);
|
|
window.addEventListener('appstatusbar-fullscreen-statusbar-show', this);
|
|
window.addEventListener('appstatusbar-fullscreen-statusbar-hide', this);
|
|
window.addEventListener('sheets-gesture-begin', this);
|
|
window.addEventListener('sheets-gesture-end', this);
|
|
window.addEventListener('utilitytraywillshow', this);
|
|
window.addEventListener('utilitytraywillhide', this);
|
|
window.addEventListener('utility-tray-overlayopened', this);
|
|
window.addEventListener('utility-tray-overlayclosed', this);
|
|
window.addEventListener('utility-tray-abortopen', this);
|
|
window.addEventListener('utility-tray-abortclose', this);
|
|
window.addEventListener('cardviewshown', this);
|
|
window.addEventListener('cardviewclosed', this);
|
|
|
|
window.addEventListener('attentionopened', this);
|
|
window.addEventListener('appwillopen', this);
|
|
window.addEventListener('appwillclose', this);
|
|
window.addEventListener('appopened', this);
|
|
window.addEventListener('appclosed', this);
|
|
window.addEventListener('hierarchytopmostwindowchanged', this);
|
|
window.addEventListener('activityopened', this);
|
|
window.addEventListener('homescreenopened', this);
|
|
window.addEventListener('stackchanged', this);
|
|
window.addEventListener('lockscreen-request-unlock', this);
|
|
|
|
// Listen to updates dialog
|
|
window.addEventListener('updatepromptshown', this);
|
|
window.addEventListener('updateprompthidden', this);
|
|
|
|
// We need to preventDefault on mouse events until
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1005815 lands
|
|
var events = ['touchstart', 'touchmove', 'touchend',
|
|
'mousedown', 'mousemove', 'mouseup'];
|
|
events.forEach(function bindEvents(name) {
|
|
this.topPanel.addEventListener(name, this.panelHandler.bind(this));
|
|
}, this);
|
|
|
|
LazyLoader.load([
|
|
'js/utility_tray_motion.js',
|
|
'js/utility_tray.js'
|
|
]).then(function() {
|
|
this.utilityTray = UtilityTray;
|
|
UtilityTray.init();
|
|
}.bind(this)).catch((err) => {
|
|
console.error('UtilityTray load or init error', err);
|
|
});
|
|
|
|
this.calculateMinimized();
|
|
},
|
|
|
|
handleEvent: function sb_handleEvent(evt) {
|
|
var icon;
|
|
switch (evt.type) {
|
|
case 'iconshown':
|
|
this._currentIcons[evt.detail.dashPureName] = true;
|
|
this.toggleMaximized();
|
|
break;
|
|
case 'iconhidden':
|
|
delete this._currentIcons[evt.detail.dashPureName];
|
|
break;
|
|
case 'ftudone':
|
|
case 'ftuskip':
|
|
this.finishInit();
|
|
break;
|
|
case 'iconrendered':
|
|
icon = evt.detail;
|
|
var order = this.PRIORITIES.indexOf(icon.dashPureName);
|
|
icon.setOrder(order);
|
|
break;
|
|
|
|
case 'attentionopened':
|
|
this.element.classList.add('maximized');
|
|
this.element.classList.remove('light');
|
|
break;
|
|
|
|
case 'sheets-gesture-begin':
|
|
case 'appwillopen':
|
|
case 'appwillclose':
|
|
case 'cardviewshown':
|
|
this.element.classList.add('hidden');
|
|
break;
|
|
|
|
case 'sheets-gesture-end':
|
|
case 'stackchanged':
|
|
case 'cardviewclosed':
|
|
this.element.classList.remove('hidden');
|
|
break;
|
|
|
|
case 'appstatusbar-fullscreen-statusbar-show':
|
|
this.topPanel.style.pointerEvents = 'none';
|
|
break;
|
|
case 'appstatusbar-fullscreen-statusbar-hide':
|
|
this.topPanel.style.pointerEvents = '';
|
|
break;
|
|
|
|
case 'utilitytraywillshow':
|
|
case 'utilitytraywillhide':
|
|
case 'appstatusbar-fullscreen-statusbar-set-appearance':
|
|
case 'utility-tray-overlayopened':
|
|
case 'utility-tray-overlayclosed':
|
|
case 'utility-tray-abortopen':
|
|
case 'utility-tray-abortclose':
|
|
case 'appchromecollapsed':
|
|
case 'updateprompthidden':
|
|
this.setAppearance();
|
|
break;
|
|
|
|
case 'appopened':
|
|
var app = evt.detail;
|
|
if (!app.isFullScreen() && !app.isFullScreenLayout()) {
|
|
this.element.setAttribute('aria-owns',
|
|
evt.detail.appChrome.element.id);
|
|
} else {
|
|
this.element.removeAttribute('aria-owns');
|
|
}
|
|
/* falls through */
|
|
case 'appclosed':
|
|
case 'hierarchytopmostwindowchanged':
|
|
case 'lockscreen-request-unlock':
|
|
case 'appchromeexpanded':
|
|
this.element.classList.remove('hidden');
|
|
this.setAppearance();
|
|
break;
|
|
|
|
case 'activityopened':
|
|
case 'apptitlestatechanged':
|
|
case 'activitytitlestatechanged':
|
|
case 'homescreentitlestatechanged':
|
|
this.setAppearance();
|
|
this.element.classList.remove('hidden');
|
|
break;
|
|
case 'homescreenopened':
|
|
// In some cases, if the user has been switching apps so fast and
|
|
// quickly he press the home button, we might miss the
|
|
// |sheets-gesture-end| event so we must resume the statusbar
|
|
// if needed
|
|
this.setAppearance();
|
|
this.element.classList.remove('hidden');
|
|
this.element.classList.remove('fullscreen');
|
|
this.element.classList.remove('fullscreen-layout');
|
|
this.element.removeAttribute('aria-owns');
|
|
break;
|
|
case 'updatepromptshown':
|
|
this.element.classList.remove('light');
|
|
break;
|
|
}
|
|
},
|
|
|
|
setAppearance: function() {
|
|
var app = Service.query('getTopMostWindow');
|
|
if (!app) {
|
|
return;
|
|
}
|
|
|
|
var isFullScreen = app.isFullScreen() || document.mozFullScreen;
|
|
|
|
this.element.classList.toggle('light',
|
|
!!(app.appChrome && app.appChrome.useLightTheming()) && !isFullScreen
|
|
);
|
|
|
|
this.element.classList.toggle('fullscreen', isFullScreen);
|
|
|
|
this.element.classList.toggle('fullscreen-layout',
|
|
app.isFullScreenLayout()
|
|
);
|
|
|
|
this.toggleMaximized();
|
|
},
|
|
|
|
toggleMaximized: function() {
|
|
var app = Service.query('getTopMostWindow');
|
|
|
|
if (!app) {
|
|
return;
|
|
}
|
|
|
|
var appsWithoutRocketbar = [
|
|
'isHomescreen',
|
|
'isAttentionWindow',
|
|
'isLockscreen'
|
|
];
|
|
|
|
var noRocketbar = appsWithoutRocketbar.some(function(name) {
|
|
return !!(app[name]);
|
|
});
|
|
var chromeMaximized = !!(app.appChrome && app.appChrome.isMaximized());
|
|
var trayActive = !!(this.utilityTray && this.utilityTray.shown);
|
|
var shouldMaximize = noRocketbar || chromeMaximized || trayActive;
|
|
var fewIcons = (this._iconsCount < this._numMinimizedIcons);
|
|
|
|
// Important: we need a boolean to make the toggle method
|
|
// take the right decision
|
|
var elem = this.element;
|
|
elem.classList.toggle('maximized', !!(shouldMaximize && !fewIcons));
|
|
},
|
|
|
|
panelHandler: function sb_panelHandler(evt) {
|
|
// Do not forward events if FTU is running
|
|
if (Service.query('isFtuRunning')) {
|
|
return;
|
|
}
|
|
|
|
// Do not forward events if the utility tray is shown.
|
|
if (this.utilityTray && this.utilityTray.shown) {
|
|
return;
|
|
}
|
|
|
|
var app = Service.query('getTopMostWindow');
|
|
app && app.handleStatusbarTouch(evt, this._cacheHeight);
|
|
},
|
|
|
|
getAllElements: function sb_getAllElements() {
|
|
this.element = document.getElementById('statusbar');
|
|
this.statusbarIcons = document.getElementById('statusbar-icons');
|
|
this.statusbarIconsMax = document.getElementById('statusbar-maximized');
|
|
this.screen = document.getElementById('screen');
|
|
this.topPanel = document.getElementById('top-panel');
|
|
this.statusbarTray = document.getElementById('statusbar-tray');
|
|
|
|
// Dummy element used at initialization.
|
|
this.statusbarIconsMin = document.createElement('div');
|
|
this.statusbarIcons.appendChild(this.statusbarIconsMin);
|
|
},
|
|
|
|
// To reduce the duplicated code
|
|
isLocked: function() {
|
|
return Service.query('locked');
|
|
}
|
|
};
|
|
exports.Statusbar = Statusbar;
|
|
}(window));
|