Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +24 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; Loading @@ -42,6 +44,7 @@ import android.view.IPinnedStackListener; import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.IntDef; import androidx.annotation.MainThread; import com.android.internal.annotations.VisibleForTesting; Loading @@ -59,6 +62,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.phone.StatusBarWindowController; import java.lang.annotation.Retention; import javax.inject.Inject; import javax.inject.Singleton; Loading @@ -70,10 +75,22 @@ import javax.inject.Singleton; */ @Singleton public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener { private static final int MAX_BUBBLES = 5; // TODO: actually enforce this private static final String TAG = "BubbleController"; private static final int MAX_BUBBLES = 5; // TODO: actually enforce this @Retention(SOURCE) @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED, DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION}) @interface DismissReason {} static final int DISMISS_USER_GESTURE = 1; static final int DISMISS_AGED = 2; static final int DISMISS_TASK_FINISHED = 3; static final int DISMISS_BLOCKED = 4; static final int DISMISS_NOTIF_CANCEL = 5; static final int DISMISS_ACCESSIBILITY_ACTION = 6; // Enables some subset of notifs to automatically become bubbles private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false; Loading Loading @@ -248,11 +265,11 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe /** * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack. */ void dismissStack() { void dismissStack(@DismissReason int reason) { if (mStackView == null) { return; } mStackView.stackDismissed(); mStackView.stackDismissed(reason); updateVisibility(); mNotificationEntryManager.updateNotifications(); Loading Loading @@ -304,9 +321,9 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * Must be called from the main thread. */ @MainThread void removeBubble(String key) { void removeBubble(String key, int reason) { if (mStackView != null) { mStackView.removeBubble(key); mStackView.removeBubble(key, reason); } mNotificationEntryManager.updateNotifications(); updateVisibility(); Loading @@ -320,7 +337,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe boolean samePackage = entry.notification.getPackageName().equals( e.notification.getPackageName()); if (samePackage) { removeBubble(entry.key); removeBubble(entry.key, DISMISS_BLOCKED); } } } Loading Loading @@ -377,7 +394,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe } if (!removedByUser) { // This was a cancel so we should remove the bubble removeBubble(entry.key); removeBubble(entry.key, DISMISS_NOTIF_CANCEL); } } }; Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +2 −1 Original line number Diff line number Diff line Loading @@ -135,7 +135,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList public void onTaskRemovalStarted(int taskId) { if (mEntry != null) { // Must post because this is called from a binder thread. post(() -> mBubbleController.removeBubble(mEntry.key)); post(() -> mBubbleController.removeBubble(mEntry.key, BubbleController.DISMISS_TASK_FINISHED)); } } }; Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +47 −12 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.systemui.bubbles; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; Loading Loading @@ -49,6 +51,7 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.ViewClippingUtil; import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController.DismissReason; import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; import com.android.systemui.bubbles.animation.StackAnimationController; Loading @@ -62,6 +65,7 @@ import java.math.RoundingMode; */ public class BubbleStackView extends FrameLayout { private static final String TAG = "BubbleStackView"; private static final boolean DEBUG = false; private Point mDisplaySize; Loading Loading @@ -232,7 +236,7 @@ public class BubbleStackView extends FrameLayout { } switch (action) { case AccessibilityNodeInfo.ACTION_DISMISS: stackDismissed(); stackDismissed(BubbleController.DISMISS_ACCESSIBILITY_ACTION); return true; case AccessibilityNodeInfo.ACTION_COLLAPSE: collapseStack(); Loading Loading @@ -356,18 +360,12 @@ public class BubbleStackView extends FrameLayout { /** * Remove a bubble from the stack. */ public void removeBubble(String key) { public void removeBubble(String key, int reason) { Bubble b = mBubbleData.removeBubble(key); if (b == null) { return; } b.entry.setBubbleDismissed(true); // Remove it from the views int removedIndex = mBubbleContainer.indexOfChild(b.iconView); b.expandedView.cleanUpExpandedState(); mBubbleContainer.removeView(b.iconView); int removedIndex = dismissBubble(b, reason); int bubbleCount = mBubbleContainer.getChildCount(); if (bubbleCount == 0) { // If no bubbles remain, collapse the entire stack. Loading @@ -385,25 +383,62 @@ public class BubbleStackView extends FrameLayout { mExpandedBubble = null; } } // TODO: consider logging reason code logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); } /** * Dismiss the stack of bubbles. */ public void stackDismissed() { public void stackDismissed(int reason) { for (Bubble bubble : mBubbleData.getBubbles()) { bubble.entry.setBubbleDismissed(true); bubble.expandedView.cleanUpExpandedState(); dismissBubble(bubble, reason); } mBubbleData.clear(); collapseStack(); mBubbleContainer.removeAllViews(); mExpandedViewContainer.removeAllViews(); // TODO: consider logging reason code logBubbleEvent(null /* no bubble associated with bubble stack dismiss */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED); } /** * Marks the notification entry as dismissed, cleans up Bubble icon and expanded view UI * elements and calls deleteIntent if necessary. * * <p>Note: This does not remove the Bubble from BubbleData. * * @param bubble the Bubble being dismissed * @param reason code for the reason the dismiss was triggered * @see BubbleController.DismissReason */ private int dismissBubble(Bubble bubble, @DismissReason int reason) { if (DEBUG) { Log.d(TAG, "dismissBubble: " + bubble + " reason=" + reason); } bubble.entry.setBubbleDismissed(true); bubble.expandedView.cleanUpExpandedState(); // Remove it from the views int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView); mBubbleContainer.removeViewAt(removedIndex); if (reason == BubbleController.DISMISS_USER_GESTURE) { Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata(); PendingIntent deleteIntent = bubbleMetadata.getDeleteIntent(); if (deleteIntent != null) { try { deleteIntent.send(); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Failed to send delete intent for bubble with key: " + (bubble.entry != null ? bubble.entry.key : " null entry")); } } } return removedIndex; } /** * Updates a bubble in the stack. * Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +3 −2 Original line number Diff line number Diff line Loading @@ -140,7 +140,7 @@ class BubbleTouchHandler implements View.OnTouchListener { case MotionEvent.ACTION_UP: trackMovement(event); if (mInDismissTarget && isStack) { mController.dismissStack(); mController.dismissStack(BubbleController.DISMISS_USER_GESTURE); } else if (mMovedEnough) { mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000); final float velX = mVelocityTracker.getXVelocity(); Loading @@ -152,7 +152,8 @@ class BubbleTouchHandler implements View.OnTouchListener { mStack.onBubbleDragFinish( mTouchedView, viewX, viewY, velX, velY, /* dismissed */ dismissed); if (dismissed) { mController.removeBubble(((BubbleView) mTouchedView).getKey()); mController.removeBubble(((BubbleView) mTouchedView).getKey(), BubbleController.DISMISS_USER_GESTURE); } } } else if (mTouchedView == mStack.getExpandedBubbleView()) { Loading packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +37 −8 Original line number Diff line number Diff line Loading @@ -20,10 +20,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.PendingIntent; import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading Loading @@ -83,6 +86,9 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private BubbleController.BubbleExpandListener mBubbleExpandListener; @Mock private PendingIntent mDeleteIntent; private BubbleData mBubbleData; @Before Loading @@ -98,9 +104,9 @@ public class BubbleControllerTest extends SysuiTestCase { // Need notifications for bubbles mNotificationTestHelper = new NotificationTestHelper(mContext); mRow = mNotificationTestHelper.createBubble(); mRow2 = mNotificationTestHelper.createBubble(); mNoChannelRow = mNotificationTestHelper.createBubble(); mRow = mNotificationTestHelper.createBubble(mDeleteIntent); mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent); mNoChannelRow = mNotificationTestHelper.createBubble(mDeleteIntent); // Return non-null notification data from the NEM when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); Loading Loading @@ -141,11 +147,10 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mBubbleStateChangeListener).onHasBubblesChanged(true); mBubbleController.removeBubble(mRow.getEntry().key); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE); assertFalse(mStatusBarWindowController.getBubblesShowing()); assertTrue(mRow.getEntry().isBubbleDismissed()); verify(mNotificationEntryManager).updateNotifications(); verify(mBubbleStateChangeListener).onHasBubblesChanged(false); } Loading @@ -155,7 +160,7 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */); assertTrue(mBubbleController.hasBubbles()); mBubbleController.dismissStack(); mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); assertFalse(mStatusBarWindowController.getBubblesShowing()); verify(mNotificationEntryManager).updateNotifications(); assertTrue(mRow.getEntry().isBubbleDismissed()); Loading Loading @@ -271,7 +276,8 @@ public class BubbleControllerTest extends SysuiTestCase { assertFalse(mRow2.getEntry().showInShadeWhenBubble()); // Dismiss currently expanded mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey()); mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(), BubbleController.DISMISS_USER_GESTURE); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); // Make sure next bubble is selected Loading @@ -279,7 +285,8 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); // Dismiss that one mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey()); mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(), BubbleController.DISMISS_USER_GESTURE); // Make sure state changes and collapse happens verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); Loading @@ -299,6 +306,28 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mRow.getEntry().showInShadeWhenBubble()); } @Test public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_AGED); verify(mDeleteIntent, never()).send(); } @Test public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(1)).send(); } @Test public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */); mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(2)).send(); } static class TestableBubbleController extends BubbleController { TestableBubbleController(Context context, Loading Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +24 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; Loading @@ -42,6 +44,7 @@ import android.view.IPinnedStackListener; import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.IntDef; import androidx.annotation.MainThread; import com.android.internal.annotations.VisibleForTesting; Loading @@ -59,6 +62,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; import com.android.systemui.statusbar.phone.StatusBarWindowController; import java.lang.annotation.Retention; import javax.inject.Inject; import javax.inject.Singleton; Loading @@ -70,10 +75,22 @@ import javax.inject.Singleton; */ @Singleton public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener { private static final int MAX_BUBBLES = 5; // TODO: actually enforce this private static final String TAG = "BubbleController"; private static final int MAX_BUBBLES = 5; // TODO: actually enforce this @Retention(SOURCE) @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED, DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION}) @interface DismissReason {} static final int DISMISS_USER_GESTURE = 1; static final int DISMISS_AGED = 2; static final int DISMISS_TASK_FINISHED = 3; static final int DISMISS_BLOCKED = 4; static final int DISMISS_NOTIF_CANCEL = 5; static final int DISMISS_ACCESSIBILITY_ACTION = 6; // Enables some subset of notifs to automatically become bubbles private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false; Loading Loading @@ -248,11 +265,11 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe /** * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack. */ void dismissStack() { void dismissStack(@DismissReason int reason) { if (mStackView == null) { return; } mStackView.stackDismissed(); mStackView.stackDismissed(reason); updateVisibility(); mNotificationEntryManager.updateNotifications(); Loading Loading @@ -304,9 +321,9 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * Must be called from the main thread. */ @MainThread void removeBubble(String key) { void removeBubble(String key, int reason) { if (mStackView != null) { mStackView.removeBubble(key); mStackView.removeBubble(key, reason); } mNotificationEntryManager.updateNotifications(); updateVisibility(); Loading @@ -320,7 +337,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe boolean samePackage = entry.notification.getPackageName().equals( e.notification.getPackageName()); if (samePackage) { removeBubble(entry.key); removeBubble(entry.key, DISMISS_BLOCKED); } } } Loading Loading @@ -377,7 +394,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe } if (!removedByUser) { // This was a cancel so we should remove the bubble removeBubble(entry.key); removeBubble(entry.key, DISMISS_NOTIF_CANCEL); } } }; Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +2 −1 Original line number Diff line number Diff line Loading @@ -135,7 +135,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList public void onTaskRemovalStarted(int taskId) { if (mEntry != null) { // Must post because this is called from a binder thread. post(() -> mBubbleController.removeBubble(mEntry.key)); post(() -> mBubbleController.removeBubble(mEntry.key, BubbleController.DISMISS_TASK_FINISHED)); } } }; Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +47 −12 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.systemui.bubbles; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; Loading Loading @@ -49,6 +51,7 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.ViewClippingUtil; import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController.DismissReason; import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; import com.android.systemui.bubbles.animation.StackAnimationController; Loading @@ -62,6 +65,7 @@ import java.math.RoundingMode; */ public class BubbleStackView extends FrameLayout { private static final String TAG = "BubbleStackView"; private static final boolean DEBUG = false; private Point mDisplaySize; Loading Loading @@ -232,7 +236,7 @@ public class BubbleStackView extends FrameLayout { } switch (action) { case AccessibilityNodeInfo.ACTION_DISMISS: stackDismissed(); stackDismissed(BubbleController.DISMISS_ACCESSIBILITY_ACTION); return true; case AccessibilityNodeInfo.ACTION_COLLAPSE: collapseStack(); Loading Loading @@ -356,18 +360,12 @@ public class BubbleStackView extends FrameLayout { /** * Remove a bubble from the stack. */ public void removeBubble(String key) { public void removeBubble(String key, int reason) { Bubble b = mBubbleData.removeBubble(key); if (b == null) { return; } b.entry.setBubbleDismissed(true); // Remove it from the views int removedIndex = mBubbleContainer.indexOfChild(b.iconView); b.expandedView.cleanUpExpandedState(); mBubbleContainer.removeView(b.iconView); int removedIndex = dismissBubble(b, reason); int bubbleCount = mBubbleContainer.getChildCount(); if (bubbleCount == 0) { // If no bubbles remain, collapse the entire stack. Loading @@ -385,25 +383,62 @@ public class BubbleStackView extends FrameLayout { mExpandedBubble = null; } } // TODO: consider logging reason code logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); } /** * Dismiss the stack of bubbles. */ public void stackDismissed() { public void stackDismissed(int reason) { for (Bubble bubble : mBubbleData.getBubbles()) { bubble.entry.setBubbleDismissed(true); bubble.expandedView.cleanUpExpandedState(); dismissBubble(bubble, reason); } mBubbleData.clear(); collapseStack(); mBubbleContainer.removeAllViews(); mExpandedViewContainer.removeAllViews(); // TODO: consider logging reason code logBubbleEvent(null /* no bubble associated with bubble stack dismiss */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED); } /** * Marks the notification entry as dismissed, cleans up Bubble icon and expanded view UI * elements and calls deleteIntent if necessary. * * <p>Note: This does not remove the Bubble from BubbleData. * * @param bubble the Bubble being dismissed * @param reason code for the reason the dismiss was triggered * @see BubbleController.DismissReason */ private int dismissBubble(Bubble bubble, @DismissReason int reason) { if (DEBUG) { Log.d(TAG, "dismissBubble: " + bubble + " reason=" + reason); } bubble.entry.setBubbleDismissed(true); bubble.expandedView.cleanUpExpandedState(); // Remove it from the views int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView); mBubbleContainer.removeViewAt(removedIndex); if (reason == BubbleController.DISMISS_USER_GESTURE) { Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata(); PendingIntent deleteIntent = bubbleMetadata.getDeleteIntent(); if (deleteIntent != null) { try { deleteIntent.send(); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Failed to send delete intent for bubble with key: " + (bubble.entry != null ? bubble.entry.key : " null entry")); } } } return removedIndex; } /** * Updates a bubble in the stack. * Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +3 −2 Original line number Diff line number Diff line Loading @@ -140,7 +140,7 @@ class BubbleTouchHandler implements View.OnTouchListener { case MotionEvent.ACTION_UP: trackMovement(event); if (mInDismissTarget && isStack) { mController.dismissStack(); mController.dismissStack(BubbleController.DISMISS_USER_GESTURE); } else if (mMovedEnough) { mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000); final float velX = mVelocityTracker.getXVelocity(); Loading @@ -152,7 +152,8 @@ class BubbleTouchHandler implements View.OnTouchListener { mStack.onBubbleDragFinish( mTouchedView, viewX, viewY, velX, velY, /* dismissed */ dismissed); if (dismissed) { mController.removeBubble(((BubbleView) mTouchedView).getKey()); mController.removeBubble(((BubbleView) mTouchedView).getKey(), BubbleController.DISMISS_USER_GESTURE); } } } else if (mTouchedView == mStack.getExpandedBubbleView()) { Loading
packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +37 −8 Original line number Diff line number Diff line Loading @@ -20,10 +20,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.PendingIntent; import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading Loading @@ -83,6 +86,9 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private BubbleController.BubbleExpandListener mBubbleExpandListener; @Mock private PendingIntent mDeleteIntent; private BubbleData mBubbleData; @Before Loading @@ -98,9 +104,9 @@ public class BubbleControllerTest extends SysuiTestCase { // Need notifications for bubbles mNotificationTestHelper = new NotificationTestHelper(mContext); mRow = mNotificationTestHelper.createBubble(); mRow2 = mNotificationTestHelper.createBubble(); mNoChannelRow = mNotificationTestHelper.createBubble(); mRow = mNotificationTestHelper.createBubble(mDeleteIntent); mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent); mNoChannelRow = mNotificationTestHelper.createBubble(mDeleteIntent); // Return non-null notification data from the NEM when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); Loading Loading @@ -141,11 +147,10 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mBubbleStateChangeListener).onHasBubblesChanged(true); mBubbleController.removeBubble(mRow.getEntry().key); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE); assertFalse(mStatusBarWindowController.getBubblesShowing()); assertTrue(mRow.getEntry().isBubbleDismissed()); verify(mNotificationEntryManager).updateNotifications(); verify(mBubbleStateChangeListener).onHasBubblesChanged(false); } Loading @@ -155,7 +160,7 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */); assertTrue(mBubbleController.hasBubbles()); mBubbleController.dismissStack(); mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); assertFalse(mStatusBarWindowController.getBubblesShowing()); verify(mNotificationEntryManager).updateNotifications(); assertTrue(mRow.getEntry().isBubbleDismissed()); Loading Loading @@ -271,7 +276,8 @@ public class BubbleControllerTest extends SysuiTestCase { assertFalse(mRow2.getEntry().showInShadeWhenBubble()); // Dismiss currently expanded mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey()); mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(), BubbleController.DISMISS_USER_GESTURE); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key); // Make sure next bubble is selected Loading @@ -279,7 +285,8 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key); // Dismiss that one mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey()); mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(), BubbleController.DISMISS_USER_GESTURE); // Make sure state changes and collapse happens verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key); Loading @@ -299,6 +306,28 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mRow.getEntry().showInShadeWhenBubble()); } @Test public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_AGED); verify(mDeleteIntent, never()).send(); } @Test public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(1)).send(); } @Test public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */); mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(2)).send(); } static class TestableBubbleController extends BubbleController { TestableBubbleController(Context context, Loading