summaryrefslogtreecommitdiffstats
path: root/services/core/java/com/android/server/wm/AppWindowAnimator.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/core/java/com/android/server/wm/AppWindowAnimator.java')
-rw-r--r--services/core/java/com/android/server/wm/AppWindowAnimator.java334
1 files changed, 334 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
new file mode 100644
index 0000000..3cccf1d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -0,0 +1,334 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.android.server.wm;
+
+import android.graphics.Matrix;
+import android.util.Slog;
+import android.util.TimeUtils;
+import android.view.Display;
+import android.view.SurfaceControl;
+import android.view.WindowManagerPolicy;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+public class AppWindowAnimator {
+ static final String TAG = "AppWindowAnimator";
+
+ final AppWindowToken mAppToken;
+ final WindowManagerService mService;
+ final WindowAnimator mAnimator;
+
+ boolean animating;
+ Animation animation;
+ boolean hasTransformation;
+ final Transformation transformation = new Transformation();
+
+ // Have we been asked to have this token keep the screen frozen?
+ // Protect with mAnimator.
+ boolean freezingScreen;
+
+ /**
+ * How long we last kept the screen frozen.
+ */
+ int lastFreezeDuration;
+
+ // Offset to the window of all layers in the token, for use by
+ // AppWindowToken animations.
+ int animLayerAdjustment;
+
+ // Propagated from AppWindowToken.allDrawn, to determine when
+ // the state changes.
+ boolean allDrawn;
+
+ // Special surface for thumbnail animation.
+ SurfaceControl thumbnail;
+ int thumbnailTransactionSeq;
+ int thumbnailX;
+ int thumbnailY;
+ int thumbnailLayer;
+ Animation thumbnailAnimation;
+ final Transformation thumbnailTransformation = new Transformation();
+
+ /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
+ ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
+
+ static final Animation sDummyAnimation = new DummyAnimation();
+
+ public AppWindowAnimator(final AppWindowToken atoken) {
+ mAppToken = atoken;
+ mService = atoken.service;
+ mAnimator = atoken.mAnimator;
+ }
+
+ public void setAnimation(Animation anim, int width, int height) {
+ if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
+ + ": " + anim + " wxh=" + width + "x" + height
+ + " isVisible=" + mAppToken.isVisible());
+ animation = anim;
+ animating = false;
+ if (!anim.isInitialized()) {
+ anim.initialize(width, height, width, height);
+ }
+ anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(mService.mTransitionAnimationScale);
+ int zorder = anim.getZAdjustment();
+ int adj = 0;
+ if (zorder == Animation.ZORDER_TOP) {
+ adj = WindowManagerService.TYPE_LAYER_OFFSET;
+ } else if (zorder == Animation.ZORDER_BOTTOM) {
+ adj = -WindowManagerService.TYPE_LAYER_OFFSET;
+ }
+
+ if (animLayerAdjustment != adj) {
+ animLayerAdjustment = adj;
+ updateLayers();
+ }
+ // Start out animation gone if window is gone, or visible if window is visible.
+ transformation.clear();
+ transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
+ hasTransformation = true;
+ }
+
+ public void setDummyAnimation() {
+ if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
+ + " isVisible=" + mAppToken.isVisible());
+ animation = sDummyAnimation;
+ hasTransformation = true;
+ transformation.clear();
+ transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
+ }
+
+ public void clearAnimation() {
+ if (animation != null) {
+ animation = null;
+ animating = true;
+ }
+ clearThumbnail();
+ if (mAppToken.deferClearAllDrawn) {
+ mAppToken.allDrawn = false;
+ mAppToken.deferClearAllDrawn = false;
+ }
+ }
+
+ public void clearThumbnail() {
+ if (thumbnail != null) {
+ thumbnail.destroy();
+ thumbnail = null;
+ }
+ }
+
+ void updateLayers() {
+ final int N = mAppToken.allAppWindows.size();
+ final int adj = animLayerAdjustment;
+ thumbnailLayer = -1;
+ for (int i=0; i<N; i++) {
+ final WindowState w = mAppToken.allAppWindows.get(i);
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ winAnimator.mAnimLayer = w.mLayer + adj;
+ if (winAnimator.mAnimLayer > thumbnailLayer) {
+ thumbnailLayer = winAnimator.mAnimLayer;
+ }
+ if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
+ + winAnimator.mAnimLayer);
+ if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
+ mService.setInputMethodAnimLayerAdjustment(adj);
+ }
+ if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
+ mService.setWallpaperAnimLayerAdjustmentLocked(adj);
+ }
+ }
+ }
+
+ private void stepThumbnailAnimation(long currentTime) {
+ thumbnailTransformation.clear();
+ thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
+ thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
+
+ ScreenRotationAnimation screenRotationAnimation =
+ mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
+ final boolean screenAnimation = screenRotationAnimation != null
+ && screenRotationAnimation.isAnimating();
+ if (screenAnimation) {
+ thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
+ }
+ // cache often used attributes locally
+ final float tmpFloats[] = mService.mTmpFloats;
+ thumbnailTransformation.getMatrix().getValues(tmpFloats);
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
+ "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
+ + ", " + tmpFloats[Matrix.MTRANS_Y], null);
+ thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
+ "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
+ + " layer=" + thumbnailLayer
+ + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
+ + "," + tmpFloats[Matrix.MSKEW_Y]
+ + "][" + tmpFloats[Matrix.MSKEW_X]
+ + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
+ thumbnail.setAlpha(thumbnailTransformation.getAlpha());
+ // The thumbnail is layered below the window immediately above this
+ // token's anim layer.
+ thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
+ - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
+ thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
+ tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
+ }
+
+ private boolean stepAnimation(long currentTime) {
+ if (animation == null) {
+ return false;
+ }
+ transformation.clear();
+ final boolean more = animation.getTransformation(currentTime, transformation);
+ if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
+ TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
+ if (!more) {
+ animation = null;
+ clearThumbnail();
+ if (WindowManagerService.DEBUG_ANIM) Slog.v(
+ TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
+ }
+ hasTransformation = more;
+ return more;
+ }
+
+ // This must be called while inside a transaction.
+ boolean stepAnimationLocked(long currentTime) {
+ if (mService.okToDisplay()) {
+ // We will run animations as long as the display isn't frozen.
+
+ if (animation == sDummyAnimation) {
+ // This guy is going to animate, but not yet. For now count
+ // it as not animating for purposes of scheduling transactions;
+ // when it is really time to animate, this will be set to
+ // a real animation and the next call will execute normally.
+ return false;
+ }
+
+ if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
+ && animation != null) {
+ if (!animating) {
+ if (WindowManagerService.DEBUG_ANIM) Slog.v(
+ TAG, "Starting animation in " + mAppToken +
+ " @ " + currentTime + " scale=" + mService.mTransitionAnimationScale
+ + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
+ animation.setStartTime(currentTime);
+ animating = true;
+ if (thumbnail != null) {
+ thumbnail.show();
+ thumbnailAnimation.setStartTime(currentTime);
+ }
+ }
+ if (stepAnimation(currentTime)) {
+ // animation isn't over, step any thumbnail and that's
+ // it for now.
+ if (thumbnail != null) {
+ stepThumbnailAnimation(currentTime);
+ }
+ return true;
+ }
+ }
+ } else if (animation != null) {
+ // If the display is frozen, and there is a pending animation,
+ // clear it and make sure we run the cleanup code.
+ animating = true;
+ animation = null;
+ }
+
+ hasTransformation = false;
+
+ if (!animating && animation == null) {
+ return false;
+ }
+
+ mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
+ "AppWindowToken");
+
+ clearAnimation();
+ animating = false;
+ if (animLayerAdjustment != 0) {
+ animLayerAdjustment = 0;
+ updateLayers();
+ }
+ if (mService.mInputMethodTarget != null
+ && mService.mInputMethodTarget.mAppToken == mAppToken) {
+ mService.moveInputMethodWindowsIfNeededLocked(true);
+ }
+
+ if (WindowManagerService.DEBUG_ANIM) Slog.v(
+ TAG, "Animation done in " + mAppToken
+ + ": reportedVisible=" + mAppToken.reportedVisible);
+
+ transformation.clear();
+
+ final int N = mAllAppWinAnimators.size();
+ for (int i=0; i<N; i++) {
+ mAllAppWinAnimators.get(i).finishExit();
+ }
+ mAppToken.updateReportedVisibilityLocked();
+
+ return false;
+ }
+
+ boolean showAllWindowsLocked() {
+ boolean isAnimating = false;
+ final int NW = mAllAppWinAnimators.size();
+ for (int i=0; i<NW; i++) {
+ WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
+ if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+ "performing show on: " + winAnimator);
+ winAnimator.performShowLocked();
+ isAnimating |= winAnimator.isAnimating();
+ }
+ return isAnimating;
+ }
+
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
+ pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
+ pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
+ pw.print(" allDrawn="); pw.print(allDrawn);
+ pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
+ if (lastFreezeDuration != 0) {
+ pw.print(prefix); pw.print("lastFreezeDuration=");
+ TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
+ }
+ if (animating || animation != null) {
+ pw.print(prefix); pw.print("animating="); pw.println(animating);
+ pw.print(prefix); pw.print("animation="); pw.println(animation);
+ }
+ if (hasTransformation) {
+ pw.print(prefix); pw.print("XForm: ");
+ transformation.printShortString(pw);
+ pw.println();
+ }
+ if (thumbnail != null) {
+ pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
+ pw.print(" x="); pw.print(thumbnailX);
+ pw.print(" y="); pw.print(thumbnailY);
+ pw.print(" layer="); pw.println(thumbnailLayer);
+ pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
+ pw.print(prefix); pw.print("thumbnailTransformation=");
+ pw.println(thumbnailTransformation.toShortString());
+ }
+ for (int i=0; i<mAllAppWinAnimators.size(); i++) {
+ WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
+ pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
+ pw.print(": "); pw.println(wanim);
+ }
+ }
+
+ // This is an animation that does nothing: it just immediately finishes
+ // itself every time it is called. It is used as a stub animation in cases
+ // where we want to synchronize multiple things that may be animating.
+ static final class DummyAnimation extends Animation {
+ @Override
+ public boolean getTransformation(long currentTime, Transformation outTransformation) {
+ return false;
+ }
+ }
+
+}