1 /*
2  * Copyright (C) 2024 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.minimize
18 
19 import android.app.ActivityManager
20 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
21 import android.os.Binder
22 import android.os.IBinder
23 import android.testing.AndroidTestingRunner
24 import android.view.SurfaceControl.Transaction
25 import android.view.WindowManager.TRANSIT_TO_BACK
26 import android.view.WindowManager.TRANSIT_TO_FRONT
27 import android.window.IRemoteTransition
28 import android.window.RemoteTransition
29 import androidx.test.filters.SmallTest
30 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
31 import com.android.wm.shell.TestRunningTaskInfoBuilder
32 import com.android.wm.shell.TestShellExecutor
33 import com.android.wm.shell.transition.TransitionInfoBuilder
34 import com.android.wm.shell.transition.Transitions
35 import com.google.common.truth.Truth.assertThat
36 import org.junit.Before
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 import org.mockito.ArgumentMatchers.any
40 import org.mockito.ArgumentMatchers.anyInt
41 import org.mockito.Mockito.mock
42 import org.mockito.Mockito.times
43 import org.mockito.Mockito.verify
44 import org.mockito.kotlin.mock
45 import org.mockito.kotlin.whenever
46 
47 @SmallTest
48 @RunWith(AndroidTestingRunner::class)
49 class DesktopWindowLimitRemoteHandlerTest {
50 
51     private val shellExecutor = TestShellExecutor()
52     private val transition: IBinder = Binder()
53 
54     private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
55     private val remoteTransition = mock<RemoteTransition>()
56     private val iRemoteTransition = mock<IRemoteTransition>()
57     private val startT = mock<Transaction>()
58     private val finishT = mock<Transaction>()
59     private val finishCallback = mock<Transitions.TransitionFinishCallback>()
60 
61     @Before
setUpnull62     fun setUp() {
63         whenever(remoteTransition.remoteTransition).thenReturn(iRemoteTransition)
64         whenever(iRemoteTransition.asBinder()).thenReturn(mock(IBinder::class.java))
65     }
66 
createRemoteHandlernull67     private fun createRemoteHandler(taskIdToMinimize: Int) =
68         DesktopWindowLimitRemoteHandler(
69             shellExecutor, rootTaskDisplayAreaOrganizer, remoteTransition, taskIdToMinimize)
70 
71     @Test
72     fun startAnimation_dontSetTransition_returnsFalse() {
73         val minimizeTask = createDesktopTask()
74         val remoteHandler = createRemoteHandler(taskIdToMinimize = minimizeTask.taskId)
75 
76         assertThat(remoteHandler.startAnimation(transition,
77             createMinimizeTransitionInfo(minimizeTask), startT, finishT, finishCallback)
78         ).isFalse()
79     }
80 
81     @Test
startAnimation_noMinimizeChange_returnsFalsenull82     fun startAnimation_noMinimizeChange_returnsFalse() {
83         val remoteHandler = createRemoteHandler(taskIdToMinimize = 1)
84         remoteHandler.setTransition(transition)
85         val info = createToFrontTransitionInfo()
86 
87         assertThat(
88             remoteHandler.startAnimation(transition, info, startT, finishT, finishCallback)
89         ).isFalse()
90     }
91 
92     @Test
startAnimation_correctTransition_returnsTruenull93     fun startAnimation_correctTransition_returnsTrue() {
94         val minimizeTask = createDesktopTask()
95         val remoteHandler = createRemoteHandler(taskIdToMinimize = minimizeTask.taskId)
96         remoteHandler.setTransition(transition)
97         val info = createMinimizeTransitionInfo(minimizeTask)
98 
99         assertThat(
100             remoteHandler.startAnimation(transition, info, startT, finishT, finishCallback)
101         ).isTrue()
102     }
103 
104     @Test
startAnimation_noMinimizeChange_doesNotReparentMinimizeChangenull105     fun startAnimation_noMinimizeChange_doesNotReparentMinimizeChange() {
106         val remoteHandler = createRemoteHandler(taskIdToMinimize = 1)
107         remoteHandler.setTransition(transition)
108         val info = createToFrontTransitionInfo()
109 
110         remoteHandler.startAnimation(transition, info, startT, finishT, finishCallback)
111 
112         verify(rootTaskDisplayAreaOrganizer, times(0))
113             .reparentToDisplayArea(anyInt(), any(), any())
114     }
115 
116     @Test
startAnimation_hasMinimizeChange_reparentsMinimizeChangenull117     fun startAnimation_hasMinimizeChange_reparentsMinimizeChange() {
118         val minimizeTask = createDesktopTask()
119         val remoteHandler = createRemoteHandler(taskIdToMinimize = minimizeTask.taskId)
120         remoteHandler.setTransition(transition)
121         val info = createMinimizeTransitionInfo(minimizeTask)
122 
123         remoteHandler.startAnimation(transition, info, startT, finishT, finishCallback)
124 
125         verify(rootTaskDisplayAreaOrganizer).reparentToDisplayArea(anyInt(), any(), any())
126     }
127 
128     @Test
startAnimation_noMinimizeChange_doesNotStartRemoteAnimationnull129     fun startAnimation_noMinimizeChange_doesNotStartRemoteAnimation() {
130         val minimizeTask = createDesktopTask()
131         val remoteHandler = createRemoteHandler(taskIdToMinimize = minimizeTask.taskId)
132         remoteHandler.setTransition(transition)
133         val info = createToFrontTransitionInfo()
134 
135         remoteHandler.startAnimation(transition, info, startT, finishT, finishCallback)
136 
137         verify(iRemoteTransition, times(0)).startAnimation(any(), any(), any(), any())
138     }
139 
140     @Test
startAnimation_hasMinimizeChange_startsRemoteAnimationnull141     fun startAnimation_hasMinimizeChange_startsRemoteAnimation() {
142         val minimizeTask = createDesktopTask()
143         val remoteHandler = createRemoteHandler(taskIdToMinimize = minimizeTask.taskId)
144         remoteHandler.setTransition(transition)
145         val info = createMinimizeTransitionInfo(minimizeTask)
146 
147         remoteHandler.startAnimation(transition, info, startT, finishT, finishCallback)
148 
149         verify(iRemoteTransition).startAnimation(any(), any(), any(), any())
150     }
151 
createDesktopTasknull152     private fun createDesktopTask() =
153         TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build()
154 
155     private fun createToFrontTransitionInfo() =
156         TransitionInfoBuilder(TRANSIT_TO_FRONT)
157             .addChange(TRANSIT_TO_FRONT,
158                 TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build())
159             .build()
160 
161     private fun createMinimizeTransitionInfo(minimizeTask: ActivityManager.RunningTaskInfo) =
162         TransitionInfoBuilder(TRANSIT_TO_FRONT)
163             .addChange(TRANSIT_TO_FRONT,
164                 TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build())
165             .addChange(TRANSIT_TO_BACK, minimizeTask)
166             .build()
167 }
168