summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/DragState.java196
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java4
2 files changed, 143 insertions, 57 deletions
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 3fdafc7bebdf..21dffff011b4 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -22,6 +22,10 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.animation.Animator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
@@ -29,7 +33,9 @@ import android.graphics.Matrix;
import android.graphics.Point;
import android.hardware.input.InputManager;
import android.os.Build;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -44,16 +50,12 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.PointerIcon;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.view.animation.ScaleAnimation;
import android.view.animation.Transformation;
-import android.view.animation.TranslateAnimation;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
@@ -78,8 +80,20 @@ class DragState {
View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
+ // Property names for animations
+ private static final String ANIMATED_PROPERTY_X = "x";
+ private static final String ANIMATED_PROPERTY_Y = "y";
+ private static final String ANIMATED_PROPERTY_ALPHA = "alpha";
+ private static final String ANIMATED_PROPERTY_SCALE = "scale";
+
+ // Messages for Handler.
+ private static final int MSG_ANIMATION_END = 0;
+
final WindowManagerService mService;
IBinder mToken;
+ /**
+ * Do not use the variable from the out of animation thread while mAnimator is not null.
+ */
SurfaceControl mSurfaceControl;
int mFlags;
IBinder mLocalWin;
@@ -101,10 +115,10 @@ class DragState {
boolean mDragInProgress;
DisplayContent mDisplayContent;
- private Animation mAnimation;
- final Transformation mTransformation = new Transformation();
+ @Nullable private ValueAnimator mAnimator;
private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
private Point mDisplaySize = new Point();
+ private final Handler mHandler;
DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
int flags, IBinder localWin) {
@@ -114,9 +128,14 @@ class DragState {
mFlags = flags;
mLocalWin = localWin;
mNotifiedWindows = new ArrayList<WindowState>();
+ mHandler = new DragStateHandler(service.mH.getLooper());
}
void reset() {
+ if (mAnimator != null) {
+ Slog.wtf(TAG_WM,
+ "Unexpectedly destroying mSurfaceControl while animation is running");
+ }
if (mSurfaceControl != null) {
mSurfaceControl.destroy();
}
@@ -388,11 +407,11 @@ class DragState {
}
void endDragLw() {
- if (mAnimation != null) {
+ if (mAnimator != null) {
return;
}
if (!mDragResult) {
- mAnimation = createReturnAnimationLocked();
+ mAnimator = createReturnAnimationLocked();
mService.scheduleAnimationLocked();
return; // Will call cleanUpDragLw when the animation is done.
}
@@ -400,11 +419,22 @@ class DragState {
}
void cancelDragLw() {
- if (mAnimation != null) {
+ if (mAnimator != null) {
+ return;
+ }
+ if (!mDragInProgress) {
+ // This can happen if an app invokes Session#cancelDragAndDrop before
+ // Session#performDrag. Reset the drag state:
+ // 1. without sending the end broadcast because the start broadcast has not been sent,
+ // and
+ // 2. without playing the cancel animation because H.DRAG_START_TIMEOUT may be sent to
+ // WindowManagerService, which will cause DragState#reset() while playing the
+ // cancel animation.
+ reset();
+ mService.mDragState = null;
return;
}
- mAnimation = createCancelAnimationLocked();
- mService.scheduleAnimationLocked();
+ mAnimator = createCancelAnimationLocked();
}
private void cleanUpDragLw() {
@@ -422,7 +452,7 @@ class DragState {
}
void notifyMoveLw(float x, float y) {
- if (mAnimation != null) {
+ if (mAnimator != null) {
return;
}
mCurrentX = x;
@@ -491,7 +521,7 @@ class DragState {
// dispatch the global drag-ended message, 'false' if we need to wait for a
// result from the recipient.
boolean notifyDropLw(float x, float y) {
- if (mAnimation != null) {
+ if (mAnimator != null) {
return false;
}
mCurrentX = x;
@@ -560,56 +590,52 @@ class DragState {
dragAndDropPermissions, result);
}
- boolean stepAnimationLocked(long currentTimeMs) {
- if (mAnimation == null) {
- return false;
- }
-
- mTransformation.clear();
- if (!mAnimation.getTransformation(currentTimeMs, mTransformation)) {
- cleanUpDragLw();
- return false;
- }
-
- mTransformation.getMatrix().postTranslate(
- mCurrentX - mThumbOffsetX, mCurrentY - mThumbOffsetY);
- final float tmpFloats[] = mService.mTmpFloats;
- mTransformation.getMatrix().getValues(tmpFloats);
- mSurfaceControl.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
- mSurfaceControl.setAlpha(mTransformation.getAlpha());
- mSurfaceControl.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
- tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
- return true;
- }
+ private ValueAnimator createReturnAnimationLocked() {
+ final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
+ PropertyValuesHolder.ofFloat(
+ ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX,
+ mOriginalX - mThumbOffsetX),
+ PropertyValuesHolder.ofFloat(
+ ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY,
+ mOriginalY - mThumbOffsetY),
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 1),
+ PropertyValuesHolder.ofFloat(
+ ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2));
- private Animation createReturnAnimationLocked() {
- final AnimationSet set = new AnimationSet(false);
final float translateX = mOriginalX - mCurrentX;
final float translateY = mOriginalY - mCurrentY;
- set.addAnimation(new TranslateAnimation( 0, translateX, 0, translateY));
- set.addAnimation(new AlphaAnimation(mOriginalAlpha, mOriginalAlpha / 2));
// Adjust the duration to the travel distance.
final double travelDistance = Math.sqrt(translateX * translateX + translateY * translateY);
final double displayDiagonal =
Math.sqrt(mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y);
final long duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal
* (MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS));
- set.setDuration(duration);
- set.setInterpolator(mCubicEaseOutInterpolator);
- set.initialize(0, 0, 0, 0);
- set.start(); // Will start on the first call to getTransformation.
- return set;
+ final AnimationListener listener = new AnimationListener();
+ animator.setDuration(duration);
+ animator.setInterpolator(mCubicEaseOutInterpolator);
+ animator.addListener(listener);
+ animator.addUpdateListener(listener);
+
+ mService.mAnimationHandler.post(() -> animator.start());
+ return animator;
}
- private Animation createCancelAnimationLocked() {
- final AnimationSet set = new AnimationSet(false);
- set.addAnimation(new ScaleAnimation(1, 0, 1, 0, mThumbOffsetX, mThumbOffsetY));
- set.addAnimation(new AlphaAnimation(mOriginalAlpha, 0));
- set.setDuration(MIN_ANIMATION_DURATION_MS);
- set.setInterpolator(mCubicEaseOutInterpolator);
- set.initialize(0, 0, 0, 0);
- set.start(); // Will start on the first call to getTransformation.
- return set;
+ private ValueAnimator createCancelAnimationLocked() {
+ final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
+ PropertyValuesHolder.ofFloat(
+ ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX),
+ PropertyValuesHolder.ofFloat(
+ ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY),
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 0),
+ PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
+ final AnimationListener listener = new AnimationListener();
+ animator.setDuration(MIN_ANIMATION_DURATION_MS);
+ animator.setInterpolator(mCubicEaseOutInterpolator);
+ animator.addListener(listener);
+ animator.addUpdateListener(listener);
+
+ mService.mAnimationHandler.post(() -> animator.start());
+ return animator;
}
private boolean isFromSource(int source) {
@@ -622,4 +648,68 @@ class DragState {
InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
}
}
+
+ private class DragStateHandler extends Handler {
+ DragStateHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ANIMATION_END:
+ synchronized (mService.mWindowMap) {
+ if (mService.mDragState != DragState.this) {
+ Slog.wtf(TAG_WM, "mDragState is updated unexpectedly while " +
+ "playing animation");
+ return;
+ }
+ if (mAnimator == null) {
+ Slog.wtf(TAG_WM, "Unexpected null mAnimator");
+ return;
+ }
+ mAnimator = null;
+ cleanUpDragLw();
+ }
+ break;
+ }
+ }
+ }
+
+ private class AnimationListener
+ implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
+ transaction.setPosition(
+ mSurfaceControl,
+ (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_X),
+ (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_Y));
+ transaction.setAlpha(
+ mSurfaceControl,
+ (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
+ transaction.setMatrix(
+ mSurfaceControl,
+ (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
+ 0, (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
+ transaction.apply();
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animator) {}
+
+ @Override
+ public void onAnimationCancel(Animator animator) {}
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {}
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ // Updating mDragState requires the WM lock so continues it on the out of
+ // AnimationThread.
+ mHandler.sendEmptyMessage(MSG_ANIMATION_END);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c01ee31e8c1c..e409a68f2dfe 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -223,10 +223,6 @@ public class WindowAnimator {
}
}
- if (mService.mDragState != null) {
- mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
- }
-
if (!mAnimating) {
cancelAnimation();
}