Add notification sent count to channel settings
Bug: 79607096 Test: robotests Change-Id: I3c1d8fd1cbd9f5b8e997f1bfd50926121a5040fb
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user