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

Commit 6fa907b8 authored by Anton Potapov's avatar Anton Potapov
Browse files

Reintroduce ScreenCaptureComponent.

ScreenCaptureComponent now lives throughout the capture process and is collected when the UI disappears of the capturing finishes. This allows to store state and the necessary settings for the duration of the caption.

Flag: com.android.systemui.new_screen_record_toolbar
Bug: 427682447
Test: atest ScreenCaptureComponentInteractorTest
Change-Id: I8702a74cd322132fe8197292eb9cd89ccfe589d0
parent 309b4ce4
Loading
Loading
Loading
Loading
+13 −8
Original line number Original line Diff line number Diff line
@@ -24,32 +24,36 @@ import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureType
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureType
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureUiState
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureUiState
import com.android.systemui.screencapture.domain.interactor.ScreenCaptureComponentInteractor
import com.android.systemui.screencapture.domain.interactor.ScreenCaptureUiInteractor
import com.android.systemui.screencapture.domain.interactor.ScreenCaptureUiInteractor
import com.android.systemui.screencapture.ui.ScreenCaptureUi
import javax.inject.Inject
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch


@SysUISingleton
@SysUISingleton
class ScreenCaptureUiStartable
class ScreenCaptureStartable
@Inject
@Inject
constructor(
constructor(
    @Application private val appScope: CoroutineScope,
    @Application private val appScope: CoroutineScope,
    private val screenCaptureComponentInteractor: ScreenCaptureComponentInteractor,
    private val screenCaptureUiInteractor: ScreenCaptureUiInteractor,
    private val screenCaptureUiInteractor: ScreenCaptureUiInteractor,
    private val screenCaptureUiFactory: ScreenCaptureUi.Factory,
    private val focusedDisplayRepository: FocusedDisplayRepository,
    private val focusedDisplayRepository: FocusedDisplayRepository,
    private val displayRepository: DisplayRepository,
    private val displayRepository: DisplayRepository,
) : CoreStartable {
) : CoreStartable {


    override fun start() {
    override fun start() {
        appScope.launch { screenCaptureComponentInteractor.initialize() }
        ScreenCaptureType.entries.forEach { observeUiState(it) }
        ScreenCaptureType.entries.forEach { observeUiState(it) }
    }
    }


    private fun observeUiState(type: ScreenCaptureType) {
    private fun observeUiState(type: ScreenCaptureType) {
        screenCaptureUiInteractor
        combine(
            .uiState(type)
                screenCaptureUiInteractor.uiState(type),
            .onEach { state ->
                screenCaptureComponentInteractor.screenCaptureComponent(type).filterNotNull(),
            ) { state, screenCaptureComponent ->
                if (state is ScreenCaptureUiState.Visible) {
                if (state is ScreenCaptureUiState.Visible) {
                    val displayId = focusedDisplayRepository.focusedDisplayId.value
                    val displayId = focusedDisplayRepository.focusedDisplayId.value
                    val display = displayRepository.getDisplay(displayId)
                    val display = displayRepository.getDisplay(displayId)
@@ -58,7 +62,8 @@ constructor(
                        Log.e("ScreenCapture", "Couldn't find display for id=$displayId")
                        Log.e("ScreenCapture", "Couldn't find display for id=$displayId")
                        screenCaptureUiInteractor.hide(type)
                        screenCaptureUiInteractor.hide(type)
                    } else {
                    } else {
                        screenCaptureUiFactory
                        screenCaptureComponent
                            .screenCaptureUiFactory()
                            .create(type = state.parameters.screenCaptureType, display = display)
                            .create(type = state.parameters.screenCaptureType, display = display)
                            .attachWindow()
                            .attachWindow()
                    }
                    }
+4 −1
Original line number Original line Diff line number Diff line
@@ -18,8 +18,11 @@ package com.android.systemui.screencapture.common


import javax.inject.Qualifier
import javax.inject.Qualifier


/** Used to qualify an item as the one used by Screen Capture. */
/** Used to qualify an item as the one used by Screen Capture UI. */
@Qualifier
@Qualifier
@MustBeDocumented
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Retention(AnnotationRetention.RUNTIME)
annotation class ScreenCaptureUi
annotation class ScreenCaptureUi

/** Used to qualify an item as the one used by Screen Capture. */
@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class ScreenCapture
+15 −1
Original line number Original line Diff line number Diff line
@@ -18,8 +18,22 @@ package com.android.systemui.screencapture.common


import javax.inject.Scope
import javax.inject.Scope


/** Scope annotation for Screen Capture scoped items within the [ScreenCaptureUiComponent]. */
/**
 * Scope annotation for Screen Capture scoped items within the [ScreenCaptureUiComponent].
 *
 * This scope exists when Screen Capture UI is visible.
 */
@Scope
@Scope
@MustBeDocumented
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Retention(AnnotationRetention.RUNTIME)
annotation class ScreenCaptureUiScope
annotation class ScreenCaptureUiScope

/**
 * Scope annotation for Screen Capture scoped items within the [ScreenCaptureComponent].
 *
 * This scope exists from the first Screen Capture UI appearance throughout the capturing.
 */
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class ScreenCaptureScope
+59 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.screencapture.common

import com.android.systemui.screencapture.common.shared.model.ScreenCaptureUiParameters
import com.android.systemui.screencapture.ui.ScreenCaptureUi
import dagger.BindsInstance
import dagger.Subcomponent
import kotlinx.coroutines.CoroutineScope

/**
 * Dagger Subcomponent interface for Screen Capture. It's alive while there is an ongoing Screen
 * Capture or the UI is visible.
 */
@ScreenCaptureScope
@Subcomponent(modules = [ScreenCaptureUiModule::class])
interface ScreenCaptureComponent {

    @ScreenCapture fun coroutineScope(): CoroutineScope

    fun screenCaptureUiFactory(): ScreenCaptureUi.Factory

    /**
     * Dagger Subcomponent Builder for [ScreenCaptureComponent].
     *
     * Actual Subcomponent Builders should extend this interface and override [build] to return the
     * actual subcomponent type.
     */
    @Subcomponent.Builder
    interface Builder {

        /** The [CoroutineScope] to use coroutines limited to Screen Capture sessions. */
        @BindsInstance fun setScope(@ScreenCapture scope: CoroutineScope): Builder

        /** [ScreenCaptureUiParameters] that has been used to start capture flow. */
        @BindsInstance
        fun setParameters(@ScreenCapture parameters: ScreenCaptureUiParameters): Builder

        /**
         * Builds this [ScreenCaptureComponent]. Actual Subcomponent Builders should override this
         * method with their own version that returns the actual subcomponent type.
         */
        fun build(): ScreenCaptureComponent
    }
}
+4 −42
Original line number Original line Diff line number Diff line
@@ -18,58 +18,20 @@ package com.android.systemui.screencapture.common


import android.app.Activity
import android.app.Activity
import com.android.systemui.CoreStartable
import com.android.systemui.CoreStartable
import com.android.systemui.screencapture.ScreenCaptureUiStartable
import com.android.systemui.screencapture.ScreenCaptureStartable
import com.android.systemui.screencapture.cast.ScreenCaptureCastUiComponent
import com.android.systemui.screencapture.common.shared.model.ScreenCaptureType
import com.android.systemui.screencapture.record.ScreenCaptureRecordUiComponent
import com.android.systemui.screencapture.record.smallscreen.ui.SmallScreenPostRecordingActivity
import com.android.systemui.screencapture.record.smallscreen.ui.SmallScreenPostRecordingActivity
import com.android.systemui.screencapture.sharescreen.ScreenCaptureShareScreenUiComponent
import dagger.Binds
import dagger.Binds
import dagger.Module
import dagger.Module
import dagger.multibindings.ClassKey
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import dagger.multibindings.IntoMap


/**
@Module(subcomponents = [ScreenCaptureComponent::class])
 * Top level Dagger Module for Screen Capture.
 *
 * Injects Screen Capture Subcomponents into the System UI dagger graph via
 * [SystemUIModule][com.android.systemui.dagger.SystemUIModule].
 */
@Module(
    subcomponents =
        [
            ScreenCaptureCastUiComponent::class,
            ScreenCaptureUiComponent::class,
            ScreenCaptureRecordUiComponent::class,
            ScreenCaptureShareScreenUiComponent::class,
        ]
)
interface ScreenCaptureModule {
interface ScreenCaptureModule {
    @Binds
    @IntoMap
    @ScreenCaptureTypeKey(ScreenCaptureType.CAST)
    fun bindCastComponentBuilder(
        impl: ScreenCaptureCastUiComponent.Builder
    ): ScreenCaptureUiComponent.Builder

    @Binds
    @IntoMap
    @ScreenCaptureTypeKey(ScreenCaptureType.RECORD)
    fun bindRecordComponentBuilder(
        impl: ScreenCaptureRecordUiComponent.Builder
    ): ScreenCaptureUiComponent.Builder

    @Binds
    @IntoMap
    @ScreenCaptureTypeKey(ScreenCaptureType.SHARE_SCREEN)
    fun bindShareScreenComponentBuilder(
        impl: ScreenCaptureShareScreenUiComponent.Builder
    ): ScreenCaptureUiComponent.Builder


    @Binds
    @Binds
    @IntoMap
    @IntoMap
    @ClassKey(ScreenCaptureUiStartable::class)
    @ClassKey(ScreenCaptureStartable::class)
    fun bindScreenCaptureUiStartable(impl: ScreenCaptureUiStartable): CoreStartable
    fun bindScreenCaptureUiStartable(impl: ScreenCaptureStartable): CoreStartable


    @Binds
    @Binds
    @IntoMap
    @IntoMap
Loading