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

Commit 5be9dd8e authored by Wes Okuhara's avatar Wes Okuhara
Browse files

Desktop screenshots: Hide UI before triggering screenshot

Finishing the ScreenCaptureActivity is not guaranteed to happen before
the screenshot is taken. To workaround this, hide the UI completely
before taking the screenshot, which guarantees the pre-capture UI is
excluded from the screenshot.

Bug: 427500006
Test: atest PreCaptureViewModelTest
Test: Manual
Flag: com.android.systemui.desktop_screen_capture
Change-Id: Ia9a828c323b5dcb1516bcb10bbfa141c860b5572
parent 6bcc447c
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ constructor(private val viewModelFactory: PreCaptureViewModel.Factory) : ScreenC
        val viewModel: PreCaptureViewModel =
            rememberViewModel("PreCaptureViewModel") { viewModelFactory.create() }

        if (viewModel.isShowingUI) {
            PreCaptureUI(viewModel = viewModel)
        }
    }
}
+18 −2
Original line number Diff line number Diff line
@@ -60,11 +60,15 @@ constructor(
    private val featuresInteractor: ScreenCaptureRecordLargeScreenFeaturesInteractor,
    private val drawableLoaderViewModelImpl: DrawableLoaderViewModelImpl,
) : HydratedActivatable(), DrawableLoaderViewModel by drawableLoaderViewModelImpl {

    private val isShowingUIFlow = MutableStateFlow(true)
    private val captureTypeSource = MutableStateFlow(ScreenCaptureType.SCREENSHOT)
    private val captureRegionSource = MutableStateFlow(ScreenCaptureRegion.FULLSCREEN)

    val icons: ScreenCaptureIcons? by iconProvider.icons.hydratedStateOf()

    val isShowingUI: Boolean by isShowingUIFlow.hydratedStateOf()

    // TODO(b/423697394) Init default value to be user's previously selected option
    val captureType: ScreenCaptureType by captureTypeSource.hydratedStateOf()

@@ -102,18 +106,30 @@ constructor(
        require(captureTypeSource.value == ScreenCaptureType.SCREENSHOT)
        require(captureRegionSource.value == ScreenCaptureRegion.FULLSCREEN)

        // Finishing the activity is not guaranteed to complete before the screenshot is taken.
        // Since the pre-capture UI should not be included in the screenshot, hide the UI first.
        hideUI()
        closeUI()

        backgroundScope.launch {
            // TODO(b/430361425) Pass in current display as argument.
            screenshotInteractor.takeFullscreenScreenshot()
        }

        // TODO(b/427500006) Close the window after requesting a fullscreen screenshot.
    }

    fun onPartialRegionDragEnd(offset: Offset, width: Dp, height: Dp) {
        // TODO(b/427541309) Update region box position and size.
    }

    /**
     * Simply hides all Composables from being visible in the [ScreenCaptureActivity], but does NOT
     * close the activity. See [closeUI] for closing the activity.
     */
    fun hideUI() {
        isShowingUIFlow.value = false
    }

    /** Closes the UI by finishing the parent [ScreenCaptureActivity]. */
    fun closeUI() {
        activity.finish()
    }
+9 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ class PreCaptureViewModelTest : SysuiTestCase() {
    fun initialState() =
        testScope.runTest {
            // Assert that the initial values are as expected upon creation and activation.
            assertThat(viewModel.isShowingUI).isTrue()
            assertThat(viewModel.captureType).isEqualTo(ScreenCaptureType.SCREENSHOT)
            assertThat(viewModel.captureRegion).isEqualTo(ScreenCaptureRegion.FULLSCREEN)
        }
@@ -194,6 +195,14 @@ class PreCaptureViewModelTest : SysuiTestCase() {
            assertThat(viewModel.captureRegionButtonViewModels.count { it.isSelected }).isEqualTo(1)
        }

    @Test
    fun hideUI_stopsShowingUI() =
        testScope.runTest {
            viewModel.hideUI()

            assertThat(viewModel.isShowingUI).isFalse()
        }

    @Test
    fun closeUI_finishesActivity() =
        testScope.runTest {