Home | History | Annotate | Download | only in wm
      1 // Copyright 2012 Google Inc. All Rights Reserved.
      2 
      3 package com.android.server.wm;
      4 
      5 import android.graphics.Matrix;
      6 import android.util.Slog;
      7 import android.view.Surface;
      8 import android.view.WindowManagerPolicy;
      9 import android.view.animation.Animation;
     10 import android.view.animation.Transformation;
     11 
     12 import java.io.PrintWriter;
     13 
     14 /**
     15  *
     16  */
     17 public class AppWindowAnimator {
     18     static final String TAG = "AppWindowAnimator";
     19 
     20     final AppWindowToken mAppToken;
     21     final WindowManagerService mService;
     22     final WindowAnimator mAnimator;
     23 
     24     boolean animating;
     25     Animation animation;
     26     boolean animInitialized;
     27     boolean hasTransformation;
     28     final Transformation transformation = new Transformation();
     29 
     30     // Have we been asked to have this token keep the screen frozen?
     31     // Protect with mAnimator.
     32     boolean freezingScreen;
     33 
     34     // Offset to the window of all layers in the token, for use by
     35     // AppWindowToken animations.
     36     int animLayerAdjustment;
     37 
     38     // Propagated from AppWindowToken.allDrawn, to determine when
     39     // the state changes.
     40     boolean allDrawn;
     41 
     42     // Special surface for thumbnail animation.
     43     Surface thumbnail;
     44     int thumbnailTransactionSeq;
     45     int thumbnailX;
     46     int thumbnailY;
     47     int thumbnailLayer;
     48     Animation thumbnailAnimation;
     49     final Transformation thumbnailTransformation = new Transformation();
     50 
     51     static final Animation sDummyAnimation = new DummyAnimation();
     52 
     53     public AppWindowAnimator(final WindowManagerService service, final AppWindowToken atoken) {
     54         mService = service;
     55         mAppToken = atoken;
     56         mAnimator = service.mAnimator;
     57     }
     58 
     59     public void setAnimation(Animation anim, boolean initialized) {
     60         if (WindowManagerService.localLOGV) Slog.v(
     61             TAG, "Setting animation in " + mAppToken + ": " + anim);
     62         animation = anim;
     63         animating = false;
     64         animInitialized = initialized;
     65         anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
     66         anim.scaleCurrentDuration(mService.mTransitionAnimationScale);
     67         int zorder = anim.getZAdjustment();
     68         int adj = 0;
     69         if (zorder == Animation.ZORDER_TOP) {
     70             adj = WindowManagerService.TYPE_LAYER_OFFSET;
     71         } else if (zorder == Animation.ZORDER_BOTTOM) {
     72             adj = -WindowManagerService.TYPE_LAYER_OFFSET;
     73         }
     74 
     75         if (animLayerAdjustment != adj) {
     76             animLayerAdjustment = adj;
     77             updateLayers();
     78         }
     79         // Start out animation gone if window is gone, or visible if window is visible.
     80         transformation.clear();
     81         transformation.setAlpha(mAppToken.reportedVisible ? 1 : 0);
     82         hasTransformation = true;
     83     }
     84 
     85     public void setDummyAnimation() {
     86         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken);
     87         animation = sDummyAnimation;
     88         animInitialized = false;
     89         hasTransformation = true;
     90         transformation.clear();
     91         transformation.setAlpha(mAppToken.reportedVisible ? 1 : 0);
     92     }
     93 
     94     public void clearAnimation() {
     95         if (animation != null) {
     96             animation = null;
     97             animating = true;
     98             animInitialized = false;
     99         }
    100         clearThumbnail();
    101     }
    102 
    103     public void clearThumbnail() {
    104         if (thumbnail != null) {
    105             thumbnail.destroy();
    106             thumbnail = null;
    107         }
    108     }
    109 
    110     void updateLayers() {
    111         final int N = mAppToken.allAppWindows.size();
    112         final int adj = animLayerAdjustment;
    113         thumbnailLayer = -1;
    114         for (int i=0; i<N; i++) {
    115             final WindowState w = mAppToken.allAppWindows.get(i);
    116             final WindowStateAnimator winAnimator = w.mWinAnimator;
    117             winAnimator.mAnimLayer = w.mLayer + adj;
    118             if (winAnimator.mAnimLayer > thumbnailLayer) {
    119                 thumbnailLayer = winAnimator.mAnimLayer;
    120             }
    121             if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
    122                     + winAnimator.mAnimLayer);
    123             if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
    124                 mService.setInputMethodAnimLayerAdjustment(adj);
    125             }
    126             if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
    127                 mService.setWallpaperAnimLayerAdjustmentLocked(adj);
    128             }
    129         }
    130     }
    131 
    132     private void stepThumbnailAnimation(long currentTime) {
    133         thumbnailTransformation.clear();
    134         thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
    135         thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
    136         final boolean screenAnimation = mAnimator.mScreenRotationAnimation != null
    137                 && mAnimator.mScreenRotationAnimation.isAnimating();
    138         if (screenAnimation) {
    139             thumbnailTransformation.postCompose(
    140                     mAnimator.mScreenRotationAnimation.getEnterTransformation());
    141         }
    142         // cache often used attributes locally
    143         final float tmpFloats[] = mService.mTmpFloats;
    144         thumbnailTransformation.getMatrix().getValues(tmpFloats);
    145         if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
    146                 "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
    147                 + ", " + tmpFloats[Matrix.MTRANS_Y], null);
    148         thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
    149         if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
    150                 "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
    151                 + " layer=" + thumbnailLayer
    152                 + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
    153                 + "," + tmpFloats[Matrix.MSKEW_Y]
    154                 + "][" + tmpFloats[Matrix.MSKEW_X]
    155                 + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
    156         thumbnail.setAlpha(thumbnailTransformation.getAlpha());
    157         // The thumbnail is layered below the window immediately above this
    158         // token's anim layer.
    159         thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
    160                 - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
    161         thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
    162                 tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
    163     }
    164 
    165     private boolean stepAnimation(long currentTime) {
    166         if (animation == null) {
    167             return false;
    168         }
    169         transformation.clear();
    170         final boolean more = animation.getTransformation(currentTime, transformation);
    171         if (WindowManagerService.DEBUG_ANIM) Slog.v(
    172             TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
    173         if (!more) {
    174             animation = null;
    175             clearThumbnail();
    176             if (WindowManagerService.DEBUG_ANIM) Slog.v(
    177                 TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
    178         }
    179         hasTransformation = more;
    180         return more;
    181     }
    182 
    183     // This must be called while inside a transaction.
    184     boolean stepAnimationLocked(long currentTime, int dw, int dh) {
    185         if (mService.okToDisplay()) {
    186             // We will run animations as long as the display isn't frozen.
    187 
    188             if (animation == sDummyAnimation) {
    189                 // This guy is going to animate, but not yet.  For now count
    190                 // it as not animating for purposes of scheduling transactions;
    191                 // when it is really time to animate, this will be set to
    192                 // a real animation and the next call will execute normally.
    193                 return false;
    194             }
    195 
    196             if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
    197                     && animation != null) {
    198                 if (!animating) {
    199                     if (WindowManagerService.DEBUG_ANIM) Slog.v(
    200                         TAG, "Starting animation in " + mAppToken +
    201                         " @ " + currentTime + ": dw=" + dw + " dh=" + dh
    202                         + " scale=" + mService.mTransitionAnimationScale
    203                         + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
    204                     if (!animInitialized) {
    205                         animation.initialize(dw, dh, dw, dh);
    206                     }
    207                     animation.setStartTime(currentTime);
    208                     animating = true;
    209                     if (thumbnail != null) {
    210                         thumbnail.show();
    211                         thumbnailAnimation.setStartTime(currentTime);
    212                     }
    213                 }
    214                 if (stepAnimation(currentTime)) {
    215                     // animation isn't over, step any thumbnail and that's
    216                     // it for now.
    217                     if (thumbnail != null) {
    218                         stepThumbnailAnimation(currentTime);
    219                     }
    220                     return true;
    221                 }
    222             }
    223         } else if (animation != null) {
    224             // If the display is frozen, and there is a pending animation,
    225             // clear it and make sure we run the cleanup code.
    226             animating = true;
    227             animation = null;
    228         }
    229 
    230         hasTransformation = false;
    231 
    232         if (!animating && animation == null) {
    233             return false;
    234         }
    235 
    236         mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
    237         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
    238             mService.debugLayoutRepeats("AppWindowToken", mAnimator.mPendingLayoutChanges);
    239         }
    240 
    241         clearAnimation();
    242         animating = false;
    243         if (animLayerAdjustment != 0) {
    244             animLayerAdjustment = 0;
    245             updateLayers();
    246         }
    247         if (mService.mInputMethodTarget != null
    248                 && mService.mInputMethodTarget.mAppToken == mAppToken) {
    249             mService.moveInputMethodWindowsIfNeededLocked(true);
    250         }
    251 
    252         if (WindowManagerService.DEBUG_ANIM) Slog.v(
    253                 TAG, "Animation done in " + mAppToken
    254                 + ": reportedVisible=" + mAppToken.reportedVisible);
    255 
    256         transformation.clear();
    257 
    258         final int N = mAppToken.windows.size();
    259         for (int i=0; i<N; i++) {
    260             mAppToken.windows.get(i).mWinAnimator.finishExit();
    261         }
    262         mAppToken.updateReportedVisibilityLocked();
    263 
    264         return false;
    265     }
    266 
    267     boolean showAllWindowsLocked() {
    268         boolean isAnimating = false;
    269         final int NW = mAppToken.allAppWindows.size();
    270         for (int i=0; i<NW; i++) {
    271             WindowStateAnimator winAnimator = mAppToken.allAppWindows.get(i).mWinAnimator;
    272             if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
    273                     "performing show on: " + winAnimator);
    274             winAnimator.performShowLocked();
    275             isAnimating |= winAnimator.isAnimating();
    276         }
    277         return isAnimating;
    278     }
    279 
    280     void dump(PrintWriter pw, String prefix) {
    281         if (freezingScreen) {
    282             pw.print(prefix); pw.print(" freezingScreen="); pw.println(freezingScreen);
    283         }
    284         if (animating || animation != null) {
    285             pw.print(prefix); pw.print("animating="); pw.print(animating);
    286                     pw.print(" animation="); pw.println(animation);
    287         }
    288         if (hasTransformation) {
    289             pw.print(prefix); pw.print("XForm: ");
    290                     transformation.printShortString(pw);
    291                     pw.println();
    292         }
    293         if (animLayerAdjustment != 0) {
    294             pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
    295         }
    296         if (thumbnail != null) {
    297             pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
    298                     pw.print(" x="); pw.print(thumbnailX);
    299                     pw.print(" y="); pw.print(thumbnailY);
    300                     pw.print(" layer="); pw.println(thumbnailLayer);
    301             pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
    302             pw.print(prefix); pw.print("thumbnailTransformation=");
    303                     pw.println(thumbnailTransformation.toShortString());
    304         }
    305     }
    306 
    307     // This is an animation that does nothing: it just immediately finishes
    308     // itself every time it is called.  It is used as a stub animation in cases
    309     // where we want to synchronize multiple things that may be animating.
    310     static final class DummyAnimation extends Animation {
    311         @Override
    312         public boolean getTransformation(long currentTime, Transformation outTransformation) {
    313             return false;
    314         }
    315     }
    316 
    317 }
    318