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

Commit 01e3821a authored by Ned Burns's avatar Ned Burns
Browse files

Invert BubbleController <-> NEM dependency

Test: atest
Change-Id: I35b9dfbead7c623a6d0321943570c6115cf7eb5e
parent 6976087e
Loading
Loading
Loading
Loading
+38 −40
Original line number Diff line number Diff line
@@ -33,8 +33,11 @@ import android.view.WindowManager;
import android.widget.FrameLayout;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.StatusBarWindowController;

import java.util.ArrayList;
@@ -57,46 +60,30 @@ public class BubbleController {
    private static final String TAG = "BubbleController";

    // Enables some subset of notifs to automatically become bubbles
    public static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
    private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
    // When a bubble is dismissed, recreate it as a notification
    public static final boolean DEBUG_DEMOTE_TO_NOTIF = false;
    private static final boolean DEBUG_DEMOTE_TO_NOTIF = false;

    // Secure settings
    private static final String ENABLE_AUTO_BUBBLE_MESSAGES = "experiment_autobubble_messaging";
    private static final String ENABLE_AUTO_BUBBLE_ONGOING = "experiment_autobubble_ongoing";
    private static final String ENABLE_AUTO_BUBBLE_ALL = "experiment_autobubble_all";

    private Context mContext;
    private BubbleDismissListener mDismissListener;
    private final Context mContext;
    private final NotificationEntryManager mNotificationEntryManager;
    private BubbleStateChangeListener mStateChangeListener;
    private BubbleExpandListener mExpandListener;

    private Map<String, BubbleView> mBubbles = new HashMap<>();
    private final Map<String, BubbleView> mBubbles = new HashMap<>();
    private BubbleStackView mStackView;
    private Point mDisplaySize;
    private final Point mDisplaySize;

    // Bubbles get added to the status bar view
    @VisibleForTesting
    protected StatusBarWindowController mStatusBarWindowController;
    private final StatusBarWindowController mStatusBarWindowController;

    // Used for determining view rect for touch interaction
    private Rect mTempRect = new Rect();

    /**
     * Listener to find out about bubble / bubble stack dismissal events.
     */
    public interface BubbleDismissListener {
        /**
         * Called when the entire stack of bubbles is dismissed by the user.
         */
        void onStackDismissed();

        /**
         * Called when a specific bubble is dismissed by the user.
         */
        void onBubbleDismissed(String key);
    }

    /**
     * Listener to be notified when some states of the bubbles change.
     */
@@ -123,17 +110,13 @@ public class BubbleController {
    @Inject
    public BubbleController(Context context, StatusBarWindowController statusBarWindowController) {
        mContext = context;
        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mDisplaySize = new Point();
        wm.getDefaultDisplay().getSize(mDisplaySize);
        mStatusBarWindowController = statusBarWindowController;
    }

    /**
     * Set a listener to be notified of bubble dismissal events.
     */
    public void setDismissListener(BubbleDismissListener listener) {
        mDismissListener = listener;
        mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
    }

    /**
@@ -180,7 +163,7 @@ public class BubbleController {
    /**
     * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack.
     */
    public void dismissStack() {
    void dismissStack() {
        if (mStackView == null) {
            return;
        }
@@ -190,9 +173,7 @@ public class BubbleController {
        for (String key: mBubbles.keySet()) {
            removeBubble(key);
        }
        if (mDismissListener != null) {
            mDismissListener.onStackDismissed();
        }
        mNotificationEntryManager.updateNotifications();
        updateBubblesShowing();
    }

@@ -238,18 +219,35 @@ public class BubbleController {
    /**
     * Removes the bubble associated with the {@param uri}.
     */
    public void removeBubble(String key) {
    void removeBubble(String key) {
        BubbleView bv = mBubbles.get(key);
        if (mStackView != null && bv != null) {
            mStackView.removeBubble(bv);
            bv.getEntry().setBubbleDismissed(true);
        }
        if (mDismissListener != null) {
            mDismissListener.onBubbleDismissed(key);

        NotificationData.Entry entry = mNotificationEntryManager.getNotificationData().get(key);
        if (entry != null) {
            entry.setBubbleDismissed(true);
            if (!DEBUG_DEMOTE_TO_NOTIF) {
                mNotificationEntryManager.performRemoveNotification(entry.notification);
            }
        }
        mNotificationEntryManager.updateNotifications();

        updateBubblesShowing();
    }

    @SuppressWarnings("FieldCanBeLocal")
    private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
        @Override
        public void onPendingEntryAdded(NotificationData.Entry entry) {
            if (shouldAutoBubble(mContext, entry)) {
                entry.setIsBubble(true);
            }
        }
    };

    private void updateBubblesShowing() {
        boolean hasBubblesShowing = false;
        for (BubbleView bv : mBubbles.values()) {
@@ -309,7 +307,7 @@ public class BubbleController {
    }

    @VisibleForTesting
    public BubbleStackView getStackView() {
    BubbleStackView getStackView() {
        return mStackView;
    }

@@ -317,7 +315,7 @@ public class BubbleController {
    /**
     * Gets an appropriate starting point to position the bubble stack.
     */
    public static Point getStartPoint(int size, Point displaySize) {
    private static Point getStartPoint(int size, Point displaySize) {
        final int x = displaySize.x - size + EDGE_OVERLAP;
        final int y = displaySize.y / 4;
        return new Point(x, y);
@@ -326,7 +324,7 @@ public class BubbleController {
    /**
     * Gets an appropriate position for the bubble when the stack is expanded.
     */
    public static Point getExpandPoint(BubbleStackView view, int size, Point displaySize) {
    static Point getExpandPoint(BubbleStackView view, int size, Point displaySize) {
        // Same place for now..
        return new Point(EDGE_OVERLAP, size);
    }
@@ -334,7 +332,7 @@ public class BubbleController {
    /**
     * Whether the notification should bubble or not.
     */
    public static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
    private static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
        if (entry.isBubbleDismissed()) {
            return false;
        }
+1 −27
Original line number Diff line number Diff line
@@ -15,8 +15,6 @@
 */
package com.android.systemui.statusbar.notification;

import static com.android.systemui.bubbles.BubbleController.DEBUG_DEMOTE_TO_NOTIF;

import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
@@ -33,7 +31,6 @@ import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -64,8 +61,7 @@ public class NotificationEntryManager implements
        Dumpable,
        NotificationInflater.InflationCallback,
        NotificationUpdateHandler,
        VisualStabilityManager.Callback,
        BubbleController.BubbleDismissListener {
        VisualStabilityManager.Callback {
    private static final String TAG = "NotificationEntryMgr";
    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

@@ -80,7 +76,6 @@ public class NotificationEntryManager implements
            Dependency.get(DeviceProvisionedController.class);
    private final ForegroundServiceController mForegroundServiceController =
            Dependency.get(ForegroundServiceController.class);
    private final BubbleController mBubbleController = Dependency.get(BubbleController.class);

    // Lazily retrieved dependencies
    private NotificationRemoteInputManager mRemoteInputManager;
@@ -126,7 +121,6 @@ public class NotificationEntryManager implements

    public NotificationEntryManager(Context context) {
        mContext = context;
        mBubbleController.setDismissListener(this /* bubbleEventListener */);
        mNotificationData = new NotificationData();
        mDeferredNotificationViewUpdateHandler = new Handler();
    }
@@ -209,23 +203,6 @@ public class NotificationEntryManager implements
                n.getKey(), null, nv, false /* forceRemove */, true /* removedByUser */);
    }

    @Override
    public void onStackDismissed() {
        updateNotifications();
    }

    @Override
    public void onBubbleDismissed(String key) {
        NotificationData.Entry entry = mNotificationData.get(key);
        if (entry != null) {
            entry.setBubbleDismissed(true);
            if (!DEBUG_DEMOTE_TO_NOTIF) {
                performRemoveNotification(entry.notification);
            }
        }
        updateNotifications();
    }

    private void abortExistingInflation(String key) {
        if (mPendingNotifications.containsKey(key)) {
            NotificationData.Entry entry = mPendingNotifications.get(key);
@@ -416,9 +393,6 @@ public class NotificationEntryManager implements
        rankingMap.getRanking(key, ranking);

        NotificationData.Entry entry = new NotificationData.Entry(notification, ranking);
        if (BubbleController.shouldAutoBubble(getContext(), entry)) {
            entry.setIsBubble(true);
        }

        Dependency.get(LeakDetector.class).trackInstance(entry);
        // Construct the expanded view.
+34 −0
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@ package com.android.systemui.bubbles;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.IActivityManager;
import android.content.Context;
@@ -29,6 +33,9 @@ import android.widget.FrameLayout;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
@@ -36,6 +43,8 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -44,6 +53,8 @@ import org.mockito.MockitoAnnotations;
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BubbleControllerTest extends SysuiTestCase {

    @Mock
    private NotificationEntryManager mNotificationEntryManager;
    @Mock
    private WindowManager mWindowManager;
    @Mock
@@ -52,17 +63,23 @@ public class BubbleControllerTest extends SysuiTestCase {
    private DozeParameters mDozeParameters;
    @Mock
    private FrameLayout mStatusBarView;
    @Captor
    private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;

    private TestableBubbleController mBubbleController;
    private StatusBarWindowController mStatusBarWindowController;
    private NotificationEntryListener mEntryListener;

    private NotificationTestHelper mNotificationTestHelper;
    private ExpandableNotificationRow mRow;
    private ExpandableNotificationRow mRow2;

    private final NotificationData mNotificationData = new NotificationData();

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);

        // Bubbles get added to status bar window view
        mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
@@ -74,7 +91,15 @@ public class BubbleControllerTest extends SysuiTestCase {
        mRow = mNotificationTestHelper.createBubble();
        mRow2 = mNotificationTestHelper.createBubble();

        // Return non-null notification data from the NEM
        when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);

        mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController);

        // Get a reference to the BubbleController's entry listener
        verify(mNotificationEntryManager, atLeastOnce())
                .addNotificationEntryListener(mEntryListenerCaptor.capture());
        mEntryListener = mEntryListenerCaptor.getValue();
    }

    @Test
@@ -102,6 +127,8 @@ public class BubbleControllerTest extends SysuiTestCase {

        mBubbleController.removeBubble(mRow.getEntry().key);
        assertFalse(mStatusBarWindowController.getBubblesShowing());
        assertTrue(mRow.getEntry().isBubbleDismissed());
        verify(mNotificationEntryManager).updateNotifications();
    }

    @Test
@@ -112,6 +139,7 @@ public class BubbleControllerTest extends SysuiTestCase {

        mBubbleController.dismissStack();
        assertFalse(mStatusBarWindowController.getBubblesShowing());
        verify(mNotificationEntryManager, times(3)).updateNotifications();
    }

    @Test
@@ -140,6 +168,12 @@ public class BubbleControllerTest extends SysuiTestCase {
        assertFalse(mBubbleController.isStackExpanded());
    }

    @Test
    public void testMarkNewNotificationAsBubble() {
        mEntryListener.onPendingEntryAdded(mRow.getEntry());
        assertTrue(mRow.getEntry().isBubble());
    }

    static class TestableBubbleController extends BubbleController {

        TestableBubbleController(Context context,
+3 −1
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
    @Mock private ShadeController mShadeController;

    private NotificationViewHierarchyManager mViewHierarchyManager;
    private NotificationTestHelper mHelper = new NotificationTestHelper(mContext);
    private NotificationTestHelper mHelper;

    @Before
    public void setUp() {
@@ -90,6 +90,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
        mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
        mDependency.injectTestDependency(ShadeController.class, mShadeController);

        mHelper = new NotificationTestHelper(mContext);

        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);

        mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,