Richard Pospesel pushed to branch android-components-102.0.14-12.0-1 at The Tor Project / Applications / android-components
Commits:
-
b65622fa
by Arturo Mejia at 2022-08-30T21:22:54+00:00
4 changed files:
- components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt
- + components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMediaDelegate.kt
- components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt
- + components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaDelegateTest.kt
Changes:
| ... | ... | @@ -16,6 +16,7 @@ import kotlinx.coroutines.MainScope |
| 16 | 16 | import kotlinx.coroutines.launch
|
| 17 | 17 | import mozilla.components.browser.engine.gecko.ext.isExcludedForTrackingProtection
|
| 18 | 18 | import mozilla.components.browser.engine.gecko.fetch.toResponse
|
| 19 | +import mozilla.components.browser.engine.gecko.media.GeckoMediaDelegate
|
|
| 19 | 20 | import mozilla.components.browser.engine.gecko.mediasession.GeckoMediaSessionDelegate
|
| 20 | 21 | import mozilla.components.browser.engine.gecko.permission.GeckoPermissionRequest
|
| 21 | 22 | import mozilla.components.browser.engine.gecko.prompt.GeckoPromptDelegate
|
| ... | ... | @@ -1098,6 +1099,7 @@ class GeckoEngineSession( |
| 1098 | 1099 | geckoSession.contentBlockingDelegate = createContentBlockingDelegate()
|
| 1099 | 1100 | geckoSession.permissionDelegate = createPermissionDelegate()
|
| 1100 | 1101 | geckoSession.promptDelegate = GeckoPromptDelegate(this)
|
| 1102 | + geckoSession.mediaDelegate = GeckoMediaDelegate(this)
|
|
| 1101 | 1103 | geckoSession.historyDelegate = createHistoryDelegate()
|
| 1102 | 1104 | geckoSession.mediaSessionDelegate = GeckoMediaSessionDelegate(this)
|
| 1103 | 1105 | geckoSession.scrollDelegate = createScrollDelegate()
|
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 4 | + |
|
| 5 | +package mozilla.components.browser.engine.gecko.media
|
|
| 6 | + |
|
| 7 | +import androidx.annotation.VisibleForTesting
|
|
| 8 | +import mozilla.components.browser.engine.gecko.GeckoEngineSession
|
|
| 9 | +import mozilla.components.concept.engine.media.RecordingDevice
|
|
| 10 | +import org.mozilla.geckoview.GeckoSession
|
|
| 11 | +import java.security.InvalidParameterException
|
|
| 12 | +import org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice as GeckoRecordingDevice
|
|
| 13 | + |
|
| 14 | +/**
|
|
| 15 | + * Gecko-based GeckoMediaDelegate implementation.
|
|
| 16 | + */
|
|
| 17 | +internal class GeckoMediaDelegate(private val geckoEngineSession: GeckoEngineSession) :
|
|
| 18 | + GeckoSession.MediaDelegate {
|
|
| 19 | + |
|
| 20 | + override fun onRecordingStatusChanged(
|
|
| 21 | + session: GeckoSession,
|
|
| 22 | + geckoDevices: Array<out GeckoRecordingDevice>
|
|
| 23 | + ) {
|
|
| 24 | + val devices = geckoDevices.map { geckoRecording ->
|
|
| 25 | + val type = geckoRecording.toType()
|
|
| 26 | + val status = geckoRecording.toStatus()
|
|
| 27 | + RecordingDevice(type, status)
|
|
| 28 | + }
|
|
| 29 | + geckoEngineSession.notifyObservers { onRecordingStateChanged(devices) }
|
|
| 30 | + }
|
|
| 31 | +}
|
|
| 32 | + |
|
| 33 | +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
| 34 | +internal fun GeckoRecordingDevice.toType(): RecordingDevice.Type {
|
|
| 35 | + return when (type) {
|
|
| 36 | + GeckoRecordingDevice.Type.CAMERA -> RecordingDevice.Type.CAMERA
|
|
| 37 | + GeckoRecordingDevice.Type.MICROPHONE -> RecordingDevice.Type.MICROPHONE
|
|
| 38 | + else -> {
|
|
| 39 | + throw InvalidParameterException("Unexpected Gecko Media type $type status $status")
|
|
| 40 | + }
|
|
| 41 | + }
|
|
| 42 | +}
|
|
| 43 | + |
|
| 44 | +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
| 45 | +internal fun GeckoRecordingDevice.toStatus(): RecordingDevice.Status {
|
|
| 46 | + return when (status) {
|
|
| 47 | + GeckoRecordingDevice.Status.RECORDING -> RecordingDevice.Status.RECORDING
|
|
| 48 | + GeckoRecordingDevice.Status.INACTIVE -> RecordingDevice.Status.INACTIVE
|
|
| 49 | + else -> {
|
|
| 50 | + throw InvalidParameterException("Unexpected Gecko Media type $type status $status")
|
|
| 51 | + }
|
|
| 52 | + }
|
|
| 53 | +} |
| ... | ... | @@ -113,6 +113,7 @@ class GeckoEngineSessionTest { |
| 113 | 113 | |
| 114 | 114 | private lateinit var navigationDelegate: ArgumentCaptor<GeckoSession.NavigationDelegate>
|
| 115 | 115 | private lateinit var progressDelegate: ArgumentCaptor<GeckoSession.ProgressDelegate>
|
| 116 | + private lateinit var mediaDelegate: ArgumentCaptor<GeckoSession.MediaDelegate>
|
|
| 116 | 117 | private lateinit var contentDelegate: ArgumentCaptor<GeckoSession.ContentDelegate>
|
| 117 | 118 | private lateinit var permissionDelegate: ArgumentCaptor<GeckoSession.PermissionDelegate>
|
| 118 | 119 | private lateinit var contentBlockingDelegate: ArgumentCaptor<ContentBlocking.Delegate>
|
| ... | ... | @@ -140,6 +141,7 @@ class GeckoEngineSessionTest { |
| 140 | 141 | whenever(runtime.settings).thenReturn(mock())
|
| 141 | 142 | navigationDelegate = ArgumentCaptor.forClass(GeckoSession.NavigationDelegate::class.java)
|
| 142 | 143 | progressDelegate = ArgumentCaptor.forClass(GeckoSession.ProgressDelegate::class.java)
|
| 144 | + mediaDelegate = ArgumentCaptor.forClass(GeckoSession.MediaDelegate::class.java)
|
|
| 143 | 145 | contentDelegate = ArgumentCaptor.forClass(GeckoSession.ContentDelegate::class.java)
|
| 144 | 146 | permissionDelegate = ArgumentCaptor.forClass(GeckoSession.PermissionDelegate::class.java)
|
| 145 | 147 | contentBlockingDelegate = ArgumentCaptor.forClass(ContentBlocking.Delegate::class.java)
|
| ... | ... | @@ -156,6 +158,7 @@ class GeckoEngineSessionTest { |
| 156 | 158 | verify(geckoSession).permissionDelegate = permissionDelegate.capture()
|
| 157 | 159 | verify(geckoSession).contentBlockingDelegate = contentBlockingDelegate.capture()
|
| 158 | 160 | verify(geckoSession).historyDelegate = historyDelegate.capture()
|
| 161 | + verify(geckoSession).mediaDelegate = mediaDelegate.capture()
|
|
| 159 | 162 | }
|
| 160 | 163 | |
| 161 | 164 | @Test
|
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 4 | + |
|
| 5 | +package mozilla.components.browser.engine.gecko.media
|
|
| 6 | + |
|
| 7 | +import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
| 8 | +import junit.framework.TestCase.assertEquals
|
|
| 9 | +import junit.framework.TestCase.assertTrue
|
|
| 10 | +import junit.framework.TestCase.fail
|
|
| 11 | +import mozilla.components.browser.engine.gecko.GeckoEngineSession
|
|
| 12 | +import mozilla.components.concept.engine.EngineSession
|
|
| 13 | +import mozilla.components.concept.engine.media.RecordingDevice
|
|
| 14 | +import mozilla.components.support.test.mock
|
|
| 15 | +import mozilla.components.support.test.whenever
|
|
| 16 | +import mozilla.components.test.ReflectionUtils
|
|
| 17 | +import org.junit.Before
|
|
| 18 | +import org.junit.Test
|
|
| 19 | +import org.junit.runner.RunWith
|
|
| 20 | +import org.mozilla.geckoview.GeckoRuntime
|
|
| 21 | +import java.security.InvalidParameterException
|
|
| 22 | +import org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice as GeckoRecordingDevice
|
|
| 23 | + |
|
| 24 | +@RunWith(AndroidJUnit4::class)
|
|
| 25 | +class GeckoMediaDelegateTest {
|
|
| 26 | + private lateinit var runtime: GeckoRuntime
|
|
| 27 | + |
|
| 28 | + @Before
|
|
| 29 | + fun setup() {
|
|
| 30 | + runtime = mock()
|
|
| 31 | + whenever(runtime.settings).thenReturn(mock())
|
|
| 32 | + }
|
|
| 33 | + |
|
| 34 | + @Test
|
|
| 35 | + fun `WHEN onRecordingStatusChanged is called THEN notify onRecordingStateChanged`() {
|
|
| 36 | + val mockSession = GeckoEngineSession(runtime)
|
|
| 37 | + var onRecordingWasCalled = false
|
|
| 38 | + val geckoRecordingDevice = createGeckoRecordingDevice(
|
|
| 39 | + status = GeckoRecordingDevice.Status.RECORDING, type = GeckoRecordingDevice.Type.CAMERA
|
|
| 40 | + )
|
|
| 41 | + val gecko = GeckoMediaDelegate(mockSession)
|
|
| 42 | + |
|
| 43 | + mockSession.register(object : EngineSession.Observer {
|
|
| 44 | + override fun onRecordingStateChanged(devices: List<RecordingDevice>) {
|
|
| 45 | + onRecordingWasCalled = true
|
|
| 46 | + }
|
|
| 47 | + })
|
|
| 48 | + |
|
| 49 | + gecko.onRecordingStatusChanged(mock(), arrayOf(geckoRecordingDevice))
|
|
| 50 | + |
|
| 51 | + assertTrue(onRecordingWasCalled)
|
|
| 52 | + }
|
|
| 53 | + |
|
| 54 | + @Test
|
|
| 55 | + fun `GIVEN a GeckoRecordingDevice status WHEN calling toStatus THEN covert to the RecordingDevice status`() {
|
|
| 56 | + val geckoRecordingDevice = createGeckoRecordingDevice(
|
|
| 57 | + status = GeckoRecordingDevice.Status.RECORDING
|
|
| 58 | + )
|
|
| 59 | + val geckoInactiveDevice = createGeckoRecordingDevice(
|
|
| 60 | + status = GeckoRecordingDevice.Status.INACTIVE
|
|
| 61 | + )
|
|
| 62 | + |
|
| 63 | + assertEquals(RecordingDevice.Status.RECORDING, geckoRecordingDevice.toStatus())
|
|
| 64 | + assertEquals(RecordingDevice.Status.INACTIVE, geckoInactiveDevice.toStatus())
|
|
| 65 | + }
|
|
| 66 | + |
|
| 67 | + @Test
|
|
| 68 | + fun `GIVEN an invalid GeckoRecordingDevice status WHEN calling toStatus THEN throw an exception`() {
|
|
| 69 | + val geckoInvalidDevice = createGeckoRecordingDevice(
|
|
| 70 | + status = 12
|
|
| 71 | + )
|
|
| 72 | + try {
|
|
| 73 | + geckoInvalidDevice.toStatus()
|
|
| 74 | + fail()
|
|
| 75 | + } catch (_: InvalidParameterException) {
|
|
| 76 | + }
|
|
| 77 | + }
|
|
| 78 | + |
|
| 79 | + @Test
|
|
| 80 | + fun `GIVEN a GeckoRecordingDevice type WHEN calling toType THEN covert to the RecordingDevice type`() {
|
|
| 81 | + val geckoCameraDevice = createGeckoRecordingDevice(
|
|
| 82 | + type = GeckoRecordingDevice.Type.CAMERA
|
|
| 83 | + )
|
|
| 84 | + val geckoMicDevice = createGeckoRecordingDevice(
|
|
| 85 | + type = GeckoRecordingDevice.Type.MICROPHONE
|
|
| 86 | + )
|
|
| 87 | + |
|
| 88 | + assertEquals(RecordingDevice.Type.CAMERA, geckoCameraDevice.toType())
|
|
| 89 | + assertEquals(RecordingDevice.Type.MICROPHONE, geckoMicDevice.toType())
|
|
| 90 | + }
|
|
| 91 | + |
|
| 92 | + @Test
|
|
| 93 | + fun `GIVEN an invalid GeckoRecordingDevice type WHEN calling toType THEN throw an exception`() {
|
|
| 94 | + val geckoInvalidDevice = createGeckoRecordingDevice(
|
|
| 95 | + type = 12
|
|
| 96 | + )
|
|
| 97 | + try {
|
|
| 98 | + geckoInvalidDevice.toType()
|
|
| 99 | + fail()
|
|
| 100 | + } catch (_: InvalidParameterException) {
|
|
| 101 | + }
|
|
| 102 | + }
|
|
| 103 | + |
|
| 104 | + private fun createGeckoRecordingDevice(
|
|
| 105 | + status: Long = GeckoRecordingDevice.Status.RECORDING,
|
|
| 106 | + type: Long = GeckoRecordingDevice.Type.CAMERA
|
|
| 107 | + ): GeckoRecordingDevice {
|
|
| 108 | + val device: GeckoRecordingDevice = mock()
|
|
| 109 | + ReflectionUtils.setField(device, "status", status)
|
|
| 110 | + ReflectionUtils.setField(device, "type", type)
|
|
| 111 | + return device
|
|
| 112 | + }
|
|
| 113 | +} |