Richard Pospesel pushed to branch android-components-102.0.14-12.0-1 at The Tor Project / Applications / android-components

Commits:

4 changed files:

Changes:

  • components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt
    ... ... @@ -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()
    

  • components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/media/GeckoMediaDelegate.kt
    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
    +}

  • components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt
    ... ... @@ -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
    

  • components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/media/GeckoMediaDelegateTest.kt
    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
    +}