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

Commit 707847d2 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB] Always include host app name in share-to-app chip dialog.

Fixes: 432665824
Flag: com.android.systemui.status_bar_share_dialog_with_app_name
Test: atest EndGenericShareToAppDialogDelegateTest
ShareToAppChipViewModelTest

Change-Id: I6d64060551d59c8a5970c1cbeac78b47853554a4
parent 47ec2d75
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -440,6 +440,16 @@ flag {
    }
}

flag {
    name: "status_bar_share_dialog_with_app_name"
    namespace: "systemui"
    description: "Update the status bar share-to-app chip dialog to include the app name more often"
    bug: "432665824"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "status_bar_window_no_custom_touch"
    namespace: "systemui"
+86 −0
Original line number Diff line number Diff line
@@ -18,16 +18,23 @@ package com.android.systemui.statusbar.chips.sharetoapp.ui.view

import android.content.DialogInterface
import android.content.applicationContext
import android.content.packageManager
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.View
import android.view.Window
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_STATUS_BAR_SHARE_DIALOG_WITH_APP_NAME
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.endMediaProjectionDialogHelper
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.testKosmos
@@ -38,6 +45,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
@@ -50,10 +58,73 @@ class EndGenericShareToAppDialogDelegateTest : SysuiTestCase() {
    private val sysuiDialog = mock<SystemUIDialog>()
    private lateinit var underTest: EndGenericShareToAppDialogDelegate

    @Test
    @EnableFlags(FLAG_STATUS_BAR_SHARE_DIALOG_WITH_APP_NAME)
    fun message_unknownHostPackage_appNameFlagOn_isGeneric() {
        createAndSetDelegate()
        whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
            .thenThrow(PackageManager.NameNotFoundException())

        underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)

        verify(sysuiDialog)
            .setMessage(context.getString(R.string.share_to_app_stop_dialog_message_generic))
    }

    @Test
    @DisableFlags(FLAG_STATUS_BAR_SHARE_DIALOG_WITH_APP_NAME)
    fun message_unknownHostPackage_appNameFlagOff_isGeneric() {
        createAndSetDelegate()
        whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
            .thenThrow(PackageManager.NameNotFoundException())

        underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)

        verify(sysuiDialog)
            .setMessage(context.getString(R.string.share_to_app_stop_dialog_message_generic))
    }

    @Test
    @EnableFlags(FLAG_STATUS_BAR_SHARE_DIALOG_WITH_APP_NAME)
    fun message_hasHostPackage_appNameFlagOn_hasAppName() {
        createAndSetDelegate()
        val hostAppInfo = mock<ApplicationInfo>()
        whenever(hostAppInfo.loadLabel(kosmos.packageManager)).thenReturn("Host Package")
        whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
            .thenReturn(hostAppInfo)

        underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)

        verify(sysuiDialog)
            .setMessage(
                context.getString(
                    R.string.share_to_app_stop_dialog_message_with_host_app,
                    "Host Package",
                )
            )
    }

    @Test
    @DisableFlags(FLAG_STATUS_BAR_SHARE_DIALOG_WITH_APP_NAME)
    fun message_hasHostPackage_appNameFlagOff_isGeneric() {
        createAndSetDelegate()
        val hostAppInfo = mock<ApplicationInfo>()
        whenever(hostAppInfo.loadLabel(kosmos.packageManager)).thenReturn("Host Package")
        whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
            .thenReturn(hostAppInfo)

        underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)

        verify(sysuiDialog)
            .setMessage(context.getString(R.string.share_to_app_stop_dialog_message_generic))
    }

    @Test
    fun positiveButton_clickStopsRecording() =
        kosmos.testScope.runTest {
            createAndSetDelegate()
            whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
                .thenThrow(PackageManager.NameNotFoundException())
            underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)

            assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isFalse()
@@ -70,6 +141,8 @@ class EndGenericShareToAppDialogDelegateTest : SysuiTestCase() {
    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_SHOW_STOP_DIALOG_POST_CALL_END)
    fun accessibilityDataSensitive_flagEnabled_appliesSetting() {
        createAndSetDelegate()
        whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
            .thenThrow(PackageManager.NameNotFoundException())

        val window = mock<Window>()
        val decorView = mock<View>()
@@ -85,6 +158,8 @@ class EndGenericShareToAppDialogDelegateTest : SysuiTestCase() {
    @DisableFlags(com.android.media.projection.flags.Flags.FLAG_SHOW_STOP_DIALOG_POST_CALL_END)
    fun accessibilityDataSensitive_flagDisabled_doesNotApplySetting() {
        createAndSetDelegate()
        whenever(kosmos.packageManager.getApplicationInfo(eq(HOST_PACKAGE), any<Int>()))
            .thenThrow(PackageManager.NameNotFoundException())

        val window = mock<Window>()
        val decorView = mock<View>()
@@ -97,11 +172,22 @@ class EndGenericShareToAppDialogDelegateTest : SysuiTestCase() {
    }

    private fun createAndSetDelegate() {
        val projectionChipState =
            ProjectionChipModel.Projecting(
                ProjectionChipModel.Receiver.ShareToApp,
                ProjectionChipModel.ContentType.Audio,
                MediaProjectionState.Projecting.NoScreen(hostPackage = HOST_PACKAGE),
            )
        underTest =
            EndGenericShareToAppDialogDelegate(
                kosmos.endMediaProjectionDialogHelper,
                kosmos.applicationContext,
                stopAction = kosmos.mediaProjectionChipInteractor::stopProjecting,
                state = projectionChipState,
            )
    }

    companion object {
        private const val HOST_PACKAGE = "fake.host.package"
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -384,6 +384,8 @@
    <string name="share_to_app_stop_dialog_message_single_app_generic">You\'re currently sharing an app</string>
    <!-- Text telling a user that they're currently sharing something to an app [CHAR LIMIT=100] -->
    <string name="share_to_app_stop_dialog_message_generic">You\'re currently sharing with an app</string>
    <!-- Text telling a user that they're currently sharing something to an app [CHAR LIMIT=100] -->
    <string name="share_to_app_stop_dialog_message_with_host_app">You\'re currently sharing with <xliff:g id="host_app_name" example="Screen Recorder App">%1$s</xliff:g></string>
    <!-- Button to stop screen sharing [CHAR LIMIT=35] -->
    <string name="share_to_app_stop_dialog_button">Stop sharing</string>

+18 −2
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.systemui.statusbar.chips.sharetoapp.ui.view
import android.content.Context
import android.os.Bundle
import android.view.View
import com.android.systemui.Flags
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel.Companion.SHARE_TO_APP_ICON
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -32,17 +34,17 @@ class EndGenericShareToAppDialogDelegate(
    private val endMediaProjectionDialogHelper: EndMediaProjectionDialogHelper,
    private val context: Context,
    private val stopAction: () -> Unit,
    private val state: ProjectionChipModel.Projecting,
) : SystemUIDialog.Delegate {
    override fun createDialog(): SystemUIDialog {
        return endMediaProjectionDialogHelper.createDialog(context, this)
    }

    override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
        val message = context.getString(R.string.share_to_app_stop_dialog_message_generic)
        with(dialog) {
            setIcon(SHARE_TO_APP_ICON)
            setTitle(R.string.share_to_app_stop_dialog_title_generic)
            setMessage(message)
            setMessage(getMessage())
            // No custom on-click, because the dialog will automatically be dismissed when the
            // button is clicked anyway.
            setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
@@ -57,4 +59,18 @@ class EndGenericShareToAppDialogDelegate(
            }
        }
    }

    private fun getMessage(): String {
        if (!Flags.statusBarShareDialogWithAppName()) {
            return context.getString(R.string.share_to_app_stop_dialog_message_generic)
        }

        val hostAppName =
            endMediaProjectionDialogHelper.getAppName(state.projectionState.hostPackage)
        return if (hostAppName != null) {
            context.getString(R.string.share_to_app_stop_dialog_message_with_host_app, hostAppName)
        } else {
            context.getString(R.string.share_to_app_stop_dialog_message_generic)
        }
    }
}
+16 −8
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ constructor(
                                    ProjectionChipModel.ContentType.Screen ->
                                        createShareScreenToAppStopDialog(currentProjection)
                                    ProjectionChipModel.ContentType.Audio ->
                                        createGenericShareScreenToAppStopDialog()
                                        createGenericShareScreenToAppStopDialog(currentProjection)
                                }
                            }
                            ProjectionChipModel.Receiver.CastToOtherDevice ->
@@ -140,7 +140,7 @@ constructor(
                                    ProjectionChipModel.ContentType.Screen ->
                                        createShareScreenToAppChip(projectionModel)
                                    ProjectionChipModel.ContentType.Audio ->
                                        createIconOnlyShareToAppChip()
                                        createIconOnlyShareToAppChip(projectionModel)
                                }
                            }
                            ProjectionChipModel.Receiver.CastToOtherDevice ->
@@ -212,8 +212,10 @@ constructor(
        )
    }

    private fun createGenericShareScreenToAppStopDialog(): MediaProjectionStopDialogModel {
        val dialogDelegate = createGenericShareToAppDialogDelegate(context)
    private fun createGenericShareScreenToAppStopDialog(
        projectionModel: ProjectionChipModel.Projecting
    ): MediaProjectionStopDialogModel {
        val dialogDelegate = createGenericShareToAppDialogDelegate(context, projectionModel)
        return MediaProjectionStopDialogModel.Shown(
            dialogDelegate,
            onDismissAction = ::onStopDialogDismissed,
@@ -269,7 +271,9 @@ constructor(
        )
    }

    private fun createIconOnlyShareToAppChip(): OngoingActivityChipModel.Active {
    private fun createIconOnlyShareToAppChip(
        state: ProjectionChipModel.Projecting
    ): OngoingActivityChipModel.Active {
        return OngoingActivityChipModel.Active(
            key = KEY,
            isImportantForPrivacy = true,
@@ -286,7 +290,7 @@ constructor(
            colors = ColorsModel.Red,
            onClickListenerLegacy =
                createDialogLaunchOnClickListener(
                    { context -> createGenericShareToAppDialogDelegate(context) },
                    { context -> createGenericShareToAppDialogDelegate(context, state) },
                    dialogTransitionAnimator,
                    DIALOG_CUJ_AUDIO_ONLY,
                    key = KEY,
@@ -298,7 +302,7 @@ constructor(
            clickBehavior =
                OngoingActivityChipModel.ClickBehavior.ExpandAction(
                    createDialogLaunchOnClickCallback(
                        { context -> createGenericShareToAppDialogDelegate(context) },
                        { context -> createGenericShareToAppDialogDelegate(context, state) },
                        dialogTransitionAnimator,
                        DIALOG_CUJ_AUDIO_ONLY,
                        key = KEY,
@@ -323,11 +327,15 @@ constructor(
            state,
        )

    private fun createGenericShareToAppDialogDelegate(context: Context) =
    private fun createGenericShareToAppDialogDelegate(
        context: Context,
        state: ProjectionChipModel.Projecting,
    ) =
        EndGenericShareToAppDialogDelegate(
            endMediaProjectionDialogHelper,
            context,
            stopAction = this::stopProjectingFromDialog,
            state,
        )

    companion object {