Merge "Statsd-log notification channel changes." into rvc-dev am: 83f3fb4610

Change-Id: Ia19363d2cc3c2abcbd1bc6a80784b9e66e102589
This commit is contained in:
Automerger Merge Worker
2020-03-03 20:03:13 +00:00
8 changed files with 495 additions and 61 deletions

View File

@@ -0,0 +1,213 @@
/*
* 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.annotation.NonNull;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.FrameworkStatsLog;
/**
* Interface for logging NotificationChannelModified statsd atoms. Provided as an interface to
* enable unit-testing - use standard implementation NotificationChannelLoggerImpl in production.
*/
public interface NotificationChannelLogger {
// The logging interface. Not anticipating a need to override these high-level methods, which by
// default forward to a lower-level interface.
/**
* Log the creation of a notification channel.
* @param channel The channel.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
*/
default void logNotificationChannelCreated(@NonNull NotificationChannel channel, int uid,
String pkg) {
logNotificationChannel(
NotificationChannelEvent.getCreated(channel),
channel, uid, pkg, 0, 0);
}
/**
* Log the deletion of a notification channel.
* @param channel The channel.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
*/
default void logNotificationChannelDeleted(@NonNull NotificationChannel channel, int uid,
String pkg) {
logNotificationChannel(
NotificationChannelEvent.getDeleted(channel),
channel, uid, pkg, 0, 0);
}
/**
* Log the modification of a notification channel.
* @param channel The channel.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
* @param oldImportance Previous importance level of the channel.
* @param byUser True if the modification was user-specified.
*/
default void logNotificationChannelModified(@NonNull NotificationChannel channel, int uid,
String pkg, int oldImportance, boolean byUser) {
logNotificationChannel(NotificationChannelEvent.getUpdated(byUser),
channel, uid, pkg, oldImportance, channel.getImportance());
}
/**
* Log the creation or modification of a notification channel group.
* @param channelGroup The notification channel group.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
* @param isNew True if this is a creation of a new group.
* @param wasBlocked
*/
default void logNotificationChannelGroup(@NonNull NotificationChannelGroup channelGroup,
int uid, String pkg, boolean isNew, boolean wasBlocked) {
logNotificationChannelGroup(NotificationChannelEvent.getGroupUpdated(isNew),
channelGroup, uid, pkg, wasBlocked);
}
/**
* Log the deletion of a notification channel group.
* @param channelGroup The notification channel group.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
*/
default void logNotificationChannelGroupDeleted(@NonNull NotificationChannelGroup channelGroup,
int uid, String pkg) {
logNotificationChannelGroup(NotificationChannelEvent.NOTIFICATION_CHANNEL_GROUP_DELETED,
channelGroup, uid, pkg, false);
}
/**
* Low-level interface for logging events, to be implemented.
* @param event Event to log.
* @param channel Notification channel.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
* @param oldImportance Old importance of the channel, if applicable (0 otherwise).
* @param newImportance New importance of the channel, if applicable (0 otherwise).
*/
void logNotificationChannel(@NonNull NotificationChannelEvent event,
@NonNull NotificationChannel channel, int uid, String pkg,
int oldImportance, int newImportance);
/**
* Low-level interface for logging channel group events, to be implemented.
* @param event Event to log.
* @param channelGroup Notification channel group.
* @param uid UID of app that owns the channel.
* @param pkg Package of app that owns the channel.
* @param wasBlocked True if the channel is being modified and was previously blocked.
*/
void logNotificationChannelGroup(@NonNull NotificationChannelEvent event,
@NonNull NotificationChannelGroup channelGroup, int uid, String pkg,
boolean wasBlocked);
/**
* The UiEvent enums that this class can log.
*/
enum NotificationChannelEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "App created a new notification channel")
NOTIFICATION_CHANNEL_CREATED(219),
@UiEvent(doc = "App modified an existing notification channel")
NOTIFICATION_CHANNEL_UPDATED(220),
@UiEvent(doc = "User modified a new notification channel")
NOTIFICATION_CHANNEL_UPDATED_BY_USER(221),
@UiEvent(doc = "App deleted an existing notification channel")
NOTIFICATION_CHANNEL_DELETED(222),
@UiEvent(doc = "App created a new notification channel group")
NOTIFICATION_CHANNEL_GROUP_CREATED(223),
@UiEvent(doc = "App modified an existing notification channel group")
NOTIFICATION_CHANNEL_GROUP_UPDATED(224),
@UiEvent(doc = "App deleted an existing notification channel group")
NOTIFICATION_CHANNEL_GROUP_DELETED(226),
@UiEvent(doc = "System created a new conversation (sub-channel in a notification channel)")
NOTIFICATION_CHANNEL_CONVERSATION_CREATED(272),
@UiEvent(doc = "System deleted a new conversation (sub-channel in a notification channel)")
NOTIFICATION_CHANNEL_CONVERSATION_DELETED(274);
private final int mId;
NotificationChannelEvent(int id) {
mId = id;
}
@Override public int getId() {
return mId;
}
public static NotificationChannelEvent getUpdated(boolean byUser) {
return byUser
? NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER
: NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED;
}
public static NotificationChannelEvent getCreated(@NonNull NotificationChannel channel) {
return channel.getConversationId() != null
? NotificationChannelEvent.NOTIFICATION_CHANNEL_CONVERSATION_CREATED
: NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED;
}
public static NotificationChannelEvent getDeleted(@NonNull NotificationChannel channel) {
return channel.getConversationId() != null
? NotificationChannelEvent.NOTIFICATION_CHANNEL_CONVERSATION_DELETED
: NotificationChannelEvent.NOTIFICATION_CHANNEL_DELETED;
}
public static NotificationChannelEvent getGroupUpdated(boolean isNew) {
return isNew
? NotificationChannelEvent.NOTIFICATION_CHANNEL_GROUP_CREATED
: NotificationChannelEvent.NOTIFICATION_CHANNEL_GROUP_DELETED;
}
}
/**
* @return Small hash of the channel ID, if present, or 0 otherwise.
*/
static int getIdHash(@NonNull NotificationChannel channel) {
return NotificationRecordLogger.smallHash(channel.getId());
}
/**
* @return Small hash of the channel ID, if present, or 0 otherwise.
*/
static int getIdHash(@NonNull NotificationChannelGroup group) {
return NotificationRecordLogger.smallHash(group.getId());
}
/**
* @return "Importance" for a channel group
*/
static int getImportance(@NonNull NotificationChannelGroup channelGroup) {
return getImportance(channelGroup.isBlocked());
}
/**
* @return "Importance" for a channel group, from its blocked status
*/
static int getImportance(boolean isBlocked) {
return isBlocked
? FrameworkStatsLog.NOTIFICATION_CHANNEL_MODIFIED__IMPORTANCE__IMPORTANCE_NONE
: FrameworkStatsLog.NOTIFICATION_CHANNEL_MODIFIED__IMPORTANCE__IMPORTANCE_DEFAULT;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import com.android.internal.util.FrameworkStatsLog;
/**
* Standard implementation of NotificationChannelLogger, which passes data through to StatsLog.
* This layer is as skinny as possible, to maximize code coverage of unit tests. Nontrivial code
* should live in the interface so it can be tested.
*/
public class NotificationChannelLoggerImpl implements NotificationChannelLogger {
@Override
public void logNotificationChannel(NotificationChannelEvent event,
NotificationChannel channel, int uid, String pkg,
int oldImportance, int newImportance) {
FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_MODIFIED,
/* int event_id*/ event.getId(),
/* int uid*/ uid,
/* String package_name */ pkg,
/* int32 channel_id_hash */ NotificationChannelLogger.getIdHash(channel),
/* int old_importance*/ oldImportance,
/* int importance*/ newImportance);
}
@Override
public void logNotificationChannelGroup(NotificationChannelEvent event,
NotificationChannelGroup channelGroup, int uid, String pkg, boolean wasBlocked) {
FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_MODIFIED,
/* int event_id*/ event.getId(),
/* int uid*/ uid,
/* String package_name */ pkg,
/* int32 channel_id_hash */ NotificationChannelLogger.getIdHash(channelGroup),
/* int old_importance*/ NotificationChannelLogger.getImportance(wasBlocked),
/* int importance*/ NotificationChannelLogger.getImportance(channelGroup));
}
}

View File

@@ -1979,7 +1979,8 @@ public class NotificationManagerService extends SystemService {
mPreferencesHelper = new PreferencesHelper(getContext(),
mPackageManagerClient,
mRankingHandler,
mZenModeHelper);
mZenModeHelper,
new NotificationChannelLoggerImpl());
mRankingHelper = new RankingHelper(getContext(),
mRankingHandler,
mPreferencesHelper,

View File

@@ -27,7 +27,6 @@ import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -307,27 +306,36 @@ public interface NotificationRecordLogger {
* @return Small hash of the channel ID, if present, or 0 otherwise.
*/
int getChannelIdHash() {
return smallHash(Objects.hashCode(r.getSbn().getNotification().getChannelId()));
return smallHash(r.getSbn().getNotification().getChannelId());
}
/**
* @return Small hash of the group ID, respecting group override if present. 0 otherwise.
*/
int getGroupIdHash() {
return smallHash(Objects.hashCode(r.getSbn().getGroup()));
return smallHash(r.getSbn().getGroup());
}
// "Small" hashes will be in the range [0, MAX_HASH).
static final int MAX_HASH = (1 << 13);
/**
* Maps in to the range [0, MAX_HASH), keeping similar values distinct.
* @param in An arbitrary integer.
* @return in mod MAX_HASH, signs chosen to stay in the range [0, MAX_HASH).
*/
@VisibleForTesting
static int smallHash(int in) {
return Math.floorMod(in, MAX_HASH);
}
}
// "Small" hashes will be in the range [0, MAX_HASH).
int MAX_HASH = (1 << 13);
/**
* Maps in to the range [0, MAX_HASH), keeping similar values distinct.
* @param in An arbitrary integer.
* @return in mod MAX_HASH, signs chosen to stay in the range [0, MAX_HASH).
*/
static int smallHash(int in) {
return Math.floorMod(in, MAX_HASH);
}
/**
* @return Small hash of the string, if non-null, or 0 otherwise.
*/
static int smallHash(@Nullable String in) {
return smallHash(Objects.hashCode(in));
}
}

View File

@@ -145,6 +145,7 @@ public class PreferencesHelper implements RankingConfig {
private final PackageManager mPm;
private final RankingHandler mRankingHandler;
private final ZenModeHelper mZenModeHelper;
private final NotificationChannelLogger mNotificationChannelLogger;
private SparseBooleanArray mBadgingEnabled;
private boolean mBubblesEnabled = DEFAULT_ALLOW_BUBBLE;
@@ -161,11 +162,12 @@ public class PreferencesHelper implements RankingConfig {
}
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper) {
ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger) {
mContext = context;
mZenModeHelper = zenHelper;
mRankingHandler = rankingHandler;
mPm = pm;
mNotificationChannelLogger = notificationChannelLogger;
// STOPSHIP (b/142218092) this should be removed before ship
if (!wasBadgingForcedTrue(context)) {
@@ -654,10 +656,6 @@ public class PreferencesHelper implements RankingConfig {
throw new IllegalArgumentException("Invalid package");
}
final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
if (!group.equals(oldGroup)) {
// will log for new entries as well as name/description changes
MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
}
if (oldGroup != null) {
group.setChannels(oldGroup.getChannels());
@@ -674,6 +672,13 @@ public class PreferencesHelper implements RankingConfig {
}
}
}
if (!group.equals(oldGroup)) {
// will log for new entries as well as name/description changes
MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
mNotificationChannelLogger.logNotificationChannelGroup(group, uid, pkg,
oldGroup == null,
(oldGroup != null) && oldGroup.isBlocked());
}
r.groups.put(group.getId(), group);
}
}
@@ -685,7 +690,7 @@ public class PreferencesHelper implements RankingConfig {
Objects.requireNonNull(channel);
Objects.requireNonNull(channel.getId());
Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()));
boolean needsPolicyFileChange = false;
boolean needsPolicyFileChange = false, wasUndeleted = false;
synchronized (mPackagePreferences) {
PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -698,15 +703,18 @@ public class PreferencesHelper implements RankingConfig {
throw new IllegalArgumentException("Reserved id");
}
NotificationChannel existing = r.channels.get(channel.getId());
// Keep most of the existing settings
if (existing != null && fromTargetApp) {
// Actually modifying an existing channel - keep most of the existing settings
if (existing.isDeleted()) {
// The existing channel was deleted - undelete it.
existing.setDeleted(false);
needsPolicyFileChange = true;
wasUndeleted = true;
// log a resurrected channel as if it's new again
MetricsLogger.action(getChannelLog(channel, pkg).setType(
com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
mNotificationChannelLogger.logNotificationChannelCreated(channel, uid, pkg);
}
if (!Objects.equals(channel.getName().toString(), existing.getName().toString())) {
@@ -756,6 +764,10 @@ public class PreferencesHelper implements RankingConfig {
}
updateConfig();
if (needsPolicyFileChange && !wasUndeleted) {
mNotificationChannelLogger.logNotificationChannelModified(existing, uid, pkg,
previousExistingImportance, false);
}
return needsPolicyFileChange;
}
@@ -806,6 +818,7 @@ public class PreferencesHelper implements RankingConfig {
}
MetricsLogger.action(getChannelLog(channel, pkg).setType(
com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
mNotificationChannelLogger.logNotificationChannelCreated(channel, uid, pkg);
}
return needsPolicyFileChange;
@@ -867,6 +880,8 @@ public class PreferencesHelper implements RankingConfig {
// only log if there are real changes
MetricsLogger.action(getChannelLog(updatedChannel, pkg)
.setSubtype(fromUser ? 1 : 0));
mNotificationChannelLogger.logNotificationChannelModified(updatedChannel, uid, pkg,
channel.getImportance(), fromUser);
}
if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
@@ -954,14 +969,21 @@ public class PreferencesHelper implements RankingConfig {
}
NotificationChannel channel = r.channels.get(channelId);
if (channel != null) {
channel.setDeleted(true);
LogMaker lm = getChannelLog(channel, pkg);
lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
MetricsLogger.action(lm);
deleteNotificationChannelLocked(channel, pkg, uid);
}
}
}
if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
updateChannelsBypassingDnd(mContext.getUserId());
}
private void deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
if (!channel.isDeleted()) {
channel.setDeleted(true);
LogMaker lm = getChannelLog(channel, pkg);
lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
MetricsLogger.action(lm);
mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg);
if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
updateChannelsBypassingDnd(mContext.getUserId());
}
}
}
@@ -1158,13 +1180,17 @@ public class PreferencesHelper implements RankingConfig {
return deletedChannels;
}
r.groups.remove(groupId);
NotificationChannelGroup channelGroup = r.groups.remove(groupId);
if (channelGroup != null) {
mNotificationChannelLogger.logNotificationChannelGroupDeleted(channelGroup, uid,
pkg);
}
int N = r.channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel nc = r.channels.valueAt(i);
if (groupId.equals(nc.getGroup())) {
nc.setDeleted(true);
deleteNotificationChannelLocked(nc, pkg, uid);
deletedChannels.add(nc);
}
}
@@ -1279,6 +1305,7 @@ public class PreferencesHelper implements RankingConfig {
lm.setType(
com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
MetricsLogger.action(lm);
mNotificationChannelLogger.logNotificationChannelDeleted(nc, uid, pkg);
deletedChannelIds.add(nc.getId());
}

View File

@@ -0,0 +1,54 @@
/*
* 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.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import java.util.ArrayList;
import java.util.List;
public class NotificationChannelLoggerFake implements NotificationChannelLogger {
static class CallRecord {
public NotificationChannelEvent event;
CallRecord(NotificationChannelEvent event) {
this.event = event;
}
}
private List<CallRecord> mCalls = new ArrayList<>();
List<CallRecord> getCalls() {
return mCalls;
}
CallRecord get(int index) {
return mCalls.get(index);
}
@Override
public void logNotificationChannel(NotificationChannelEvent event, NotificationChannel channel,
int uid, String pkg, int oldImportance, int newImportance) {
mCalls.add(new CallRecord(event));
}
@Override
public void logNotificationChannelGroup(NotificationChannelEvent event,
NotificationChannelGroup channelGroup, int uid, String pkg, boolean wasBlocked) {
mCalls.add(new CallRecord(event));
}
}

View File

@@ -60,16 +60,16 @@ public class NotificationRecordLoggerTest extends UiServiceTestCase {
@Test
public void testSmallHash() {
assertEquals(0, NotificationRecordLogger.NotificationRecordPair.smallHash(0));
final int maxHash = NotificationRecordLogger.NotificationRecordPair.MAX_HASH;
assertEquals(0, NotificationRecordLogger.smallHash(0));
final int maxHash = NotificationRecordLogger.MAX_HASH;
assertEquals(0,
NotificationRecordLogger.NotificationRecordPair.smallHash(maxHash));
NotificationRecordLogger.smallHash(maxHash));
assertEquals(0,
NotificationRecordLogger.NotificationRecordPair.smallHash(17 * maxHash));
NotificationRecordLogger.smallHash(17 * maxHash));
assertEquals(maxHash - 1,
NotificationRecordLogger.NotificationRecordPair.smallHash(maxHash - 1));
NotificationRecordLogger.smallHash(maxHash - 1));
assertEquals(maxHash - 1,
NotificationRecordLogger.NotificationRecordPair.smallHash(-1));
NotificationRecordLogger.smallHash(-1));
}
@Test
@@ -78,10 +78,10 @@ public class NotificationRecordLoggerTest extends UiServiceTestCase {
getNotificationRecordPair(0, null).getNotificationIdHash());
assertEquals(1,
getNotificationRecordPair(1, null).getNotificationIdHash());
assertEquals(NotificationRecordLogger.NotificationRecordPair.MAX_HASH - 1,
assertEquals(NotificationRecordLogger.MAX_HASH - 1,
getNotificationRecordPair(-1, null).getNotificationIdHash());
final String tag = "someTag";
final int hash = NotificationRecordLogger.NotificationRecordPair.smallHash(tag.hashCode());
final int hash = NotificationRecordLogger.smallHash(tag.hashCode());
assertEquals(hash, getNotificationRecordPair(0, tag).getNotificationIdHash());
// We xor the tag and hashcode together before compressing the range. The order of
// operations doesn't matter if id is small.
@@ -89,19 +89,19 @@ public class NotificationRecordLoggerTest extends UiServiceTestCase {
getNotificationRecordPair(1, tag).getNotificationIdHash());
// But it does matter for an id with more 1 bits than fit in the small hash.
assertEquals(
NotificationRecordLogger.NotificationRecordPair.smallHash(-1 ^ tag.hashCode()),
NotificationRecordLogger.smallHash(-1 ^ tag.hashCode()),
getNotificationRecordPair(-1, tag).getNotificationIdHash());
assertNotEquals(-1 ^ hash,
NotificationRecordLogger.NotificationRecordPair.smallHash(-1 ^ tag.hashCode()));
NotificationRecordLogger.smallHash(-1 ^ tag.hashCode()));
}
@Test
public void testGetChannelIdHash() {
assertEquals(
NotificationRecordLogger.NotificationRecordPair.smallHash(CHANNEL_ID.hashCode()),
NotificationRecordLogger.smallHash(CHANNEL_ID.hashCode()),
getNotificationRecordPair(0, null).getChannelIdHash());
assertNotEquals(
NotificationRecordLogger.NotificationRecordPair.smallHash(CHANNEL_ID.hashCode()),
NotificationRecordLogger.smallHash(CHANNEL_ID.hashCode()),
CHANNEL_ID.hashCode());
}
@@ -113,7 +113,7 @@ public class NotificationRecordLoggerTest extends UiServiceTestCase {
final String group = "someGroup";
p.r.setOverrideGroupKey(group);
assertEquals(
NotificationRecordLogger.NotificationRecordPair.smallHash(group.hashCode()),
NotificationRecordLogger.smallHash(group.hashCode()),
p.getGroupIdHash());
}
}

View File

@@ -134,6 +134,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
private PreferencesHelper mHelper;
private AudioAttributes mAudioAttributes;
private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
@Before
public void setUp() throws Exception {
@@ -183,7 +184,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
resetZenModeHelper();
mAudioAttributes = new AudioAttributes.Builder()
@@ -1106,6 +1107,22 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist");
}
@Test
public void testDoubleDeleteChannel() throws Exception {
NotificationChannel channel = getChannel();
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
assertEquals(2, mLogger.getCalls().size());
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
mLogger.get(0).event);
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_DELETED,
mLogger.get(1).event);
// No log for the second delete of the same channel.
}
@Test
public void testGetDeletedChannel() throws Exception {
NotificationChannel channel = getChannel();
@@ -1444,7 +1461,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1455,7 +1472,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start notification policy off with mAreChannelsBypassingDnd = false
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1525,6 +1542,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// Old settings not overridden
compareChannels(channel,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false));
assertEquals(1, mLogger.getCalls().size());
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
mLogger.get(0).event);
}
@Test
@@ -1594,6 +1616,16 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(1, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).size());
verify(mHandler, never()).requestSort();
assertEquals(7, mLogger.getCalls().size());
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_GROUP_DELETED,
mLogger.get(5).event); // Next-to-last log is the deletion of the channel group.
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_DELETED,
mLogger.get(6).event); // Final log is the deletion of the channel.
}
@Test
@@ -1739,6 +1771,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(ncg,
mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
verify(mHandler, never()).requestSort();
assertEquals(1, mLogger.getCalls().size());
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_GROUP_CREATED,
mLogger.get(0).event);
}
@Test
@@ -1751,6 +1788,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
fail("Created a channel with a bad group");
} catch (IllegalArgumentException e) {
}
assertEquals(0, mLogger.getCalls().size());
}
@Test
@@ -1905,6 +1943,17 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
verify(mHandler, times(1)).requestSort();
assertEquals(3, mLogger.getCalls().size());
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_GROUP_CREATED,
mLogger.get(0).event);
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
mLogger.get(1).event);
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED,
mLogger.get(2).event);
}
@Test
@@ -2189,7 +2238,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ "</package>\n"
+ "</ranking>\n";
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadByteArrayXml(preQXml.getBytes(), true, UserHandle.USER_SYSTEM);
assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -2201,7 +2250,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -2297,7 +2346,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2308,7 +2357,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2320,7 +2369,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2332,7 +2381,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
// appears disabled
@@ -2350,7 +2399,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
// appears disabled
@@ -2368,7 +2417,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
@@ -2383,7 +2432,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.getAppLockedFields(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O));
@@ -2876,7 +2925,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
public void testPlaceholderConversationId_flagOn() throws Exception {
Settings.Global.putString(
mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -2896,7 +2945,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
public void testPlaceholderConversationId_flagOff() throws Exception {
Settings.Global.putString(
mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -2916,7 +2965,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
public void testNormalConversationId_flagOff() throws Exception {
Settings.Global.putString(
mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -2936,7 +2985,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
public void testNoConversationId_flagOff() throws Exception {
Settings.Global.putString(
mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -3171,5 +3220,33 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), true));
assertEquals(channel2,
mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), true));
assertEquals(7, mLogger.getCalls().size());
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
mLogger.get(0).event); // Channel messages
assertEquals(
NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED,
mLogger.get(1).event); // Channel calls
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
mLogger.get(2).event); // Channel channel - Conversation A person msgs
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
mLogger.get(3).event); // Channel noMatch - Conversation B person msgs
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_CONVERSATION_CREATED,
mLogger.get(4).event); // Channel channel2 - Conversation A person calls
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
mLogger.get(5).event); // Delete Channel channel - Conversation A person msgs
assertEquals(
NotificationChannelLogger.NotificationChannelEvent
.NOTIFICATION_CHANNEL_CONVERSATION_DELETED,
mLogger.get(6).event); // Delete Channel channel2 - Conversation A person calls
}
}