blob: 6c5928245d1394f4b451ee3c8328022b027a1448 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.cts;
import android.app.PolicyProto;
import android.service.notification.ConditionProto;
import android.service.notification.ManagedServicesProto;
import android.service.notification.NotificationRecordProto;
import android.service.notification.NotificationServiceDumpProto;
import android.service.notification.RankingHelperProto;
import android.service.notification.RankingHelperProto.RecordProto;
import android.service.notification.ZenMode;
import android.service.notification.ZenModeProto;
import android.service.notification.ZenRuleProto;
import com.android.tradefed.device.ITestDevice;
import java.util.List;
/**
* Test to check that the notification service properly outputs its dump state.
*
* make -j32 CtsIncidentHostTestCases
* cts-tradefed run singleCommand cts-dev -d --module CtsIncidentHostTestCases
*/
public class NotificationIncidentTest extends ProtoDumpTestCase {
// Constants from android.app.NotificationManager
private static final int IMPORTANCE_UNSPECIFIED = -1000;
private static final int IMPORTANCE_NONE = 0;
private static final int IMPORTANCE_MAX = 5;
private static final int VISIBILITY_NO_OVERRIDE = -1000;
// Constants from android.app.Notification
private static final int PRIORITY_MIN = -2;
private static final int PRIORITY_MAX = 2;
private static final int VISIBILITY_SECRET = -1;
private static final int VISIBILITY_PUBLIC = 1;
// These constants are those in PackageManager.
public static final String FEATURE_WATCH = "android.hardware.type.watch";
private static final String DEVICE_SIDE_TEST_APK = "CtsNotificationIncidentTestApp.apk";
private static final String TEST_APP_TAG = "NotificationIncidentTestActivity";
private static final String TEST_APP_LOG = "Notification posted.";
private static final String TEST_ACTIVITY =
"com.android.server.cts.notifications/.NotificationIncidentTestActivity";
private static final int WAIT_MS = 1000;
private static final String DEVICE_SIDE_TEST_PKG = "com.android.server.cts.notifications";
/**
* Tests that at least one notification is posted, and verify its properties are plausible.
*/
public void testNotificationRecords() throws Exception {
ITestDevice device = getDevice();
try {
installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true);
int retries = 3;
do {
device.executeShellCommand("am start -n " + TEST_ACTIVITY);
} while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0);
final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(),
"dumpsys notification --proto");
assertTrue(dump.getRecordsCount() > 0);
boolean found = false;
for (NotificationRecordProto record : dump.getRecordsList()) {
if (record.getKey().contains("android")) {
found = true;
assertTrue(record.getImportance() > IMPORTANCE_NONE);
// Ensure these fields exist, at least
record.getFlags();
record.getChannelId();
record.getSound();
record.getAudioAttributes();
record.getCanVibrate();
record.getCanShowLight();
record.getGroupKey();
}
assertTrue(
NotificationRecordProto.State.getDescriptor()
.getValues()
.contains(record.getState().getValueDescriptor()));
}
assertTrue(found);
} finally {
if (device.getInstalledPackageNames().contains(DEVICE_SIDE_TEST_PKG)) {
device.uninstallPackage(DEVICE_SIDE_TEST_PKG);
}
}
}
/** Test valid values from the RankingHelper. */
public void testRankingConfig() throws Exception {
final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(),
"dumpsys notification --proto");
verifyRankingHelperProto(dump.getRankingConfig(), PRIVACY_NONE);
}
private static void verifyRankingHelperProto(RankingHelperProto rhProto, final int filterLevel) throws Exception {
for (RecordProto rp : rhProto.getRecordsList()) {
verifyRecordProto(rp);
}
for (RecordProto rp : rhProto.getRecordsRestoredWithoutUidList()) {
verifyRecordProto(rp);
}
}
private static void verifyRecordProto(RecordProto rp) throws Exception {
assertTrue(!rp.getPackage().isEmpty());
assertTrue(rp.getUid() == -10000 || rp.getUid() >= 0);
assertTrue("Record importance is an invalid value: " + rp.getImportance(),
rp.getImportance() == IMPORTANCE_UNSPECIFIED ||
(rp.getImportance() >= IMPORTANCE_NONE && rp.getImportance() <= IMPORTANCE_MAX));
assertTrue(rp.getPriority() >= PRIORITY_MIN && rp.getPriority() <= PRIORITY_MAX);
assertTrue("Record visibility is an invalid value: " + rp.getVisibility(),
rp.getVisibility() == VISIBILITY_NO_OVERRIDE ||
(rp.getVisibility() >= VISIBILITY_SECRET &&
rp.getVisibility() <= VISIBILITY_PUBLIC));
}
// Tests default state: zen mode is a valid/expected value
public void testZenMode() throws Exception {
final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(),
"dumpsys notification --proto");
verifyZenModeProto(dump.getZen(), PRIVACY_NONE);
}
private static void verifyZenModeProto(ZenModeProto zenProto, final int filterLevel) throws Exception {
assertTrue("Unexpected ZenMode value",
ZenMode.getDescriptor().getValues().contains(zenProto.getZenMode().getValueDescriptor()));
List<ZenRuleProto> zenRules = zenProto.getEnabledActiveConditionsList();
for (int i = 0; i < zenRules.size(); ++i) {
ZenRuleProto zr = zenRules.get(i);
ConditionProto cp = zr.getCondition();
if (filterLevel == PRIVACY_AUTO) {
assertTrue(zr.getId().isEmpty());
assertTrue(zr.getName().isEmpty());
assertTrue(zr.getConditionId().isEmpty());
assertTrue(cp.getId().isEmpty());
assertTrue(cp.getSummary().isEmpty());
assertTrue(cp.getLine1().isEmpty());
assertTrue(cp.getLine2().isEmpty());
} else if (i > 0) {
// There will be at most one manual rule, the rest will be automatic. The fields
// tested here are required for automatic rules.
assertFalse(zr.getId().isEmpty());
assertFalse(zr.getName().isEmpty());
assertTrue(zr.getCreationTimeMs() > 0);
assertFalse(zr.getConditionId().isEmpty());
}
assertTrue(ConditionProto.State.getDescriptor().getValues()
.contains(cp.getState().getValueDescriptor()));
}
PolicyProto policy = zenProto.getPolicy();
for (PolicyProto.Category c : policy.getPriorityCategoriesList()) {
assertTrue(PolicyProto.Category.getDescriptor().getValues()
.contains(c.getValueDescriptor()));
}
assertTrue(PolicyProto.Sender.getDescriptor().getValues()
.contains(policy.getPriorityCallSender().getValueDescriptor()));
assertTrue(PolicyProto.Sender.getDescriptor().getValues()
.contains(policy.getPriorityMessageSender().getValueDescriptor()));
for (PolicyProto.SuppressedVisualEffect sve : policy.getSuppressedVisualEffectsList()) {
assertTrue(PolicyProto.SuppressedVisualEffect.getDescriptor().getValues()
.contains(sve.getValueDescriptor()));
}
}
static void verifyNotificationServiceDumpProto(NotificationServiceDumpProto dump, final int filterLevel) throws Exception {
for (NotificationRecordProto nr : dump.getRecordsList()) {
verifyNotificationRecordProto(nr, filterLevel);
}
verifyZenModeProto(dump.getZen(), filterLevel);
verifyManagedServicesProto(dump.getNotificationListeners(), filterLevel);
verifyManagedServicesProto(dump.getNotificationAssistants(), filterLevel);
verifyManagedServicesProto(dump.getConditionProviders(), filterLevel);
verifyRankingHelperProto(dump.getRankingConfig(), filterLevel);
}
private static void verifyManagedServicesProto(ManagedServicesProto ms, final int filterLevel) throws Exception {
for (ManagedServicesProto.ServiceProto sp : ms.getApprovedList()) {
for (String n : sp.getNameList()) {
assertFalse(n.isEmpty());
}
assertTrue(sp.getUserId() >= 0);
}
}
private static void verifyNotificationRecordProto(NotificationRecordProto record, final int filterLevel) throws Exception {
// Ensure these fields exist, at least
record.getFlags();
record.getChannelId();
record.getSound();
record.getAudioAttributes();
record.getCanVibrate();
record.getCanShowLight();
record.getGroupKey();
if (filterLevel == PRIVACY_AUTO) {
assertTrue(record.getChannelId().isEmpty());
assertTrue(record.getSound().isEmpty());
assertTrue(record.getGroupKey().isEmpty());
}
assertTrue(NotificationRecordProto.State.getDescriptor().getValues()
.contains(record.getState().getValueDescriptor()));
}
}