diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java index ea1def07a309c..d2fe394248752 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java @@ -28,10 +28,12 @@ import java.lang.annotation.RetentionPolicy; * and triaging purposes. */ public class DozeEvent extends RichEvent { - public static final int TOTAL_EVENT_TYPES = 19; - - public DozeEvent(int logLevel, int type, String reason) { - super(logLevel, type, reason); + /** + * Initializes a doze event + */ + public DozeEvent init(@EventType int type, String reason) { + super.init(DEBUG, type, reason); + return this; } /** @@ -89,21 +91,6 @@ public class DozeEvent extends RichEvent { } } - /** - * Builds a DozeEvent. - */ - public static class DozeEventBuilder extends RichEvent.Builder { - @Override - public DozeEventBuilder getBuilder() { - return this; - } - - @Override - public RichEvent build() { - return new DozeEvent(mLogLevel, mType, mReason); - } - } - @IntDef({PICKUP_WAKEUP, PULSE_START, PULSE_FINISH, NOTIFICATION_PULSE, DOZING, FLING, EMERGENCY_CALL, KEYGUARD_BOUNCER_CHANGED, SCREEN_ON, SCREEN_OFF, MISSED_TICK, TIME_TICK_SCHEDULED, KEYGUARD_VISIBILITY_CHANGE, DOZE_STATE_CHANGED, WAKE_DISPLAY, @@ -132,6 +119,7 @@ public class DozeEvent extends RichEvent { public static final int PULSE_DROPPED = 16; public static final int PULSE_DISABLED_BY_PROX = 17; public static final int SENSOR_TRIGGERED = 18; + public static final int TOTAL_EVENT_TYPES = 19; public static final int TOTAL_REASONS = 10; @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 2e4466d479279..fe504216b1668 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -35,9 +35,11 @@ import javax.inject.Singleton; * dependency DumpController DozeLog */ @Singleton -public class DozeLog extends SysuiLog { +public class DozeLog extends SysuiLog { private static final String TAG = "DozeLog"; + private DozeEvent mRecycledEvent; + private boolean mPulsing; private long mSince; private SummaryStats mPickupPulseNearVibrationStats; @@ -73,8 +75,8 @@ public class DozeLog extends SysuiLog { * Appends pickup wakeup event to the logs */ public void tracePickupWakeUp(boolean withinVibrationThreshold) { - if (log(DozeEvent.PICKUP_WAKEUP, - "withinVibrationThreshold=" + withinVibrationThreshold)) { + log(DozeEvent.PICKUP_WAKEUP, "withinVibrationThreshold=" + withinVibrationThreshold); + if (mEnabled) { (withinVibrationThreshold ? mPickupPulseNearVibrationStats : mPickupPulseNotNearVibrationStats).append(); } @@ -85,27 +87,24 @@ public class DozeLog extends SysuiLog { * @param reason why the pulse started */ public void tracePulseStart(@DozeEvent.Reason int reason) { - if (log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason))) { - mPulsing = true; - } + log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason)); + if (mEnabled) mPulsing = true; } /** * Appends pulse finished event to the logs */ public void tracePulseFinish() { - if (log(DozeEvent.PULSE_FINISH)) { - mPulsing = false; - } + log(DozeEvent.PULSE_FINISH); + if (mEnabled) mPulsing = false; } /** * Appends pulse event to the logs */ public void traceNotificationPulse() { - if (log(DozeEvent.NOTIFICATION_PULSE)) { - mNotificationPulseStats.append(); - } + log(DozeEvent.NOTIFICATION_PULSE); + if (mEnabled) mNotificationPulseStats.append(); } /** @@ -113,9 +112,8 @@ public class DozeLog extends SysuiLog { * @param dozing true if dozing, else false */ public void traceDozing(boolean dozing) { - if (log(DozeEvent.DOZING, "dozing=" + dozing)) { - mPulsing = false; - } + log(DozeEvent.DOZING, "dozing=" + dozing); + if (mEnabled) mPulsing = false; } /** @@ -133,9 +131,8 @@ public class DozeLog extends SysuiLog { * Appends emergency call event to the logs */ public void traceEmergencyCall() { - if (log(DozeEvent.EMERGENCY_CALL)) { - mEmergencyCallStats.append(); - } + log(DozeEvent.EMERGENCY_CALL); + if (mEnabled) mEmergencyCallStats.append(); } /** @@ -150,7 +147,8 @@ public class DozeLog extends SysuiLog { * Appends screen-on event to the logs */ public void traceScreenOn() { - if (log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing)) { + log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing); + if (mEnabled) { (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append(); mPulsing = false; } @@ -188,10 +186,8 @@ public class DozeLog extends SysuiLog { * @param showing whether the keyguard is now showing */ public void traceKeyguard(boolean showing) { - if (log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing) - && !showing) { - mPulsing = false; - } + log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing); + if (mEnabled && !showing) mPulsing = false; } /** @@ -217,12 +213,11 @@ public class DozeLog extends SysuiLog { * @param reason why proximity result was triggered */ public void traceProximityResult(boolean near, long millis, @DozeEvent.Reason int reason) { - if (log(DozeEvent.PROXIMITY_RESULT, + log(DozeEvent.PROXIMITY_RESULT, " reason=" + DozeEvent.reasonToString(reason) - + " near=" + near - + " millis=" + millis)) { - mProxStats[reason][near ? 0 : 1].append(); - } + + " near=" + near + + " millis=" + millis); + if (mEnabled) mProxStats[reason][near ? 0 : 1].append(); } /** @@ -250,15 +245,16 @@ public class DozeLog extends SysuiLog { } } - private boolean log(@DozeEvent.EventType int eventType) { - return log(eventType, ""); + private void log(@DozeEvent.EventType int eventType) { + log(eventType, ""); } - private boolean log(@DozeEvent.EventType int eventType, String msg) { - return super.log(new DozeEvent.DozeEventBuilder() - .setType(eventType) - .setReason(msg) - .build()); + private void log(@DozeEvent.EventType int eventType, String msg) { + if (mRecycledEvent != null) { + mRecycledEvent = log(mRecycledEvent.init(eventType, msg)); + } else { + mRecycledEvent = log(new DozeEvent().init(eventType, msg)); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/log/Event.java b/packages/SystemUI/src/com/android/systemui/log/Event.java index 92862a2bc74c3..7bc1abfbb0d8e 100644 --- a/packages/SystemUI/src/com/android/systemui/log/Event.java +++ b/packages/SystemUI/src/com/android/systemui/log/Event.java @@ -37,20 +37,28 @@ public class Event { public static final int INFO = 4; public static final int WARN = 5; public static final int ERROR = 6; + public static final @Level int DEFAULT_LOG_LEVEL = DEBUG; private long mTimestamp; - private @Level int mLogLevel = DEBUG; - protected String mMessage; + private @Level int mLogLevel = DEFAULT_LOG_LEVEL; + private String mMessage = ""; - public Event(String message) { - mTimestamp = System.currentTimeMillis(); - mMessage = message; + /** + * initialize an event with a message + */ + public Event init(String message) { + init(DEFAULT_LOG_LEVEL, message); + return this; } - public Event(@Level int logLevel, String message) { + /** + * initialize an event with a logLevel and message + */ + public Event init(@Level int logLevel, String message) { mTimestamp = System.currentTimeMillis(); mLogLevel = logLevel; mMessage = message; + return this; } public String getMessage() { @@ -64,4 +72,13 @@ public class Event { public @Level int getLogLevel() { return mLogLevel; } + + /** + * Recycle this event + */ + void recycle() { + mTimestamp = -1; + mLogLevel = DEFAULT_LOG_LEVEL; + mMessage = ""; + } } diff --git a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java index acf761ed3936c..470f2b0d1b98d 100644 --- a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java +++ b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java @@ -23,23 +23,21 @@ package com.android.systemui.log; * Events are stored in {@link SysuiLog} and can be printed in a dumpsys. */ public abstract class RichEvent extends Event { - private final int mType; - private final String mReason; + private int mType; /** - * Create a rich event that includes an event type that matches with an index in the array + * Initializes a rich event that includes an event type that matches with an index in the array * getEventLabels(). */ - public RichEvent(@Event.Level int logLevel, int type, String reason) { - super(logLevel, null); + public RichEvent init(@Event.Level int logLevel, int type, String reason) { final int numEvents = getEventLabels().length; if (type < 0 || type >= numEvents) { throw new IllegalArgumentException("Unsupported event type. Events only supported" + " from 0 to " + (numEvents - 1) + ", but given type=" + type); } mType = type; - mReason = reason; - mMessage = getEventLabels()[mType] + " " + mReason; + super.init(logLevel, getEventLabels()[mType] + " " + reason); + return this; } /** @@ -49,25 +47,43 @@ public abstract class RichEvent extends Event { */ public abstract String[] getEventLabels(); - public int getType() { - return mType; + @Override + public void recycle() { + super.recycle(); + mType = -1; } - public String getReason() { - return mReason; + public int getType() { + return mType; } /** * Builder to build a RichEvent. * @param Log specific builder that is extending this builder + * @param Type of event we'll be building */ - public abstract static class Builder> { + public abstract static class Builder, E extends RichEvent> { public static final int UNINITIALIZED = -1; + public final SysuiLog mLog; private B mBuilder = getBuilder(); - protected int mType = UNINITIALIZED; + protected int mType; protected String mReason; - protected @Level int mLogLevel = VERBOSE; + protected @Level int mLogLevel; + + public Builder(SysuiLog sysuiLog) { + mLog = sysuiLog; + reset(); + } + + /** + * Reset this builder's parameters so it can be reused to build another RichEvent. + */ + public void reset() { + mType = UNINITIALIZED; + mReason = null; + mLogLevel = VERBOSE; + } /** * Get the log-specific builder. @@ -75,9 +91,9 @@ public abstract class RichEvent extends Event { public abstract B getBuilder(); /** - * Build the log-specific event. + * Build the log-specific event given an event to populate. */ - public abstract RichEvent build(); + public abstract E build(E e); /** * Optional - set the log level. Defaults to DEBUG. diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java index 0f71d22b218f0..4e15668f6a340 100644 --- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java @@ -20,6 +20,7 @@ import android.os.Build; import android.os.SystemProperties; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.DumpController; import com.android.systemui.Dumpable; @@ -39,23 +40,26 @@ import java.util.Locale; * To manually view the logs via adb: * adb shell dumpsys activity service com.android.systemui/.SystemUIService \ * dependency DumpController + * + * Logs can be disabled by setting the following SystemProperty and then restarting the device: + * adb shell setprop persist.sysui.log.enabled. true/false && adb reboot + * + * @param Type of event we'll be logging */ -public class SysuiLog implements Dumpable { +public class SysuiLog implements Dumpable { public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US); - private final Object mDataLock = new Object(); + protected final Object mDataLock = new Object(); private final String mId; private final int mMaxLogs; protected boolean mEnabled; protected boolean mLogToLogcatEnabled; - @VisibleForTesting protected ArrayDeque mTimeline; + @VisibleForTesting protected ArrayDeque mTimeline; /** * Creates a SysuiLog - * To enable or disable logs, set the system property and then restart the device: - * adb shell setprop sysui.log.enabled. true/false && adb reboot * @param dumpController where to register this logger's dumpsys * @param id user-readable tag for this logger * @param maxDebugLogs maximum number of logs to retain when {@link sDebuggable} is true @@ -79,23 +83,20 @@ public class SysuiLog implements Dumpable { dumpController.registerDumpable(mId, this); } - public SysuiLog(DumpController dumpController, String id) { - this(dumpController, id, DEFAULT_MAX_DEBUG_LOGS, DEFAULT_MAX_LOGS); - } - /** * Logs an event to the timeline which can be printed by the dumpsys. * May also log to logcat if enabled. - * @return true if event was logged, else false + * @return the last event that was discarded from the Timeline (can be recycled) */ - public boolean log(Event event) { + public E log(E event) { if (!mEnabled) { - return false; + return null; } + E recycledEvent = null; synchronized (mDataLock) { if (mTimeline.size() >= mMaxLogs) { - mTimeline.removeFirst(); + recycledEvent = mTimeline.removeFirst(); } mTimeline.add(event); @@ -121,13 +122,18 @@ public class SysuiLog implements Dumpable { break; } } - return true; + + if (recycledEvent != null) { + recycledEvent.recycle(); + } + + return recycledEvent; } /** * @return user-readable string of the given event with timestamp */ - public String eventToTimestampedString(Event event) { + private String eventToTimestampedString(Event event) { StringBuilder sb = new StringBuilder(); sb.append(SysuiLog.DATE_FORMAT.format(event.getTimestamp())); sb.append(" "); @@ -142,9 +148,7 @@ public class SysuiLog implements Dumpable { return event.getMessage(); } - /** - * only call on this method if you have the mDataLock - */ + @GuardedBy("mDataLock") private void dumpTimelineLocked(PrintWriter pw) { pw.println("\tTimeline:"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 7a58097f3ec18..d81743ab1f5d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -267,14 +267,13 @@ public class NotificationEntryManager implements NotificationEntry entry = mPendingNotifications.get(key); entry.abortTask(); mPendingNotifications.remove(key); - mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.getSbn(), null, - "PendingNotification aborted. " + reason); + mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry, "PendingNotification aborted" + + " reason=" + reason); } NotificationEntry addedEntry = getActiveNotificationUnfiltered(key); if (addedEntry != null) { addedEntry.abortTask(); - mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getSbn(), - null, reason); + mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getKey() + " " + reason); } } @@ -501,7 +500,7 @@ public class NotificationEntryManager implements abortExistingInflation(key, "addNotification"); mPendingNotifications.put(key, entry); - mNotifLog.log(NotifEvent.NOTIF_ADDED, entry.getSbn()); + mNotifLog.log(NotifEvent.NOTIF_ADDED, entry); for (NotificationEntryListener listener : mNotificationEntryListeners) { listener.onPendingEntryAdded(entry); } @@ -536,7 +535,7 @@ public class NotificationEntryManager implements entry.setSbn(notification); mGroupManager.onEntryUpdated(entry, oldSbn); - mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.getSbn(), entry.getRanking()); + mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry); for (NotificationEntryListener listener : mNotificationEntryListeners) { listener.onPreEntryUpdated(entry); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java index 21a4b4f895e52..a1cfb5424c086 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java @@ -29,7 +29,6 @@ import static com.android.systemui.statusbar.notification.collection.listbuilder import android.annotation.MainThread; import android.annotation.Nullable; import android.util.ArrayMap; -import android.util.Log; import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; @@ -40,6 +39,8 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider; +import com.android.systemui.statusbar.notification.logging.NotifEvent; +import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.util.Assert; import com.android.systemui.util.time.SystemClock; @@ -59,8 +60,8 @@ import javax.inject.Singleton; @MainThread @Singleton public class NotifListBuilderImpl implements NotifListBuilder { - private final SystemClock mSystemClock; + private final NotifLog mNotifLog; private final List mNotifList = new ArrayList<>(); @@ -86,9 +87,10 @@ public class NotifListBuilderImpl implements NotifListBuilder { private final List mReadOnlyNotifList = Collections.unmodifiableList(mNotifList); @Inject - public NotifListBuilderImpl(SystemClock systemClock) { + public NotifListBuilderImpl(SystemClock systemClock, NotifLog notifLog) { Assert.isMainThread(); mSystemClock = systemClock; + mNotifLog = notifLog; } /** @@ -193,7 +195,8 @@ public class NotifListBuilderImpl implements NotifListBuilder { Assert.isMainThread(); mPipelineState.requireIsBefore(STATE_BUILD_STARTED); - Log.i(TAG, "Build request received from NotifCollection"); + mNotifLog.log(NotifEvent.ON_BUILD_LIST, "Request received from " + + "NotifCollection"); mAllEntries = entries; buildList(); } @@ -202,8 +205,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { private void onFilterInvalidated(NotifFilter filter) { Assert.isMainThread(); - // TODO: Convert these log statements (here and elsewhere) into timeline logging - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.FILTER_INVALIDATED, String.format( "Filter \"%s\" invalidated; pipeline state is %d", filter.getName(), mPipelineState.getState())); @@ -214,7 +216,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { private void onPromoterInvalidated(NotifPromoter filter) { Assert.isMainThread(); - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.PROMOTER_INVALIDATED, String.format( "NotifPromoter \"%s\" invalidated; pipeline state is %d", filter.getName(), mPipelineState.getState())); @@ -225,7 +227,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { private void onSectionsProviderInvalidated(SectionsProvider provider) { Assert.isMainThread(); - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.SECTIONS_PROVIDER_INVALIDATED, String.format( "Sections provider \"%s\" invalidated; pipeline state is %d", provider.getName(), mPipelineState.getState())); @@ -236,7 +238,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { private void onNotifComparatorInvalidated(NotifComparator comparator) { Assert.isMainThread(); - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.COMPARATOR_INVALIDATED, String.format( "Comparator \"%s\" invalidated; pipeline state is %d", comparator.getName(), mPipelineState.getState())); @@ -254,7 +256,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { * if we detect that behavior, we should crash instantly. */ private void buildList() { - Log.i(TAG, "Starting notif list build #" + mIterationCount + "..."); + mNotifLog.log(NotifEvent.START_BUILD_LIST, "Run #" + mIterationCount + "..."); mPipelineState.requireIsBefore(STATE_BUILD_STARTED); mPipelineState.setState(STATE_BUILD_STARTED); @@ -288,15 +290,16 @@ public class NotifListBuilderImpl implements NotifListBuilder { freeEmptyGroups(); // Step 5: Dispatch the new list, first to any listeners and then to the view layer - Log.i(TAG, "List finalized, is:\n" + dumpList(mNotifList)); - Log.i(TAG, "Dispatching final list to listeners..."); + mNotifLog.log(NotifEvent.DISPATCH_FINAL_LIST, "List finalized, is:\n" + + dumpList(mNotifList)); dispatchOnBeforeRenderList(mReadOnlyNotifList); if (mOnRenderListListener != null) { mOnRenderListListener.onRenderList(mReadOnlyNotifList); } // Step 6: We're done! - Log.i(TAG, "Notif list build #" + mIterationCount + " completed"); + mNotifLog.log(NotifEvent.LIST_BUILD_COMPLETE, + "Notif list build #" + mIterationCount + " completed"); mPipelineState.setState(STATE_IDLE); mIterationCount++; } @@ -354,7 +357,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { if (existingSummary == null) { group.setSummary(entry); } else { - Log.w(TAG, String.format( + mNotifLog.log(NotifEvent.WARN, String.format( "Duplicate summary for group '%s': '%s' vs. '%s'", group.getKey(), existingSummary.getKey(), @@ -377,7 +380,8 @@ public class NotifListBuilderImpl implements NotifListBuilder { final String topLevelKey = entry.getKey(); if (mGroups.containsKey(topLevelKey)) { - Log.wtf(TAG, "Duplicate non-group top-level key: " + topLevelKey); + mNotifLog.log(NotifEvent.WARN, + "Duplicate non-group top-level key: " + topLevelKey); } else { entry.setParent(ROOT_ENTRY); out.add(entry); @@ -539,7 +543,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { private void logParentingChanges() { for (NotificationEntry entry : mAllEntries) { if (entry.getParent() != entry.getPreviousParent()) { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.PARENT_CHANGED, String.format( "%s: parent changed from %s to %s", entry.getKey(), entry.getPreviousParent() == null @@ -550,7 +554,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { } for (GroupEntry group : mGroups.values()) { if (group.getParent() != group.getPreviousParent()) { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.PARENT_CHANGED, String.format( "%s: parent changed from %s to %s", group.getKey(), group.getPreviousParent() == null @@ -607,17 +611,17 @@ public class NotifListBuilderImpl implements NotifListBuilder { if (filter != entry.mExcludingFilter) { if (entry.mExcludingFilter == null) { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.FILTER_CHANGED, String.format( "%s: filtered out by '%s'", entry.getKey(), filter.getName())); } else if (filter == null) { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.FILTER_CHANGED, String.format( "%s: no longer filtered out (previous filter was '%s')", entry.getKey(), entry.mExcludingFilter.getName())); } else { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.FILTER_CHANGED, String.format( "%s: filter changed: '%s' -> '%s'", entry.getKey(), entry.mExcludingFilter, @@ -648,23 +652,22 @@ public class NotifListBuilderImpl implements NotifListBuilder { if (promoter != entry.mNotifPromoter) { if (entry.mNotifPromoter == null) { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.PROMOTER_CHANGED, String.format( "%s: Entry promoted to top level by '%s'", entry.getKey(), promoter.getName())); } else if (promoter == null) { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.PROMOTER_CHANGED, String.format( "%s: Entry is no longer promoted to top level (previous promoter was '%s')", entry.getKey(), entry.mNotifPromoter.getName())); } else { - Log.i(TAG, String.format( + mNotifLog.log(NotifEvent.PROMOTER_CHANGED, String.format( "%s: Top-level promoter changed: '%s' -> '%s'", entry.getKey(), entry.mNotifPromoter, promoter)); } - entry.mNotifPromoter = promoter; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java index 511aafc2d12a8..defa3722deef7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java @@ -56,7 +56,7 @@ public class DeviceProvisionedCoordinator implements Coordinator { notifListBuilder.addFilter(mNotifFilter); } - protected final NotifFilter mNotifFilter = new NotifFilter(TAG) { + private final NotifFilter mNotifFilter = new NotifFilter(TAG) { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { return !mDeviceProvisionedController.isDeviceProvisioned() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java index 4803cf478327e..378599b79cc09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java @@ -24,7 +24,6 @@ import android.util.ArraySet; import com.android.systemui.ForegroundServiceController; import com.android.systemui.appops.AppOpsController; -import com.android.systemui.dagger.qualifiers.BgHandler; import com.android.systemui.dagger.qualifiers.MainHandler; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifCollectionListener; @@ -52,12 +51,11 @@ import javax.inject.Singleton; */ @Singleton public class ForegroundCoordinator implements Coordinator { - private static final String TAG = "ForegroundNotificationCoordinator"; + private static final String TAG = "ForegroundCoordinator"; private final ForegroundServiceController mForegroundServiceController; private final AppOpsController mAppOpsController; private final Handler mMainHandler; - private final Handler mBgHandler; private NotifCollection mNotifCollection; @@ -65,12 +63,10 @@ public class ForegroundCoordinator implements Coordinator { public ForegroundCoordinator( ForegroundServiceController foregroundServiceController, AppOpsController appOpsController, - @MainHandler Handler mainHandler, - @BgHandler Handler bgHandler) { + @MainHandler Handler mainHandler) { mForegroundServiceController = foregroundServiceController; mAppOpsController = appOpsController; mMainHandler = mainHandler; - mBgHandler = bgHandler; } @Override @@ -93,7 +89,7 @@ public class ForegroundCoordinator implements Coordinator { /** * Filters out notifications that represent foreground services that are no longer running. */ - protected final NotifFilter mNotifFilter = new NotifFilter(TAG) { + private final NotifFilter mNotifFilter = new NotifFilter(TAG) { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { StatusBarNotification sbn = entry.getSbn(); @@ -120,7 +116,8 @@ public class ForegroundCoordinator implements Coordinator { * Extends the lifetime of foreground notification services such that they show for at least * five seconds */ - private final NotifLifetimeExtender mForegroundLifetimeExtender = new NotifLifetimeExtender() { + private final NotifLifetimeExtender mForegroundLifetimeExtender = + new NotifLifetimeExtender() { private static final int MIN_FGS_TIME_MS = 5000; private OnEndLifetimeExtensionCallback mEndCallback; private Map mEndRunnables = new HashMap<>(); @@ -154,8 +151,8 @@ public class ForegroundCoordinator implements Coordinator { } }; mEndRunnables.put(entry.getKey(), runnable); - mBgHandler.postDelayed(runnable, MIN_FGS_TIME_MS - - (currTime - entry.getSbn().getPostTime())); + mMainHandler.postDelayed(runnable, + MIN_FGS_TIME_MS - (currTime - entry.getSbn().getPostTime())); } } @@ -166,7 +163,7 @@ public class ForegroundCoordinator implements Coordinator { public void cancelLifetimeExtension(NotificationEntry entry) { if (mEndRunnables.containsKey(entry.getKey())) { Runnable endRunnable = mEndRunnables.remove(entry.getKey()); - mBgHandler.removeCallbacks(endRunnable); + mMainHandler.removeCallbacks(endRunnable); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java index 6daf3fc50b300..4413dc46724a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java @@ -51,7 +51,7 @@ import javax.inject.Singleton; */ @Singleton public class KeyguardCoordinator implements Coordinator { - private static final String TAG = "KeyguardNotificationCoordinator"; + private static final String TAG = "KeyguardCoordinator"; private final Context mContext; private final Handler mMainHandler; @@ -86,7 +86,7 @@ public class KeyguardCoordinator implements Coordinator { notifListBuilder.addFilter(mNotifFilter); } - protected final NotifFilter mNotifFilter = new NotifFilter(TAG) { + private final NotifFilter mNotifFilter = new NotifFilter(TAG) { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { final StatusBarNotification sbn = entry.getSbn(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index c390f96f004df..24e7a79e95883 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -26,7 +26,10 @@ import javax.inject.Inject; import javax.inject.Singleton; /** - * Filters out NotificationEntries based on its Ranking. + * Filters out NotificationEntries based on its Ranking and dozing state. + * We check the NotificationEntry's Ranking for: + * - whether the notification's app is suspended or hiding its notifications + * - whether DND settings are hiding notifications from ambient display or the notification list */ @Singleton public class RankingCoordinator implements Coordinator { @@ -51,7 +54,7 @@ public class RankingCoordinator implements Coordinator { * NotifListBuilder invalidates the notification list each time the ranking is updated, * so we don't need to explicitly invalidate this filter on ranking update. */ - protected final NotifFilter mNotifFilter = new NotifFilter(TAG) { + private final NotifFilter mNotifFilter = new NotifFilter(TAG) { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { // App suspended from Ranking diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java index 8ebbca26fa5ba..3b06220c7c9c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java @@ -17,10 +17,12 @@ package com.android.systemui.statusbar.notification.logging; import android.annotation.IntDef; -import android.service.notification.NotificationListenerService.Ranking; +import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import com.android.systemui.log.RichEvent; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -31,103 +33,71 @@ import java.lang.annotation.RetentionPolicy; * here to mitigate memory usage. */ public class NotifEvent extends RichEvent { - public static final int TOTAL_EVENT_TYPES = 11; - /** - * Creates a NotifEvent with an event type that matches with an index in the array - * getSupportedEvents() and {@link EventType}. - * - * The status bar notification and ranking objects are stored as shallow copies of the current - * state of the event when this event occurred. + * Initializes a rich event that includes an event type that matches with an index in the array + * getEventLabels(). */ - public NotifEvent(int logLevel, int type, String reason, StatusBarNotification sbn, - Ranking ranking) { - super(logLevel, type, reason); - mMessage += getExtraInfo(sbn, ranking); - } - - private String getExtraInfo(StatusBarNotification sbn, Ranking ranking) { - StringBuilder extraInfo = new StringBuilder(); - + public NotifEvent init(@EventType int type, StatusBarNotification sbn, + NotificationListenerService.Ranking ranking, String reason) { + StringBuilder extraInfo = new StringBuilder(reason); if (sbn != null) { - extraInfo.append(" Sbn="); - extraInfo.append(sbn); + extraInfo.append(" " + sbn.getKey()); } if (ranking != null) { extraInfo.append(" Ranking="); - extraInfo.append(ranking); + extraInfo.append(ranking.getRank()); } - - return extraInfo.toString(); + super.init(INFO, type, extraInfo.toString()); + return this; } /** - * Event labels for NotifEvents - * Index corresponds to the {@link EventType} + * Event labels for ListBuilderEvents + * Index corresponds to an # in {@link EventType} */ @Override public String[] getEventLabels() { - final String[] events = new String[]{ - "NotifAdded", - "NotifRemoved", - "NotifUpdated", - "Filter", - "Sort", - "FilterAndSort", - "NotifVisibilityChanged", - "LifetimeExtended", - "RemoveIntercepted", - "InflationAborted", - "Inflated" - }; - - if (events.length != TOTAL_EVENT_TYPES) { - throw new IllegalStateException("NotifEvents events.length should match " - + TOTAL_EVENT_TYPES - + " events.length=" + events.length - + " TOTAL_EVENT_LENGTH=" + TOTAL_EVENT_TYPES); - } - return events; + assert (TOTAL_EVENT_LABELS == (TOTAL_NEM_EVENT_TYPES + TOTAL_LIST_BUILDER_EVENT_TYPES)); + return EVENT_LABELS; } /** - * Builds a NotifEvent. + * @return if this event occurred in {@link NotifListBuilder} */ - public static class NotifEventBuilder extends RichEvent.Builder { - private StatusBarNotification mSbn; - private Ranking mRanking; - - @Override - public NotifEventBuilder getBuilder() { - return this; - } - - /** - * Stores the status bar notification object. A shallow copy is stored in the NotifEvent's - * constructor. - */ - public NotifEventBuilder setSbn(StatusBarNotification sbn) { - mSbn = sbn; - return this; - } - - /** - * Stores the ranking object. A shallow copy is stored in the NotifEvent's - * constructor. - */ - public NotifEventBuilder setRanking(Ranking ranking) { - mRanking = ranking; - return this; - } - - @Override - public RichEvent build() { - return new NotifEvent(mLogLevel, mType, mReason, mSbn, mRanking); - } + static boolean isListBuilderEvent(@EventType int type) { + return isBetweenInclusive(type, 0, TOTAL_LIST_BUILDER_EVENT_TYPES); } - @IntDef({NOTIF_ADDED, + /** + * @return if this event occurred in {@link NotificationEntryManager} + */ + static boolean isNemEvent(@EventType int type) { + return isBetweenInclusive(type, TOTAL_LIST_BUILDER_EVENT_TYPES, + TOTAL_LIST_BUILDER_EVENT_TYPES + TOTAL_NEM_EVENT_TYPES); + } + + private static boolean isBetweenInclusive(int x, int a, int b) { + return x >= a && x <= b; + } + + @IntDef({ + // NotifListBuilder events: + WARN, + ON_BUILD_LIST, + START_BUILD_LIST, + DISPATCH_FINAL_LIST, + LIST_BUILD_COMPLETE, + FILTER_INVALIDATED, + PROMOTER_INVALIDATED, + SECTIONS_PROVIDER_INVALIDATED, + COMPARATOR_INVALIDATED, + PARENT_CHANGED, + FILTER_CHANGED, + PROMOTER_CHANGED, + + // NotificationEntryManager events: + NOTIF_ADDED, NOTIF_REMOVED, NOTIF_UPDATED, FILTER, @@ -139,22 +109,72 @@ public class NotifEvent extends RichEvent { INFLATION_ABORTED, INFLATED }) - - /** - * Types of NotifEvents - */ @Retention(RetentionPolicy.SOURCE) public @interface EventType {} - public static final int NOTIF_ADDED = 0; - public static final int NOTIF_REMOVED = 1; - public static final int NOTIF_UPDATED = 2; - public static final int FILTER = 3; - public static final int SORT = 4; - public static final int FILTER_AND_SORT = 5; - public static final int NOTIF_VISIBILITY_CHANGED = 6; - public static final int LIFETIME_EXTENDED = 7; + + private static final String[] EVENT_LABELS = + new String[]{ + // NotifListBuilder labels: + "Warning", + "OnBuildList", + "StartBuildList", + "DispatchFinalList", + "ListBuildComplete", + "FilterInvalidated", + "PromoterInvalidated", + "SectionsProviderInvalidated", + "ComparatorInvalidated", + "ParentChanged", + "FilterChanged", + "PromoterChanged", + + // NEM event labels: + "NotifAdded", + "NotifRemoved", + "NotifUpdated", + "Filter", + "Sort", + "FilterAndSort", + "NotifVisibilityChanged", + "LifetimeExtended", + "RemoveIntercepted", + "InflationAborted", + "Inflated" + }; + + private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length; + + /** + * Events related to {@link NotifListBuilder} + */ + public static final int WARN = 0; + public static final int ON_BUILD_LIST = 1; + public static final int START_BUILD_LIST = 2; + public static final int DISPATCH_FINAL_LIST = 3; + public static final int LIST_BUILD_COMPLETE = 4; + public static final int FILTER_INVALIDATED = 5; + public static final int PROMOTER_INVALIDATED = 6; + public static final int SECTIONS_PROVIDER_INVALIDATED = 7; + public static final int COMPARATOR_INVALIDATED = 8; + public static final int PARENT_CHANGED = 9; + public static final int FILTER_CHANGED = 10; + public static final int PROMOTER_CHANGED = 11; + private static final int TOTAL_LIST_BUILDER_EVENT_TYPES = 12; + + /** + * Events related to {@link NotificationEntryManager} + */ + public static final int NOTIF_ADDED = TOTAL_LIST_BUILDER_EVENT_TYPES + 0; + public static final int NOTIF_REMOVED = TOTAL_LIST_BUILDER_EVENT_TYPES + 1; + public static final int NOTIF_UPDATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 2; + public static final int FILTER = TOTAL_LIST_BUILDER_EVENT_TYPES + 3; + public static final int SORT = TOTAL_LIST_BUILDER_EVENT_TYPES + 4; + public static final int FILTER_AND_SORT = TOTAL_LIST_BUILDER_EVENT_TYPES + 5; + public static final int NOTIF_VISIBILITY_CHANGED = TOTAL_LIST_BUILDER_EVENT_TYPES + 6; + public static final int LIFETIME_EXTENDED = TOTAL_LIST_BUILDER_EVENT_TYPES + 7; // unable to remove notif - removal intercepted by {@link NotificationRemoveInterceptor} - public static final int REMOVE_INTERCEPTED = 8; - public static final int INFLATION_ABORTED = 9; - public static final int INFLATED = 10; + public static final int REMOVE_INTERCEPTED = TOTAL_LIST_BUILDER_EVENT_TYPES + 8; + public static final int INFLATION_ABORTED = TOTAL_LIST_BUILDER_EVENT_TYPES + 9; + public static final int INFLATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 10; + private static final int TOTAL_NEM_EVENT_TYPES = 11; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java index 1292831078949..299d628d0fd25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.logging; +import android.os.SystemProperties; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.StatusBarNotification; @@ -33,93 +34,82 @@ import javax.inject.Singleton; * dependency DumpController NotifLog */ @Singleton -public class NotifLog extends SysuiLog { +public class NotifLog extends SysuiLog { private static final String TAG = "NotifLog"; + private static final boolean SHOW_NEM_LOGS = + SystemProperties.getBoolean("persist.sysui.log.notif.nem", true); + private static final boolean SHOW_LIST_BUILDER_LOGS = + SystemProperties.getBoolean("persist.sysui.log.notif.listbuilder", true); + private static final int MAX_DOZE_DEBUG_LOGS = 400; private static final int MAX_DOZE_LOGS = 50; + private NotifEvent mRecycledEvent; + @Inject public NotifLog(DumpController dumpController) { super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS); } /** - * Logs a {@link NotifEvent} with a notification, ranking and message + * Logs a {@link NotifEvent} with a notification, ranking and message. + * Uses the last recycled event if available. * @return true if successfully logged, else false */ - public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, - Ranking ranking, String msg) { - return log(new NotifEvent.NotifEventBuilder() - .setType(eventType) - .setSbn(sbn) - .setRanking(ranking) - .setReason(msg) - .build()); + public void log(@NotifEvent.EventType int eventType, + StatusBarNotification sbn, Ranking ranking, String msg) { + if (!mEnabled + || (NotifEvent.isListBuilderEvent(eventType) && !SHOW_LIST_BUILDER_LOGS) + || (NotifEvent.isNemEvent(eventType) && !SHOW_NEM_LOGS)) { + return; + } + + if (mRecycledEvent != null) { + mRecycledEvent = log(mRecycledEvent.init(eventType, sbn, ranking, msg)); + } else { + mRecycledEvent = log(new NotifEvent().init(eventType, sbn, ranking, msg)); + } } /** - * Logs a {@link NotifEvent} - * @return true if successfully logged, else false + * Logs a {@link NotifEvent} with no extra information aside from the event type */ - public boolean log(@NotifEvent.EventType int eventType) { - return log(eventType, null, null, null); + public void log(@NotifEvent.EventType int eventType) { + log(eventType, null, null, ""); } /** * Logs a {@link NotifEvent} with a message - * @return true if successfully logged, else false */ - public boolean log(@NotifEvent.EventType int eventType, String msg) { - return log(eventType, null, null, msg); + public void log(@NotifEvent.EventType int eventType, String msg) { + log(eventType, null, null, msg); } /** - * Logs a {@link NotifEvent} with a notification - * @return true if successfully logged, else false + * Logs a {@link NotifEvent} with a entry */ - public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn) { - return log(eventType, sbn, null, ""); + public void log(@NotifEvent.EventType int eventType, NotificationEntry entry) { + log(eventType, entry.getSbn(), entry.getRanking(), ""); } /** - * Logs a {@link NotifEvent} with a notification - * @return true if successfully logged, else false + * Logs a {@link NotifEvent} with a NotificationEntry and message */ - public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) { - return log(eventType, sbn, null, msg); + public void log(@NotifEvent.EventType int eventType, NotificationEntry entry, String msg) { + log(eventType, entry.getSbn(), entry.getRanking(), msg); } /** - * Logs a {@link NotifEvent} with a ranking - * @return true if successfully logged, else false + * Logs a {@link NotifEvent} with a notification and message */ - public boolean log(@NotifEvent.EventType int eventType, Ranking ranking) { - return log(eventType, null, ranking, ""); + public void log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) { + log(eventType, sbn, null, msg); } /** - * Logs a {@link NotifEvent} with a notification and ranking - * @return true if successfully logged, else false + * Logs a {@link NotifEvent} with a ranking and message */ - public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, - Ranking ranking) { - return log(eventType, sbn, ranking, ""); - } - - /** - * Logs a {@link NotifEvent} with a notification entry - * @return true if successfully logged, else false - */ - public boolean log(@NotifEvent.EventType int eventType, NotificationEntry entry) { - return log(eventType, entry.getSbn(), entry.getRanking(), ""); - } - - /** - * Logs a {@link NotifEvent} with a notification entry - * @return true if successfully logged, else false - */ - public boolean log(@NotifEvent.EventType int eventType, NotificationEntry entry, - String msg) { - return log(eventType, entry.getSbn(), entry.getRanking(), msg); + public void log(@NotifEvent.EventType int eventType, Ranking ranking, String msg) { + log(eventType, null, ranking, msg); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java index 2f90641775e82..4a90bb91ca37b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java @@ -57,7 +57,7 @@ public class RichEventTest extends SysuiTestCase { class TestableRichEvent extends RichEvent { TestableRichEvent(int logLevel, int type, String reason) { - super(logLevel, type, reason); + init(logLevel, type, reason); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java index 1e8ebeafce8a7..e7b317e882ef7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java @@ -35,11 +35,12 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) public class SysuiLogTest extends SysuiTestCase { private static final String TEST_ID = "TestLogger"; + private static final String TEST_MSG = "msg"; private static final int MAX_LOGS = 5; @Mock private DumpController mDumpController; - private SysuiLog mSysuiLog; + private SysuiLog mSysuiLog; @Before public void setup() { @@ -48,35 +49,63 @@ public class SysuiLogTest extends SysuiTestCase { @Test public void testLogDisabled_noLogsWritten() { - mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false, false); - assertEquals(mSysuiLog.mTimeline, null); + mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, false); + assertEquals(null, mSysuiLog.mTimeline); - mSysuiLog.log(new Event("msg")); - assertEquals(mSysuiLog.mTimeline, null); + mSysuiLog.log(createEvent(TEST_MSG)); + assertEquals(null, mSysuiLog.mTimeline); } @Test public void testLogEnabled_logWritten() { - mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false); - assertEquals(mSysuiLog.mTimeline.size(), 0); + mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); + assertEquals(0, mSysuiLog.mTimeline.size()); - mSysuiLog.log(new Event("msg")); - assertEquals(mSysuiLog.mTimeline.size(), 1); + mSysuiLog.log(createEvent(TEST_MSG)); + assertEquals(1, mSysuiLog.mTimeline.size()); } @Test public void testMaxLogs() { - mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false); + mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); assertEquals(mSysuiLog.mTimeline.size(), 0); - final String msg = "msg"; for (int i = 0; i < MAX_LOGS + 1; i++) { - mSysuiLog.log(new Event(msg + i)); + mSysuiLog.log(createEvent(TEST_MSG + i)); } - assertEquals(mSysuiLog.mTimeline.size(), MAX_LOGS); + assertEquals(MAX_LOGS, mSysuiLog.mTimeline.size()); - // check the first message (msg0) is deleted: - assertEquals(mSysuiLog.mTimeline.getFirst().getMessage(), msg + "1"); + // check the first message (msg0) was replaced with msg1: + assertEquals(TEST_MSG + "1", mSysuiLog.mTimeline.getFirst().getMessage()); + } + + @Test + public void testRecycleLogs() { + // GIVEN a SysuiLog with one log + mSysuiLog = new TestSysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); + Event e = createEvent(TEST_MSG); // msg + mSysuiLog.log(e); // Logs: [msg] + + Event recycledEvent = null; + // WHEN we add MAX_LOGS after the first log + for (int i = 0; i < MAX_LOGS; i++) { + recycledEvent = mSysuiLog.log(createEvent(TEST_MSG + i)); + } + // Logs: [msg1, msg2, msg3, msg4] + + // THEN we see the recycledEvent is e + assertEquals(e, recycledEvent); + } + + private Event createEvent(String msg) { + return new Event().init(msg); + } + + public class TestSysuiLog extends SysuiLog { + protected TestSysuiLog(DumpController dumpController, String id, int maxLogs, + boolean enabled) { + super(dumpController, id, maxLogs, enabled, false); + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java index a25af84ca28ef..6d56b06fe72e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider; +import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.util.Assert; import com.android.systemui.util.time.FakeSystemClock; @@ -76,6 +77,7 @@ public class NotifListBuilderImplTest extends SysuiTestCase { private NotifListBuilderImpl mListBuilder; private FakeSystemClock mSystemClock = new FakeSystemClock(); + @Mock private NotifLog mNotifLog; @Mock private NotifCollection mNotifCollection; @Spy private OnBeforeTransformGroupsListener mOnBeforeTransformGroupsListener; @Spy private OnBeforeSortListener mOnBeforeSortListener; @@ -97,7 +99,7 @@ public class NotifListBuilderImplTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); Assert.sMainLooper = TestableLooper.get(this).getLooper(); - mListBuilder = new NotifListBuilderImpl(mSystemClock); + mListBuilder = new NotifListBuilderImpl(mSystemClock, mNotifLog); mListBuilder.setOnRenderListListener(mOnRenderListListener); mListBuilder.attach(mNotifCollection);