Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
120 lines
3 KiB
JavaScript
Executable file
120 lines
3 KiB
JavaScript
Executable file
/* global
|
|
AudioContext
|
|
*/
|
|
|
|
(function(exports) {
|
|
'use strict';
|
|
|
|
const SETTINGS = {
|
|
notificationVolume: 'audio.volume.notification',
|
|
vibration: 'vibration.enabled'
|
|
};
|
|
|
|
const ATTENTION_PATTERN = [4, 1, 2, 1, 2, 1];
|
|
ATTENTION_PATTERN.push(...ATTENTION_PATTERN);
|
|
|
|
const ATTENTION_SOUND_VOLUME = 0.3;
|
|
|
|
function getSetting(key) {
|
|
if (!navigator.mozSettings) {
|
|
return Promise.reject(new Error('The mozSettings API is not available.'));
|
|
}
|
|
|
|
return navigator.mozSettings.createLock().get(key).then(
|
|
(result) => result[key]
|
|
);
|
|
}
|
|
|
|
function getSettings(settings) {
|
|
return Promise.all(
|
|
settings.map(getSetting)
|
|
).catch((e) => {
|
|
// catch and log errors
|
|
console.error('Error while retrieving settings', e.message, e);
|
|
return settings.map(() => null);
|
|
}).then((results) => {
|
|
return settings.reduce((result, setting, i) => {
|
|
result[setting] = results[i];
|
|
return result;
|
|
}, {});
|
|
});
|
|
}
|
|
|
|
// Converts from the ATTENTION_PATTERN (suitable for the Vibration API) to a
|
|
// Float32Array suitable for the Audio API.
|
|
//
|
|
// The Float32Array will be interpolated so we just need to have the changes.
|
|
// Each value will last a "unit" of time.
|
|
function getAttentionCurveWave() {
|
|
var result = [];
|
|
var currentValue = ATTENTION_SOUND_VOLUME;
|
|
|
|
ATTENTION_PATTERN.forEach(duration => {
|
|
for (var i = 0; i < duration; i++) {
|
|
result.push(currentValue);
|
|
}
|
|
|
|
currentValue = ATTENTION_SOUND_VOLUME - currentValue;
|
|
});
|
|
|
|
return new Float32Array(result);
|
|
}
|
|
|
|
function ringtone() {
|
|
var audioChannel = 'notification';
|
|
var audioCtx = new AudioContext(audioChannel);
|
|
|
|
var o1 = audioCtx.createOscillator();
|
|
var o2 = audioCtx.createOscillator();
|
|
var gain = audioCtx.createGain();
|
|
|
|
var time = audioCtx.currentTime;
|
|
o1.type = o2.type = 'sine';
|
|
o1.frequency.value = 853;
|
|
o2.frequency.value = 960;
|
|
|
|
o1.start();
|
|
o2.start();
|
|
// Eventually stop the oscillator to allow garbage collecting.
|
|
o1.stop(time + 11);
|
|
o2.stop(time + 11);
|
|
|
|
var wave = getAttentionCurveWave();
|
|
gain.gain.setValueCurveAtTime(wave, time, 11);
|
|
|
|
o1.connect(gain);
|
|
o2.connect(gain);
|
|
gain.connect(audioCtx.destination);
|
|
}
|
|
|
|
function vibrate() {
|
|
var pattern = ATTENTION_PATTERN.map((value) => value * 500);
|
|
// vibration only works when App is in the foreground
|
|
if (document.hidden) {
|
|
window.addEventListener('visibilitychange', function waitOn() {
|
|
window.removeEventListener('visibilitychange', waitOn);
|
|
navigator.vibrate(pattern);
|
|
});
|
|
} else {
|
|
navigator.vibrate(pattern);
|
|
}
|
|
}
|
|
|
|
var Notify = {
|
|
notify: function notification_ringtone() {
|
|
return getSettings(
|
|
[SETTINGS.notificationVolume, SETTINGS.vibration]
|
|
).then((settings) => {
|
|
if (settings[SETTINGS.notificationVolume]) {
|
|
ringtone();
|
|
}
|
|
|
|
if (settings[SETTINGS.vibration]) {
|
|
vibrate();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.Notify = Notify;
|
|
}(this));
|