1 /*
2  * Copyright (C) 2023 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.systemui.recents
18 
19 import android.content.ComponentName
20 import android.content.Context
21 import android.content.pm.PackageManager
22 import android.content.pm.ResolveInfo
23 import android.os.PowerManager
24 import android.os.Process
25 import android.os.UserHandle
26 import android.os.UserManager
27 import android.testing.TestableContext
28 import android.testing.TestableLooper
29 import androidx.test.ext.junit.runners.AndroidJUnit4
30 import androidx.test.filters.SmallTest
31 import com.android.dx.mockito.inline.extended.ExtendedMockito
32 import com.android.internal.app.AssistUtils
33 import com.android.internal.logging.UiEventLogger
34 import com.android.systemui.SysuiTestCase
35 import com.android.systemui.broadcast.BroadcastDispatcher
36 import com.android.systemui.dagger.qualifiers.Main
37 import com.android.systemui.dump.DumpManager
38 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
39 import com.android.systemui.keyguard.WakefulnessLifecycle
40 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
41 import com.android.systemui.model.SysUiState
42 import com.android.systemui.model.sceneContainerPlugin
43 import com.android.systemui.navigationbar.NavigationBarController
44 import com.android.systemui.navigationbar.NavigationModeController
45 import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
46 import com.android.systemui.settings.FakeDisplayTracker
47 import com.android.systemui.settings.UserTracker
48 import com.android.systemui.shade.ShadeViewController
49 import com.android.systemui.shared.recents.IOverviewProxy
50 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK
51 import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_ASLEEP
52 import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_AWAKE
53 import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_GOING_TO_SLEEP
54 import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_WAKING
55 import com.android.systemui.statusbar.CommandQueue
56 import com.android.systemui.statusbar.NotificationShadeWindowController
57 import com.android.systemui.testKosmos
58 import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
59 import com.android.systemui.util.mockito.mock
60 import com.android.systemui.util.mockito.whenever
61 import com.android.systemui.util.time.FakeSystemClock
62 import com.android.wm.shell.back.BackAnimation
63 import com.android.wm.shell.sysui.ShellInterface
64 import com.google.common.util.concurrent.MoreExecutors
65 import java.util.Optional
66 import java.util.concurrent.Executor
67 import org.junit.After
68 import org.junit.Before
69 import org.junit.Test
70 import org.junit.runner.RunWith
71 import org.mockito.ArgumentMatchers
72 import org.mockito.Mock
73 import org.mockito.Mockito.any
74 import org.mockito.Mockito.anyInt
75 import org.mockito.Mockito.atLeast
76 import org.mockito.Mockito.clearInvocations
77 import org.mockito.Mockito.longThat
78 import org.mockito.Mockito.mock
79 import org.mockito.Mockito.spy
80 import org.mockito.Mockito.times
81 import org.mockito.Mockito.verify
82 import org.mockito.Mockito.`when`
83 import org.mockito.MockitoAnnotations
84 
85 @SmallTest
86 @RunWith(AndroidJUnit4::class)
87 @TestableLooper.RunWithLooper(setAsMainLooper = true)
88 class OverviewProxyServiceTest : SysuiTestCase() {
89 
90     @Main private val executor: Executor = MoreExecutors.directExecutor()
91 
92     private val kosmos = testKosmos()
93     private lateinit var subject: OverviewProxyService
94     @Mock private val dumpManager = DumpManager()
95     private val displayTracker = FakeDisplayTracker(mContext)
96     private val fakeSystemClock = FakeSystemClock()
97     private val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin)
98     private val wakefulnessLifecycle =
99         WakefulnessLifecycle(mContext, null, fakeSystemClock, dumpManager)
100 
101     @Mock private lateinit var overviewProxy: IOverviewProxy.Stub
102     @Mock private lateinit var packageManager: PackageManager
103 
104     // The following mocks belong to not-yet-tested parts of OverviewProxyService.
105     @Mock private lateinit var commandQueue: CommandQueue
106     @Mock private lateinit var shellInterface: ShellInterface
107     @Mock private lateinit var navBarController: NavigationBarController
108     @Mock private lateinit var shadeViewController: ShadeViewController
109     @Mock private lateinit var screenPinningRequest: ScreenPinningRequest
110     @Mock private lateinit var navModeController: NavigationModeController
111     @Mock private lateinit var statusBarWinController: NotificationShadeWindowController
112     @Mock private lateinit var userTracker: UserTracker
113     @Mock private lateinit var userManager: UserManager
114     @Mock private lateinit var uiEventLogger: UiEventLogger
115     @Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
116     @Mock
117     private lateinit var inWindowLauncherUnlockAnimationManager:
118         InWindowLauncherUnlockAnimationManager
119     @Mock private lateinit var assistUtils: AssistUtils
120     @Mock
121     private lateinit var unfoldTransitionProgressForwarder:
122         Optional<UnfoldTransitionProgressForwarder>
123     @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
124     @Mock private lateinit var backAnimation: Optional<BackAnimation>
125 
126     @Before
setUpnull127     fun setUp() {
128         MockitoAnnotations.initMocks(this)
129 
130         val serviceComponent = ComponentName("test_package", "service_provider")
131         context.addMockService(serviceComponent, overviewProxy)
132         context.addMockServiceResolver(
133             TestableContext.MockServiceResolver {
134                 if (it.action == ACTION_QUICKSTEP) serviceComponent else null
135             }
136         )
137         whenever(overviewProxy.queryLocalInterface(ArgumentMatchers.anyString()))
138             .thenReturn(overviewProxy)
139         whenever(overviewProxy.asBinder()).thenReturn(overviewProxy)
140 
141         // packageManager.resolveServiceAsUser has to return non-null for
142         // OverviewProxyService#isEnabled to become true.
143         context.setMockPackageManager(packageManager)
144         whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
145             .thenReturn(mock(ResolveInfo::class.java))
146 
147         mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
148 
149         subject = createOverviewProxyService(context)
150     }
151 
152     @After
tearDownnull153     fun tearDown() {
154         subject.shutdownForTest()
155     }
156 
157     @Test
wakefulnessLifecycle_dispatchFinishedWakingUpSetsSysUIflagToAWAKEnull158     fun wakefulnessLifecycle_dispatchFinishedWakingUpSetsSysUIflagToAWAKE() {
159         // WakefulnessLifecycle is initialized to AWAKE initially, and won't emit a noop.
160         wakefulnessLifecycle.dispatchFinishedGoingToSleep()
161         clearInvocations(overviewProxy)
162 
163         wakefulnessLifecycle.dispatchFinishedWakingUp()
164 
165         verify(overviewProxy)
166             .onSystemUiStateChanged(
167                 longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_AWAKE }
168             )
169     }
170 
171     @Test
wakefulnessLifecycle_dispatchStartedWakingUpSetsSysUIflagToWAKINGnull172     fun wakefulnessLifecycle_dispatchStartedWakingUpSetsSysUIflagToWAKING() {
173         wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN)
174 
175         verify(overviewProxy)
176             .onSystemUiStateChanged(
177                 longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_WAKING }
178             )
179     }
180 
181     @Test
wakefulnessLifecycle_dispatchFinishedGoingToSleepSetsSysUIflagToASLEEPnull182     fun wakefulnessLifecycle_dispatchFinishedGoingToSleepSetsSysUIflagToASLEEP() {
183         wakefulnessLifecycle.dispatchFinishedGoingToSleep()
184 
185         verify(overviewProxy)
186             .onSystemUiStateChanged(
187                 longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_ASLEEP }
188             )
189     }
190 
191     @Test
wakefulnessLifecycle_dispatchStartedGoingToSleepSetsSysUIflagToGOING_TO_SLEEPnull192     fun wakefulnessLifecycle_dispatchStartedGoingToSleepSetsSysUIflagToGOING_TO_SLEEP() {
193         wakefulnessLifecycle.dispatchStartedGoingToSleep(
194             PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON
195         )
196 
197         verify(overviewProxy)
198             .onSystemUiStateChanged(
199                 longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP }
200             )
201     }
202 
203     @Test
connectToOverviewService_primaryUserNoVisibleBgUsersSupported_expectBindServicenull204     fun connectToOverviewService_primaryUserNoVisibleBgUsersSupported_expectBindService() {
205         val mockitoSession =
206             ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
207         try {
208             `when`(Process.myUserHandle()).thenReturn(UserHandle.SYSTEM)
209             `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false)
210             val spyContext = spy(context)
211             val ops = createOverviewProxyService(spyContext)
212             ops.startConnectionToCurrentUser()
213             verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any())
214         } finally {
215             mockitoSession.finishMocking()
216         }
217     }
218 
219     @Test
connectToOverviewService_nonPrimaryUserNoVisibleBgUsersSupported_expectNoBindServicenull220     fun connectToOverviewService_nonPrimaryUserNoVisibleBgUsersSupported_expectNoBindService() {
221         val mockitoSession =
222             ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
223         try {
224             `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
225             `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false)
226             val spyContext = spy(context)
227             val ops = createOverviewProxyService(spyContext)
228             ops.startConnectionToCurrentUser()
229             verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any())
230         } finally {
231             mockitoSession.finishMocking()
232         }
233     }
234 
235     @Test
connectToOverviewService_nonPrimaryBgUserVisibleBgUsersSupported_expectBindServicenull236     fun connectToOverviewService_nonPrimaryBgUserVisibleBgUsersSupported_expectBindService() {
237         val mockitoSession =
238             ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
239         try {
240             `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
241             `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true)
242             `when`(userManager.isUserForeground()).thenReturn(false)
243             val spyContext = spy(context)
244             val ops = createOverviewProxyService(spyContext)
245             ops.startConnectionToCurrentUser()
246             verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any())
247         } finally {
248             mockitoSession.finishMocking()
249         }
250     }
251 
252     @Test
connectToOverviewService_nonPrimaryFgUserVisibleBgUsersSupported_expectNoBindServicenull253     fun connectToOverviewService_nonPrimaryFgUserVisibleBgUsersSupported_expectNoBindService() {
254         val mockitoSession =
255             ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking()
256         try {
257             `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
258             `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true)
259             `when`(userManager.isUserForeground()).thenReturn(true)
260             val spyContext = spy(context)
261             val ops = createOverviewProxyService(spyContext)
262             ops.startConnectionToCurrentUser()
263             verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any())
264         } finally {
265             mockitoSession.finishMocking()
266         }
267     }
268 
createOverviewProxyServicenull269     private fun createOverviewProxyService(ctx: Context): OverviewProxyService {
270         return OverviewProxyService(
271             ctx,
272             executor,
273             commandQueue,
274             shellInterface,
275             { navBarController },
276             { shadeViewController },
277             screenPinningRequest,
278             navModeController,
279             statusBarWinController,
280             sysUiState,
281             mock(),
282             mock(),
283             userTracker,
284             userManager,
285             wakefulnessLifecycle,
286             uiEventLogger,
287             displayTracker,
288             sysuiUnlockAnimationController,
289             inWindowLauncherUnlockAnimationManager,
290             assistUtils,
291             dumpManager,
292             unfoldTransitionProgressForwarder,
293             broadcastDispatcher,
294             backAnimation,
295         )
296     }
297 }
298