Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Bug 1157140 - Add MozChromeEvent and MozContentEvent to control the a…
Browse files Browse the repository at this point in the history
…udio channels in System app r=alive, dkuo
  • Loading branch information
evanxd committed May 13, 2015
1 parent 702e614 commit 38ced27
Show file tree
Hide file tree
Showing 5 changed files with 594 additions and 194 deletions.
181 changes: 137 additions & 44 deletions apps/system/js/audio_channel_controller.js
Expand Up @@ -9,11 +9,35 @@
/**
* AudioChannelController controls the audio channel to
* play or pause.
*
* There are two ways to create an AudioChannelController instance.
* One is for System app, and the other one is for other apps.
*
* Doing `new AudioChannelController('notification')`
* to create a controller for System app's notification audio channel.
*
* Doing `new AudioChannelController(musicApp, contentChannel)`
* to create a controller for Music app's content audio channel.
*
* @param {AppWindow|String} app
* If you want to create a controller for System app's audio channel,
* use a String.
* If you want to create a controller for other app's audio channel,
* use a AppWindow.
* @param {BrowserElementAudioChannel} channel
* An audio channel belongs to the app.
*/
var AudioChannelController = function(app, channel) {
this.app = app;
this.name = channel.name;
this._channel = channel;
this._isBelongedToSystemApp = app.instanceID === 'systemAppID';
if (this._isBelongedToSystemApp) {
window.addEventListener('mozChromeEvent', this);
} else {
app.element.addEventListener('_destroyed', this);
channel.addEventListener('activestatechanged', this);
}
this._states = {
active: false,
playing: false,
Expand All @@ -22,8 +46,6 @@
};
this._policy = {};
this._generateID();
channel.addEventListener('activestatechanged', this);
app.element.addEventListener('_destroyed', this);
};

AudioChannelController.prototype = Object.create(BaseUI.prototype);
Expand All @@ -50,6 +72,43 @@
case '_destroyed':
this.publish('destroyed');
break;

case 'mozChromeEvent':
var detail = evt.detail;
var name = detail.name;
switch (detail.type) {
case 'system-audiochannel-state-changed':
if (name === this.name) {
this._states.active = detail.isActive;
this.publish('statechanged');
}
break;

case 'system-audiochannel-mute-onsuccess':
name === this.name &&
this.debug('Set muting state of audio channel as ' +
detail.isMuted);
break;

case 'system-audiochannel-mute-onerror':
name === this.name &&
this.debug('Cannot set muting state of audio channel as ' +
detail.isMuted);
break;

case 'system-audiochannel-volume-onsuccess':
name === this.name &&
this.debug('Set volume of the audio channel as ' +
detail.volume);
break;

case 'system-audiochannel-volume-onerror':
name === this.name &&
this.debug('Cannot set volume of the audio channel as ' +
detail.volume);
break;
}
break;
}
};

Expand Down Expand Up @@ -137,20 +196,26 @@
*/
AudioChannelController.prototype._play = function() {
this._states.playing = true;
var promise = new Promise((resolve) => {
var request = this._channel.setMuted(false);
request.onsuccess = () => {
resolve();
};
request.onerror = () => {
throw 'Cannot play the audio channel.';
};
});
promise.then(() => {
this.app.debug('Play the audio channel.');
}).catch(e => {
this.app.debug(e);
});
if (this._isBelongedToSystemApp) {
this._sendContentEvent({
type: 'system-audiochannel-mute', isMuted: false
});
} else {
var promise = new Promise((resolve) => {
var request = this._channel.setMuted(false);
request.onsuccess = () => {
resolve();
};
request.onerror = () => {
throw 'Cannot play the audio channel.';
};
});
promise.then(() => {
this.app.debug('Play the audio channel.');
}).catch(e => {
this.app.debug(e);
});
}
};

/**
Expand All @@ -175,20 +240,26 @@
*/
AudioChannelController.prototype._pause = function() {
this._states.playing = false;
var promise = new Promise((resolve) => {
var request = this._channel.setMuted(true);
request.onsuccess = () => {
resolve();
};
request.onerror = () => {
throw 'Cannot pause the audio channel.';
};
});
promise.then(() => {
this.app.debug('Pause the audio channel');
}).catch(e => {
this.app.debug(e);
});
if (this._isBelongedToSystemApp) {
this._sendContentEvent({
type: 'system-audiochannel-mute', isMuted: true
});
} else {
var promise = new Promise((resolve) => {
var request = this._channel.setMuted(true);
request.onsuccess = () => {
resolve();
};
request.onerror = () => {
throw 'Cannot pause the audio channel.';
};
});
promise.then(() => {
this.app.debug('Pause the audio channel');
}).catch(e => {
this.app.debug(e);
});
}
};

/**
Expand All @@ -212,20 +283,26 @@
* @param {Number} volume 0 to 1.
*/
AudioChannelController.prototype._setVolume = function(volume) {
var promise = new Promise((resolve) => {
var request = this._channel.setVolume(volume);
request.onsuccess = () => {
resolve();
};
request.onerror = () => {
throw 'Cannot set volume of the audio channel.';
};
});
promise.then(() => {
this.app.debug('Set volume: ' + volume);
}).catch(e => {
this.app.debug(e);
});
if (this._isBelongedToSystemApp) {
this._sendContentEvent({
type: 'system-audiochannel-volume', volume: volume
});
} else {
var promise = new Promise((resolve) => {
var request = this._channel.setVolume(volume);
request.onsuccess = () => {
resolve();
};
request.onerror = () => {
throw 'Cannot set volume of the audio channel.';
};
});
promise.then(() => {
this.app.debug('Set volume: ' + volume);
}).catch(e => {
this.app.debug(e);
});
}
};

/**
Expand All @@ -235,5 +312,21 @@
this.instanceID = this.app.instanceID + '_' + this.name;
};

/**
* Send MozContentEvent to control the audio chanenl in System app.
*
* @param {Object} detail The arguments for passing to Gecko.
* @param {Object} detail.type The operation for the audio channel.
* @param {Object} detail.name The audio channel name you want to control.
* @param {Object} detail.volume The volume you want to set.
*/
AudioChannelController.prototype._sendContentEvent = function(detail) {
detail.name = this.name;
var evt = new CustomEvent('mozContentEvent', {
bubbles: true, cancelable: true, detail: detail
});
window.dispatchEvent(evt);
};

exports.AudioChannelController = AudioChannelController;
}(window));
3 changes: 2 additions & 1 deletion apps/system/js/core.js
Expand Up @@ -24,7 +24,8 @@
'CameraTrigger',
'FeatureDetector',
'AudioChannelService',
'Activities'
'Activities',
'SystemWindow'
];

Core.SERVICES = [
Expand Down
67 changes: 67 additions & 0 deletions apps/system/js/system_window.js
@@ -0,0 +1,67 @@
/* global AudioChannelController */
/* global BaseModule */
'use strict';

(function() {
/**
* SystemWindow is a placeholder for the system app's mozbrowser iframe
* but with no actual UI.
* We will use mozChromeEvent/mozContentEvent to communicate with shell.js
* to use the actual mozbrowser iframe of the system app.
*/
var SystemWindow = function() {};

SystemWindow.EVENTS = [
'mozChromeEvent'
];

BaseModule.create(SystemWindow, {
name: 'SystemWindow',
DEBUG: false,
// The fake app window ID of System app.
instanceID: null,
// The audio channels belong to System app.
audioChannels: null,

/**
* Initial the module.
*/
_start: function() {
this.instanceID = 'systemAppID';
this.audioChannels = new Map();
// Get System app's audio channels.
this._sendContentEvent({ type: 'system-audiochannel-list' });
},

/**
* Handle MozChromeEvent.
*
* @param {Event} evt The event to handle.
*/
_handle_mozChromeEvent: function(evt) {
var detail = evt.detail;
switch (detail.type) {
case 'system-audiochannel-list':
detail.audioChannels.forEach((name) => {
this.audioChannels.set(
name, new AudioChannelController(this, { name: name })
);
});
break;
}
},

/**
* Send MozContentEvent to control the audio chanenl in System app.
*
* @param {Object} detail The arguments for passing to Gecko.
* @param {Object} detail.type The operation for the audio channel.
*/
_sendContentEvent: function(detail) {
var evt = new CustomEvent('mozContentEvent', {
bubbles: true, cancelable: true, detail: detail
});
window.dispatchEvent(evt);
}
});
}());

0 comments on commit 38ced27

Please sign in to comment.