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