Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79f8df7d authored by Daniel Andersson's avatar Daniel Andersson
Browse files

Desktop screen capture: initial full screen recording functionality

Bug: 437392234
Test: PreCaptureViewModelTest and manual
Flag: com.android.systemui.large_screen_screencapture
Change-Id: Iafacc2ab576599916a8c6592e6327d77d842126c
parent f47e2b33
Loading
Loading
Loading
Loading
+35 −1
Original line number Original line Diff line number Diff line
@@ -27,6 +27,9 @@ import com.android.systemui.screencapture.common.ui.viewmodel.DrawableLoaderView
import com.android.systemui.screencapture.domain.interactor.ScreenCaptureUiInteractor
import com.android.systemui.screencapture.domain.interactor.ScreenCaptureUiInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.LargeScreenCaptureFeaturesInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.LargeScreenCaptureFeaturesInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.ScreenshotInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.ScreenshotInteractor
import com.android.systemui.screenrecord.ScreenRecordingAudioSource
import com.android.systemui.screenrecord.domain.ScreenRecordingParameters
import com.android.systemui.screenrecord.domain.interactor.ScreenRecordingServiceInteractor
import dagger.assisted.Assisted
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.assisted.AssistedInject
@@ -60,6 +63,7 @@ constructor(
    private val featuresInteractor: LargeScreenCaptureFeaturesInteractor,
    private val featuresInteractor: LargeScreenCaptureFeaturesInteractor,
    private val drawableLoaderViewModelImpl: DrawableLoaderViewModelImpl,
    private val drawableLoaderViewModelImpl: DrawableLoaderViewModelImpl,
    private val screenCaptureUiInteractor: ScreenCaptureUiInteractor,
    private val screenCaptureUiInteractor: ScreenCaptureUiInteractor,
    private val screenRecordingServiceInteractor: ScreenRecordingServiceInteractor,
) : HydratedActivatable(), DrawableLoaderViewModel by drawableLoaderViewModelImpl {
) : HydratedActivatable(), DrawableLoaderViewModel by drawableLoaderViewModelImpl {


    private val isShowingUiFlow = MutableStateFlow(true)
    private val isShowingUiFlow = MutableStateFlow(true)
@@ -121,7 +125,7 @@ constructor(
    fun beginCapture() {
    fun beginCapture() {
        when (captureTypeSource.value) {
        when (captureTypeSource.value) {
            ScreenCaptureType.SCREENSHOT -> takeScreenshot()
            ScreenCaptureType.SCREENSHOT -> takeScreenshot()
            ScreenCaptureType.SCREEN_RECORD -> {}
            ScreenCaptureType.SCREEN_RECORD -> startRecording()
        }
        }
    }
    }


@@ -155,6 +159,36 @@ constructor(
        closeUi()
        closeUi()
    }
    }


    private fun startRecording() {
        when (captureRegionSource.value) {
            ScreenCaptureRegion.FULLSCREEN -> startFullscreenRecording()
            ScreenCaptureRegion.PARTIAL -> {}
            ScreenCaptureRegion.APP_WINDOW -> {}
        }
    }

    private fun startFullscreenRecording() {
        require(captureTypeSource.value == ScreenCaptureType.SCREEN_RECORD)
        require(captureRegionSource.value == ScreenCaptureRegion.FULLSCREEN)

        // Hide the pre-capture UI before starting the recording.
        // TODO(b/437970158): Show the countdown before starting recording.
        hideUi()
        closeUi()

        backgroundScope.launch {
            screenRecordingServiceInteractor.startRecording(
                // TODO(b/437971334): Get options from the UI.
                ScreenRecordingParameters(
                    captureTarget = null, // Fullscreen.
                    audioSource = ScreenRecordingAudioSource.INTERNAL,
                    displayId = displayId,
                    shouldShowTaps = false,
                )
            )
        }
    }

    /**
    /**
     * Simply hides all Composables from being visible, which avoids the parent window close
     * Simply hides all Composables from being visible, which avoids the parent window close
     * animation. This is useful to ensure the UI is not visible before a screenshot is taken. Note:
     * animation. This is useful to ensure the UI is not visible before a screenshot is taken. Note:
+27 −0
Original line number Original line Diff line number Diff line
@@ -37,6 +37,10 @@ import com.android.systemui.lifecycle.activateIn
import com.android.systemui.res.R
import com.android.systemui.res.R
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureUiState
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureUiState
import com.android.systemui.screencapture.data.repository.screenCaptureUiRepository
import com.android.systemui.screencapture.data.repository.screenCaptureUiRepository
import com.android.systemui.screenrecord.ScreenRecordingAudioSource
import com.android.systemui.screenrecord.domain.ScreenRecordingParameters
import com.android.systemui.screenrecord.domain.interactor.ScreenRecordingServiceInteractor
import com.android.systemui.screenrecord.domain.interactor.screenRecordingServiceInteractor
import com.android.systemui.screenshot.mockImageCapture
import com.android.systemui.screenshot.mockImageCapture
import com.android.systemui.testKosmos
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
@@ -64,10 +68,13 @@ class PreCaptureViewModelTest : SysuiTestCase() {
    private val viewModel: PreCaptureViewModel by lazy {
    private val viewModel: PreCaptureViewModel by lazy {
        kosmos.preCaptureViewModelFactory.create(displayId)
        kosmos.preCaptureViewModelFactory.create(displayId)
    }
    }
    @Mock
    private lateinit var mockScreenRecordingServiceInteractor: ScreenRecordingServiceInteractor


    @Before
    @Before
    fun setUp() {
    fun setUp() {
        MockitoAnnotations.openMocks(this)
        MockitoAnnotations.openMocks(this)
        kosmos.screenRecordingServiceInteractor = mockScreenRecordingServiceInteractor
        viewModel.activateIn(testScope)
        viewModel.activateIn(testScope)
    }
    }


@@ -213,6 +220,26 @@ class PreCaptureViewModelTest : SysuiTestCase() {
            assertThat(capturedRequest.displayId).isEqualTo(displayId)
            assertThat(capturedRequest.displayId).isEqualTo(displayId)
        }
        }


    @Test
    fun beginCapture_forFullScreenRecording_startsRecordingWithCorrectParameters() =
        kosmos.runTest {
            viewModel.updateCaptureType(ScreenCaptureType.SCREEN_RECORD)
            viewModel.updateCaptureRegion(ScreenCaptureRegion.FULLSCREEN)

            viewModel.beginCapture()

            val paramsCaptor = argumentCaptor<ScreenRecordingParameters>()
            verify(mockScreenRecordingServiceInteractor, times(1))
                .startRecording(paramsCaptor.capture())
            val capturedParams = paramsCaptor.lastValue
            with(capturedParams) {
                assertThat(captureTarget).isNull()
                assertThat(audioSource).isEqualTo(ScreenRecordingAudioSource.INTERNAL)
                assertThat(this.displayId).isEqualTo(displayId)
                assertThat(shouldShowTaps).isFalse()
            }
        }

    @Test
    @Test
    @DisableFlags(Flags.FLAG_LARGE_SCREEN_SCREENSHOT_APP_WINDOW)
    @DisableFlags(Flags.FLAG_LARGE_SCREEN_SCREENSHOT_APP_WINDOW)
    fun captureRegionButtonViewModels_excludesAppWindowWithFeatureDisabled() =
    fun captureRegionButtonViewModels_excludesAppWindowWithFeatureDisabled() =
+2 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.screencapture.common.ui.viewmodel.drawableLoaderView
import com.android.systemui.screencapture.domain.interactor.screenCaptureUiInteractor
import com.android.systemui.screencapture.domain.interactor.screenCaptureUiInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.largeScreenCaptureFeaturesInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.largeScreenCaptureFeaturesInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.screenshotInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.screenshotInteractor
import com.android.systemui.screenrecord.domain.interactor.screenRecordingServiceInteractor


val Kosmos.preCaptureViewModelFactory by Fixture {
val Kosmos.preCaptureViewModelFactory by Fixture {
    object : PreCaptureViewModel.Factory {
    object : PreCaptureViewModel.Factory {
@@ -37,6 +38,7 @@ val Kosmos.preCaptureViewModelFactory by Fixture {
                featuresInteractor = largeScreenCaptureFeaturesInteractor,
                featuresInteractor = largeScreenCaptureFeaturesInteractor,
                drawableLoaderViewModelImpl = drawableLoaderViewModelImpl,
                drawableLoaderViewModelImpl = drawableLoaderViewModelImpl,
                screenCaptureUiInteractor = screenCaptureUiInteractor,
                screenCaptureUiInteractor = screenCaptureUiInteractor,
                screenRecordingServiceInteractor = screenRecordingServiceInteractor,
            )
            )
        }
        }
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -22,7 +22,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.screenrecord.screenRecordUxController
import com.android.systemui.screenrecord.screenRecordUxController
import com.android.systemui.user.data.repository.userRepository
import com.android.systemui.user.data.repository.userRepository


val Kosmos.screenRecordingServiceInteractor: ScreenRecordingServiceInteractor by
var Kosmos.screenRecordingServiceInteractor: ScreenRecordingServiceInteractor by
    Kosmos.Fixture {
    Kosmos.Fixture {
        ScreenRecordingServiceInteractor(
        ScreenRecordingServiceInteractor(
            applicationContext,
            applicationContext,