Merge changes from topic "floating_dismiss" into tm-dev

* changes:
  Update PIP dismiss to use DismissView
  Update dismiss to new spec
This commit is contained in:
Mady Mellor
2022-02-23 18:12:07 +00:00
committed by Android (Google) Code Review
3 changed files with 62 additions and 70 deletions

View File

@@ -18,8 +18,8 @@
<dimen name="dismiss_circle_size">96dp</dimen> <dimen name="dismiss_circle_size">96dp</dimen>
<dimen name="dismiss_circle_small">60dp</dimen> <dimen name="dismiss_circle_small">60dp</dimen>
<!-- The height of the gradient indicating the dismiss edge when moving a PIP. --> <!-- The height of the gradient indicating the dismiss edge when moving a PIP or bubble. -->
<dimen name="floating_dismiss_gradient_height">250dp</dimen> <dimen name="floating_dismiss_gradient_height">548dp</dimen>
<!-- The padding around a PiP actions. --> <!-- The padding around a PiP actions. -->
<dimen name="pip_action_padding">16dp</dimen> <dimen name="pip_action_padding">16dp</dimen>

View File

@@ -16,11 +16,16 @@
package com.android.wm.shell.bubbles package com.android.wm.shell.bubbles
import android.animation.ObjectAnimator
import android.content.Context import android.content.Context
import android.graphics.drawable.TransitionDrawable import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.util.IntProperty
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.view.WindowInsets
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
@@ -28,8 +33,6 @@ import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
import com.android.wm.shell.R import com.android.wm.shell.R
import com.android.wm.shell.animation.PhysicsAnimator import com.android.wm.shell.animation.PhysicsAnimator
import com.android.wm.shell.common.DismissCircleView import com.android.wm.shell.common.DismissCircleView
import android.view.WindowInsets
import android.view.WindowManager
/* /*
* View that handles interactions between DismissCircleView and BubbleStackView. * View that handles interactions between DismissCircleView and BubbleStackView.
@@ -41,9 +44,21 @@ class DismissView(context: Context) : FrameLayout(context) {
private val animator = PhysicsAnimator.getInstance(circle) private val animator = PhysicsAnimator.getInstance(circle)
private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY) private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
private val DISMISS_SCRIM_FADE_MS = 200 private val DISMISS_SCRIM_FADE_MS = 200L
private var wm: WindowManager = private var wm: WindowManager =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private var gradientDrawable = createGradient()
private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
object : IntProperty<GradientDrawable>("alpha") {
override fun setValue(d: GradientDrawable, percent: Int) {
d.alpha = percent
}
override fun get(d: GradientDrawable): Int {
return d.alpha
}
}
init { init {
setLayoutParams(LayoutParams( setLayoutParams(LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -53,8 +68,7 @@ class DismissView(context: Context) : FrameLayout(context) {
setClipToPadding(false) setClipToPadding(false)
setClipChildren(false) setClipChildren(false)
setVisibility(View.INVISIBLE) setVisibility(View.INVISIBLE)
setBackgroundResource( setBackgroundDrawable(gradientDrawable)
R.drawable.floating_dismiss_gradient_transition)
val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size) val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
addView(circle, LayoutParams(targetSize, targetSize, addView(circle, LayoutParams(targetSize, targetSize,
@@ -71,7 +85,11 @@ class DismissView(context: Context) : FrameLayout(context) {
if (isShowing) return if (isShowing) return
isShowing = true isShowing = true
setVisibility(View.VISIBLE) setVisibility(View.VISIBLE)
(getBackground() as TransitionDrawable).startTransition(DISMISS_SCRIM_FADE_MS) val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
gradientDrawable.alpha, 255)
alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
alphaAnim.start()
animator.cancel() animator.cancel()
animator animator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, spring) .spring(DynamicAnimation.TRANSLATION_Y, 0f, spring)
@@ -85,7 +103,10 @@ class DismissView(context: Context) : FrameLayout(context) {
fun hide() { fun hide() {
if (!isShowing) return if (!isShowing) return
isShowing = false isShowing = false
(getBackground() as TransitionDrawable).reverseTransition(DISMISS_SCRIM_FADE_MS) val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
gradientDrawable.alpha, 0)
alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
alphaAnim.start()
animator animator
.spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(), .spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(),
spring) spring)
@@ -93,6 +114,13 @@ class DismissView(context: Context) : FrameLayout(context) {
.start() .start()
} }
/**
* Cancels the animator for the dismiss target.
*/
fun cancelAnimators() {
animator.cancel()
}
fun updateResources() { fun updateResources() {
updatePadding() updatePadding()
layoutParams.height = resources.getDimensionPixelSize( layoutParams.height = resources.getDimensionPixelSize(
@@ -104,6 +132,20 @@ class DismissView(context: Context) : FrameLayout(context) {
circle.requestLayout() circle.requestLayout()
} }
private fun createGradient(): GradientDrawable {
val gradientColor = context.resources.getColor(android.R.color.system_neutral1_900)
val alpha = 0.7f * 255
val gradientColorWithAlpha = Color.argb(alpha.toInt(),
Color.red(gradientColor),
Color.green(gradientColor),
Color.blue(gradientColor))
val gd = GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,
intArrayOf(gradientColorWithAlpha, Color.TRANSPARENT))
gd.setAlpha(0)
return gd
}
private fun updatePadding() { private fun updatePadding() {
val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets() val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
val navInset = insets.getInsetsIgnoringVisibility( val navInset = insets.getInsetsIgnoringVisibility(

View File

@@ -20,27 +20,20 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.TransitionDrawable;
import android.view.Gravity;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.wm.shell.R; import com.android.wm.shell.R;
import com.android.wm.shell.animation.PhysicsAnimator; import com.android.wm.shell.bubbles.DismissView;
import com.android.wm.shell.common.DismissCircleView; import com.android.wm.shell.common.DismissCircleView;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject; import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -56,9 +49,6 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
/* The multiplier to apply scale the target size by when applying the magnetic field radius */ /* The multiplier to apply scale the target size by when applying the magnetic field radius */
private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f; private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
/** Duration of the dismiss scrim fading in/out. */
private static final int DISMISS_TRANSITION_DURATION_MS = 200;
/** /**
* MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move * MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move
* PIP. * PIP.
@@ -69,7 +59,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
* Container for the dismiss circle, so that it can be animated within the container via * Container for the dismiss circle, so that it can be animated within the container via
* translation rather than within the WindowManager via slow layout animations. * translation rather than within the WindowManager via slow layout animations.
*/ */
private ViewGroup mTargetViewContainer; private DismissView mTargetViewContainer;
/** Circle view used to render the dismiss target. */ /** Circle view used to render the dismiss target. */
private DismissCircleView mTargetView; private DismissCircleView mTargetView;
@@ -79,16 +69,6 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
*/ */
private MagnetizedObject.MagneticTarget mMagneticTarget; private MagnetizedObject.MagneticTarget mMagneticTarget;
/**
* PhysicsAnimator instance for animating the dismiss target in/out.
*/
private PhysicsAnimator<View> mMagneticTargetAnimator;
/** Default configuration to use for springing the dismiss target in/out. */
private final PhysicsAnimator.SpringConfig mTargetSpringConfig =
new PhysicsAnimator.SpringConfig(
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
// Allow dragging the PIP to a location to close it // Allow dragging the PIP to a location to close it
private boolean mEnableDismissDragToEdge; private boolean mEnableDismissDragToEdge;
@@ -125,12 +105,8 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
cleanUpDismissTarget(); cleanUpDismissTarget();
} }
mTargetView = new DismissCircleView(mContext); mTargetViewContainer = new DismissView(mContext);
mTargetViewContainer = new FrameLayout(mContext); mTargetView = mTargetViewContainer.getCircle();
mTargetViewContainer.setBackgroundDrawable(
mContext.getDrawable(R.drawable.floating_dismiss_gradient_transition));
mTargetViewContainer.setClipChildren(false);
mTargetViewContainer.addView(mTargetView);
mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> { mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets)) { if (!windowInsets.equals(mWindowInsets)) {
mWindowInsets = windowInsets; mWindowInsets = windowInsets;
@@ -187,7 +163,6 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
} }
}); });
mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
} }
@Override @Override
@@ -213,19 +188,13 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
if (mTargetView == null) { if (mTargetView == null) {
return; return;
} }
if (mTargetViewContainer != null) {
mTargetViewContainer.updateResources();
}
final Resources res = mContext.getResources(); final Resources res = mContext.getResources();
mTargetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size); mTargetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height); mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
final WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
final Insets navInset = insets.getInsetsIgnoringVisibility(
WindowInsets.Type.navigationBars());
final FrameLayout.LayoutParams newParams =
new FrameLayout.LayoutParams(mTargetSize, mTargetSize);
newParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
newParams.bottomMargin = navInset.bottom + mContext.getResources().getDimensionPixelSize(
R.dimen.floating_dismiss_bottom_margin);
mTargetView.setLayoutParams(newParams);
// Set the magnetic field radius equal to the target size from the center of the target // Set the magnetic field radius equal to the target size from the center of the target
setMagneticFieldRadiusPercent(mMagneticFieldRadiusPercent); setMagneticFieldRadiusPercent(mMagneticFieldRadiusPercent);
@@ -261,7 +230,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
/** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */ /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */
public void createOrUpdateDismissTarget() { public void createOrUpdateDismissTarget() {
if (!mTargetViewContainer.isAttachedToWindow()) { if (!mTargetViewContainer.isAttachedToWindow()) {
mMagneticTargetAnimator.cancel(); mTargetViewContainer.cancelAnimators();
mTargetViewContainer.setVisibility(View.INVISIBLE); mTargetViewContainer.setVisibility(View.INVISIBLE);
mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this); mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
@@ -312,18 +281,8 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
createOrUpdateDismissTarget(); createOrUpdateDismissTarget();
if (mTargetViewContainer.getVisibility() != View.VISIBLE) { if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
mTargetView.setTranslationY(mTargetViewContainer.getHeight());
mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this); mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);
mTargetViewContainer.show();
// Cancel in case we were in the middle of animating it out.
mMagneticTargetAnimator.cancel();
mMagneticTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig)
.start();
((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition(
DISMISS_TRANSITION_DURATION_MS);
} }
} }
@@ -332,16 +291,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
if (!mEnableDismissDragToEdge) { if (!mEnableDismissDragToEdge) {
return; return;
} }
mTargetViewContainer.hide();
mMagneticTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y,
mTargetViewContainer.getHeight(),
mTargetSpringConfig)
.withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
.start();
((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
DISMISS_TRANSITION_DURATION_MS);
} }
/** /**