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.systemui.activity.data.repository
18 
19 import android.app.ActivityManager
20 import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
21 import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
22 import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_TOP_SLEEPING
23 import android.app.activityManager
24 import androidx.test.ext.junit.runners.AndroidJUnit4
25 import androidx.test.filters.SmallTest
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.kosmos.Kosmos
28 import com.android.systemui.kosmos.collectLastValue
29 import com.android.systemui.kosmos.runTest
30 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
31 import com.android.systemui.log.core.Logger
32 import com.android.systemui.log.logcatLogBuffer
33 import com.android.systemui.testKosmos
34 import com.google.common.truth.Truth.assertThat
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.mockito.kotlin.any
38 import org.mockito.kotlin.argumentCaptor
39 import org.mockito.kotlin.verify
40 import org.mockito.kotlin.whenever
41 
42 @SmallTest
43 @RunWith(AndroidJUnit4::class)
44 class ActivityManagerRepositoryTest : SysuiTestCase() {
45     private val kosmos = testKosmos().useUnconfinedTestDispatcher()
46     private val logger = Logger(logcatLogBuffer("ActivityManagerRepositoryTest"), "tag")
47 
<lambda>null48     private val Kosmos.underTest by Kosmos.Fixture { realActivityManagerRepository }
49 
50     @Test
createIsAppVisibleFlow_fetchesInitialValue_truenull51     fun createIsAppVisibleFlow_fetchesInitialValue_true() =
52         kosmos.runTest {
53             whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_FOREGROUND)
54 
55             val latest by
56                 collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
57 
58             assertThat(latest).isTrue()
59         }
60 
61     @Test
createIsAppVisibleFlow_fetchesInitialValue_falsenull62     fun createIsAppVisibleFlow_fetchesInitialValue_false() =
63         kosmos.runTest {
64             whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
65 
66             val latest by
67                 collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
68 
69             assertThat(latest).isFalse()
70         }
71 
72     @Test
createIsAppVisibleFlow_getsImportanceUpdatesnull73     fun createIsAppVisibleFlow_getsImportanceUpdates() =
74         kosmos.runTest {
75             val latest by
76                 collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
77 
78             val listenerCaptor = argumentCaptor<ActivityManager.OnUidImportanceListener>()
79             verify(activityManager).addOnUidImportanceListener(listenerCaptor.capture(), any())
80             val listener = listenerCaptor.firstValue
81 
82             listener.onUidImportance(THIS_UID, IMPORTANCE_GONE)
83             assertThat(latest).isFalse()
84 
85             listener.onUidImportance(THIS_UID, IMPORTANCE_FOREGROUND)
86             assertThat(latest).isTrue()
87 
88             listener.onUidImportance(THIS_UID, IMPORTANCE_TOP_SLEEPING)
89             assertThat(latest).isFalse()
90         }
91 
92     @Test
createIsAppVisibleFlow_ignoresUpdatesForOtherUidsnull93     fun createIsAppVisibleFlow_ignoresUpdatesForOtherUids() =
94         kosmos.runTest {
95             val latest by
96                 collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
97 
98             val listenerCaptor = argumentCaptor<ActivityManager.OnUidImportanceListener>()
99             verify(activityManager).addOnUidImportanceListener(listenerCaptor.capture(), any())
100             val listener = listenerCaptor.firstValue
101 
102             listener.onUidImportance(THIS_UID, IMPORTANCE_GONE)
103             assertThat(latest).isFalse()
104 
105             // WHEN another UID becomes foreground
106             listener.onUidImportance(THIS_UID + 2, IMPORTANCE_FOREGROUND)
107 
108             // THEN this UID still stays not visible
109             assertThat(latest).isFalse()
110         }
111 
112     @Test
createIsAppVisibleFlow_securityExceptionOnUidRegistration_oknull113     fun createIsAppVisibleFlow_securityExceptionOnUidRegistration_ok() =
114         kosmos.runTest {
115             whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
116             whenever(activityManager.addOnUidImportanceListener(any(), any()))
117                 .thenThrow(SecurityException())
118 
119             val latest by
120                 collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
121 
122             // Verify no crash, and we get a value emitted
123             assertThat(latest).isFalse()
124         }
125 
126     /** Regression test for b/216248574. */
127     @Test
createIsAppVisibleFlow_getUidImportanceThrowsException_oknull128     fun createIsAppVisibleFlow_getUidImportanceThrowsException_ok() =
129         kosmos.runTest {
130             whenever(activityManager.getUidImportance(any())).thenThrow(SecurityException())
131 
132             val latest by
133                 collectLastValue(underTest.createIsAppVisibleFlow(THIS_UID, logger, LOG_TAG))
134 
135             // Verify no crash, and we get a value emitted
136             assertThat(latest).isFalse()
137         }
138 
139     companion object {
140         private const val THIS_UID = 558
141         private const val LOG_TAG = "LogTag"
142     }
143 }
144