1 /* 2 * Copyright (C) 2017 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.settings.notification; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.ArgumentMatchers.anyInt; 24 import static org.mockito.ArgumentMatchers.anyString; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.when; 27 28 import android.app.INotificationManager; 29 import android.app.role.RoleManager; 30 import android.app.usage.UsageEvents; 31 import android.bluetooth.BluetoothAdapter; 32 import android.companion.AssociationInfo; 33 import android.companion.ICompanionDeviceManager; 34 import android.content.ComponentName; 35 import android.content.pm.ApplicationInfo; 36 import android.content.pm.PackageInfo; 37 import android.content.pm.PackageManager; 38 import android.net.MacAddress; 39 import android.os.Build; 40 import android.os.Parcel; 41 42 import com.android.settings.notification.NotificationBackend.AppRow; 43 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 44 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 45 import com.android.settingslib.bluetooth.LocalBluetoothManager; 46 47 import com.google.common.collect.ImmutableList; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.Mock; 53 import org.mockito.MockitoAnnotations; 54 import org.robolectric.RobolectricTestRunner; 55 import org.robolectric.RuntimeEnvironment; 56 57 import java.util.ArrayList; 58 import java.util.Collection; 59 import java.util.List; 60 61 @RunWith(RobolectricTestRunner.class) 62 public class NotificationBackendTest { 63 64 @Mock 65 LocalBluetoothManager mBm; 66 @Mock 67 ICompanionDeviceManager mCdm; 68 @Mock 69 CachedBluetoothDeviceManager mCbm; 70 ComponentName mCn = new ComponentName("a", "b"); 71 @Mock 72 INotificationManager mInm; 73 NotificationBackend mNotificationBackend; 74 75 @Before setUp()76 public void setUp() { 77 MockitoAnnotations.initMocks(this); 78 when(mBm.getCachedDeviceManager()).thenReturn(mCbm); 79 mNotificationBackend = new NotificationBackend(); 80 mNotificationBackend.setNm(mInm); 81 } 82 83 @Test testMarkAppRow_fixedImportance()84 public void testMarkAppRow_fixedImportance() throws Exception { 85 PackageInfo pi = new PackageInfo(); 86 pi.packageName = "test"; 87 pi.applicationInfo = new ApplicationInfo(); 88 pi.applicationInfo.packageName = "test"; 89 pi.applicationInfo.uid = 123; 90 91 when(mInm.isImportanceLocked(pi.packageName, 123)).thenReturn(true); 92 93 AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, 94 mock(PackageManager.class), pi); 95 96 assertTrue(appRow.systemApp); 97 assertTrue(appRow.lockedImportance); 98 } 99 100 @Test testMarkAppRow_notFixedPermission()101 public void testMarkAppRow_notFixedPermission() throws Exception { 102 PackageInfo pi = new PackageInfo(); 103 pi.packageName = "test"; 104 pi.applicationInfo = new ApplicationInfo(); 105 pi.applicationInfo.packageName = "test"; 106 pi.applicationInfo.uid = 123; 107 108 when(mInm.isImportanceLocked(anyString(), anyInt())).thenReturn(false); 109 110 AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, 111 mock(PackageManager.class), pi); 112 113 assertFalse(appRow.systemApp); 114 assertFalse(appRow.lockedImportance); 115 } 116 117 @Test testMarkAppRow_targetsT_noPermissionRequest()118 public void testMarkAppRow_targetsT_noPermissionRequest() throws Exception { 119 PackageInfo pi = new PackageInfo(); 120 pi.packageName = "test"; 121 pi.applicationInfo = new ApplicationInfo(); 122 pi.applicationInfo.packageName = "test"; 123 pi.applicationInfo.uid = 123; 124 pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU; 125 pi.requestedPermissions = new String[] {"something"}; 126 127 when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false); 128 129 AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, 130 mock(PackageManager.class), pi); 131 132 assertFalse(appRow.systemApp); 133 assertTrue(appRow.lockedImportance); 134 } 135 136 @Test testMarkAppRow_targetsT_permissionRequest()137 public void testMarkAppRow_targetsT_permissionRequest() throws Exception { 138 PackageInfo pi = new PackageInfo(); 139 pi.packageName = "test"; 140 pi.applicationInfo = new ApplicationInfo(); 141 pi.applicationInfo.packageName = "test"; 142 pi.applicationInfo.uid = 123; 143 pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU; 144 pi.requestedPermissions = new String[] {"something", 145 android.Manifest.permission.POST_NOTIFICATIONS}; 146 147 when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false); 148 149 AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, 150 mock(PackageManager.class), pi); 151 152 assertFalse(appRow.systemApp); 153 assertFalse(appRow.lockedImportance); 154 } 155 156 @Test testGetAggregatedUsageEvents_multipleEventsAgg()157 public void testGetAggregatedUsageEvents_multipleEventsAgg() { 158 List<UsageEvents.Event> events = new ArrayList<>(); 159 UsageEvents.Event good = new UsageEvents.Event(); 160 good.mEventType = UsageEvents.Event.NOTIFICATION_INTERRUPTION; 161 good.mPackage = "pkg"; 162 good.mNotificationChannelId = "channel1"; 163 good.mTimeStamp = 2; 164 events.add(good); 165 UsageEvents.Event good2 = new UsageEvents.Event(); 166 good2.mEventType = UsageEvents.Event.NOTIFICATION_INTERRUPTION; 167 good2.mPackage = "pkg"; 168 good2.mNotificationChannelId = "channel2"; 169 good2.mTimeStamp = 3; 170 events.add(good2); 171 UsageEvents.Event good1 = new UsageEvents.Event(); 172 good1.mEventType = UsageEvents.Event.NOTIFICATION_INTERRUPTION; 173 good1.mPackage = "pkg"; 174 good1.mNotificationChannelId = "channel1"; 175 good1.mTimeStamp = 6; 176 events.add(good1); 177 NotificationBackend backend = new NotificationBackend(); 178 179 AppRow appRow = new AppRow(); 180 appRow.pkg = "pkg"; 181 backend.recordAggregatedUsageEvents(getUsageEvents(events), appRow); 182 183 assertThat(appRow.sentByChannel.get("channel1").sentCount).isEqualTo(2); 184 assertThat(appRow.sentByChannel.get("channel1").lastSent).isEqualTo(6); 185 assertThat(appRow.sentByChannel.get("channel1").avgSentWeekly).isEqualTo(2); 186 assertThat(appRow.sentByChannel.get("channel2").sentCount).isEqualTo(1); 187 assertThat(appRow.sentByChannel.get("channel2").lastSent).isEqualTo(3); 188 assertThat(appRow.sentByChannel.get("channel2").avgSentWeekly).isEqualTo(1); 189 assertThat(appRow.sentByApp.sentCount).isEqualTo(3); 190 assertThat(appRow.sentByApp.lastSent).isEqualTo(6); 191 assertThat(appRow.sentByApp.avgSentWeekly).isEqualTo(3); 192 } 193 getUsageEvents(List<UsageEvents.Event> events)194 private UsageEvents getUsageEvents(List<UsageEvents.Event> events) { 195 UsageEvents usageEvents = new UsageEvents(events, new String[] {"pkg"}); 196 Parcel parcel = Parcel.obtain(); 197 parcel.setDataPosition(0); 198 usageEvents.writeToParcel(parcel, 0); 199 parcel.setDataPosition(0); 200 return UsageEvents.CREATOR.createFromParcel(parcel); 201 } 202 203 @Test getDeviceList_noAssociations()204 public void getDeviceList_noAssociations() throws Exception { 205 when(mCdm.getAssociations(mCn.getPackageName(), 0)).thenReturn(null); 206 207 Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>(); 208 CachedBluetoothDevice cbd1 = mock(CachedBluetoothDevice.class); 209 when(cbd1.getAddress()).thenReturn("00:00:00:00:00:10"); 210 when(cbd1.getName()).thenReturn("Device 1"); 211 cachedDevices.add(cbd1); 212 when(mCbm.getCachedDevicesCopy()).thenReturn(cachedDevices); 213 214 BluetoothAdapter.getDefaultAdapter().enable(); 215 216 assertThat(new NotificationBackend().getDeviceList( 217 mCdm, mBm, mCn.getPackageName(), 0).toString()).isEmpty(); 218 } 219 220 @Test getDeviceList_associationsButNoDevice()221 public void getDeviceList_associationsButNoDevice() throws Exception { 222 List<AssociationInfo> associations = 223 mockAssociations("00:00:00:00:00:10", "00:00:00:00:00:20"); 224 when(mCdm.getAssociations(mCn.getPackageName(), 0)).thenReturn(associations); 225 226 when(mCbm.getCachedDevicesCopy()).thenReturn(new ArrayList<>()); 227 228 assertThat(new NotificationBackend().getDeviceList( 229 mCdm, mBm, mCn.getPackageName(), 0).toString()).isEmpty(); 230 } 231 232 @Test getDeviceList_singleDevice()233 public void getDeviceList_singleDevice() throws Exception { 234 String[] macs = { "00:00:00:00:00:10", "00:00:00:00:00:20" }; 235 List<AssociationInfo> associations = mockAssociations(macs); 236 when(mCdm.getAssociations(mCn.getPackageName(), 0)).thenReturn(associations); 237 238 Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>(); 239 CachedBluetoothDevice cbd1 = mock(CachedBluetoothDevice.class); 240 when(cbd1.getAddress()).thenReturn(macs[0]); 241 when(cbd1.getName()).thenReturn("Device 1"); 242 cachedDevices.add(cbd1); 243 when(mCbm.getCachedDevicesCopy()).thenReturn(cachedDevices); 244 245 assertThat(new NotificationBackend().getDeviceList( 246 mCdm, mBm, mCn.getPackageName(), 0).toString()).isEqualTo("Device 1"); 247 } 248 249 @Test getDeviceList_multipleDevices()250 public void getDeviceList_multipleDevices() throws Exception { 251 String[] macs = { "00:00:00:00:00:10", "00:00:00:00:00:20" }; 252 List<AssociationInfo> associations = mockAssociations(macs); 253 when(mCdm.getAssociations(mCn.getPackageName(), 0)).thenReturn(associations); 254 255 Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>(); 256 CachedBluetoothDevice cbd1 = mock(CachedBluetoothDevice.class); 257 when(cbd1.getAddress()).thenReturn(macs[0]); 258 when(cbd1.getName()).thenReturn("Device 1"); 259 cachedDevices.add(cbd1); 260 261 CachedBluetoothDevice cbd2 = mock(CachedBluetoothDevice.class); 262 when(cbd2.getAddress()).thenReturn(macs[1]); 263 when(cbd2.getName()).thenReturn("Device 2"); 264 cachedDevices.add(cbd2); 265 when(mCbm.getCachedDevicesCopy()).thenReturn(cachedDevices); 266 267 assertThat(new NotificationBackend().getDeviceList( 268 mCdm, mBm, mCn.getPackageName(), 0).toString()).isEqualTo("Device 1, Device 2"); 269 } 270 mockAssociations(String... macAddresses)271 private ImmutableList<AssociationInfo> mockAssociations(String... macAddresses) { 272 final AssociationInfo[] associations = new AssociationInfo[macAddresses.length]; 273 for (int index = 0; index < macAddresses.length; index++) { 274 final AssociationInfo association = mock(AssociationInfo.class); 275 when(association.isSelfManaged()).thenReturn(false); 276 when(association.getDeviceMacAddress()) 277 .thenReturn(MacAddress.fromString(macAddresses[index])); 278 associations[index] = association; 279 } 280 return ImmutableList.copyOf(associations); 281 } 282 } 283