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

Commit 5f726610 authored by Wes Okuhara's avatar Wes Okuhara Committed by Android (Google) Code Review
Browse files

Merge changes I29ca34db,Ibe79ed0e into main

* changes:
  Desktop screenshots: Temporary fix to ensure UI is excluded from image
  Desktop screenshots: Refactor capture method after user click
parents 003b2bc6 413b8f6f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject

@SysUISingleton
class ScreenCaptureRecordLargeScreenFeaturesInteractor @Inject constructor() {
class LargeScreenCaptureFeaturesInteractor @Inject constructor() {
    val appWindowRegionSupported = Flags.largeScreenScreenshotAppWindow()

    val screenRecordingSupported = Flags.largeScreenRecording()
+4 −4
Original line number Diff line number Diff line
@@ -34,13 +34,13 @@ import kotlinx.coroutines.withContext
class ScreenshotInteractor
@Inject
constructor(
    private val imageCapture: ImageCapture,
    private val screenshotHelper: ScreenshotHelper,
    @Background private val backgroundContext: CoroutineContext,
    @Background private val backgroundHandler: Handler,
    private val imageCapture: ImageCapture,
    private val screenshotHelper: ScreenshotHelper,
    private val userRepository: UserRepository,
) {
    suspend fun takeFullscreenScreenshot(displayId: Int) {
    suspend fun requestFullscreenScreenshot(displayId: Int) {
        val request =
            ScreenshotRequest.Builder(
                    WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
@@ -52,7 +52,7 @@ constructor(
        takeScreenshot(request)
    }

    suspend fun takePartialScreenshot(regionBounds: Rect, displayId: Int) {
    suspend fun requestPartialScreenshot(regionBounds: Rect, displayId: Int) {
        val bitmap =
            withContext(backgroundContext) {
                requireNotNull(imageCapture.captureDisplay(displayId, regionBounds))
+2 −2
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ import com.android.systemui.screencapture.record.largescreen.ui.viewmodel.PreCap
import javax.inject.Inject

@ScreenCaptureScope
class LargeScreenCaptureRecordContent
class LargeScreenCaptureContent
@Inject
constructor(private val viewModelFactory: PreCaptureViewModel.Factory) : ScreenCaptureContent {

@@ -35,7 +35,7 @@ constructor(private val viewModelFactory: PreCaptureViewModel.Factory) : ScreenC
        val viewModel: PreCaptureViewModel =
            rememberViewModel("PreCaptureViewModel") { viewModelFactory.create(displayId) }

        if (viewModel.isShowingUI) {
        if (viewModel.isShowingUi) {
            PreCaptureUI(viewModel = viewModel)
        }
    }
+3 −3
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ fun PreCaptureUI(viewModel: PreCaptureViewModel) {
            PreCaptureToolbar(
                viewModel = viewModel,
                expanded = true,
                onCloseClick = { viewModel.closeUI() },
                onCloseClick = { viewModel.closeUi() },
            )
        }

@@ -89,7 +89,7 @@ fun PreCaptureUI(viewModel: PreCaptureViewModel) {
                                        R.string.screen_capture_fullscreen_record_button
                                }
                            ),
                        onClick = { viewModel.takeFullscreenScreenshot() },
                        onClick = viewModel::beginCapture,
                    )
                }
            }
@@ -116,7 +116,7 @@ fun PreCaptureUI(viewModel: PreCaptureViewModel) {
                        ),
                    buttonIcon = icon,
                    onRegionSelected = { rect: Rect -> viewModel.updateRegionBox(rect) },
                    onCaptureClick = { viewModel.takePartialScreenshot() },
                    onCaptureClick = viewModel::beginCapture,
                )
            }

+40 −28
Original line number Diff line number Diff line
@@ -25,13 +25,14 @@ import com.android.systemui.res.R
import com.android.systemui.screencapture.common.ui.viewmodel.DrawableLoaderViewModel
import com.android.systemui.screencapture.common.ui.viewmodel.DrawableLoaderViewModelImpl
import com.android.systemui.screencapture.domain.interactor.ScreenCaptureUiInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.ScreenCaptureRecordLargeScreenFeaturesInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.LargeScreenCaptureFeaturesInteractor
import com.android.systemui.screencapture.record.largescreen.domain.interactor.ScreenshotInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -56,19 +57,19 @@ constructor(
    @Background private val backgroundScope: CoroutineScope,
    private val iconProvider: ScreenCaptureIconProvider,
    private val screenshotInteractor: ScreenshotInteractor,
    private val featuresInteractor: ScreenCaptureRecordLargeScreenFeaturesInteractor,
    private val featuresInteractor: LargeScreenCaptureFeaturesInteractor,
    private val drawableLoaderViewModelImpl: DrawableLoaderViewModelImpl,
    private val screenCaptureUiInteractor: ScreenCaptureUiInteractor,
) : HydratedActivatable(), DrawableLoaderViewModel by drawableLoaderViewModelImpl {

    private val isShowingUIFlow = MutableStateFlow(true)
    private val isShowingUiFlow = MutableStateFlow(true)
    private val captureTypeSource = MutableStateFlow(ScreenCaptureType.SCREENSHOT)
    private val captureRegionSource = MutableStateFlow(ScreenCaptureRegion.FULLSCREEN)
    private val regionBoxSource = MutableStateFlow<Rect?>(null)

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

    val isShowingUI: Boolean by isShowingUIFlow.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()
@@ -116,44 +117,55 @@ constructor(
        regionBoxSource.value = bounds
    }

    fun takeFullscreenScreenshot() {
        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()
    /** Initiates capture of the screen depending on the currently chosen capture type. */
    fun beginCapture() {
        when (captureTypeSource.value) {
            ScreenCaptureType.SCREENSHOT -> takeScreenshot()
            ScreenCaptureType.SCREEN_RECORD -> {}
        }
    }

        backgroundScope.launch { screenshotInteractor.takeFullscreenScreenshot(displayId) }
    private fun takeScreenshot() {
        when (captureRegionSource.value) {
            ScreenCaptureRegion.FULLSCREEN -> beginFullscreenScreenshot()
            ScreenCaptureRegion.PARTIAL -> beginPartialScreenshot()
            ScreenCaptureRegion.APP_WINDOW -> {}
        }
    }

    fun takePartialScreenshot() {
        require(captureTypeSource.value == ScreenCaptureType.SCREENSHOT)
        require(captureRegionSource.value == ScreenCaptureRegion.PARTIAL)
    private fun beginFullscreenScreenshot() {
        // Hide the UI to avoid the parent window closing animation.
        hideUi()
        backgroundScope.launch { screenshotInteractor.requestFullscreenScreenshot(displayId) }
        closeUi()
    }

    private fun beginPartialScreenshot() {
        val regionBoxRect = requireNotNull(regionBoxSource.value)

        // 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()

        // Hide the UI to avoid the parent window closing animation.
        hideUi()
        backgroundScope.launch {
            screenshotInteractor.takePartialScreenshot(regionBoxRect, displayId)
            // Temporary fix to allow enough time for the pre-capture UI to dismiss.
            // TODO(b/435225255) Implement a more reliable way to ensure the UI is hidden prior to
            // taking the screenshot.
            delay(100)
            screenshotInteractor.requestPartialScreenshot(regionBoxRect, displayId)
        }
        closeUi()
    }

    /**
     * Simply hides all Composables from being visible in the [ScreenCaptureActivity], but does NOT
     * close the activity. See [closeUI] for closing the activity.
     * 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:
     * this does NOT close the parent window. See [closeUi] for closing the window.
     */
    fun hideUI() {
        isShowingUIFlow.value = false
    fun hideUi() {
        isShowingUiFlow.value = false
    }

    /** Closes the UI by finishing the parent [ScreenCaptureActivity]. */
    fun closeUI() {
    /** Closes the UI by hiding the parent window. */
    fun closeUi() {
        screenCaptureUiInteractor.hide(
            com.android.systemui.screencapture.common.shared.model.ScreenCaptureType.RECORD
        )
Loading