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,266 @@
/* global BaseModule */
/* global Service */
'use strict';
(function() {
/**
* AudioChannelService manages audio channels in apps.
* It could allow or deny a audio channel to play in some specific cases.
* For example, Music app would like to play when FM app is already playing.
* It will allow Music app to play, and pause FM app.
*
* @class AudioChannelService
*/
var AudioChannelService = function() {};
AudioChannelService.EVENTS = [
'audiochannelstatechanged',
'audiochanneldestroyed',
'hierarchytopmostwindowchanged',
'systemwindowaudiochannelsregistered'
];
AudioChannelService.SUB_MODULES = [
'AudioChannelPolicy'
];
BaseModule.create(AudioChannelService, {
name: 'AudioChannelService',
DEBUG: false,
// If true, all audio channels of System app are muted.
_isSystemMuted: false,
// A map contains playing audio channels.
_activeAudioChannels: null,
// A map contains audio channels' weights.
_audioChannelWeights: null,
// An array contains audio channels could be resumed
// when any other audio channel ends.
_interruptedAudioChannels: null,
// The most top app window.
_topMostWindow: null,
/**
* Initial the module.
*/
_start: function() {
this._activeAudioChannels = new Map();
this._audioChannelWeights = new Map([
['none', 0], ['system', 1], ['normal', 2], ['content', 3],
['alarm', 4], ['ringer', 5], ['telephony', 6],
['notification', 7], ['publicnotification', 8]
]);
this._interruptedAudioChannels = [];
this._muteSystemAudioChannels();
this.debug('Start Audio Channel Manager');
},
/**
* Handle the audio chanel when it is active or in inactive.
*
* @param {Event} evt The event to handle.
*/
_handle_audiochannelstatechanged: function(evt) {
var audioChannel = evt.detail;
this.debug('Audio channel state is ' + audioChannel.isActive());
this._manageAudioChannels(audioChannel);
},
/**
* Remove the window's audio channels from
* `_activeAudioChannels` and `_interruptedAudioChannels`
* when the window is terminated.
*
* @param {Event} evt The event to handle.
*/
_handle_audiochanneldestroyed: function(evt) {
var audioChannel = evt.detail;
this._activeAudioChannels.delete(audioChannel.instanceID);
this._deleteAudioChannelFromInterruptedAudioChannels(audioChannel);
this._resumeAudioChannels();
},
/**
* Handle the audio chanel when the app is in foreground.
*/
_handle_hierarchytopmostwindowchanged: function() {
this._topMostWindow = Service.query('getTopMostWindow');
if (this._topMostWindow) {
this.debug(this._topMostWindow.name + ' is opened');
this._resumeAudioChannels(this._topMostWindow);
}
},
/**
* Mute the System app's audio channels after they are registered.
*/
_handle_systemwindowaudiochannelsregistered: function() {
this._muteSystemAudioChannels();
},
/**
* Play or pause the new audio channel and the active audio channels.
*
* @param {AudioChannelController} audioChannel The new audio channel.
*/
_manageAudioChannels: function(audioChannel) {
if (audioChannel.isActive()) {
this.audioChannelPolicy.applyPolicy(
audioChannel,
this._activeAudioChannels
);
this._activeAudioChannels.forEach((audioChannel) => {
this._handleAudioChannel(audioChannel);
});
this._handleAudioChannel(audioChannel);
if (!this._isAudioChannelInBackground(audioChannel)) {
this.publish('visibleaudiochannelchanged', {
channel: audioChannel.name
});
}
var channel = this._getTopPriorityAudioChannel();
this.publish('audiochannelchanged', { channel: channel });
} else {
this._resetAudioChannel(audioChannel);
this._resumeAudioChannels();
}
},
/**
* Set the audio channel as default state as muted,
* and fade in the faded out audio channels.
*
* @param {AudioChannelController} audioChannel The audio channel.
*/
_resetAudioChannel: function(audioChannel) {
audioChannel.setPolicy({ isAllowedToPlay: false });
this._handleAudioChannel(audioChannel);
if (audioChannel.name === 'notification' ||
audioChannel.name === 'publicnotification') {
this._fadeInFadedOutAudioChannels();
}
},
/**
* Handle the audio channel
* and update `_activeAudioChannels` and `_interruptedAudioChannels`.
*
* @param {AudioChannelController} audioChannel The audio channel.
*/
_handleAudioChannel: function(audioChannel) {
var policy = audioChannel.proceedPolicy().getPolicy();
if (policy.isAllowedToPlay) {
this._activeAudioChannels.set(
audioChannel.instanceID,
audioChannel
);
this.debug('Playing ' + audioChannel.instanceID);
} else {
this._activeAudioChannels.delete(audioChannel.instanceID);
if (policy.isNeededToResumeWhenOtherEnds) {
this._interruptedAudioChannels.push(audioChannel);
this.debug('Interrupted ' + audioChannel.instanceID);
}
}
},
/**
* Fade in all faded out audio channels.
*/
_fadeInFadedOutAudioChannels: function() {
this._activeAudioChannels.forEach((audioChannel) => {
audioChannel.isFadingOut() && audioChannel
.setPolicy({ isNeededToFadeOut: false })
.proceedPolicy();
});
},
/**
* Resume interrupted audio channels.
*
* @param {AppWindow} [app] The app window in foreground.
*/
_resumeAudioChannels: function(app) {
// FIXME: The `app` param should always have `audioChannels`,
// then we don't need to check it.
// Resume the app's audio channels.
if (app) {
app.audioChannels && app.audioChannels.forEach((audioChannel) => {
audioChannel.isActive() && this._manageAudioChannels(audioChannel);
audioChannel.isPlaying() &&
this._deleteAudioChannelFromInterruptedAudioChannels(audioChannel);
});
}
// Resume the latest interrupted audio channel.
var audioChannel;
var length = this._interruptedAudioChannels.length;
if (this._activeAudioChannels.size === 0 && length) {
audioChannel = this._interruptedAudioChannels[length - 1];
audioChannel.setPolicy({ isAllowedToPlay: true });
this._handleAudioChannel(audioChannel);
audioChannel.isPlaying() && this._interruptedAudioChannels.pop();
}
// Send audiochannelchanged evnet to SoundManager.
var channel = this._getTopPriorityAudioChannel();
this.publish('audiochannelchanged', { channel: channel });
},
/**
* Get the top priority audio channel from activeAudioChannels.
*
* @return {String}
*/
_getTopPriorityAudioChannel: function() {
var channel = 'none';
this._activeAudioChannels.forEach((audioChannel) => {
if (this._audioChannelWeights.get(audioChannel.name) >
this._audioChannelWeights.get(channel)) {
channel = audioChannel.name;
}
});
return channel;
},
/**
* Delete the audio channel from `_interruptedAudioChannels` array.
*
* @param {AudioChannelController} audioChannel
* The audio channel want to delete.
*/
_deleteAudioChannelFromInterruptedAudioChannels: function(audioChannel) {
var index = this._interruptedAudioChannels
.findIndex(function(interruptedAudioChannel) {
return interruptedAudioChannel.instanceID ===
audioChannel.instanceID;
});
index !== -1 && this._interruptedAudioChannels.splice(index, 1);
},
/**
* Check the audio channel is in background or not.
*
* @param {AudioChannelController} audioChannel The audio channel.
* @return {Boolean}
*/
_isAudioChannelInBackground: function(audioChannel) {
var isAudioChannelInBackground = true;
if ((this._topMostWindow &&
this._topMostWindow.instanceID === audioChannel.app.instanceID) ||
(audioChannel.isActive() && audioChannel.app.isInputMethod)) {
isAudioChannelInBackground = false;
}
return isAudioChannelInBackground;
},
_muteSystemAudioChannels: function() {
var audioChannels = this.service.query('SystemWindow.getAudioChannels');
if (!this._isSystemMuted && audioChannels && audioChannels.size) {
audioChannels.forEach((audioChannel) => {
audioChannel
.setPolicy({ isAllowedToPlay: false })
.proceedPolicy();
});
this._isSystemMuted = true;
}
}
});
}());