Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,418 @@
/* global Service */
'use strict';
(function(exports) {
var TransitionEvents =
['open', 'close', 'complete', 'timeout',
'immediate-open', 'immediate-close'];
var TransitionStateTable = {
'closed': ['opening', null, null, null, 'opened', null],
'opened': [null, 'closing', null, null, null, 'closed'],
'opening': [null, 'closing', 'opened', 'opened', 'opened', 'closed'],
'closing': ['opened', null, 'closed', 'closed', 'opened', 'closed']
};
/**
* AppTransitionController controlls the opening and closing animation
* of the given appWindow.
*
* ##### Flow chart #####
* ![AppTransition Flow chart](http://i.imgur.com/k0hO2AN.png)
*
* ##### State machine #####
* ![AppTransition State machine](http://i.imgur.com/0arU9rl.png)
*
* @param {AppWindow} app The app window instance which this controller
* belongs to.
*
* @class AppTransitionController
*/
var AppTransitionController =
function AppTransitionController(app) {
if (!app || !app.element) {
return;
}
this.app = app;
this.app.debug('default animation:',
this.app.openAnimation, this.app.closeAnimation);
if (this.app.openAnimation) {
this.openAnimation = this.app.openAnimation;
}
if (this.app.closeAnimation) {
this.closeAnimation = this.app.closeAnimation;
}
if (this.app.CLASS_NAME == 'AppWindow') {
this.OPENING_TRANSITION_TIMEOUT = 2500;
}
this.app.element.addEventListener('_opening', this);
this.app.element.addEventListener('_closing', this);
this.app.element.addEventListener('_opened', this);
this.app.element.addEventListener('_closed', this);
this.app.element.addEventListener('_opentransitionstart', this);
this.app.element.addEventListener('_closetransitionstart', this);
this.app.element.addEventListener('_loaded', this);
this.app.element.addEventListener('_openingtimeout', this);
this.app.element.addEventListener('_closingtimeout', this);
this.app.element.addEventListener('animationend', this);
};
AppTransitionController.prototype.destroy = function() {
if (!this.app || !this.app.element) {
return;
}
this.app.element.removeEventListener('_opening', this);
this.app.element.removeEventListener('_closing', this);
this.app.element.removeEventListener('_opened', this);
this.app.element.removeEventListener('_closed', this);
this.app.element.removeEventListener('_opentransitionstart', this);
this.app.element.removeEventListener('_closetransitionstart', this);
this.app.element.removeEventListener('_loaded', this);
this.app.element.removeEventListener('_openingtimeout', this);
this.app.element.removeEventListener('_closingtimeout', this);
this.app.element.removeEventListener('animationend', this);
this.app = null;
};
AppTransitionController.prototype._transitionState = 'closed';
AppTransitionController.prototype._waitingForLoad = false;
AppTransitionController.prototype.openAnimation = 'enlarge';
AppTransitionController.prototype.closeAnimation = 'reduce';
AppTransitionController.prototype.OPENING_TRANSITION_TIMEOUT = 1000;
AppTransitionController.prototype.CLOSING_TRANSITION_TIMEOUT = 1000;
AppTransitionController.prototype.SLOW_TRANSITION_TIMEOUT = 3500;
AppTransitionController.prototype._firstTransition = true;
AppTransitionController.prototype.changeTransitionState =
function atc_changeTransitionState(evt) {
var currentState = this._transitionState;
var evtIndex = TransitionEvents.indexOf(evt);
var state = TransitionStateTable[currentState][evtIndex];
if (!state) {
return;
}
this.app.debug(currentState, state, '::', evt);
this.switchTransitionState(state);
this.resetTransition();
this['_do_' + state]();
this.app.publish(state);
//backward compatibility
if (!this.app) {
return;
}
if (state == 'opening') {
/**
* Fired when the app is doing opening animation.
* @event AppWindow#appopening
*/
this.app.publish('willopen');
} else if (state == 'closing') {
/**
* Fired when the app is doing closing animation.
* @event AppWindow#appclosing
*/
this.app.publish('willclose');
} else if (state == 'opened') {
/**
* Fired when the app's opening animation is ended.
* @event AppWindow#appopen
*/
this.app.publish('open');
} else if (state == 'closed') {
/**
* Fired when the app's closing animation is ended.
* @event AppWindow#appclose
*/
this.app.publish('close');
}
};
AppTransitionController.prototype._do_closing =
function atc_do_closing() {
var slow = Service.query('slowTransition');
var timeout = slow ? this.SLOW_TRANSITION_TIMEOUT :
this.CLOSING_TRANSITION_TIMEOUT;
this.app.debug('timer to ensure closed does occur.');
this._closingTimeout = window.setTimeout(() => {
if (!this.app) {
return;
}
this.app.broadcast('closingtimeout');
}, timeout);
if (!this.app || !this.app.element) {
return;
}
this.app.element.classList.add('transition-closing');
this.app.element.classList.add(this.getAnimationName('close'));
};
AppTransitionController.prototype._do_closed =
function atc_do_closed() {
};
AppTransitionController.prototype.getAnimationName = function(type) {
return this.currentAnimation || this[type + 'Animation'] || type;
};
AppTransitionController.prototype._do_opening =
function atc_do_opening() {
var slow = Service.query('slowTransition');
var timeout = slow ? this.SLOW_TRANSITION_TIMEOUT :
this.OPENING_TRANSITION_TIMEOUT;
this.app.debug('timer to ensure opened does occur.');
this._openingTimeout = window.setTimeout(() => {
this.app && this.app.broadcast('openingtimeout');
}, timeout);
this._waitingForLoad = false;
this.app.element.classList.add('transition-opening');
this.app.element.classList.add(this.getAnimationName('open'));
this.app.debug(this.app.element.classList);
};
AppTransitionController.prototype._do_opened =
function atc_do_opened() {
};
AppTransitionController.prototype.switchTransitionState =
function atc_switchTransitionState(state) {
this._transitionState = state;
if (!this.app) {
return;
}
this.app._changeState('transition', this._transitionState);
};
// TODO: move general transition handlers into another object.
AppTransitionController.prototype.handle_closing =
function atc_handle_closing() {
if (!this.app || !this.app.element) {
return;
}
/* The AttentionToaster will take care of that for AttentionWindows */
/* InputWindow & InputWindowManager will take care of visibility of IM */
if (!this.app.isAttentionWindow && !this.app.isCallscreenWindow &&
!this.app.isInputMethod) {
this.app.setVisible(false);
}
this.switchTransitionState('closing');
};
AppTransitionController.prototype.handle_closed =
function atc_handle_closed() {
if (!this.app || !this.app.element) {
return;
}
this.resetTransition();
this.app.setNFCFocus(false);
this.app.element.classList.remove('active');
};
AppTransitionController.prototype.handle_opening =
function atc_handle_opening() {
if (!this.app || !this.app.element) {
return;
}
if (this.app.loaded) {
var self = this;
this.app.element.addEventListener('_opened', function onopen() {
// Perf test needs.
self.app.element.removeEventListener('_opened', onopen);
self.app.publish('loadtime', {
time: parseInt(Date.now() - self.app.launchTime),
type: 'w',
src: self.app.config.url
});
});
}
this.app.reviveBrowser();
this.app.launchTime = Date.now();
this.app.fadeIn();
// TODO:
// May have orientation manager to deal with lock orientation request.
if (this.app.isHomescreen ||
this.app.isCallscreenWindow) {
this.app.setOrientation();
}
};
AppTransitionController.prototype.handle_opened =
function atc_handle_opened() {
if (!this.app || !this.app.element) {
return;
}
this.app.reviveBrowser();
this.resetTransition();
this.app.element.removeAttribute('aria-hidden');
this.app.show();
this.app.element.classList.add('active');
// If we set the orientation in handle_opening we want to let the resize
// happen before requesting foreground.
if (this.currentAnimation == 'immediate') {
setTimeout(this.app.requestForeground.bind(this.app));
} else {
this.app.requestForeground();
}
// TODO:
// May have orientation manager to deal with lock orientation request.
if (!this.app.isCallscreenWindow) {
this.app.setOrientation();
}
this.focusApp();
};
AppTransitionController.prototype.focusApp = function() {
if (!this.app) {
return;
}
if (this._shouldFocusApp()) {
this.app.debug('focusing this app.');
this.app.focus();
this.app.setNFCFocus(true);
}
};
AppTransitionController.prototype._shouldFocusApp = function() {
// SearchWindow should not focus itself,
// because the input is inside system app.
var bottomWindow = this.app.getBottomMostWindow();
var topmostui = Service.query('getTopMostUI');
var stayBackground = this.app.config &&
this.app.config.stayBackground;
return (this.app.CLASS_NAME !== 'SearchWindow' &&
this._transitionState == 'opened' &&
Service.query('getTopMostWindow') === this.app &&
!stayBackground &&
topmostui &&
topmostui.name === bottomWindow.HIERARCHY_MANAGER);
};
AppTransitionController.prototype.requireOpen = function(animation) {
this.currentAnimation = animation || this.openAnimation;
this.app.debug('open with ' + this.currentAnimation);
if (this.currentAnimation == 'immediate') {
this.app.publish('opening');
this.changeTransitionState('immediate-open');
} else {
this.changeTransitionState('open');
}
};
AppTransitionController.prototype.requireClose = function(animation) {
this.currentAnimation = animation || this.closeAnimation;
this.app.debug('close with ' + this.currentAnimation);
if (this.currentAnimation == 'immediate') {
this.app.publish('closing');
this.changeTransitionState('immediate-close');
} else {
this.changeTransitionState('close');
}
};
AppTransitionController.prototype.resetTransition =
function atc_resetTransition() {
if (this._openingTimeout) {
window.clearTimeout(this._openingTimeout);
this._openingTimeout = null;
}
if (this._closingTimeout) {
window.clearTimeout(this._closingTimeout);
this._closingTimeout = null;
}
this.clearTransitionClasses();
};
AppTransitionController.prototype.clearTransitionClasses =
function atc_removeTransitionClasses() {
if (!this.app || !this.app.element) {
return;
}
var classes = ['enlarge', 'reduce', 'to-cardview', 'from-cardview',
'invoking', 'invoked', 'zoom-in', 'zoom-out', 'fade-in', 'fade-out',
'transition-opening', 'transition-closing', 'immediate', 'fadeout',
'slideleft', 'slideright', 'in-from-left', 'out-to-right',
'will-become-active', 'will-become-inactive',
'slide-to-top', 'slide-from-top',
'slide-to-bottom', 'slide-from-bottom',
'home-from-cardview', 'home-to-cardview', 'from-new-card'];
classes.forEach(function iterator(cls) {
this.app.element.classList.remove(cls);
}, this);
};
AppTransitionController.prototype.handleEvent =
function atc_handleEvent(evt) {
switch (evt.type) {
case '_opening':
this.handle_opening();
break;
case '_opened':
this.handle_opened();
break;
case '_closed':
this.handle_closed();
break;
case '_closing':
this.handle_closing();
break;
case '_closingtimeout':
case '_openingtimeout':
this.changeTransitionState('timeout', evt.type);
break;
case '_loaded':
if (this._waitingForLoad) {
this._waitingForLoad = false;
this.changeTransitionState('complete');
}
break;
case 'animationend':
evt.stopPropagation();
if (this._transitionState == 'closing') {
this.changeTransitionState('complete', evt.type);
break;
}
// Hide touch-blocker when launching animation is ended.
this.app.element.classList.remove('transition-opening');
// We decide to drop this event if system is busy loading
// the active app or doing some other more important task.
// In case of the browser, we don't want to wait for the page
// being fully loaded to trigger the 'opened' event
if (!this.app.isBrowser() && Service.query('isBusyLoading')) {
this._waitingForLoad = true;
if (this.app.isHomescreen && this._transitionState == 'opening') {
/**
* focusing the app will have some side effect,
* but we don't care if we are opening the homescreen.
*/
this.app.focus();
}
break;
}
this.app.debug(evt.animationName + ' has been ENDED!');
this.changeTransitionState('complete', evt.type);
break;
}
};
exports.AppTransitionController = AppTransitionController;
}(window));