VulpesOS/gaia/tv_apps/smart-system/js/sound_manager.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

987 lines
30 KiB
JavaScript
Executable file

/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* global AsyncSemaphore, CustomDialog, FtuLauncher, ScreenManager,
SettingsCache, SettingsListener, Service */
(function(exports) {
'use strict';
/**
* SoundManager handles hardware volume key events, bluetooth volume changes,
* and volume/channel change events.
* @class SoundManager
* @requires AsyncSemaphore
* @requires FtuLauncher
* @requires ScreenManager
*/
function SoundManager() {
}
/**
* settings key for vibration
* @memberOf SoundManager
*/
SoundManager.VIBRATION_SETTINGS_KEY = 'vibration.enabled';
/**
* user preference key for vibration which is used at async storage.
* @memberOf SoundManager
*/
SoundManager.VIBRATION_USER_PREF_KEY = 'preference.vibration.enabled';
/**
* reset time span for volume warning dialog.
* @memberOf SoundManager
*/
SoundManager.CE_RESET_TIME = 72000000;
/**
* constant for CE counter interval.
* @memberOf SoundManager
*/
SoundManager.TIME_ONE_MINUTE = 60000;
/**
* elapsed time from last volume warning dialog which is used at async
* storage.
* @memberOf SoundManager
*/
SoundManager.CACHE_CETIMES = 'CE_ACCTIME';
// volume cache
// Platform doesn't provide the maximum value of each channel
// therefore, hard code here.
SoundManager.MAX_VOLUME = {
'alarm': 15,
'notification': 15,
'content': 15,
'bt_sco': 15
};
/**
* Store the current active channel;
* change with 'audio-channel-changed' mozChromeEvent
* All candidates and definitions can be found at AudioChannels link.
*
* @see {link https://wiki.mozilla.org/WebAPI/AudioChannels|AudioChannels}
* @memberOf SoundManager.prototype
* @type {String}
*/
SoundManager.prototype.currentChannel = 'none';
/**
* Tell if vibration is enabled currently.
*
* @memberOf SoundManager.prototype
* @type {Boolean}
*/
SoundManager.prototype.vibrationEnabled = true;
/**
* Default volume control channel
* Possible values:
* normal
* content
* notification
* alarm
* ringer
* publicnotification
* unknown
* @memberOf SoundManager.prototype
* @type {String}
*/
SoundManager.prototype.defaultVolumeControlChannel = 'unknown';
/**
* is headset connected.
* @memberOf SoundManager.prototype
* @type {Boolean}
*/
SoundManager.prototype.isHeadsetConnected = false;
/**
* We have three virtual states here:
* OFF -> VIBRATION -> MUTE
* @memberOf SoundManager.prototype
* @type {String}
*/
SoundManager.prototype.muteState = 'OFF';
/**
* User preference to tell if vibration is enabled. The value is read from
* 'preference.vibration.enabled' key.
* @memberOf SoundManager.prototype
* @type {Boolean}
*/
SoundManager.prototype.vibrationUserPrefEnabled = true;
/**
* Cache the volume when entering silent mode.
* Currently only two channel would be used for mute.
* @memberOf SoundManager.prototype
* @type {Object}
*/
SoundManager.prototype.cachedVolume = {
'content': -1,
'notification': -1
};
/**
* The keys of cachedVolume.
* @memberOf SoundManager.prototype
* @type {Array}
* @see cachedVolume
*/
SoundManager.prototype.cachedChannels = ['content', 'notification'];
/**
* The interval ID of CE accumulator.
* @memberOf SoundManager.prototype
* @type {Number}
*/
SoundManager.prototype.CEAccumulatorID = null;
/**
* The minimum warning volume level.
* @memberOf SoundManager.prototype
* @type {Number}
* @default 11
*/
SoundManager.prototype.CEWarningVol = 11;
/**
* The accumulated time where the volume is above {@link CEWarningVol} and the
* channel is "content".
* @memberOf SoundManager.prototype
* @type {Number}
* @see CEWarningVol
*/
SoundManager.prototype.CEAccumulatorTime = 0;
/**
* The start time of accumulator running.
* @memberOf SoundManager.prototype
* @type {Number}
*/
SoundManager.prototype.CETimestamp = 0;
/**
* The current volume for all channels: alarm, notification,
* content, and bt_sco.
* @memberOf SoundManager.prototype
* @type {Object}
* @see {@link https://wiki.mozilla.org/WebAPI/AudioChannels#Volume_control}
*/
SoundManager.prototype.currentVolume = {
'alarm': 15,
'notification': 15,
'content': 15,
'bt_sco': 15
};
/**
* A semaphore used inside of SoundManager.
* @memberOf SoundManager.prototype
* @type {AsyncSemaphore}
*/
SoundManager.prototype.pendingRequest = new AsyncSemaphore();
/**
* To tell if the homescreen is visible.
*
* @memberOf SoundManager.prototype
* @type {Boolean}
*/
SoundManager.prototype.homescreenVisible = true;
/**
* A counter for checking if the vibration settings is made by SoundManager.
*
* @memberOf SoundManager.prototype
* @type {Number}
*/
SoundManager.prototype.setVibrationEnabledCount = 0;
/**
* A flag to tell if the volume is fetched from settings.
*
* @memberOf SoundManager.prototype
* @type {Boolean}
*/
SoundManager.prototype.volumeFetched = false;
/**
* A timer ID for auto hiding volume UI.
*
* @memberOf SoundManager.prototype
* @type {Boolean}
*/
SoundManager.prototype.activeTimerID = 0;
/**
* It adds listeners to window events, observes the change of mozSettings, and
* loads settings from mozSettings.
*
* @memberOf SoundManager.prototype
* @returns {SoundManager}
*/
SoundManager.prototype.start = function sm_start() {
window.addEventListener('volumeup', this);
window.addEventListener('volumedown', this);
window.addEventListener('mute', this);
window.addEventListener('unmute', this);
window.addEventListener('mozChromeEvent', this);
window.addEventListener('unload', this);
window.addEventListener('appopen', this);
window.addEventListener('ftudone', this);
window.addEventListener('holdhome', this);
window.addEventListener('homescreenopening', this);
window.addEventListener('homescreenopened', this);
this.initVibrationUserPref();
this.bindVolumeSettingsHandlers();
var self = this;
SettingsCache.observe('audio.volume.cemaxvol', 11, function(volume) {
self.CEWarningVol = volume;
});
window.asyncStorage.getItem(SoundManager.CACHE_CETIMES,
function getCETime(value) {
if (!value) {
return;
} else {
self.CEAccumulatorTime = value;
}
});
};
/**
* It removes listeners from window events
*
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.stop = function sm_stop() {
window.removeEventListener('volumeup', this);
window.removeEventListener('volumedown', this);
window.removeEventListener('mute', this);
window.removeEventListener('unmute', this);
window.removeEventListener('mozChromeEvent', this);
window.removeEventListener('unload', this);
window.removeEventListener('appopen', this);
window.removeEventListener('ftudone', this);
window.removeEventListener('holdhome', this);
window.removeEventListener('homescreenopening', this);
window.removeEventListener('homescreenopened', this);
};
/**
* It handles the events from window object, including hardware key events,
* mozChromeEvent, and custom event made by System app.
*
* @memberOf SoundManager.prototype
* @param {DOMEvent} e
*/
SoundManager.prototype.handleEvent = function sm_handleEvent(e) {
switch (e.type) {
case 'volumeup':
this.handleVolumeKey(1);
break;
case 'volumedown':
this.handleVolumeKey(-1);
break;
case 'mute':
this.setMute(true);
break;
case 'unmute':
this.setMute(false);
break;
case 'mozChromeEvent':
switch (e.detail.type) {
case 'bluetooth-volumeset':
this.changeVolume(e.detail.value - this.currentVolume.bt_sco,
'bt_sco');
break;
case 'audio-channel-changed':
this.currentChannel = e.detail.channel;
this.ceAccumulator();
break;
case 'headphones-status-changed':
this.isHeadsetConnected = (e.detail.state !== 'off');
this.ceAccumulator();
break;
case 'default-volume-channel-changed':
this.defaultVolumeControlChannel = e.detail.channel;
// Do not accumulate CE time here because this event
// doesn't mean the content is playing now.
break;
}
break;
case 'unload':
this.stopAccumulator();
break;
case 'appopen':
this.homescreenVisible = false;
break;
case 'ftudone':
this.homescreenVisible = true;
break;
case 'holdhome':
CustomDialog.hide();
break;
case 'homescreenopening':
case 'homescreenopened':
this.homescreenVisible = true;
CustomDialog.hide();
break;
}
};
/**
* This function handles the volume key up/down behavior. When it is under a
* call and user sues a bluetooth, we need to change the volume of BT SCO.
* When the headset is connected, we need to activate CE counter. Otherwise,
* we calls normal changeVolume API.
*
* @memberOf SoundManager.prototype
* @param {Number} offset the offset which will be added to volume value.
*/
SoundManager.prototype.handleVolumeKey = function sm_handleVolumeKey(offset) {
if (!ScreenManager.screenEnabled && this.currentChannel === 'none') {
return;
}
if (this.isHeadsetConnected && offset > 0) {
this.headsetVolumeup();
} else {
this.changeVolume(offset);
}
};
/**
* The mute/unmute event is dispatched from sleep menu.
* But if we have a mute/unmute hardware button or virtual button,
* we could make the button handler to fire this event, too.
*
* @memberOf SoundManager.prototype
* @param {Boolean} mute the state of mute.
*/
SoundManager.prototype.setMute = function sm_setMute(mute) {
/**
*/
if (mute) {
// Turn off vibration for really silence.
this.setVibrationEnabled(false);
this.enterSilentMode('notification');
} else {
// Turn on vibration.
this.setVibrationEnabled(true);
this.leaveSilentMode('notification');
this.leaveSilentMode('content');
}
};
/*
* When hardware volume key is pressed, we need to decide which channel we
* should toggle.
* This method returns the string for setting key 'audio.volume.*' represents
* that.
* Note: this string does not always equal to currentChannel since some
* different channels are grouped together to listen to the same setting.
* @memberOf SoundManager.prototype
* @returns {String} the volume channel
*/
SoundManager.prototype.getChannel = function sm_getChannel() {
switch (this.currentChannel) {
case 'normal':
case 'content':
return 'content';
case 'alarm':
return 'alarm';
case 'notification':
case 'ringer':
return 'notification';
default:
if (this.defaultVolumeControlChannel !== 'unknown') {
return this.defaultVolumeControlChannel;
} else {
return this.homescreenVisible || (Service.locked) ||
FtuLauncher.isFtuRunning() ? 'notification' : 'content';
}
}
};
/**
* It reads vibration user preference from asyncStorage and listen the change
* from mozSettings.
*
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.initVibrationUserPref = function sm_initVUserPref() {
var self = this;
// check asyncStorage
window.asyncStorage.getItem(SoundManager.VIBRATION_USER_PREF_KEY,
function onok(value) {
if (value === null) {
// not found, read from settings.
var r = SettingsListener.getSettingsLock().get(
SoundManager.VIBRATION_SETTINGS_KEY);
r.onsuccess = function get_onsuccess() {
// write back to asyncStorage.
self.writeVibrationUserPref(
r.result[SoundManager.VIBRATION_SETTINGS_KEY]);
};
r.onerror = function get_onerror() {
// initial value to true
self.writeVibrationUserPref(true);
};
} else {
self.vibrationUserPrefEnabled = value;
}
});
// observe settings
SettingsCache.observe(SoundManager.VIBRATION_SETTINGS_KEY,
true, function(vibration) {
var setBySelf = false;
var toggleVibrationEnabled = function toggle_vibration_enabled() {
// XXX: If the value does not set by sound manager,
// we assume it comes from
// the settings app and consider it as user preference.
if (!setBySelf) {
self.writeVibrationUserPref(vibration);
}
self.vibrationEnabled = vibration;
};
if (self.setVibrationEnabledCount > 0) {
self.setVibrationEnabledCount--;
setBySelf = true;
}
self.pendingRequest.wait(toggleVibrationEnabled, self);
});
};
/**
* It saves the user perference of vibration to asyncStorage.
*
* @memberOf SoundManager.prototype
* @param {Boolean} value vibration preference
*/
SoundManager.prototype.writeVibrationUserPref = function sm_writeUP(value) {
if (this.vibrationUserPrefEnabled === value) {
return;
}
// if value is null or undefined, we view it as initial value which is true.
if (value === null || typeof(value) === 'undefined') {
value = true;
}
var self = this;
window.asyncStorage.setItem(SoundManager.VIBRATION_USER_PREF_KEY, value,
function set_onsuccess() {
self.vibrationUserPrefEnabled = value;
});
};
/**
* It checks the state to start/stop the CE accumulator.
*
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.ceAccumulator = function sm_ceAccumulator() {
if (this.isHeadsetConnected && this.getChannel() === 'content' &&
this.currentVolume[this.currentChannel] >= this.CEWarningVol) {
if (this.CEAccumulatorTime === 0) {
this.resetToCEMaxVolume();
} else {
this.startAccumulator();
}
} else {
this.stopAccumulator();
}
};
/**
* It handles the case of pressing volumeup hardware key when headset is
* connected. This function mainly checks the state to start the CE
* accumulator and change the volume.
*
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.headsetVolumeup = function sm_headsetVolumeup() {
if ((this.currentVolume[this.getChannel()] + 1) >= this.CEWarningVol &&
this.getChannel() === 'content') {
if (this.CEAccumulatorTime === 0) {
var self = this;
var okfn = function() {
self.changeVolume(1);
self.startAccumulator();
};
this.resetToCEMaxVolume(okfn);
} else {
this.startAccumulator();
this.changeVolume(1);
}
} else {
this.changeVolume(1);
}
};
/**
* It shows a warning dialog to tell user that the volume may hurt his/her
* ear.
*
* @memberOf SoundManager.prototype
* @param {Function} okfun the callback function when user press ok.
*/
SoundManager.prototype.showCEWarningDialog = function sm_showCEDialog(okfn) {
// Show dialog.
var ceTitle = {
'icon': '/style/sound_manager/images/icon_Volumewarning.png',
'id': 'ceWarningtitle'
};
var ceMsg = 'ceWarningcontent';
var cancel = {
'title': 'ok'
};
var self = this;
var screen = document.getElementById('screen');
if (okfn instanceof Function) {
cancel.callback = function onCancel() {
okfn();
CustomDialog.hide();
};
} else {
cancel.callback = function onCancel() {
self.startAccumulator();
CustomDialog.hide();
};
}
CustomDialog
.show(ceTitle, ceMsg, cancel, null, screen)
.setAttribute('data-z-index-level', 'system-dialog');
};
/**
* It starts the CE accumulator.
*
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.startAccumulator = function sm_startAccumulator() {
if (this.CEAccumulatorID === null) {
if (this.CEAccumulatorTime === 0) {
this.CEAccumulatorTime = 1;
this.CETimestamp = parseInt(new Date().getTime(), 10);
}
var self = this;
this.CEAccumulatorID = window.setInterval(function ceCounter() {
self.CEAccumulatorTime += SoundManager.TIME_ONE_MINUTE;
self.CETimestamp = parseInt(new Date().getTime(), 10);
if (self.CEAccumulatorTime > SoundManager.CE_RESET_TIME) {
self.CEAccumulatorTime = 0; // reset time
self.CETimestamp = 0; // reset timestamp
self.stopAccumulator();
self.resetToCEMaxVolume();
}
}, SoundManager.TIME_ONE_MINUTE);
}
};
/**
* It stops the CE accumulator.
*
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.stopAccumulator = function sm_stopAccumulator() {
if (this.CEAccumulatorID !== null) {
window.clearInterval(this.CEAccumulatorID);
this.CEAccumulatorID = null;
if (this.CETimestamp !== 0) {
this.CEAccumulatorTime = this.CEAccumulatorTime +
(parseInt(new Date().getTime(), 10) - this.CETimestamp);
}
window.asyncStorage.setItem(SoundManager.CACHE_CETIMES,
this.CEAccumulatorTime);
}
};
/**
* It resets the content channel to warning volume - 1 and shows the warning
* dialog for confirm.
*
* @memberOf SoundManager.prototype
* @param {Function} okfun the callback function when user press ok.
*/
SoundManager.prototype.resetToCEMaxVolume = function sm_resetCEMax(callback) {
this.pendingRequest.v();
var req = SettingsListener.getSettingsLock().set({
'audio.volume.content': this.CEWarningVol - 1
});
var self = this;
req.onsuccess = function onSuccess() {
self.pendingRequest.p();
self.showCEWarningDialog(callback);
};
req.onerror = function onError() {
self.pendingRequest.p();
self.showCEWarningDialog(callback);
};
};
/**
* Bind setting handlers for each channel's volume change.
* @memberOf SoundManager.prototype
* @param {Function} callback Callback being called after each setting handler
* has been invoked once.
*/
SoundManager.prototype.bindVolumeSettingsHandlers = function sm_bindHdlers() {
var callsMade = 0;
var callbacksReceived = 0;
var self = this;
function observeSettingsVolumeChange(channel) {
var setting = 'audio.volume.' + channel;
SettingsCache.observe(setting, 5, function onChange(volume) {
var settingsChange = function settings_change() {
var max = SoundManager.MAX_VOLUME[channel];
self.currentVolume[channel] =
parseInt(Math.max(0, Math.min(max, volume)), 10);
if (channel === 'content' && self.volumeFetched && volume > 0) {
self.leaveSilentMode('content',
/* skip volume restore */ true);
} else if (channel === 'notification' && volume > 0) {
self.leaveSilentMode('notification',
/* skip volume restore */ true);
} else if (channel === 'notification' && volume === 0) {
// Enter silent mode when notification volume is 0
// no matter who sets this value.
self.enterSilentMode('notification');
}
if (!self.volumeFetched && ++callbacksReceived === callsMade) {
self.fetchCachedVolume();
}
};
// Initial loaded setting should always pass through
// (one per channel)
self.pendingRequest.wait(settingsChange, self);
});
}
for (var channel in this.currentVolume) {
callsMade++;
observeSettingsVolumeChange(channel);
}
};
/**
* Fetch stored volume if it exists.
* We should make sure this happens after settingsDB callback
* after booting.
* @memberOf SoundManager.prototype
*/
SoundManager.prototype.fetchCachedVolume = function sm_fetchCachedVolume() {
if (this.volumeFetched) {
return;
}
this.volumeFetched = true;
this.pendingRequest.v(this.cachedChannels.length);
var self = this;
this.cachedChannels.forEach(
function iterator(channel) {
window.asyncStorage.getItem('content.volume',
function onGettingCachedVolume(value) {
if (!value) {
self.pendingRequest.p();
return;
}
self.cachedVolume[channel] = value;
self.pendingRequest.p();
});
}
);
};
/**
* It handles the vibration case when changing the volume.
* @memberOf SoundManager.prototype
* @param {Number} curVolume the base volume
* @param {Number} delta the offset of the change
* @param {String} channel the target channel
* @returns {Number} the volume value. (-1) is for slient mode and (0) is for
* vibration mode
*/
SoundManager.prototype.calculateVolume = function sm_calVol(
curVolume, delta, channel) {
var volume = curVolume;
if (channel === 'notification') {
if (volume === 0 && !this.vibrationEnabled) {
// This is for voluming up from Silent to Vibrate.
// Let's take -1 as the silent state and
// 0 as the vibrate state for easier calculation here.
volume = -1;
}
volume += delta;
} else {
volume += delta;
}
return volume;
};
/**
* It enables the vibration and returns the mute state.
* @memberOf SoundManager.prototype
* @param {Number} curVolume the base volume
* @param {Number} delta the offset of the change
* @param {String} channel the target channel
* @returns {String} the mute state
*/
SoundManager.prototype.getVibrationAndMuteState = function sm_getState(
curVolume, delta, channel) {
if (channel === 'notification') {
var state;
var volume = curVolume;
if (volume === 0 && !this.vibrationEnabled) {
// This is for voluming up from Silent to Vibrate.
// Let's take -1 as the silent state and
// 0 as the vibrate state for easier calculation here.
volume = -1;
}
volume += delta;
if (volume < 0) {
state = 'MUTE';
this.vibrationEnabled = false;
} else if (volume === 0) {
state = 'MUTE';
this.vibrationEnabled = true;
} else {
// Restore the vibration setting only when leaving silent mode.
if (curVolume <= 0) {
this.vibrationEnabled = this.vibrationUserPrefEnabled;
}
state = 'OFF';
}
return state;
} else {
if (curVolume + delta <= 0) {
return 'MUTE';
} else {
return 'OFF';
}
}
};
/**
* Entering silent mode.
* @memberOf SoundManager.prototype
* @param {String} [channel="content"] Specify the channel name
* which is going to enter silent mode.
*/
SoundManager.prototype.enterSilentMode = function sm_enterSlient(channel) {
if (!channel) {
channel = 'content';
}
// Don't need to enter silent mode more than once.
if (this.currentVolume[channel] === 0) {
return;
}
var isCachedAlready =
(this.cachedVolume[channel] === this.currentVolume[channel]);
this.cachedVolume[channel] = this.currentVolume[channel];
this.pendingRequest.v();
var settingObject = {};
settingObject['audio.volume.' + channel] = 0;
var req = SettingsListener.getSettingsLock().set(settingObject);
var self = this;
req.onsuccess = function onSuccess() {
self.pendingRequest.p();
// Write to async storage only happens when
// we haven't stored it before.
// If the user presses the volume rockers repeatedly down and up,
// between silent-mode/vibration mode/normal mode,
// we won't repeatedly write the same value to storage.
if (!isCachedAlready) {
window.asyncStorage.setItem(channel + '.volume',
self.cachedVolume[channel]);
}
};
req.onerror = function onError() {
self.pendingRequest.p();
};
};
/**
* Leaving silent mode.
* @memberOf SoundManager.prototype
* @param {String} channel Specify the channel name
* which is going to leave silent mode.
* @param {Boolean} skip_restore Specify to skip the volume restore or not.
*/
SoundManager.prototype.leaveSilentMode = function sm_leaveSlient(channel,
skip_restore) {
if (!channel) {
channel = 'content';
}
// We're leaving silent mode.
if (!skip_restore &&
(this.cachedVolume[channel] > 0 ||
this.currentVolume[channel] === 0)) {
var req;
var settingObject = {};
var self = this;
// At least rollback to 1,
// otherwise we don't really leave silent mode.
settingObject['audio.volume.' + channel] =
(this.cachedVolume[channel] > 0) ? this.cachedVolume[channel] : 1;
this.pendingRequest.v();
req = SettingsListener.getSettingsLock().set(settingObject);
req.onsuccess = function onSuccess() {
self.pendingRequest.p();
};
req.onerror = function onError() {
self.pendingRequest.p();
};
}
this.cachedVolume[channel] = -1;
};
/**
* It updates the volume, turns on/off slient mode, and updates UI.
* @memberOf SoundManager.prototype
* @param {Number} delta Specify the channel name
* @param {String} [channel] Specify the channel name. It uses getChannel()
* when this argument is absent.
*/
SoundManager.prototype.changeVolume = function sm_changeVolume(delta,
channel) {
channel = channel ? channel : this.getChannel();
var vibrationEnabledOld = this.vibrationEnabled;
var volume = this.calculateVolume(this.currentVolume[channel], delta,
channel);
this.muteState =
this.getVibrationAndMuteState(this.currentVolume[channel], delta,
channel);
// Silent mode entry point
if (volume <= 0 && delta < 0 && channel == 'notification') {
this.enterSilentMode('content');
} else if (volume == 1 && delta > 0 && channel == 'notification' &&
this.cachedVolume.content >= 0) {
// Now since the active channel is notification channel,
// we're leaving content silent mode and the same time restoring it.
this.leaveSilentMode('content');
// In the notification silent mode, volume rocker priority is higher
// than stored notification volume value so we skip the restore.
this.leaveSilentMode('notification', /*skip volume restore*/ true);
}
this.currentVolume[channel] = volume =
Math.max(0, Math.min(SoundManager.MAX_VOLUME[channel], volume));
var overlay = document.getElementById('system-overlay');
var notification = document.getElementById('volume');
var overlayClasses = overlay.classList;
var classes = notification.classList;
switch (this.muteState) {
case 'OFF':
classes.remove('mute');
break;
case 'MUTE':
classes.add('mute');
break;
}
if (this.vibrationEnabled) {
classes.add('vibration');
} else {
classes.remove('vibration');
}
if (vibrationEnabledOld != this.vibrationEnabled) {
this.setVibrationEnabled(this.vibrationEnabled);
}
var steps =
Array.prototype.slice.call(notification.querySelectorAll('div'), 0);
var maxVolumeStep = volume;
for (var i = 0; i < steps.length; i++) {
var step = steps[i];
if (i < maxVolumeStep) {
step.classList.add('active');
} else {
step.classList.remove('active');
}
}
overlayClasses.add('volume');
classes.add('visible');
window.clearTimeout(this.activeTimerID);
this.activeTimerID = window.setTimeout(function hideSound() {
overlayClasses.remove('volume');
classes.remove('visible');
}, 1500);
if (!window.navigator.mozSettings) {
return;
}
this.pendingRequest.v();
notification.dataset.channel = channel;
var settingObject = {};
settingObject['audio.volume.' + channel] = volume;
var req = SettingsListener.getSettingsLock().set(settingObject);
var self = this;
req.onsuccess = function onSuccess() {
self.pendingRequest.p();
};
req.onerror = function onError() {
self.pendingRequest.p();
};
};
/**
* It enables the vibration.
* @memberOf SoundManager.prototype
* @param {Boolean} enabled the enable state of vibration.
*/
SoundManager.prototype.setVibrationEnabled = function sm_enableVib(enabled) {
this.setVibrationEnabledCount++;
SettingsListener.getSettingsLock().set({
'vibration.enabled': enabled
});
};
exports.SoundManager = SoundManager;
// XXX: we shoud move the code to bootstrap but it is so buggy to put there.
// So, we put here temporary.
exports.soundManager = new SoundManager();
if (navigator.mozL10n) {
// unit tests call start() manually
navigator.mozL10n.once(function() {
exports.soundManager.start();
});
}
})(window);