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