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

Commit d0bcf853 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Show connected display in cast and screenshare dialogs" into main

parents 77e0f66e 4d3ac512
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -48,3 +48,10 @@ flag {
    is_exported: true
}

flag {
  name: "media_projection_connected_display_screen_sharing"
  namespace: "media_projection"
  description: "Enable sharing and casting connected display"
  bug: "406217983"
}
+55 −0
Original line number Diff line number Diff line
@@ -17,36 +17,54 @@
package com.android.systemui.mediaprojection.permission

import android.app.AlertDialog
import android.hardware.display.DisplayManager
import android.hardware.display.displayManager
import android.media.projection.MediaProjectionConfig
import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.testing.TestableLooper
import android.view.Display
import android.view.WindowManager
import android.widget.Spinner
import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.media.projection.flags.Flags.FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY
import com.android.media.projection.flags.Flags.FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY_SCREEN_SHARING
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.AlertDialogWithDelegate
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertEquals
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever

/**
 * atest
 * SystemUITests:com.android.systemui.mediaprojection.permission.ShareToAppPermissionDialogDelegateTest
 */
@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class ShareToAppPermissionDialogDelegateTest : SysuiTestCase() {

    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val testScope = kosmos.testScope
    private val displayManager = kosmos.displayManager

    @get:Rule val checkFlagRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()

    private lateinit var dialog: AlertDialog
@@ -57,6 +75,8 @@ class ShareToAppPermissionDialogDelegateTest : SysuiTestCase() {
        R.string.media_projection_entry_app_permission_dialog_option_text_single_app
    private val resIdFullScreen =
        R.string.media_projection_entry_app_permission_dialog_option_text_entire_screen
    private val resIdDisplay =
        R.string.screen_share_permission_dialog_option_text_entire_screen_for_display
    private val resIdSingleAppDisabled =
        R.string.media_projection_entry_app_permission_dialog_single_app_disabled
    private val resIdSingleAppNotSupported =
@@ -183,6 +203,41 @@ class ShareToAppPermissionDialogDelegateTest : SysuiTestCase() {
            )
    }

    @Test
    @RequiresFlagsEnabled(
        FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY,
        FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY_SCREEN_SHARING,
    )
    fun connectedDisplayShown() {
        testScope.runTest {
            context.addMockSystemService(DisplayManager::class.java, displayManager)
            val mainDisplay =
                mock<Display>().apply {
                    whenever(displayId).thenReturn(Display.DEFAULT_DISPLAY)
                    whenever(name).thenReturn("Default Display")
                    whenever(type).thenReturn(Display.TYPE_INTERNAL)
                }

            val connectedDisplay =
                mock<Display>().apply {
                    whenever(displayId).thenReturn(1000)
                    whenever(name).thenReturn("Connected Display")
                    whenever(type).thenReturn(Display.TYPE_EXTERNAL)
                }
            whenever(displayManager.displays).thenReturn(arrayOf(mainDisplay, connectedDisplay))
            setUpAndShowDialog()

            val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_options)
            val optionsText =
                (0 until spinner.adapter.count)
                    .map { spinner.adapter.getDropDownView(it, null, spinner) }
                    .mapNotNull { it.findViewById<TextView>(android.R.id.text1)?.text }

            // check that the first option is single app and enabled
            assertThat(optionsText).contains(context.getString(resIdDisplay, "Connected Display"))
        }
    }

    private fun setUpAndShowDialog(
        mediaProjectionConfig: MediaProjectionConfig? = null,
        overrideDisableSingleAppOption: Boolean = false,
+51 −0
Original line number Diff line number Diff line
@@ -17,36 +17,50 @@
package com.android.systemui.mediaprojection.permission

import android.app.AlertDialog
import android.hardware.display.DisplayManager
import android.hardware.display.displayManager
import android.media.projection.MediaProjectionConfig
import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.testing.TestableLooper
import android.view.Display
import android.view.WindowManager
import android.widget.Spinner
import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.media.projection.flags.Flags.FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY
import com.android.media.projection.flags.Flags.FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY_SCREEN_SHARING
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.AlertDialogWithDelegate
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertEquals
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class SystemCastPermissionDialogDelegateTest : SysuiTestCase() {

    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val testScope = kosmos.testScope
    private val displayManager = kosmos.displayManager

    @get:Rule val checkFlagRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()

    private lateinit var dialog: AlertDialog
@@ -59,6 +73,8 @@ class SystemCastPermissionDialogDelegateTest : SysuiTestCase() {
        R.string.media_projection_entry_cast_permission_dialog_option_text_entire_screen
    private val resIdSingleAppDisabled =
        R.string.media_projection_entry_app_permission_dialog_single_app_disabled
    private val resIdDisplay =
        R.string.media_projection_entry_cast_permission_dialog_option_text_entire_screen_for_display
    private val resIdSingleAppNotSupported =
        R.string.media_projection_entry_app_permission_dialog_single_app_not_supported

@@ -183,6 +199,41 @@ class SystemCastPermissionDialogDelegateTest : SysuiTestCase() {
            )
    }

    @Test
    @RequiresFlagsEnabled(
        FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY,
        FLAG_MEDIA_PROJECTION_CONNECTED_DISPLAY_SCREEN_SHARING,
    )
    fun connectedDisplayShown() {
        testScope.runTest {
            context.addMockSystemService(DisplayManager::class.java, displayManager)
            val mainDisplay =
                mock<Display>().apply {
                    whenever(displayId).thenReturn(Display.DEFAULT_DISPLAY)
                    whenever(name).thenReturn("Default Display")
                    whenever(type).thenReturn(Display.TYPE_INTERNAL)
                }

            val connectedDisplay =
                mock<Display>().apply {
                    whenever(displayId).thenReturn(1000)
                    whenever(name).thenReturn("Connected Display")
                    whenever(type).thenReturn(Display.TYPE_EXTERNAL)
                }
            whenever(displayManager.displays).thenReturn(arrayOf(mainDisplay, connectedDisplay))
            setUpAndShowDialog()

            val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_options)
            val optionsText =
                (0 until spinner.adapter.count)
                    .map { spinner.adapter.getDropDownView(it, null, spinner) }
                    .mapNotNull { it.findViewById<TextView>(android.R.id.text1)?.text }

            // check that the list contains the connected display (type EXTERNAL)
            assertThat(optionsText).contains(context.getString(resIdDisplay, "Connected Display"))
        }
    }

    private fun setUpAndShowDialog(
        mediaProjectionConfig: MediaProjectionConfig? = null,
        overrideDisableSingleAppOption: Boolean = false,
+4 −0
Original line number Diff line number Diff line
@@ -1476,6 +1476,8 @@
    <string name="media_projection_entry_app_permission_dialog_option_text_single_app">@string/screen_share_permission_dialog_option_single_app</string>
    <!-- 1P/3P app media projection permission option for capturing the whole screen [CHAR LIMIT=50] -->
    <string name="screen_share_permission_dialog_option_entire_screen">Share entire screen</string>
    <!-- Screen recording permission option for recording a connected external display [CHAR LIMIT=50] -->
    <string name="screen_share_permission_dialog_option_text_entire_screen_for_display">Share <xliff:g id="display_name" example="Display 1">%s</xliff:g></string>
    <!-- CTS tests rely on the `screen_share_permission_dialog_option_entire_screen` resource name, so just point the updated resource name to the old resource name. -->
    <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen">@string/screen_share_permission_dialog_option_entire_screen</string>
    <!-- 1P/3P app media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] -->
@@ -1498,6 +1500,8 @@
    <string name="media_projection_entry_cast_permission_dialog_option_text_single_app">Cast one app</string>
    <!-- System casting media projection permission option for capturing the whole screen [CHAR LIMIT=50] -->
    <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen">Cast entire screen</string>
    <!-- System casting media projection permission option for capturing a  connected external display. %s will be replaced by the display name [CHAR LIMIT=50] -->
    <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen_for_display">Cast <xliff:g id="display_name" example="Display 1">%s</xliff:g></string>
    <!-- System casting media projection permission warning for capturing the whole screen when SysUI casting requests it. [CHAR LIMIT=350] -->
    <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen">When you’re casting your entire screen, anything on your screen is visible. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
    <!-- System casting media projection permission warning for capturing a single app when SysUI casting requests it. [CHAR LIMIT=350] -->
+26 −0
Original line number Diff line number Diff line
@@ -17,12 +17,25 @@
package com.android.systemui.mediaprojection.permission

import android.content.Context
import android.hardware.display.DisplayManager
import android.media.projection.MediaProjectionConfig
import android.view.Display
import com.android.media.projection.flags.Flags
import com.android.systemui.res.R

/** Various utility methods related to media projection permissions. */
object MediaProjectionPermissionUtils {

    private val RECORDABLE_DISPLAY_TYPES =
        intArrayOf(
            Display.TYPE_OVERLAY,
            Display.TYPE_EXTERNAL,
            Display.TYPE_INTERNAL,
            Display.TYPE_WIFI,
        )
    private val filterDeviceTypeFlag: Boolean =
        com.android.media.projection.flags.Flags.mediaProjectionConnectedDisplayNoVirtualDevice()

    fun getSingleAppDisabledText(
        context: Context,
        appName: String,
@@ -59,4 +72,17 @@ object MediaProjectionPermissionUtils {
            null
        }
    }

    fun getConnectedDisplays(displayManager: DisplayManager?): List<Display> {
        if (!com.android.media.projection.flags.Flags.mediaProjectionConnectedDisplay()) {
            return emptyList()
        }
        if (displayManager == null) {
            return emptyList()
        }
        return displayManager.displays.filter {
            it.displayId != Display.DEFAULT_DISPLAY &&
                (!filterDeviceTypeFlag || it.type in RECORDABLE_DISPLAY_TYPES)
        }
    }
}
Loading