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.server.cts; 18 19 import android.app.PolicyProto; 20 import android.service.notification.ConditionProto; 21 import android.service.notification.ManagedServicesProto; 22 import android.service.notification.NotificationRecordProto; 23 import android.service.notification.NotificationServiceDumpProto; 24 import android.service.notification.RankingHelperProto; 25 import android.service.notification.RankingHelperProto.RecordProto; 26 import android.service.notification.ZenMode; 27 import android.service.notification.ZenModeProto; 28 import android.service.notification.ZenRuleProto; 29 30 import com.android.tradefed.device.ITestDevice; 31 32 import java.util.List; 33 34 /** 35 * Test to check that the notification service properly outputs its dump state. 36 * 37 * make -j32 CtsIncidentHostTestCases 38 * cts-tradefed run singleCommand cts-dev -d --module CtsIncidentHostTestCases 39 */ 40 public class NotificationIncidentTest extends ProtoDumpTestCase { 41 // Constants from android.app.NotificationManager 42 private static final int IMPORTANCE_UNSPECIFIED = -1000; 43 private static final int IMPORTANCE_NONE = 0; 44 private static final int IMPORTANCE_MAX = 5; 45 private static final int VISIBILITY_NO_OVERRIDE = -1000; 46 // Constants from android.app.Notification 47 private static final int PRIORITY_MIN = -2; 48 private static final int PRIORITY_MAX = 2; 49 private static final int VISIBILITY_SECRET = -1; 50 private static final int VISIBILITY_PUBLIC = 1; 51 // These constants are those in PackageManager. 52 public static final String FEATURE_WATCH = "android.hardware.type.watch"; 53 54 private static final String DEVICE_SIDE_TEST_APK = "CtsNotificationIncidentTestApp.apk"; 55 private static final String TEST_APP_TAG = "NotificationIncidentTestActivity"; 56 private static final String TEST_APP_LOG = "Notification posted."; 57 private static final String TEST_ACTIVITY = 58 "com.android.server.cts.notifications/.NotificationIncidentTestActivity"; 59 private static final int WAIT_MS = 1000; 60 private static final String DEVICE_SIDE_TEST_PKG = "com.android.server.cts.notifications"; 61 62 /** 63 * Tests that at least one notification is posted, and verify its properties are plausible. 64 */ testNotificationRecords()65 public void testNotificationRecords() throws Exception { 66 ITestDevice device = getDevice(); 67 try { 68 installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); 69 int retries = 3; 70 do { 71 device.executeShellCommand("am start -n " + TEST_ACTIVITY); 72 } while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0); 73 74 final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(), 75 "dumpsys notification --proto"); 76 77 assertTrue(dump.getRecordsCount() > 0); 78 boolean found = false; 79 for (NotificationRecordProto record : dump.getRecordsList()) { 80 if (record.getKey().contains("android")) { 81 found = true; 82 assertTrue(record.getImportance() > IMPORTANCE_NONE); 83 84 // Ensure these fields exist, at least 85 record.getFlags(); 86 record.getChannelId(); 87 record.getSound(); 88 record.getAudioAttributes(); 89 record.getCanVibrate(); 90 record.getCanShowLight(); 91 record.getGroupKey(); 92 } 93 assertTrue( 94 NotificationRecordProto.State.getDescriptor() 95 .getValues() 96 .contains(record.getState().getValueDescriptor())); 97 } 98 99 assertTrue(found); 100 } finally { 101 if (device.getInstalledPackageNames().contains(DEVICE_SIDE_TEST_PKG)) { 102 device.uninstallPackage(DEVICE_SIDE_TEST_PKG); 103 } 104 } 105 } 106 107 /** Test valid values from the RankingHelper. */ testRankingConfig()108 public void testRankingConfig() throws Exception { 109 final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(), 110 "dumpsys notification --proto"); 111 112 verifyRankingHelperProto(dump.getRankingConfig(), PRIVACY_NONE); 113 } 114 verifyRankingHelperProto(RankingHelperProto rhProto, final int filterLevel)115 private static void verifyRankingHelperProto(RankingHelperProto rhProto, final int filterLevel) throws Exception { 116 for (RecordProto rp : rhProto.getRecordsList()) { 117 verifyRecordProto(rp); 118 } 119 for (RecordProto rp : rhProto.getRecordsRestoredWithoutUidList()) { 120 verifyRecordProto(rp); 121 } 122 } 123 verifyRecordProto(RecordProto rp)124 private static void verifyRecordProto(RecordProto rp) throws Exception { 125 assertTrue(!rp.getPackage().isEmpty()); 126 assertTrue(rp.getUid() == -10000 || rp.getUid() >= 0 || rp.getUid() == -1); 127 assertTrue("Record importance is an invalid value: " + rp.getImportance(), 128 rp.getImportance() == IMPORTANCE_UNSPECIFIED || 129 (rp.getImportance() >= IMPORTANCE_NONE && rp.getImportance() <= IMPORTANCE_MAX)); 130 assertTrue(rp.getPriority() >= PRIORITY_MIN && rp.getPriority() <= PRIORITY_MAX); 131 assertTrue("Record visibility is an invalid value: " + rp.getVisibility(), 132 rp.getVisibility() == VISIBILITY_NO_OVERRIDE || 133 (rp.getVisibility() >= VISIBILITY_SECRET && 134 rp.getVisibility() <= VISIBILITY_PUBLIC)); 135 } 136 137 // Tests default state: zen mode is a valid/expected value testZenMode()138 public void testZenMode() throws Exception { 139 final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(), 140 "dumpsys notification --proto"); 141 142 verifyZenModeProto(dump.getZen(), PRIVACY_NONE); 143 } 144 verifyZenModeProto(ZenModeProto zenProto, final int filterLevel)145 private static void verifyZenModeProto(ZenModeProto zenProto, final int filterLevel) throws Exception { 146 assertTrue("Unexpected ZenMode value", 147 ZenMode.getDescriptor().getValues().contains(zenProto.getZenMode().getValueDescriptor())); 148 149 List<ZenRuleProto> zenRules = zenProto.getEnabledActiveConditionsList(); 150 for (int i = 0; i < zenRules.size(); ++i) { 151 ZenRuleProto zr = zenRules.get(i); 152 ConditionProto cp = zr.getCondition(); 153 if (filterLevel == PRIVACY_AUTO) { 154 assertTrue(zr.getId().isEmpty()); 155 assertTrue(zr.getName().isEmpty()); 156 assertTrue(zr.getConditionId().isEmpty()); 157 158 assertTrue(cp.getId().isEmpty()); 159 assertTrue(cp.getSummary().isEmpty()); 160 assertTrue(cp.getLine1().isEmpty()); 161 assertTrue(cp.getLine2().isEmpty()); 162 } else if (i > 0) { 163 // There will be at most one manual rule, the rest will be automatic. The fields 164 // tested here are required for automatic rules. 165 assertFalse(zr.getId().isEmpty()); 166 assertFalse(zr.getName().isEmpty()); 167 assertTrue(zr.getCreationTimeMs() > 0); 168 assertFalse(zr.getConditionId().isEmpty()); 169 } 170 171 assertTrue(ConditionProto.State.getDescriptor().getValues() 172 .contains(cp.getState().getValueDescriptor())); 173 } 174 175 PolicyProto policy = zenProto.getPolicy(); 176 for (PolicyProto.Category c : policy.getPriorityCategoriesList()) { 177 assertTrue(PolicyProto.Category.getDescriptor().getValues() 178 .contains(c.getValueDescriptor())); 179 } 180 assertTrue(PolicyProto.Sender.getDescriptor().getValues() 181 .contains(policy.getPriorityCallSender().getValueDescriptor())); 182 assertTrue(PolicyProto.Sender.getDescriptor().getValues() 183 .contains(policy.getPriorityMessageSender().getValueDescriptor())); 184 for (PolicyProto.SuppressedVisualEffect sve : policy.getSuppressedVisualEffectsList()) { 185 assertTrue(PolicyProto.SuppressedVisualEffect.getDescriptor().getValues() 186 .contains(sve.getValueDescriptor())); 187 } 188 } 189 verifyNotificationServiceDumpProto(NotificationServiceDumpProto dump, final int filterLevel)190 static void verifyNotificationServiceDumpProto(NotificationServiceDumpProto dump, final int filterLevel) throws Exception { 191 for (NotificationRecordProto nr : dump.getRecordsList()) { 192 verifyNotificationRecordProto(nr, filterLevel); 193 } 194 verifyZenModeProto(dump.getZen(), filterLevel); 195 verifyManagedServicesProto(dump.getNotificationListeners(), filterLevel); 196 verifyManagedServicesProto(dump.getNotificationAssistants(), filterLevel); 197 verifyManagedServicesProto(dump.getConditionProviders(), filterLevel); 198 verifyRankingHelperProto(dump.getRankingConfig(), filterLevel); 199 } 200 verifyManagedServicesProto(ManagedServicesProto ms, final int filterLevel)201 private static void verifyManagedServicesProto(ManagedServicesProto ms, final int filterLevel) throws Exception { 202 for (ManagedServicesProto.ServiceProto sp : ms.getApprovedList()) { 203 for (String n : sp.getNameList()) { 204 assertFalse(n.isEmpty()); 205 } 206 assertTrue(sp.getUserId() >= 0); 207 } 208 } 209 verifyNotificationRecordProto(NotificationRecordProto record, final int filterLevel)210 private static void verifyNotificationRecordProto(NotificationRecordProto record, final int filterLevel) throws Exception { 211 // Ensure these fields exist, at least 212 record.getFlags(); 213 record.getChannelId(); 214 record.getSound(); 215 record.getAudioAttributes(); 216 record.getCanVibrate(); 217 record.getCanShowLight(); 218 record.getGroupKey(); 219 220 if (filterLevel == PRIVACY_AUTO) { 221 assertTrue(record.getChannelId().isEmpty()); 222 assertTrue(record.getSound().isEmpty()); 223 assertTrue(record.getGroupKey().isEmpty()); 224 } 225 226 assertTrue(NotificationRecordProto.State.getDescriptor().getValues() 227 .contains(record.getState().getValueDescriptor())); 228 } 229 } 230