mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 946454 - [Roku] Show 'casting' button in the video controls r=wesj, dolske
This commit is contained in:
parent
b14d01f56e
commit
78297a38af
@ -29,6 +29,7 @@
|
||||
|
||||
.fullscreenButton,
|
||||
.playButton,
|
||||
.castingButton,
|
||||
.muteButton {
|
||||
-moz-appearance: none;
|
||||
min-height: 42px;
|
||||
@ -62,6 +63,10 @@
|
||||
background: url("chrome://b2g/content/images/play-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
||||
.castingButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.muteButton {
|
||||
background: url("chrome://b2g/content/images/mute-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
.fullscreenButton,
|
||||
.playButton,
|
||||
.castingButton,
|
||||
.muteButton {
|
||||
-moz-appearance: none;
|
||||
min-height: 42px;
|
||||
@ -62,6 +63,10 @@
|
||||
background: url("chrome://browser/skin/images/play-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
||||
.castingButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.muteButton {
|
||||
background: url("chrome://browser/skin/images/mute-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
@ -63,6 +63,47 @@ var CastingApps = {
|
||||
}
|
||||
},
|
||||
|
||||
_sendEventToVideo: function _sendEventToVideo(aElement, aData) {
|
||||
let event = aElement.ownerDocument.createEvent("CustomEvent");
|
||||
event.initCustomEvent("media-videoCasting", false, true, JSON.stringify(aData));
|
||||
aElement.dispatchEvent(event);
|
||||
},
|
||||
|
||||
handleVideoBindingAttached: function handleVideoBindingAttached(aTab, aEvent) {
|
||||
// Let's figure out if we have everything needed to cast a video. The binding
|
||||
// defaults to |false| so we only need to send an event if |true|.
|
||||
let video = aEvent.target;
|
||||
if (!video instanceof HTMLVideoElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SimpleServiceDiscovery.services.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.getVideo(video, 0, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the binding know casting is allowed
|
||||
this._sendEventToVideo(video, { allow: true });
|
||||
},
|
||||
|
||||
handleVideoBindingCast: function handleVideoBindingCast(aTab, aEvent) {
|
||||
// The binding wants to start a casting session
|
||||
let video = aEvent.target;
|
||||
if (!video instanceof HTMLVideoElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close an existing session first. closeExternal has checks for an exsting
|
||||
// session and handles remote and video binding shutdown.
|
||||
this.closeExternal();
|
||||
|
||||
// Start the new session
|
||||
this.openExternal(video, 0, 0);
|
||||
},
|
||||
|
||||
makeURI: function makeURI(aURL, aOriginCharset, aBaseURI) {
|
||||
return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
|
||||
},
|
||||
@ -221,7 +262,8 @@ var CastingApps = {
|
||||
title: video.title,
|
||||
source: video.source,
|
||||
poster: video.poster
|
||||
}
|
||||
},
|
||||
videoRef: Cu.getWeakReference(video.element)
|
||||
};
|
||||
}.bind(this), this);
|
||||
}.bind(this));
|
||||
@ -236,6 +278,12 @@ var CastingApps = {
|
||||
|
||||
this.session.remoteMedia.shutdown();
|
||||
this.session.app.stop();
|
||||
|
||||
let video = this.session.videoRef.get();
|
||||
if (video) {
|
||||
this._sendEventToVideo(video, { active: false });
|
||||
}
|
||||
|
||||
delete this.session;
|
||||
},
|
||||
|
||||
@ -247,6 +295,11 @@ var CastingApps = {
|
||||
|
||||
aRemoteMedia.load(this.session.data);
|
||||
sendMessageToJava({ type: "Casting:Started", device: this.session.service.friendlyName });
|
||||
|
||||
let video = this.session.videoRef.get();
|
||||
if (video) {
|
||||
this._sendEventToVideo(video, { active: true });
|
||||
}
|
||||
},
|
||||
|
||||
onRemoteMediaStop: function(aRemoteMedia) {
|
||||
|
@ -3010,11 +3010,14 @@ Tab.prototype = {
|
||||
this.browser.addEventListener("blur", this, true);
|
||||
this.browser.addEventListener("scroll", this, true);
|
||||
this.browser.addEventListener("MozScrolledAreaChanged", this, true);
|
||||
// Note that the XBL binding is untrusted
|
||||
this.browser.addEventListener("PluginBindingAttached", this, true, true);
|
||||
this.browser.addEventListener("pageshow", this, true);
|
||||
this.browser.addEventListener("MozApplicationManifest", this, true);
|
||||
|
||||
// Note that the XBL binding is untrusted
|
||||
this.browser.addEventListener("PluginBindingAttached", this, true, true);
|
||||
this.browser.addEventListener("VideoBindingAttached", this, true, true);
|
||||
this.browser.addEventListener("VideoBindingCast", this, true, true);
|
||||
|
||||
Services.obs.addObserver(this, "before-first-paint", false);
|
||||
Services.obs.addObserver(this, "after-viewport-change", false);
|
||||
Services.prefs.addObserver("browser.ui.zoom.force-user-scalable", this, false);
|
||||
@ -3179,10 +3182,13 @@ Tab.prototype = {
|
||||
this.browser.removeEventListener("blur", this, true);
|
||||
this.browser.removeEventListener("scroll", this, true);
|
||||
this.browser.removeEventListener("MozScrolledAreaChanged", this, true);
|
||||
this.browser.removeEventListener("PluginBindingAttached", this, true);
|
||||
this.browser.removeEventListener("pageshow", this, true);
|
||||
this.browser.removeEventListener("MozApplicationManifest", this, true);
|
||||
|
||||
this.browser.removeEventListener("PluginBindingAttached", this, true, true);
|
||||
this.browser.removeEventListener("VideoBindingAttached", this, true, true);
|
||||
this.browser.removeEventListener("VideoBindingCast", this, true, true);
|
||||
|
||||
Services.obs.removeObserver(this, "before-first-paint");
|
||||
Services.obs.removeObserver(this, "after-viewport-change");
|
||||
Services.prefs.removeObserver("browser.ui.zoom.force-user-scalable", this);
|
||||
@ -3934,6 +3940,16 @@ Tab.prototype = {
|
||||
break;
|
||||
}
|
||||
|
||||
case "VideoBindingAttached": {
|
||||
CastingApps.handleVideoBindingAttached(this, aEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
case "VideoBindingCast": {
|
||||
CastingApps.handleVideoBindingCast(this, aEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
case "MozApplicationManifest": {
|
||||
OfflineApps.offlineAppRequested(aEvent.originalTarget.defaultView);
|
||||
break;
|
||||
|
BIN
mobile/android/themes/core/images/cast-active-hdpi.png
Normal file
BIN
mobile/android/themes/core/images/cast-active-hdpi.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 684 B |
BIN
mobile/android/themes/core/images/cast-ready-hdpi.png
Normal file
BIN
mobile/android/themes/core/images/cast-ready-hdpi.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 542 B |
@ -62,6 +62,8 @@ chrome.jar:
|
||||
skin/images/search-clear-30.png (images/search-clear-30.png)
|
||||
skin/images/play-hdpi.png (images/play-hdpi.png)
|
||||
skin/images/pause-hdpi.png (images/pause-hdpi.png)
|
||||
skin/images/cast-ready-hdpi.png (images/cast-ready-hdpi.png)
|
||||
skin/images/cast-active-hdpi.png (images/cast-active-hdpi.png)
|
||||
skin/images/mute-hdpi.png (images/mute-hdpi.png)
|
||||
skin/images/unmute-hdpi.png (images/unmute-hdpi.png)
|
||||
skin/images/scrubber-hdpi.png (images/scrubber-hdpi.png)
|
||||
|
@ -28,6 +28,7 @@
|
||||
}
|
||||
|
||||
.playButton,
|
||||
.castingButton,
|
||||
.muteButton {
|
||||
-moz-appearance: none;
|
||||
min-height: 42px;
|
||||
@ -44,6 +45,14 @@
|
||||
background: url("chrome://browser/skin/images/play-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
||||
.castingButton {
|
||||
background: url("chrome://browser/skin/images/cast-ready-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
||||
.castingButton[active="true"] {
|
||||
background: url("chrome://browser/skin/images/cast-active-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
||||
.muteButton {
|
||||
background: url("chrome://browser/skin/images/mute-hdpi.png") no-repeat center;
|
||||
}
|
||||
|
@ -1527,6 +1527,8 @@
|
||||
</box>
|
||||
<vbox class="controlBar" hidden="true">
|
||||
<hbox class="buttonsBar">
|
||||
<button class="castingButton" hidden="true"
|
||||
aria-label="&castingButton.castingLabel;"/>
|
||||
<button class="fullscreenButton"
|
||||
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
|
||||
exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
|
||||
@ -1566,9 +1568,11 @@
|
||||
this.isTouchControl = true;
|
||||
this.TouchUtils = {
|
||||
videocontrols: null,
|
||||
controlsTimer : null,
|
||||
controlsTimeout : 5000,
|
||||
video: null,
|
||||
controlsTimer: null,
|
||||
controlsTimeout: 5000,
|
||||
positionLabel: null,
|
||||
castingButton: null,
|
||||
|
||||
get Utils() {
|
||||
return this.videocontrols.Utils;
|
||||
@ -1640,13 +1644,59 @@
|
||||
this.Utils.video.removeEventListener(event, this, false);
|
||||
},
|
||||
|
||||
isVideoCasting : function () {
|
||||
let unwrappedVideo = XPCNativeWrapper.unwrap(this.video);
|
||||
if (unwrappedVideo.mozIsCasting)
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
updateCasting : function (eventDetail) {
|
||||
let unwrappedVideo = XPCNativeWrapper.unwrap(this.video);
|
||||
let castingData = JSON.parse(eventDetail);
|
||||
if ("allow" in castingData) {
|
||||
if (castingData.allow)
|
||||
unwrappedVideo.mozAllowCasting = true;
|
||||
else
|
||||
delete unwrappedVideo.mozAllowCasting;
|
||||
}
|
||||
|
||||
if ("active" in castingData) {
|
||||
if (castingData.active)
|
||||
unwrappedVideo.mozIsCasting = true;
|
||||
else
|
||||
delete unwrappedVideo.mozIsCasting;
|
||||
}
|
||||
this.setCastButtonState();
|
||||
},
|
||||
|
||||
startCasting : function () {
|
||||
this.videocontrols.dispatchEvent(new CustomEvent("VideoBindingCast"));
|
||||
},
|
||||
|
||||
setCastButtonState : function () {
|
||||
let unwrappedVideo = XPCNativeWrapper.unwrap(this.video);
|
||||
if (this.isAudioOnly || !unwrappedVideo.mozAllowCasting) {
|
||||
this.castingButton.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (unwrappedVideo.mozIsCasting) {
|
||||
this.castingButton.setAttribute("active", "true");
|
||||
} else {
|
||||
this.castingButton.removeAttribute("active");
|
||||
}
|
||||
|
||||
this.castingButton.hidden = false;
|
||||
},
|
||||
|
||||
init : function (binding) {
|
||||
this.videocontrols = binding;
|
||||
var video = binding.parentNode;
|
||||
this.video = binding.parentNode;
|
||||
|
||||
let self = this;
|
||||
this.Utils.playButton.addEventListener("command", function() {
|
||||
if (!self.Utils.video.paused)
|
||||
if (!self.video.paused)
|
||||
self.delayHideControls(0);
|
||||
else
|
||||
self.showControls();
|
||||
@ -1659,26 +1709,38 @@
|
||||
}, false);
|
||||
this.Utils.muteButton.addEventListener("click", function() { self.delayHideControls(self.controlsTimeout); }, false);
|
||||
|
||||
this.castingButton = document.getAnonymousElementByAttribute(binding, "class", "castingButton");
|
||||
this.castingButton.addEventListener("command", function() {
|
||||
self.startCasting();
|
||||
}, false);
|
||||
|
||||
this.video.addEventListener("media-videoCasting", function (e) {
|
||||
if (!e.isTrusted)
|
||||
return;
|
||||
self.updateCasting(e.detail);
|
||||
}, false, true);
|
||||
|
||||
// The first time the controls appear we want to just display
|
||||
// a play button that does not fade away. The firstShow property
|
||||
// makes that happen. But because of bug 718107 this init() method
|
||||
// may be called again when we switch in or out of fullscreen
|
||||
// mode. So we only set firstShow if we're not autoplaying and
|
||||
// if we are at the beginning of the video and not already playing
|
||||
if (!video.autoplay && this.Utils.dynamicControls && video.paused &&
|
||||
video.currentTime === 0)
|
||||
if (!this.video.autoplay && this.Utils.dynamicControls && this.video.paused &&
|
||||
this.video.currentTime === 0)
|
||||
this.firstShow = true;
|
||||
|
||||
// If the video is not at the start, then we probably just
|
||||
// transitioned into or out of fullscreen mode, and we don't want
|
||||
// the controls to remain visible. this.controlsTimeout is a full
|
||||
// 5s, which feels too long after the transition.
|
||||
if (video.currentTime !== 0) {
|
||||
if (this.video.currentTime !== 0) {
|
||||
this.delayHideControls(this.Utils.HIDE_CONTROLS_TIMEOUT_MS);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.TouchUtils.init(this);
|
||||
this.dispatchEvent(new CustomEvent("VideoBindingAttached"));
|
||||
]]>
|
||||
</constructor>
|
||||
<destructor>
|
||||
|
@ -8,6 +8,7 @@
|
||||
<!ENTITY muteButton.unmuteLabel "Unmute">
|
||||
<!ENTITY fullscreenButton.enterfullscreenlabel "Full Screen">
|
||||
<!ENTITY fullscreenButton.exitfullscreenlabel "Exit Full Screen">
|
||||
<!ENTITY castingButton.castingLabel "Cast to Screen">
|
||||
|
||||
<!ENTITY stats.media "Media">
|
||||
<!ENTITY stats.size "Size">
|
||||
|
Loading…
Reference in New Issue
Block a user