import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
+
+import com.android.internal.annotations.GuardedBy;
+
import dalvik.system.CloseGuard;
import libcore.util.NativeAllocationRegistry;
private final String mName;
long mNativeObject; // package visibility only for Surface.java access
+ // TODO: Move this to native.
+ private final Object mSizeLock = new Object();
+ @GuardedBy("mSizeLock")
+ private int mWidth;
+ @GuardedBy("mSizeLock")
+ private int mHeight;
+
static Transaction sGlobalTransaction;
static long sTransactionNestCount = 0;
}
mName = name;
+ mWidth = w;
+ mHeight = h;
mNativeObject = nativeCreate(session, name, w, h, format, flags,
parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
if (mNativeObject == 0) {
// event logging.
public SurfaceControl(SurfaceControl other) {
mName = other.mName;
+ mWidth = other.mWidth;
+ mHeight = other.mHeight;
mNativeObject = other.mNativeObject;
other.mCloseGuard.close();
other.mNativeObject = 0;
private SurfaceControl(Parcel in) {
mName = in.readString();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
mNativeObject = nativeReadFromParcel(in);
if (mNativeObject == 0) {
throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
+ dest.writeInt(mWidth);
+ dest.writeInt(mHeight);
nativeWriteToParcel(mNativeObject, dest);
}
}
}
+ public int getWidth() {
+ synchronized (mSizeLock) {
+ return mWidth;
+ }
+ }
+
+ public int getHeight() {
+ synchronized (mSizeLock) {
+ return mHeight;
+ }
+ }
+
@Override
public String toString() {
return "Surface(name=" + mName + ")/@0x" +
nativeGetNativeTransactionFinalizer(), 512);
private long mNativeObject;
+ private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
Runnable mFreeNativeResources;
public Transaction() {
* Jankier version of apply. Avoid use (b/28068298).
*/
public void apply(boolean sync) {
+ applyResizedSurfaces();
nativeApplyTransaction(mNativeObject, sync);
}
+ private void applyResizedSurfaces() {
+ for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) {
+ final Point size = mResizedSurfaces.valueAt(i);
+ final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i);
+ synchronized (surfaceControl.mSizeLock) {
+ surfaceControl.mWidth = size.x;
+ surfaceControl.mHeight = size.y;
+ }
+ }
+ mResizedSurfaces.clear();
+ }
+
public Transaction show(SurfaceControl sc) {
sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
public Transaction setSize(SurfaceControl sc, int w, int h) {
sc.checkNotReleased();
+ mResizedSurfaces.put(sc, new Point(w, h));
nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
* other transaction as if it had been applied.
*/
public Transaction merge(Transaction other) {
+ mResizedSurfaces.putAll(other.mResizedSurfaces);
+ other.mResizedSurfaces.clear();
nativeMergeTransaction(mNativeObject, other.mNativeObject);
return this;
}
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.Transformation;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.LinkedList;
class AppTokenList extends ArrayList<AppWindowToken> {
}
// If this initial window is animating, stop it -- we will do an animation to reveal
// it from behind the starting window, so there is no need for it to also be doing its
// own stuff.
- winAnimator.clearAnimation();
+ win.cancelAnimation();
if (getController() != null) {
getController().removeStartingWindow();
}
}
for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
- if ((mChildren.get(i)).isWindowAnimationSet()) {
+ if ((mChildren.get(i)).isSelfOrChildAnimating()) {
delayed = true;
}
}
*/
private void destroySurfaces(boolean cleanupOnResume) {
boolean destroyedSomething = false;
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
+
+ // Copying to a different list as multiple children can be removed.
+ // TODO: Not sure why this is needed.
+ final LinkedList<WindowState> children = new LinkedList<>(mChildren);
+ for (int i = children.size() - 1; i >= 0; i--) {
+ final WindowState win = children.get(i);
destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
}
if (destroyedSomething) {
+ " pv=" + w.mPolicyVisibility
+ " mDrawState=" + winAnimator.drawStateToString()
+ " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
- + " a=" + winAnimator.mAnimating);
+ + " a=" + winAnimator.isAnimationSet());
}
}
}
@Override
+ boolean isSelfAnimating() {
+ return mAppAnimator.isAnimating();
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
import android.view.MagnificationSpec;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import com.android.internal.annotations.VisibleForTesting;
new ApplySurfaceChangesTransactionState();
private final ScreenshotApplicationState mScreenshotApplicationState =
new ScreenshotApplicationState();
+ private final Transaction mTmpTransaction = new Transaction();
// True if this display is in the process of being removed. Used to determine if the removal of
// the display's direct children should be allowed.
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
- if (winAnimator.hasSurface()) {
- final boolean wasAnimating = winAnimator.mWasAnimating;
- final boolean nowAnimating = winAnimator.stepAnimationLocked(
- mTmpWindowAnimator.mCurrentTime);
- winAnimator.mWasAnimating = nowAnimating;
- mTmpWindowAnimator.orAnimating(nowAnimating);
-
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating);
-
- if (wasAnimating && !winAnimator.mAnimating
- && mWallpaperController.isWallpaperTarget(w)) {
- mTmpWindowAnimator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
- pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- if (DEBUG_LAYOUT_REPEATS) {
- mService.mWindowPlacerLocked.debugLayoutRepeats(
- "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges);
- }
- }
- }
-
final AppWindowToken atoken = w.mAppToken;
if (winAnimator.mDrawState == READY_TO_SHOW) {
if (atoken == null || atoken.allDrawn) {
// If this window is animating, make a note that we have an animating window and take
// care of a request to run a detached wallpaper animation.
- if (winAnimator.mAnimating) {
- if (winAnimator.mAnimation != null) {
- if ((flags & FLAG_SHOW_WALLPAPER) != 0
- && winAnimator.mAnimation.getDetachWallpaper()) {
+ if (winAnimator.isAnimationSet()) {
+ final AnimationAdapter anim = w.getAnimation();
+ if (anim != null) {
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0 && anim.getDetachWallpaper()) {
mTmpWindow = w;
}
- final int color = winAnimator.mAnimation.getBackgroundColor();
+ final int color = anim.getBackgroundColor();
if (color != 0) {
final TaskStack stack = w.getStack();
if (stack != null) {
}
}
}
- mTmpWindowAnimator.setAnimating(true);
}
// If this window's app token is running a detached wallpaper animation, make a note so
mWallpaperController.updateWallpaperVisibility();
}
- w.handleWindowMovedIfNeeded();
+ // Use mTmpTransaction instead of mPendingTransaction because we don't want to commit
+ // other changes in mPendingTransaction at this point.
+ w.handleWindowMovedIfNeeded(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
final WindowStateAnimator winAnimator = w.mWinAnimator;
}
}
final TaskStack stack = w.getStack();
- if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening())
+ if ((!winAnimator.isWaitingForOpening())
|| (stack != null && stack.isAnimatingBounds())) {
// Updates the shown frame before we set up the surface. This is needed
// because the resizing could change the top-left position (in addition to
winAnimator.computeShownFrameLocked();
}
winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
+
+ // Since setSurfaceBoundariesLocked applies the clipping, we need to apply the position
+ // to the surface of the window container as well. Use mTmpTransaction instead of
+ // mPendingTransaction to avoid committing any existing changes in there.
+ w.updateSurfacePosition(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
final AppWindowToken atoken = w.mAppToken;
forAllWindows(w -> {
if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
&& w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
- w.mWinAnimator.setAnimation(
- policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
+ w.startAnimation(policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
}
}, true /* traverseTopToBottom */);
}
}
@Override
- void destroyAfterPendingTransaction(SurfaceControl surface) {
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
mPendingDestroyingSurfaces.add(surface);
}
/**
* Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
+ * {@link #destroyAfterPendingTransaction}.
*/
void onPendingTransactionApplied() {
for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
// There might be an old window delaying the animation start - clear it.
if (mDelayedImeWin != null) {
- mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ mDelayedImeWin.endDelayingAnimationStart();
}
mDelayedImeWin = imeWin;
- imeWin.mWinAnimator.startDelayingAnimationStart();
+ imeWin.startDelayingAnimationStart();
}
// If we are already waiting for something to be drawn, clear out the old one so it
mService.mWaitingForDrawnCallback.run();
}
mService.mWaitingForDrawnCallback = () -> {
- mAnimationStartDelayed = false;
- if (mDelayedImeWin != null) {
- mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
- }
- // If the adjust status changed since this was posted, only notify
- // the new states and don't animate.
- long duration = 0;
- if (mAdjustedForIme == adjustedForIme
- && mAdjustedForDivider == adjustedForDivider) {
- duration = IME_ADJUST_ANIM_DURATION;
- } else {
- Slog.w(TAG, "IME adjust changed while waiting for drawn:"
- + " adjustedForIme=" + adjustedForIme
- + " adjustedForDivider=" + adjustedForDivider
- + " mAdjustedForIme=" + mAdjustedForIme
- + " mAdjustedForDivider=" + mAdjustedForDivider);
+ synchronized (mService.mWindowMap) {
+ mAnimationStartDelayed = false;
+ if (mDelayedImeWin != null) {
+ mDelayedImeWin.endDelayingAnimationStart();
+ }
+ // If the adjust status changed since this was posted, only notify
+ // the new states and don't animate.
+ long duration = 0;
+ if (mAdjustedForIme == adjustedForIme
+ && mAdjustedForDivider == adjustedForDivider) {
+ duration = IME_ADJUST_ANIM_DURATION;
+ } else {
+ Slog.w(TAG, "IME adjust changed while waiting for drawn:"
+ + " adjustedForIme=" + adjustedForIme
+ + " adjustedForDivider=" + adjustedForDivider
+ + " mAdjustedForIme=" + mAdjustedForIme
+ + " mAdjustedForDivider=" + mAdjustedForDivider);
+ }
+ notifyAdjustedForImeChanged(
+ mAdjustedForIme || mAdjustedForDivider, duration);
}
- notifyAdjustedForImeChanged(
- mAdjustedForIme || mAdjustedForDivider, duration);
};
} else {
notifyAdjustedForImeChanged(
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
-import android.view.animation.Transformation;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
synchronized (mLock) {
if (mPendingAnimations.containsKey(leash)) {
mPendingAnimations.remove(leash);
- // TODO: Releasing the leash is problematic if reparenting hasn't happened yet.
- // Fix with transaction
- //leash.release();
return;
}
final ValueAnimator anim = mRunningAnimations.get(leash);
SurfaceAnimationThread.getHandler().post(() -> {
anim.cancel();
applyTransaction();
- //leash.release();
});
}
}
// Animation length is already expected to be scaled.
result.overrideDurationScale(1.0f);
- result.setDuration(a.animSpec.getDuration());
+ result.setDuration(a.mAnimSpec.getDuration());
result.addUpdateListener(animation -> {
applyTransformation(a, mFrameTransaction, result.getCurrentPlayTime());
@Override
public void onAnimationStart(Animator animation) {
- mFrameTransaction.show(a.leash);
+ mFrameTransaction.show(a.mLeash);
}
@Override
@Override
public void onAnimationEnd(Animator animation) {
synchronized (mLock) {
- mRunningAnimations.remove(a.leash);
+ mRunningAnimations.remove(a.mLeash);
}
if (!mCancelled) {
// Post on other thread that we can push final state without jank.
- AnimationThread.getHandler().post(() -> {
- a.finishCallback.run();
-
- // Make sure to release the leash after finishCallback has been invoked such
- // that reparenting is done already when releasing the leash.
- a.leash.release();
- });
+ AnimationThread.getHandler().post(a.mFinishCallback);
}
}
});
result.start();
- mRunningAnimations.put(a.leash, result);
+ mRunningAnimations.put(a.mLeash, result);
}
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
- a.animSpec.apply(t, a.leash, currentPlayTime);
+ a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}
private void stepAnimation(long frameTimeNanos) {
}
private static final class RunningAnimation {
- final AnimationSpec animSpec;
- final SurfaceControl leash;
- final Runnable finishCallback;
+ final AnimationSpec mAnimSpec;
+ final SurfaceControl mLeash;
+ final Runnable mFinishCallback;
RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) {
- this.animSpec = animSpec;
- this.leash = leash;
- this.finishCallback = finishCallback;
+ mAnimSpec = animSpec;
+ mLeash = leash;
+ mFinishCallback = finishCallback;
}
}
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
cancelAnimation(t, true /* restarting */);
mAnimation = anim;
- final SurfaceControl surface = mAnimatable.getSurface();
+ final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
Slog.w(TAG, "Unable to start animation, surface is null or no children.");
cancelAnimation();
}
mLeash = createAnimationLeash(surface, t,
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
- mAnimatable.onLeashCreated(t, mLeash);
+ mAnimatable.onAnimationLeashCreated(t, mLeash);
if (mAnimationStartDelayed) {
if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
return;
* surface is reparented to the leash. This method takes care of that.
*/
void setLayer(Transaction t, int layer) {
- t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurface(), layer);
+ t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
+ }
+
+ /**
+ * Sets the surface to be relatively layered.
+ *
+ * @see #setLayer
+ */
+ void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+ t.setRelativeLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), relativeTo, layer);
}
/**
* @see #setLayer
*/
void reparent(Transaction t, SurfaceControl newParent) {
- t.reparent(mLeash != null ? mLeash : mAnimatable.getSurface(), newParent.getHandle());
+ t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent.getHandle());
}
/**
}
private void reset(Transaction t) {
- final SurfaceControl surface = mAnimatable.getSurface();
- final SurfaceControl parent = mAnimatable.getParentSurface();
+ final SurfaceControl surface = mAnimatable.getSurfaceControl();
+ final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
// If the surface was destroyed, we don't care to reparent it back.
final boolean destroy = mLeash != null && surface != null && parent != null;
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
t.reparent(surface, parent.getHandle());
}
+ if (mLeash != null) {
+ mAnimatable.destroyAfterPendingTransaction(mLeash);
+ }
mLeash = null;
mAnimation = null;
// Make sure to inform the animatable after the leash was destroyed.
if (destroy) {
- mAnimatable.onLeashDestroyed(t);
+ mAnimatable.onAnimationLeashDestroyed(t);
}
}
private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
int height, boolean hidden) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
- final SurfaceControl.Builder builder = mAnimatable.makeLeash()
+ final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
.setName(surface + " - animation-leash")
.setSize(width, height);
final SurfaceControl leash = builder.build();
* @param t The transaction to use to apply any necessary changes.
* @param leash The leash that was created.
*/
- void onLeashCreated(Transaction t, SurfaceControl leash);
+ void onAnimationLeashCreated(Transaction t, SurfaceControl leash);
/**
* Called when the leash is being destroyed, and the surface was reparented back to the
*
* @param t The transaction to use to apply any necessary changes.
*/
- void onLeashDestroyed(Transaction t);
+ void onAnimationLeashDestroyed(Transaction t);
+
+ /**
+ * Destroy a given surface after executing {@link #getPendingTransaction}.
+ *
+ * @see WindowContainer#destroyAfterPendingTransaction
+ */
+ void destroyAfterPendingTransaction(SurfaceControl surface);
/**
- * @return A new child surface.
+ * @return A new surface to be used for the animation leash, inserted at the correct
+ * position in the hierarchy.
*/
- SurfaceControl.Builder makeLeash();
+ SurfaceControl.Builder makeAnimationLeash();
/**
* @return The surface of the object to be animated.
*/
- @Nullable SurfaceControl getSurface();
+ @Nullable SurfaceControl getSurfaceControl();
/**
* @return The parent of the surface object to be animated.
*/
- @Nullable SurfaceControl getParentSurface();
+ @Nullable SurfaceControl getParentSurfaceControl();
/**
* @return The width of the surface to be animated.
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.EMPTY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
boolean shouldDeferRemoval() {
// TODO: This should probably return false if mChildren.isEmpty() regardless if the stack
// is animating...
- return hasWindowsAlive() && mStack.isAnimating();
+ return hasWindowsAlive() && mStack.isSelfOrChildAnimating();
}
@Override
@Override
void removeIfPossible() {
- if (isAnimating()) {
+ if (isSelfOrChildAnimating()) {
mDeferRemoval = true;
return;
}
/** Returns true if a removal action is still being deferred. */
boolean checkCompleteDeferredRemoval() {
- if (isAnimating()) {
+ if (isSelfOrChildAnimating()) {
return true;
}
if (mDeferRemoval) {
void startAnimation(Animation anim) {
for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
final WindowState windowState = mChildren.get(ndx);
- windowState.mWinAnimator.setAnimation(anim);
+ windowState.startAnimation(anim);
}
}
private Animation mAnimation;
private final Point mPosition = new Point();
- private final ThreadLocal<Tmp> mThreadLocalTmps = ThreadLocal.withInitial(Tmp::new);
+ private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
public WindowAnimationSpec(Animation animation, Point position) {
mAnimation = animation;
@Override
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
- final Tmp tmp = mThreadLocalTmps.get();
+ final TmpValues tmp = mThreadLocalTmps.get();
tmp.transformation.clear();
mAnimation.getTransformation(currentPlayTime, tmp.transformation);
tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
t.setAlpha(leash, tmp.transformation.getAlpha());
}
- private static class Tmp {
+ private static class TmpValues {
final Transformation transformation = new Transformation();
final float[] floats = new float[9];
}
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
import android.annotation.CallSuper;
import android.content.res.Configuration;
+import android.graphics.PixelFormat.Opacity;
+import android.util.Slog;
import android.view.MagnificationSpec;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
import android.util.Pools;
import android.util.proto.ProtoOutputStream;
+
import com.android.internal.util.ToBooleanFunction;
+import com.android.server.wm.SurfaceAnimator.Animatable;
+import java.io.PrintWriter;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.function.Consumer;
* changes are made to this class.
*/
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
- implements Comparable<WindowContainer> {
+ implements Comparable<WindowContainer>, Animatable {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
static final int POSITION_TOP = Integer.MAX_VALUE;
static final int POSITION_BOTTOM = Integer.MIN_VALUE;
* For removing or setting new parent {@link #setParent} should be used, because it also
* performs configuration updates based on new parent's settings.
*/
- private WindowContainer mParent = null;
+ private WindowContainer<WindowContainer> mParent = null;
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
new Pools.SynchronizedPool<>(3);
// The owner/creator for this container. No controller if null.
- WindowContainerController mController;
+ WindowContainerController mController;
protected SurfaceControl mSurfaceControl;
private int mLastLayer = 0;
/**
* Applied as part of the animation pass in "prepareSurfaces".
*/
- private final Transaction mPendingTransaction;
+ protected final Transaction mPendingTransaction;
+ protected final SurfaceAnimator mSurfaceAnimator;
protected final WindowManagerService mService;
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
}
@Override
return mChildren.get(index);
}
- final protected void setParent(WindowContainer parent) {
+ final protected void setParent(WindowContainer<WindowContainer> parent) {
mParent = parent;
// Removing parent usually means that we've detached this entity to destroy it or to attach
// to another parent. In both cases we don't need to update the configuration now.
if (mParent == null) {
return;
}
+
if (mSurfaceControl == null) {
// If we don't yet have a surface, but we now have a parent, we should
// build a surface.
mSurfaceControl = makeSurface().build();
getPendingTransaction().show(mSurfaceControl);
} else {
- // If we have a surface but a new parent, we just need to perform a reparent.
- getPendingTransaction().reparent(mSurfaceControl, mParent.mSurfaceControl.getHandle());
+ // If we have a surface but a new parent, we just need to perform a reparent. Go through
+ // surface animator such that hierarchy is preserved when animating, i.e.
+ // mSurfaceControl stays attached to the leash and we just reparent the leash to the
+ // new parent.
+ mSurfaceAnimator.reparent(getPendingTransaction(), mParent.mSurfaceControl);
}
// Either way we need to ask the parent to assign us a Z-order.
}
// Temp. holders for a chain of containers we are currently processing.
- private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
- private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
+ private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
+ private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
/**
* Adds the input window container has a child of this container in order based on the input
@CallSuper
void removeImmediately() {
while (!mChildren.isEmpty()) {
- final WindowContainer child = mChildren.peekLast();
+ final E child = mChildren.peekLast();
child.removeImmediately();
// Need to do this after calling remove on the child because the child might try to
// remove/detach itself from its parent which will cause an exception if we remove
}
}
- boolean isAnimating() {
+ /**
+ * @return Whether our own container is running an animation or any child, no matter how deep in
+ * the hierarchy, is animating.
+ */
+ boolean isSelfOrChildAnimating() {
+ if (isSelfAnimating()) {
+ return true;
+ }
for (int j = mChildren.size() - 1; j >= 0; j--) {
final WindowContainer wc = mChildren.get(j);
- if (wc.isAnimating()) {
+ if (wc.isSelfOrChildAnimating()) {
return true;
}
}
return false;
}
+ /**
+ * @return Whether our own container is running an animation or our parent is animating. This
+ * doesn't consider whether children are animating.
+ */
+ boolean isAnimating() {
+
+ // We are animating if we ourselves are animating or if our parent is animating.
+ return isSelfAnimating() || mParent != null && mParent.isAnimating();
+ }
+
+ /**
+ * @return Whether our own container running an animation at the moment.
+ */
+ boolean isSelfAnimating() {
+ return mSurfaceAnimator.isAnimating();
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
.setParent(mSurfaceControl);
}
+ @Override
+ public SurfaceControl getParentSurfaceControl() {
+ final WindowContainer parent = getParent();
+ if (parent == null) {
+ return null;
+ }
+ return parent.getSurfaceControl();
+ }
+
/**
* @return Whether this WindowContainer should be magnified by the accessibility magnifier.
*/
void assignLayer(Transaction t, int layer) {
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
if (mSurfaceControl != null && changed) {
- t.setLayer(mSurfaceControl, layer);
+
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setLayer(t, layer);
mLastLayer = layer;
mLastRelativeToLayer = null;
}
void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
if (mSurfaceControl != null && changed) {
- t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
+
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
mLastLayer = layer;
mLastRelativeToLayer = relativeTo;
}
}
}
- SurfaceControl getSurfaceControl() {
+ @Override
+ public SurfaceControl getSurfaceControl() {
return mSurfaceControl;
}
* rather than an intentional design, so please take care when
* expanding use.
*/
- void destroyAfterPendingTransaction(SurfaceControl surface) {
+ @Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
if (mParent != null) {
mParent.destroyAfterPendingTransaction(surface);
}
}
-
- Transaction getPendingTransaction() {
+
+ @Override
+ public Transaction getPendingTransaction() {
return mPendingTransaction;
}
+
+ /**
+ * Starts an animation on the container.
+ *
+ * @param anim The animation to run.
+ * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
+ * some point but the meaning is too weird to work for all containers.
+ */
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+ if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
+
+ // TODO: This should use isVisible() but because isVisible has a really weird meaning at
+ // the moment this doesn't work for all animatable window containers.
+ mSurfaceAnimator.startAnimation(t, anim, hidden);
+ }
+
+ void cancelAnimation() {
+ mSurfaceAnimator.cancelAnimation();
+ }
+
+ @Override
+ public Builder makeAnimationLeash() {
+ return makeSurface();
+ }
+
+ @Override
+ public void commitPendingTransaction() {
+ scheduleAnimation();
+ }
+
+ private void reassignLayer(Transaction t) {
+ final WindowContainer parent = getParent();
+ if (parent != null) {
+ parent.assignChildLayers(t);
+ }
+ }
+
+ @Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ reassignLayer(t);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ reassignLayer(t);
+ }
+
+ /**
+ * Called when an animation has finished running.
+ */
+ protected void onAnimationFinished() {
+ }
+
+ /**
+ * @return The currently running animation, if any, or {@code null} otherwise.
+ */
+ AnimationAdapter getAnimation() {
+ return mSurfaceAnimator.getAnimation();
+ }
+
+ /**
+ * @see SurfaceAnimator#startDelayingAnimationStart
+ */
+ void startDelayingAnimationStart() {
+ mSurfaceAnimator.startDelayingAnimationStart();
+ }
+
+ /**
+ * @see SurfaceAnimator#endDelayingAnimationStart
+ */
+ void endDelayingAnimationStart() {
+ mSurfaceAnimator.endDelayingAnimationStart();
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return mSurfaceControl.getWidth();
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return mSurfaceControl.getHeight();
+ }
+
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ if (mSurfaceAnimator.isAnimating()) {
+ pw.print(prefix); pw.println("ContainerAnimator:");
+ mSurfaceAnimator.dump(pw, prefix + " ");
+ }
+ }
}
}
}
- boolean mAnimateWallpaperWithTarget;
-
// TODO: Move to RootWindowContainer
AppWindowToken mFocusedApp = null;
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = isDefaultDisplay;
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else if (win.mWinAnimator.isAnimationSet()) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
win.mAnimatingExit = true;
- win.mWinAnimator.mAnimating = true;
} else {
if (mInputMethodWindow == win) {
setInputMethodWindowLocked(null);
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.SurfaceControl.Transaction;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.SurfaceControl.Transaction;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.view.ViewTreeObserver;
import android.view.WindowInfo;
import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputWindowHandle;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
*/
private boolean mDrawnStateEvaluated;
+ private final Point mSurfacePosition = new Point();
+
/**
* Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
* of z-order and 1 otherwise.
final AppWindowToken atoken = mAppToken;
if (atoken != null) {
return ((!isParentWindowHidden() && !atoken.hiddenRequested)
- || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
+ || mWinAnimator.isAnimationSet() || atoken.mAppAnimator.animation != null);
}
- return !isParentWindowHidden() || mWinAnimator.mAnimation != null;
+ return !isParentWindowHidden() || mWinAnimator.isAnimationSet();
}
/**
}
return mHasSurface && mPolicyVisibility && !mDestroying
&& ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
- || mWinAnimator.mAnimation != null
+ || mWinAnimator.isAnimationSet()
|| ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
}
// started.
final boolean appAnimationStarting = mAppToken != null
&& mAppToken.mAppAnimator.isAnimationStarting();
- final boolean exitingSelf = mAnimatingExit && (!mWinAnimator.isAnimationStarting()
- && !appAnimationStarting);
+ final boolean exitingSelf = mAnimatingExit && !appAnimationStarting;
final boolean appExiting = mAppToken != null && mAppToken.hidden && !appAnimationStarting;
final boolean exiting = exitingSelf || mDestroying || appExiting;
return isDrawnLw() && mPolicyVisibility
&& ((!isParentWindowHidden() &&
(atoken == null || !atoken.hiddenRequested))
- || mWinAnimator.mAnimating
+ || mWinAnimator.isAnimationSet()
|| (atoken != null && atoken.mAppAnimator.animation != null));
}
*/
@Override
public boolean isAnimatingLw() {
- return mWinAnimator.mAnimation != null
+ return mWinAnimator.isAnimationSet()
|| (mAppToken != null && mAppToken.mAppAnimator.animation != null);
}
// to determine if it's occluding apps.
return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
|| (mIsWallpaper && mWallpaperVisible))
- && isDrawnLw() && mWinAnimator.mAnimation == null
+ && isDrawnLw() && !mWinAnimator.isAnimationSet()
&& (mAppToken == null || mAppToken.mAppAnimator.animation == null);
}
* listeners and optionally animate it. Simply checking a change of position is not enough,
* because being move due to dock divider is not a trigger for animation.
*/
- void handleWindowMovedIfNeeded() {
+ void handleWindowMovedIfNeeded(Transaction t) {
if (!hasMoved()) {
return;
}
&& !isDragResizing() && !adjustedForMinimizedDockOrIme
&& getWindowConfiguration().hasMovementAnimations()
&& !mWinAnimator.mLastHidden) {
- mWinAnimator.setMoveAnimation(left, top);
+ startMoveAnimation(t, left, top);
}
//TODO (multidisplay): Accessibility supported only for the default display.
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
- + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
+ + mPolicyVisibility + " isAnimationSet=" + mWinAnimator.isAnimationSet());
if (!mToken.okToAnimate()) {
doAnimation = false;
- } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
+ } else if (mPolicyVisibility && !mWinAnimator.isAnimationSet()) {
// Check for the case where we are currently visible and
// not animating; we do not want to do animation at such a
// point to become visible when we already are.
}
if (doAnimation) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
- if (mWinAnimator.mAnimation == null) {
+ if (!mWinAnimator.isAnimationSet()) {
doAnimation = false;
}
}
return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
}
- @Override
- boolean isAnimating() {
- if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
- return true;
- }
- return super.isAnimating();
- }
-
void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
animators.add(mWinAnimator);
proto.end(token);
}
+ @Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final TaskStack stack = getStack();
pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
pw.print(" cutout=" + mLastDisplayCutout);
pw.println();
}
+ super.dump(pw, prefix, dumpAll);
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
mWinAnimator.dump(pw, prefix + " ", dumpAll);
if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
@Override
String getName() {
return Integer.toHexString(System.identityHashCode(this))
- + " " + getWindowTag();
+ + " " + getWindowTag();
}
CharSequence getWindowTag() {
+ " tok.hiddenRequested="
+ (mAppToken != null && mAppToken.hiddenRequested)
+ " tok.hidden=" + (mAppToken != null && mAppToken.hidden)
- + " animating=" + mWinAnimator.mAnimating
+ + " animationSet=" + mWinAnimator.isAnimationSet()
+ " tok animating="
+ (mWinAnimator.mAppAnimator != null && mWinAnimator.mAppAnimator.animating)
+ " Callers=" + Debug.getCallers(4));
return null;
}
- boolean isWindowAnimationSet() {
- if (mWinAnimator.isWindowAnimationSet()) {
- return true;
- }
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- if (c.isWindowAnimationSet()) {
- return true;
- }
- }
- return false;
- }
-
void onExitAnimationDone() {
if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
+ ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
- + " windowAnimating=" + mWinAnimator.isWindowAnimationSet());
+ + " selfAnimating=" + isSelfAnimating());
if (!mChildren.isEmpty()) {
// Copying to a different list as multiple children can be removed.
}
}
- if (!mWinAnimator.isWindowAnimationSet()) {
- //TODO (multidisplay): Accessibility is supported only for the default display.
- if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
- mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
- }
+ if (isSelfAnimating()) {
+ return;
}
- if (!mAnimatingExit) {
- return;
+ //TODO (multidisplay): Accessibility is supported only for the default display.
+ if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
- if (mWinAnimator.isWindowAnimationSet()) {
+ if (!mAnimatingExit) {
return;
}
mAnimatingExit = false;
didSomething = true;
}
- if (mWinAnimator.mAnimating) {
- mWinAnimator.mAnimating = false;
- didSomething = true;
- }
if (mDestroying) {
mDestroying = false;
mService.mDestroySurface.remove(this);
+ " mDrawState=" + mWinAnimator.mDrawState
+ " ph=" + isParentWindowHidden()
+ " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
- + " a=" + mWinAnimator.mAnimating);
+ + " a=" + mWinAnimator.isAnimationSet());
}
}
mLastDisplayCutout = mDisplayCutout;
}
+ void startAnimation(Animation anim) {
+ final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+ anim.initialize(mFrame.width(), mFrame.height(),
+ displayInfo.appWidth, displayInfo.appHeight);
+ anim.restrictDuration(MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new WindowAnimationSpec(anim, mSurfacePosition), mService.mSurfaceAnimationRunner);
+ startAnimation(mPendingTransaction, adapter);
+ commitPendingTransaction();
+ }
+
+ private void startMoveAnimation(Transaction t, int left, int top) {
+ if (DEBUG_ANIM) Slog.v(TAG, "Setting move animation on " + this);
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new MoveAnimationSpec(mLastFrame.left, mLastFrame.top, left, top),
+ mService.mSurfaceAnimationRunner);
+ startAnimation(t, adapter);
+ }
+
+ private void startAnimation(Transaction t, AnimationAdapter adapter) {
+ startAnimation(t, adapter, mWinAnimator.mLastHidden);
+ }
+
+ @Override
+ protected void onAnimationFinished() {
+ mWinAnimator.onAnimationFinished();
+ }
+
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
// access to its windows children. Need to investigate re-writing
// {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
return getAnimLayerAdjustment() > 0 || mWillReplaceWindow;
}
- @Override
- SurfaceControl.Builder makeSurface() {
- return getParent().makeChildSurface(this);
- }
-
private void applyDims(Dimmer dimmer) {
if (!mAnimatingExit && mAppDied) {
mIsDimming = true;
applyDims(dimmer);
}
+ updateSurfacePosition(mPendingTransaction);
+
mWinAnimator.prepareSurfaceLocked(true);
super.prepareSurfaces();
}
@Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ super.onAnimationLeashCreated(t, leash);
+
+ // Leash is now responsible for position, so set our position to 0.
+ t.setPosition(mSurfaceControl, 0, 0);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ super.onAnimationLeashDestroyed(t);
+ updateSurfacePosition(t);
+ }
+
+ void updateSurfacePosition(Transaction t) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+
+ int left = mFrame.left;
+ int top = mFrame.top;
+ if (isChildWindow()) {
+ // TODO: This probably falls apart at some point and we should
+ // actually compute relative coordinates.
+ final WindowState parent = getParentWindow();
+ left -= parent.mFrame.left;
+ top -= parent.mFrame.top;
+ }
+ mSurfacePosition.set(left, top);
+ if (!mSurfaceAnimator.hasLeash()) {
+ t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ }
+ }
+
+ @Override
void assignLayer(Transaction t, int layer) {
// See comment in assignRelativeLayerForImeTargetChild
if (!isChildWindow()
layer++;
}
}
+
+ private final class MoveAnimationSpec implements AnimationSpec {
+
+ private final long mDuration;
+ private Interpolator mInterpolator;
+ private Point mFrom = new Point();
+ private Point mTo = new Point();
+
+ private MoveAnimationSpec(int fromX, int fromY, int toX, int toY) {
+ final Animation anim = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.window_move_from_decor);
+ mDuration = anim.computeDurationHint();
+ mInterpolator = anim.getInterpolator();
+ mFrom.set(fromX, fromY);
+ mTo.set(toX, toY);
+ }
+
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+ final float fraction = (float) currentPlayTime / getDuration();
+ final float v = mInterpolator.getInterpolation(fraction);
+ t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v,
+ mFrom.y + (mTo.y - mFrom.y) * v);
+ }
+ }
}
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import com.android.server.policy.WindowManagerPolicy;
-import java.io.PrintWriter;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* Keep track of animations and surface operations for a single WindowState.
final boolean mIsWallpaper;
private final WallpaperController mWallpaperControllerLocked;
- // Currently running animation.
- boolean mAnimating;
- boolean mLocalAnimating;
- Animation mAnimation;
boolean mAnimationIsEntrance;
- boolean mHasTransformation;
- boolean mHasLocalTransformation;
- final Transformation mTransformation = new Transformation();
- boolean mWasAnimating; // Were we animating going into the most recent animation step?
int mAnimLayer;
int mLastLayer;
- long mAnimationStartTime;
- long mLastAnimationTime;
- int mStackClip = STACK_CLIP_BEFORE_ANIM;
/**
* Set when we have changed the size of the surface, to know that
private final Rect mSystemDecorRect = new Rect();
private final Rect mLastSystemDecorRect = new Rect();
- // Used to save animation distances between the time they are calculated and when they are used.
- private int mAnimDx;
- private int mAnimDy;
-
- /** Is the next animation to be started a window move animation? */
- private boolean mAnimateMove = false;
-
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
private float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
int mAttrType;
- static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
-
boolean mForceScaleUntilResize;
// WindowState.mHScale and WindowState.mVScale contain the
mAnimator = service.mAnimator;
mPolicy = service.mPolicy;
mContext = service.mContext;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- mAnimDx = displayInfo.appWidth;
- mAnimDy = displayInfo.appHeight;
- } else {
- Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
- // This is checked on return and dealt with.
- }
mWin = win;
mParentWinAnimator = !win.isChildWindow() ? null : win.getParentWindow().mWinAnimator;
mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
}
- public void setAnimation(Animation anim, long startTime, int stackClip) {
- if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
- mAnimating = false;
- mLocalAnimating = false;
- mAnimation = anim;
- mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
- mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
- // Start out animation gone if window is gone, or visible if window is visible.
- mTransformation.clear();
- mTransformation.setAlpha(mLastHidden ? 0 : 1);
- mHasLocalTransformation = true;
- mAnimationStartTime = startTime;
- mStackClip = stackClip;
- }
-
- public void setAnimation(Animation anim, int stackClip) {
- setAnimation(anim, -1, stackClip);
- }
-
- public void setAnimation(Animation anim) {
- setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
- }
-
- public void clearAnimation() {
- if (mAnimation != null) {
- mAnimating = true;
- mLocalAnimating = false;
- mAnimation.cancel();
- mAnimation = null;
- mStackClip = STACK_CLIP_BEFORE_ANIM;
- }
- }
-
/**
* Is the window or its container currently set to animate or currently animating?
*/
boolean isAnimationSet() {
- return mAnimation != null
- || (mParentWinAnimator != null && mParentWinAnimator.mAnimation != null)
- || (mAppAnimator != null && mAppAnimator.isAnimating());
- }
-
- /**
- * @return whether an animation is about to start, i.e. the animation is set already but we
- * haven't processed the first frame yet.
- */
- boolean isAnimationStarting() {
- return isAnimationSet() && !mAnimating;
+ return mWin.isAnimating();
}
/** Is the window animating the DummyAnimation? */
}
/**
- * Is this window currently set to animate or currently animating?
- */
- boolean isWindowAnimationSet() {
- return mAnimation != null;
- }
-
- /**
* Is this window currently waiting to run an opening animation?
*/
boolean isWaitingForOpening() {
if (DEBUG_ANIM) Slog.d(TAG,
"cancelExitAnimationForNextAnimationLocked: " + mWin);
- if (mAnimation != null) {
- mAnimation.cancel();
- mAnimation = null;
- mLocalAnimating = false;
- mWin.destroySurfaceUnchecked();
- }
+ mWin.cancelAnimation();
+ mWin.destroySurfaceUnchecked();
}
- private boolean stepAnimation(long currentTime) {
- if ((mAnimation == null) || !mLocalAnimating) {
- return false;
- }
- currentTime = getAnimationFrameTime(mAnimation, currentTime);
- mTransformation.clear();
- final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
- if (mAnimationStartDelayed && mAnimationIsEntrance) {
- mTransformation.setAlpha(0f);
- }
- if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
- + ", xform=" + mTransformation);
- return more;
- }
-
- // This must be called while inside a transaction. Returns true if
- // there is more animation to run.
- boolean stepAnimationLocked(long currentTime) {
- // Save the animation state as it was before this step so WindowManagerService can tell if
- // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
- mWasAnimating = mAnimating;
- final DisplayContent displayContent = mWin.getDisplayContent();
- if (mWin.mToken.okToAnimate()) {
- // We will run animations as long as the display isn't frozen.
-
- if (mWin.isDrawnLw() && mAnimation != null) {
- mHasTransformation = true;
- mHasLocalTransformation = true;
- if (!mLocalAnimating) {
- if (DEBUG_ANIM) Slog.v(
- TAG, "Starting animation in " + this +
- " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
- " wh=" + mWin.mFrame.height() +
- " dx=" + mAnimDx + " dy=" + mAnimDy +
- " scale=" + mService.getWindowAnimationScaleLocked());
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (mAnimateMove) {
- mAnimateMove = false;
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
- mAnimDx, mAnimDy);
- } else {
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
- displayInfo.appWidth, displayInfo.appHeight);
- }
- mAnimDx = displayInfo.appWidth;
- mAnimDy = displayInfo.appHeight;
- mAnimation.setStartTime(mAnimationStartTime != -1
- ? mAnimationStartTime
- : currentTime);
- mLocalAnimating = true;
- mAnimating = true;
- }
- if ((mAnimation != null) && mLocalAnimating) {
- mLastAnimationTime = currentTime;
- if (stepAnimation(currentTime)) {
- return true;
- }
- }
- if (DEBUG_ANIM) Slog.v(
- TAG, "Finished animation in " + this +
- " @ " + currentTime);
- //WindowManagerService.this.dump();
- }
- mHasLocalTransformation = false;
- if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null
- && mAppAnimator.animation != null) {
- // When our app token is animating, we kind-of pretend like
- // we are as well. Note the mLocalAnimating mAnimationIsEntrance
- // part of this check means that we will only do this if
- // our window is not currently exiting, or it is not
- // locally animating itself. The idea being that one that
- // is exiting and doing a local animation should be removed
- // once that animation is done.
- mAnimating = true;
- mHasTransformation = true;
- mTransformation.clear();
- return false;
- } else if (mHasTransformation) {
- // Little trick to get through the path below to act like
- // we have finished an animation.
- mAnimating = true;
- } else if (isAnimationSet()) {
- mAnimating = true;
- }
- } else if (mAnimation != null) {
- // If the display is frozen, and there is a pending animation,
- // clear it and make sure we run the cleanup code.
- mAnimating = true;
- }
-
- if (!mAnimating && !mLocalAnimating) {
- return false;
- }
-
+ void onAnimationFinished() {
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
- TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
- + ", reportedVisible="
- + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
+ TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
+ + ", reportedVisible="
+ + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
- mAnimating = false;
- mLocalAnimating = false;
- if (mAnimation != null) {
- mAnimation.cancel();
- mAnimation = null;
- }
if (mAnimator.mWindowDetachedWallpaper == mWin) {
mAnimator.mWindowDetachedWallpaper = null;
}
- mAnimLayer = mWin.getSpecialWindowAnimLayerAdjustment();
- if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
- mHasTransformation = false;
- mHasLocalTransformation = false;
- mStackClip = STACK_CLIP_BEFORE_ANIM;
+
mWin.checkPolicyVisibilityChange();
- mTransformation.clear();
+ final DisplayContent displayContent = mWin.getDisplayContent();
if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
// Upon completion of a not-visible to visible status bar animation a relayout is
// required.
mWin.onExitAnimationDone();
final int displayId = mWin.getDisplayId();
- mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+ int pendingLayoutChanges = FINISH_LAYOUT_REDO_ANIM;
+ if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) {
+ pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ mAnimator.setPendingLayoutChanges(displayId, pendingLayoutChanges);
if (DEBUG_LAYOUT_REPEATS)
mService.mWindowPlacerLocked.debugLayoutRepeats(
"WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
if (mWin.mAppToken != null) {
mWin.mAppToken.updateReportedVisibilityLocked();
}
-
- return false;
}
void hide(String reason) {
}
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
- attrs.getTitle().toString(),
- width, height, format, flags, this, windowType, ownerUid);
+ attrs.getTitle().toString(), width, height, format, flags, this,
+ windowType, ownerUid);
mSurfaceFormat = format;
w.setHasSurface(true);
}
void computeShownFrameLocked() {
- final boolean selfTransformation = mHasLocalTransformation;
Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
? mAppAnimator.transformation : null;
- Transformation wallpaperTargetTransformation = null;
-
- // Wallpapers are animated based on the "real" window they
- // are currently targeting.
- final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
- if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
- final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
- if (wallpaperAnimator.mHasLocalTransformation &&
- wallpaperAnimator.mAnimation != null &&
- !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
- wallpaperTargetTransformation = wallpaperAnimator.mTransformation;
- if (DEBUG_WALLPAPER && wallpaperTargetTransformation != null) {
- Slog.v(TAG, "WP target attached xform: " + wallpaperTargetTransformation);
- }
- }
- final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
- null : wallpaperTarget.mAppToken.mAppAnimator;
- if (wpAppAnimator != null && wpAppAnimator.hasTransformation
- && wpAppAnimator.animation != null
- && !wpAppAnimator.animation.getDetachWallpaper()) {
- appTransformation = wpAppAnimator.transformation;
- if (DEBUG_WALLPAPER && appTransformation != null) {
- Slog.v(TAG, "WP target app xform: " + appTransformation);
- }
- }
- }
final int displayId = mWin.getDisplayId();
final ScreenRotationAnimation screenRotationAnimation =
screenRotationAnimation != null && screenRotationAnimation.isAnimating();
mHasClipRect = false;
- if (selfTransformation || wallpaperTargetTransformation != null
- || appTransformation != null || screenAnimation) {
+ if (appTransformation != null || screenAnimation) {
// cache often used attributes locally
final Rect frame = mWin.mFrame;
final float tmpFloats[] = mService.mTmpFloats;
tmpMatrix.reset();
}
tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
- if (selfTransformation) {
- tmpMatrix.postConcat(mTransformation.getMatrix());
- }
- if (wallpaperTargetTransformation != null) {
- tmpMatrix.postConcat(wallpaperTargetTransformation.getMatrix());
- }
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
- int left = frame.left;
- int top = frame.top;
- if (mWin.isChildWindow()) {
- WindowState parent = mWin.getParentWindow();
- left -= parent.mFrame.left;
- top -= parent.mFrame.top;
- }
+ tmpMatrix.postTranslate(mWin.mXOffset, mWin.mYOffset);
- // The translation that applies the position of the window needs to be applied at the
- // end in case that other translations include scaling. Otherwise the scaling will
- // affect this translation. But it needs to be set before the screen rotation animation
- // so the pivot point is at the center of the screen for all windows.
- tmpMatrix.postTranslate(left + mWin.mXOffset, top + mWin.mYOffset);
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
&& x == frame.left && y == frame.top))) {
//Slog.i(TAG_WM, "Applying alpha transform");
- if (selfTransformation) {
- mShownAlpha *= mTransformation.getAlpha();
- }
- if (wallpaperTargetTransformation != null) {
- mShownAlpha *= wallpaperTargetTransformation.getAlpha();
- }
if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha();
if (appTransformation.hasClipRect()) {
if ((DEBUG_ANIM || WindowManagerService.localLOGV)
&& (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
- + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
- + " attached=" + (wallpaperTargetTransformation == null ?
- "null" : wallpaperTargetTransformation.getAlpha())
+ " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
+ " screen=" + (screenAnimation ?
screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
TAG, "computeShownFrameLocked: " + this +
" not attached, mAlpha=" + mAlpha);
- mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
- if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
- mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
- }
+ mWin.mShownPosition.set(mWin.mXOffset, mWin.mYOffset);
mShownAlpha = mAlpha;
mHaveMatrix = false;
mDsDx = mWin.mGlobalScale;
if (mAppAnimator != null && mAppAnimator.animation != null) {
return mAppAnimator.getStackClip();
} else {
- return mStackClip;
+ return STACK_CLIP_AFTER_ANIM;
}
}
if (mSurfaceResized) {
mReportSurfaceResized = true;
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
+ FINISH_LAYOUT_REDO_WALLPAPER);
}
}
// Run another pass through performLayout to set mHasContent in the
// LogicalDisplay.
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+ FINISH_LAYOUT_REDO_ANIM);
} else {
w.setOrientationChanging(false);
}
* @return true if an animation has been loaded.
*/
boolean applyAnimationLocked(int transit, boolean isEntrance) {
- if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
+ if (mWin.isSelfAnimating() && mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
return true;
}
+ if (isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ mWin.getDisplayContent().adjustForImeIfNeeded();
+ mWin.setDisplayLayoutNeeded();
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
+ " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
- setAnimation(a);
+ mWin.startAnimation(a);
mAnimationIsEntrance = isEntrance;
}
} else {
- clearAnimation();
+ mWin.cancelAnimation();
}
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ if (!isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
mWin.getDisplayContent().adjustForImeIfNeeded();
- if (isEntrance) {
- mWin.setDisplayLayoutNeeded();
- mService.mWindowPlacerLocked.requestTraversal();
- }
}
- return mAnimation != null;
- }
- private void applyFadeoutDuringKeyguardExitAnimation() {
- long startTime = mAnimation.getStartTime();
- long duration = mAnimation.getDuration();
- long elapsed = mLastAnimationTime - startTime;
- long fadeDuration = duration - elapsed;
- if (fadeDuration <= 0) {
- // Never mind, this would be no visible animation, so abort the animation change.
- return;
- }
- AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
- newAnimation.setDuration(duration);
- newAnimation.setStartTime(startTime);
- newAnimation.addAnimation(mAnimation);
- Animation fadeOut = AnimationUtils.loadAnimation(
- mContext, com.android.internal.R.anim.app_starting_exit);
- fadeOut.setDuration(fadeDuration);
- fadeOut.setStartOffset(elapsed);
- newAnimation.addAnimation(fadeOut);
- newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDx, mAnimDy);
- mAnimation = newAnimation;
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ return isAnimationSet();
}
void writeToProto(ProtoOutputStream proto, long fieldId) {
}
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
- if (mAnimating || mLocalAnimating || mAnimationIsEntrance
- || mAnimation != null) {
- pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
- pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
- pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
- pw.print(" mAnimation="); pw.print(mAnimation);
- pw.print(" mStackClip="); pw.println(mStackClip);
- }
- if (mHasTransformation || mHasLocalTransformation) {
- pw.print(prefix); pw.print("XForm: has=");
- pw.print(mHasTransformation);
- pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
- pw.print(" "); mTransformation.printShortString(pw);
- pw.println();
+ if (mAnimationIsEntrance) {
+ pw.print(prefix); pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
}
if (mSurfaceController != null) {
mSurfaceController.dump(pw, prefix, dumpAll);
}
}
- void setMoveAnimation(int left, int top) {
- final Animation a = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.window_move_from_decor);
- setAnimation(a);
- mAnimDx = mWin.mLastFrame.left - left;
- mAnimDy = mWin.mLastFrame.top - top;
- mAnimateMove = true;
- }
-
- void deferTransactionUntilParentFrame(long frameNumber) {
- if (!mWin.isChildWindow()) {
- return;
- }
- mSurfaceController.deferTransactionUntil(
- mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(), frameNumber);
- }
-
- /**
- * Sometimes we need to synchronize the first frame of animation with some external event.
- * To achieve this, we prolong the start of the animation and keep producing the first frame of
- * the animation.
- */
- private long getAnimationFrameTime(Animation animation, long currentTime) {
- if (mAnimationStartDelayed) {
- animation.setStartTime(currentTime);
- return currentTime + 1;
- }
- return currentTime;
- }
-
- void startDelayingAnimationStart() {
- mAnimationStartDelayed = true;
- }
-
- void endDelayingAnimationStart() {
- mAnimationStartDelayed = false;
- }
-
void seamlesslyRotateWindow(int oldRotation, int newRotation) {
final WindowState w = mWin;
if (!w.isVisibleNow() || w.mIsWallpaper) {
mSurfaceController.detachChildren();
}
}
+
+ int getLayer() {
+ return mLastLayer;
+ }
}
private boolean mSurfaceShown = false;
private float mSurfaceX = 0;
private float mSurfaceY = 0;
- private float mSurfaceW = 0;
- private float mSurfaceH = 0;
+ private int mSurfaceW = 0;
+ private int mSurfaceH = 0;
// Initialize to the identity matrix.
private float mLastDsdx = 1;
return mSurfaceY;
}
- float getWidth() {
+ int getWidth() {
return mSurfaceW;
}
- float getHeight() {
+ int getHeight() {
return mSurfaceH;
}
appAnimator.setNullAnimation();
// TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
// animating?
+ wtoken.setAllAppWinAnimators();
wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
// setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is
+ ", oldWallpaper=" + oldWallpaper
+ ", openingApps=" + openingApps
+ ", closingApps=" + closingApps);
- mService.mAnimateWallpaperWithTarget = false;
+
if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
transit = TRANSIT_WALLPAPER_OPEN;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
+ AppTransition.appTransitionToString(transit));
- } else {
- mService.mAnimateWallpaperWithTarget = true;
}
}
return transit;
}
@Override
- SurfaceControl getSurfaceControl() {
+ public SurfaceControl getSurfaceControl() {
return mControl;
}
@Override
- SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getPendingTransaction() {
return mTransaction;
}
}
}
@Override
- SurfaceControl getSurfaceControl() {
+ public SurfaceControl getSurfaceControl() {
return mHostControl;
}
@Override
- SurfaceControl.Transaction getPendingTransaction() {
+ public SurfaceControl.Transaction getPendingTransaction() {
return mHostTransaction;
}
}
@Before
public void setUp() throws Exception {
super.setUp();
-
mHost = new MockSurfaceBuildingContainer();
+
mTransaction = mock(SurfaceControl.Transaction.class);
mDimmer = new Dimmer(mHost);
}
/**
* Test class for {@link SurfaceAnimationRunner}.
*
- * runtest frameworks-services -c com.android.server.wm.SurfaceAnimationRunnerTest
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
*/
@SmallTest
@Presubmit
@Test
public void testCancel_notStarted() throws Exception {
- mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(),
+ mMockTransaction);
mSurfaceAnimationRunner
.startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
this::finishedCallback);
waitUntilHandlersIdle();
assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
assertFinishCallbackNotCalled();
- //verify(mMockSurface).release();
}
@Test
public void testCancel_running() throws Exception {
- mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+ mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(),
+ mMockTransaction);
mSurfaceAnimationRunner
.startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
this::finishedCallback);
assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
waitUntilHandlersIdle();
assertFinishCallbackNotCalled();
- //verify(mMockSurface).release();
}
private void waitUntilNextFrame() throws Exception {
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
-import com.google.android.collect.Lists;
-
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
/**
* Test class for {@link SurfaceAnimatorTest}.
*
- * runtest frameworks-services -c com.android.server.wm.SurfaceAnimatorTest
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest
*/
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class SurfaceAnimatorTest extends WindowTestsBase {
- @Mock
- AnimationAdapter mSpec;
- @Mock
- AnimationAdapter mSpec2;
+ @Mock AnimationAdapter mSpec;
+ @Mock AnimationAdapter mSpec2;
@Mock Transaction mTransaction;
- private SurfaceAnimator mSurfaceAnimator;
- private SurfaceControl mParent;
- private SurfaceControl mSurface;
- private boolean mFinishedCallbackCalled;
- private SurfaceControl mLeash;
private SurfaceSession mSession = new SurfaceSession();
-
- private final Animatable mAnimatable = new Animatable() {
- @Override
- public Transaction getPendingTransaction() {
- return mTransaction;
- }
-
- @Override
- public void commitPendingTransaction() {
- }
-
- @Override
- public void onLeashCreated(Transaction t, SurfaceControl leash) {
- }
-
- @Override
- public void onLeashDestroyed(Transaction t) {
- }
-
- @Override
- public Builder makeLeash() {
- return new SurfaceControl.Builder(mSession) {
-
- @Override
- public SurfaceControl build() {
- mLeash = super.build();
- return mLeash;
- }
- }.setParent(mParent);
- }
-
- @Override
- public SurfaceControl getSurface() {
- return mSurface;
- }
-
- @Override
- public SurfaceControl getParentSurface() {
- return mParent;
- }
-
- @Override
- public int getSurfaceWidth() {
- return 1;
- }
-
- @Override
- public int getSurfaceHeight() {
- return 1;
- }
- };
-
- private final Runnable mFinishedCallback = () -> {
- mFinishedCallbackCalled = true;
- };
+ private MyAnimatable mAnimatable;
@Before
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
- mParent = sWm.makeSurfaceBuilder(mSession)
- .setName("test surface parent")
- .setSize(3000, 3000)
- .build();
- mSurface = sWm.makeSurfaceBuilder(mSession)
- .setName("test surface")
- .setSize(1, 1)
- .build();
- mFinishedCallbackCalled = false;
- mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(mAnimatable, mFinishedCallback, sWm);
+ mAnimatable = new MyAnimatable();
}
@Test
public void testRunAnimation() throws Exception {
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
- assertTrue(mSurfaceAnimator.isAnimating());
- assertNotNull(mSurfaceAnimator.getAnimation());
- verify(mTransaction).reparent(eq(mSurface), eq(mLeash.getHandle()));
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash.getHandle()));
verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec);
- assertFalse(mSurfaceAnimator.isAnimating());
- assertNull(mSurfaceAnimator.getAnimation());
- assertTrue(mFinishedCallbackCalled);
-
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNull(mAnimatable.mSurfaceAnimator.getAnimation());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@Test
public void testOverrideAnimation() throws Exception {
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ final SurfaceControl firstLeash = mAnimatable.mLeash;
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
- assertFalse(mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ assertFalse(mAnimatable.mFinishedCallbackCalled);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
- assertTrue(mSurfaceAnimator.isAnimating());
- assertNotNull(mSurfaceAnimator.getAnimation());
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
// First animation was finished, but this shouldn't cancel the second animation
callbackCaptor.getValue().onAnimationFinished(mSpec);
- assertTrue(mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
// Second animation was finished
verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
callbackCaptor.getValue().onAnimationFinished(mSpec2);
- assertFalse(mSurfaceAnimator.isAnimating());
- assertTrue(mFinishedCallbackCalled);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
}
@Test
public void testCancelAnimation() throws Exception {
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- assertTrue(mSurfaceAnimator.isAnimating());
- mSurfaceAnimator.cancelAnimation();
- assertFalse(mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.cancelAnimation();
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
verify(mSpec).onAnimationCancelled(any());
- assertTrue(mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
}
@Test
public void testDelayingAnimationStart() throws Exception {
- mSurfaceAnimator.startDelayingAnimationStart();
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
verifyZeroInteractions(mSpec);
- assertTrue(mSurfaceAnimator.isAnimating());
- mSurfaceAnimator.endDelayingAnimationStart();
+ assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+ mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
verify(mSpec).startAnimation(any(), any(), any());
}
@Test
public void testDelayingAnimationStartAndCancelled() throws Exception {
- mSurfaceAnimator.startDelayingAnimationStart();
- mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
- mSurfaceAnimator.cancelAnimation();
+ mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.cancelAnimation();
verifyZeroInteractions(mSpec);
- assertFalse(mSurfaceAnimator.isAnimating());
- assertTrue(mFinishedCallbackCalled);
+ assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+ assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ }
+
+ private class MyAnimatable implements Animatable {
+
+ final SurfaceControl mParent;
+ final SurfaceControl mSurface;
+ final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
+ final SurfaceAnimator mSurfaceAnimator;
+ SurfaceControl mLeash;
+ boolean mFinishedCallbackCalled;
+
+ MyAnimatable() {
+ mParent = sWm.makeSurfaceBuilder(mSession)
+ .setName("test surface parent")
+ .setSize(3000, 3000)
+ .build();
+ mSurface = sWm.makeSurfaceBuilder(mSession)
+ .setName("test surface")
+ .setSize(1, 1)
+ .build();
+ mFinishedCallbackCalled = false;
+ mLeash = null;
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+ }
+
+ @Override
+ public Transaction getPendingTransaction() {
+ return mTransaction;
+ }
+
+ @Override
+ public void commitPendingTransaction() {
+ }
+
+ @Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ }
+
+ @Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mPendingDestroySurfaces.add(surface);
+ }
+
+ @Override
+ public Builder makeAnimationLeash() {
+ return new SurfaceControl.Builder(mSession) {
+
+ @Override
+ public SurfaceControl build() {
+ mLeash = super.build();
+ return mLeash;
+ }
+ }.setParent(mParent);
+ }
+
+ @Override
+ public SurfaceControl getSurfaceControl() {
+ return mSurface;
+ }
+
+ @Override
+ public SurfaceControl getParentSurfaceControl() {
+ return mParent;
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return 1;
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return 1;
+ }
+
+ private final Runnable mFinishedCallback = () -> {
+ mFinishedCallbackCalled = true;
+ };
}
}
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
final TestWindowContainer child21 = child2.addChildWindow();
- assertTrue(root.isAnimating());
+ assertFalse(root.isAnimating());
assertTrue(child1.isAnimating());
- assertFalse(child11.isAnimating());
+ assertTrue(child11.isAnimating());
assertTrue(child12.isAnimating());
assertFalse(child2.isAnimating());
assertFalse(child21.isAnimating());
+
+ assertTrue(root.isSelfOrChildAnimating());
+ assertTrue(child1.isSelfOrChildAnimating());
+ assertFalse(child11.isSelfOrChildAnimating());
+ assertTrue(child12.isSelfOrChildAnimating());
+ assertFalse(child2.isSelfOrChildAnimating());
+ assertFalse(child21.isSelfOrChildAnimating());
}
@Test
}
@Override
- boolean isAnimating() {
- return mIsAnimating || super.isAnimating();
+ boolean isSelfAnimating() {
+ return mIsAnimating;
}
@Override
public static class TestTask extends Task {
boolean mShouldDeferRemoval = false;
boolean mOnDisplayChangedCalled = false;
- private boolean mUseLocalIsAnimating = false;
private boolean mIsAnimating = false;
TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
}
@Override
- boolean isAnimating() {
- return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+ boolean isSelfAnimating() {
+ return mIsAnimating;
}
void setLocalIsAnimating(boolean isAnimating) {
- mUseLocalIsAnimating = true;
mIsAnimating = isAnimating;
}
}