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

Commit 39813386 authored by Merissa Mitchell's avatar Merissa Mitchell Committed by Android (Google) Code Review
Browse files

Merge "[PiP on Desktop] Check App Ops before minimizing to PiP." into main

parents f140c1fa 9399d145
Loading
Loading
Loading
Loading
+35 −2
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.ActivityManager
import android.app.ActivityManager.RecentTaskInfo
import android.app.ActivityManager.RecentTaskInfo
import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityOptions
import android.app.ActivityOptions
import android.app.AppOpsManager
import android.app.KeyguardManager
import android.app.KeyguardManager
import android.app.PendingIntent
import android.app.PendingIntent
import android.app.TaskInfo
import android.app.TaskInfo
@@ -33,6 +34,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.app.WindowConfiguration.WindowingMode
import android.app.WindowConfiguration.WindowingMode
import android.content.Context
import android.content.Context
import android.content.Intent
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Point
import android.graphics.Point
import android.graphics.PointF
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.Rect
@@ -1024,10 +1026,11 @@ class DesktopTasksController(
            } else {
            } else {
                taskRepository.isOnlyVisibleNonClosingTask(taskId = taskId, displayId = displayId)
                taskRepository.isOnlyVisibleNonClosingTask(taskId = taskId, displayId = displayId)
            }
            }

        val isMinimizingToPip =
        val isMinimizingToPip =
            DesktopExperienceFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue &&
            DesktopExperienceFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue &&
                (taskInfo.pictureInPictureParams?.isAutoEnterEnabled ?: false)
                (taskInfo.pictureInPictureParams?.isAutoEnterEnabled ?: false) &&

                isPipAllowedInAppOps(taskInfo)
        // If task is going to PiP, start a PiP transition instead of a minimize transition
        // If task is going to PiP, start a PiP transition instead of a minimize transition
        if (isMinimizingToPip) {
        if (isMinimizingToPip) {
            val requestInfo =
            val requestInfo =
@@ -1100,6 +1103,36 @@ class DesktopTasksController(
        )
        )
    }
    }


    /** Checks whether the given [taskInfo] is allowed to enter PiP in AppOps. */
    private fun isPipAllowedInAppOps(taskInfo: RunningTaskInfo): Boolean {
        val packageName =
            taskInfo.baseActivity?.packageName
                ?: taskInfo.topActivity?.packageName
                ?: taskInfo.origActivity?.packageName
                ?: taskInfo.realActivity?.packageName
                ?: return false

        val appOpsManager =
            checkNotNull(context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager)
        try {
            val appInfo =
                context.packageManager.getApplicationInfoAsUser(packageName, /* flags= */ 0, userId)
            return appOpsManager.checkOpNoThrow(
                AppOpsManager.OP_PICTURE_IN_PICTURE,
                appInfo.uid,
                packageName,
            ) == AppOpsManager.MODE_ALLOWED
        } catch (_: PackageManager.NameNotFoundException) {
            logW(
                "isPipAllowedInAppOps: Failed to find applicationInfo for packageName=%s " +
                    "and userId=%d",
                packageName,
                userId,
            )
        }
        return false
    }

    /** Move or launch a task with given [taskId] to fullscreen */
    /** Move or launch a task with given [taskId] to fullscreen */
    @JvmOverloads
    @JvmOverloads
    fun moveToFullscreen(
    fun moveToFullscreen(
+55 −6
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.wm.shell.desktopmode
import android.app.ActivityManager.RecentTaskInfo
import android.app.ActivityManager.RecentTaskInfo
import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityOptions
import android.app.ActivityOptions
import android.app.AppOpsManager
import android.app.KeyguardManager
import android.app.KeyguardManager
import android.app.PendingIntent
import android.app.PendingIntent
import android.app.PictureInPictureParams
import android.app.PictureInPictureParams
@@ -276,6 +277,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
    @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler
    @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler
    @Mock
    @Mock
    private lateinit var moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler
    private lateinit var moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler
    @Mock private lateinit var mockAppOpsManager: AppOpsManager


    private lateinit var controller: DesktopTasksController
    private lateinit var controller: DesktopTasksController
    private lateinit var shellInit: ShellInit
    private lateinit var shellInit: ShellInit
@@ -3800,10 +3802,23 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            .addPendingTransition(DeskTransition.DeactivateDesk(token = transition, deskId = 0))
            .addPendingTransition(DeskTransition.DeactivateDesk(token = transition, deskId = 0))
    }
    }


    private fun minimizePipTask(task: RunningTaskInfo) {
    private fun minimizePipTask(task: RunningTaskInfo, appOpsAllowed: Boolean = true) {
        val handler = mock(TransitionHandler::class.java)
        val handler = mock(TransitionHandler::class.java)
        whenever(transitions.dispatchRequest(any(), any(), anyOrNull()))
        whenever(transitions.dispatchRequest(any(), any(), anyOrNull()))
            .thenReturn(android.util.Pair(handler, WindowContainerTransaction()))
            .thenReturn(android.util.Pair(handler, WindowContainerTransaction()))
        mContext.addMockSystemService(Context.APP_OPS_SERVICE, mockAppOpsManager)
        mContext.setMockPackageManager(packageManager)

        whenever(
                mockAppOpsManager.checkOpNoThrow(
                    eq(AppOpsManager.OP_PICTURE_IN_PICTURE),
                    any(),
                    any(),
                )
            )
            .thenReturn(
                if (appOpsAllowed) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_IGNORED
            )


        controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
        controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
    }
    }
@@ -3840,6 +3855,34 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        verify(freeformTaskTransitionStarter, never()).startPipTransition(any())
        verify(freeformTaskTransitionStarter, never()).startPipTransition(any())
    }
    }


    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
    fun onPipTaskMinimize_pipNotAllowedInAppOps_startMinimizeTransition() {
        val task = setUpPipTask(autoEnterEnabled = true)
        whenever(
                freeformTaskTransitionStarter.startMinimizedModeTransition(
                    any(),
                    anyInt(),
                    anyBoolean(),
                )
            )
            .thenReturn(Binder())
        whenever(
                mockAppOpsManager.checkOpNoThrow(
                    eq(AppOpsManager.OP_PICTURE_IN_PICTURE),
                    any(),
                    any(),
                )
            )
            .thenReturn(AppOpsManager.MODE_IGNORED)

        minimizePipTask(task, appOpsAllowed = false)

        verify(freeformTaskTransitionStarter)
            .startMinimizedModeTransition(any(), eq(task.taskId), anyBoolean())
        verify(freeformTaskTransitionStarter, never()).startPipTransition(any())
    }

    @Test
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
    fun onPipTaskMinimize_autoEnterEnabled_sendsTaskbarRoundingUpdate() {
    fun onPipTaskMinimize_autoEnterEnabled_sendsTaskbarRoundingUpdate() {
@@ -8841,10 +8884,16 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        autoEnterEnabled: Boolean,
        autoEnterEnabled: Boolean,
        displayId: Int = DEFAULT_DISPLAY,
        displayId: Int = DEFAULT_DISPLAY,
        deskId: Int = DEFAULT_DISPLAY,
        deskId: Int = DEFAULT_DISPLAY,
    ): RunningTaskInfo =
    ): RunningTaskInfo {
        val task =
            setUpFreeformTask(displayId = displayId, deskId = deskId).apply {
            setUpFreeformTask(displayId = displayId, deskId = deskId).apply {
                pictureInPictureParams =
                pictureInPictureParams =
                    PictureInPictureParams.Builder().setAutoEnterEnabled(autoEnterEnabled).build()
                    PictureInPictureParams.Builder().setAutoEnterEnabled(autoEnterEnabled).build()
                baseActivity = ComponentName("com.test.dummypackage", "TestClass")
            }
        whenever(packageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt()))
            .thenReturn(task.topActivityInfo?.applicationInfo)
        return task
    }
    }


    private fun setUpHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
    private fun setUpHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {