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