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

Commit 72b3afc1 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB][Screen Chips] Show app name in screen record stop dialog if needed.

Builds on Ia4aa6132b342127b4b9202ecd40d561c0fb882c2 to also show "You
will stop recording [app name]" for the screen record stop dialog.
ScreenRecordRepository doesn't have this information (because
RecordingController doesn't have it), so the ScreenRecordChipInteractor
now needs to also listen to MediaProjectionRepository, which *does* have
the information.

Bug: 332662551
Flag: com.android.systemui.status_bar_screen_sharing_chips
Test: Start a screen recording for a single app -> click chip -> verify
dialog says "You will stop recording [app name]", with [app name] in
bold
Test: Start a screen recording for the entire screen -> click chip ->
verify dialog says just "You will stop recording your screen"
Test: atest ScreenRecordChipInteractorTest
EndScreenRecordingDialogDelegateTest

Change-Id: Id9aa09b246dc42ebbf56fca276b336820e574823
parent 04481f29
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -323,6 +323,8 @@
    <string name="screenrecord_stop_dialog_title">Stop recording screen?</string>
    <string name="screenrecord_stop_dialog_title">Stop recording screen?</string>
    <!-- Text telling a user that they will stop recording their screen if they click the "Stop recording" button [CHAR LIMIT=100] -->
    <!-- Text telling a user that they will stop recording their screen if they click the "Stop recording" button [CHAR LIMIT=100] -->
    <string name="screenrecord_stop_dialog_message">You will stop recording your screen</string>
    <string name="screenrecord_stop_dialog_message">You will stop recording your screen</string>
    <!-- Text telling a user that they will stop recording the contents of the specified [app_name] if they click the "Stop recording" button. Note that the app name will appear in bold. [CHAR LIMIT=100] -->
    <string name="screenrecord_stop_dialog_message_specific_app">You will stop recording &lt;b><xliff:g id="app_name" example="Photos App">%1$s</xliff:g>&lt;/b></string>
    <!-- Button to stop a screen recording [CHAR LIMIT=35] -->
    <!-- Button to stop a screen recording [CHAR LIMIT=35] -->
    <string name="screenrecord_stop_dialog_button">Stop recording</string>
    <string name="screenrecord_stop_dialog_button">Stop recording</string>


+5 −1
Original line number Original line Diff line number Diff line
@@ -49,11 +49,15 @@ constructor(
     *   specify which app is currently being projected.
     *   specify which app is currently being projected.
     */
     */
    fun getDialogMessage(
    fun getDialogMessage(
        state: MediaProjectionState.Projecting,
        state: MediaProjectionState,
        @StringRes genericMessageResId: Int,
        @StringRes genericMessageResId: Int,
        @StringRes specificAppMessageResId: Int,
        @StringRes specificAppMessageResId: Int,
    ): CharSequence {
    ): CharSequence {
        when (state) {
        when (state) {
            // NotProjecting might happen if there's a bit of lag between when the screen recording
            // starts and when MediaProjection is aware that it's started, so handle it here just in
            // case.
            is MediaProjectionState.NotProjecting,
            is MediaProjectionState.Projecting.EntireScreen ->
            is MediaProjectionState.Projecting.EntireScreen ->
                return context.getString(genericMessageResId)
                return context.getString(genericMessageResId)
            is MediaProjectionState.Projecting.SingleTask -> {
            is MediaProjectionState.Projecting.SingleTask -> {
+20 −10
Original line number Original line Diff line number Diff line
@@ -21,20 +21,22 @@ import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
import com.android.systemui.res.R
import com.android.systemui.res.R
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.screenrecord.ui.view.EndScreenRecordingDialogDelegate
import com.android.systemui.statusbar.chips.screenrecord.ui.view.EndScreenRecordingDialogDelegate
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch


@@ -45,14 +47,20 @@ class ScreenRecordChipInteractor
constructor(
constructor(
    @Application private val scope: CoroutineScope,
    @Application private val scope: CoroutineScope,
    private val screenRecordRepository: ScreenRecordRepository,
    private val screenRecordRepository: ScreenRecordRepository,
    private val mediaProjectionRepository: MediaProjectionRepository,
    private val systemClock: SystemClock,
    private val systemClock: SystemClock,
    private val dialogFactory: SystemUIDialog.Factory,
    private val endMediaProjectionDialogHelper: EndMediaProjectionDialogHelper,
    private val dialogTransitionAnimator: DialogTransitionAnimator,
    private val dialogTransitionAnimator: DialogTransitionAnimator,
) : OngoingActivityChipInteractor {
) : OngoingActivityChipInteractor {
    override val chip: StateFlow<OngoingActivityChipModel> =
    override val chip: StateFlow<OngoingActivityChipModel> =
        screenRecordRepository.screenRecordState
        // ScreenRecordRepository has the main "is the screen being recorded?" state, and
            .map { state ->
        // MediaProjectionRepository has information about what specifically is being recorded (a
                when (state) {
        // single app or the entire screen)
        combine(
                screenRecordRepository.screenRecordState,
                mediaProjectionRepository.mediaProjectionState,
            ) { screenRecordState, mediaProjectionState ->
                when (screenRecordState) {
                    is ScreenRecordModel.DoingNothing,
                    is ScreenRecordModel.DoingNothing,
                    // TODO(b/332662551): Implement the 3-2-1 countdown chip.
                    // TODO(b/332662551): Implement the 3-2-1 countdown chip.
                    is ScreenRecordModel.Starting -> OngoingActivityChipModel.Hidden
                    is ScreenRecordModel.Starting -> OngoingActivityChipModel.Hidden
@@ -62,7 +70,7 @@ constructor(
                            icon = Icon.Resource(ICON, contentDescription = null),
                            icon = Icon.Resource(ICON, contentDescription = null),
                            startTimeMs = systemClock.elapsedRealtime(),
                            startTimeMs = systemClock.elapsedRealtime(),
                            createDialogLaunchOnClickListener(
                            createDialogLaunchOnClickListener(
                                dialogDelegate,
                                createDelegate(mediaProjectionState),
                                dialogTransitionAnimator
                                dialogTransitionAnimator
                            ),
                            ),
                        )
                        )
@@ -75,11 +83,13 @@ constructor(
        scope.launch { screenRecordRepository.stopRecording() }
        scope.launch { screenRecordRepository.stopRecording() }
    }
    }


    private val dialogDelegate =
    private fun createDelegate(state: MediaProjectionState): EndScreenRecordingDialogDelegate {
        EndScreenRecordingDialogDelegate(
        return EndScreenRecordingDialogDelegate(
            dialogFactory,
            endMediaProjectionDialogHelper,
            this@ScreenRecordChipInteractor,
            this@ScreenRecordChipInteractor,
            state,
        )
        )
    }


    companion object {
    companion object {
        @DrawableRes val ICON = R.drawable.ic_screenrecord
        @DrawableRes val ICON = R.drawable.ic_screenrecord
+12 −4
Original line number Original line Diff line number Diff line
@@ -17,26 +17,34 @@
package com.android.systemui.statusbar.chips.screenrecord.ui.view
package com.android.systemui.statusbar.chips.screenrecord.ui.view


import android.os.Bundle
import android.os.Bundle
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.res.R
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.SystemUIDialog


/** A dialog that lets the user stop an ongoing screen recording. */
/** A dialog that lets the user stop an ongoing screen recording. */
class EndScreenRecordingDialogDelegate(
class EndScreenRecordingDialogDelegate(
    private val systemUIDialogFactory: SystemUIDialog.Factory,
    private val endMediaProjectionDialogHelper: EndMediaProjectionDialogHelper,
    private val interactor: ScreenRecordChipInteractor,
    private val interactor: ScreenRecordChipInteractor,
    private val state: MediaProjectionState,
) : SystemUIDialog.Delegate {
) : SystemUIDialog.Delegate {


    override fun createDialog(): SystemUIDialog {
    override fun createDialog(): SystemUIDialog {
        return systemUIDialogFactory.create(this)
        return endMediaProjectionDialogHelper.createDialog(this)
    }
    }


    override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
    override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
        with(dialog) {
        with(dialog) {
            setIcon(ScreenRecordChipInteractor.ICON)
            setIcon(ScreenRecordChipInteractor.ICON)
            setTitle(R.string.screenrecord_stop_dialog_title)
            setTitle(R.string.screenrecord_stop_dialog_title)
            // TODO(b/332662551): Use a different message if they're sharing just a single app.
            setMessage(
            setMessage(R.string.screenrecord_stop_dialog_message)
                endMediaProjectionDialogHelper.getDialogMessage(
                    state,
                    genericMessageResId = R.string.screenrecord_stop_dialog_message,
                    specificAppMessageResId = R.string.screenrecord_stop_dialog_message_specific_app
                )
            )
            // No custom on-click, because the dialog will automatically be dismissed when the
            // No custom on-click, because the dialog will automatically be dismissed when the
            // button is clicked anyway.
            // button is clicked anyway.
            setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
            setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+12 −0
Original line number Original line Diff line number Diff line
@@ -55,6 +55,18 @@ class EndMediaProjectionDialogHelperTest : SysuiTestCase() {
        verify(kosmos.mockSystemUIDialogFactory).create(delegate)
        verify(kosmos.mockSystemUIDialogFactory).create(delegate)
    }
    }


    @Test
    fun getDialogMessage_notProjecting_isGenericMessage() {
        val result =
            underTest.getDialogMessage(
                MediaProjectionState.NotProjecting,
                R.string.accessibility_home,
                R.string.cast_to_other_device_stop_dialog_message_specific_app,
            )

        assertThat(result).isEqualTo(context.getString(R.string.accessibility_home))
    }

    @Test
    @Test
    fun getDialogMessage_entireScreen_isGenericMessage() {
    fun getDialogMessage_entireScreen_isGenericMessage() {
        val result =
        val result =
Loading