• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wm.shell.desktopmode
18 
19 import android.app.ActivityManager
20 import android.os.IBinder
21 import android.window.DesktopExperienceFlags
22 import android.window.WindowContainerTransaction
23 import com.android.internal.protolog.ProtoLog
24 import com.android.wm.shell.common.pip.PipDesktopState
25 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
26 
27 /**
28  * Controller to perform extra handling to PiP transitions that are entering while in Desktop mode.
29  */
30 class DesktopPipTransitionController(
31     private val desktopTasksController: DesktopTasksController,
32     private val desktopUserRepositories: DesktopUserRepositories,
33     private val pipDesktopState: PipDesktopState,
34 ) {
35 
36     /**
37      * This is called by [PipTransition#handleRequest] when a request for entering PiP is received.
38      *
39      * @param wct WindowContainerTransaction that will apply these changes
40      * @param transition that will apply this transaction
41      * @param taskInfo of the task that is entering PiP
42      */
handlePipTransitionnull43     fun handlePipTransition(
44         wct: WindowContainerTransaction,
45         transition: IBinder,
46         taskInfo: ActivityManager.RunningTaskInfo,
47     ) {
48         if (!pipDesktopState.isDesktopWindowingPipEnabled()) {
49             return
50         }
51 
52         // Early return if the transition is a synthetic transition that is not backed by a true
53         // system transition.
54         if (transition == DesktopTasksController.SYNTHETIC_TRANSITION) {
55             logD("handlePipTransitionIfInDesktop: SYNTHETIC_TRANSITION, not a true transition")
56             return
57         }
58 
59         val taskId = taskInfo.taskId
60         val displayId = taskInfo.displayId
61         val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId)
62         if (!desktopRepository.isAnyDeskActive(displayId)) {
63             logD("handlePipTransitionIfInDesktop: PiP transition is not in Desktop session")
64             return
65         }
66 
67         val deskId =
68             desktopRepository.getActiveDeskId(displayId)
69                 ?: if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
70                     logW(
71                         "handlePipTransitionIfInDesktop: " +
72                             "Active desk not found for display id %d",
73                         displayId,
74                     )
75                     return
76                 } else {
77                     checkNotNull(desktopRepository.getDefaultDeskId(displayId)) {
78                         "$TAG: handlePipTransitionIfInDesktop: " +
79                             "Expected a default desk to exist in display with id $displayId"
80                     }
81                 }
82 
83         val isLastTask =
84             desktopRepository.isOnlyVisibleNonClosingTaskInDesk(
85                 taskId = taskId,
86                 deskId = deskId,
87                 displayId = displayId,
88             )
89         if (!isLastTask) {
90             logD("handlePipTransitionIfInDesktop: PiP task is not last visible task in Desk")
91             return
92         }
93 
94         val desktopExitRunnable =
95             desktopTasksController.performDesktopExitCleanUp(
96                 wct = wct,
97                 deskId = deskId,
98                 displayId = displayId,
99                 willExitDesktop = true,
100             )
101         desktopExitRunnable?.invoke(transition)
102     }
103 
logWnull104     private fun logW(msg: String, vararg arguments: Any?) {
105         ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
106     }
107 
logDnull108     private fun logD(msg: String, vararg arguments: Any?) {
109         ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
110     }
111 
112     private companion object {
113         private const val TAG = "DesktopPipTransitionController"
114     }
115 }
116