Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24096646 authored by Will Brockman's avatar Will Brockman Committed by Automerger Merge Worker
Browse files

Merge "More accurate notification panel logs." into rvc-dev am: 0e934737

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11441782

Change-Id: I29e6f8c4194f4b52b48a187d1f5256b66a445619
parents b7a44240 0e934737
Loading
Loading
Loading
Loading
+95 −33
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.util.Log;

import androidx.annotation.Nullable;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -36,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,6 +60,7 @@ import javax.inject.Inject;
 */
public class NotificationLogger implements StateListener {
    private static final String TAG = "NotificationLogger";
    private static final boolean DEBUG = false;

    /** The minimum delay in ms between reports of notification visibility. */
    private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
@@ -79,7 +82,12 @@ public class NotificationLogger implements StateListener {
    private long mLastVisibilityReportUptimeMs;
    private NotificationListContainer mListContainer;
    private final Object mDozingLock = new Object();
    private boolean mDozing;
    @GuardedBy("mDozingLock")
    private Boolean mDozing = null;  // Use null to indicate state is not yet known
    @GuardedBy("mDozingLock")
    private Boolean mLockscreen = null;  // Use null to indicate state is not yet known
    private Boolean mPanelExpanded = null;  // Use null to indicate state is not yet known
    private boolean mLogging = false;

    protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
            new OnChildLocationsChangedListener() {
@@ -247,6 +255,11 @@ public class NotificationLogger implements StateListener {
    }

    public void stopNotificationLogging() {
        if (mLogging) {
            mLogging = false;
            if (DEBUG) {
                Log.i(TAG, "stopNotificationLogging: log notifications invisible");
            }
            // Report all notifications as invisible and turn down the
            // reporter.
            if (!mCurrentlyVisibleNotifications.isEmpty()) {
@@ -257,8 +270,14 @@ public class NotificationLogger implements StateListener {
            mHandler.removeCallbacks(mVisibilityReporter);
            mListContainer.setChildLocationsChangedListener(null);
        }
    }

    public void startNotificationLogging() {
        if (!mLogging) {
            mLogging = true;
            if (DEBUG) {
                Log.i(TAG, "startNotificationLogging");
            }
            mListContainer.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
            // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
            // cause the scroller to emit child location events. Hence generate
@@ -267,13 +286,13 @@ public class NotificationLogger implements StateListener {
            // (Note that in cases where the scroller does emit events, this
            // additional event doesn't break anything.)
            mNotificationLocationsChangedListener.onChildLocationsChanged();
        mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
                mEntryManager.getVisibleNotifications());
        }
    }

    private void setDozing(boolean dozing) {
        synchronized (mDozingLock) {
            mDozing = dozing;
            maybeUpdateLoggingStatus();
        }
    }

@@ -343,11 +362,6 @@ public class NotificationLogger implements StateListener {
                for (int i = 0; i < N; i++) {
                    newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
                }

                synchronized (mDozingLock) {
                    // setNotificationsShown should only be called if we are confident that
                    // the user has seen the notification, aka not when ambient display is on
                    if (!mDozing) {
                // TODO: Call NotificationEntryManager to do this, once it exists.
                // TODO: Consider not catching all runtime exceptions here.
                try {
@@ -356,8 +370,6 @@ public class NotificationLogger implements StateListener {
                    Log.d(TAG, "failed setNotificationsShown: ", e);
                }
            }
                }
            }
            recycleAllVisibilityObjects(newlyVisibleAr);
            recycleAllVisibilityObjects(noLongerVisibleAr);
        });
@@ -400,14 +412,64 @@ public class NotificationLogger implements StateListener {

    @Override
    public void onStateChanged(int newState) {
        // don't care about state change
        if (DEBUG) {
            Log.i(TAG, "onStateChanged: new=" + newState);
        }
        synchronized (mDozingLock) {
            mLockscreen = (newState == StatusBarState.KEYGUARD
                    || newState == StatusBarState.SHADE_LOCKED);
        }
    }

    @Override
    public void onDozingChanged(boolean isDozing) {
        if (DEBUG) {
            Log.i(TAG, "onDozingChanged: new=" + isDozing);
        }
        setDozing(isDozing);
    }

    @GuardedBy("mDozingLock")
    private void maybeUpdateLoggingStatus() {
        if (mPanelExpanded == null || mDozing == null) {
            if (DEBUG) {
                Log.i(TAG, "Panel status unclear: panelExpandedKnown="
                        + (mPanelExpanded == null) + " dozingKnown=" + (mDozing == null));
            }
            return;
        }
        // Once we know panelExpanded and Dozing, turn logging on & off when appropriate
        boolean lockscreen = mLockscreen == null ? false : mLockscreen;
        if (mPanelExpanded && !mDozing) {
            mNotificationPanelLogger.logPanelShown(lockscreen,
                    mEntryManager.getVisibleNotifications());
            if (DEBUG) {
                Log.i(TAG, "Notification panel shown, lockscreen=" + lockscreen);
            }
            startNotificationLogging();
        } else {
            if (DEBUG) {
                Log.i(TAG, "Notification panel hidden, lockscreen=" + lockscreen);
            }
            stopNotificationLogging();
        }
    }

    /**
     * Called by StatusBar to notify the logger that the panel expansion has changed.
     * The panel may be showing any of the normal notification panel, the AOD, or the bouncer.
     * @param isExpanded True if the panel is expanded.
     */
    public void onPanelExpandedChanged(boolean isExpanded) {
        if (DEBUG) {
            Log.i(TAG, "onPanelExpandedChanged: new=" + isExpanded);
        }
        mPanelExpanded = isExpanded;
        synchronized (mDozingLock) {
            maybeUpdateLoggingStatus();
        }
    }

    /**
     * Called when the notification is expanded / collapsed.
     */
+8 −6
Original line number Diff line number Diff line
@@ -1788,6 +1788,9 @@ public class StatusBar extends SystemUI implements DemoMode,
    }

    public void setPanelExpanded(boolean isExpanded) {
        if (mPanelExpanded != isExpanded) {
            mNotificationLogger.onPanelExpandedChanged(isExpanded);
        }
        mPanelExpanded = isExpanded;
        updateHideIconsForBouncer(false /* animate */);
        mNotificationShadeWindowController.setPanelExpanded(isExpanded);
@@ -2900,7 +2903,6 @@ public class StatusBar extends SystemUI implements DemoMode,
    }

    // Visibility reporting

    protected void handleVisibleToUserChanged(boolean visibleToUser) {
        if (visibleToUser) {
            handleVisibleToUserChangedImpl(visibleToUser);
@@ -2922,12 +2924,12 @@ public class StatusBar extends SystemUI implements DemoMode,
        }
    }

    /**
     * The LEDs are turned off when the notification panel is shown, even just a little bit.
     * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
     */
    private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
    // Visibility reporting

    void handleVisibleToUserChangedImpl(boolean visibleToUser) {
        if (visibleToUser) {
            /* The LEDs are turned off when the notification panel is shown, even just a little bit.
             * See also StatusBar.setPanelExpanded for another place where we attempt to do this. */
            boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
            boolean clearNotificationEffects =
                    !mPresenter.isPresenterFullyCollapsed() &&
+43 −6
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -42,6 +44,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -163,28 +166,61 @@ public class NotificationLoggerTest extends SysuiTestCase {
        mUiBgExecutor.runAllReady();
        Mockito.reset(mBarService);

        mLogger.stopNotificationLogging();
        setStateAsleep();
        mLogger.onDozingChanged(false);  // Wake to lockscreen
        mLogger.onDozingChanged(true);  // And go back to sleep, turning off logging
        mUiBgExecutor.runAllReady();
        // The visibility objects are recycled by NotificationLogger, so we can't use specific
        // matchers here.
        verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
    }

    private void setStateAsleep() {
        mLogger.onPanelExpandedChanged(true);
        mLogger.onDozingChanged(true);
        mLogger.onStateChanged(StatusBarState.KEYGUARD);
    }

    private void setStateAwake() {
        mLogger.onPanelExpandedChanged(false);
        mLogger.onDozingChanged(false);
        mLogger.onStateChanged(StatusBarState.SHADE);
    }

    @Test
    public void testLogPanelShownOnWake() {
        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
        setStateAsleep();
        mLogger.onDozingChanged(false);  // Wake to lockscreen
        assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
        assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
        assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
        Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
        assertEquals(TEST_PACKAGE_NAME, n.packageName);
        assertEquals(TEST_UID, n.uid);
        assertEquals(1, n.instanceId);
        assertFalse(n.isGroupSummary);
        assertEquals(1 + BUCKET_ALERTING, n.section);
    }

    @Test
    public void testLogPanelShownOnLoggingStart() {
    public void testLogPanelShownOnShadePull() {
        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
        mLogger.startNotificationLogging();
        setStateAwake();
        // Now expand panel
        mLogger.onPanelExpandedChanged(true);
        assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
        assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
        assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
        assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
        Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
        assertEquals(TEST_PACKAGE_NAME, n.packageName);
        assertEquals(TEST_UID, n.uid);
        assertEquals(1, n.instanceId);
        assertEquals(false, n.isGroupSummary);
        assertFalse(n.isGroupSummary);
        assertEquals(1 + BUCKET_ALERTING, n.section);
    }


    @Test
    public void testLogPanelShownHandlesNullInstanceIds() {
        // Construct a NotificationEntry like mEntry, but with a null instance id.
@@ -198,7 +234,8 @@ public class NotificationLoggerTest extends SysuiTestCase {
        entry.setRow(mRow);

        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
        mLogger.startNotificationLogging();
        setStateAsleep();
        mLogger.onDozingChanged(false);  // Wake to lockscreen
        assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
        assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
        Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];