From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- mobile/android/chrome/content/CastingApps.js | 850 +++++++++++++++++++++++++++ 1 file changed, 850 insertions(+) create mode 100644 mobile/android/chrome/content/CastingApps.js (limited to 'mobile/android/chrome/content/CastingApps.js') diff --git a/mobile/android/chrome/content/CastingApps.js b/mobile/android/chrome/content/CastingApps.js new file mode 100644 index 000000000..76773c4d8 --- /dev/null +++ b/mobile/android/chrome/content/CastingApps.js @@ -0,0 +1,850 @@ +// -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +XPCOMUtils.defineLazyModuleGetter(this, "PageActions", + "resource://gre/modules/PageActions.jsm"); + +// Define service devices. We should consider moving these to their respective +// JSM files, but we left them here to allow for better lazy JSM loading. +var rokuDevice = { + id: "roku:ecp", + target: "roku:ecp", + factory: function(aService) { + Cu.import("resource://gre/modules/RokuApp.jsm"); + return new RokuApp(aService); + }, + types: ["video/mp4"], + extensions: ["mp4"] +}; + +var mediaPlayerDevice = { + id: "media:router", + target: "media:router", + factory: function(aService) { + Cu.import("resource://gre/modules/MediaPlayerApp.jsm"); + return new MediaPlayerApp(aService); + }, + types: ["video/mp4", "video/webm", "application/x-mpegurl"], + extensions: ["mp4", "webm", "m3u", "m3u8"], + init: function() { + Services.obs.addObserver(this, "MediaPlayer:Added", false); + Services.obs.addObserver(this, "MediaPlayer:Changed", false); + Services.obs.addObserver(this, "MediaPlayer:Removed", false); + }, + observe: function(subject, topic, data) { + if (topic === "MediaPlayer:Added") { + let service = this.toService(JSON.parse(data)); + SimpleServiceDiscovery.addService(service); + } else if (topic === "MediaPlayer:Changed") { + let service = this.toService(JSON.parse(data)); + SimpleServiceDiscovery.updateService(service); + } else if (topic === "MediaPlayer:Removed") { + SimpleServiceDiscovery.removeService(data); + } + }, + toService: function(display) { + // Convert the native data into something matching what is created in _processService() + return { + location: display.location, + target: "media:router", + friendlyName: display.friendlyName, + uuid: display.uuid, + manufacturer: display.manufacturer, + modelName: display.modelName, + mirror: display.mirror + }; + } +}; + +var fxOSTVDevice = { + id: "app://fling-player.gaiamobile.org", + target: "app://fling-player.gaiamobile.org/index.html", + factory: function(aService) { + Cu.import("resource://gre/modules/PresentationApp.jsm"); + let request = new window.PresentationRequest(this.target); + return new PresentationApp(aService, request); + }, + init: function() { + Services.obs.addObserver(this, "presentation-device-change", false); + SimpleServiceDiscovery.addExternalDiscovery(this); + }, + observe: function(subject, topic, data) { + let device = subject.QueryInterface(Ci.nsIPresentationDevice); + let service = this.toService(device); + switch (data) { + case "add": + SimpleServiceDiscovery.addService(service); + break; + case "update": + SimpleServiceDiscovery.updateService(service); + break; + case "remove": + if(SimpleServiceDiscovery.findServiceForID(device.id)) { + SimpleServiceDiscovery.removeService(device.id); + } + break; + } + }, + toService: function(device) { + return { + location: device.id, + target: fxOSTVDevice.target, + friendlyName: device.name, + uuid: device.id, + manufacturer: "Firefox OS TV", + modelName: "Firefox OS TV", + }; + }, + startDiscovery: function() { + window.navigator.mozPresentationDeviceInfo.forceDiscovery(); + + // need to update the lastPing time for known device. + window.navigator.mozPresentationDeviceInfo.getAll() + .then(function(devices) { + for (let device of devices) { + let service = fxOSTVDevice.toService(device); + SimpleServiceDiscovery.addService(service); + } + }); + }, + stopDiscovery: function() { + // do nothing + }, + types: ["video/mp4", "video/webm"], + extensions: ["mp4", "webm"], +}; + +var CastingApps = { + _castMenuId: -1, + mirrorStartMenuId: -1, + mirrorStopMenuId: -1, + _blocked: null, + _bound: null, + _interval: 120 * 1000, // 120 seconds + + init: function ca_init() { + if (!this.isCastingEnabled()) { + return; + } + + // Register targets + SimpleServiceDiscovery.registerDevice(rokuDevice); + + // MediaPlayerDevice will notify us any time the native device list changes. + mediaPlayerDevice.init(); + SimpleServiceDiscovery.registerDevice(mediaPlayerDevice); + + // Presentation Device will notify us any time the available device list changes. + if (window.PresentationRequest) { + fxOSTVDevice.init(); + SimpleServiceDiscovery.registerDevice(fxOSTVDevice); + } + + // Search for devices continuously + SimpleServiceDiscovery.search(this._interval); + + this._castMenuId = NativeWindow.contextmenus.add( + Strings.browser.GetStringFromName("contextmenu.sendToDevice"), + this.filterCast, + this.handleContextMenu.bind(this) + ); + + Services.obs.addObserver(this, "Casting:Play", false); + Services.obs.addObserver(this, "Casting:Pause", false); + Services.obs.addObserver(this, "Casting:Stop", false); + Services.obs.addObserver(this, "Casting:Mirror", false); + Services.obs.addObserver(this, "ssdp-service-found", false); + Services.obs.addObserver(this, "ssdp-service-lost", false); + Services.obs.addObserver(this, "application-background", false); + Services.obs.addObserver(this, "application-foreground", false); + + BrowserApp.deck.addEventListener("TabSelect", this, true); + BrowserApp.deck.addEventListener("pageshow", this, true); + BrowserApp.deck.addEventListener("playing", this, true); + BrowserApp.deck.addEventListener("ended", this, true); + BrowserApp.deck.addEventListener("MozAutoplayMediaBlocked", this, true); + // Note that the XBL binding is untrusted + BrowserApp.deck.addEventListener("MozNoControlsVideoBindingAttached", this, true, true); + }, + + _mirrorStarted: function(stopMirrorCallback) { + this.stopMirrorCallback = stopMirrorCallback; + NativeWindow.menu.update(this.mirrorStartMenuId, { visible: false }); + NativeWindow.menu.update(this.mirrorStopMenuId, { visible: true }); + }, + + serviceAdded: function(aService) { + if (this.isMirroringEnabled() && aService.mirror && this.mirrorStartMenuId == -1) { + this.mirrorStartMenuId = NativeWindow.menu.add({ + name: Strings.browser.GetStringFromName("casting.mirrorTab"), + callback: function() { + let callbackFunc = function(aService) { + let app = SimpleServiceDiscovery.findAppForService(aService); + if (app) { + app.mirror(function() {}, window, BrowserApp.selectedTab.getViewport(), this._mirrorStarted.bind(this), window.BrowserApp.selectedBrowser.contentWindow); + } + }.bind(this); + + this.prompt(callbackFunc, aService => aService.mirror); + }.bind(this), + parent: NativeWindow.menu.toolsMenuID + }); + + this.mirrorStopMenuId = NativeWindow.menu.add({ + name: Strings.browser.GetStringFromName("casting.mirrorTabStop"), + callback: function() { + if (this.tabMirror) { + this.tabMirror.stop(); + this.tabMirror = null; + } else if (this.stopMirrorCallback) { + this.stopMirrorCallback(); + this.stopMirrorCallback = null; + } + NativeWindow.menu.update(this.mirrorStartMenuId, { visible: true }); + NativeWindow.menu.update(this.mirrorStopMenuId, { visible: false }); + }.bind(this), + }); + } + if (this.mirrorStartMenuId != -1) { + NativeWindow.menu.update(this.mirrorStopMenuId, { visible: false }); + } + }, + + serviceLost: function(aService) { + if (aService.mirror && this.mirrorStartMenuId != -1) { + let haveMirror = false; + SimpleServiceDiscovery.services.forEach(function(service) { + if (service.mirror) { + haveMirror = true; + } + }); + if (!haveMirror) { + NativeWindow.menu.remove(this.mirrorStartMenuId); + this.mirrorStartMenuId = -1; + } + } + }, + + isCastingEnabled: function isCastingEnabled() { + return Services.prefs.getBoolPref("browser.casting.enabled"); + }, + + isMirroringEnabled: function isMirroringEnabled() { + return Services.prefs.getBoolPref("browser.mirroring.enabled"); + }, + + observe: function (aSubject, aTopic, aData) { + switch (aTopic) { + case "Casting:Play": + if (this.session && this.session.remoteMedia.status == "paused") { + this.session.remoteMedia.play(); + } + break; + case "Casting:Pause": + if (this.session && this.session.remoteMedia.status == "started") { + this.session.remoteMedia.pause(); + } + break; + case "Casting:Stop": + if (this.session) { + this.closeExternal(); + } + break; + case "Casting:Mirror": + { + Cu.import("resource://gre/modules/TabMirror.jsm"); + this.tabMirror = new TabMirror(aData, window); + NativeWindow.menu.update(this.mirrorStartMenuId, { visible: false }); + NativeWindow.menu.update(this.mirrorStopMenuId, { visible: true }); + } + break; + case "ssdp-service-found": + this.serviceAdded(SimpleServiceDiscovery.findServiceForID(aData)); + break; + case "ssdp-service-lost": + this.serviceLost(SimpleServiceDiscovery.findServiceForID(aData)); + break; + case "application-background": + // Turn off polling while in the background + this._interval = SimpleServiceDiscovery.search(0); + SimpleServiceDiscovery.stopSearch(); + break; + case "application-foreground": + // Turn polling on when app comes back to foreground + SimpleServiceDiscovery.search(this._interval); + break; + } + }, + + handleEvent: function(aEvent) { + switch (aEvent.type) { + case "TabSelect": { + let tab = BrowserApp.getTabForBrowser(aEvent.target); + this._updatePageActionForTab(tab, aEvent); + break; + } + case "pageshow": { + let tab = BrowserApp.getTabForWindow(aEvent.originalTarget.defaultView); + this._updatePageActionForTab(tab, aEvent); + break; + } + case "playing": + case "ended": { + let video = aEvent.target; + if (video instanceof HTMLVideoElement) { + // If playing, send the