Merge "high-frequency notification stats." into mnc-dev
This commit is contained in:
@@ -33,7 +33,7 @@ public class NotificationIntrusivenessExtractor implements NotificationSignalExt
|
|||||||
the top of the ranking order, before it falls back to its natural position. */
|
the top of the ranking order, before it falls back to its natural position. */
|
||||||
private static final long HANG_TIME_MS = 10000;
|
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() + ".");
|
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -856,8 +856,10 @@ public class NotificationManagerService extends SystemService {
|
|||||||
} catch (Resources.NotFoundException e) {
|
} catch (Resources.NotFoundException e) {
|
||||||
extractorNames = new String[0];
|
extractorNames = new String[0];
|
||||||
}
|
}
|
||||||
|
mUsageStats = new NotificationUsageStats(getContext());
|
||||||
mRankingHelper = new RankingHelper(getContext(),
|
mRankingHelper = new RankingHelper(getContext(),
|
||||||
new RankingWorkerHandler(mRankingThread.getLooper()),
|
new RankingWorkerHandler(mRankingThread.getLooper()),
|
||||||
|
mUsageStats,
|
||||||
extractorNames);
|
extractorNames);
|
||||||
mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
|
mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
|
||||||
mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
|
mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
|
||||||
@@ -882,7 +884,6 @@ public class NotificationManagerService extends SystemService {
|
|||||||
});
|
});
|
||||||
final File systemDir = new File(Environment.getDataDirectory(), "system");
|
final File systemDir = new File(Environment.getDataDirectory(), "system");
|
||||||
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
|
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
|
||||||
mUsageStats = new NotificationUsageStats(getContext());
|
|
||||||
|
|
||||||
importOldBlockDb();
|
importOldBlockDb();
|
||||||
|
|
||||||
@@ -2071,6 +2072,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
r.score = JUNK_SCORE;
|
r.score = JUNK_SCORE;
|
||||||
Slog.e(TAG, "Suppressing notification from package " + pkg
|
Slog.e(TAG, "Suppressing notification from package " + pkg
|
||||||
+ " by user request.");
|
+ " by user request.");
|
||||||
|
mUsageStats.registerBlocked(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2736,12 +2738,6 @@ public class NotificationManagerService extends SystemService {
|
|||||||
case REASON_NOMAN_CANCEL_ALL:
|
case REASON_NOMAN_CANCEL_ALL:
|
||||||
mUsageStats.registerRemovedByApp(r);
|
mUsageStats.registerRemovedByApp(r);
|
||||||
break;
|
break;
|
||||||
case REASON_DELEGATE_CLICK:
|
|
||||||
mUsageStats.registerCancelDueToClick(r);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mUsageStats.registerCancelUnknown(r);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mNotificationsByKey.remove(r.sbn.getKey());
|
mNotificationsByKey.remove(r.sbn.getKey());
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.content.Context;
|
|||||||
public interface NotificationSignalExtractor {
|
public interface NotificationSignalExtractor {
|
||||||
|
|
||||||
/** One-time initialization. */
|
/** One-time initialization. */
|
||||||
public void initialize(Context context);
|
public void initialize(Context context, NotificationUsageStats usageStats);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called once per notification that is posted or updated.
|
* Called once per notification that is posted or updated.
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ import android.os.Handler;
|
|||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.service.notification.StatusBarNotification;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -47,21 +47,45 @@ import java.util.Map;
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public class NotificationUsageStats {
|
public class NotificationUsageStats {
|
||||||
// WARNING: Aggregated stats can grow unboundedly with pkg+id+tag.
|
private static final String TAG = "NotificationUsageStats";
|
||||||
// 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 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 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).
|
// 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 SQLiteLog mSQLiteLog;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
private final Handler mHandler;
|
||||||
|
private long mLastEmitTime;
|
||||||
|
|
||||||
public NotificationUsageStats(Context context) {
|
public NotificationUsageStats(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
mLastEmitTime = SystemClock.elapsedRealtime();
|
||||||
mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null;
|
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 class NotificationUsageStats {
|
|||||||
public synchronized void registerPostedByApp(NotificationRecord notification) {
|
public synchronized void registerPostedByApp(NotificationRecord notification) {
|
||||||
notification.stats = new SingleNotificationStats();
|
notification.stats = new SingleNotificationStats();
|
||||||
notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
|
notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
|
||||||
|
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
|
||||||
|
for (AggregatedStats stats : aggregatedStatsArray) {
|
||||||
stats.numPostedByApp++;
|
stats.numPostedByApp++;
|
||||||
}
|
}
|
||||||
|
releaseAggregatedStatsLocked(aggregatedStatsArray);
|
||||||
if (ENABLE_SQLITE_LOG) {
|
if (ENABLE_SQLITE_LOG) {
|
||||||
mSQLiteLog.logPosted(notification);
|
mSQLiteLog.logPosted(notification);
|
||||||
}
|
}
|
||||||
@@ -83,9 +110,11 @@ public class NotificationUsageStats {
|
|||||||
*/
|
*/
|
||||||
public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
|
public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
|
||||||
notification.stats = old.stats;
|
notification.stats = old.stats;
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
|
||||||
|
for (AggregatedStats stats : aggregatedStatsArray) {
|
||||||
stats.numUpdatedByApp++;
|
stats.numUpdatedByApp++;
|
||||||
}
|
}
|
||||||
|
releaseAggregatedStatsLocked(aggregatedStatsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,10 +122,11 @@ public class NotificationUsageStats {
|
|||||||
*/
|
*/
|
||||||
public synchronized void registerRemovedByApp(NotificationRecord notification) {
|
public synchronized void registerRemovedByApp(NotificationRecord notification) {
|
||||||
notification.stats.onRemoved();
|
notification.stats.onRemoved();
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
|
||||||
|
for (AggregatedStats stats : aggregatedStatsArray) {
|
||||||
stats.numRemovedByApp++;
|
stats.numRemovedByApp++;
|
||||||
stats.collect(notification.stats);
|
|
||||||
}
|
}
|
||||||
|
releaseAggregatedStatsLocked(aggregatedStatsArray);
|
||||||
if (ENABLE_SQLITE_LOG) {
|
if (ENABLE_SQLITE_LOG) {
|
||||||
mSQLiteLog.logRemoved(notification);
|
mSQLiteLog.logRemoved(notification);
|
||||||
}
|
}
|
||||||
@@ -109,10 +139,6 @@ public class NotificationUsageStats {
|
|||||||
MetricsLogger.histogram(mContext, "note_dismiss_longevity",
|
MetricsLogger.histogram(mContext, "note_dismiss_longevity",
|
||||||
(int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
|
(int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
|
||||||
notification.stats.onDismiss();
|
notification.stats.onDismiss();
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
|
||||||
stats.numDismissedByUser++;
|
|
||||||
stats.collect(notification.stats);
|
|
||||||
}
|
|
||||||
if (ENABLE_SQLITE_LOG) {
|
if (ENABLE_SQLITE_LOG) {
|
||||||
mSQLiteLog.logDismissed(notification);
|
mSQLiteLog.logDismissed(notification);
|
||||||
}
|
}
|
||||||
@@ -125,36 +151,36 @@ public class NotificationUsageStats {
|
|||||||
MetricsLogger.histogram(mContext, "note_click_longevity",
|
MetricsLogger.histogram(mContext, "note_click_longevity",
|
||||||
(int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
|
(int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
|
||||||
notification.stats.onClick();
|
notification.stats.onClick();
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
|
||||||
stats.numClickedByUser++;
|
|
||||||
}
|
|
||||||
if (ENABLE_SQLITE_LOG) {
|
if (ENABLE_SQLITE_LOG) {
|
||||||
mSQLiteLog.logClicked(notification);
|
mSQLiteLog.logClicked(notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public synchronized void registerPeopleAffinity(NotificationRecord notification, boolean valid,
|
||||||
* Called when the notification is canceled because the user clicked it.
|
boolean starred, boolean cached) {
|
||||||
*
|
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
|
||||||
* <p>Called after {@link #registerClickedByUser(NotificationRecord)}.</p>
|
for (AggregatedStats stats : aggregatedStatsArray) {
|
||||||
*/
|
if (valid) {
|
||||||
public synchronized void registerCancelDueToClick(NotificationRecord notification) {
|
stats.numWithValidPeople++;
|
||||||
notification.stats.onCancel();
|
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
|
||||||
stats.collect(notification.stats);
|
|
||||||
}
|
}
|
||||||
|
if (starred) {
|
||||||
|
stats.numWithStaredPeople++;
|
||||||
|
}
|
||||||
|
if (cached) {
|
||||||
|
stats.numPeopleCacheHit++;
|
||||||
|
} else {
|
||||||
|
stats.numPeopleCacheMiss++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
releaseAggregatedStatsLocked(aggregatedStatsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public synchronized void registerBlocked(NotificationRecord notification) {
|
||||||
* Called when the notification is canceled due to unknown reasons.
|
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
|
||||||
*
|
for (AggregatedStats stats : aggregatedStatsArray) {
|
||||||
* <p>Called for notifications of apps being uninstalled, for example.</p>
|
stats.numBlocked++;
|
||||||
*/
|
|
||||||
public synchronized void registerCancelUnknown(NotificationRecord notification) {
|
|
||||||
notification.stats.onCancel();
|
|
||||||
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
|
|
||||||
stats.collect(notification.stats);
|
|
||||||
}
|
}
|
||||||
|
releaseAggregatedStatsLocked(aggregatedStatsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locked by this.
|
// Locked by this.
|
||||||
@@ -163,24 +189,28 @@ public class NotificationUsageStats {
|
|||||||
return EMPTY_AGGREGATED_STATS;
|
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());
|
// Locked by this.
|
||||||
String userPackage = user + ":" + n.getPackageName();
|
private void releaseAggregatedStatsLocked(AggregatedStats[] array) {
|
||||||
|
for(int i = 0; i < array.length; i++) {
|
||||||
// TODO: Use pool of arrays.
|
array[i] = null;
|
||||||
return new AggregatedStats[] {
|
}
|
||||||
getOrCreateAggregatedStatsLocked(user),
|
mStatsArrays.offer(array);
|
||||||
getOrCreateAggregatedStatsLocked(userPackage),
|
|
||||||
getOrCreateAggregatedStatsLocked(n.getKey()),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locked by this.
|
// Locked by this.
|
||||||
private AggregatedStats getOrCreateAggregatedStatsLocked(String key) {
|
private AggregatedStats getOrCreateAggregatedStatsLocked(String key) {
|
||||||
AggregatedStats result = mStats.get(key);
|
AggregatedStats result = mStats.get(key);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = new AggregatedStats(key);
|
result = new AggregatedStats(mContext, key);
|
||||||
mStats.put(key, result);
|
mStats.put(key, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -193,64 +223,74 @@ public class NotificationUsageStats {
|
|||||||
continue;
|
continue;
|
||||||
as.dump(pw, indent);
|
as.dump(pw, indent);
|
||||||
}
|
}
|
||||||
|
pw.println(indent + "mStatsArrays.size(): " + mStatsArrays.size());
|
||||||
}
|
}
|
||||||
if (ENABLE_SQLITE_LOG) {
|
if (ENABLE_SQLITE_LOG) {
|
||||||
mSQLiteLog.dump(pw, indent, filter);
|
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.
|
* Aggregated notification stats.
|
||||||
*/
|
*/
|
||||||
private static class AggregatedStats {
|
private static class AggregatedStats {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
public final String key;
|
public final String key;
|
||||||
|
|
||||||
// ---- Updated as the respective events occur.
|
// ---- Updated as the respective events occur.
|
||||||
public int numPostedByApp;
|
public int numPostedByApp;
|
||||||
public int numUpdatedByApp;
|
public int numUpdatedByApp;
|
||||||
public int numRemovedByApp;
|
public int numRemovedByApp;
|
||||||
public int numClickedByUser;
|
public int numPeopleCacheHit;
|
||||||
public int numDismissedByUser;
|
public int numPeopleCacheMiss;;
|
||||||
|
public int numWithStaredPeople;
|
||||||
|
public int numWithValidPeople;
|
||||||
|
public int numBlocked;
|
||||||
|
|
||||||
// ---- Updated when a notification is canceled.
|
private AggregatedStats mPrevious;
|
||||||
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();
|
|
||||||
|
|
||||||
public AggregatedStats(String key) {
|
public AggregatedStats(Context context, String key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void collect(SingleNotificationStats singleNotificationStats) {
|
public void emit() {
|
||||||
posttimeMs.addSample(
|
if (mPrevious == null) {
|
||||||
SystemClock.elapsedRealtime() - singleNotificationStats.posttimeElapsedMs);
|
mPrevious = new AggregatedStats(null, key);
|
||||||
if (singleNotificationStats.posttimeToDismissMs >= 0) {
|
|
||||||
posttimeToDismissMs.addSample(singleNotificationStats.posttimeToDismissMs);
|
|
||||||
}
|
}
|
||||||
if (singleNotificationStats.posttimeToFirstClickMs >= 0) {
|
|
||||||
posttimeToFirstClickMs.addSample(singleNotificationStats.posttimeToFirstClickMs);
|
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;
|
||||||
}
|
}
|
||||||
airtimeCount.addSample(singleNotificationStats.airtimeCount);
|
|
||||||
if (singleNotificationStats.airtimeMs >= 0) {
|
void maybeCount(String name, int value) {
|
||||||
airtimeMs.addSample(singleNotificationStats.airtimeMs);
|
if (value > 0) {
|
||||||
}
|
MetricsLogger.count(mContext, name, value);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,17 +309,11 @@ public class NotificationUsageStats {
|
|||||||
indent + " numPostedByApp=" + numPostedByApp + ",\n" +
|
indent + " numPostedByApp=" + numPostedByApp + ",\n" +
|
||||||
indent + " numUpdatedByApp=" + numUpdatedByApp + ",\n" +
|
indent + " numUpdatedByApp=" + numUpdatedByApp + ",\n" +
|
||||||
indent + " numRemovedByApp=" + numRemovedByApp + ",\n" +
|
indent + " numRemovedByApp=" + numRemovedByApp + ",\n" +
|
||||||
indent + " numClickedByUser=" + numClickedByUser + ",\n" +
|
indent + " numPeopleCacheHit=" + numPeopleCacheHit + ",\n" +
|
||||||
indent + " numDismissedByUser=" + numDismissedByUser + ",\n" +
|
indent + " numWithStaredPeople=" + numWithStaredPeople + ",\n" +
|
||||||
indent + " posttimeMs=" + posttimeMs + ",\n" +
|
indent + " numWithValidPeople=" + numWithValidPeople + ",\n" +
|
||||||
indent + " posttimeToDismissMs=" + posttimeToDismissMs + ",\n" +
|
indent + " numPeopleCacheMiss=" + numPeopleCacheMiss + ",\n" +
|
||||||
indent + " posttimeToFirstClickMs=" + posttimeToFirstClickMs + ",\n" +
|
indent + " numBlocked=" + numBlocked + ",\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 + "}";
|
indent + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class PackagePriorityExtractor implements NotificationSignalExtractor {
|
|||||||
|
|
||||||
private RankingConfig mConfig;
|
private RankingConfig mConfig;
|
||||||
|
|
||||||
public void initialize(Context ctx) {
|
public void initialize(Context ctx, NotificationUsageStats usageStats) {
|
||||||
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
|
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class PackageVisibilityExtractor implements NotificationSignalExtractor {
|
|||||||
|
|
||||||
private RankingConfig mConfig;
|
private RankingConfig mConfig;
|
||||||
|
|
||||||
public void initialize(Context ctx) {
|
public void initialize(Context ctx, NotificationUsageStats usageStats) {
|
||||||
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
|
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ public class RankingHelper implements RankingConfig {
|
|||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final Handler mRankingHandler;
|
private final Handler mRankingHandler;
|
||||||
|
|
||||||
public RankingHelper(Context context, Handler rankingHandler, String[] extractorNames) {
|
public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
|
||||||
|
String[] extractorNames) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mRankingHandler = rankingHandler;
|
mRankingHandler = rankingHandler;
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ public class RankingHelper implements RankingConfig {
|
|||||||
Class<?> extractorClass = mContext.getClassLoader().loadClass(extractorNames[i]);
|
Class<?> extractorClass = mContext.getClassLoader().loadClass(extractorNames[i]);
|
||||||
NotificationSignalExtractor extractor =
|
NotificationSignalExtractor extractor =
|
||||||
(NotificationSignalExtractor) extractorClass.newInstance();
|
(NotificationSignalExtractor) extractorClass.newInstance();
|
||||||
extractor.initialize(mContext);
|
extractor.initialize(mContext, usageStats);
|
||||||
extractor.setConfig(this);
|
extractor.setConfig(this);
|
||||||
mSignalExtractors[i] = extractor;
|
mSignalExtractors[i] = extractor;
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import android.util.ArrayMap;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import com.android.internal.logging.MetricsLogger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -85,11 +84,13 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
|
|||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private ContentObserver mObserver;
|
private ContentObserver mObserver;
|
||||||
private int mEvictionCount;
|
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() + ".");
|
if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
|
||||||
mUserToContextMap = new ArrayMap<>();
|
mUserToContextMap = new ArrayMap<>();
|
||||||
mBaseContext = context;
|
mBaseContext = context;
|
||||||
|
mUsageStats = usageStats;
|
||||||
mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
|
mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
|
||||||
mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
|
mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
|
||||||
mBaseContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
|
mBaseContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
|
||||||
@@ -203,8 +204,15 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
|
|||||||
final String key = record.getKey();
|
final String key = record.getKey();
|
||||||
final Bundle extras = record.getNotification().extras;
|
final Bundle extras = record.getNotification().extras;
|
||||||
final float[] affinityOut = new float[1];
|
final float[] affinityOut = new float[1];
|
||||||
final RankingReconsideration rr = validatePeople(context, key, extras, affinityOut);
|
final PeopleRankingReconsideration rr = validatePeople(context, key, extras, affinityOut);
|
||||||
record.setContactAffinity(affinityOut[0]);
|
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;
|
return rr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +253,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
|
|||||||
|
|
||||||
if (pendingLookups.isEmpty()) {
|
if (pendingLookups.isEmpty()) {
|
||||||
if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity);
|
if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity);
|
||||||
if (affinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,6 +420,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
|
|||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
private float mContactAffinity = NONE;
|
private float mContactAffinity = NONE;
|
||||||
|
private NotificationRecord mRecord;
|
||||||
|
|
||||||
private PeopleRankingReconsideration(Context context, String key, LinkedList<String> pendingLookups) {
|
private PeopleRankingReconsideration(Context context, String key, LinkedList<String> pendingLookups) {
|
||||||
super(key);
|
super(key);
|
||||||
@@ -456,7 +464,10 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
|
|||||||
"ms");
|
"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
|
@Override
|
||||||
@@ -469,6 +480,10 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
|
|||||||
public float getContactAffinity() {
|
public float getContactAffinity() {
|
||||||
return mContactAffinity;
|
return mContactAffinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRecord(NotificationRecord record) {
|
||||||
|
mRecord = record;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.server.notification;
|
package com.android.server.notification;
|
||||||
|
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
@@ -24,6 +27,7 @@ import android.test.suitebuilder.annotation.SmallTest;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class RankingHelperTest extends AndroidTestCase {
|
public class RankingHelperTest extends AndroidTestCase {
|
||||||
|
@Mock NotificationUsageStats mUsageStats;
|
||||||
|
|
||||||
private Notification mNotiGroupGSortA;
|
private Notification mNotiGroupGSortA;
|
||||||
private Notification mNotiGroupGSortB;
|
private Notification mNotiGroupGSortB;
|
||||||
@@ -39,9 +43,10 @@ public class RankingHelperTest extends AndroidTestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
UserHandle user = UserHandle.ALL;
|
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())
|
mNotiGroupGSortA = new Notification.Builder(getContext())
|
||||||
.setContentTitle("A")
|
.setContentTitle("A")
|
||||||
|
|||||||
Reference in New Issue
Block a user