diff options
Diffstat (limited to 'services/core/java/com/android/server/wm/AppWindowAnimator.java')
-rw-r--r-- | services/core/java/com/android/server/wm/AppWindowAnimator.java | 334 |
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; + } + } + +} |