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