summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java27
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/notification/NotificationDelegate.java1
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java12
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java103
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java13
8 files changed, 166 insertions, 5 deletions
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index f3430e7..243ce97 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -49,6 +49,7 @@ interface IStatusBarService
void onNotificationClear(String pkg, String tag, int id, int userId);
void onNotificationVisibilityChanged(
in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
+ void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
void setSystemUiVisibility(int vis, int mask);
void setHardKeyboardEnabled(boolean enabled);
void setWindowState(int window, int state);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index dff3f55..87b1f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -96,7 +96,7 @@ import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
- RecentsComponent.Callbacks {
+ RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
@@ -1035,6 +1035,7 @@ public abstract class BaseStatusBar extends SystemUI implements
Context.LAYOUT_INFLATER_SERVICE);
row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
parent, false);
+ row.setExpansionLogger(this, entry.notification.getKey());
}
// the notification inspector (see SwipeHelper.setLongPressListener)
@@ -1784,4 +1785,13 @@ public abstract class BaseStatusBar extends SystemUI implements
}
return contextForUser.getPackageManager();
}
+
+ @Override
+ public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
+ try {
+ mBarService.onNotificationExpansionChanged(key, userAction, expanded);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e042a53..4b0af11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -54,6 +54,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mMaxExpandHeight;
private View mVetoButton;
private boolean mClearable;
+ private ExpansionLogger mLogger;
+ private String mLoggingKey;
+
+ public interface ExpansionLogger {
+ public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
+ }
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -66,6 +72,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void reset() {
super.reset();
mRowMinHeight = 0;
+ final boolean wasExpanded = isExpanded();
mRowMaxHeight = 0;
mExpandable = false;
mHasUserChangedExpansion = false;
@@ -76,6 +83,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPublicLayout.reset();
mPrivateLayout.reset();
mMaxExpandHeight = 0;
+ logExpansionEvent(false, wasExpanded);
}
@Override
@@ -131,8 +139,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
public void setUserExpanded(boolean userExpanded) {
if (userExpanded && !mExpandable) return;
+ final boolean wasExpanded = isExpanded();
mHasUserChangedExpansion = true;
mUserExpanded = userExpanded;
+ logExpansionEvent(true, wasExpanded);
}
public boolean isUserLocked() {
@@ -156,15 +166,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
* @param expand whether the system wants this notification to be expanded.
*/
public void setSystemExpanded(boolean expand) {
+ final boolean wasExpanded = isExpanded();
mIsSystemExpanded = expand;
notifyHeightChanged();
+ logExpansionEvent(false, wasExpanded);
}
/**
* @param expansionDisabled whether to prevent notification expansion
*/
public void setExpansionDisabled(boolean expansionDisabled) {
+ final boolean wasExpanded = isExpanded();
mExpansionDisabled = expansionDisabled;
+ logExpansionEvent(false, wasExpanded);
notifyHeightChanged();
}
@@ -302,4 +316,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private NotificationContentView getShowingLayout() {
return mShowingPublic ? mPublicLayout : mPrivateLayout;
}
+
+ public void setExpansionLogger(ExpansionLogger logger, String key) {
+ mLogger = logger;
+ mLoggingKey = key;
+ }
+
+
+ private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
+ final boolean nowExpanded = isExpanded();
+ if (wasExpanded != nowExpanded && mLogger != null) {
+ mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 6fab37c..3c50947 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -65,6 +65,8 @@ option java_package com.android.server
27501 notification_panel_hidden
# when notifications are newly displayed on screen, or disappear from screen
27510 notification_visibility_changed (newlyVisibleKeys|3),(noLongerVisibleKeys|3)
+# when notifications are expanded, or contracted
+27511 notification_expansion (key|3),(user_action|1),(expanded|1)
# when a notification has been clicked
27520 notification_clicked (key|3)
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index b41b478..1b59f52 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -32,4 +32,5 @@ public interface NotificationDelegate {
boolean allowDisable(int what, IBinder token, String pkg);
void onNotificationVisibilityChanged(
String[] newlyVisibleKeys, String[] noLongerVisibleKeys);
+ void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bedd369..f9230a3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -611,6 +611,18 @@ public class NotificationManagerService extends SystemService {
}
}
}
+
+ @Override
+ public void onNotificationExpansionChanged(String key,
+ boolean userAction, boolean expanded) {
+ EventLogTags.writeNotificationExpansion(key, userAction ? 1 : 0, expanded ? 1 : 0);
+ synchronized (mNotificationList) {
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r != null) {
+ r.stats.onExpansionChanged(userAction, expanded);
+ }
+ }
+ }
};
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index adf9516..9b56464 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -200,6 +200,9 @@ public class NotificationUsageStats {
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) {
this.key = key;
@@ -222,6 +225,14 @@ public class NotificationUsageStats {
posttimeToFirstAirtimeMs.addSample(
singleNotificationStats.posttimeToFirstAirtimeMs);
}
+ if (singleNotificationStats.posttimeToFirstVisibleExpansionMs >= 0) {
+ posttimeToFirstVisibleExpansionMs.addSample(
+ singleNotificationStats.posttimeToFirstVisibleExpansionMs);
+ }
+ userExpansionCount.addSample(singleNotificationStats.userExpansionCount);
+ if (singleNotificationStats.airtimeExpandedMs >= 0) {
+ airtimeExpandedMs.addSample(singleNotificationStats.airtimeExpandedMs);
+ }
}
public void dump(PrintWriter pw, String indent) {
@@ -247,6 +258,9 @@ public class NotificationUsageStats {
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 + "}";
}
}
@@ -255,6 +269,8 @@ public class NotificationUsageStats {
* Tracks usage of an individual notification that is currently active.
*/
public static class SingleNotificationStats {
+ private boolean isVisible = false;
+ private boolean isExpanded = false;
/** SystemClock.elapsedRealtime() when the notification was posted. */
public long posttimeElapsedMs = -1;
/** Elapsed time since the notification was posted until it was first clicked, or -1. */
@@ -272,6 +288,20 @@ public class NotificationUsageStats {
public long currentAirtimeStartElapsedMs = -1;
/** Accumulated visible time. */
public long airtimeMs = 0;
+ /**
+ * Time in ms between the notification being posted and when it first
+ * became visible and expanded; -1 if it was never visibly expanded.
+ */
+ public long posttimeToFirstVisibleExpansionMs = -1;
+ /**
+ * If currently visible, SystemClock.elapsedRealtime() when the notification was made
+ * visible; -1 otherwise.
+ */
+ public long currentAirtimeExpandedStartElapsedMs = -1;
+ /** Accumulated visible expanded time. */
+ public long airtimeExpandedMs = 0;
+ /** Number of times the notification has been expanded by the user. */
+ public long userExpansionCount = 0;
public long getCurrentPosttimeMs() {
if (posttimeElapsedMs < 0) {
@@ -284,7 +314,16 @@ public class NotificationUsageStats {
long result = airtimeMs;
// Add incomplete airtime if currently shown.
if (currentAirtimeStartElapsedMs >= 0) {
- result+= (SystemClock.elapsedRealtime() - currentAirtimeStartElapsedMs);
+ result += (SystemClock.elapsedRealtime() - currentAirtimeStartElapsedMs);
+ }
+ return result;
+ }
+
+ public long getCurrentAirtimeExpandedMs() {
+ long result = airtimeExpandedMs;
+ // Add incomplete expanded airtime if currently shown.
+ if (currentAirtimeExpandedStartElapsedMs >= 0) {
+ result += (SystemClock.elapsedRealtime() - currentAirtimeExpandedStartElapsedMs);
}
return result;
}
@@ -318,6 +357,8 @@ public class NotificationUsageStats {
public void onVisibilityChanged(boolean visible) {
long elapsedNowMs = SystemClock.elapsedRealtime();
+ final boolean wasVisible = isVisible;
+ isVisible = visible;
if (visible) {
if (currentAirtimeStartElapsedMs < 0) {
airtimeCount++;
@@ -332,6 +373,37 @@ public class NotificationUsageStats {
currentAirtimeStartElapsedMs = -1;
}
}
+
+ if (wasVisible != isVisible) {
+ updateVisiblyExpandedStats();
+ }
+ }
+
+ public void onExpansionChanged(boolean userAction, boolean expanded) {
+ isExpanded = expanded;
+ if (isExpanded && userAction) {
+ userExpansionCount++;
+ }
+ updateVisiblyExpandedStats();
+ }
+
+ private void updateVisiblyExpandedStats() {
+ long elapsedNowMs = SystemClock.elapsedRealtime();
+ if (isExpanded && isVisible) {
+ // expanded and visible
+ if (currentAirtimeExpandedStartElapsedMs < 0) {
+ currentAirtimeExpandedStartElapsedMs = elapsedNowMs;
+ }
+ if (posttimeToFirstVisibleExpansionMs < 0) {
+ posttimeToFirstVisibleExpansionMs = elapsedNowMs - posttimeElapsedMs;
+ }
+ } else {
+ // not-expanded or not-visible
+ if (currentAirtimeExpandedStartElapsedMs >= 0) {
+ airtimeExpandedMs += (elapsedNowMs - currentAirtimeExpandedStartElapsedMs);
+ currentAirtimeExpandedStartElapsedMs = -1;
+ }
+ }
}
/** The notification is leaving the system. Finalize. */
@@ -348,6 +420,9 @@ public class NotificationUsageStats {
", airtimeCount=" + airtimeCount +
", airtimeMs=" + airtimeMs +
", currentAirtimeStartElapsedMs=" + currentAirtimeStartElapsedMs +
+ ", airtimeExpandedMs=" + airtimeExpandedMs +
+ ", posttimeToFirstVisibleExpansionMs=" + posttimeToFirstVisibleExpansionMs +
+ ", currentAirtimeExpandedSEMs=" + currentAirtimeExpandedStartElapsedMs +
'}';
}
}
@@ -393,7 +468,7 @@ public class NotificationUsageStats {
private static final int MSG_DISMISS = 4;
private static final String DB_NAME = "notification_log.db";
- private static final int DB_VERSION = 2;
+ private static final int DB_VERSION = 3;
/** Age in ms after which events are pruned from the DB. */
private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week
@@ -419,6 +494,10 @@ public class NotificationUsageStats {
private static final String COL_ACTION_COUNT = "action_count";
private static final String COL_POSTTIME_MS = "posttime_ms";
private static final String COL_AIRTIME_MS = "airtime_ms";
+ private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms";
+ private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms";
+ private static final String COL_EXPAND_COUNT = "expansion_count";
+
private static final int EVENT_TYPE_POST = 1;
private static final int EVENT_TYPE_CLICK = 2;
@@ -481,6 +560,9 @@ public class NotificationUsageStats {
COL_ACTION_COUNT + " INT," +
COL_POSTTIME_MS + " INT," +
COL_AIRTIME_MS + " INT" +
+ COL_FIRST_EXPANSIONTIME_MS + " INT" +
+ COL_AIRTIME_EXPANDED_MS + " INT" +
+ COL_EXPAND_COUNT + " INT" +
")");
}
@@ -493,6 +575,16 @@ public class NotificationUsageStats {
COL_POSTTIME_MS + " INT");
db.execSQL("ALTER TABLE " + TAB_LOG + " ADD COLUMN " +
COL_AIRTIME_MS + " INT");
+ case 2:
+ // Add COL_EXPANSIONTIME_MS column
+ db.execSQL("ALTER TABLE " + TAB_LOG + " ADD COLUMN " +
+ COL_FIRST_EXPANSIONTIME_MS + " INT");
+ // Add COL_AIRTIME_EXPANDED_MS column
+ db.execSQL("ALTER TABLE " + TAB_LOG + " ADD COLUMN " +
+ COL_AIRTIME_EXPANDED_MS + " INT");
+ // Add COL_EXPAND_COUNT column
+ db.execSQL("ALTER TABLE " + TAB_LOG + " ADD COLUMN " +
+ COL_EXPAND_COUNT + " INT");
}
}
};
@@ -553,7 +645,7 @@ public class NotificationUsageStats {
if (eventType == EVENT_TYPE_POST) {
putNotificationDetails(r, cv);
} else {
- putPosttimeAirtime(r, cv);
+ putPosttimeVisibility(r, cv);
}
SQLiteDatabase db = mHelper.getWritableDatabase();
if (db.insert(TAB_LOG, null, cv) < 0) {
@@ -597,9 +689,12 @@ public class NotificationUsageStats {
r.getNotification().actions.length : 0);
}
- private static void putPosttimeAirtime(NotificationRecord r, ContentValues outCv) {
+ private static void putPosttimeVisibility(NotificationRecord r, ContentValues outCv) {
outCv.put(COL_POSTTIME_MS, r.stats.getCurrentPosttimeMs());
outCv.put(COL_AIRTIME_MS, r.stats.getCurrentAirtimeMs());
+ outCv.put(COL_EXPAND_COUNT, r.stats.userExpansionCount);
+ outCv.put(COL_AIRTIME_EXPANDED_MS, r.stats.getCurrentAirtimeExpandedMs());
+ outCv.put(COL_FIRST_EXPANSIONTIME_MS, r.stats.posttimeToFirstVisibleExpansionMs);
}
public void dump(PrintWriter pw, String indent, DumpFilter filter) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d0013aa..f33943d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -573,6 +573,19 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
@Override
+ public void onNotificationExpansionChanged(String key, boolean userAction,
+ boolean expanded) throws RemoteException {
+ enforceStatusBarService();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onNotificationExpansionChanged(
+ key, userAction, expanded);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void onClearAllNotifications(int userId) {
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();