blob: 540ac843ad8ec7c90470e9051803f2ec034440d3 [file] [log] [blame]
Fabian Kozynski1f32cf02018-10-23 12:23:31 -04001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.appops;
18
Fabian Kozynskia4b41842019-05-28 11:19:17 -040019import static junit.framework.TestCase.assertFalse;
20
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040021import static org.junit.Assert.assertEquals;
Fabian Kozynskia4b41842019-05-28 11:19:17 -040022import static org.junit.Assert.assertTrue;
Fabian Kozynski510585d2018-12-19 13:59:17 -050023import static org.mockito.ArgumentMatchers.any;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040024import static org.mockito.ArgumentMatchers.anyBoolean;
25import static org.mockito.ArgumentMatchers.anyInt;
Fabian Kozynski510585d2018-12-19 13:59:17 -050026import static org.mockito.ArgumentMatchers.anyLong;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040027import static org.mockito.ArgumentMatchers.anyString;
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000028import static org.mockito.ArgumentMatchers.eq;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040029import static org.mockito.Mockito.never;
30import static org.mockito.Mockito.times;
31import static org.mockito.Mockito.verify;
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000032import static org.mockito.Mockito.when;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040033
34import android.app.AppOpsManager;
Philip P. Moltmanne3dbb5a2019-03-07 10:06:11 -080035import android.content.pm.PackageManager;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040036import android.os.UserHandle;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040037import android.testing.AndroidTestingRunner;
38import android.testing.TestableLooper;
39
Brett Chabot84151d92019-02-27 15:37:59 -080040import androidx.test.filters.SmallTest;
41
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040042import com.android.systemui.SysuiTestCase;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040043
44import org.junit.Before;
45import org.junit.Test;
46import org.junit.runner.RunWith;
47import org.mockito.Mock;
48import org.mockito.MockitoAnnotations;
49
50@SmallTest
51@RunWith(AndroidTestingRunner.class)
52@TestableLooper.RunWithLooper
53public class AppOpsControllerTest extends SysuiTestCase {
54 private static final String TEST_PACKAGE_NAME = "test";
Philip P. Moltmanne3dbb5a2019-03-07 10:06:11 -080055 private static final int TEST_UID = UserHandle.getUid(0, 0);
56 private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0);
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000057 private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0);
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040058
Fabian Kozynski510585d2018-12-19 13:59:17 -050059 @Mock
60 private AppOpsManager mAppOpsManager;
61 @Mock
Philip P. Moltmanne3dbb5a2019-03-07 10:06:11 -080062 private PackageManager mPackageManager;
63 @Mock
Fabian Kozynski510585d2018-12-19 13:59:17 -050064 private AppOpsController.Callback mCallback;
65 @Mock
66 private AppOpsControllerImpl.H mMockHandler;
Fabian Kozynski7c86b632019-06-07 13:07:27 -040067 @Mock
68 private PermissionFlagsCache mFlagsCache;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040069
70 private AppOpsControllerImpl mController;
Fabian Kozynski7c86b632019-06-07 13:07:27 -040071 private TestableLooper mTestableLooper;
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040072
73 @Before
74 public void setUp() {
75 MockitoAnnotations.initMocks(this);
Fabian Kozynski7c86b632019-06-07 13:07:27 -040076 mTestableLooper = TestableLooper.get(this);
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040077
78 getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager);
79
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000080 // All permissions of TEST_UID and TEST_UID_OTHER are user sensitive. None of
81 // TEST_UID_NON_USER_SENSITIVE are user sensitive.
82 getContext().setMockPackageManager(mPackageManager);
Fabian Kozynski7c86b632019-06-07 13:07:27 -040083 when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000084 eq(UserHandle.getUserHandleForUid(TEST_UID)))).thenReturn(
85 PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED);
Fabian Kozynski7c86b632019-06-07 13:07:27 -040086 when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000087 eq(UserHandle.getUserHandleForUid(TEST_UID_OTHER)))).thenReturn(
88 PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED);
Fabian Kozynski7c86b632019-06-07 13:07:27 -040089 when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
Fabian Kozynski53ceaf62019-06-04 16:21:46 +000090 eq(UserHandle.getUserHandleForUid(TEST_UID_NON_USER_SENSITIVE)))).thenReturn(0);
91
Fabian Kozynski7c86b632019-06-07 13:07:27 -040092 mController = new AppOpsControllerImpl(mContext, mTestableLooper.getLooper(), mFlagsCache);
Fabian Kozynski1f32cf02018-10-23 12:23:31 -040093 }
94
95 @Test
96 public void testOnlyListenForFewOps() {
97 mController.setListening(true);
98 verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController);
99 }
100
101 @Test
102 public void testStopListening() {
103 mController.setListening(false);
104 verify(mAppOpsManager, times(1)).stopWatchingActive(mController);
105 }
106
107 @Test
108 public void addCallback_includedCode() {
Fabian Kozynski510585d2018-12-19 13:59:17 -0500109 mController.addCallback(
110 new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION},
111 mCallback);
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400112 mController.onOpActiveChanged(
113 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
Fabian Kozynski0b4592c2018-12-20 12:58:45 -0500114 mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
Fabian Kozynski510585d2018-12-19 13:59:17 -0500115 AppOpsManager.MODE_ALLOWED);
Fabian Kozynski7c86b632019-06-07 13:07:27 -0400116 mTestableLooper.processAllMessages();
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400117 verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO,
118 TEST_UID, TEST_PACKAGE_NAME, true);
119 }
120
121 @Test
122 public void addCallback_notIncludedCode() {
123 mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback);
124 mController.onOpActiveChanged(
125 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
Fabian Kozynski7c86b632019-06-07 13:07:27 -0400126 mTestableLooper.processAllMessages();
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400127 verify(mCallback, never()).onActiveStateChanged(
128 anyInt(), anyInt(), anyString(), anyBoolean());
129 }
130
131 @Test
132 public void removeCallback_sameCode() {
133 mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
134 mController.removeCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
135 mController.onOpActiveChanged(
136 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
Fabian Kozynski7c86b632019-06-07 13:07:27 -0400137 mTestableLooper.processAllMessages();
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400138 verify(mCallback, never()).onActiveStateChanged(
139 anyInt(), anyInt(), anyString(), anyBoolean());
140 }
141
142 @Test
143 public void addCallback_notSameCode() {
144 mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
Fabian Kozynski510585d2018-12-19 13:59:17 -0500145 mController.removeCallback(new int[]{AppOpsManager.OP_CAMERA}, mCallback);
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400146 mController.onOpActiveChanged(
147 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
Fabian Kozynski7c86b632019-06-07 13:07:27 -0400148 mTestableLooper.processAllMessages();
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400149 verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO,
150 TEST_UID, TEST_PACKAGE_NAME, true);
151 }
152
153 @Test
154 public void getActiveItems_sameDetails() {
155 mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
156 TEST_UID, TEST_PACKAGE_NAME, true);
157 mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
158 TEST_UID, TEST_PACKAGE_NAME, true);
159 assertEquals(1, mController.getActiveAppOps().size());
160 }
161
162 @Test
163 public void getActiveItems_differentDetails() {
164 mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
165 TEST_UID, TEST_PACKAGE_NAME, true);
166 mController.onOpActiveChanged(AppOpsManager.OP_CAMERA,
167 TEST_UID, TEST_PACKAGE_NAME, true);
Fabian Kozynski0b4592c2018-12-20 12:58:45 -0500168 mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION,
Fabian Kozynski510585d2018-12-19 13:59:17 -0500169 TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
170 assertEquals(3, mController.getActiveAppOps().size());
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400171 }
172
Fabian Kozynski510585d2018-12-19 13:59:17 -0500173 @Test
174 public void getActiveItemsForUser() {
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400175 mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
176 TEST_UID, TEST_PACKAGE_NAME, true);
177 mController.onOpActiveChanged(AppOpsManager.OP_CAMERA,
178 TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
Fabian Kozynski0b4592c2018-12-20 12:58:45 -0500179 mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION,
Fabian Kozynski510585d2018-12-19 13:59:17 -0500180 TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
181 assertEquals(2,
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400182 mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size());
183 assertEquals(1,
Fabian Kozynski510585d2018-12-19 13:59:17 -0500184 mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID_OTHER)).size());
185 }
186
187 @Test
Fabian Kozynski53ceaf62019-06-04 16:21:46 +0000188 public void nonUserSensitiveOpsAreIgnored() {
189 mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
190 TEST_UID_NON_USER_SENSITIVE, TEST_PACKAGE_NAME, true);
191 assertEquals(0, mController.getActiveAppOpsForUser(
192 UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size());
193 }
194
195 @Test
Fabian Kozynski510585d2018-12-19 13:59:17 -0500196 public void opNotedScheduledForRemoval() {
197 mController.setBGHandler(mMockHandler);
Fabian Kozynski0b4592c2018-12-20 12:58:45 -0500198 mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
Fabian Kozynski510585d2018-12-19 13:59:17 -0500199 AppOpsManager.MODE_ALLOWED);
200 verify(mMockHandler).scheduleRemoval(any(AppOpItem.class), anyLong());
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400201 }
Fabian Kozynskia4b41842019-05-28 11:19:17 -0400202
203 @Test
204 public void noItemsAfterStopListening() {
205 mController.setBGHandler(mMockHandler);
206
207 mController.setListening(true);
208 mController.onOpActiveChanged(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
209 true);
210 mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
211 AppOpsManager.MODE_ALLOWED);
212 assertFalse(mController.getActiveAppOps().isEmpty());
213
214 mController.setListening(false);
215
216 verify(mMockHandler).removeCallbacksAndMessages(null);
217 assertTrue(mController.getActiveAppOps().isEmpty());
218 }
Fabian Kozynski1f32cf02018-10-23 12:23:31 -0400219}