1 /*
2  * Copyright (C) 2020 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.controls.management
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.content.ComponentName
23 import android.content.Context
24 import android.content.ContextWrapper
25 import android.content.Intent
26 import android.content.pm.PackageManager
27 import android.os.UserHandle
28 import android.service.controls.Control
29 import android.service.controls.ControlsProviderService
30 import android.testing.AndroidTestingRunner
31 import androidx.test.filters.SmallTest
32 import com.android.systemui.SysuiTestCase
33 import org.junit.Assert.assertEquals
34 import org.junit.Assert.assertFalse
35 import org.junit.Assert.assertNull
36 import org.junit.Assert.assertTrue
37 import org.junit.Assert.fail
38 import org.junit.Before
39 import org.junit.Test
40 import org.junit.runner.RunWith
41 import org.mockito.ArgumentMatchers.anyInt
42 import org.mockito.ArgumentMatchers.anyString
43 import org.mockito.ArgumentMatchers.eq
44 import org.mockito.Mock
45 import org.mockito.Mockito.`when`
46 import org.mockito.MockitoAnnotations
47 
48 @SmallTest
49 @RunWith(AndroidTestingRunner::class)
50 class ControlsRequestReceiverTest : SysuiTestCase() {
51 
52     @Mock
53     private lateinit var packageManager: PackageManager
54     @Mock
55     private lateinit var activityManager: ActivityManager
56     @Mock
57     private lateinit var control: Control
58 
59     private val componentName = ComponentName("test_pkg", "test_cls")
60     private lateinit var receiver: ControlsRequestReceiver
61     private lateinit var wrapper: MyWrapper
62     private lateinit var intent: Intent
63 
64     @Before
65     fun setUp() {
66         MockitoAnnotations.initMocks(this)
67 
68         mContext.setMockPackageManager(packageManager)
69         `when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)).thenReturn(true)
70         mContext.addMockSystemService(ActivityManager::class.java, activityManager)
71 
72         receiver = ControlsRequestReceiver()
73 
74         wrapper = MyWrapper(context)
75 
76         intent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
77             putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
78             putExtra(ControlsProviderService.EXTRA_CONTROL, control)
79         }
80     }
81 
82     @Test
83     fun testPackageVerification_nonExistentPackage() {
84         `when`(packageManager.getPackageUid(anyString(), anyInt()))
85                 .thenThrow(PackageManager.NameNotFoundException::class.java)
86 
87         assertFalse(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
88     }
89 
90     @Test
91     fun testPackageVerification_uidNotInForeground() {
92         `when`(packageManager.getPackageUid(anyString(), anyInt())).thenReturn(12345)
93 
94         `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
95 
96         assertFalse(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
97     }
98 
99     @Test
100     fun testPackageVerification_OK() {
101         `when`(packageManager.getPackageUid(anyString(), anyInt())).thenReturn(12345)
102 
103         `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
104         `when`(activityManager.getUidImportance(12345)).thenReturn(IMPORTANCE_FOREGROUND)
105 
106         assertTrue(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
107     }
108 
109     @Test
110     fun testOnReceive_packageNotVerified_nameNotFound() {
111         `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
112                 .thenThrow(PackageManager.NameNotFoundException::class.java)
113 
114         receiver.onReceive(wrapper, intent)
115 
116         assertNull(wrapper.intent)
117     }
118 
119     @Test
120     fun testOnReceive_packageNotVerified_notForeground() {
121         `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
122                 .thenReturn(12345)
123 
124         `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
125 
126         receiver.onReceive(wrapper, intent)
127 
128         assertNull(wrapper.intent)
129     }
130 
131     @Test
132     fun testOnReceive_OK() {
133         `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
134                 .thenReturn(12345)
135 
136         `when`(activityManager.getUidImportance(eq(12345))).thenReturn(IMPORTANCE_FOREGROUND)
137 
138         receiver.onReceive(wrapper, intent)
139 
140         wrapper.intent?.let {
141             assertEquals(ComponentName(wrapper, ControlsRequestDialog::class.java), it.component)
142 
143             assertEquals(control, it.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL))
144 
145             assertEquals(componentName, it.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME))
146         } ?: run { fail("Null start intent") }
147     }
148 
149     @Test
150     fun testFeatureDisabled_activityNotStarted() {
151         `when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)).thenReturn(false)
152         receiver.onReceive(wrapper, intent)
153 
154         assertNull(wrapper.intent)
155     }
156 
157     @Test
158     fun testClassCastExceptionComponentName_noCrash() {
159         val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
160             putExtra(Intent.EXTRA_COMPONENT_NAME, Intent())
161             putExtra(ControlsProviderService.EXTRA_CONTROL, control)
162         }
163         receiver.onReceive(wrapper, badIntent)
164 
165         assertNull(wrapper.intent)
166     }
167 
168     @Test
169     fun testClassCastExceptionControl_noCrash() {
170         val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
171             putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
172             putExtra(ControlsProviderService.EXTRA_CONTROL, Intent())
173         }
174         receiver.onReceive(wrapper, badIntent)
175 
176         assertNull(wrapper.intent)
177     }
178 
179     class MyWrapper(context: Context) : ContextWrapper(context) {
180         var intent: Intent? = null
181 
182         override fun startActivityAsUser(intent: Intent, user: UserHandle) {
183             // Always launch activity as system
184             assertTrue(user == UserHandle.SYSTEM)
185             this.intent = intent
186         }
187 
188         override fun startActivity(intent: Intent) {
189             this.intent = intent
190         }
191     }
192 }