diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDismissView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDismissView.java deleted file mode 100644 index 9db371e487c7e..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDismissView.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.bubbles; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.SpringAnimation; -import androidx.dynamicanimation.animation.SpringForce; - -import com.android.systemui.R; - -/** Dismiss view that contains a scrim gradient, as well as a dismiss icon, text, and circle. */ -public class BubbleDismissView extends FrameLayout { - /** Duration for animations involving the dismiss target text/icon. */ - private static final int DISMISS_TARGET_ANIMATION_BASE_DURATION = 150; - private static final float SCALE_FOR_POP = 1.2f; - private static final float SCALE_FOR_DISMISS = 0.9f; - - private LinearLayout mDismissTarget; - private ImageView mDismissIcon; - private View mDismissCircle; - - private SpringAnimation mDismissTargetAlphaSpring; - private SpringAnimation mDismissTargetVerticalSpring; - - public BubbleDismissView(Context context) { - super(context); - setVisibility(GONE); - - LayoutInflater.from(context).inflate(R.layout.bubble_dismiss_target, this, true); - mDismissTarget = findViewById(R.id.bubble_dismiss_icon_container); - mDismissIcon = findViewById(R.id.bubble_dismiss_close_icon); - mDismissCircle = findViewById(R.id.bubble_dismiss_circle); - - // Set up the basic target area animations. These are very simple animations that don't need - // fancy interpolators. - final AccelerateDecelerateInterpolator interpolator = - new AccelerateDecelerateInterpolator(); - mDismissIcon.animate() - .setDuration(DISMISS_TARGET_ANIMATION_BASE_DURATION) - .setInterpolator(interpolator); - mDismissCircle.animate() - .setDuration(DISMISS_TARGET_ANIMATION_BASE_DURATION / 2) - .setInterpolator(interpolator); - - mDismissTargetAlphaSpring = - new SpringAnimation(mDismissTarget, DynamicAnimation.ALPHA) - .setSpring(new SpringForce() - .setStiffness(SpringForce.STIFFNESS_LOW) - .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)); - mDismissTargetVerticalSpring = - new SpringAnimation(mDismissTarget, DynamicAnimation.TRANSLATION_Y) - .setSpring(new SpringForce() - .setStiffness(SpringForce.STIFFNESS_MEDIUM) - .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)); - - mDismissTargetAlphaSpring.addEndListener((anim, canceled, alpha, velocity) -> { - // Since DynamicAnimations end when they're 'nearly' done, we can't rely on alpha being - // exactly zero when this listener is triggered. However, if it's less than 50% we can - // safely assume it was animating out rather than in. - if (alpha < 0.5f) { - // If the alpha spring was animating the view out, set it to GONE when it's done. - setVisibility(INVISIBLE); - } - }); - } - - /** Springs in the dismiss target. */ - void springIn() { - setVisibility(View.VISIBLE); - - // Fade in the dismiss target icon. - mDismissIcon.animate() - .setDuration(50) - .scaleX(1f) - .scaleY(1f) - .alpha(1f); - mDismissTarget.setAlpha(0f); - mDismissTargetAlphaSpring.animateToFinalPosition(1f); - - // Spring up the dismiss target. - mDismissTarget.setTranslationY(mDismissTarget.getHeight() / 2f); - mDismissTargetVerticalSpring.animateToFinalPosition(0); - - mDismissCircle.setAlpha(0f); - mDismissCircle.setScaleX(SCALE_FOR_POP); - mDismissCircle.setScaleY(SCALE_FOR_POP); - - // Fade in circle and reduce size. - mDismissCircle.animate() - .alpha(1f) - .scaleX(1f) - .scaleY(1f); - } - - /** Springs out the dismiss target. */ - void springOut() { - // Fade out the target icon. - mDismissIcon.animate() - .setDuration(50) - .scaleX(SCALE_FOR_DISMISS) - .scaleY(SCALE_FOR_DISMISS) - .alpha(0f); - - // Fade out the target. - mDismissTargetAlphaSpring.animateToFinalPosition(0f); - - // Spring the target down a bit. - mDismissTargetVerticalSpring.animateToFinalPosition(mDismissTarget.getHeight() / 2f); - - // Pop out the circle. - mDismissCircle.animate() - .scaleX(SCALE_FOR_DISMISS) - .scaleY(SCALE_FOR_DISMISS) - .alpha(0f); - } - - /** Returns the Y value of the center of the dismiss target. */ - float getDismissTargetCenterY() { - return getTop() + mDismissTarget.getTop() + mDismissTarget.getHeight() / 2f; - } - - /** Returns the dismiss target, which contains the text/icon and any added padding. */ - View getDismissTarget() { - return mDismissTarget; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 75c6385c22a36..b5ad5e6fffec0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -48,7 +48,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; -import android.graphics.drawable.TransitionDrawable; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; @@ -95,7 +94,6 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; -import com.android.systemui.util.DismissCircleView; import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.RelativeTouchListener; import com.android.systemui.util.animation.PhysicsAnimator; @@ -139,9 +137,6 @@ public class BubbleStackView extends FrameLayout /** Percent to darken the bubbles when they're in the dismiss target. */ private static final float DARKEN_PERCENT = 0.3f; - /** Duration of the dismiss scrim fading in/out. */ - private static final int DISMISS_TRANSITION_DURATION_MS = 200; - /** How long to wait, in milliseconds, before hiding the flyout. */ @VisibleForTesting static final int FLYOUT_HIDE_AFTER = 5000; @@ -300,7 +295,7 @@ public class BubbleStackView extends FrameLayout public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Stack view state:"); pw.print(" gestureInProgress: "); pw.println(mIsGestureInProgress); - pw.print(" showingDismiss: "); pw.println(mShowingDismiss); + pw.print(" showingDismiss: "); pw.println(mDismissView.isShowing()); pw.print(" isExpansionAnimating: "); pw.println(mIsExpansionAnimating); pw.print(" expandedContainerVis: "); pw.println(mExpandedViewContainer.getVisibility()); pw.print(" expandedContainerAlpha: "); pw.println(mExpandedViewContainer.getAlpha()); @@ -347,7 +342,6 @@ public class BubbleStackView extends FrameLayout private boolean mViewUpdatedRequested = false; private boolean mIsExpansionAnimating = false; private boolean mIsBubbleSwitchAnimating = false; - private boolean mShowingDismiss = false; /** The view to desaturate/darken when magneted to the dismiss target. */ @Nullable private View mDesaturateAndDarkenTargetView; @@ -465,7 +459,7 @@ public class BubbleStackView extends FrameLayout if (wasFlungOut) { mExpandedAnimationController.snapBubbleBack( mExpandedAnimationController.getDraggedOutBubble(), velX, velY); - hideDismissTarget(); + mDismissView.hide(); } else { mExpandedAnimationController.onUnstuckFromTarget(); } @@ -479,9 +473,9 @@ public class BubbleStackView extends FrameLayout mExpandedAnimationController.dismissDraggedOutBubble( mExpandedAnimationController.getDraggedOutBubble() /* bubble */, - mDismissTargetContainer.getHeight() /* translationYBy */, + mDismissView.getHeight() /* translationYBy */, BubbleStackView.this::dismissMagnetizedObject /* after */); - hideDismissTarget(); + mDismissView.hide(); } }; @@ -502,7 +496,7 @@ public class BubbleStackView extends FrameLayout if (wasFlungOut) { mStackAnimationController.flingStackThenSpringToEdge( mStackAnimationController.getStackPosition().x, velX, velY); - hideDismissTarget(); + mDismissView.hide(); } else { mStackAnimationController.onUnstuckFromTarget(); } @@ -511,14 +505,14 @@ public class BubbleStackView extends FrameLayout @Override public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { mStackAnimationController.animateStackDismissal( - mDismissTargetContainer.getHeight() /* translationYBy */, + mDismissView.getHeight() /* translationYBy */, () -> { resetDesaturationAndDarken(); dismissMagnetizedObject(); } ); - hideDismissTarget(); + mDismissView.hide(); } }; @@ -639,7 +633,7 @@ public class BubbleStackView extends FrameLayout } // Show the dismiss target, if we haven't already. - springInDismissTargetMaybe(); + mDismissView.show(); // First, see if the magnetized object consumes the event - if so, we shouldn't move the // bubble since it's stuck to the target. @@ -681,7 +675,7 @@ public class BubbleStackView extends FrameLayout SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); } - hideDismissTarget(); + mDismissView.hide(); } mIsDraggingStack = false; @@ -743,12 +737,7 @@ public class BubbleStackView extends FrameLayout } }; - private View mDismissTargetCircle; - private ViewGroup mDismissTargetContainer; - private PhysicsAnimator mDismissTargetAnimator; - private PhysicsAnimator.SpringConfig mDismissTargetSpring = new PhysicsAnimator.SpringConfig( - SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); - + private DismissView mDismissView; private int mOrientation = Configuration.ORIENTATION_UNDEFINED; @Nullable @@ -866,34 +855,8 @@ public class BubbleStackView extends FrameLayout .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)); mFlyoutTransitionSpring.addEndListener(mAfterFlyoutTransitionSpring); - final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size); - mDismissTargetCircle = new DismissCircleView(context); - final FrameLayout.LayoutParams newParams = - new FrameLayout.LayoutParams(targetSize, targetSize); - newParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - mDismissTargetCircle.setLayoutParams(newParams); - mDismissTargetAnimator = PhysicsAnimator.getInstance(mDismissTargetCircle); - - mDismissTargetContainer = new FrameLayout(context); - mDismissTargetContainer.setLayoutParams(new FrameLayout.LayoutParams( - MATCH_PARENT, - getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height), - Gravity.BOTTOM)); - - final int bottomMargin = - getResources().getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin); - mDismissTargetContainer.setPadding(0, 0, 0, bottomMargin); - mDismissTargetContainer.setClipToPadding(false); - mDismissTargetContainer.setClipChildren(false); - mDismissTargetContainer.addView(mDismissTargetCircle); - mDismissTargetContainer.setVisibility(View.INVISIBLE); - mDismissTargetContainer.setBackgroundResource( - R.drawable.floating_dismiss_gradient_transition); - addView(mDismissTargetContainer); - - // Start translated down so the target springs up. - mDismissTargetCircle.setTranslationY( - getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height)); + mDismissView = new DismissView(context); + addView(mDismissView); final ContentResolver contentResolver = getContext().getContentResolver(); final int dismissRadius = Settings.Secure.getInt( @@ -901,7 +864,8 @@ public class BubbleStackView extends FrameLayout // Save the MagneticTarget instance for the newly set up view - we'll add this to the // MagnetizedObjects. - mMagneticTarget = new MagnetizedObject.MagneticTarget(mDismissTargetCircle, dismissRadius); + mMagneticTarget = new MagnetizedObject.MagneticTarget( + mDismissView.getCircle(), dismissRadius); setClipChildren(false); setFocusable(true); @@ -1277,12 +1241,7 @@ public class BubbleStackView extends FrameLayout } mExpandedAnimationController.updateResources(mOrientation, mDisplaySize); mStackAnimationController.updateResources(mOrientation); - - final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size); - mDismissTargetCircle.getLayoutParams().width = targetSize; - mDismissTargetCircle.getLayoutParams().height = targetSize; - mDismissTargetCircle.requestLayout(); - + mDismissView.updateResources(); mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2); } @@ -2360,48 +2319,6 @@ public class BubbleStackView extends FrameLayout } } - /** Animates in the dismiss target. */ - private void springInDismissTargetMaybe() { - if (mShowingDismiss) { - return; - } - - mShowingDismiss = true; - - mDismissTargetContainer.bringToFront(); - mDismissTargetContainer.setZ(Short.MAX_VALUE - 1); - mDismissTargetContainer.setVisibility(VISIBLE); - - ((TransitionDrawable) mDismissTargetContainer.getBackground()).startTransition( - DISMISS_TRANSITION_DURATION_MS); - - mDismissTargetAnimator.cancel(); - mDismissTargetAnimator - .spring(DynamicAnimation.TRANSLATION_Y, 0f, mDismissTargetSpring) - .start(); - } - - /** - * Animates the dismiss target out, as well as the circle that encircles the bubbles, if they - * were dragged into the target and encircled. - */ - private void hideDismissTarget() { - if (!mShowingDismiss) { - return; - } - - mShowingDismiss = false; - - ((TransitionDrawable) mDismissTargetContainer.getBackground()).reverseTransition( - DISMISS_TRANSITION_DURATION_MS); - - mDismissTargetAnimator - .spring(DynamicAnimation.TRANSLATION_Y, mDismissTargetContainer.getHeight(), - mDismissTargetSpring) - .withEndActions(() -> mDismissTargetContainer.setVisibility(View.INVISIBLE)) - .start(); - } - /** Animates the flyout collapsed (to dot), or the reverse, starting with the given velocity. */ private void animateFlyoutCollapsed(boolean collapsed, float velX) { final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt new file mode 100644 index 0000000000000..71faf4a2eeb78 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt @@ -0,0 +1,85 @@ +package com.android.systemui.bubbles + +import android.content.Context +import android.graphics.drawable.TransitionDrawable +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.dynamicanimation.animation.DynamicAnimation +import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY +import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW +import com.android.systemui.R +import com.android.systemui.util.DismissCircleView +import com.android.systemui.util.animation.PhysicsAnimator + +/* + * View that handles interactions between DismissCircleView and BubbleStackView. + */ +class DismissView(context: Context) : FrameLayout(context) { + + var circle = DismissCircleView(context).apply { + val targetSize: Int = context.resources.getDimensionPixelSize(R.dimen.dismiss_circle_size) + val newParams = LayoutParams(targetSize, targetSize) + newParams.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL + setLayoutParams(newParams) + setTranslationY( + resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height).toFloat()) + } + + var isShowing = false + private val animator = PhysicsAnimator.getInstance(circle) + private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY); + private val DISMISS_SCRIM_FADE_MS = 200 + init { + setLayoutParams(LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height), + Gravity.BOTTOM)) + setPadding(0, 0, 0, resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin)) + setClipToPadding(false) + setClipChildren(false) + setVisibility(View.INVISIBLE) + setBackgroundResource( + R.drawable.floating_dismiss_gradient_transition) + addView(circle) + } + + /** + * Animates this view in. + */ + fun show() { + if (isShowing) return + isShowing = true + bringToFront() + setZ(Short.MAX_VALUE - 1f) + setVisibility(View.VISIBLE) + (getBackground() as TransitionDrawable).startTransition(DISMISS_SCRIM_FADE_MS) + animator.cancel() + animator + .spring(DynamicAnimation.TRANSLATION_Y, 0f, spring) + .start() + } + + /** + * Animates this view out, as well as the circle that encircles the bubbles, if they + * were dragged into the target and encircled. + */ + fun hide() { + if (!isShowing) return + isShowing = false + (getBackground() as TransitionDrawable).reverseTransition(DISMISS_SCRIM_FADE_MS) + animator + .spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(), + spring) + .withEndActions({ setVisibility(View.INVISIBLE) }) + .start() + } + + fun updateResources() { + val targetSize: Int = context.resources.getDimensionPixelSize(R.dimen.dismiss_circle_size) + circle.layoutParams.width = targetSize + circle.layoutParams.height = targetSize + circle.requestLayout() + } +} \ No newline at end of file