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 static android.app.ActivityManager.StackId;
     20 import static android.view.Display.DEFAULT_DISPLAY;
     21 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
     22 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
     23 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
     24 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     25 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
     26 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
     27 import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
     28 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
     29 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
     30 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
     31 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
     32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
     33 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
     34 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
     35 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
     36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
     37 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
     38 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
     39 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
     40 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
     41 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
     42 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     43 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     44 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
     45 import static com.android.server.wm.WindowManagerService.localLOGV;
     46 import static com.android.server.wm.WindowManagerService.logWithStack;
     47 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
     48 import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
     49 
     50 import android.content.Context;
     51 import android.graphics.Matrix;
     52 import android.graphics.PixelFormat;
     53 import android.graphics.Point;
     54 import android.graphics.Rect;
     55 import android.graphics.RectF;
     56 import android.graphics.Region;
     57 import android.os.Debug;
     58 import android.os.Trace;
     59 import android.util.Slog;
     60 import android.view.DisplayInfo;
     61 import android.view.MagnificationSpec;
     62 import android.view.Surface.OutOfResourcesException;
     63 import android.view.SurfaceControl;
     64 import android.view.WindowManager;
     65 import android.view.WindowManager.LayoutParams;
     66 import android.view.WindowManagerPolicy;
     67 import android.view.animation.Animation;
     68 import android.view.animation.AnimationSet;
     69 import android.view.animation.AnimationUtils;
     70 import android.view.animation.Transformation;
     71 
     72 import java.io.PrintWriter;
     73 import java.io.FileDescriptor;
     74 
     75 /**
     76  * Keep track of animations and surface operations for a single WindowState.
     77  **/
     78 class WindowStateAnimator {
     79     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
     80     static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
     81 
     82     /**
     83      * Mode how the window gets clipped by the stack bounds during an animation: The clipping should
     84      * be applied after applying the animation transformation, i.e. the stack bounds don't move
     85      * during the animation.
     86      */
     87     static final int STACK_CLIP_AFTER_ANIM = 0;
     88 
     89     /**
     90      * Mode how the window gets clipped by the stack bounds: The clipping should be applied before
     91      * applying the animation transformation, i.e. the stack bounds move with the window.
     92      */
     93     static final int STACK_CLIP_BEFORE_ANIM = 1;
     94 
     95     /**
     96      * Mode how window gets clipped by the stack bounds during an animation: Don't clip the window
     97      * by the stack bounds.
     98      */
     99     static final int STACK_CLIP_NONE = 2;
    100 
    101     // Unchanging local convenience fields.
    102     final WindowManagerService mService;
    103     final WindowState mWin;
    104     private final WindowStateAnimator mParentWinAnimator;
    105     final WindowAnimator mAnimator;
    106     AppWindowAnimator mAppAnimator;
    107     final Session mSession;
    108     final WindowManagerPolicy mPolicy;
    109     final Context mContext;
    110     final boolean mIsWallpaper;
    111     private final WallpaperController mWallpaperControllerLocked;
    112 
    113     // Currently running animation.
    114     boolean mAnimating;
    115     boolean mLocalAnimating;
    116     Animation mAnimation;
    117     boolean mAnimationIsEntrance;
    118     boolean mHasTransformation;
    119     boolean mHasLocalTransformation;
    120     final Transformation mTransformation = new Transformation();
    121     boolean mWasAnimating;      // Were we animating going into the most recent animation step?
    122     int mAnimLayer;
    123     int mLastLayer;
    124     long mAnimationStartTime;
    125     long mLastAnimationTime;
    126     int mStackClip = STACK_CLIP_BEFORE_ANIM;
    127 
    128     /**
    129      * Set when we have changed the size of the surface, to know that
    130      * we must tell them application to resize (and thus redraw itself).
    131      */
    132     boolean mSurfaceResized;
    133     /**
    134      * Whether we should inform the client on next relayoutWindow that
    135      * the surface has been resized since last time.
    136      */
    137     boolean mReportSurfaceResized;
    138     WindowSurfaceController mSurfaceController;
    139     private WindowSurfaceController mPendingDestroySurface;
    140 
    141     /**
    142      * Set if the client has asked that the destroy of its surface be delayed
    143      * until it explicitly says it is okay.
    144      */
    145     boolean mSurfaceDestroyDeferred;
    146 
    147     private boolean mDestroyPreservedSurfaceUponRedraw;
    148     float mShownAlpha = 0;
    149     float mAlpha = 0;
    150     float mLastAlpha = 0;
    151 
    152     boolean mHasClipRect;
    153     Rect mClipRect = new Rect();
    154     Rect mTmpClipRect = new Rect();
    155     Rect mTmpFinalClipRect = new Rect();
    156     Rect mLastClipRect = new Rect();
    157     Rect mLastFinalClipRect = new Rect();
    158     Rect mTmpStackBounds = new Rect();
    159     private Rect mTmpAnimatingBounds = new Rect();
    160     private Rect mTmpSourceBounds = new Rect();
    161 
    162     /**
    163      * This is rectangle of the window's surface that is not covered by
    164      * system decorations.
    165      */
    166     private final Rect mSystemDecorRect = new Rect();
    167     private final Rect mLastSystemDecorRect = new Rect();
    168 
    169     // Used to save animation distances between the time they are calculated and when they are used.
    170     private int mAnimDx;
    171     private int mAnimDy;
    172 
    173     /** Is the next animation to be started a window move animation? */
    174     private boolean mAnimateMove = false;
    175 
    176     float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
    177     private float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
    178 
    179     boolean mHaveMatrix;
    180 
    181     // Set to true if, when the window gets displayed, it should perform
    182     // an enter animation.
    183     boolean mEnterAnimationPending;
    184 
    185     /** Used to indicate that this window is undergoing an enter animation. Used for system
    186      * windows to make the callback to View.dispatchOnWindowShownCallback(). Set when the
    187      * window is first added or shown, cleared when the callback has been made. */
    188     boolean mEnteringAnimation;
    189 
    190     private boolean mAnimationStartDelayed;
    191 
    192     /** The pixel format of the underlying SurfaceControl */
    193     int mSurfaceFormat;
    194 
    195     /** This is set when there is no Surface */
    196     static final int NO_SURFACE = 0;
    197     /** This is set after the Surface has been created but before the window has been drawn. During
    198      * this time the surface is hidden. */
    199     static final int DRAW_PENDING = 1;
    200     /** This is set after the window has finished drawing for the first time but before its surface
    201      * is shown.  The surface will be displayed when the next layout is run. */
    202     static final int COMMIT_DRAW_PENDING = 2;
    203     /** This is set during the time after the window's drawing has been committed, and before its
    204      * surface is actually shown.  It is used to delay showing the surface until all windows in a
    205      * token are ready to be shown. */
    206     static final int READY_TO_SHOW = 3;
    207     /** Set when the window has been shown in the screen the first time. */
    208     static final int HAS_DRAWN = 4;
    209 
    210     String drawStateToString() {
    211         switch (mDrawState) {
    212             case NO_SURFACE: return "NO_SURFACE";
    213             case DRAW_PENDING: return "DRAW_PENDING";
    214             case COMMIT_DRAW_PENDING: return "COMMIT_DRAW_PENDING";
    215             case READY_TO_SHOW: return "READY_TO_SHOW";
    216             case HAS_DRAWN: return "HAS_DRAWN";
    217             default: return Integer.toString(mDrawState);
    218         }
    219     }
    220     int mDrawState;
    221 
    222     /** Was this window last hidden? */
    223     boolean mLastHidden;
    224 
    225     int mAttrType;
    226 
    227     static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
    228 
    229     boolean mForceScaleUntilResize;
    230 
    231     // WindowState.mHScale and WindowState.mVScale contain the
    232     // scale according to client specified layout parameters (e.g.
    233     // one layout size, with another surface size, creates such scaling).
    234     // Here we track an additional scaling factor used to follow stack
    235     // scaling (as in the case of the Pinned stack animation).
    236     float mExtraHScale = (float) 1.0;
    237     float mExtraVScale = (float) 1.0;
    238 
    239     private final Rect mTmpSize = new Rect();
    240 
    241     WindowStateAnimator(final WindowState win) {
    242         final WindowManagerService service = win.mService;
    243 
    244         mService = service;
    245         mAnimator = service.mAnimator;
    246         mPolicy = service.mPolicy;
    247         mContext = service.mContext;
    248         final DisplayContent displayContent = win.getDisplayContent();
    249         if (displayContent != null) {
    250             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
    251             mAnimDx = displayInfo.appWidth;
    252             mAnimDy = displayInfo.appHeight;
    253         } else {
    254             Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
    255             // This is checked on return and dealt with.
    256         }
    257 
    258         mWin = win;
    259         mParentWinAnimator = !win.isChildWindow() ? null : win.getParentWindow().mWinAnimator;
    260         mAppAnimator = win.mAppToken == null ? null : win.mAppToken.mAppAnimator;
    261         mSession = win.mSession;
    262         mAttrType = win.mAttrs.type;
    263         mIsWallpaper = win.mIsWallpaper;
    264         mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
    265     }
    266 
    267     public void setAnimation(Animation anim, long startTime, int stackClip) {
    268         if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
    269         mAnimating = false;
    270         mLocalAnimating = false;
    271         mAnimation = anim;
    272         mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
    273         mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
    274         // Start out animation gone if window is gone, or visible if window is visible.
    275         mTransformation.clear();
    276         mTransformation.setAlpha(mLastHidden ? 0 : 1);
    277         mHasLocalTransformation = true;
    278         mAnimationStartTime = startTime;
    279         mStackClip = stackClip;
    280     }
    281 
    282     public void setAnimation(Animation anim, int stackClip) {
    283         setAnimation(anim, -1, stackClip);
    284     }
    285 
    286     public void setAnimation(Animation anim) {
    287         setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
    288     }
    289 
    290     public void clearAnimation() {
    291         if (mAnimation != null) {
    292             mAnimating = true;
    293             mLocalAnimating = false;
    294             mAnimation.cancel();
    295             mAnimation = null;
    296             mStackClip = STACK_CLIP_BEFORE_ANIM;
    297         }
    298     }
    299 
    300     /**
    301      * Is the window or its container currently set to animate or currently animating?
    302      */
    303     boolean isAnimationSet() {
    304         return mAnimation != null
    305                 || (mParentWinAnimator != null && mParentWinAnimator.mAnimation != null)
    306                 || (mAppAnimator != null && mAppAnimator.isAnimating());
    307     }
    308 
    309     /**
    310      * @return whether an animation is about to start, i.e. the animation is set already but we
    311      *         haven't processed the first frame yet.
    312      */
    313     boolean isAnimationStarting() {
    314         return isAnimationSet() && !mAnimating;
    315     }
    316 
    317     /** Is the window animating the DummyAnimation? */
    318     boolean isDummyAnimation() {
    319         return mAppAnimator != null
    320                 && mAppAnimator.animation == sDummyAnimation;
    321     }
    322 
    323     /**
    324      * Is this window currently set to animate or currently animating?
    325      */
    326     boolean isWindowAnimationSet() {
    327         return mAnimation != null;
    328     }
    329 
    330     /**
    331      * Is this window currently waiting to run an opening animation?
    332      */
    333     boolean isWaitingForOpening() {
    334         return mService.mAppTransition.isTransitionSet() && isDummyAnimation()
    335                 && mService.mOpeningApps.contains(mWin.mAppToken);
    336     }
    337 
    338     void cancelExitAnimationForNextAnimationLocked() {
    339         if (DEBUG_ANIM) Slog.d(TAG,
    340                 "cancelExitAnimationForNextAnimationLocked: " + mWin);
    341 
    342         if (mAnimation != null) {
    343             mAnimation.cancel();
    344             mAnimation = null;
    345             mLocalAnimating = false;
    346             mWin.destroyOrSaveSurfaceUnchecked();
    347         }
    348     }
    349 
    350     private boolean stepAnimation(long currentTime) {
    351         if ((mAnimation == null) || !mLocalAnimating) {
    352             return false;
    353         }
    354         currentTime = getAnimationFrameTime(mAnimation, currentTime);
    355         mTransformation.clear();
    356         final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
    357         if (mAnimationStartDelayed && mAnimationIsEntrance) {
    358             mTransformation.setAlpha(0f);
    359         }
    360         if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
    361                 + ", xform=" + mTransformation);
    362         return more;
    363     }
    364 
    365     // This must be called while inside a transaction.  Returns true if
    366     // there is more animation to run.
    367     boolean stepAnimationLocked(long currentTime) {
    368         // Save the animation state as it was before this step so WindowManagerService can tell if
    369         // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
    370         mWasAnimating = mAnimating;
    371         final DisplayContent displayContent = mWin.getDisplayContent();
    372         if (mWin.mToken.okToAnimate()) {
    373             // We will run animations as long as the display isn't frozen.
    374 
    375             if (mWin.isDrawnLw() && mAnimation != null) {
    376                 mHasTransformation = true;
    377                 mHasLocalTransformation = true;
    378                 if (!mLocalAnimating) {
    379                     if (DEBUG_ANIM) Slog.v(
    380                         TAG, "Starting animation in " + this +
    381                         " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
    382                         " wh=" + mWin.mFrame.height() +
    383                         " dx=" + mAnimDx + " dy=" + mAnimDy +
    384                         " scale=" + mService.getWindowAnimationScaleLocked());
    385                     final DisplayInfo displayInfo = displayContent.getDisplayInfo();
    386                     if (mAnimateMove) {
    387                         mAnimateMove = false;
    388                         mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
    389                                 mAnimDx, mAnimDy);
    390                     } else {
    391                         mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
    392                                 displayInfo.appWidth, displayInfo.appHeight);
    393                     }
    394                     mAnimDx = displayInfo.appWidth;
    395                     mAnimDy = displayInfo.appHeight;
    396                     mAnimation.setStartTime(mAnimationStartTime != -1
    397                             ? mAnimationStartTime
    398                             : currentTime);
    399                     mLocalAnimating = true;
    400                     mAnimating = true;
    401                 }
    402                 if ((mAnimation != null) && mLocalAnimating) {
    403                     mLastAnimationTime = currentTime;
    404                     if (stepAnimation(currentTime)) {
    405                         return true;
    406                     }
    407                 }
    408                 if (DEBUG_ANIM) Slog.v(
    409                     TAG, "Finished animation in " + this +
    410                     " @ " + currentTime);
    411                 //WindowManagerService.this.dump();
    412             }
    413             mHasLocalTransformation = false;
    414             if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null
    415                     && mAppAnimator.animation != null) {
    416                 // When our app token is animating, we kind-of pretend like
    417                 // we are as well.  Note the mLocalAnimating mAnimationIsEntrance
    418                 // part of this check means that we will only do this if
    419                 // our window is not currently exiting, or it is not
    420                 // locally animating itself.  The idea being that one that
    421                 // is exiting and doing a local animation should be removed
    422                 // once that animation is done.
    423                 mAnimating = true;
    424                 mHasTransformation = true;
    425                 mTransformation.clear();
    426                 return false;
    427             } else if (mHasTransformation) {
    428                 // Little trick to get through the path below to act like
    429                 // we have finished an animation.
    430                 mAnimating = true;
    431             } else if (isAnimationSet()) {
    432                 mAnimating = true;
    433             }
    434         } else if (mAnimation != null) {
    435             // If the display is frozen, and there is a pending animation,
    436             // clear it and make sure we run the cleanup code.
    437             mAnimating = true;
    438         }
    439 
    440         if (!mAnimating && !mLocalAnimating) {
    441             return false;
    442         }
    443 
    444         // Done animating, clean up.
    445         if (DEBUG_ANIM) Slog.v(
    446             TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
    447             + ", reportedVisible="
    448             + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
    449 
    450         mAnimating = false;
    451         mLocalAnimating = false;
    452         if (mAnimation != null) {
    453             mAnimation.cancel();
    454             mAnimation = null;
    455         }
    456         if (mAnimator.mWindowDetachedWallpaper == mWin) {
    457             mAnimator.mWindowDetachedWallpaper = null;
    458         }
    459         mAnimLayer = mWin.getSpecialWindowAnimLayerAdjustment();
    460         if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
    461         mHasTransformation = false;
    462         mHasLocalTransformation = false;
    463         mStackClip = STACK_CLIP_BEFORE_ANIM;
    464         mWin.checkPolicyVisibilityChange();
    465         mTransformation.clear();
    466         if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
    467             // Upon completion of a not-visible to visible status bar animation a relayout is
    468             // required.
    469             if (displayContent != null) {
    470                 displayContent.setLayoutNeeded();
    471             }
    472         }
    473 
    474         mWin.onExitAnimationDone();
    475         final int displayId = mWin.getDisplayId();
    476         mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
    477         if (DEBUG_LAYOUT_REPEATS)
    478             mService.mWindowPlacerLocked.debugLayoutRepeats(
    479                     "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
    480 
    481         if (mWin.mAppToken != null) {
    482             mWin.mAppToken.updateReportedVisibilityLocked();
    483         }
    484 
    485         return false;
    486     }
    487 
    488     void hide(String reason) {
    489         if (!mLastHidden) {
    490             //dump();
    491             mLastHidden = true;
    492             if (mSurfaceController != null) {
    493                 mSurfaceController.hideInTransaction(reason);
    494             }
    495         }
    496     }
    497 
    498     boolean finishDrawingLocked() {
    499         final boolean startingWindow =
    500                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
    501         if (DEBUG_STARTING_WINDOW && startingWindow) {
    502             Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
    503                     + drawStateToString());
    504         }
    505 
    506         boolean layoutNeeded = mWin.clearAnimatingWithSavedSurface();
    507 
    508         if (mDrawState == DRAW_PENDING) {
    509             if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
    510                 Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
    511                         + mSurfaceController);
    512             if (DEBUG_STARTING_WINDOW && startingWindow) {
    513                 Slog.v(TAG, "Draw state now committed in " + mWin);
    514             }
    515             mDrawState = COMMIT_DRAW_PENDING;
    516             layoutNeeded = true;
    517         }
    518 
    519         return layoutNeeded;
    520     }
    521 
    522     // This must be called while inside a transaction.
    523     boolean commitFinishDrawingLocked() {
    524         if (DEBUG_STARTING_WINDOW_VERBOSE &&
    525                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
    526             Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
    527                     + drawStateToString());
    528         }
    529         if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
    530             return false;
    531         }
    532         if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
    533             Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
    534         }
    535         mDrawState = READY_TO_SHOW;
    536         boolean result = false;
    537         final AppWindowToken atoken = mWin.mAppToken;
    538         if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
    539             result = mWin.performShowLocked();
    540         }
    541         return result;
    542     }
    543 
    544     void preserveSurfaceLocked() {
    545         if (mDestroyPreservedSurfaceUponRedraw) {
    546             // This could happen when switching the surface mode very fast. For example,
    547             // we preserved a surface when dragResizing changed to true. Then before the
    548             // preserved surface is removed, dragResizing changed to false again.
    549             // In this case, we need to leave the preserved surface alone, and destroy
    550             // the actual surface, so that the createSurface call could create a surface
    551             // of the proper size. The preserved surface will still be removed when client
    552             // finishes drawing to the new surface.
    553             mSurfaceDestroyDeferred = false;
    554             destroySurfaceLocked();
    555             mSurfaceDestroyDeferred = true;
    556             return;
    557         }
    558         if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false);
    559         if (mSurfaceController != null) {
    560             mSurfaceController.setLayer(mAnimLayer + 1);
    561         }
    562         mDestroyPreservedSurfaceUponRedraw = true;
    563         mSurfaceDestroyDeferred = true;
    564         destroySurfaceLocked();
    565     }
    566 
    567     void destroyPreservedSurfaceLocked() {
    568         if (!mDestroyPreservedSurfaceUponRedraw) {
    569             return;
    570         }
    571         if (mSurfaceController != null) {
    572             if (mPendingDestroySurface != null) {
    573                 // If we are preserving a surface but we aren't relaunching that means
    574                 // we are just doing an in-place switch. In that case any SurfaceFlinger side
    575                 // child layers need to be reparented to the new surface to make this
    576                 // transparent to the app.
    577                 if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) {
    578                     SurfaceControl.openTransaction();
    579                     mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
    580                     SurfaceControl.closeTransaction();
    581                 }
    582             }
    583         }
    584 
    585         destroyDeferredSurfaceLocked();
    586         mDestroyPreservedSurfaceUponRedraw = false;
    587     }
    588 
    589     void markPreservedSurfaceForDestroy() {
    590         if (mDestroyPreservedSurfaceUponRedraw
    591                 && !mService.mDestroyPreservedSurface.contains(mWin)) {
    592             mService.mDestroyPreservedSurface.add(mWin);
    593         }
    594     }
    595 
    596     private int getLayerStack() {
    597         return mWin.getDisplayContent().getDisplay().getLayerStack();
    598     }
    599 
    600     void updateLayerStackInTransaction() {
    601         if (mSurfaceController != null) {
    602             mSurfaceController.setLayerStackInTransaction(
    603                     getLayerStack());
    604         }
    605     }
    606 
    607     void resetDrawState() {
    608         mDrawState = DRAW_PENDING;
    609 
    610         if (mWin.mAppToken == null) {
    611             return;
    612         }
    613 
    614         if (mWin.mAppToken.mAppAnimator.animation == null) {
    615             mWin.mAppToken.clearAllDrawn();
    616         } else {
    617             // Currently animating, persist current state of allDrawn until animation
    618             // is complete.
    619             mWin.mAppToken.deferClearAllDrawn = true;
    620         }
    621     }
    622 
    623     WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
    624         final WindowState w = mWin;
    625         if (w.restoreSavedSurface()) {
    626             if (DEBUG_ANIM) Slog.i(TAG,
    627                     "createSurface: " + this + ": called when we had a saved surface");
    628             return mSurfaceController;
    629         }
    630 
    631         if (mSurfaceController != null) {
    632             return mSurfaceController;
    633         }
    634 
    635         if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
    636             windowType = SurfaceControl.WINDOW_TYPE_DONT_SCREENSHOT;
    637         }
    638 
    639         w.setHasSurface(false);
    640 
    641         if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
    642                 "createSurface " + this + ": mDrawState=DRAW_PENDING");
    643 
    644         resetDrawState();
    645 
    646         mService.makeWindowFreezingScreenIfNeededLocked(w);
    647 
    648         int flags = SurfaceControl.HIDDEN;
    649         final WindowManager.LayoutParams attrs = w.mAttrs;
    650 
    651         if (mService.isSecureLocked(w)) {
    652             flags |= SurfaceControl.SECURE;
    653         }
    654 
    655         mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
    656         calculateSurfaceBounds(w, attrs);
    657         final int width = mTmpSize.width();
    658         final int height = mTmpSize.height();
    659 
    660         if (DEBUG_VISIBILITY) {
    661             Slog.v(TAG, "Creating surface in session "
    662                     + mSession.mSurfaceSession + " window " + this
    663                     + " w=" + width + " h=" + height
    664                     + " x=" + mTmpSize.left + " y=" + mTmpSize.top
    665                     + " format=" + attrs.format + " flags=" + flags);
    666         }
    667 
    668         // We may abort, so initialize to defaults.
    669         mLastSystemDecorRect.set(0, 0, 0, 0);
    670         mHasClipRect = false;
    671         mClipRect.set(0, 0, 0, 0);
    672         mLastClipRect.set(0, 0, 0, 0);
    673 
    674         // Set up surface control with initial size.
    675         try {
    676 
    677             final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
    678             final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
    679             if (!PixelFormat.formatHasAlpha(attrs.format)
    680                     // Don't make surface with surfaceInsets opaque as they display a
    681                     // translucent shadow.
    682                     && attrs.surfaceInsets.left == 0
    683                     && attrs.surfaceInsets.top == 0
    684                     && attrs.surfaceInsets.right == 0
    685                     && attrs.surfaceInsets.bottom == 0
    686                     // Don't make surface opaque when resizing to reduce the amount of
    687                     // artifacts shown in areas the app isn't drawing content to.
    688                     && !w.isDragResizing()) {
    689                 flags |= SurfaceControl.OPAQUE;
    690             }
    691 
    692             mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
    693                     attrs.getTitle().toString(),
    694                     width, height, format, flags, this, windowType, ownerUid);
    695             mSurfaceFormat = format;
    696 
    697             w.setHasSurface(true);
    698 
    699             if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    700                 Slog.i(TAG, "  CREATE SURFACE "
    701                         + mSurfaceController + " IN SESSION "
    702                         + mSession.mSurfaceSession
    703                         + ": pid=" + mSession.mPid + " format="
    704                         + attrs.format + " flags=0x"
    705                         + Integer.toHexString(flags)
    706                         + " / " + this);
    707             }
    708         } catch (OutOfResourcesException e) {
    709             Slog.w(TAG, "OutOfResourcesException creating surface");
    710             mService.mRoot.reclaimSomeSurfaceMemory(this, "create", true);
    711             mDrawState = NO_SURFACE;
    712             return null;
    713         } catch (Exception e) {
    714             Slog.e(TAG, "Exception creating surface", e);
    715             mDrawState = NO_SURFACE;
    716             return null;
    717         }
    718 
    719         if (WindowManagerService.localLOGV) Slog.v(TAG, "Got surface: " + mSurfaceController
    720                 + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
    721                 + ", animLayer=" + mAnimLayer);
    722 
    723         if (SHOW_LIGHT_TRANSACTIONS) {
    724             Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
    725             WindowManagerService.logSurface(w, "CREATE pos=("
    726                     + w.mFrame.left + "," + w.mFrame.top + ") ("
    727                     + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
    728         }
    729 
    730         // Start a new transaction and apply position & offset.
    731 
    732         mService.openSurfaceTransaction();
    733         try {
    734             mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, false);
    735             mSurfaceController.setLayerStackInTransaction(getLayerStack());
    736             mSurfaceController.setLayer(mAnimLayer);
    737         } finally {
    738             mService.closeSurfaceTransaction();
    739         }
    740 
    741         mLastHidden = true;
    742 
    743         if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
    744         return mSurfaceController;
    745     }
    746 
    747     private void calculateSurfaceBounds(WindowState w, LayoutParams attrs) {
    748         if ((attrs.flags & FLAG_SCALED) != 0) {
    749             // For a scaled surface, we always want the requested size.
    750             mTmpSize.right = mTmpSize.left + w.mRequestedWidth;
    751             mTmpSize.bottom = mTmpSize.top + w.mRequestedHeight;
    752         } else {
    753             // When we're doing a drag-resizing, request a surface that's fullscreen size,
    754             // so that we don't need to reallocate during the process. This also prevents
    755             // buffer drops due to size mismatch.
    756             if (w.isDragResizing()) {
    757                 if (w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM) {
    758                     mTmpSize.left = 0;
    759                     mTmpSize.top = 0;
    760                 }
    761                 final DisplayInfo displayInfo = w.getDisplayInfo();
    762                 mTmpSize.right = mTmpSize.left + displayInfo.logicalWidth;
    763                 mTmpSize.bottom = mTmpSize.top + displayInfo.logicalHeight;
    764             } else {
    765                 mTmpSize.right = mTmpSize.left + w.mCompatFrame.width();
    766                 mTmpSize.bottom = mTmpSize.top + w.mCompatFrame.height();
    767             }
    768         }
    769 
    770         // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
    771         // This doesn't necessarily mean that there is an error in the system. The sizes might be
    772         // incorrect, because it is before the first layout or draw.
    773         if (mTmpSize.width() < 1) {
    774             mTmpSize.right = mTmpSize.left + 1;
    775         }
    776         if (mTmpSize.height() < 1) {
    777             mTmpSize.bottom = mTmpSize.top + 1;
    778         }
    779 
    780         // Adjust for surface insets.
    781         mTmpSize.left -= attrs.surfaceInsets.left;
    782         mTmpSize.top -= attrs.surfaceInsets.top;
    783         mTmpSize.right += attrs.surfaceInsets.right;
    784         mTmpSize.bottom += attrs.surfaceInsets.bottom;
    785     }
    786 
    787     boolean hasSurface() {
    788         return !mWin.hasSavedSurface()
    789                 && mSurfaceController != null && mSurfaceController.hasSurface();
    790     }
    791 
    792     void destroySurfaceLocked() {
    793         final AppWindowToken wtoken = mWin.mAppToken;
    794         if (wtoken != null) {
    795             if (mWin == wtoken.startingWindow) {
    796                 wtoken.startingDisplayed = false;
    797             }
    798         }
    799 
    800         mWin.clearHasSavedSurface();
    801 
    802         if (mSurfaceController == null) {
    803             return;
    804         }
    805 
    806         // When destroying a surface we want to make sure child windows are hidden. If we are
    807         // preserving the surface until redraw though we intend to swap it out with another surface
    808         // for resizing. In this case the window always remains visible to the user and the child
    809         // windows should likewise remain visible.
    810         if (!mDestroyPreservedSurfaceUponRedraw) {
    811             mWin.mHidden = true;
    812         }
    813 
    814         try {
    815             if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
    816                     + mSurfaceController + ", session " + mSession);
    817             if (mSurfaceDestroyDeferred) {
    818                 if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
    819                     if (mPendingDestroySurface != null) {
    820                         if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    821                             WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
    822                         }
    823                         mPendingDestroySurface.destroyInTransaction();
    824                     }
    825                     mPendingDestroySurface = mSurfaceController;
    826                 }
    827             } else {
    828                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    829                     WindowManagerService.logSurface(mWin, "DESTROY", true);
    830                 }
    831                 destroySurface();
    832             }
    833             // Don't hide wallpaper if we're deferring the surface destroy
    834             // because of a surface change.
    835             if (!mDestroyPreservedSurfaceUponRedraw) {
    836                 mWallpaperControllerLocked.hideWallpapers(mWin);
    837             }
    838         } catch (RuntimeException e) {
    839             Slog.w(TAG, "Exception thrown when destroying Window " + this
    840                 + " surface " + mSurfaceController + " session " + mSession + ": " + e.toString());
    841         }
    842 
    843         // Whether the surface was preserved (and copied to mPendingDestroySurface) or not, it
    844         // needs to be cleared to match the WindowState.mHasSurface state. It is also necessary
    845         // so it can be recreated successfully in mPendingDestroySurface case.
    846         mWin.setHasSurface(false);
    847         if (mSurfaceController != null) {
    848             mSurfaceController.setShown(false);
    849         }
    850         mSurfaceController = null;
    851         mDrawState = NO_SURFACE;
    852     }
    853 
    854     void destroyDeferredSurfaceLocked() {
    855         try {
    856             if (mPendingDestroySurface != null) {
    857                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
    858                     WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
    859                 }
    860                 mPendingDestroySurface.destroyInTransaction();
    861                 // Don't hide wallpaper if we're destroying a deferred surface
    862                 // after a surface mode change.
    863                 if (!mDestroyPreservedSurfaceUponRedraw) {
    864                     mWallpaperControllerLocked.hideWallpapers(mWin);
    865                 }
    866             }
    867         } catch (RuntimeException e) {
    868             Slog.w(TAG, "Exception thrown when destroying Window "
    869                     + this + " surface " + mPendingDestroySurface
    870                     + " session " + mSession + ": " + e.toString());
    871         }
    872         mSurfaceDestroyDeferred = false;
    873         mPendingDestroySurface = null;
    874     }
    875 
    876     void applyMagnificationSpec(MagnificationSpec spec, Matrix transform) {
    877         final int surfaceInsetLeft = mWin.mAttrs.surfaceInsets.left;
    878         final int surfaceInsetTop = mWin.mAttrs.surfaceInsets.top;
    879 
    880         if (spec != null && !spec.isNop()) {
    881             float scale = spec.scale;
    882             transform.postScale(scale, scale);
    883             transform.postTranslate(spec.offsetX, spec.offsetY);
    884 
    885             // As we are scaling the whole surface, to keep the content
    886             // in the same position we will also have to scale the surfaceInsets.
    887             transform.postTranslate(-(surfaceInsetLeft*scale - surfaceInsetLeft),
    888                     -(surfaceInsetTop*scale - surfaceInsetTop));
    889         }
    890     }
    891 
    892     void computeShownFrameLocked() {
    893         final boolean selfTransformation = mHasLocalTransformation;
    894         Transformation attachedTransformation =
    895                 (mParentWinAnimator != null && mParentWinAnimator.mHasLocalTransformation)
    896                 ? mParentWinAnimator.mTransformation : null;
    897         Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
    898                 ? mAppAnimator.transformation : null;
    899 
    900         // Wallpapers are animated based on the "real" window they
    901         // are currently targeting.
    902         final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
    903         if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
    904             final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
    905             if (wallpaperAnimator.mHasLocalTransformation &&
    906                     wallpaperAnimator.mAnimation != null &&
    907                     !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
    908                 attachedTransformation = wallpaperAnimator.mTransformation;
    909                 if (DEBUG_WALLPAPER && attachedTransformation != null) {
    910                     Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
    911                 }
    912             }
    913             final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
    914                     null : wallpaperTarget.mAppToken.mAppAnimator;
    915                 if (wpAppAnimator != null && wpAppAnimator.hasTransformation
    916                     && wpAppAnimator.animation != null
    917                     && !wpAppAnimator.animation.getDetachWallpaper()) {
    918                 appTransformation = wpAppAnimator.transformation;
    919                 if (DEBUG_WALLPAPER && appTransformation != null) {
    920                     Slog.v(TAG, "WP target app xform: " + appTransformation);
    921                 }
    922             }
    923         }
    924 
    925         final int displayId = mWin.getDisplayId();
    926         final ScreenRotationAnimation screenRotationAnimation =
    927                 mAnimator.getScreenRotationAnimationLocked(displayId);
    928         final boolean screenAnimation =
    929                 screenRotationAnimation != null && screenRotationAnimation.isAnimating();
    930 
    931         mHasClipRect = false;
    932         if (selfTransformation || attachedTransformation != null
    933                 || appTransformation != null || screenAnimation) {
    934             // cache often used attributes locally
    935             final Rect frame = mWin.mFrame;
    936             final float tmpFloats[] = mService.mTmpFloats;
    937             final Matrix tmpMatrix = mWin.mTmpMatrix;
    938 
    939             // Compute the desired transformation.
    940             if (screenAnimation && screenRotationAnimation.isRotating()) {
    941                 // If we are doing a screen animation, the global rotation
    942                 // applied to windows can result in windows that are carefully
    943                 // aligned with each other to slightly separate, allowing you
    944                 // to see what is behind them.  An unsightly mess.  This...
    945                 // thing...  magically makes it call good: scale each window
    946                 // slightly (two pixels larger in each dimension, from the
    947                 // window's center).
    948                 final float w = frame.width();
    949                 final float h = frame.height();
    950                 if (w>=1 && h>=1) {
    951                     tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);
    952                 } else {
    953                     tmpMatrix.reset();
    954                 }
    955             } else {
    956                 tmpMatrix.reset();
    957             }
    958             tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
    959             if (selfTransformation) {
    960                 tmpMatrix.postConcat(mTransformation.getMatrix());
    961             }
    962             if (attachedTransformation != null) {
    963                 tmpMatrix.postConcat(attachedTransformation.getMatrix());
    964             }
    965             if (appTransformation != null) {
    966                 tmpMatrix.postConcat(appTransformation.getMatrix());
    967             }
    968 
    969             // The translation that applies the position of the window needs to be applied at the
    970             // end in case that other translations include scaling. Otherwise the scaling will
    971             // affect this translation. But it needs to be set before the screen rotation animation
    972             // so the pivot point is at the center of the screen for all windows.
    973             tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
    974             if (screenAnimation) {
    975                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
    976             }
    977 
    978             MagnificationSpec spec = getMagnificationSpec();
    979             if (spec != null) {
    980                 applyMagnificationSpec(spec, tmpMatrix);
    981             }
    982 
    983             // "convert" it into SurfaceFlinger's format
    984             // (a 2x2 matrix + an offset)
    985             // Here we must not transform the position of the surface
    986             // since it is already included in the transformation.
    987             //Slog.i(TAG_WM, "Transform: " + matrix);
    988 
    989             mHaveMatrix = true;
    990             tmpMatrix.getValues(tmpFloats);
    991             mDsDx = tmpFloats[Matrix.MSCALE_X];
    992             mDtDx = tmpFloats[Matrix.MSKEW_Y];
    993             mDtDy = tmpFloats[Matrix.MSKEW_X];
    994             mDsDy = tmpFloats[Matrix.MSCALE_Y];
    995             float x = tmpFloats[Matrix.MTRANS_X];
    996             float y = tmpFloats[Matrix.MTRANS_Y];
    997             mWin.mShownPosition.set(Math.round(x), Math.round(y));
    998 
    999             // Now set the alpha...  but because our current hardware
   1000             // can't do alpha transformation on a non-opaque surface,
   1001             // turn it off if we are running an animation that is also
   1002             // transforming since it is more important to have that
   1003             // animation be smooth.
   1004             mShownAlpha = mAlpha;
   1005             if (!mService.mLimitedAlphaCompositing
   1006                     || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
   1007                     || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
   1008                             && x == frame.left && y == frame.top))) {
   1009                 //Slog.i(TAG_WM, "Applying alpha transform");
   1010                 if (selfTransformation) {
   1011                     mShownAlpha *= mTransformation.getAlpha();
   1012                 }
   1013                 if (attachedTransformation != null) {
   1014                     mShownAlpha *= attachedTransformation.getAlpha();
   1015                 }
   1016                 if (appTransformation != null) {
   1017                     mShownAlpha *= appTransformation.getAlpha();
   1018                     if (appTransformation.hasClipRect()) {
   1019                         mClipRect.set(appTransformation.getClipRect());
   1020                         mHasClipRect = true;
   1021                         // The app transformation clip will be in the coordinate space of the main
   1022                         // activity window, which the animation correctly assumes will be placed at
   1023                         // (0,0)+(insets) relative to the containing frame. This isn't necessarily
   1024                         // true for child windows though which can have an arbitrary frame position
   1025                         // relative to their containing frame. We need to offset the difference
   1026                         // between the containing frame as used to calculate the crop and our
   1027                         // bounds to compensate for this.
   1028                         if (mWin.layoutInParentFrame()) {
   1029                             mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
   1030                                     mWin.mContainingFrame.top - mWin.mFrame.top );
   1031                         }
   1032                     }
   1033                 }
   1034                 if (screenAnimation) {
   1035                     mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
   1036                 }
   1037             } else {
   1038                 //Slog.i(TAG_WM, "Not applying alpha transform");
   1039             }
   1040 
   1041             if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)
   1042                     && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
   1043                     TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
   1044                     + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
   1045                     + " attached=" + (attachedTransformation == null ?
   1046                             "null" : attachedTransformation.getAlpha())
   1047                     + " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
   1048                     + " screen=" + (screenAnimation ?
   1049                             screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
   1050             return;
   1051         } else if (mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
   1052             return;
   1053         } else if (mWin.isDragResizeChanged()) {
   1054             // This window is awaiting a relayout because user just started (or ended)
   1055             // drag-resizing. The shown frame (which affects surface size and pos)
   1056             // should not be updated until we get next finished draw with the new surface.
   1057             // Otherwise one or two frames rendered with old settings would be displayed
   1058             // with new geometry.
   1059             return;
   1060         }
   1061 
   1062         if (WindowManagerService.localLOGV) Slog.v(
   1063                 TAG, "computeShownFrameLocked: " + this +
   1064                 " not attached, mAlpha=" + mAlpha);
   1065 
   1066         MagnificationSpec spec = getMagnificationSpec();
   1067         if (spec != null) {
   1068             final Rect frame = mWin.mFrame;
   1069             final float tmpFloats[] = mService.mTmpFloats;
   1070             final Matrix tmpMatrix = mWin.mTmpMatrix;
   1071 
   1072             tmpMatrix.setScale(mWin.mGlobalScale, mWin.mGlobalScale);
   1073             tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
   1074 
   1075             applyMagnificationSpec(spec, tmpMatrix);
   1076 
   1077             tmpMatrix.getValues(tmpFloats);
   1078 
   1079             mHaveMatrix = true;
   1080             mDsDx = tmpFloats[Matrix.MSCALE_X];
   1081             mDtDx = tmpFloats[Matrix.MSKEW_Y];
   1082             mDtDy = tmpFloats[Matrix.MSKEW_X];
   1083             mDsDy = tmpFloats[Matrix.MSCALE_Y];
   1084             float x = tmpFloats[Matrix.MTRANS_X];
   1085             float y = tmpFloats[Matrix.MTRANS_Y];
   1086             mWin.mShownPosition.set(Math.round(x), Math.round(y));
   1087 
   1088             mShownAlpha = mAlpha;
   1089         } else {
   1090             mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
   1091             if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
   1092                 mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
   1093             }
   1094             mShownAlpha = mAlpha;
   1095             mHaveMatrix = false;
   1096             mDsDx = mWin.mGlobalScale;
   1097             mDtDx = 0;
   1098             mDtDy = 0;
   1099             mDsDy = mWin.mGlobalScale;
   1100         }
   1101     }
   1102 
   1103     private MagnificationSpec getMagnificationSpec() {
   1104         //TODO (multidisplay): Magnification is supported only for the default display.
   1105         if (mService.mAccessibilityController != null && mWin.getDisplayId() == DEFAULT_DISPLAY) {
   1106             return mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);
   1107         }
   1108         return null;
   1109     }
   1110 
   1111     /**
   1112      * In some scenarios we use a screen space clip rect (so called, final clip rect)
   1113      * to crop to stack bounds. Generally because it's easier to deal with while
   1114      * animating.
   1115      *
   1116      * @return True in scenarios where we use the final clip rect for stack clipping.
   1117      */
   1118     private boolean useFinalClipRect() {
   1119         return (isAnimationSet() && resolveStackClip() == STACK_CLIP_AFTER_ANIM)
   1120                 || mDestroyPreservedSurfaceUponRedraw || mWin.inPinnedWorkspace();
   1121     }
   1122 
   1123     /**
   1124      * Calculate the screen-space crop rect and fill finalClipRect.
   1125      * @return true if finalClipRect has been filled, otherwise,
   1126      * no screen space crop should be applied.
   1127      */
   1128     private boolean calculateFinalCrop(Rect finalClipRect) {
   1129         final WindowState w = mWin;
   1130         final DisplayContent displayContent = w.getDisplayContent();
   1131         finalClipRect.setEmpty();
   1132 
   1133         if (displayContent == null) {
   1134             return false;
   1135         }
   1136 
   1137         if (!shouldCropToStackBounds() || !useFinalClipRect()) {
   1138             return false;
   1139         }
   1140 
   1141         // Task is non-null per shouldCropToStackBounds
   1142         final TaskStack stack = w.getTask().mStack;
   1143         stack.getDimBounds(finalClipRect);
   1144 
   1145         if (StackId.tasksAreFloating(stack.mStackId)) {
   1146             w.expandForSurfaceInsets(finalClipRect);
   1147         }
   1148 
   1149         // We may be applying a magnification spec to all windows,
   1150         // simulating a transformation in screen space, in which case
   1151         // we need to transform all other screen space values...including
   1152         // the final crop. This is kind of messed up and we should look
   1153         // in to actually transforming screen-space via a parent-layer.
   1154         // b/38322835
   1155         MagnificationSpec spec = getMagnificationSpec();
   1156         if (spec != null && !spec.isNop()) {
   1157             Matrix transform = mWin.mTmpMatrix;
   1158             RectF finalCrop = mService.mTmpRectF;
   1159             transform.reset();
   1160             transform.postScale(spec.scale, spec.scale);
   1161             transform.postTranslate(-spec.offsetX, -spec.offsetY);
   1162             transform.mapRect(finalCrop);
   1163             finalClipRect.top = (int)finalCrop.top;
   1164             finalClipRect.left = (int)finalCrop.left;
   1165             finalClipRect.right = (int)finalClipRect.right;
   1166             finalClipRect.bottom = (int)finalClipRect.bottom;
   1167         }
   1168 
   1169         return true;
   1170     }
   1171 
   1172     /**
   1173      * Calculate the window-space crop rect and fill clipRect.
   1174      * @return true if clipRect has been filled otherwise, no window space crop should be applied.
   1175      */
   1176     private boolean calculateCrop(Rect clipRect) {
   1177         final WindowState w = mWin;
   1178         final DisplayContent displayContent = w.getDisplayContent();
   1179         clipRect.setEmpty();
   1180 
   1181         if (displayContent == null) {
   1182             return false;
   1183         }
   1184 
   1185         if (w.inPinnedWorkspace()) {
   1186             return false;
   1187         }
   1188 
   1189         // If we're animating, the wallpaper should only
   1190         // be updated at the end of the animation.
   1191         if (w.mAttrs.type == TYPE_WALLPAPER) {
   1192             return false;
   1193         }
   1194 
   1195         if (DEBUG_WINDOW_CROP) Slog.d(TAG,
   1196                 "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
   1197 
   1198         w.calculatePolicyCrop(mSystemDecorRect);
   1199 
   1200         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
   1201                 + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
   1202 
   1203         final Task task = w.getTask();
   1204         final boolean fullscreen = w.fillsDisplay() || (task != null && task.isFullscreen());
   1205         final boolean isFreeformResizing =
   1206                 w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
   1207 
   1208         // We use the clip rect as provided by the tranformation for non-fullscreen windows to
   1209         // avoid premature clipping with the system decor rect.
   1210         clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
   1211         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
   1212                 + " mHasClipRect=" + mHasClipRect + " fullscreen=" + fullscreen);
   1213 
   1214         if (isFreeformResizing && !w.isChildWindow()) {
   1215             // For freeform resizing non child windows, we are using the big surface positioned
   1216             // at 0,0. Thus we must express the crop in that coordinate space.
   1217             clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
   1218         }
   1219 
   1220         w.expandForSurfaceInsets(clipRect);
   1221 
   1222         if (mHasClipRect && fullscreen) {
   1223             // We intersect the clip rect specified by the transformation with the expanded system
   1224             // decor rect to prevent artifacts from drawing during animation if the transformation
   1225             // clip rect extends outside the system decor rect.
   1226             clipRect.intersect(mClipRect);
   1227         }
   1228         // The clip rect was generated assuming (0,0) as the window origin,
   1229         // so we need to translate to match the actual surface coordinates.
   1230         clipRect.offset(w.mAttrs.surfaceInsets.left, w.mAttrs.surfaceInsets.top);
   1231 
   1232         if (!useFinalClipRect()) {
   1233             adjustCropToStackBounds(clipRect, isFreeformResizing);
   1234         }
   1235         if (DEBUG_WINDOW_CROP) Slog.d(TAG,
   1236                 "win=" + w + " Clip rect after stack adjustment=" + clipRect);
   1237 
   1238         w.transformClipRectFromScreenToSurfaceSpace(clipRect);
   1239 
   1240         return true;
   1241     }
   1242 
   1243     private void applyCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
   1244         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "applyCrop: win=" + mWin
   1245                 + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
   1246         if (clipRect != null) {
   1247             if (!clipRect.equals(mLastClipRect)) {
   1248                 mLastClipRect.set(clipRect);
   1249                 mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
   1250             }
   1251         } else {
   1252             mSurfaceController.clearCropInTransaction(recoveringMemory);
   1253         }
   1254 
   1255         if (finalClipRect == null) {
   1256             finalClipRect = mService.mTmpRect;
   1257             finalClipRect.setEmpty();
   1258         }
   1259         if (!finalClipRect.equals(mLastFinalClipRect)) {
   1260             mLastFinalClipRect.set(finalClipRect);
   1261             mSurfaceController.setFinalCropInTransaction(finalClipRect);
   1262             if (mDestroyPreservedSurfaceUponRedraw && mPendingDestroySurface != null) {
   1263                 mPendingDestroySurface.setFinalCropInTransaction(finalClipRect);
   1264             }
   1265         }
   1266     }
   1267 
   1268     private int resolveStackClip() {
   1269         // App animation overrides window animation stack clip mode.
   1270         if (mAppAnimator != null && mAppAnimator.animation != null) {
   1271             return mAppAnimator.getStackClip();
   1272         } else {
   1273             return mStackClip;
   1274         }
   1275     }
   1276 
   1277     private boolean shouldCropToStackBounds() {
   1278         final WindowState w = mWin;
   1279         final DisplayContent displayContent = w.getDisplayContent();
   1280         if (displayContent != null && !displayContent.isDefaultDisplay) {
   1281             // There are some windows that live on other displays while their app and main window
   1282             // live on the default display (e.g. casting...). We don't want to crop this windows
   1283             // to the stack bounds which is only currently supported on the default display.
   1284             // TODO(multi-display): Need to support cropping to stack bounds on other displays
   1285             // when we have stacks on other displays.
   1286             return false;
   1287         }
   1288 
   1289         final Task task = w.getTask();
   1290         if (task == null || !task.cropWindowsToStackBounds()) {
   1291             return false;
   1292         }
   1293 
   1294         final int stackClip = resolveStackClip();
   1295 
   1296         // It's animating and we don't want to clip it to stack bounds during animation - abort.
   1297         if (isAnimationSet() && stackClip == STACK_CLIP_NONE) {
   1298             return false;
   1299         }
   1300         return true;
   1301     }
   1302 
   1303     private void adjustCropToStackBounds(Rect clipRect,
   1304             boolean isFreeformResizing) {
   1305         final WindowState w = mWin;
   1306 
   1307         if (!shouldCropToStackBounds()) {
   1308             return;
   1309         }
   1310 
   1311         final TaskStack stack = w.getTask().mStack;
   1312         stack.getDimBounds(mTmpStackBounds);
   1313         final Rect surfaceInsets = w.getAttrs().surfaceInsets;
   1314         // When we resize we use the big surface approach, which means we can't trust the
   1315         // window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
   1316         // hardcoding it, we use surface coordinates.
   1317         final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
   1318                 w.mFrame.left + mWin.mXOffset - surfaceInsets.left;
   1319         final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
   1320                 w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
   1321 
   1322         // We need to do some acrobatics with surface position, because their clip region is
   1323         // relative to the inside of the surface, but the stack bounds aren't.
   1324         if (StackId.hasWindowShadow(stack.mStackId)
   1325                 && !StackId.isTaskResizeAllowed(stack.mStackId)) {
   1326                 // The windows in this stack display drop shadows and the fill the entire stack
   1327                 // area. Adjust the stack bounds we will use to cropping take into account the
   1328                 // offsets we use to display the drop shadow so it doesn't get cropped.
   1329                 mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
   1330                         -surfaceInsets.right, -surfaceInsets.bottom);
   1331         }
   1332 
   1333         clipRect.left = Math.max(0,
   1334                 Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
   1335         clipRect.top = Math.max(0,
   1336                 Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
   1337         clipRect.right = Math.max(0,
   1338                 Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
   1339         clipRect.bottom = Math.max(0,
   1340                 Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
   1341     }
   1342 
   1343     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
   1344         if (mSurfaceController == null) {
   1345             return;
   1346         }
   1347 
   1348         final WindowState w = mWin;
   1349         final LayoutParams attrs = mWin.getAttrs();
   1350         final Task task = w.getTask();
   1351 
   1352         // We got resized, so block all updates until we got the new surface.
   1353         if (w.isResizedWhileNotDragResizing() && !w.isGoneForLayoutLw()) {
   1354             return;
   1355         }
   1356 
   1357         mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
   1358         calculateSurfaceBounds(w, attrs);
   1359 
   1360         mExtraHScale = (float) 1.0;
   1361         mExtraVScale = (float) 1.0;
   1362 
   1363         boolean wasForceScaled = mForceScaleUntilResize;
   1364         boolean wasSeamlesslyRotated = w.mSeamlesslyRotated;
   1365 
   1366         // Once relayout has been called at least once, we need to make sure
   1367         // we only resize the client surface during calls to relayout. For
   1368         // clients which use indeterminate measure specs (MATCH_PARENT),
   1369         // we may try and change their window size without a call to relayout.
   1370         // However, this would be unsafe, as the client may be in the middle
   1371         // of producing a frame at the old size, having just completed layout
   1372         // to find the surface size changed underneath it.
   1373         if (!w.mRelayoutCalled || w.mInRelayout) {
   1374             mSurfaceResized = mSurfaceController.setSizeInTransaction(
   1375                     mTmpSize.width(), mTmpSize.height(), recoveringMemory);
   1376         } else {
   1377             mSurfaceResized = false;
   1378         }
   1379         mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
   1380         // If we are undergoing seamless rotation, the surface has already
   1381         // been set up to persist at it's old location. We need to freeze
   1382         // updates until a resize occurs.
   1383         mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
   1384 
   1385         Rect clipRect = null, finalClipRect = null;
   1386         if (calculateCrop(mTmpClipRect)) {
   1387             clipRect = mTmpClipRect;
   1388         }
   1389         if (calculateFinalCrop(mTmpFinalClipRect)) {
   1390             finalClipRect = mTmpFinalClipRect;
   1391         }
   1392 
   1393         float surfaceWidth = mSurfaceController.getWidth();
   1394         float surfaceHeight = mSurfaceController.getHeight();
   1395 
   1396         if (isForceScaled()) {
   1397             int hInsets = attrs.surfaceInsets.left + attrs.surfaceInsets.right;
   1398             int vInsets = attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
   1399             float surfaceContentWidth = surfaceWidth - hInsets;
   1400             float surfaceContentHeight = surfaceHeight - vInsets;
   1401             if (!mForceScaleUntilResize) {
   1402                 mSurfaceController.forceScaleableInTransaction(true);
   1403             }
   1404 
   1405             int posX = mTmpSize.left;
   1406             int posY = mTmpSize.top;
   1407             task.mStack.getDimBounds(mTmpStackBounds);
   1408 
   1409             boolean allowStretching = false;
   1410             task.mStack.getFinalAnimationSourceHintBounds(mTmpSourceBounds);
   1411             // If we don't have source bounds, we can attempt to use the content insets
   1412             // in the following scenario:
   1413             //    1. We have content insets.
   1414             //    2. We are not transitioning to full screen
   1415             // We have to be careful to check "lastAnimatingBoundsWasToFullscreen" rather than
   1416             // the mBoundsAnimating state, as we may have already left it and only be here
   1417             // because of the force-scale until resize state.
   1418             if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0
   1419                     || mWin.mLastRelayoutContentInsets.height() > 0)
   1420                         && !task.mStack.lastAnimatingBoundsWasToFullscreen()) {
   1421                 mTmpSourceBounds.set(task.mStack.mPreAnimationBounds);
   1422                 mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
   1423                 allowStretching = true;
   1424             }
   1425             if (!mTmpSourceBounds.isEmpty()) {
   1426                 // Get the final target stack bounds, if we are not animating, this is just the
   1427                 // current stack bounds
   1428                 task.mStack.getFinalAnimationBounds(mTmpAnimatingBounds);
   1429 
   1430                 // Calculate the current progress and interpolate the difference between the target
   1431                 // and source bounds
   1432                 float finalWidth = mTmpAnimatingBounds.width();
   1433                 float initialWidth = mTmpSourceBounds.width();
   1434                 float tw = (surfaceContentWidth - mTmpStackBounds.width())
   1435                         / (surfaceContentWidth - mTmpAnimatingBounds.width());
   1436                 float th = tw;
   1437                 mExtraHScale = (initialWidth + tw * (finalWidth - initialWidth)) / initialWidth;
   1438                 if (allowStretching) {
   1439                     float finalHeight = mTmpAnimatingBounds.height();
   1440                     float initialHeight = mTmpSourceBounds.height();
   1441                     th = (surfaceContentHeight - mTmpStackBounds.height())
   1442                         / (surfaceContentHeight - mTmpAnimatingBounds.height());
   1443                     mExtraVScale = (initialHeight + tw * (finalHeight - initialHeight))
   1444                             / initialHeight;
   1445                 } else {
   1446                     mExtraVScale = mExtraHScale;
   1447                 }
   1448 
   1449                 // Adjust the position to account for the inset bounds
   1450                 posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left);
   1451                 posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top);
   1452 
   1453                 // Always clip to the stack bounds since the surface can be larger with the current
   1454                 // scale
   1455                 clipRect = null;
   1456                 finalClipRect = mTmpStackBounds;
   1457             } else {
   1458                 // We want to calculate the scaling based on the content area, not based on
   1459                 // the entire surface, so that we scale in sync with windows that don't have insets.
   1460                 mExtraHScale = mTmpStackBounds.width() / surfaceContentWidth;
   1461                 mExtraVScale = mTmpStackBounds.height() / surfaceContentHeight;
   1462 
   1463                 // Since we are scaled to fit in our previously desired crop, we can now
   1464                 // expose the whole window in buffer space, and not risk extending
   1465                 // past where the system would have cropped us
   1466                 clipRect = null;
   1467                 finalClipRect = null;
   1468             }
   1469 
   1470             // In the case of ForceScaleToStack we scale entire tasks together,
   1471             // and so we need to scale our offsets relative to the task bounds
   1472             // or parent and child windows would fall out of alignment.
   1473             posX -= (int) (attrs.x * (1 - mExtraHScale));
   1474             posY -= (int) (attrs.y * (1 - mExtraVScale));
   1475 
   1476             // Imagine we are scaling down. As we scale the buffer down, we decrease the
   1477             // distance between the surface top left, and the start of the surface contents
   1478             // (previously it was surfaceInsets.left pixels in screen space but now it
   1479             // will be surfaceInsets.left*mExtraHScale). This means in order to keep the
   1480             // non inset content at the same position, we have to shift the whole window
   1481             // forward. Likewise for scaling up, we've increased this distance, and we need
   1482             // to shift by a negative number to compensate.
   1483             posX += attrs.surfaceInsets.left * (1 - mExtraHScale);
   1484             posY += attrs.surfaceInsets.top * (1 - mExtraVScale);
   1485 
   1486             mSurfaceController.setPositionInTransaction((float) Math.floor(posX),
   1487                     (float) Math.floor(posY), recoveringMemory);
   1488 
   1489             // Various surfaces in the scaled stack may resize at different times.
   1490             // We need to ensure for each surface, that we disable transformation matrix
   1491             // scaling in the same transaction which we resize the surface in.
   1492             // As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
   1493             // then take over the scaling until the new buffer arrives, and things
   1494             // will be seamless.
   1495             mForceScaleUntilResize = true;
   1496         } else {
   1497             if (!w.mSeamlesslyRotated) {
   1498                 mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
   1499                         recoveringMemory);
   1500             }
   1501         }
   1502 
   1503         // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
   1504         // to prevent further updates until buffer latch.
   1505         // When ending both force scaling, and seamless rotation, we need to freeze
   1506         // the Surface geometry until a buffer comes in at the new size (normally position and crop
   1507         // are unfrozen). setGeometryAppliesWithResizeInTransaction accomplishes this for us.
   1508         if ((wasForceScaled && !mForceScaleUntilResize) ||
   1509                 (wasSeamlesslyRotated && !w.mSeamlesslyRotated)) {
   1510             mSurfaceController.setGeometryAppliesWithResizeInTransaction(true);
   1511             mSurfaceController.forceScaleableInTransaction(false);
   1512         }
   1513 
   1514         if (!w.mSeamlesslyRotated) {
   1515             applyCrop(clipRect, finalClipRect, recoveringMemory);
   1516             mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
   1517                     mDtDx * w.mVScale * mExtraVScale,
   1518                     mDtDy * w.mHScale * mExtraHScale,
   1519                     mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
   1520         }
   1521 
   1522         if (mSurfaceResized) {
   1523             mReportSurfaceResized = true;
   1524             mAnimator.setPendingLayoutChanges(w.getDisplayId(),
   1525                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
   1526             w.applyDimLayerIfNeeded();
   1527         }
   1528     }
   1529 
   1530     /**
   1531      * Get rect of the task this window is currently in. If there is no task, rect will be set to
   1532      * empty.
   1533      */
   1534     void getContainerRect(Rect rect) {
   1535         final Task task = mWin.getTask();
   1536         if (task != null) {
   1537             task.getDimBounds(rect);
   1538         } else {
   1539             rect.left = rect.top = rect.right = rect.bottom = 0;
   1540         }
   1541     }
   1542 
   1543     void prepareSurfaceLocked(final boolean recoveringMemory) {
   1544         final WindowState w = mWin;
   1545         if (!hasSurface()) {
   1546 
   1547             // There is no need to wait for an animation change if our window is gone for layout
   1548             // already as we'll never be visible.
   1549             if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
   1550                 if (DEBUG_ORIENTATION) {
   1551                     Slog.v(TAG, "Orientation change skips hidden " + w);
   1552                 }
   1553                 w.setOrientationChanging(false);
   1554             }
   1555             return;
   1556         }
   1557 
   1558         // Do not change surface properties of opening apps if we are waiting for the
   1559         // transition to be ready. transitionGoodToGo could be not ready even after all
   1560         // opening apps are drawn. It's only waiting on isFetchingAppTransitionsSpecs()
   1561         // to get the animation spec. (For example, go into Recents and immediately open
   1562         // the same app again before the app's surface is destroyed or saved, the surface
   1563         // is always ready in the whole process.) If we go ahead here, the opening app
   1564         // will be shown with the full size before the correct animation spec arrives.
   1565         if (isWaitingForOpening()) {
   1566             return;
   1567         }
   1568 
   1569         boolean displayed = false;
   1570 
   1571         computeShownFrameLocked();
   1572 
   1573         setSurfaceBoundariesLocked(recoveringMemory);
   1574 
   1575         if (mIsWallpaper && !mWin.mWallpaperVisible) {
   1576             // Wallpaper is no longer visible and there is no wp target => hide it.
   1577             hide("prepareSurfaceLocked");
   1578         } else if (w.isParentWindowHidden() || !w.isOnScreen()) {
   1579             hide("prepareSurfaceLocked");
   1580             mWallpaperControllerLocked.hideWallpapers(w);
   1581 
   1582             // If we are waiting for this window to handle an orientation change. If this window is
   1583             // really hidden (gone for layout), there is no point in still waiting for it.
   1584             // Note that this does introduce a potential glitch if the window becomes unhidden
   1585             // before it has drawn for the new orientation.
   1586             if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
   1587                 w.setOrientationChanging(false);
   1588                 if (DEBUG_ORIENTATION) Slog.v(TAG,
   1589                         "Orientation change skips hidden " + w);
   1590             }
   1591         } else if (mLastLayer != mAnimLayer
   1592                 || mLastAlpha != mShownAlpha
   1593                 || mLastDsDx != mDsDx
   1594                 || mLastDtDx != mDtDx
   1595                 || mLastDsDy != mDsDy
   1596                 || mLastDtDy != mDtDy
   1597                 || w.mLastHScale != w.mHScale
   1598                 || w.mLastVScale != w.mVScale
   1599                 || mLastHidden) {
   1600             displayed = true;
   1601             mLastAlpha = mShownAlpha;
   1602             mLastLayer = mAnimLayer;
   1603             mLastDsDx = mDsDx;
   1604             mLastDtDx = mDtDx;
   1605             mLastDsDy = mDsDy;
   1606             mLastDtDy = mDtDy;
   1607             w.mLastHScale = w.mHScale;
   1608             w.mLastVScale = w.mVScale;
   1609             if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
   1610                     "controller=" + mSurfaceController +
   1611                     "alpha=" + mShownAlpha + " layer=" + mAnimLayer
   1612                     + " matrix=[" + mDsDx + "*" + w.mHScale
   1613                     + "," + mDtDx + "*" + w.mVScale
   1614                     + "][" + mDtDy + "*" + w.mHScale
   1615                     + "," + mDsDy + "*" + w.mVScale + "]", false);
   1616 
   1617             boolean prepared =
   1618                 mSurfaceController.prepareToShowInTransaction(mShownAlpha,
   1619                         mDsDx * w.mHScale * mExtraHScale,
   1620                         mDtDx * w.mVScale * mExtraVScale,
   1621                         mDtDy * w.mHScale * mExtraHScale,
   1622                         mDsDy * w.mVScale * mExtraVScale,
   1623                         recoveringMemory);
   1624             mSurfaceController.setLayer(mAnimLayer);
   1625 
   1626             if (prepared && mDrawState == HAS_DRAWN) {
   1627                 if (mLastHidden) {
   1628                     if (showSurfaceRobustlyLocked()) {
   1629                         markPreservedSurfaceForDestroy();
   1630                         mAnimator.requestRemovalOfReplacedWindows(w);
   1631                         mLastHidden = false;
   1632                         if (mIsWallpaper) {
   1633                             w.dispatchWallpaperVisibility(true);
   1634                         }
   1635                         // This draw means the difference between unique content and mirroring.
   1636                         // Run another pass through performLayout to set mHasContent in the
   1637                         // LogicalDisplay.
   1638                         mAnimator.setPendingLayoutChanges(w.getDisplayId(),
   1639                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
   1640                     } else {
   1641                         w.setOrientationChanging(false);
   1642                     }
   1643                 }
   1644                 // We process mTurnOnScreen even for windows which have already
   1645                 // been shown, to handle cases where windows are not necessarily
   1646                 // hidden while the screen is turning off.
   1647                 // TODO(b/63773439): These cases should be eliminated, though we probably still
   1648                 // want to process mTurnOnScreen in this way for clarity.
   1649                 if (mWin.mTurnOnScreen &&
   1650                         (mWin.mAppToken == null || mWin.mAppToken.canTurnScreenOn())) {
   1651                     if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
   1652                     mWin.mTurnOnScreen = false;
   1653 
   1654                     // The window should only turn the screen on once per resume, but
   1655                     // prepareSurfaceLocked can be called multiple times. Set canTurnScreenOn to
   1656                     // false so the window doesn't turn the screen on again during this resume.
   1657                     if (mWin.mAppToken != null) {
   1658                         mWin.mAppToken.setCanTurnScreenOn(false);
   1659                     }
   1660 
   1661                     // We do not add {@code SET_TURN_ON_SCREEN} when the screen is already
   1662                     // interactive as the value may persist until the next animation, which could
   1663                     // potentially occurring while turning off the screen. This would lead to the
   1664                     // screen incorrectly turning back on.
   1665                     if (!mService.mPowerManager.isInteractive()) {
   1666                         mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
   1667                     }
   1668                 }
   1669             }
   1670             if (hasSurface()) {
   1671                 w.mToken.hasVisible = true;
   1672             }
   1673         } else {
   1674             if (DEBUG_ANIM && isAnimationSet()) {
   1675                 Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
   1676             }
   1677             displayed = true;
   1678         }
   1679 
   1680         if (w.getOrientationChanging()) {
   1681             if (!w.isDrawnLw()) {
   1682                 mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
   1683                 mAnimator.mLastWindowFreezeSource = w;
   1684                 if (DEBUG_ORIENTATION) Slog.v(TAG,
   1685                         "Orientation continue waiting for draw in " + w);
   1686             } else {
   1687                 w.setOrientationChanging(false);
   1688                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
   1689             }
   1690         }
   1691 
   1692         if (displayed) {
   1693             w.mToken.hasVisible = true;
   1694         }
   1695     }
   1696 
   1697     void setTransparentRegionHintLocked(final Region region) {
   1698         if (mSurfaceController == null) {
   1699             Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
   1700             return;
   1701         }
   1702         mSurfaceController.setTransparentRegionHint(region);
   1703     }
   1704 
   1705     void setWallpaperOffset(Point shownPosition) {
   1706         final LayoutParams attrs = mWin.getAttrs();
   1707         final int left = shownPosition.x - attrs.surfaceInsets.left;
   1708         final int top = shownPosition.y - attrs.surfaceInsets.top;
   1709 
   1710         try {
   1711             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
   1712             mService.openSurfaceTransaction();
   1713             mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
   1714                     mWin.mFrame.top + top, false);
   1715             applyCrop(null, null, false);
   1716         } catch (RuntimeException e) {
   1717             Slog.w(TAG, "Error positioning surface of " + mWin
   1718                     + " pos=(" + left + "," + top + ")", e);
   1719         } finally {
   1720             mService.closeSurfaceTransaction();
   1721             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
   1722                     "<<< CLOSE TRANSACTION setWallpaperOffset");
   1723         }
   1724     }
   1725 
   1726     /**
   1727      * Try to change the pixel format without recreating the surface. This
   1728      * will be common in the case of changing from PixelFormat.OPAQUE to
   1729      * PixelFormat.TRANSLUCENT in the hardware-accelerated case as both
   1730      * requested formats resolve to the same underlying SurfaceControl format
   1731      * @return True if format was succesfully changed, false otherwise
   1732      */
   1733     boolean tryChangeFormatInPlaceLocked() {
   1734         if (mSurfaceController == null) {
   1735             return false;
   1736         }
   1737         final LayoutParams attrs = mWin.getAttrs();
   1738         final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
   1739         final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
   1740         if (format == mSurfaceFormat) {
   1741             setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
   1742             return true;
   1743         }
   1744         return false;
   1745     }
   1746 
   1747     void setOpaqueLocked(boolean isOpaque) {
   1748         if (mSurfaceController == null) {
   1749             return;
   1750         }
   1751         mSurfaceController.setOpaque(isOpaque);
   1752     }
   1753 
   1754     void setSecureLocked(boolean isSecure) {
   1755         if (mSurfaceController == null) {
   1756             return;
   1757         }
   1758         mSurfaceController.setSecure(isSecure);
   1759     }
   1760 
   1761     /**
   1762      * Have the surface flinger show a surface, robustly dealing with
   1763      * error conditions.  In particular, if there is not enough memory
   1764      * to show the surface, then we will try to get rid of other surfaces
   1765      * in order to succeed.
   1766      *
   1767      * @return Returns true if the surface was successfully shown.
   1768      */
   1769     private boolean showSurfaceRobustlyLocked() {
   1770         final Task task = mWin.getTask();
   1771         if (task != null && StackId.windowsAreScaleable(task.mStack.mStackId)) {
   1772             mSurfaceController.forceScaleableInTransaction(true);
   1773         }
   1774 
   1775         boolean shown = mSurfaceController.showRobustlyInTransaction();
   1776         if (!shown)
   1777             return false;
   1778 
   1779         return true;
   1780     }
   1781 
   1782     void applyEnterAnimationLocked() {
   1783         // If we are the new part of a window replacement transition and we have requested
   1784         // not to animate, we instead want to make it seamless, so we don't want to apply
   1785         // an enter transition.
   1786         if (mWin.mSkipEnterAnimationForSeamlessReplacement) {
   1787             return;
   1788         }
   1789         final int transit;
   1790         if (mEnterAnimationPending) {
   1791             mEnterAnimationPending = false;
   1792             transit = WindowManagerPolicy.TRANSIT_ENTER;
   1793         } else {
   1794             transit = WindowManagerPolicy.TRANSIT_SHOW;
   1795         }
   1796         applyAnimationLocked(transit, true);
   1797         //TODO (multidisplay): Magnification is supported only for the default display.
   1798         if (mService.mAccessibilityController != null
   1799                 && mWin.getDisplayId() == DEFAULT_DISPLAY) {
   1800             mService.mAccessibilityController.onWindowTransitionLocked(mWin, transit);
   1801         }
   1802     }
   1803 
   1804     /**
   1805      * Choose the correct animation and set it to the passed WindowState.
   1806      * @param transit If AppTransition.TRANSIT_PREVIEW_DONE and the app window has been drawn
   1807      *      then the animation will be app_starting_exit. Any other value loads the animation from
   1808      *      the switch statement below.
   1809      * @param isEntrance The animation type the last time this was called. Used to keep from
   1810      *      loading the same animation twice.
   1811      * @return true if an animation has been loaded.
   1812      */
   1813     boolean applyAnimationLocked(int transit, boolean isEntrance) {
   1814         if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
   1815             // If we are trying to apply an animation, but already running
   1816             // an animation of the same type, then just leave that one alone.
   1817             return true;
   1818         }
   1819 
   1820         // Only apply an animation if the display isn't frozen.  If it is
   1821         // frozen, there is no reason to animate and it can cause strange
   1822         // artifacts when we unfreeze the display if some different animation
   1823         // is running.
   1824         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
   1825         if (mWin.mToken.okToAnimate()) {
   1826             int anim = mPolicy.selectAnimationLw(mWin, transit);
   1827             int attr = -1;
   1828             Animation a = null;
   1829             if (anim != 0) {
   1830                 a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
   1831             } else {
   1832                 switch (transit) {
   1833                     case WindowManagerPolicy.TRANSIT_ENTER:
   1834                         attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
   1835                         break;
   1836                     case WindowManagerPolicy.TRANSIT_EXIT:
   1837                         attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
   1838                         break;
   1839                     case WindowManagerPolicy.TRANSIT_SHOW:
   1840                         attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
   1841                         break;
   1842                     case WindowManagerPolicy.TRANSIT_HIDE:
   1843                         attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
   1844                         break;
   1845                 }
   1846                 if (attr >= 0) {
   1847                     a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);
   1848                 }
   1849             }
   1850             if (DEBUG_ANIM) Slog.v(TAG,
   1851                     "applyAnimation: win=" + this
   1852                     + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
   1853                     + " a=" + a
   1854                     + " transit=" + transit
   1855                     + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
   1856             if (a != null) {
   1857                 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
   1858                 setAnimation(a);
   1859                 mAnimationIsEntrance = isEntrance;
   1860             }
   1861         } else {
   1862             clearAnimation();
   1863         }
   1864         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
   1865 
   1866         if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
   1867             mWin.getDisplayContent().adjustForImeIfNeeded();
   1868             if (isEntrance) {
   1869                 mWin.setDisplayLayoutNeeded();
   1870                 mService.mWindowPlacerLocked.requestTraversal();
   1871             }
   1872         }
   1873         return mAnimation != null;
   1874     }
   1875 
   1876     private void applyFadeoutDuringKeyguardExitAnimation() {
   1877         long startTime = mAnimation.getStartTime();
   1878         long duration = mAnimation.getDuration();
   1879         long elapsed = mLastAnimationTime - startTime;
   1880         long fadeDuration = duration - elapsed;
   1881         if (fadeDuration <= 0) {
   1882             // Never mind, this would be no visible animation, so abort the animation change.
   1883             return;
   1884         }
   1885         AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
   1886         newAnimation.setDuration(duration);
   1887         newAnimation.setStartTime(startTime);
   1888         newAnimation.addAnimation(mAnimation);
   1889         Animation fadeOut = AnimationUtils.loadAnimation(
   1890                 mContext, com.android.internal.R.anim.app_starting_exit);
   1891         fadeOut.setDuration(fadeDuration);
   1892         fadeOut.setStartOffset(elapsed);
   1893         newAnimation.addAnimation(fadeOut);
   1894         newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDx, mAnimDy);
   1895         mAnimation = newAnimation;
   1896     }
   1897 
   1898     public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
   1899         if (mAnimating || mLocalAnimating || mAnimationIsEntrance
   1900                 || mAnimation != null) {
   1901             pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
   1902                     pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
   1903                     pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
   1904                     pw.print(" mAnimation="); pw.print(mAnimation);
   1905                     pw.print(" mStackClip="); pw.println(mStackClip);
   1906         }
   1907         if (mHasTransformation || mHasLocalTransformation) {
   1908             pw.print(prefix); pw.print("XForm: has=");
   1909                     pw.print(mHasTransformation);
   1910                     pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
   1911                     pw.print(" "); mTransformation.printShortString(pw);
   1912                     pw.println();
   1913         }
   1914         if (mSurfaceController != null) {
   1915             mSurfaceController.dump(pw, prefix, dumpAll);
   1916         }
   1917         if (dumpAll) {
   1918             pw.print(prefix); pw.print("mDrawState="); pw.print(drawStateToString());
   1919             pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
   1920             pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
   1921             pw.print(" last="); mLastSystemDecorRect.printShortString(pw);
   1922             pw.print(" mHasClipRect="); pw.print(mHasClipRect);
   1923             pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
   1924 
   1925             if (!mLastFinalClipRect.isEmpty()) {
   1926                 pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
   1927             }
   1928             pw.println();
   1929         }
   1930 
   1931         if (mPendingDestroySurface != null) {
   1932             pw.print(prefix); pw.print("mPendingDestroySurface=");
   1933                     pw.println(mPendingDestroySurface);
   1934         }
   1935         if (mSurfaceResized || mSurfaceDestroyDeferred) {
   1936             pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
   1937                     pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred);
   1938         }
   1939         if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
   1940             pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
   1941                     pw.print(" mAlpha="); pw.print(mAlpha);
   1942                     pw.print(" mLastAlpha="); pw.println(mLastAlpha);
   1943         }
   1944         if (mHaveMatrix || mWin.mGlobalScale != 1) {
   1945             pw.print(prefix); pw.print("mGlobalScale="); pw.print(mWin.mGlobalScale);
   1946                     pw.print(" mDsDx="); pw.print(mDsDx);
   1947                     pw.print(" mDtDx="); pw.print(mDtDx);
   1948                     pw.print(" mDtDy="); pw.print(mDtDy);
   1949                     pw.print(" mDsDy="); pw.println(mDsDy);
   1950         }
   1951         if (mAnimationStartDelayed) {
   1952             pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed);
   1953         }
   1954     }
   1955 
   1956     @Override
   1957     public String toString() {
   1958         StringBuffer sb = new StringBuffer("WindowStateAnimator{");
   1959         sb.append(Integer.toHexString(System.identityHashCode(this)));
   1960         sb.append(' ');
   1961         sb.append(mWin.mAttrs.getTitle());
   1962         sb.append('}');
   1963         return sb.toString();
   1964     }
   1965 
   1966     void reclaimSomeSurfaceMemory(String operation, boolean secure) {
   1967         mService.mRoot.reclaimSomeSurfaceMemory(this, operation, secure);
   1968     }
   1969 
   1970     boolean getShown() {
   1971         if (mSurfaceController != null) {
   1972             return mSurfaceController.getShown();
   1973         }
   1974         return false;
   1975     }
   1976 
   1977     void destroySurface() {
   1978         try {
   1979             if (mSurfaceController != null) {
   1980                 mSurfaceController.destroyInTransaction();
   1981             }
   1982         } catch (RuntimeException e) {
   1983             Slog.w(TAG, "Exception thrown when destroying surface " + this
   1984                     + " surface " + mSurfaceController + " session " + mSession + ": " + e);
   1985         } finally {
   1986             mWin.setHasSurface(false);
   1987             mSurfaceController = null;
   1988             mDrawState = NO_SURFACE;
   1989         }
   1990     }
   1991 
   1992     void setMoveAnimation(int left, int top) {
   1993         final Animation a = AnimationUtils.loadAnimation(mContext,
   1994                 com.android.internal.R.anim.window_move_from_decor);
   1995         setAnimation(a);
   1996         mAnimDx = mWin.mLastFrame.left - left;
   1997         mAnimDy = mWin.mLastFrame.top - top;
   1998         mAnimateMove = true;
   1999     }
   2000 
   2001     void deferTransactionUntilParentFrame(long frameNumber) {
   2002         if (!mWin.isChildWindow()) {
   2003             return;
   2004         }
   2005         mSurfaceController.deferTransactionUntil(
   2006                 mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(), frameNumber);
   2007     }
   2008 
   2009     /**
   2010      * Sometimes we need to synchronize the first frame of animation with some external event.
   2011      * To achieve this, we prolong the start of the animation and keep producing the first frame of
   2012      * the animation.
   2013      */
   2014     private long getAnimationFrameTime(Animation animation, long currentTime) {
   2015         if (mAnimationStartDelayed) {
   2016             animation.setStartTime(currentTime);
   2017             return currentTime + 1;
   2018         }
   2019         return currentTime;
   2020     }
   2021 
   2022     void startDelayingAnimationStart() {
   2023         mAnimationStartDelayed = true;
   2024     }
   2025 
   2026     void endDelayingAnimationStart() {
   2027         mAnimationStartDelayed = false;
   2028     }
   2029 
   2030     void seamlesslyRotateWindow(int oldRotation, int newRotation) {
   2031         final WindowState w = mWin;
   2032         if (!w.isVisibleNow() || w.mIsWallpaper) {
   2033             return;
   2034         }
   2035 
   2036         final Rect cropRect = mService.mTmpRect;
   2037         final Rect displayRect = mService.mTmpRect2;
   2038         final RectF frameRect = mService.mTmpRectF;
   2039         final Matrix transform = mService.mTmpTransform;
   2040 
   2041         final float x = w.mFrame.left;
   2042         final float y = w.mFrame.top;
   2043         final float width = w.mFrame.width();
   2044         final float height = w.mFrame.height();
   2045 
   2046         mService.getDefaultDisplayContentLocked().getLogicalDisplayRect(displayRect);
   2047         final float displayWidth = displayRect.width();
   2048         final float displayHeight = displayRect.height();
   2049 
   2050         // Compute a transform matrix to undo the coordinate space transformation,
   2051         // and present the window at the same physical position it previously occupied.
   2052         final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
   2053         DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight,
   2054                 transform);
   2055 
   2056         // We just need to apply a rotation matrix to the window. For example
   2057         // if we have a portrait window and rotate to landscape, the window is still portrait
   2058         // and now extends off the bottom of the screen (and only halfway across). Essentially we
   2059         // apply a transform to display the current buffer at it's old position
   2060         // (in the new coordinate space). We then freeze layer updates until the resize
   2061         // occurs, at which point we undo, them.
   2062         mService.markForSeamlessRotation(w, true);
   2063         transform.getValues(mService.mTmpFloats);
   2064 
   2065         float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
   2066         float DtDx = mService.mTmpFloats[Matrix.MSKEW_Y];
   2067         float DtDy = mService.mTmpFloats[Matrix.MSKEW_X];
   2068         float DsDy = mService.mTmpFloats[Matrix.MSCALE_Y];
   2069         float nx = mService.mTmpFloats[Matrix.MTRANS_X];
   2070         float ny = mService.mTmpFloats[Matrix.MTRANS_Y];
   2071         mSurfaceController.setPositionInTransaction(nx, ny, false);
   2072         mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale,
   2073                 DtDx * w.mVScale,
   2074                 DtDy * w.mHScale,
   2075                 DsDy * w.mVScale, false);
   2076     }
   2077 
   2078     void enableSurfaceTrace(FileDescriptor fd) {
   2079         if (mSurfaceController != null) {
   2080             mSurfaceController.installRemoteTrace(fd);
   2081         }
   2082     }
   2083 
   2084     void disableSurfaceTrace() {
   2085         if (mSurfaceController != null) {
   2086             try {
   2087                 mSurfaceController.removeRemoteTrace();
   2088             } catch (ClassCastException e) {
   2089                 Slog.e(TAG, "Disable surface trace for " + this + " but its not enabled");
   2090             }
   2091         }
   2092     }
   2093 
   2094     /** The force-scaled state for a given window can persist past
   2095      * the state for it's stack as the windows complete resizing
   2096      * independently of one another.
   2097      */
   2098     boolean isForceScaled() {
   2099         final Task task = mWin.getTask();
   2100         if (task != null && task.mStack.isForceScaled()) {
   2101             return true;
   2102         }
   2103         return mForceScaleUntilResize;
   2104     }
   2105 
   2106     void detachChildren() {
   2107         if (mSurfaceController != null) {
   2108             mSurfaceController.detachChildren();
   2109         }
   2110     }
   2111 }
   2112