From 1a934a338e13e0263d5fe7c081782394205291e4 Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Tue, 19 May 2020 13:45:46 -0400 Subject: [PATCH] add unit tests for the atom puller Bug: 153195691 Test: atest PreferencesHelperTest Change-Id: Ieea24601a6a110ed391ade42800036df62073cca --- .../NotificationManagerService.java | 3 +- .../notification/PreferencesHelper.java | 11 +- .../server/notification/SysUiStatsEvent.java | 68 ++++++ services/tests/uiservicestests/Android.bp | 1 + .../notification/PreferencesHelperTest.java | 220 ++++++++++++++---- .../notification/WrappedSysUiStatsEvent.java | 133 +++++++++++ 6 files changed, 389 insertions(+), 47 deletions(-) create mode 100644 services/core/java/com/android/server/notification/SysUiStatsEvent.java create mode 100644 services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 86e8734177f04..0e3216093c737 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1950,7 +1950,8 @@ public class NotificationManagerService extends SystemService { mRankingHandler, mZenModeHelper, new NotificationChannelLoggerImpl(), - mAppOps); + mAppOps, + new SysUiStatsEvent.BuilderFactory()); mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 9d56d817440bd..ba2cd279d493b 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -139,6 +139,7 @@ public class PreferencesHelper implements RankingConfig { * fields. */ private static final int DEFAULT_LOCKED_APP_FIELDS = 0; + private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory; /** * All user-lockable fields for a given application. @@ -170,13 +171,15 @@ public class PreferencesHelper implements RankingConfig { public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger, - AppOpsManager appOpsManager) { + AppOpsManager appOpsManager, + SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) { mContext = context; mZenModeHelper = zenHelper; mRankingHandler = rankingHandler; mPm = pm; mNotificationChannelLogger = notificationChannelLogger; mAppOps = appOpsManager; + mStatsEventBuilderFactory = statsEventBuilderFactory; updateBadgingEnabled(); updateBubblesEnabled(); @@ -1897,7 +1900,7 @@ public class PreferencesHelper implements RankingConfig { if (i > NOTIFICATION_PREFERENCES_PULL_LIMIT) { break; } - StatsEvent.Builder event = StatsEvent.newBuilder() + SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder() .setAtomId(PACKAGE_NOTIFICATION_PREFERENCES); final PackagePreferences r = mPackagePreferences.valueAt(i); event.writeInt(r.uid); @@ -1926,7 +1929,7 @@ public class PreferencesHelper implements RankingConfig { if (++totalChannelsPulled > NOTIFICATION_CHANNEL_PULL_LIMIT) { break; } - StatsEvent.Builder event = StatsEvent.newBuilder() + SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder() .setAtomId(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES); event.writeInt(r.uid); event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true); @@ -1961,7 +1964,7 @@ public class PreferencesHelper implements RankingConfig { if (++totalGroupsPulled > NOTIFICATION_CHANNEL_GROUP_PULL_LIMIT) { break; } - StatsEvent.Builder event = StatsEvent.newBuilder() + SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder() .setAtomId(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES); event.writeInt(r.uid); event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true); diff --git a/services/core/java/com/android/server/notification/SysUiStatsEvent.java b/services/core/java/com/android/server/notification/SysUiStatsEvent.java new file mode 100644 index 0000000000000..9bc2346d4e963 --- /dev/null +++ b/services/core/java/com/android/server/notification/SysUiStatsEvent.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 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.notification; + +import android.util.StatsEvent; + +/** + * Wrapper for StatsEvent that enables unit testing. + */ +public class SysUiStatsEvent { + + static class Builder { + private final StatsEvent.Builder mBuilder; + + protected Builder(StatsEvent.Builder builder) { + mBuilder = builder; + } + + public StatsEvent build() { + return mBuilder.build(); + } + + public Builder setAtomId(int atomId) { + mBuilder.setAtomId(atomId); + return this; + } + + public Builder writeInt(int value) { + mBuilder.writeInt(value); + return this; + } + + public Builder addBooleanAnnotation(byte annotation, boolean value) { + mBuilder.addBooleanAnnotation(annotation, value); + return this; + } + + public Builder writeString(String value) { + mBuilder.writeString(value); + return this; + } + + public Builder writeBoolean(boolean value) { + mBuilder.writeBoolean(value); + return this; + } + } + + static class BuilderFactory { + Builder newBuilder() { + return new Builder(StatsEvent.newBuilder()); + } + } +} diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp index b7199f7cdd5a0..4439f998a527f 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -21,6 +21,7 @@ android_test { "mockito-target-inline-minus-junit4", "platform-test-annotations", "platformprotosnano", + "statsdprotolite", "hamcrest-library", "testables", "truth-prebuilt", diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 078c21e045129..bd45c3d90916e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -29,6 +29,16 @@ import static android.app.NotificationManager.IMPORTANCE_MAX; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID; +import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IMPORTANCE_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_CONVERSATION_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DELETED_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DEMOTED_CONVERSATION_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_IMPORTANT_CONVERSATION_FIELD_NUMBER; +import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.UID_FIELD_NUMBER; import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE; import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT; @@ -90,7 +100,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.FastXmlSerializer; import com.android.server.UiServiceTestCase; - import org.json.JSONArray; import org.json.JSONObject; import org.junit.Before; @@ -109,6 +118,7 @@ import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -145,6 +155,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { private PreferencesHelper mHelper; private AudioAttributes mAudioAttributes; private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake(); + private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; @Before public void setUp() throws Exception { @@ -196,8 +207,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT); + + mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory(); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); resetZenModeHelper(); mAudioAttributes = new AudioAttributes.Builder() @@ -1482,7 +1496,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); assertFalse(mHelper.areChannelsBypassingDnd()); verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); resetZenModeHelper(); @@ -1494,7 +1508,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0); when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); assertFalse(mHelper.areChannelsBypassingDnd()); verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); resetZenModeHelper(); @@ -2261,7 +2275,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { + "\n" + "\n"; mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadByteArrayXml(preQXml.getBytes(), true, UserHandle.USER_SYSTEM); assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, @@ -2274,7 +2288,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, @@ -2371,7 +2385,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); @@ -2383,7 +2397,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O)); @@ -2396,7 +2410,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); @@ -2409,7 +2423,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); // appears disabled @@ -2428,7 +2442,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); // appears disabled @@ -2447,7 +2461,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O)); @@ -2502,7 +2516,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O)); @@ -2519,7 +2533,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); @@ -2998,31 +3012,6 @@ public class PreferencesHelperTest extends UiServiceTestCase { PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId); } - - @Test - public void testPullConversationNotificationChannel() { - String conversationId = "friend"; - - NotificationChannel parent = - new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); - - String channelId = String.format( - CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId); - NotificationChannel friend = new NotificationChannel(channelId, - "messages", IMPORTANCE_DEFAULT); - friend.setConversationId(parent.getId(), conversationId); - mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); - ArrayList events = new ArrayList<>(); - mHelper.pullPackageChannelPreferencesStats(events); - boolean found = false; - for (StatsEvent event : events) { - // TODO(b/153195691): inspect the content once it is possible to do so - found = true; - } - assertTrue("conversation was not in the pull", found); - } - @Test public void testGetNotificationChannel_conversationProvidedByNotCustomizedYet() { String conversationId = "friend"; @@ -3056,7 +3045,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testPlaceholderConversationId_shortcutRequired() throws Exception { mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); final String xml = "\n" + "\n" @@ -3075,7 +3064,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testNormalConversationId_shortcutRequired() throws Exception { mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); final String xml = "\n" + "\n" @@ -3094,7 +3083,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testNoConversationId_shortcutRequired() throws Exception { mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, - mAppOpsManager); + mAppOpsManager, mStatsEventBuilderFactory); final String xml = "\n" + "\n" @@ -3456,4 +3445,151 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.setValidMessageSent(PKG_P, UID_P); assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P)); } + + @Test + public void testPullPackageChannelPreferencesStats() { + String channelId = "parent"; + String name = "messages"; + NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false); + NotificationChannel channel = + new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + NotificationChannel fodderB = new NotificationChannel("b", "b", IMPORTANCE_HIGH); + mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false); + + ArrayList events = new ArrayList<>(); + mHelper.pullPackageChannelPreferencesStats(events); + + int found = 0; + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES + && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) { + ++found; + assertEquals("uid", UID_O, builder.getValue(UID_FIELD_NUMBER)); + assertTrue("uid annotation", builder.getBooleanAnnotation( + UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID)); + assertEquals("importance", IMPORTANCE_DEFAULT, builder.getValue( + IMPORTANCE_FIELD_NUMBER)); + assertEquals("name", name, builder.getValue(CHANNEL_NAME_FIELD_NUMBER)); + assertFalse("isconv", builder.getBoolean(IS_CONVERSATION_FIELD_NUMBER)); + assertFalse("deleted", builder.getBoolean(IS_DELETED_FIELD_NUMBER)); + } + } + } + + @Test + public void testPullPackageChannelPreferencesStats_one_to_one() { + NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false); + NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false); + NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH); + mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false); + + List channels = new LinkedList<>(Arrays.asList("a", "b", "c")); + + ArrayList events = new ArrayList<>(); + mHelper.pullPackageChannelPreferencesStats(events); + + int found = 0; + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES) { + Object id = builder.getValue(CHANNEL_ID_FIELD_NUMBER); + assertTrue("missing channel in the output", channels.contains(id)); + channels.remove(id); + } + } + assertTrue("unexpected channel in output", channels.isEmpty()); + } + + @Test + public void testPullPackageChannelPreferencesStats_conversation() { + String conversationId = "friend"; + + NotificationChannel parent = + new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + + String channelId = String.format( + CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId); + String name = "conversation"; + NotificationChannel friend = new NotificationChannel(channelId, + name, IMPORTANCE_DEFAULT); + friend.setConversationId(parent.getId(), conversationId); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + + ArrayList events = new ArrayList<>(); + mHelper.pullPackageChannelPreferencesStats(events); + + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES + && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) { + assertTrue("isConveration should be true", builder.getBoolean( + IS_CONVERSATION_FIELD_NUMBER)); + assertFalse("not demoted", builder.getBoolean( + IS_DEMOTED_CONVERSATION_FIELD_NUMBER)); + assertFalse("not important", builder.getBoolean( + IS_IMPORTANT_CONVERSATION_FIELD_NUMBER)); + } + } + } + + @Test + public void testPullPackageChannelPreferencesStats_conversation_demoted() { + NotificationChannel parent = + new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + String channelId = String.format( + CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend"); + NotificationChannel friend = new NotificationChannel(channelId, + "conversation", IMPORTANCE_DEFAULT); + friend.setConversationId(parent.getId(), "friend"); + friend.setDemoted(true); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + + ArrayList events = new ArrayList<>(); + mHelper.pullPackageChannelPreferencesStats(events); + + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES + && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) { + assertTrue("isConveration should be true", builder.getBoolean( + IS_CONVERSATION_FIELD_NUMBER)); + assertTrue("is demoted", builder.getBoolean( + IS_DEMOTED_CONVERSATION_FIELD_NUMBER)); + assertFalse("not important", builder.getBoolean( + IS_IMPORTANT_CONVERSATION_FIELD_NUMBER)); + } + } + } + + @Test + public void testPullPackageChannelPreferencesStats_conversation_priority() { + NotificationChannel parent = + new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + String channelId = String.format( + CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend"); + NotificationChannel friend = new NotificationChannel(channelId, + "conversation", IMPORTANCE_DEFAULT); + friend.setConversationId(parent.getId(), "friend"); + friend.setImportantConversation(true); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + + ArrayList events = new ArrayList<>(); + mHelper.pullPackageChannelPreferencesStats(events); + + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES + && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) { + assertTrue("isConveration should be true", builder.getBoolean( + IS_CONVERSATION_FIELD_NUMBER)); + assertFalse("not demoted", builder.getBoolean( + IS_DEMOTED_CONVERSATION_FIELD_NUMBER)); + assertTrue("is important", builder.getBoolean( + IS_IMPORTANT_CONVERSATION_FIELD_NUMBER)); + } + } + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java new file mode 100644 index 0000000000000..f4f64d779d304 --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2020 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.notification; + +import android.util.StatsEvent; + +import com.android.server.notification.SysUiStatsEvent.Builder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Wrapper for SysUiStatsEvent that implements validation. + */ +public class WrappedSysUiStatsEvent { + + static class WrappedBuilder extends Builder { + private ArrayList mValues; + private HashMap> mAnnotations; + private int mAtomId; + private int mLastIndex; + private boolean mBuilt; + + WrappedBuilder(StatsEvent.Builder builder) { + super(builder); + mValues = new ArrayList<>(); + mAnnotations = new HashMap<>(); + mValues.add(0); // proto fields are 1-based + } + + @Override + public Builder setAtomId(int atomId) { + mAtomId = atomId; + super.setAtomId(atomId); + return this; + } + + @Override + public Builder writeInt(int value) { + addValue(Integer.valueOf(value)); + super.writeInt(value); + return this; + } + + @Override + public Builder addBooleanAnnotation(byte annotation, boolean value) { + addAnnotation(annotation, Boolean.valueOf(value)); + super.addBooleanAnnotation(annotation, value); + return this; + } + + @Override + public Builder writeString(String value) { + addValue(value); + super.writeString(value); + return this; + } + + @Override + public Builder writeBoolean(boolean value) { + addValue(Boolean.valueOf(value)); + super.writeBoolean(value); + return this; + } + + @Override + public StatsEvent build() { + mBuilt = true; + return super.build(); + } + + public Object getValue(int index) { + return index < mValues.size() ? mValues.get(index) : null; + } + + /** useful to make assertTrue() statemetns more readable. */ + public boolean getBoolean(int index) { + return (Boolean) mValues.get(index); + } + + private void addValue(Object value) { + mLastIndex = mValues.size(); + mValues.add(value); + } + + private void addAnnotation(byte annotation, Object value) { + Integer key = Integer.valueOf(mLastIndex); + if (!mAnnotations.containsKey(key)) { + mAnnotations.put(key, new HashMap<>()); + } + mAnnotations.get(key).put(Byte.valueOf(annotation), value); + } + + public boolean getBooleanAnnotation(int i, byte a) { + return ((Boolean) mAnnotations.get(Integer.valueOf(i)).get(Byte.valueOf(a))) + .booleanValue(); + } + + public int getAtomId() { + return mAtomId; + } + } + + static class WrappedBuilderFactory extends SysUiStatsEvent.BuilderFactory { + public List builders; + + WrappedBuilderFactory() { + builders = new ArrayList<>(); + } + + @Override + Builder newBuilder() { + WrappedBuilder b = new WrappedBuilder(StatsEvent.newBuilder()); + builders.add(b); + return b; + } + } +}