Add notification sent count to channel settings

Bug: 79607096
Test: robotests
Change-Id: I3c1d8fd1cbd9f5b8e997f1bfd50926121a5040fb
This commit is contained in:
Julia Reynolds
2018-06-12 10:17:26 -04:00
parent a5711f1bc6
commit 8ebfb12cac
4 changed files with 156 additions and 0 deletions

View File

@@ -21,6 +21,8 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -28,21 +30,30 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.NotifyingApp;
import android.text.format.DateUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
import com.android.settingslib.utils.StringUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class NotificationBackend {
private static final String TAG = "NotificationBackend";
static IUsageStatsManager sUsageStatsManager = IUsageStatsManager.Stub.asInterface(
ServiceManager.getService(Context.USAGE_STATS_SERVICE));
private static final int DAYS_TO_CHECK = 7;
static INotificationManager sINM = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -62,6 +73,7 @@ public class NotificationBackend {
row.userId = UserHandle.getUserId(row.uid);
row.blockedChannelCount = getBlockedChannelCount(row.pkg, row.uid);
row.channelCount = getChannelCount(row.pkg, row.uid);
row.sentByChannel = getAggregatedUsageEvents(context, row.userId, row.pkg);
return row;
}
@@ -259,6 +271,87 @@ public class NotificationBackend {
}
}
protected Map<String, NotificationsSentState> getAggregatedUsageEvents(
Context context, int userId, String pkg) {
long now = System.currentTimeMillis();
long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK);
UsageEvents events = null;
try {
events = sUsageStatsManager.queryEventsForPackageForUser(
startTime, now, userId, pkg, context.getPackageName());
} catch (RemoteException e) {
e.printStackTrace();
}
return getAggregatedUsageEvents(events);
}
protected Map<String, NotificationsSentState> getAggregatedUsageEvents(UsageEvents events) {
Map<String, NotificationsSentState> sentByChannel = new HashMap<>();
if (events != null) {
UsageEvents.Event event = new UsageEvents.Event();
while (events.hasNextEvent()) {
events.getNextEvent(event);
if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) {
String channelId = event.mNotificationChannelId;
if (channelId != null) {
NotificationsSentState stats = sentByChannel.get(channelId);
if (stats == null) {
stats = new NotificationsSentState();
sentByChannel.put(channelId, stats);
}
if (event.getTimeStamp() > stats.lastSent) {
stats.lastSent = event.getTimeStamp();
}
stats.sentCount++;
calculateAvgSentCounts(stats);
}
}
}
}
return sentByChannel;
}
public static CharSequence getSentSummary(Context context, NotificationsSentState state,
boolean sortByRecency) {
if (state == null) {
return null;
}
if (sortByRecency) {
if (state.lastSent == 0) {
return context.getString(R.string.notifications_sent_never);
}
return StringUtil.formatRelativeTime(
context, System.currentTimeMillis() - state.lastSent, true);
} else {
if (state.avgSentWeekly > 0) {
return context.getString(R.string.notifications_sent_weekly, state.avgSentWeekly);
}
return context.getString(R.string.notifications_sent_daily, state.avgSentDaily);
}
}
private void calculateAvgSentCounts(NotificationsSentState stats) {
if (stats != null) {
stats.avgSentDaily = Math.round((float) stats.sentCount / DAYS_TO_CHECK);
if (stats.sentCount < DAYS_TO_CHECK) {
stats.avgSentWeekly = stats.sentCount;
}
}
}
/**
* NotificationsSentState contains how often an app sends notifications and how recently it sent
* one.
*/
public static class NotificationsSentState {
public int avgSentDaily = 0;
public int avgSentWeekly = 0;
public long lastSent = 0;
public int sentCount = 0;
}
static class Row {
public String section;
}
@@ -278,5 +371,6 @@ public class NotificationBackend {
public int userId;
public int blockedChannelCount;
public int channelCount;
public Map<String, NotificationsSentState> sentByChannel;
}
}

View File

@@ -276,6 +276,8 @@ abstract public class NotificationSettingsBase extends DashboardFragment {
&& !groupBlocked);
channelPref.setKey(channel.getId());
channelPref.setTitle(channel.getName());
channelPref.setSummary(NotificationBackend.getSentSummary(
mContext, mAppRow.sentByChannel.get(channel.getId()), false));
channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
Bundle channelArgs = new Bundle();
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.usage.IUsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -78,6 +79,8 @@ public class AppNotificationPreferenceControllerTest {
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.info = new ApplicationInfo();
when(mFragment.getAppEntry()).thenReturn(appEntry);
NotificationBackend backend = new NotificationBackend();
ReflectionHelpers.setField(backend, "sUsageStatsManager", mock(IUsageStatsManager.class));
ReflectionHelpers.setField(mController, "mBackend", new NotificationBackend());
mController.displayPreference(mScreen);

View File

@@ -16,17 +16,31 @@
package com.android.settings.notification;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import android.app.usage.UsageEvents;
import android.os.Parcel;
import com.android.settings.notification.NotificationBackend.AppRow;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RunWith(SettingsRobolectricTestRunner.class)
public class NotificationBackendTest {
@@ -118,4 +132,47 @@ public class NotificationBackendTest {
assertTrue(appRow.lockedImportance);
assertEquals("SpecificChannel", appRow.lockedChannelId);
}
@Test
public void testGetAggregatedUsageEvents_multipleEventsAgg() {
List<UsageEvents.Event> events = new ArrayList<>();
UsageEvents.Event good = new UsageEvents.Event();
good.mEventType = UsageEvents.Event.NOTIFICATION_INTERRUPTION;
good.mPackage = "pkg";
good.mNotificationChannelId = "channel1";
good.mTimeStamp = 2;
events.add(good);
UsageEvents.Event good1 = new UsageEvents.Event();
good1.mEventType = UsageEvents.Event.NOTIFICATION_INTERRUPTION;
good1.mPackage = "pkg";
good1.mNotificationChannelId = "channel1";
good1.mTimeStamp = 6;
events.add(good1);
UsageEvents.Event good2 = new UsageEvents.Event();
good2.mEventType = UsageEvents.Event.NOTIFICATION_INTERRUPTION;
good2.mPackage = "pkg";
good2.mNotificationChannelId = "channel2";
good2.mTimeStamp = 3;
events.add(good2);
NotificationBackend backend = new NotificationBackend();
Map<String, NotificationBackend.NotificationsSentState> stats =
backend.getAggregatedUsageEvents(getUsageEvents(events));
assertThat(stats.get("channel1").sentCount).isEqualTo(2);
assertThat(stats.get("channel1").lastSent).isEqualTo(6);
assertThat(stats.get("channel1").avgSentWeekly).isEqualTo(2);
assertThat(stats.get("channel2").sentCount).isEqualTo(1);
assertThat(stats.get("channel2").lastSent).isEqualTo(3);
assertThat(stats.get("channel2").avgSentWeekly).isEqualTo(1);
}
private UsageEvents getUsageEvents(List<UsageEvents.Event> events) {
UsageEvents usageEvents = new UsageEvents(events, new String[] {"pkg"});
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
usageEvents.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
return UsageEvents.CREATOR.createFromParcel(parcel);
}
}