Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wm;
     18 
     19 import android.graphics.Matrix;
     20 import android.os.RemoteException;
     21 import android.util.Slog;
     22 import android.util.TimeUtils;
     23 import android.view.Display;
     24 import android.view.SurfaceControl;
     25 import android.view.WindowManagerPolicy;
     26 import android.view.animation.Animation;
     27 import android.view.animation.Transformation;
     28 
     29 import java.io.PrintWriter;
     30 import java.util.ArrayList;
     31 
     32 public class AppWindowAnimator {
     33     static final String TAG = "AppWindowAnimator";
     34 
     35     final AppWindowToken mAppToken;
     36     final WindowManagerService mService;
     37     final WindowAnimator mAnimator;
     38 
     39     boolean animating;
     40     Animation animation;
     41     boolean hasTransformation;
     42     final Transformation transformation = new Transformation();
     43 
     44     // Have we been asked to have this token keep the screen frozen?
     45     // Protect with mAnimator.
     46     boolean freezingScreen;
     47 
     48     /**
     49      * How long we last kept the screen frozen.
     50      */
     51     int lastFreezeDuration;
     52 
     53     // Offset to the window of all layers in the token, for use by
     54     // AppWindowToken animations.
     55     int animLayerAdjustment;
     56 
     57     // Propagated from AppWindowToken.allDrawn, to determine when
     58     // the state changes.
     59     boolean allDrawn;
     60 
     61     // Special surface for thumbnail animation.  If deferThumbnailDestruction is enabled, then we
     62     // will make sure that the thumbnail is destroyed after the other surface is completed.  This
     63     // requires that the duration of the two animations are the same.
     64     SurfaceControl thumbnail;
     65     int thumbnailTransactionSeq;
     66     int thumbnailX;
     67     int thumbnailY;
     68     int thumbnailLayer;
     69     int thumbnailForceAboveLayer;
     70     Animation thumbnailAnimation;
     71     final Transformation thumbnailTransformation = new Transformation();
     72     // This flag indicates that the destruction of the thumbnail surface is synchronized with
     73     // another animation, so defer the destruction of this thumbnail surface for a single frame
     74     // after the secondary animation completes.
     75     boolean deferThumbnailDestruction;
     76     // This flag is set if the animator has deferThumbnailDestruction set and has reached the final
     77     // frame of animation.  It will extend the animation by one frame and then clean up afterwards.
     78     boolean deferFinalFrameCleanup;
     79 
     80     /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
     81     ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
     82 
     83     static final Animation sDummyAnimation = new DummyAnimation();
     84 
     85     public AppWindowAnimator(final AppWindowToken atoken) {
     86         mAppToken = atoken;
     87         mService = atoken.service;
     88         mAnimator = atoken.mAnimator;
     89     }
     90 
     91     public void setAnimation(Animation anim, int width, int height) {
     92         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
     93                 + ": " + anim + " wxh=" + width + "x" + height
     94                 + " isVisible=" + mAppToken.isVisible());
     95         animation = anim;
     96         animating = false;
     97         if (!anim.isInitialized()) {
     98             anim.initialize(width, height, width, height);
     99         }
    100         anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
    101         anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
    102         int zorder = anim.getZAdjustment();
    103         int adj = 0;
    104         if (zorder == Animation.ZORDER_TOP) {
    105             adj = WindowManagerService.TYPE_LAYER_OFFSET;
    106         } else if (zorder == Animation.ZORDER_BOTTOM) {
    107             adj = -WindowManagerService.TYPE_LAYER_OFFSET;
    108         }
    109 
    110         if (animLayerAdjustment != adj) {
    111             animLayerAdjustment = adj;
    112             updateLayers();
    113         }
    114         // Start out animation gone if window is gone, or visible if window is visible.
    115         transformation.clear();
    116         transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
    117         hasTransformation = true;
    118 
    119         if (!mAppToken.appFullscreen) {
    120             anim.setBackgroundColor(0);
    121         }
    122     }
    123 
    124     public void setDummyAnimation() {
    125         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
    126                 + " isVisible=" + mAppToken.isVisible());
    127         animation = sDummyAnimation;
    128         hasTransformation = true;
    129         transformation.clear();
    130         transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
    131     }
    132 
    133     public void clearAnimation() {
    134         if (animation != null) {
    135             animation = null;
    136             animating = true;
    137         }
    138         clearThumbnail();
    139         if (mAppToken.deferClearAllDrawn) {
    140             mAppToken.allDrawn = false;
    141             mAppToken.deferClearAllDrawn = false;
    142         }
    143     }
    144 
    145     public void clearThumbnail() {
    146         if (thumbnail != null) {
    147             thumbnail.destroy();
    148             thumbnail = null;
    149         }
    150         deferThumbnailDestruction = false;
    151     }
    152 
    153     void updateLayers() {
    154         final int N = mAppToken.allAppWindows.size();
    155         final int adj = animLayerAdjustment;
    156         thumbnailLayer = -1;
    157         for (int i=0; i<N; i++) {
    158             final WindowState w = mAppToken.allAppWindows.get(i);
    159             final WindowStateAnimator winAnimator = w.mWinAnimator;
    160             winAnimator.mAnimLayer = w.mLayer + adj;
    161             if (winAnimator.mAnimLayer > thumbnailLayer) {
    162                 thumbnailLayer = winAnimator.mAnimLayer;
    163             }
    164             if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
    165                     + winAnimator.mAnimLayer);
    166             if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
    167                 mService.setInputMethodAnimLayerAdjustment(adj);
    168             }
    169             if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
    170                 mService.setWallpaperAnimLayerAdjustmentLocked(adj);
    171             }
    172         }
    173     }
    174 
    175     private void stepThumbnailAnimation(long currentTime) {
    176         thumbnailTransformation.clear();
    177         thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
    178         thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
    179 
    180         ScreenRotationAnimation screenRotationAnimation =
    181                 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
    182         final boolean screenAnimation = screenRotationAnimation != null
    183                 && screenRotationAnimation.isAnimating();
    184         if (screenAnimation) {
    185             thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
    186         }
    187         // cache often used attributes locally
    188         final float tmpFloats[] = mService.mTmpFloats;
    189         thumbnailTransformation.getMatrix().getValues(tmpFloats);
    190         if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
    191                 "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
    192                 + ", " + tmpFloats[Matrix.MTRANS_Y], null);
    193         thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
    194         if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
    195                 "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
    196                 + " layer=" + thumbnailLayer
    197                 + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
    198                 + "," + tmpFloats[Matrix.MSKEW_Y]
    199                 + "][" + tmpFloats[Matrix.MSKEW_X]
    200                 + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
    201         thumbnail.setAlpha(thumbnailTransformation.getAlpha());
    202         if (thumbnailForceAboveLayer > 0) {
    203             thumbnail.setLayer(thumbnailForceAboveLayer + 1);
    204         } else {
    205             // The thumbnail is layered below the window immediately above this
    206             // token's anim layer.
    207             thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
    208                     - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
    209         }
    210         thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
    211                 tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
    212     }
    213 
    214     private boolean stepAnimation(long currentTime) {
    215         if (animation == null) {
    216             return false;
    217         }
    218         transformation.clear();
    219         boolean hasMoreFrames = animation.getTransformation(currentTime, transformation);
    220         if (!hasMoreFrames) {
    221             if (deferThumbnailDestruction && !deferFinalFrameCleanup) {
    222                 // We are deferring the thumbnail destruction, so extend the animation for one more
    223                 // (dummy) frame before we clean up
    224                 deferFinalFrameCleanup = true;
    225                 hasMoreFrames = true;
    226             } else {
    227                 if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
    228                         TAG, "Stepped animation in " + mAppToken + ": more=" + hasMoreFrames +
    229                                 ", xform=" + transformation);
    230                 deferFinalFrameCleanup = false;
    231                 animation = null;
    232                 clearThumbnail();
    233                 if (WindowManagerService.DEBUG_ANIM) Slog.v(
    234                         TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
    235             }
    236         }
    237         hasTransformation = hasMoreFrames;
    238         return hasMoreFrames;
    239     }
    240 
    241     // This must be called while inside a transaction.
    242     boolean stepAnimationLocked(long currentTime) {
    243         if (mService.okToDisplay()) {
    244             // We will run animations as long as the display isn't frozen.
    245 
    246             if (animation == sDummyAnimation) {
    247                 // This guy is going to animate, but not yet.  For now count
    248                 // it as not animating for purposes of scheduling transactions;
    249                 // when it is really time to animate, this will be set to
    250                 // a real animation and the next call will execute normally.
    251                 return false;
    252             }
    253 
    254             if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
    255                     && animation != null) {
    256                 if (!animating) {
    257                     if (WindowManagerService.DEBUG_ANIM) Slog.v(
    258                         TAG, "Starting animation in " + mAppToken +
    259                         " @ " + currentTime + " scale="
    260                         + mService.getTransitionAnimationScaleLocked()
    261                         + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
    262                     animation.setStartTime(currentTime);
    263                     animating = true;
    264                     if (thumbnail != null) {
    265                         thumbnail.show();
    266                         thumbnailAnimation.setStartTime(currentTime);
    267                     }
    268                 }
    269                 if (stepAnimation(currentTime)) {
    270                     // animation isn't over, step any thumbnail and that's
    271                     // it for now.
    272                     if (thumbnail != null) {
    273                         stepThumbnailAnimation(currentTime);
    274                     }
    275                     return true;
    276                 }
    277             }
    278         } else if (animation != null) {
    279             // If the display is frozen, and there is a pending animation,
    280             // clear it and make sure we run the cleanup code.
    281             animating = true;
    282             animation = null;
    283         }
    284 
    285         hasTransformation = false;
    286 
    287         if (!animating && animation == null) {
    288             return false;
    289         }
    290 
    291         mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
    292                 "AppWindowToken");
    293 
    294         clearAnimation();
    295         animating = false;
    296         if (animLayerAdjustment != 0) {
    297             animLayerAdjustment = 0;
    298             updateLayers();
    299         }
    300         if (mService.mInputMethodTarget != null
    301                 && mService.mInputMethodTarget.mAppToken == mAppToken) {
    302             mService.moveInputMethodWindowsIfNeededLocked(true);
    303         }
    304 
    305         if (WindowManagerService.DEBUG_ANIM) Slog.v(
    306                 TAG, "Animation done in " + mAppToken
    307                 + ": reportedVisible=" + mAppToken.reportedVisible);
    308 
    309         transformation.clear();
    310 
    311         final int numAllAppWinAnimators = mAllAppWinAnimators.size();
    312         for (int i = 0; i < numAllAppWinAnimators; i++) {
    313             mAllAppWinAnimators.get(i).finishExit();
    314         }
    315         if (mAppToken.mLaunchTaskBehind) {
    316             try {
    317                 mService.mActivityManager.notifyLaunchTaskBehindComplete(mAppToken.token);
    318             } catch (RemoteException e) {
    319             }
    320             mAppToken.mLaunchTaskBehind = false;
    321         } else {
    322             mAppToken.updateReportedVisibilityLocked();
    323             if (mAppToken.mEnteringAnimation) {
    324                 mAppToken.mEnteringAnimation = false;
    325                 try {
    326                     mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token);
    327                 } catch (RemoteException e) {
    328                 }
    329             }
    330         }
    331 
    332         return false;
    333     }
    334 
    335     boolean showAllWindowsLocked() {
    336         boolean isAnimating = false;
    337         final int NW = mAllAppWinAnimators.size();
    338         for (int i=0; i<NW; i++) {
    339             WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
    340             if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
    341                     "performing show on: " + winAnimator);
    342             winAnimator.performShowLocked();
    343             isAnimating |= winAnimator.isAnimating();
    344         }
    345         return isAnimating;
    346     }
    347 
    348     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
    349         pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
    350         pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
    351         pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
    352                 pw.print(" allDrawn="); pw.print(allDrawn);
    353                 pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
    354         if (lastFreezeDuration != 0) {
    355             pw.print(prefix); pw.print("lastFreezeDuration=");
    356                     TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
    357         }
    358         if (animating || animation != null) {
    359             pw.print(prefix); pw.print("animating="); pw.println(animating);
    360             pw.print(prefix); pw.print("animation="); pw.println(animation);
    361         }
    362         if (hasTransformation) {
    363             pw.print(prefix); pw.print("XForm: ");
    364                     transformation.printShortString(pw);
    365                     pw.println();
    366         }
    367         if (thumbnail != null) {
    368             pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
    369                     pw.print(" x="); pw.print(thumbnailX);
    370                     pw.print(" y="); pw.print(thumbnailY);
    371                     pw.print(" layer="); pw.println(thumbnailLayer);
    372             pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
    373             pw.print(prefix); pw.print("thumbnailTransformation=");
    374                     pw.println(thumbnailTransformation.toShortString());
    375         }
    376         for (int i=0; i<mAllAppWinAnimators.size(); i++) {
    377             WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
    378             pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
    379                     pw.print(": "); pw.println(wanim);
    380         }
    381     }
    382 
    383     // This is an animation that does nothing: it just immediately finishes
    384     // itself every time it is called.  It is used as a stub animation in cases
    385     // where we want to synchronize multiple things that may be animating.
    386     static final class DummyAnimation extends Animation {
    387         @Override
    388         public boolean getTransformation(long currentTime, Transformation outTransformation) {
    389             return false;
    390         }
    391     }
    392 
    393 }
    394