high-frequency notification stats.
Aggregate and then periodically report stats that are high-frequency
because they are driven by app behavior, not user behavior.
Reuse the NotificationUsageStats facility.
Remove redundant stats.
Lessen memory foot print.
Enable in-memeory aggregates with small, bounded memory footprint.
Bug: 20258744
Change-Id: I87e391419c53917fa13c68a56f8cdb40a7c8e548
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index 22cdd58..d4fadcf 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -33,7 +33,7 @@
the top of the ranking order, before it falls back to its natural position. */
private static final long HANG_TIME_MS = 10000;
- public void initialize(Context ctx) {
+ public void initialize(Context ctx, NotificationUsageStats usageStats) {
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 90e912d..9c288be 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -856,8 +856,10 @@
} catch (Resources.NotFoundException e) {
extractorNames = new String[0];
}
+ mUsageStats = new NotificationUsageStats(getContext());
mRankingHelper = new RankingHelper(getContext(),
new RankingWorkerHandler(mRankingThread.getLooper()),
+ mUsageStats,
extractorNames);
mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
@@ -882,7 +884,6 @@
});
final File systemDir = new File(Environment.getDataDirectory(), "system");
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
- mUsageStats = new NotificationUsageStats(getContext());
importOldBlockDb();
@@ -2071,6 +2072,7 @@
r.score = JUNK_SCORE;
Slog.e(TAG, "Suppressing notification from package " + pkg
+ " by user request.");
+ mUsageStats.registerBlocked(r);
}
}
@@ -2736,12 +2738,6 @@
case REASON_NOMAN_CANCEL_ALL:
mUsageStats.registerRemovedByApp(r);
break;
- case REASON_DELEGATE_CLICK:
- mUsageStats.registerCancelDueToClick(r);
- break;
- default:
- mUsageStats.registerCancelUnknown(r);
- break;
}
mNotificationsByKey.remove(r.sbn.getKey());
diff --git a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java
index 43d05d0..31f8b27 100644
--- a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java
@@ -26,7 +26,7 @@
public interface NotificationSignalExtractor {
/** One-time initialization. */
- public void initialize(Context context);
+ public void initialize(Context context, NotificationUsageStats usageStats);
/**
* Called once per notification that is posted or updated.
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 4696771..2d5c199 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -25,13 +25,13 @@
import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemClock;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.logging.MetricsLogger;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;
@@ -47,21 +47,45 @@
* {@hide}
*/
public class NotificationUsageStats {
- // WARNING: Aggregated stats can grow unboundedly with pkg+id+tag.
- // Don't enable on production builds.
- private static final boolean ENABLE_AGGREGATED_IN_MEMORY_STATS = false;
- private static final boolean ENABLE_SQLITE_LOG = true;
+ private static final String TAG = "NotificationUsageStats";
+ private static final boolean ENABLE_AGGREGATED_IN_MEMORY_STATS = true;
+ private static final boolean ENABLE_SQLITE_LOG = true;
private static final AggregatedStats[] EMPTY_AGGREGATED_STATS = new AggregatedStats[0];
+ private static final String DEVICE_GLOBAL_STATS = "__global"; // packages start with letters
+ private static final int MSG_EMIT = 1;
+
+ private static final boolean DEBUG = false;
+ public static final int TEN_SECONDS = 1000 * 10;
+ public static final int ONE_HOUR = 1000 * 60 * 60;
+ private static final long EMIT_PERIOD = DEBUG ? TEN_SECONDS : ONE_HOUR;
// Guarded by synchronized(this).
- private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
+ private final Map<String, AggregatedStats> mStats = new HashMap<>();
+ private final ArrayDeque<AggregatedStats[]> mStatsArrays = new ArrayDeque<>();
private final SQLiteLog mSQLiteLog;
private final Context mContext;
+ private final Handler mHandler;
+ private long mLastEmitTime;
public NotificationUsageStats(Context context) {
mContext = context;
+ mLastEmitTime = SystemClock.elapsedRealtime();
mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null;
+ mHandler = new Handler(mContext.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_EMIT:
+ emit();
+ break;
+ default:
+ Log.wtf(TAG, "Unknown message type: " + msg.what);
+ break;
+ }
+ }
+ };
+ mHandler.sendEmptyMessageDelayed(MSG_EMIT, EMIT_PERIOD);
}
/**
@@ -70,9 +94,12 @@
public synchronized void registerPostedByApp(NotificationRecord notification) {
notification.stats = new SingleNotificationStats();
notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
+ for (AggregatedStats stats : aggregatedStatsArray) {
stats.numPostedByApp++;
}
+ releaseAggregatedStatsLocked(aggregatedStatsArray);
if (ENABLE_SQLITE_LOG) {
mSQLiteLog.logPosted(notification);
}
@@ -83,9 +110,11 @@
*/
public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
notification.stats = old.stats;
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
+ for (AggregatedStats stats : aggregatedStatsArray) {
stats.numUpdatedByApp++;
}
+ releaseAggregatedStatsLocked(aggregatedStatsArray);
}
/**
@@ -93,10 +122,11 @@
*/
public synchronized void registerRemovedByApp(NotificationRecord notification) {
notification.stats.onRemoved();
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
+ for (AggregatedStats stats : aggregatedStatsArray) {
stats.numRemovedByApp++;
- stats.collect(notification.stats);
}
+ releaseAggregatedStatsLocked(aggregatedStatsArray);
if (ENABLE_SQLITE_LOG) {
mSQLiteLog.logRemoved(notification);
}
@@ -109,10 +139,6 @@
MetricsLogger.histogram(mContext, "note_dismiss_longevity",
(int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
notification.stats.onDismiss();
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
- stats.numDismissedByUser++;
- stats.collect(notification.stats);
- }
if (ENABLE_SQLITE_LOG) {
mSQLiteLog.logDismissed(notification);
}
@@ -125,36 +151,36 @@
MetricsLogger.histogram(mContext, "note_click_longevity",
(int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
notification.stats.onClick();
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
- stats.numClickedByUser++;
- }
if (ENABLE_SQLITE_LOG) {
mSQLiteLog.logClicked(notification);
}
}
- /**
- * Called when the notification is canceled because the user clicked it.
- *
- * <p>Called after {@link #registerClickedByUser(NotificationRecord)}.</p>
- */
- public synchronized void registerCancelDueToClick(NotificationRecord notification) {
- notification.stats.onCancel();
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
- stats.collect(notification.stats);
+ public synchronized void registerPeopleAffinity(NotificationRecord notification, boolean valid,
+ boolean starred, boolean cached) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
+ for (AggregatedStats stats : aggregatedStatsArray) {
+ if (valid) {
+ stats.numWithValidPeople++;
+ }
+ if (starred) {
+ stats.numWithStaredPeople++;
+ }
+ if (cached) {
+ stats.numPeopleCacheHit++;
+ } else {
+ stats.numPeopleCacheMiss++;
+ }
}
+ releaseAggregatedStatsLocked(aggregatedStatsArray);
}
- /**
- * Called when the notification is canceled due to unknown reasons.
- *
- * <p>Called for notifications of apps being uninstalled, for example.</p>
- */
- public synchronized void registerCancelUnknown(NotificationRecord notification) {
- notification.stats.onCancel();
- for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
- stats.collect(notification.stats);
+ public synchronized void registerBlocked(NotificationRecord notification) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
+ for (AggregatedStats stats : aggregatedStatsArray) {
+ stats.numBlocked++;
}
+ releaseAggregatedStatsLocked(aggregatedStatsArray);
}
// Locked by this.
@@ -163,24 +189,28 @@
return EMPTY_AGGREGATED_STATS;
}
- StatusBarNotification n = record.sbn;
+ // TODO: expand to package-level counts in the future.
+ AggregatedStats[] array = mStatsArrays.poll();
+ if (array == null) {
+ array = new AggregatedStats[1];
+ }
+ array[0] = getOrCreateAggregatedStatsLocked(DEVICE_GLOBAL_STATS);
+ return array;
+ }
- String user = String.valueOf(n.getUserId());
- String userPackage = user + ":" + n.getPackageName();
-
- // TODO: Use pool of arrays.
- return new AggregatedStats[] {
- getOrCreateAggregatedStatsLocked(user),
- getOrCreateAggregatedStatsLocked(userPackage),
- getOrCreateAggregatedStatsLocked(n.getKey()),
- };
+ // Locked by this.
+ private void releaseAggregatedStatsLocked(AggregatedStats[] array) {
+ for(int i = 0; i < array.length; i++) {
+ array[i] = null;
+ }
+ mStatsArrays.offer(array);
}
// Locked by this.
private AggregatedStats getOrCreateAggregatedStatsLocked(String key) {
AggregatedStats result = mStats.get(key);
if (result == null) {
- result = new AggregatedStats(key);
+ result = new AggregatedStats(mContext, key);
mStats.put(key, result);
}
return result;
@@ -193,64 +223,74 @@
continue;
as.dump(pw, indent);
}
+ pw.println(indent + "mStatsArrays.size(): " + mStatsArrays.size());
}
if (ENABLE_SQLITE_LOG) {
mSQLiteLog.dump(pw, indent, filter);
}
}
+ public synchronized void emit() {
+ // TODO: expand to package-level counts in the future.
+ AggregatedStats stats = getOrCreateAggregatedStatsLocked(DEVICE_GLOBAL_STATS);
+ stats.emit();
+ mLastEmitTime = SystemClock.elapsedRealtime();
+ mHandler.removeMessages(MSG_EMIT);
+ mHandler.sendEmptyMessageDelayed(MSG_EMIT, EMIT_PERIOD);
+ }
+
/**
* Aggregated notification stats.
*/
private static class AggregatedStats {
+
+ private final Context mContext;
public final String key;
// ---- Updated as the respective events occur.
public int numPostedByApp;
public int numUpdatedByApp;
public int numRemovedByApp;
- public int numClickedByUser;
- public int numDismissedByUser;
+ public int numPeopleCacheHit;
+ public int numPeopleCacheMiss;;
+ public int numWithStaredPeople;
+ public int numWithValidPeople;
+ public int numBlocked;
- // ---- Updated when a notification is canceled.
- public final Aggregate posttimeMs = new Aggregate();
- public final Aggregate posttimeToDismissMs = new Aggregate();
- public final Aggregate posttimeToFirstClickMs = new Aggregate();
- public final Aggregate airtimeCount = new Aggregate();
- public final Aggregate airtimeMs = new Aggregate();
- public final Aggregate posttimeToFirstAirtimeMs = new Aggregate();
- public final Aggregate userExpansionCount = new Aggregate();
- public final Aggregate airtimeExpandedMs = new Aggregate();
- public final Aggregate posttimeToFirstVisibleExpansionMs = new Aggregate();
+ private AggregatedStats mPrevious;
- public AggregatedStats(String key) {
+ public AggregatedStats(Context context, String key) {
this.key = key;
+ mContext = context;
}
- public void collect(SingleNotificationStats singleNotificationStats) {
- posttimeMs.addSample(
- SystemClock.elapsedRealtime() - singleNotificationStats.posttimeElapsedMs);
- if (singleNotificationStats.posttimeToDismissMs >= 0) {
- posttimeToDismissMs.addSample(singleNotificationStats.posttimeToDismissMs);
+ public void emit() {
+ if (mPrevious == null) {
+ mPrevious = new AggregatedStats(null, key);
}
- if (singleNotificationStats.posttimeToFirstClickMs >= 0) {
- posttimeToFirstClickMs.addSample(singleNotificationStats.posttimeToFirstClickMs);
- }
- airtimeCount.addSample(singleNotificationStats.airtimeCount);
- if (singleNotificationStats.airtimeMs >= 0) {
- airtimeMs.addSample(singleNotificationStats.airtimeMs);
- }
- if (singleNotificationStats.posttimeToFirstAirtimeMs >= 0) {
- posttimeToFirstAirtimeMs.addSample(
- singleNotificationStats.posttimeToFirstAirtimeMs);
- }
- if (singleNotificationStats.posttimeToFirstVisibleExpansionMs >= 0) {
- posttimeToFirstVisibleExpansionMs.addSample(
- singleNotificationStats.posttimeToFirstVisibleExpansionMs);
- }
- userExpansionCount.addSample(singleNotificationStats.userExpansionCount);
- if (singleNotificationStats.airtimeExpandedMs >= 0) {
- airtimeExpandedMs.addSample(singleNotificationStats.airtimeExpandedMs);
+
+ maybeCount("note_post", (numPostedByApp - mPrevious.numPostedByApp));
+ maybeCount("note_update", (numUpdatedByApp - mPrevious.numUpdatedByApp));
+ maybeCount("note_remove", (numRemovedByApp - mPrevious.numRemovedByApp));
+ maybeCount("note_with_people", (numWithValidPeople - mPrevious.numWithValidPeople));
+ maybeCount("note_with_stars", (numWithStaredPeople - mPrevious.numWithStaredPeople));
+ maybeCount("people_cache_hit", (numPeopleCacheHit - mPrevious.numPeopleCacheHit));
+ maybeCount("people_cache_miss", (numPeopleCacheMiss - mPrevious.numPeopleCacheMiss));
+ maybeCount("note_blocked", (numBlocked - mPrevious.numBlocked));
+
+ mPrevious.numPostedByApp = numPostedByApp;
+ mPrevious.numUpdatedByApp = numUpdatedByApp;
+ mPrevious.numRemovedByApp = numRemovedByApp;
+ mPrevious.numPeopleCacheHit = numPeopleCacheHit;
+ mPrevious.numPeopleCacheMiss = numPeopleCacheMiss;
+ mPrevious.numWithStaredPeople = numWithStaredPeople;
+ mPrevious.numWithValidPeople = numWithValidPeople;
+ mPrevious.numBlocked = numBlocked;
+ }
+
+ void maybeCount(String name, int value) {
+ if (value > 0) {
+ MetricsLogger.count(mContext, name, value);
}
}
@@ -269,17 +309,11 @@
indent + " numPostedByApp=" + numPostedByApp + ",\n" +
indent + " numUpdatedByApp=" + numUpdatedByApp + ",\n" +
indent + " numRemovedByApp=" + numRemovedByApp + ",\n" +
- indent + " numClickedByUser=" + numClickedByUser + ",\n" +
- indent + " numDismissedByUser=" + numDismissedByUser + ",\n" +
- indent + " posttimeMs=" + posttimeMs + ",\n" +
- indent + " posttimeToDismissMs=" + posttimeToDismissMs + ",\n" +
- indent + " posttimeToFirstClickMs=" + posttimeToFirstClickMs + ",\n" +
- indent + " airtimeCount=" + airtimeCount + ",\n" +
- indent + " airtimeMs=" + airtimeMs + ",\n" +
- indent + " posttimeToFirstAirtimeMs=" + posttimeToFirstAirtimeMs + ",\n" +
- indent + " userExpansionCount=" + userExpansionCount + ",\n" +
- indent + " airtimeExpandedMs=" + airtimeExpandedMs + ",\n" +
- indent + " posttimeToFVEMs=" + posttimeToFirstVisibleExpansionMs + ",\n" +
+ indent + " numPeopleCacheHit=" + numPeopleCacheHit + ",\n" +
+ indent + " numWithStaredPeople=" + numWithStaredPeople + ",\n" +
+ indent + " numWithValidPeople=" + numWithValidPeople + ",\n" +
+ indent + " numPeopleCacheMiss=" + numPeopleCacheMiss + ",\n" +
+ indent + " numBlocked=" + numBlocked + ",\n" +
indent + "}";
}
}
diff --git a/services/core/java/com/android/server/notification/PackagePriorityExtractor.java b/services/core/java/com/android/server/notification/PackagePriorityExtractor.java
index a13e54a..6beed9c 100644
--- a/services/core/java/com/android/server/notification/PackagePriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/PackagePriorityExtractor.java
@@ -24,7 +24,7 @@
private RankingConfig mConfig;
- public void initialize(Context ctx) {
+ public void initialize(Context ctx, NotificationUsageStats usageStats) {
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
}
diff --git a/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java b/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java
index f720f9f..af99db7 100644
--- a/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/PackageVisibilityExtractor.java
@@ -24,7 +24,7 @@
private RankingConfig mConfig;
- public void initialize(Context ctx) {
+ public void initialize(Context ctx, NotificationUsageStats usageStats) {
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index e503ac8..a089518 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -68,7 +68,8 @@
private final Context mContext;
private final Handler mRankingHandler;
- public RankingHelper(Context context, Handler rankingHandler, String[] extractorNames) {
+ public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
+ String[] extractorNames) {
mContext = context;
mRankingHandler = rankingHandler;
@@ -79,7 +80,7 @@
Class<?> extractorClass = mContext.getClassLoader().loadClass(extractorNames[i]);
NotificationSignalExtractor extractor =
(NotificationSignalExtractor) extractorClass.newInstance();
- extractor.initialize(mContext);
+ extractor.initialize(mContext, usageStats);
extractor.setConfig(this);
mSignalExtractors[i] = extractor;
} catch (ClassNotFoundException e) {
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 4af7d4e..0420269 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -34,7 +34,6 @@
import android.util.Log;
import android.util.LruCache;
import android.util.Slog;
-import com.android.internal.logging.MetricsLogger;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -85,11 +84,13 @@
private Handler mHandler;
private ContentObserver mObserver;
private int mEvictionCount;
+ private NotificationUsageStats mUsageStats;
- public void initialize(Context context) {
+ public void initialize(Context context, NotificationUsageStats usageStats) {
if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
mUserToContextMap = new ArrayMap<>();
mBaseContext = context;
+ mUsageStats = usageStats;
mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
mBaseContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
@@ -203,8 +204,15 @@
final String key = record.getKey();
final Bundle extras = record.getNotification().extras;
final float[] affinityOut = new float[1];
- final RankingReconsideration rr = validatePeople(context, key, extras, affinityOut);
- record.setContactAffinity(affinityOut[0]);
+ final PeopleRankingReconsideration rr = validatePeople(context, key, extras, affinityOut);
+ final float affinity = affinityOut[0];
+ record.setContactAffinity(affinity);
+ if (rr == null) {
+ mUsageStats.registerPeopleAffinity(record, affinity > NONE, affinity == STARRED_CONTACT,
+ true /* cached */);
+ } else {
+ rr.setRecord(record);
+ }
return rr;
}
@@ -245,7 +253,6 @@
if (pendingLookups.isEmpty()) {
if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity);
- if (affinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1);
return null;
}
@@ -413,6 +420,7 @@
private final Context mContext;
private float mContactAffinity = NONE;
+ private NotificationRecord mRecord;
private PeopleRankingReconsideration(Context context, String key, LinkedList<String> pendingLookups) {
super(key);
@@ -456,7 +464,10 @@
"ms");
}
- if (mContactAffinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1);
+ if (mRecord != null) {
+ mUsageStats.registerPeopleAffinity(mRecord, mContactAffinity > NONE,
+ mContactAffinity == STARRED_CONTACT, false /* cached */);
+ }
}
@Override
@@ -469,6 +480,10 @@
public float getContactAffinity() {
return mContactAffinity;
}
+
+ public void setRecord(NotificationRecord record) {
+ mRecord = record;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index 3cc04e8..b40fd068 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -15,6 +15,9 @@
*/
package com.android.server.notification;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
import android.app.Notification;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
@@ -24,6 +27,7 @@
import java.util.ArrayList;
public class RankingHelperTest extends AndroidTestCase {
+ @Mock NotificationUsageStats mUsageStats;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
@@ -39,9 +43,10 @@
@Override
public void setUp() {
+ MockitoAnnotations.initMocks(this);
UserHandle user = UserHandle.ALL;
- mHelper = new RankingHelper(getContext(), null, new String[0]);
+ mHelper = new RankingHelper(getContext(), null, mUsageStats, new String[0]);
mNotiGroupGSortA = new Notification.Builder(getContext())
.setContentTitle("A")