Verified Commit 169b6812 authored by Arturo Mejia's avatar Arturo Mejia Committed by Pier Angelo Vendrame
Browse files

Improve the media delegate

parent 6415ced7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import mozilla.components.browser.engine.gecko.ext.isExcludedForTrackingProtection
import mozilla.components.browser.engine.gecko.fetch.toResponse
import mozilla.components.browser.engine.gecko.media.GeckoMediaDelegate
import mozilla.components.browser.engine.gecko.mediasession.GeckoMediaSessionDelegate
import mozilla.components.browser.engine.gecko.permission.GeckoPermissionRequest
import mozilla.components.browser.engine.gecko.prompt.GeckoPromptDelegate
@@ -1098,6 +1099,7 @@ class GeckoEngineSession(
        geckoSession.contentBlockingDelegate = createContentBlockingDelegate()
        geckoSession.permissionDelegate = createPermissionDelegate()
        geckoSession.promptDelegate = GeckoPromptDelegate(this)
        geckoSession.mediaDelegate = GeckoMediaDelegate(this)
        geckoSession.historyDelegate = createHistoryDelegate()
        geckoSession.mediaSessionDelegate = GeckoMediaSessionDelegate(this)
        geckoSession.scrollDelegate = createScrollDelegate()
+53 −0
Original line number Diff line number Diff line
/* 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/. */

package mozilla.components.browser.engine.gecko.media

import androidx.annotation.VisibleForTesting
import mozilla.components.browser.engine.gecko.GeckoEngineSession
import mozilla.components.concept.engine.media.RecordingDevice
import org.mozilla.geckoview.GeckoSession
import java.security.InvalidParameterException
import org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice as GeckoRecordingDevice

/**
 * Gecko-based GeckoMediaDelegate implementation.
 */
internal class GeckoMediaDelegate(private val geckoEngineSession: GeckoEngineSession) :
    GeckoSession.MediaDelegate {

    override fun onRecordingStatusChanged(
        session: GeckoSession,
        geckoDevices: Array<out GeckoRecordingDevice>
    ) {
        val devices = geckoDevices.map { geckoRecording ->
            val type = geckoRecording.toType()
            val status = geckoRecording.toStatus()
            RecordingDevice(type, status)
        }
        geckoEngineSession.notifyObservers { onRecordingStateChanged(devices) }
    }
}

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun GeckoRecordingDevice.toType(): RecordingDevice.Type {
    return when (type) {
        GeckoRecordingDevice.Type.CAMERA -> RecordingDevice.Type.CAMERA
        GeckoRecordingDevice.Type.MICROPHONE -> RecordingDevice.Type.MICROPHONE
        else -> {
            throw InvalidParameterException("Unexpected Gecko Media type $type status $status")
        }
    }
}

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun GeckoRecordingDevice.toStatus(): RecordingDevice.Status {
    return when (status) {
        GeckoRecordingDevice.Status.RECORDING -> RecordingDevice.Status.RECORDING
        GeckoRecordingDevice.Status.INACTIVE -> RecordingDevice.Status.INACTIVE
        else -> {
            throw InvalidParameterException("Unexpected Gecko Media type $type status $status")
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ class GeckoEngineSessionTest {

    private lateinit var navigationDelegate: ArgumentCaptor<GeckoSession.NavigationDelegate>
    private lateinit var progressDelegate: ArgumentCaptor<GeckoSession.ProgressDelegate>
    private lateinit var mediaDelegate: ArgumentCaptor<GeckoSession.MediaDelegate>
    private lateinit var contentDelegate: ArgumentCaptor<GeckoSession.ContentDelegate>
    private lateinit var permissionDelegate: ArgumentCaptor<GeckoSession.PermissionDelegate>
    private lateinit var contentBlockingDelegate: ArgumentCaptor<ContentBlocking.Delegate>
@@ -140,6 +141,7 @@ class GeckoEngineSessionTest {
        whenever(runtime.settings).thenReturn(mock())
        navigationDelegate = ArgumentCaptor.forClass(GeckoSession.NavigationDelegate::class.java)
        progressDelegate = ArgumentCaptor.forClass(GeckoSession.ProgressDelegate::class.java)
        mediaDelegate = ArgumentCaptor.forClass(GeckoSession.MediaDelegate::class.java)
        contentDelegate = ArgumentCaptor.forClass(GeckoSession.ContentDelegate::class.java)
        permissionDelegate = ArgumentCaptor.forClass(GeckoSession.PermissionDelegate::class.java)
        contentBlockingDelegate = ArgumentCaptor.forClass(ContentBlocking.Delegate::class.java)
@@ -156,6 +158,7 @@ class GeckoEngineSessionTest {
        verify(geckoSession).permissionDelegate = permissionDelegate.capture()
        verify(geckoSession).contentBlockingDelegate = contentBlockingDelegate.capture()
        verify(geckoSession).historyDelegate = historyDelegate.capture()
        verify(geckoSession).mediaDelegate = mediaDelegate.capture()
    }

    @Test
+113 −0
Original line number Diff line number Diff line
/* 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/. */

package mozilla.components.browser.engine.gecko.media

import androidx.test.ext.junit.runners.AndroidJUnit4
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertTrue
import junit.framework.TestCase.fail
import mozilla.components.browser.engine.gecko.GeckoEngineSession
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.media.RecordingDevice
import mozilla.components.support.test.mock
import mozilla.components.support.test.whenever
import mozilla.components.test.ReflectionUtils
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.GeckoRuntime
import java.security.InvalidParameterException
import org.mozilla.geckoview.GeckoSession.MediaDelegate.RecordingDevice as GeckoRecordingDevice

@RunWith(AndroidJUnit4::class)
class GeckoMediaDelegateTest {
    private lateinit var runtime: GeckoRuntime

    @Before
    fun setup() {
        runtime = mock()
        whenever(runtime.settings).thenReturn(mock())
    }

    @Test
    fun `WHEN onRecordingStatusChanged is called THEN notify onRecordingStateChanged`() {
        val mockSession = GeckoEngineSession(runtime)
        var onRecordingWasCalled = false
        val geckoRecordingDevice = createGeckoRecordingDevice(
            status = GeckoRecordingDevice.Status.RECORDING, type = GeckoRecordingDevice.Type.CAMERA
        )
        val gecko = GeckoMediaDelegate(mockSession)

        mockSession.register(object : EngineSession.Observer {
            override fun onRecordingStateChanged(devices: List<RecordingDevice>) {
                onRecordingWasCalled = true
            }
        })

        gecko.onRecordingStatusChanged(mock(), arrayOf(geckoRecordingDevice))

        assertTrue(onRecordingWasCalled)
    }

    @Test
    fun `GIVEN a GeckoRecordingDevice status WHEN calling toStatus THEN covert to the RecordingDevice status`() {
        val geckoRecordingDevice = createGeckoRecordingDevice(
            status = GeckoRecordingDevice.Status.RECORDING
        )
        val geckoInactiveDevice = createGeckoRecordingDevice(
            status = GeckoRecordingDevice.Status.INACTIVE
        )

        assertEquals(RecordingDevice.Status.RECORDING, geckoRecordingDevice.toStatus())
        assertEquals(RecordingDevice.Status.INACTIVE, geckoInactiveDevice.toStatus())
    }

    @Test
    fun `GIVEN an invalid GeckoRecordingDevice status WHEN calling toStatus THEN throw an exception`() {
        val geckoInvalidDevice = createGeckoRecordingDevice(
            status = 12
        )
        try {
            geckoInvalidDevice.toStatus()
            fail()
        } catch (_: InvalidParameterException) {
        }
    }

    @Test
    fun `GIVEN a GeckoRecordingDevice type WHEN calling toType THEN covert to the RecordingDevice type`() {
        val geckoCameraDevice = createGeckoRecordingDevice(
            type = GeckoRecordingDevice.Type.CAMERA
        )
        val geckoMicDevice = createGeckoRecordingDevice(
            type = GeckoRecordingDevice.Type.MICROPHONE
        )

        assertEquals(RecordingDevice.Type.CAMERA, geckoCameraDevice.toType())
        assertEquals(RecordingDevice.Type.MICROPHONE, geckoMicDevice.toType())
    }

    @Test
    fun `GIVEN an invalid GeckoRecordingDevice type WHEN calling toType THEN throw an exception`() {
        val geckoInvalidDevice = createGeckoRecordingDevice(
            type = 12
        )
        try {
            geckoInvalidDevice.toType()
            fail()
        } catch (_: InvalidParameterException) {
        }
    }

    private fun createGeckoRecordingDevice(
        status: Long = GeckoRecordingDevice.Status.RECORDING,
        type: Long = GeckoRecordingDevice.Type.CAMERA
    ): GeckoRecordingDevice {
        val device: GeckoRecordingDevice = mock()
        ReflectionUtils.setField(device, "status", status)
        ReflectionUtils.setField(device, "type", type)
        return device
    }
}