diff --git a/mobile/android/actors/GeckoViewPermissionChild.jsm b/mobile/android/actors/GeckoViewPermissionChild.jsm index a0278cbe13095..e075e91fbaac1 100644 --- a/mobile/android/actors/GeckoViewPermissionChild.jsm +++ b/mobile/android/actors/GeckoViewPermissionChild.jsm @@ -35,6 +35,13 @@ class GeckoViewPermissionChild extends GeckoViewActorChild { return this.sendQuery("GetAppPermissions", aPermissions); } + mediaRecordingStatusChanged(aDevices) { + return this.eventDispatcher.sendRequest({ + type: "GeckoView:MediaRecordingStatusChanged", + devices: aDevices, + }); + } + async promptPermission(aRequest) { // Only allow exactly one permission request here. const types = aRequest.types.QueryInterface(Ci.nsIArray); diff --git a/mobile/android/actors/GeckoViewPermissionProcessChild.jsm b/mobile/android/actors/GeckoViewPermissionProcessChild.jsm index c89ef659a1251..d779eeccb407b 100644 --- a/mobile/android/actors/GeckoViewPermissionProcessChild.jsm +++ b/mobile/android/actors/GeckoViewPermissionProcessChild.jsm @@ -12,8 +12,27 @@ const { GeckoViewUtils } = ChromeUtils.import( "resource://gre/modules/GeckoViewUtils.jsm" ); const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +XPCOMUtils.defineLazyServiceGetter( + this, + "MediaManagerService", + "@mozilla.org/mediaManagerService;1", + "nsIMediaManagerService" +); + +const STATUS_RECORDING = "recording"; +const STATUS_INACTIVE = "inactive"; +const TYPE_CAMERA = "camera"; +const TYPE_MICROPHONE = "microphone"; class GeckoViewPermissionProcessChild extends JSProcessActorChild { + getActor(window) { + return window.windowGlobalChild.getActor("GeckoViewPermission"); + } + /* ---------- nsIObserver ---------- */ async observe(aSubject, aTopic, aData) { switch (aTopic) { @@ -45,7 +64,60 @@ class GeckoViewPermissionProcessChild extends JSProcessActorChild { ); break; } + case "recording-device-events": { + this.handleRecordingDeviceEvents(aSubject); + break; + } + } + } + + handleRecordingDeviceEvents(aRequest) { + aRequest.QueryInterface(Ci.nsIPropertyBag2); + const contentWindow = aRequest.getProperty("window"); + const devices = []; + + const getStatusString = function(activityStatus) { + switch (activityStatus) { + case MediaManagerService.STATE_CAPTURE_ENABLED: + case MediaManagerService.STATE_CAPTURE_DISABLED: + return STATUS_RECORDING; + case MediaManagerService.STATE_NOCAPTURE: + return STATUS_INACTIVE; + default: + throw new Error("Unexpected activityStatus value"); + } + }; + + const hasCamera = {}; + const hasMicrophone = {}; + const screen = {}; + const window = {}; + const browser = {}; + const mediaDevices = {}; + MediaManagerService.mediaCaptureWindowState( + contentWindow, + hasCamera, + hasMicrophone, + screen, + window, + browser, + mediaDevices + ); + var cameraStatus = getStatusString(hasCamera.value); + var microphoneStatus = getStatusString(hasMicrophone.value); + if (hasCamera.value != MediaManagerService.STATE_NOCAPTURE) { + devices.push({ + type: TYPE_CAMERA, + status: cameraStatus, + }); + } + if (hasMicrophone.value != MediaManagerService.STATE_NOCAPTURE) { + devices.push({ + type: TYPE_MICROPHONE, + status: microphoneStatus, + }); } + this.getActor(contentWindow).mediaRecordingStatusChanged(devices); } async handleMediaRequest(aRequest) { @@ -84,17 +156,15 @@ class GeckoViewPermissionProcessChild extends JSProcessActorChild { return null; } - const response = await window.windowGlobalChild - .getActor("GeckoViewPermission") - .getMediaPermission({ - uri: window.document.documentURI, - video: constraints.video - ? sources.filter(source => source.type === "videoinput") - : null, - audio: constraints.audio - ? sources.filter(source => source.type === "audioinput") - : null, - }); + const response = await this.getActor(window).getMediaPermission({ + uri: window.document.documentURI, + video: constraints.video + ? sources.filter(source => source.type === "videoinput") + : null, + audio: constraints.audio + ? sources.filter(source => source.type === "audioinput") + : null, + }); if (!response) { // Rejected. @@ -110,9 +180,7 @@ class GeckoViewPermissionProcessChild extends JSProcessActorChild { Cu.reportError("Media device error: invalid video id"); return null; } - await window.windowGlobalChild - .getActor("GeckoViewPermission") - .addCameraPermission(); + await this.getActor(window).addCameraPermission(); allowedDevices.appendElement(video); } if (constraints.audio) { diff --git a/mobile/android/components/geckoview/GeckoViewStartup.jsm b/mobile/android/components/geckoview/GeckoViewStartup.jsm index 9179d4ed0ce1a..316464efbfa48 100644 --- a/mobile/android/components/geckoview/GeckoViewStartup.jsm +++ b/mobile/android/components/geckoview/GeckoViewStartup.jsm @@ -39,6 +39,7 @@ const JSPROCESSACTORS = { observers: [ "getUserMedia:ask-device-permission", "getUserMedia:request", + "recording-device-events", "PeerConnection:request", ], }, @@ -99,12 +100,6 @@ class GeckoViewStartup { switch (aTopic) { case "content-process-ready-for-script": case "app-startup": { - // Parent and content process. - GeckoViewUtils.addLazyGetter(this, "GeckoViewRecordingMedia", { - module: "resource://gre/modules/GeckoViewMedia.jsm", - observers: ["recording-device-events"], - }); - GeckoViewUtils.addLazyGetter(this, "GeckoViewConsole", { module: "resource://gre/modules/GeckoViewConsole.jsm", }); diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/MediaDelegateXOriginTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/MediaDelegateXOriginTest.kt index 3f9ec055899b6..42d513e7e1e25 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/MediaDelegateXOriginTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/MediaDelegateXOriginTest.kt @@ -148,9 +148,6 @@ class MediaDelegateXOriginTest : BaseSessionTest() { } @Test fun testDeviceRecordingEventAudioAndVideoInXOriginIframe() { - // TODO: Bug 1648153 - assumeThat(sessionRule.env.isFission, Matchers.equalTo(false)) - // TODO: needs bug 1700243 assumeThat(sessionRule.env.isIsolatedProcess, Matchers.equalTo(false)) @@ -166,9 +163,6 @@ class MediaDelegateXOriginTest : BaseSessionTest() { } @Test fun testDeviceRecordingEventAudioAndVideoInXOriginIframeNoAllow() { - // TODO: Bug 1648153 - assumeThat(sessionRule.env.isFission, Matchers.equalTo(false)) - mainSession.loadTestPath(GETUSERMEDIA_XORIGIN_CONTAINER_HTML_PATH) mainSession.waitForPageStop() diff --git a/mobile/android/modules/geckoview/GeckoViewMedia.jsm b/mobile/android/modules/geckoview/GeckoViewMedia.jsm deleted file mode 100644 index 05f17cbe955df..0000000000000 --- a/mobile/android/modules/geckoview/GeckoViewMedia.jsm +++ /dev/null @@ -1,100 +0,0 @@ -/* 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"; - -var EXPORTED_SYMBOLS = ["GeckoViewRecordingMedia"]; - -const { GeckoViewUtils } = ChromeUtils.import( - "resource://gre/modules/GeckoViewUtils.jsm" -); -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -XPCOMUtils.defineLazyServiceGetter( - this, - "MediaManagerService", - "@mozilla.org/mediaManagerService;1", - "nsIMediaManagerService" -); - -const STATUS_RECORDING = "recording"; -const STATUS_INACTIVE = "inactive"; -const TYPE_CAMERA = "camera"; -const TYPE_MICROPHONE = "microphone"; - -const GeckoViewRecordingMedia = { - // The event listener for this is hooked up in GeckoViewStartup.jsm - observe(aSubject, aTopic, aData) { - debug`observe: aTopic=${aTopic}`; - switch (aTopic) { - case "recording-device-events": { - this.handleRecordingDeviceEvents(); - break; - } - } - }, - - handleRecordingDeviceEvents() { - const [dispatcher] = GeckoViewUtils.getActiveDispatcherAndWindow(); - if (dispatcher) { - const windows = MediaManagerService.activeMediaCaptureWindows; - const devices = []; - - const getStatusString = function(activityStatus) { - switch (activityStatus) { - case MediaManagerService.STATE_CAPTURE_ENABLED: - case MediaManagerService.STATE_CAPTURE_DISABLED: - return STATUS_RECORDING; - case MediaManagerService.STATE_NOCAPTURE: - return STATUS_INACTIVE; - default: - throw new Error("Unexpected activityStatus value"); - } - }; - - for (let i = 0; i < windows.length; i++) { - const win = windows.queryElementAt(i, Ci.nsIDOMWindow); - const hasCamera = {}; - const hasMicrophone = {}; - const screen = {}; - const window = {}; - const browser = {}; - const mediaDevices = {}; - MediaManagerService.mediaCaptureWindowState( - win, - hasCamera, - hasMicrophone, - screen, - window, - browser, - mediaDevices - ); - var cameraStatus = getStatusString(hasCamera.value); - var microphoneStatus = getStatusString(hasMicrophone.value); - if (hasCamera.value != MediaManagerService.STATE_NOCAPTURE) { - devices.push({ - type: TYPE_CAMERA, - status: cameraStatus, - }); - } - if (hasMicrophone.value != MediaManagerService.STATE_NOCAPTURE) { - devices.push({ - type: TYPE_MICROPHONE, - status: microphoneStatus, - }); - } - } - dispatcher.sendRequestForResult({ - type: "GeckoView:MediaRecordingStatusChanged", - devices, - }); - } else { - console.log("no dispatcher present"); - } - }, -}; - -const { debug, warn } = GeckoViewUtils.initLogging("GeckoViewMedia"); diff --git a/mobile/android/modules/geckoview/moz.build b/mobile/android/modules/geckoview/moz.build index 7330f0cb29640..766a8c9a27f48 100644 --- a/mobile/android/modules/geckoview/moz.build +++ b/mobile/android/modules/geckoview/moz.build @@ -18,7 +18,6 @@ EXTRA_JS_MODULES += [ "GeckoViewConsole.jsm", "GeckoViewContent.jsm", "GeckoViewContentBlocking.jsm", - "GeckoViewMedia.jsm", "GeckoViewMediaControl.jsm", "GeckoViewModule.jsm", "GeckoViewNavigation.jsm",