diff options
| author | 2020-05-21 00:25:11 +0000 | |
|---|---|---|
| committer | 2020-05-21 00:25:11 +0000 | |
| commit | e7b00f678c53cc8b2ce59d87c016c530113ad2f2 (patch) | |
| tree | 6500cad8decd83a0e306ed208e815901f1ebbfa8 | |
| parent | 1de6b7ed7310132e0e8445ccbcb0659a3f00fc83 (diff) | |
| parent | 4395bbdd29ad58ffdbb36e198759e2d37e78cb20 (diff) | |
Merge "Remove Bubbles from the WM, only after all bubbles finish animating out." into rvc-dev
6 files changed, 132 insertions, 44 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index a578f337cca2..2587369cf0f5 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -185,9 +185,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // Used to post to main UI thread private Handler mHandler = new Handler(); - /** LayoutParams used to add the BubbleStackView to the window maanger. */ + /** LayoutParams used to add the BubbleStackView to the window manager. */ private WindowManager.LayoutParams mWmLayoutParams; - + /** Whether or not the BubbleStackView has been added to the WindowManager. */ + private boolean mAddedToWindowManager = false; // Used for determining view rect for touch interaction private Rect mTempRect = new Rect(); @@ -595,9 +596,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (mStackView == null) { mStackView = new BubbleStackView( mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator, - mSysUiState, mNotificationShadeWindowController); + mSysUiState, mNotificationShadeWindowController, this::onAllBubblesAnimatedOut); mStackView.addView(mBubbleScrim); - addToWindowManager(); if (mExpandListener != null) { mStackView.setExpandListener(mExpandListener); } @@ -605,10 +605,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mStackView.setUnbubbleConversationCallback(notificationEntry -> onUserChangedBubble(notificationEntry, false /* shouldBubble */)); } + + addToWindowManagerMaybe(); } - /** Adds the BubbleStackView to the WindowManager. */ - private void addToWindowManager() { + /** Adds the BubbleStackView to the WindowManager if it's not already there. */ + private void addToWindowManagerMaybe() { + // If the stack is null, or already added, don't add it. + if (mStackView == null || mAddedToWindowManager) { + return; + } + mWmLayoutParams = new WindowManager.LayoutParams( // Fill the screen so we can use translation animations to position the bubble // stack. We'll use touchable regions to ignore touches that are not on the bubbles @@ -629,9 +636,37 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mWmLayoutParams.packageName = mContext.getPackageName(); mWmLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mWindowManager.addView(mStackView, mWmLayoutParams); + try { + mAddedToWindowManager = true; + mWindowManager.addView(mStackView, mWmLayoutParams); + } catch (IllegalStateException e) { + // This means the stack has already been added. This shouldn't happen, since we keep + // track of that, but just in case, update the previously added view's layout params. + e.printStackTrace(); + updateWmFlags(); + } + } + + /** Removes the BubbleStackView from the WindowManager if it's there. */ + private void removeFromWindowManagerMaybe() { + if (!mAddedToWindowManager) { + return; + } + + try { + mAddedToWindowManager = false; + mWindowManager.removeView(mStackView); + } catch (IllegalArgumentException e) { + // This means the stack has already been removed - it shouldn't happen, but ignore if it + // does, since we wanted it removed anyway. + e.printStackTrace(); + } } + /** + * Updates the BubbleStackView's WindowManager.LayoutParams, and updates the WindowManager with + * the new params if the stack has been added. + */ private void updateWmFlags() { if (isStackExpanded()) { // If we're expanded, we want to be focusable so that the ActivityView can receive focus @@ -643,7 +678,25 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; } - mWindowManager.updateViewLayout(mStackView, mWmLayoutParams); + if (mStackView != null && mAddedToWindowManager) { + try { + mWindowManager.updateViewLayout(mStackView, mWmLayoutParams); + } catch (IllegalArgumentException e) { + // If the stack is somehow not there, ignore the attempt to update it. + e.printStackTrace(); + } + } + } + + /** + * Called by the BubbleStackView and whenever all bubbles have animated out, and none have been + * added in the meantime. + */ + private void onAllBubblesAnimatedOut() { + if (mStackView != null) { + mStackView.setVisibility(INVISIBLE); + removeFromWindowManagerMaybe(); + } } /** @@ -833,10 +886,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) { - if (mStackView == null) { - // Lazy init stack view when a bubble is created - ensureStackViewCreated(); - } + // Lazy init stack view when a bubble is created + ensureStackViewCreated(); + // If this is an interruptive notif, mark that it's interrupted if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) { notif.setInterruption(); @@ -1196,11 +1248,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (mStackView == null) { return; } - if (mStatusBarStateListener.getCurrentState() == SHADE && hasBubbles()) { - // Bubbles only appear in unlocked shade - mStackView.setVisibility(hasBubbles() ? VISIBLE : INVISIBLE); - } else if (mStackView != null) { + + if (mStatusBarStateListener.getCurrentState() != SHADE) { + // Bubbles don't appear over the locked shade. mStackView.setVisibility(INVISIBLE); + } else if (hasBubbles()) { + // If we're unlocked, show the stack if we have bubbles. If we don't have bubbles, the + // stack will be set to INVISIBLE in onAllBubblesAnimatedOut after the bubbles animate + // out. + mStackView.setVisibility(VISIBLE); } mStackView.updateContentDescription(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 88f5eb0b250c..c97ca2b9d8f8 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -656,7 +656,8 @@ public class BubbleStackView extends FrameLayout @Nullable SurfaceSynchronizer synchronizer, FloatingContentCoordinator floatingContentCoordinator, SysUiState sysUiState, - NotificationShadeWindowController notificationShadeWindowController) { + NotificationShadeWindowController notificationShadeWindowController, + Runnable allBubblesAnimatedOutAction) { super(context); mBubbleData = data; @@ -691,11 +692,18 @@ public class BubbleStackView extends FrameLayout mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding); int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); + final Runnable onBubbleAnimatedOut = () -> { + if (getBubbleCount() == 0) { + allBubblesAnimatedOutAction.run(); + } + }; + mStackAnimationController = new StackAnimationController( - floatingContentCoordinator, this::getBubbleCount); + floatingContentCoordinator, this::getBubbleCount, onBubbleAnimatedOut); mExpandedAnimationController = new ExpandedAnimationController( - mDisplaySize, mExpandedViewPadding, res.getConfiguration().orientation); + mDisplaySize, mExpandedViewPadding, res.getConfiguration().orientation, + onBubbleAnimatedOut); mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER; setUpUserEducation(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java index f57cf42ce4ff..76ff1afef3f7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java @@ -32,6 +32,7 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.util.animation.PhysicsAnimator; import com.android.systemui.util.magnetictarget.MagnetizedObject; import com.google.android.collect.Sets; @@ -69,6 +70,10 @@ public class ExpandedAnimationController */ private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f; + private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfig = + new PhysicsAnimator.SpringConfig( + EXPAND_COLLAPSE_ANIM_STIFFNESS, SpringForce.DAMPING_RATIO_NO_BOUNCY); + /** Horizontal offset between bubbles, which we need to know to re-stack them. */ private float mStackOffsetPx; /** Space between status bar and bubbles in the expanded state. */ @@ -116,10 +121,17 @@ public class ExpandedAnimationController private int mExpandedViewPadding; + /** + * Callback to run whenever any bubble is animated out. The BubbleStackView will check if the + * end of this animation means we have no bubbles left, and notify the BubbleController. + */ + private Runnable mOnBubbleAnimatedOutAction; + public ExpandedAnimationController(Point displaySize, int expandedViewPadding, - int orientation) { + int orientation, Runnable onBubbleAnimatedOutAction) { updateResources(orientation, displaySize); mExpandedViewPadding = expandedViewPadding; + mOnBubbleAnimatedOutAction = onBubbleAnimatedOutAction; } /** @@ -355,8 +367,8 @@ public class ExpandedAnimationController } animationForChild(bubble) .withStiffness(SpringForce.STIFFNESS_HIGH) - .scaleX(1.1f) - .scaleY(1.1f) + .scaleX(0f) + .scaleY(0f) .translationY(bubble.getTranslationY() + translationYBy) .alpha(0f, after) .start(); @@ -500,18 +512,17 @@ public class ExpandedAnimationController @Override void onChildRemoved(View child, int index, Runnable finishRemoval) { - final PhysicsAnimationLayout.PhysicsPropertyAnimator animator = animationForChild(child); - // If we're removing the dragged-out bubble, that means it got dismissed. if (child.equals(getDraggedOutBubble())) { mMagnetizedBubbleDraggingOut = null; finishRemoval.run(); + mOnBubbleAnimatedOutAction.run(); } else { - animator.alpha(0f, finishRemoval /* endAction */) - .withStiffness(SpringForce.STIFFNESS_HIGH) - .withDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) - .scaleX(1.1f) - .scaleY(1.1f) + PhysicsAnimator.getInstance(child) + .spring(DynamicAnimation.ALPHA, 0f) + .spring(DynamicAnimation.SCALE_X, 0f, mAnimateOutSpringConfig) + .spring(DynamicAnimation.SCALE_Y, 0f, mAnimateOutSpringConfig) + .withEndActions(finishRemoval, mOnBubbleAnimatedOutAction) .start(); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index 2cfe1dde0b51..8318c21ad4cf 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -74,6 +74,10 @@ public class StackAnimationController extends private static final int FLING_FOLLOW_STIFFNESS = 20000; public static final float DEFAULT_BOUNCINESS = 0.9f; + private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfig = + new PhysicsAnimator.SpringConfig( + ANIMATE_IN_STIFFNESS, SpringForce.DAMPING_RATIO_NO_BOUNCY); + /** * Friction applied to fling animations. Since the stack must land on one of the sides of the * screen, we want less friction horizontally so that the stack has a better chance of making it @@ -248,12 +252,19 @@ public class StackAnimationController extends /** Returns the number of 'real' bubbles (excluding the overflow bubble). */ private IntSupplier mBubbleCountSupplier; + /** + * Callback to run whenever any bubble is animated out. The BubbleStackView will check if the + * end of this animation means we have no bubbles left, and notify the BubbleController. + */ + private Runnable mOnBubbleAnimatedOutAction; + public StackAnimationController( FloatingContentCoordinator floatingContentCoordinator, - IntSupplier bubbleCountSupplier) { + IntSupplier bubbleCountSupplier, + Runnable onBubbleAnimatedOutAction) { mFloatingContentCoordinator = floatingContentCoordinator; mBubbleCountSupplier = bubbleCountSupplier; - + mOnBubbleAnimatedOutAction = onBubbleAnimatedOutAction; } /** @@ -652,8 +663,8 @@ public class StackAnimationController extends public void animateStackDismissal(float translationYBy, Runnable after) { animationsForChildrenFromIndex(0, (index, animation) -> animation - .scaleX(0.5f) - .scaleY(0.5f) + .scaleX(0f) + .scaleY(0f) .alpha(0f) .translationY( mLayout.getChildAt(index).getTranslationY() + translationYBy) @@ -760,13 +771,11 @@ public class StackAnimationController extends @Override void onChildRemoved(View child, int index, Runnable finishRemoval) { - // Animate the removing view in the opposite direction of the stack. - final float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X); - animationForChild(child) - .alpha(0f, finishRemoval /* after */) - .scaleX(ANIMATE_IN_STARTING_SCALE) - .scaleY(ANIMATE_IN_STARTING_SCALE) - .translationX(mStackPosition.x - (-xOffset * ANIMATE_TRANSLATION_FACTOR)) + PhysicsAnimator.getInstance(child) + .spring(DynamicAnimation.ALPHA, 0f) + .spring(DynamicAnimation.SCALE_X, 0f, mAnimateOutSpringConfig) + .spring(DynamicAnimation.SCALE_Y, 0f, mAnimateOutSpringConfig) + .withEndActions(finishRemoval, mOnBubbleAnimatedOutAction) .start(); // If there are other bubbles, pull them into the correct position. diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java index ec6d3e9d0dff..6a1486382eac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java @@ -49,11 +49,13 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC private int mOrientation = Configuration.ORIENTATION_PORTRAIT; private float mLauncherGridDiff = 30f; + private Runnable mOnBubbleAnimatedOutAction = Mockito.mock(Runnable.class); + @Spy private ExpandedAnimationController mExpandedController = new ExpandedAnimationController( new Point(mDisplayWidth, mDisplayHeight) /* displaySize */, - mExpandedViewPadding, mOrientation); + mExpandedViewPadding, mOrientation, mOnBubbleAnimatedOutAction); private int mStackOffset; private float mBubblePaddingTop; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java index b1ac022dbe9c..cc62a2f36392 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java @@ -40,6 +40,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -66,7 +67,7 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase public int getAsInt() { return mLayout.getChildCount(); } - })); + }, Mockito.mock(Runnable.class))); mLayout.setActiveController(mStackController); addOneMoreThanBubbleLimitBubbles(); mStackOffset = mLayout.getResources().getDimensionPixelSize(R.dimen.bubble_stack_offset); @@ -303,8 +304,9 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase private class TestableStackController extends StackAnimationController { TestableStackController( FloatingContentCoordinator floatingContentCoordinator, - IntSupplier bubbleCountSupplier) { - super(floatingContentCoordinator, bubbleCountSupplier); + IntSupplier bubbleCountSupplier, + Runnable onBubbleAnimatedOutAction) { + super(floatingContentCoordinator, bubbleCountSupplier, onBubbleAnimatedOutAction); } @Override |