2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.wm;
19 import static android.app.ActivityManager.StackId;
20 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
21 import static android.view.Display.DEFAULT_DISPLAY;
22 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
23 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
24 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
25 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
26 import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
27 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
28 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
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_SURFACE_TRACE;
35 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
37 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
38 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
39 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
40 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
41 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
42 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
43 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
44 import static com.android.server.wm.WindowManagerService.localLOGV;
45 import static com.android.server.wm.WindowManagerService.logWithStack;
46 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
47 import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
49 import android.content.Context;
50 import android.graphics.Matrix;
51 import android.graphics.PixelFormat;
52 import android.graphics.Point;
53 import android.graphics.Rect;
54 import android.graphics.RectF;
55 import android.graphics.Region;
56 import android.os.Debug;
57 import android.os.RemoteException;
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;
63 import android.view.Surface.OutOfResourcesException;
64 import android.view.SurfaceControl;
65 import android.view.WindowManager;
66 import android.view.WindowManager.LayoutParams;
67 import android.view.WindowManagerPolicy;
68 import android.view.animation.Animation;
69 import android.view.animation.AnimationSet;
70 import android.view.animation.AnimationUtils;
71 import android.view.animation.Transformation;
73 import com.android.server.wm.WindowManagerService.H;
75 import java.io.PrintWriter;
78 * Keep track of animations and surface operations for a single WindowState.
80 class WindowStateAnimator {
81 static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
82 static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
85 * Mode how the window gets clipped by the stack bounds during an animation: The clipping should
86 * be applied after applying the animation transformation, i.e. the stack bounds don't move
87 * during the animation.
89 static final int STACK_CLIP_AFTER_ANIM = 0;
92 * Mode how the window gets clipped by the stack bounds: The clipping should be applied before
93 * applying the animation transformation, i.e. the stack bounds move with the window.
95 static final int STACK_CLIP_BEFORE_ANIM = 1;
98 * Mode how window gets clipped by the stack bounds during an animation: Don't clip the window
99 * by the stack bounds.
101 static final int STACK_CLIP_NONE = 2;
103 // Unchanging local convenience fields.
104 final WindowManagerService mService;
105 final WindowState mWin;
106 final WindowStateAnimator mAttachedWinAnimator;
107 final WindowAnimator mAnimator;
108 AppWindowAnimator mAppAnimator;
109 final Session mSession;
110 final WindowManagerPolicy mPolicy;
111 final Context mContext;
112 final boolean mIsWallpaper;
113 final WallpaperController mWallpaperControllerLocked;
115 // Currently running animation.
117 boolean mLocalAnimating;
118 Animation mAnimation;
119 boolean mAnimationIsEntrance;
120 boolean mHasTransformation;
121 boolean mHasLocalTransformation;
122 final Transformation mTransformation = new Transformation();
123 boolean mWasAnimating; // Were we animating going into the most recent animation step?
126 long mAnimationStartTime;
127 long mLastAnimationTime;
128 int mStackClip = STACK_CLIP_BEFORE_ANIM;
131 * Set when we have changed the size of the surface, to know that
132 * we must tell them application to resize (and thus redraw itself).
134 boolean mSurfaceResized;
136 * Whether we should inform the client on next relayoutWindow that
137 * the surface has been resized since last time.
139 boolean mReportSurfaceResized;
140 WindowSurfaceController mSurfaceController;
141 private WindowSurfaceController mPendingDestroySurface;
144 * Set if the client has asked that the destroy of its surface be delayed
145 * until it explicitly says it is okay.
147 boolean mSurfaceDestroyDeferred;
149 private boolean mDestroyPreservedSurfaceUponRedraw;
150 float mShownAlpha = 0;
152 float mLastAlpha = 0;
154 boolean mHasClipRect;
155 Rect mClipRect = new Rect();
156 Rect mTmpClipRect = new Rect();
157 Rect mTmpFinalClipRect = new Rect();
158 Rect mLastClipRect = new Rect();
159 Rect mLastFinalClipRect = new Rect();
160 Rect mTmpStackBounds = new Rect();
163 * This is rectangle of the window's surface that is not covered by
164 * system decorations.
166 private final Rect mSystemDecorRect = new Rect();
167 private final Rect mLastSystemDecorRect = new Rect();
169 // Used to save animation distances between the time they are calculated and when they are used.
173 /** Is the next animation to be started a window move animation? */
174 private boolean mAnimateMove = false;
176 float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
177 float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
181 // Set to true if, when the window gets displayed, it should perform
182 // an enter animation.
183 boolean mEnterAnimationPending;
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;
190 private boolean mAnimationStartDelayed;
192 boolean mKeyguardGoingAwayAnimation;
193 boolean mKeyguardGoingAwayWithWallpaper;
195 /** The pixel format of the underlying SurfaceControl */
198 /** This is set when there is no Surface */
199 static final int NO_SURFACE = 0;
200 /** This is set after the Surface has been created but before the window has been drawn. During
201 * this time the surface is hidden. */
202 static final int DRAW_PENDING = 1;
203 /** This is set after the window has finished drawing for the first time but before its surface
204 * is shown. The surface will be displayed when the next layout is run. */
205 static final int COMMIT_DRAW_PENDING = 2;
206 /** This is set during the time after the window's drawing has been committed, and before its
207 * surface is actually shown. It is used to delay showing the surface until all windows in a
208 * token are ready to be shown. */
209 static final int READY_TO_SHOW = 3;
210 /** Set when the window has been shown in the screen the first time. */
211 static final int HAS_DRAWN = 4;
213 String drawStateToString() {
214 switch (mDrawState) {
215 case NO_SURFACE: return "NO_SURFACE";
216 case DRAW_PENDING: return "DRAW_PENDING";
217 case COMMIT_DRAW_PENDING: return "COMMIT_DRAW_PENDING";
218 case READY_TO_SHOW: return "READY_TO_SHOW";
219 case HAS_DRAWN: return "HAS_DRAWN";
220 default: return Integer.toString(mDrawState);
225 /** Was this window last hidden? */
230 static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
231 long mDeferTransactionUntilFrame = -1;
232 long mDeferTransactionTime = -1;
234 boolean mForceScaleUntilResize;
236 // WindowState.mHScale and WindowState.mVScale contain the
237 // scale according to client specified layout parameters (e.g.
238 // one layout size, with another surface size, creates such scaling).
239 // Here we track an additional scaling factor used to follow stack
240 // scaling (as in the case of the Pinned stack animation).
241 float mExtraHScale = (float) 1.0;
242 float mExtraVScale = (float) 1.0;
244 private final Rect mTmpSize = new Rect();
246 WindowStateAnimator(final WindowState win) {
247 final WindowManagerService service = win.mService;
250 mAnimator = service.mAnimator;
251 mPolicy = service.mPolicy;
252 mContext = service.mContext;
253 final DisplayContent displayContent = win.getDisplayContent();
254 if (displayContent != null) {
255 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
256 mAnimDx = displayInfo.appWidth;
257 mAnimDy = displayInfo.appHeight;
259 Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
260 // This is checked on return and dealt with.
264 mAttachedWinAnimator = win.mAttachedWindow == null
265 ? null : win.mAttachedWindow.mWinAnimator;
266 mAppAnimator = win.mAppToken == null ? null : win.mAppToken.mAppAnimator;
267 mSession = win.mSession;
268 mAttrType = win.mAttrs.type;
269 mIsWallpaper = win.mIsWallpaper;
270 mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
273 public void setAnimation(Animation anim, long startTime, int stackClip) {
274 if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
276 mLocalAnimating = false;
278 mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
279 mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
280 // Start out animation gone if window is gone, or visible if window is visible.
281 mTransformation.clear();
282 mTransformation.setAlpha(mLastHidden ? 0 : 1);
283 mHasLocalTransformation = true;
284 mAnimationStartTime = startTime;
285 mStackClip = stackClip;
288 public void setAnimation(Animation anim, int stackClip) {
289 setAnimation(anim, -1, stackClip);
292 public void setAnimation(Animation anim) {
293 setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
296 public void clearAnimation() {
297 if (mAnimation != null) {
299 mLocalAnimating = false;
302 mKeyguardGoingAwayAnimation = false;
303 mKeyguardGoingAwayWithWallpaper = false;
304 mStackClip = STACK_CLIP_BEFORE_ANIM;
309 * Is the window or its container currently set to animate or currently animating?
311 boolean isAnimationSet() {
312 return mAnimation != null
313 || (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)
314 || (mAppAnimator != null && mAppAnimator.isAnimating());
318 * @return whether an animation is about to start, i.e. the animation is set already but we
319 * haven't processed the first frame yet.
321 boolean isAnimationStarting() {
322 return isAnimationSet() && !mAnimating;
325 /** Is the window animating the DummyAnimation? */
326 boolean isDummyAnimation() {
327 return mAppAnimator != null
328 && mAppAnimator.animation == sDummyAnimation;
332 * Is this window currently set to animate or currently animating?
334 boolean isWindowAnimationSet() {
335 return mAnimation != null;
339 * Is this window currently waiting to run an opening animation?
341 boolean isWaitingForOpening() {
342 return mService.mAppTransition.isTransitionSet() && isDummyAnimation()
343 && mService.mOpeningApps.contains(mWin.mAppToken);
346 void cancelExitAnimationForNextAnimationLocked() {
347 if (DEBUG_ANIM) Slog.d(TAG,
348 "cancelExitAnimationForNextAnimationLocked: " + mWin);
350 if (mAnimation != null) {
353 mLocalAnimating = false;
354 mWin.destroyOrSaveSurface();
358 private boolean stepAnimation(long currentTime) {
359 if ((mAnimation == null) || !mLocalAnimating) {
362 currentTime = getAnimationFrameTime(mAnimation, currentTime);
363 mTransformation.clear();
364 final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
365 if (mAnimationStartDelayed && mAnimationIsEntrance) {
366 mTransformation.setAlpha(0f);
368 if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
369 + ", xform=" + mTransformation);
373 // This must be called while inside a transaction. Returns true if
374 // there is more animation to run.
375 boolean stepAnimationLocked(long currentTime) {
376 // Save the animation state as it was before this step so WindowManagerService can tell if
377 // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
378 mWasAnimating = mAnimating;
379 final DisplayContent displayContent = mWin.getDisplayContent();
380 if (displayContent != null && mService.okToDisplay()) {
381 // We will run animations as long as the display isn't frozen.
383 if (mWin.isDrawnLw() && mAnimation != null) {
384 mHasTransformation = true;
385 mHasLocalTransformation = true;
386 if (!mLocalAnimating) {
387 if (DEBUG_ANIM) Slog.v(
388 TAG, "Starting animation in " + this +
389 " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
390 " wh=" + mWin.mFrame.height() +
391 " dx=" + mAnimDx + " dy=" + mAnimDy +
392 " scale=" + mService.getWindowAnimationScaleLocked());
393 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
395 mAnimateMove = false;
396 mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
399 mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
400 displayInfo.appWidth, displayInfo.appHeight);
402 mAnimDx = displayInfo.appWidth;
403 mAnimDy = displayInfo.appHeight;
404 mAnimation.setStartTime(mAnimationStartTime != -1
405 ? mAnimationStartTime
407 mLocalAnimating = true;
410 if ((mAnimation != null) && mLocalAnimating) {
411 mLastAnimationTime = currentTime;
412 if (stepAnimation(currentTime)) {
416 if (DEBUG_ANIM) Slog.v(
417 TAG, "Finished animation in " + this +
418 " @ " + currentTime);
419 //WindowManagerService.this.dump();
421 mHasLocalTransformation = false;
422 if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null
423 && mAppAnimator.animation != null) {
424 // When our app token is animating, we kind-of pretend like
425 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
426 // part of this check means that we will only do this if
427 // our window is not currently exiting, or it is not
428 // locally animating itself. The idea being that one that
429 // is exiting and doing a local animation should be removed
430 // once that animation is done.
432 mHasTransformation = true;
433 mTransformation.clear();
435 } else if (mHasTransformation) {
436 // Little trick to get through the path below to act like
437 // we have finished an animation.
439 } else if (isAnimationSet()) {
442 } else if (mAnimation != null) {
443 // If the display is frozen, and there is a pending animation,
444 // clear it and make sure we run the cleanup code.
448 if (!mAnimating && !mLocalAnimating) {
452 // Done animating, clean up.
453 if (DEBUG_ANIM) Slog.v(
454 TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
455 + ", reportedVisible="
456 + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
459 mKeyguardGoingAwayAnimation = false;
460 mKeyguardGoingAwayWithWallpaper = false;
461 mLocalAnimating = false;
462 if (mAnimation != null) {
466 if (mAnimator.mWindowDetachedWallpaper == mWin) {
467 mAnimator.mWindowDetachedWallpaper = null;
469 mAnimLayer = mWin.mLayer
470 + mService.mLayersController.getSpecialWindowAnimLayerAdjustment(mWin);
471 if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
472 mHasTransformation = false;
473 mHasLocalTransformation = false;
474 mStackClip = STACK_CLIP_BEFORE_ANIM;
475 mWin.checkPolicyVisibilityChange();
476 mTransformation.clear();
477 if (mDrawState == HAS_DRAWN
478 && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
479 && mWin.mAppToken != null
480 && mWin.mAppToken.firstWindowDrawn
481 && mWin.mAppToken.startingData != null) {
482 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Finish starting "
483 + mWin.mToken + ": first real window done animating");
484 mService.mFinishedStarting.add(mWin.mAppToken);
485 mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
486 } else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
487 // Upon completion of a not-visible to visible status bar animation a relayout is
489 if (displayContent != null) {
490 displayContent.layoutNeeded = true;
495 final int displayId = mWin.getDisplayId();
496 mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
497 if (DEBUG_LAYOUT_REPEATS)
498 mService.mWindowPlacerLocked.debugLayoutRepeats(
499 "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
501 if (mWin.mAppToken != null) {
502 mWin.mAppToken.updateReportedVisibilityLocked();
509 if (DEBUG_ANIM) Slog.v(
510 TAG, "finishExit in " + this
511 + ": exiting=" + mWin.mAnimatingExit
512 + " remove=" + mWin.mRemoveOnExit
513 + " windowAnimating=" + isWindowAnimationSet());
515 if (!mWin.mChildWindows.isEmpty()) {
516 // Copying to a different list as multiple children can be removed.
517 final WindowList childWindows = new WindowList(mWin.mChildWindows);
518 for (int i = childWindows.size() - 1; i >= 0; i--) {
519 childWindows.get(i).mWinAnimator.finishExit();
523 if (mEnteringAnimation) {
524 mEnteringAnimation = false;
525 mService.requestTraversal();
526 // System windows don't have an activity and an app token as a result, but need a way
527 // to be informed about their entrance animation end.
528 if (mWin.mAppToken == null) {
530 mWin.mClient.dispatchWindowShown();
531 } catch (RemoteException e) {
536 if (!isWindowAnimationSet()) {
537 //TODO (multidisplay): Accessibility is supported only for the default display.
538 if (mService.mAccessibilityController != null
539 && mWin.getDisplayId() == DEFAULT_DISPLAY) {
540 mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
544 if (!mWin.mAnimatingExit) {
548 if (isWindowAnimationSet()) {
552 if (WindowManagerService.localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG,
553 "Exit animation finished in " + this + ": remove=" + mWin.mRemoveOnExit);
556 mWin.mDestroying = true;
558 final boolean hasSurface = hasSurface();
563 // If we have an app token, we ask it to destroy the surface for us,
564 // so that it can take care to ensure the activity has actually stopped
565 // and the surface is not still in use. Otherwise we add the service to
566 // mDestroySurface and allow it to be processed in our next transaction.
567 if (mWin.mAppToken != null) {
568 mWin.mAppToken.destroySurfaces();
571 mService.mDestroySurface.add(mWin);
573 if (mWin.mRemoveOnExit) {
574 mService.mPendingRemove.add(mWin);
575 mWin.mRemoveOnExit = false;
578 mWin.mAnimatingExit = false;
579 mWallpaperControllerLocked.hideWallpapers(mWin);
582 void hide(String reason) {
586 if (mSurfaceController != null) {
587 mSurfaceController.hideInTransaction(reason);
592 boolean finishDrawingLocked() {
593 final boolean startingWindow =
594 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
595 if (DEBUG_STARTING_WINDOW && startingWindow) {
596 Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
597 + drawStateToString());
600 boolean layoutNeeded = mWin.clearAnimatingWithSavedSurface();
602 if (mDrawState == DRAW_PENDING) {
603 if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
604 Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
605 + mSurfaceController);
606 if (DEBUG_STARTING_WINDOW && startingWindow) {
607 Slog.v(TAG, "Draw state now committed in " + mWin);
609 mDrawState = COMMIT_DRAW_PENDING;
616 // This must be called while inside a transaction.
617 boolean commitFinishDrawingLocked() {
618 if (DEBUG_STARTING_WINDOW &&
619 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
620 Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
621 + drawStateToString());
623 if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
626 if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
627 Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
629 mDrawState = READY_TO_SHOW;
630 boolean result = false;
631 final AppWindowToken atoken = mWin.mAppToken;
632 if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
633 result = performShowLocked();
638 void preserveSurfaceLocked() {
639 if (mDestroyPreservedSurfaceUponRedraw) {
640 // This could happen when switching the surface mode very fast. For example,
641 // we preserved a surface when dragResizing changed to true. Then before the
642 // preserved surface is removed, dragResizing changed to false again.
643 // In this case, we need to leave the preserved surface alone, and destroy
644 // the actual surface, so that the createSurface call could create a surface
645 // of the proper size. The preserved surface will still be removed when client
646 // finishes drawing to the new surface.
647 mSurfaceDestroyDeferred = false;
648 destroySurfaceLocked();
649 mSurfaceDestroyDeferred = true;
652 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false);
653 if (mSurfaceController != null) {
654 mSurfaceController.setLayer(mAnimLayer + 1);
656 mDestroyPreservedSurfaceUponRedraw = true;
657 mSurfaceDestroyDeferred = true;
658 destroySurfaceLocked();
661 void destroyPreservedSurfaceLocked() {
662 if (!mDestroyPreservedSurfaceUponRedraw) {
665 destroyDeferredSurfaceLocked();
666 mDestroyPreservedSurfaceUponRedraw = false;
669 void markPreservedSurfaceForDestroy() {
670 if (mDestroyPreservedSurfaceUponRedraw
671 && !mService.mDestroyPreservedSurface.contains(mWin)) {
672 mService.mDestroyPreservedSurface.add(mWin);
676 WindowSurfaceController createSurfaceLocked() {
677 final WindowState w = mWin;
678 if (w.hasSavedSurface()) {
679 if (DEBUG_ANIM) Slog.i(TAG,
680 "createSurface: " + this + ": called when we had a saved surface");
681 w.restoreSavedSurface();
682 return mSurfaceController;
685 if (mSurfaceController != null) {
686 return mSurfaceController;
689 w.setHasSurface(false);
691 if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
692 "createSurface " + this + ": mDrawState=DRAW_PENDING");
694 mDrawState = DRAW_PENDING;
695 if (w.mAppToken != null) {
696 if (w.mAppToken.mAppAnimator.animation == null) {
697 w.mAppToken.clearAllDrawn();
699 // Currently animating, persist current state of allDrawn until animation
701 w.mAppToken.deferClearAllDrawn = true;
705 mService.makeWindowFreezingScreenIfNeededLocked(w);
707 int flags = SurfaceControl.HIDDEN;
708 final WindowManager.LayoutParams attrs = w.mAttrs;
710 if (mService.isSecureLocked(w)) {
711 flags |= SurfaceControl.SECURE;
714 mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
715 calculateSurfaceBounds(w, attrs);
716 final int width = mTmpSize.width();
717 final int height = mTmpSize.height();
719 if (DEBUG_VISIBILITY) {
720 Slog.v(TAG, "Creating surface in session "
721 + mSession.mSurfaceSession + " window " + this
722 + " w=" + width + " h=" + height
723 + " x=" + mTmpSize.left + " y=" + mTmpSize.top
724 + " format=" + attrs.format + " flags=" + flags);
727 // We may abort, so initialize to defaults.
728 mLastSystemDecorRect.set(0, 0, 0, 0);
729 mHasClipRect = false;
730 mClipRect.set(0, 0, 0, 0);
731 mLastClipRect.set(0, 0, 0, 0);
733 // Set up surface control with initial size.
736 final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
737 final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
738 if (!PixelFormat.formatHasAlpha(attrs.format)
739 // Don't make surface with surfaceInsets opaque as they display a
740 // translucent shadow.
741 && attrs.surfaceInsets.left == 0
742 && attrs.surfaceInsets.top == 0
743 && attrs.surfaceInsets.right == 0
744 && attrs.surfaceInsets.bottom == 0
745 // Don't make surface opaque when resizing to reduce the amount of
746 // artifacts shown in areas the app isn't drawing content to.
747 && !w.isDragResizing()) {
748 flags |= SurfaceControl.OPAQUE;
751 mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
752 attrs.getTitle().toString(),
753 width, height, format, flags, this);
755 w.setHasSurface(true);
757 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
758 Slog.i(TAG, " CREATE SURFACE "
759 + mSurfaceController + " IN SESSION "
760 + mSession.mSurfaceSession
761 + ": pid=" + mSession.mPid + " format="
762 + attrs.format + " flags=0x"
763 + Integer.toHexString(flags)
766 } catch (OutOfResourcesException e) {
767 Slog.w(TAG, "OutOfResourcesException creating surface");
768 mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
769 mDrawState = NO_SURFACE;
771 } catch (Exception e) {
772 Slog.e(TAG, "Exception creating surface", e);
773 mDrawState = NO_SURFACE;
777 if (WindowManagerService.localLOGV) Slog.v(TAG, "Got surface: " + mSurfaceController
778 + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
779 + ", animLayer=" + mAnimLayer);
781 if (SHOW_LIGHT_TRANSACTIONS) {
782 Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
783 WindowManagerService.logSurface(w, "CREATE pos=("
784 + w.mFrame.left + "," + w.mFrame.top + ") ("
785 + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
788 // Start a new transaction and apply position & offset.
789 final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
790 mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
793 if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
794 return mSurfaceController;
797 private void calculateSurfaceBounds(WindowState w, LayoutParams attrs) {
798 if ((attrs.flags & FLAG_SCALED) != 0) {
799 // For a scaled surface, we always want the requested size.
800 mTmpSize.right = mTmpSize.left + w.mRequestedWidth;
801 mTmpSize.bottom = mTmpSize.top + w.mRequestedHeight;
803 // When we're doing a drag-resizing, request a surface that's fullscreen size,
804 // so that we don't need to reallocate during the process. This also prevents
805 // buffer drops due to size mismatch.
806 if (w.isDragResizing()) {
807 if (w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM) {
811 final DisplayInfo displayInfo = w.getDisplayInfo();
812 mTmpSize.right = mTmpSize.left + displayInfo.logicalWidth;
813 mTmpSize.bottom = mTmpSize.top + displayInfo.logicalHeight;
815 mTmpSize.right = mTmpSize.left + w.mCompatFrame.width();
816 mTmpSize.bottom = mTmpSize.top + w.mCompatFrame.height();
820 // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
821 // This doesn't necessarily mean that there is an error in the system. The sizes might be
822 // incorrect, because it is before the first layout or draw.
823 if (mTmpSize.width() < 1) {
824 mTmpSize.right = mTmpSize.left + 1;
826 if (mTmpSize.height() < 1) {
827 mTmpSize.bottom = mTmpSize.top + 1;
830 // Adjust for surface insets.
831 mTmpSize.left -= attrs.surfaceInsets.left;
832 mTmpSize.top -= attrs.surfaceInsets.top;
833 mTmpSize.right += attrs.surfaceInsets.right;
834 mTmpSize.bottom += attrs.surfaceInsets.bottom;
837 boolean hasSurface() {
838 return !mWin.hasSavedSurface()
839 && mSurfaceController != null && mSurfaceController.hasSurface();
842 void destroySurfaceLocked() {
843 final AppWindowToken wtoken = mWin.mAppToken;
844 if (wtoken != null) {
845 if (mWin == wtoken.startingWindow) {
846 wtoken.startingDisplayed = false;
850 mWin.clearHasSavedSurface();
852 if (mSurfaceController == null) {
856 int i = mWin.mChildWindows.size();
857 // When destroying a surface we want to make sure child windows are hidden. If we are
858 // preserving the surface until redraw though we intend to swap it out with another surface
859 // for resizing. In this case the window always remains visible to the user and the child
860 // windows should likewise remain visible.
861 while (!mDestroyPreservedSurfaceUponRedraw && i > 0) {
863 WindowState c = mWin.mChildWindows.get(i);
864 c.mAttachedHidden = true;
868 if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
869 + mSurfaceController + ", session " + mSession);
870 if (mSurfaceDestroyDeferred) {
871 if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
872 if (mPendingDestroySurface != null) {
873 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
874 WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
876 mPendingDestroySurface.destroyInTransaction();
878 mPendingDestroySurface = mSurfaceController;
881 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
882 WindowManagerService.logSurface(mWin, "DESTROY", true);
886 // Don't hide wallpaper if we're deferring the surface destroy
887 // because of a surface change.
888 if (!mDestroyPreservedSurfaceUponRedraw) {
889 mWallpaperControllerLocked.hideWallpapers(mWin);
891 } catch (RuntimeException e) {
892 Slog.w(TAG, "Exception thrown when destroying Window " + this
893 + " surface " + mSurfaceController + " session " + mSession + ": " + e.toString());
896 // Whether the surface was preserved (and copied to mPendingDestroySurface) or not, it
897 // needs to be cleared to match the WindowState.mHasSurface state. It is also necessary
898 // so it can be recreated successfully in mPendingDestroySurface case.
899 mWin.setHasSurface(false);
900 if (mSurfaceController != null) {
901 mSurfaceController.setShown(false);
903 mSurfaceController = null;
904 mDrawState = NO_SURFACE;
907 void destroyDeferredSurfaceLocked() {
909 if (mPendingDestroySurface != null) {
910 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
911 WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
913 mPendingDestroySurface.destroyInTransaction();
914 // Don't hide wallpaper if we're destroying a deferred surface
915 // after a surface mode change.
916 if (!mDestroyPreservedSurfaceUponRedraw) {
917 mWallpaperControllerLocked.hideWallpapers(mWin);
920 } catch (RuntimeException e) {
921 Slog.w(TAG, "Exception thrown when destroying Window "
922 + this + " surface " + mPendingDestroySurface
923 + " session " + mSession + ": " + e.toString());
925 mSurfaceDestroyDeferred = false;
926 mPendingDestroySurface = null;
929 void computeShownFrameLocked() {
930 final boolean selfTransformation = mHasLocalTransformation;
931 Transformation attachedTransformation =
932 (mAttachedWinAnimator != null && mAttachedWinAnimator.mHasLocalTransformation)
933 ? mAttachedWinAnimator.mTransformation : null;
934 Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
935 ? mAppAnimator.transformation : null;
937 // Wallpapers are animated based on the "real" window they
938 // are currently targeting.
939 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
940 if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
941 final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
942 if (wallpaperAnimator.mHasLocalTransformation &&
943 wallpaperAnimator.mAnimation != null &&
944 !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
945 attachedTransformation = wallpaperAnimator.mTransformation;
946 if (DEBUG_WALLPAPER && attachedTransformation != null) {
947 Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
950 final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
951 null : wallpaperTarget.mAppToken.mAppAnimator;
952 if (wpAppAnimator != null && wpAppAnimator.hasTransformation
953 && wpAppAnimator.animation != null
954 && !wpAppAnimator.animation.getDetachWallpaper()) {
955 appTransformation = wpAppAnimator.transformation;
956 if (DEBUG_WALLPAPER && appTransformation != null) {
957 Slog.v(TAG, "WP target app xform: " + appTransformation);
962 final int displayId = mWin.getDisplayId();
963 final ScreenRotationAnimation screenRotationAnimation =
964 mAnimator.getScreenRotationAnimationLocked(displayId);
965 final boolean screenAnimation =
966 screenRotationAnimation != null && screenRotationAnimation.isAnimating();
968 mHasClipRect = false;
969 if (selfTransformation || attachedTransformation != null
970 || appTransformation != null || screenAnimation) {
971 // cache often used attributes locally
972 final Rect frame = mWin.mFrame;
973 final float tmpFloats[] = mService.mTmpFloats;
974 final Matrix tmpMatrix = mWin.mTmpMatrix;
976 // Compute the desired transformation.
977 if (screenAnimation && screenRotationAnimation.isRotating()) {
978 // If we are doing a screen animation, the global rotation
979 // applied to windows can result in windows that are carefully
980 // aligned with each other to slightly separate, allowing you
981 // to see what is behind them. An unsightly mess. This...
982 // thing... magically makes it call good: scale each window
983 // slightly (two pixels larger in each dimension, from the
985 final float w = frame.width();
986 final float h = frame.height();
988 tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);
995 tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
996 if (selfTransformation) {
997 tmpMatrix.postConcat(mTransformation.getMatrix());
999 if (attachedTransformation != null) {
1000 tmpMatrix.postConcat(attachedTransformation.getMatrix());
1002 if (appTransformation != null) {
1003 tmpMatrix.postConcat(appTransformation.getMatrix());
1006 // The translation that applies the position of the window needs to be applied at the
1007 // end in case that other translations include scaling. Otherwise the scaling will
1008 // affect this translation. But it needs to be set before the screen rotation animation
1009 // so the pivot point is at the center of the screen for all windows.
1010 tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
1011 if (screenAnimation) {
1012 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
1015 //TODO (multidisplay): Magnification is supported only for the default display.
1016 if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
1017 MagnificationSpec spec = mService.mAccessibilityController
1018 .getMagnificationSpecForWindowLocked(mWin);
1019 if (spec != null && !spec.isNop()) {
1020 tmpMatrix.postScale(spec.scale, spec.scale);
1021 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
1025 // "convert" it into SurfaceFlinger's format
1026 // (a 2x2 matrix + an offset)
1027 // Here we must not transform the position of the surface
1028 // since it is already included in the transformation.
1029 //Slog.i(TAG_WM, "Transform: " + matrix);
1032 tmpMatrix.getValues(tmpFloats);
1033 mDsDx = tmpFloats[Matrix.MSCALE_X];
1034 mDtDx = tmpFloats[Matrix.MSKEW_Y];
1035 mDsDy = tmpFloats[Matrix.MSKEW_X];
1036 mDtDy = tmpFloats[Matrix.MSCALE_Y];
1037 float x = tmpFloats[Matrix.MTRANS_X];
1038 float y = tmpFloats[Matrix.MTRANS_Y];
1039 mWin.mShownPosition.set((int) x, (int) y);
1041 // Now set the alpha... but because our current hardware
1042 // can't do alpha transformation on a non-opaque surface,
1043 // turn it off if we are running an animation that is also
1044 // transforming since it is more important to have that
1045 // animation be smooth.
1046 mShownAlpha = mAlpha;
1047 if (!mService.mLimitedAlphaCompositing
1048 || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
1049 || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
1050 && x == frame.left && y == frame.top))) {
1051 //Slog.i(TAG_WM, "Applying alpha transform");
1052 if (selfTransformation) {
1053 mShownAlpha *= mTransformation.getAlpha();
1055 if (attachedTransformation != null) {
1056 mShownAlpha *= attachedTransformation.getAlpha();
1058 if (appTransformation != null) {
1059 mShownAlpha *= appTransformation.getAlpha();
1060 if (appTransformation.hasClipRect()) {
1061 mClipRect.set(appTransformation.getClipRect());
1062 mHasClipRect = true;
1063 // The app transformation clip will be in the coordinate space of the main
1064 // activity window, which the animation correctly assumes will be placed at
1065 // (0,0)+(insets) relative to the containing frame. This isn't necessarily
1066 // true for child windows though which can have an arbitrary frame position
1067 // relative to their containing frame. We need to offset the difference
1068 // between the containing frame as used to calculate the crop and our
1069 // bounds to compensate for this.
1070 if (mWin.layoutInParentFrame()) {
1071 mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
1072 mWin.mContainingFrame.top - mWin.mFrame.top );
1076 if (screenAnimation) {
1077 mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
1080 //Slog.i(TAG_WM, "Not applying alpha transform");
1083 if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)
1084 && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
1085 TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
1086 + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
1087 + " attached=" + (attachedTransformation == null ?
1088 "null" : attachedTransformation.getAlpha())
1089 + " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
1090 + " screen=" + (screenAnimation ?
1091 screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
1093 } else if (mIsWallpaper && mService.mWindowPlacerLocked.mWallpaperActionPending) {
1095 } else if (mWin.isDragResizeChanged()) {
1096 // This window is awaiting a relayout because user just started (or ended)
1097 // drag-resizing. The shown frame (which affects surface size and pos)
1098 // should not be updated until we get next finished draw with the new surface.
1099 // Otherwise one or two frames rendered with old settings would be displayed
1100 // with new geometry.
1104 if (WindowManagerService.localLOGV) Slog.v(
1105 TAG, "computeShownFrameLocked: " + this +
1106 " not attached, mAlpha=" + mAlpha);
1108 MagnificationSpec spec = null;
1109 //TODO (multidisplay): Magnification is supported only for the default display.
1110 if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
1111 spec = mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);
1114 final Rect frame = mWin.mFrame;
1115 final float tmpFloats[] = mService.mTmpFloats;
1116 final Matrix tmpMatrix = mWin.mTmpMatrix;
1118 tmpMatrix.setScale(mWin.mGlobalScale, mWin.mGlobalScale);
1119 tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
1121 if (spec != null && !spec.isNop()) {
1122 tmpMatrix.postScale(spec.scale, spec.scale);
1123 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
1126 tmpMatrix.getValues(tmpFloats);
1129 mDsDx = tmpFloats[Matrix.MSCALE_X];
1130 mDtDx = tmpFloats[Matrix.MSKEW_Y];
1131 mDsDy = tmpFloats[Matrix.MSKEW_X];
1132 mDtDy = tmpFloats[Matrix.MSCALE_Y];
1133 float x = tmpFloats[Matrix.MTRANS_X];
1134 float y = tmpFloats[Matrix.MTRANS_Y];
1135 mWin.mShownPosition.set((int) x, (int) y);
1137 mShownAlpha = mAlpha;
1139 mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
1140 if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
1141 mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
1143 mShownAlpha = mAlpha;
1144 mHaveMatrix = false;
1145 mDsDx = mWin.mGlobalScale;
1148 mDtDy = mWin.mGlobalScale;
1152 private void calculateSystemDecorRect() {
1153 final WindowState w = mWin;
1154 final Rect decorRect = w.mDecorFrame;
1155 final int width = w.mFrame.width();
1156 final int height = w.mFrame.height();
1158 // Compute the offset of the window in relation to the decor rect.
1159 final int left = w.mXOffset + w.mFrame.left;
1160 final int top = w.mYOffset + w.mFrame.top;
1162 // Initialize the decor rect to the entire frame.
1163 if (w.isDockedResizing() ||
1164 (w.isChildWindow() && w.mAttachedWindow.isDockedResizing())) {
1166 // If we are resizing with the divider, the task bounds might be smaller than the
1167 // stack bounds. The system decor is used to clip to the task bounds, which we don't
1168 // want in this case in order to avoid holes.
1170 // We take care to not shrink the width, for surfaces which are larger than
1171 // the display region. Of course this area will not eventually be visible
1172 // but if we truncate the width now, we will calculate incorrectly
1173 // when adjusting to the stack bounds.
1174 final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
1175 mSystemDecorRect.set(0, 0,
1176 Math.max(width, displayInfo.logicalWidth),
1177 Math.max(height, displayInfo.logicalHeight));
1179 mSystemDecorRect.set(0, 0, width, height);
1182 // If a freeform window is animating from a position where it would be cutoff, it would be
1183 // cutoff during the animation. We don't want that, so for the duration of the animation
1184 // we ignore the decor cropping and depend on layering to position windows correctly.
1185 final boolean cropToDecor = !(w.inFreeformWorkspace() && w.isAnimatingLw());
1187 // Intersect with the decor rect, offsetted by window position.
1188 mSystemDecorRect.intersect(decorRect.left - left, decorRect.top - top,
1189 decorRect.right - left, decorRect.bottom - top);
1192 // If size compatibility is being applied to the window, the
1193 // surface is scaled relative to the screen. Also apply this
1194 // scaling to the crop rect. We aren't using the standard rect
1195 // scale function because we want to round things to make the crop
1196 // always round to a larger rect to ensure we don't crop too
1197 // much and hide part of the window that should be seen.
1198 if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) {
1199 final float scale = w.mInvGlobalScale;
1200 mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
1201 mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
1202 mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
1203 mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
1207 void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) {
1208 final WindowState w = mWin;
1209 final DisplayContent displayContent = w.getDisplayContent();
1210 if (displayContent == null) {
1211 clipRect.setEmpty();
1212 finalClipRect.setEmpty();
1215 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
1216 if (DEBUG_WINDOW_CROP) Slog.d(TAG,
1217 "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
1219 // Need to recompute a new system decor rect each time.
1220 if (!w.isDefaultDisplay()) {
1221 // On a different display there is no system decor. Crop the window
1222 // by the screen boundaries.
1223 mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
1224 mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top,
1225 displayInfo.logicalWidth - w.mCompatFrame.left,
1226 displayInfo.logicalHeight - w.mCompatFrame.top);
1227 } else if (w.mLayer >= mService.mSystemDecorLayer) {
1228 // Above the decor layer is easy, just use the entire window.
1229 mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
1230 } else if (w.mDecorFrame.isEmpty()) {
1231 // Windows without policy decor aren't cropped.
1232 mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
1233 } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.isAnimating()) {
1234 // If we're animating, the wallpaper crop should only be updated at the end of the
1236 mTmpClipRect.set(mSystemDecorRect);
1237 calculateSystemDecorRect();
1238 mSystemDecorRect.union(mTmpClipRect);
1240 // Crop to the system decor specified by policy.
1241 calculateSystemDecorRect();
1242 if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
1243 + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
1246 final boolean fullscreen = w.isFrameFullscreen(displayInfo);
1247 final boolean isFreeformResizing =
1248 w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
1250 // We use the clip rect as provided by the tranformation for non-fullscreen windows to
1251 // avoid premature clipping with the system decor rect.
1252 clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
1253 if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
1254 + " mHasClipRect=" + mHasClipRect + " fullscreen=" + fullscreen);
1256 if (isFreeformResizing && !w.isChildWindow()) {
1257 // For freeform resizing non child windows, we are using the big surface positioned
1258 // at 0,0. Thus we must express the crop in that coordinate space.
1259 clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
1262 // Expand the clip rect for surface insets.
1263 final WindowManager.LayoutParams attrs = w.mAttrs;
1264 clipRect.left -= attrs.surfaceInsets.left;
1265 clipRect.top -= attrs.surfaceInsets.top;
1266 clipRect.right += attrs.surfaceInsets.right;
1267 clipRect.bottom += attrs.surfaceInsets.bottom;
1269 if (mHasClipRect && fullscreen) {
1270 // We intersect the clip rect specified by the transformation with the expanded system
1271 // decor rect to prevent artifacts from drawing during animation if the transformation
1272 // clip rect extends outside the system decor rect.
1273 clipRect.intersect(mClipRect);
1275 // The clip rect was generated assuming (0,0) as the window origin,
1276 // so we need to translate to match the actual surface coordinates.
1277 clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
1279 finalClipRect.setEmpty();
1280 adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
1281 if (DEBUG_WINDOW_CROP) Slog.d(TAG,
1282 "win=" + w + " Clip rect after stack adjustment=" + clipRect);
1284 w.transformClipRectFromScreenToSurfaceSpace(clipRect);
1286 // See {@link WindowState#notifyMovedInStack} for why this is necessary.
1287 if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
1288 clipRect.setEmpty();
1292 void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
1293 if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
1294 + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
1295 if (clipRect != null) {
1296 if (!clipRect.equals(mLastClipRect)) {
1297 mLastClipRect.set(clipRect);
1298 mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
1301 mSurfaceController.clearCropInTransaction(recoveringMemory);
1303 if (!finalClipRect.equals(mLastFinalClipRect)) {
1304 mLastFinalClipRect.set(finalClipRect);
1305 mSurfaceController.setFinalCropInTransaction(finalClipRect);
1306 if (mDestroyPreservedSurfaceUponRedraw && mPendingDestroySurface != null) {
1307 mPendingDestroySurface.setFinalCropInTransaction(finalClipRect);
1312 private int resolveStackClip() {
1313 // App animation overrides window animation stack clip mode.
1314 if (mAppAnimator != null && mAppAnimator.animation != null) {
1315 return mAppAnimator.getStackClip();
1320 private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect,
1321 boolean isFreeformResizing) {
1323 final DisplayContent displayContent = w.getDisplayContent();
1324 if (displayContent != null && !displayContent.isDefaultDisplay) {
1325 // There are some windows that live on other displays while their app and main window
1326 // live on the default display (e.g. casting...). We don't want to crop this windows
1327 // to the stack bounds which is only currently supported on the default display.
1328 // TODO(multi-display): Need to support cropping to stack bounds on other displays
1329 // when we have stacks on other displays.
1333 final Task task = w.getTask();
1334 if (task == null || !task.cropWindowsToStackBounds()) {
1338 final int stackClip = resolveStackClip();
1340 // It's animating and we don't want to clip it to stack bounds during animation - abort.
1341 if (isAnimationSet() && stackClip == STACK_CLIP_NONE) {
1345 final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
1346 if (w == winShowWhenLocked && mPolicy.isKeyguardShowingOrOccluded()) {
1350 final TaskStack stack = task.mStack;
1351 stack.getDimBounds(mTmpStackBounds);
1352 final Rect surfaceInsets = w.getAttrs().surfaceInsets;
1353 // When we resize we use the big surface approach, which means we can't trust the
1354 // window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
1355 // hardcoding it, we use surface coordinates.
1356 final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
1357 w.mFrame.left + mWin.mXOffset - surfaceInsets.left;
1358 final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
1359 w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
1361 // If we are animating, we either apply the clip before applying all the animation
1362 // transformation or after all the transformation.
1363 final boolean useFinalClipRect = isAnimationSet() && stackClip == STACK_CLIP_AFTER_ANIM
1364 || mDestroyPreservedSurfaceUponRedraw;
1366 // We need to do some acrobatics with surface position, because their clip region is
1367 // relative to the inside of the surface, but the stack bounds aren't.
1368 if (useFinalClipRect) {
1369 finalClipRect.set(mTmpStackBounds);
1371 if (StackId.hasWindowShadow(stack.mStackId)
1372 && !StackId.isTaskResizeAllowed(stack.mStackId)) {
1373 // The windows in this stack display drop shadows and the fill the entire stack
1374 // area. Adjust the stack bounds we will use to cropping take into account the
1375 // offsets we use to display the drop shadow so it doesn't get cropped.
1376 mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
1377 -surfaceInsets.right, -surfaceInsets.bottom);
1380 clipRect.left = Math.max(0,
1381 Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
1382 clipRect.top = Math.max(0,
1383 Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
1384 clipRect.right = Math.max(0,
1385 Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
1386 clipRect.bottom = Math.max(0,
1387 Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
1391 void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
1392 final WindowState w = mWin;
1393 final Task task = w.getTask();
1395 // We got resized, so block all updates until we got the new surface.
1396 if (w.isResizedWhileNotDragResizing() && !w.isGoneForLayoutLw()) {
1400 mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
1401 calculateSurfaceBounds(w, w.getAttrs());
1403 mExtraHScale = (float) 1.0;
1404 mExtraVScale = (float) 1.0;
1406 boolean wasForceScaled = mForceScaleUntilResize;
1407 boolean wasSeamlesslyRotated = w.mSeamlesslyRotated;
1409 // Once relayout has been called at least once, we need to make sure
1410 // we only resize the client surface during calls to relayout. For
1411 // clients which use indeterminate measure specs (MATCH_PARENT),
1412 // we may try and change their window size without a call to relayout.
1413 // However, this would be unsafe, as the client may be in the middle
1414 // of producing a frame at the old size, having just completed layout
1415 // to find the surface size changed underneath it.
1416 if (!w.mRelayoutCalled || w.mInRelayout) {
1417 mSurfaceResized = mSurfaceController.setSizeInTransaction(
1418 mTmpSize.width(), mTmpSize.height(), recoveringMemory);
1420 mSurfaceResized = false;
1422 mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
1423 // If we are undergoing seamless rotation, the surface has already
1424 // been set up to persist at it's old location. We need to freeze
1425 // updates until a resize occurs.
1426 w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized;
1428 calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
1430 float surfaceWidth = mSurfaceController.getWidth();
1431 float surfaceHeight = mSurfaceController.getHeight();
1433 if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) {
1434 int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
1435 int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
1436 if (!mForceScaleUntilResize) {
1437 mSurfaceController.forceScaleableInTransaction(true);
1439 // We want to calculate the scaling based on the content area, not based on
1440 // the entire surface, so that we scale in sync with windows that don't have insets.
1441 mExtraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
1442 mExtraVScale = (mTmpClipRect.height() - vInsets) / (float)(surfaceHeight - vInsets);
1444 // In the case of ForceScaleToCrop we scale entire tasks together,
1445 // and so we need to scale our offsets relative to the task bounds
1446 // or parent and child windows would fall out of alignment.
1447 int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - mExtraHScale));
1448 int posY = (int) (mTmpSize.top - w.mAttrs.y * (1 - mExtraVScale));
1449 // Imagine we are scaling down. As we scale the buffer down, we decrease the
1450 // distance between the surface top left, and the start of the surface contents
1451 // (previously it was surfaceInsets.left pixels in screen space but now it
1452 // will be surfaceInsets.left*mExtraHScale). This means in order to keep the
1453 // non inset content at the same position, we have to shift the whole window
1454 // forward. Likewise for scaling up, we've increased this distance, and we need
1455 // to shift by a negative number to compensate.
1456 posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
1457 posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
1459 mSurfaceController.setPositionInTransaction((float)Math.floor(posX),
1460 (float)Math.floor(posY), recoveringMemory);
1462 // Since we are scaled to fit in our previously desired crop, we can now
1463 // expose the whole window in buffer space, and not risk extending
1464 // past where the system would have cropped us
1465 mTmpClipRect.set(0, 0, (int)surfaceWidth, (int)surfaceHeight);
1466 mTmpFinalClipRect.setEmpty();
1468 // Various surfaces in the scaled stack may resize at different times.
1469 // We need to ensure for each surface, that we disable transformation matrix
1470 // scaling in the same transaction which we resize the surface in.
1471 // As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
1472 // then take over the scaling until the new buffer arrives, and things
1473 // will be seamless.
1474 mForceScaleUntilResize = true;
1476 if (!w.mSeamlesslyRotated) {
1477 mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
1482 // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
1483 // to prevent further updates until buffer latch.
1484 // When ending both force scaling, and seamless rotation, we need to freeze
1485 // the Surface geometry until a buffer comes in at the new size (normally position and crop
1486 // are unfrozen). setGeometryAppliesWithResizeInTransaction accomplishes this for us.
1487 if ((wasForceScaled && !mForceScaleUntilResize) ||
1488 (wasSeamlesslyRotated && !w.mSeamlesslyRotated)) {
1489 mSurfaceController.setGeometryAppliesWithResizeInTransaction(true);
1490 mSurfaceController.forceScaleableInTransaction(false);
1493 Rect clipRect = mTmpClipRect;
1494 if (w.inPinnedWorkspace()) {
1496 task.mStack.getDimBounds(mTmpFinalClipRect);
1497 mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
1498 -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
1501 if (!w.mSeamlesslyRotated) {
1502 updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
1503 mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
1504 mDtDx * w.mVScale * mExtraVScale,
1505 mDsDy * w.mHScale * mExtraHScale,
1506 mDtDy * w.mVScale * mExtraVScale, recoveringMemory);
1509 if (mSurfaceResized) {
1510 mReportSurfaceResized = true;
1511 mAnimator.setPendingLayoutChanges(w.getDisplayId(),
1512 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
1513 w.applyDimLayerIfNeeded();
1518 void prepareSurfaceLocked(final boolean recoveringMemory) {
1519 final WindowState w = mWin;
1520 if (!hasSurface()) {
1521 if (w.mOrientationChanging) {
1522 if (DEBUG_ORIENTATION) {
1523 Slog.v(TAG, "Orientation change skips hidden " + w);
1525 w.mOrientationChanging = false;
1530 // Do not change surface properties of opening apps if we are waiting for the
1531 // transition to be ready. transitionGoodToGo could be not ready even after all
1532 // opening apps are drawn. It's only waiting on isFetchingAppTransitionsSpecs()
1533 // to get the animation spec. (For example, go into Recents and immediately open
1534 // the same app again before the app's surface is destroyed or saved, the surface
1535 // is always ready in the whole process.) If we go ahead here, the opening app
1536 // will be shown with the full size before the correct animation spec arrives.
1537 if (isWaitingForOpening()) {
1541 boolean displayed = false;
1543 computeShownFrameLocked();
1545 setSurfaceBoundariesLocked(recoveringMemory);
1547 if (mIsWallpaper && !mWin.mWallpaperVisible) {
1548 // Wallpaper is no longer visible and there is no wp target => hide it.
1549 hide("prepareSurfaceLocked");
1550 } else if (w.mAttachedHidden || !w.isOnScreen()) {
1551 hide("prepareSurfaceLocked");
1552 mWallpaperControllerLocked.hideWallpapers(w);
1554 // If we are waiting for this window to handle an
1555 // orientation change, well, it is hidden, so
1556 // doesn't really matter. Note that this does
1557 // introduce a potential glitch if the window
1558 // becomes unhidden before it has drawn for the
1560 if (w.mOrientationChanging) {
1561 w.mOrientationChanging = false;
1562 if (DEBUG_ORIENTATION) Slog.v(TAG,
1563 "Orientation change skips hidden " + w);
1565 } else if (mLastLayer != mAnimLayer
1566 || mLastAlpha != mShownAlpha
1567 || mLastDsDx != mDsDx
1568 || mLastDtDx != mDtDx
1569 || mLastDsDy != mDsDy
1570 || mLastDtDy != mDtDy
1571 || w.mLastHScale != w.mHScale
1572 || w.mLastVScale != w.mVScale
1575 mLastAlpha = mShownAlpha;
1576 mLastLayer = mAnimLayer;
1581 w.mLastHScale = w.mHScale;
1582 w.mLastVScale = w.mVScale;
1583 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
1584 "controller=" + mSurfaceController +
1585 "alpha=" + mShownAlpha + " layer=" + mAnimLayer
1586 + " matrix=[" + mDsDx + "*" + w.mHScale
1587 + "," + mDtDx + "*" + w.mVScale
1588 + "][" + mDsDy + "*" + w.mHScale
1589 + "," + mDtDy + "*" + w.mVScale + "]", false);
1592 mSurfaceController.prepareToShowInTransaction(mShownAlpha, mAnimLayer,
1593 mDsDx * w.mHScale * mExtraHScale,
1594 mDtDx * w.mVScale * mExtraVScale,
1595 mDsDy * w.mHScale * mExtraHScale,
1596 mDtDy * w.mVScale * mExtraVScale,
1599 if (prepared && mLastHidden && mDrawState == HAS_DRAWN) {
1600 if (showSurfaceRobustlyLocked()) {
1601 markPreservedSurfaceForDestroy();
1602 mAnimator.requestRemovalOfReplacedWindows(w);
1603 mLastHidden = false;
1605 mWallpaperControllerLocked.dispatchWallpaperVisibility(w, true);
1607 // This draw means the difference between unique content and mirroring.
1608 // Run another pass through performLayout to set mHasContent in the
1610 mAnimator.setPendingLayoutChanges(w.getDisplayId(),
1611 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
1613 w.mOrientationChanging = false;
1617 w.mToken.hasVisible = true;
1620 if (DEBUG_ANIM && isAnimationSet()) {
1621 Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
1627 if (w.mOrientationChanging) {
1628 if (!w.isDrawnLw()) {
1629 mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
1630 mAnimator.mLastWindowFreezeSource = w;
1631 if (DEBUG_ORIENTATION) Slog.v(TAG,
1632 "Orientation continue waiting for draw in " + w);
1634 w.mOrientationChanging = false;
1635 if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
1638 w.mToken.hasVisible = true;
1642 void setTransparentRegionHintLocked(final Region region) {
1643 if (mSurfaceController == null) {
1644 Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
1647 mSurfaceController.setTransparentRegionHint(region);
1650 void setWallpaperOffset(Point shownPosition) {
1651 final LayoutParams attrs = mWin.getAttrs();
1652 final int left = shownPosition.x - attrs.surfaceInsets.left;
1653 final int top = shownPosition.y - attrs.surfaceInsets.top;
1656 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
1657 SurfaceControl.openTransaction();
1658 mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
1659 mWin.mFrame.top + top, false);
1660 calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
1661 updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false);
1662 } catch (RuntimeException e) {
1663 Slog.w(TAG, "Error positioning surface of " + mWin
1664 + " pos=(" + left + "," + top + ")", e);
1666 SurfaceControl.closeTransaction();
1667 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
1668 "<<< CLOSE TRANSACTION setWallpaperOffset");
1673 * Try to change the pixel format without recreating the surface. This
1674 * will be common in the case of changing from PixelFormat.OPAQUE to
1675 * PixelFormat.TRANSLUCENT in the hardware-accelerated case as both
1676 * requested formats resolve to the same underlying SurfaceControl format
1677 * @return True if format was succesfully changed, false otherwise
1679 boolean tryChangeFormatInPlaceLocked() {
1680 if (mSurfaceController == null) {
1683 final LayoutParams attrs = mWin.getAttrs();
1684 final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
1685 final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
1686 if (format == mSurfaceFormat) {
1687 setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
1693 void setOpaqueLocked(boolean isOpaque) {
1694 if (mSurfaceController == null) {
1697 mSurfaceController.setOpaque(isOpaque);
1700 void setSecureLocked(boolean isSecure) {
1701 if (mSurfaceController == null) {
1704 mSurfaceController.setSecure(isSecure);
1707 // This must be called while inside a transaction.
1708 boolean performShowLocked() {
1709 if (mWin.isHiddenFromUserLocked()) {
1710 if (DEBUG_VISIBILITY) Slog.w(TAG, "hiding " + mWin + ", belonging to " + mWin.mOwnerUid);
1714 if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
1715 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
1716 Slog.v(TAG, "performShow on " + this
1717 + ": mDrawState=" + drawStateToString() + " readyForDisplay="
1718 + mWin.isReadyForDisplayIgnoringKeyguard()
1719 + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING)
1720 + " during animation: policyVis=" + mWin.mPolicyVisibility
1721 + " attHidden=" + mWin.mAttachedHidden
1722 + " tok.hiddenRequested="
1723 + (mWin.mAppToken != null ? mWin.mAppToken.hiddenRequested : false)
1725 + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
1726 + " animating=" + mAnimating
1728 + (mAppAnimator != null ? mAppAnimator.animating : false) + " Callers="
1729 + Debug.getCallers(3));
1731 if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplayIgnoringKeyguard()) {
1732 if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
1733 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
1734 Slog.v(TAG, "Showing " + this
1735 + " during animation: policyVis=" + mWin.mPolicyVisibility
1736 + " attHidden=" + mWin.mAttachedHidden
1737 + " tok.hiddenRequested="
1738 + (mWin.mAppToken != null ? mWin.mAppToken.hiddenRequested : false)
1740 + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
1741 + " animating=" + mAnimating
1743 + (mAppAnimator != null ? mAppAnimator.animating : false));
1746 mService.enableScreenIfNeededLocked();
1748 applyEnterAnimationLocked();
1750 // Force the show in the next prepareSurfaceLocked() call.
1752 if (DEBUG_SURFACE_TRACE || DEBUG_ANIM)
1753 Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN in " + mWin);
1754 mDrawState = HAS_DRAWN;
1755 mService.scheduleAnimationLocked();
1757 int i = mWin.mChildWindows.size();
1760 WindowState c = mWin.mChildWindows.get(i);
1761 if (c.mAttachedHidden) {
1762 c.mAttachedHidden = false;
1763 if (c.mWinAnimator.mSurfaceController != null) {
1764 c.mWinAnimator.performShowLocked();
1765 // It hadn't been shown, which means layout not
1766 // performed on it, so now we want to make sure to
1767 // do a layout. If called from within the transaction
1768 // loop, this will cause it to restart with a new
1770 final DisplayContent displayContent = c.getDisplayContent();
1771 if (displayContent != null) {
1772 displayContent.layoutNeeded = true;
1778 if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING && mWin.mAppToken != null) {
1779 mWin.mAppToken.onFirstWindowDrawn(mWin, this);
1782 if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
1783 mWin.mDisplayContent.mDividerControllerLocked.resetImeHideRequested();
1792 * Have the surface flinger show a surface, robustly dealing with
1793 * error conditions. In particular, if there is not enough memory
1794 * to show the surface, then we will try to get rid of other surfaces
1795 * in order to succeed.
1797 * @return Returns true if the surface was successfully shown.
1799 private boolean showSurfaceRobustlyLocked() {
1800 final Task task = mWin.getTask();
1801 if (task != null && StackId.windowsAreScaleable(task.mStack.mStackId)) {
1802 mSurfaceController.forceScaleableInTransaction(true);
1805 boolean shown = mSurfaceController.showRobustlyInTransaction();
1809 if (mWin.mTurnOnScreen) {
1810 if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
1811 mWin.mTurnOnScreen = false;
1812 mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
1817 void applyEnterAnimationLocked() {
1818 // If we are the new part of a window replacement transition and we have requested
1819 // not to animate, we instead want to make it seamless, so we don't want to apply
1820 // an enter transition.
1821 if (mWin.mSkipEnterAnimationForSeamlessReplacement) {
1825 if (mEnterAnimationPending) {
1826 mEnterAnimationPending = false;
1827 transit = WindowManagerPolicy.TRANSIT_ENTER;
1829 transit = WindowManagerPolicy.TRANSIT_SHOW;
1831 applyAnimationLocked(transit, true);
1832 //TODO (multidisplay): Magnification is supported only for the default display.
1833 if (mService.mAccessibilityController != null
1834 && mWin.getDisplayId() == DEFAULT_DISPLAY) {
1835 mService.mAccessibilityController.onWindowTransitionLocked(mWin, transit);
1840 * Choose the correct animation and set it to the passed WindowState.
1841 * @param transit If AppTransition.TRANSIT_PREVIEW_DONE and the app window has been drawn
1842 * then the animation will be app_starting_exit. Any other value loads the animation from
1843 * the switch statement below.
1844 * @param isEntrance The animation type the last time this was called. Used to keep from
1845 * loading the same animation twice.
1846 * @return true if an animation has been loaded.
1848 boolean applyAnimationLocked(int transit, boolean isEntrance) {
1849 if ((mLocalAnimating && mAnimationIsEntrance == isEntrance)
1850 || mKeyguardGoingAwayAnimation) {
1851 // If we are trying to apply an animation, but already running
1852 // an animation of the same type, then just leave that one alone.
1854 // If we are in a keyguard exit animation, and the window should animate away, modify
1855 // keyguard exit animation such that it also fades out.
1856 if (mAnimation != null && mKeyguardGoingAwayAnimation
1857 && transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) {
1858 applyFadeoutDuringKeyguardExitAnimation();
1863 // Only apply an animation if the display isn't frozen. If it is
1864 // frozen, there is no reason to animate and it can cause strange
1865 // artifacts when we unfreeze the display if some different animation
1867 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
1868 if (mService.okToDisplay()) {
1869 int anim = mPolicy.selectAnimationLw(mWin, transit);
1873 a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
1876 case WindowManagerPolicy.TRANSIT_ENTER:
1877 attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
1879 case WindowManagerPolicy.TRANSIT_EXIT:
1880 attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
1882 case WindowManagerPolicy.TRANSIT_SHOW:
1883 attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
1885 case WindowManagerPolicy.TRANSIT_HIDE:
1886 attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
1890 a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);
1893 if (DEBUG_ANIM) Slog.v(TAG,
1894 "applyAnimation: win=" + this
1895 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
1897 + " transit=" + transit
1898 + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
1900 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
1902 mAnimationIsEntrance = isEntrance;
1907 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
1909 if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
1910 mService.adjustForImeIfNeeded(mWin.mDisplayContent);
1912 mWin.setDisplayLayoutNeeded();
1913 mService.mWindowPlacerLocked.requestTraversal();
1916 return mAnimation != null;
1919 private void applyFadeoutDuringKeyguardExitAnimation() {
1920 long startTime = mAnimation.getStartTime();
1921 long duration = mAnimation.getDuration();
1922 long elapsed = mLastAnimationTime - startTime;
1923 long fadeDuration = duration - elapsed;
1924 if (fadeDuration <= 0) {
1925 // Never mind, this would be no visible animation, so abort the animation change.
1928 AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
1929 newAnimation.setDuration(duration);
1930 newAnimation.setStartTime(startTime);
1931 newAnimation.addAnimation(mAnimation);
1932 Animation fadeOut = AnimationUtils.loadAnimation(
1933 mContext, com.android.internal.R.anim.app_starting_exit);
1934 fadeOut.setDuration(fadeDuration);
1935 fadeOut.setStartOffset(elapsed);
1936 newAnimation.addAnimation(fadeOut);
1937 newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDx, mAnimDy);
1938 mAnimation = newAnimation;
1941 public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1942 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
1943 || mAnimation != null) {
1944 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
1945 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
1946 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
1947 pw.print(" mAnimation="); pw.print(mAnimation);
1948 pw.print(" mStackClip="); pw.println(mStackClip);
1950 if (mHasTransformation || mHasLocalTransformation) {
1951 pw.print(prefix); pw.print("XForm: has=");
1952 pw.print(mHasTransformation);
1953 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
1954 pw.print(" "); mTransformation.printShortString(pw);
1957 if (mSurfaceController != null) {
1958 mSurfaceController.dump(pw, prefix, dumpAll);
1961 pw.print(prefix); pw.print("mDrawState="); pw.print(drawStateToString());
1962 pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
1963 pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
1964 pw.print(" last="); mLastSystemDecorRect.printShortString(pw);
1965 pw.print(" mHasClipRect="); pw.print(mHasClipRect);
1966 pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
1968 if (!mLastFinalClipRect.isEmpty()) {
1969 pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
1974 if (mPendingDestroySurface != null) {
1975 pw.print(prefix); pw.print("mPendingDestroySurface=");
1976 pw.println(mPendingDestroySurface);
1978 if (mSurfaceResized || mSurfaceDestroyDeferred) {
1979 pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
1980 pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred);
1982 if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
1983 pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
1984 pw.print(" mAlpha="); pw.print(mAlpha);
1985 pw.print(" mLastAlpha="); pw.println(mLastAlpha);
1987 if (mHaveMatrix || mWin.mGlobalScale != 1) {
1988 pw.print(prefix); pw.print("mGlobalScale="); pw.print(mWin.mGlobalScale);
1989 pw.print(" mDsDx="); pw.print(mDsDx);
1990 pw.print(" mDtDx="); pw.print(mDtDx);
1991 pw.print(" mDsDy="); pw.print(mDsDy);
1992 pw.print(" mDtDy="); pw.println(mDtDy);
1994 if (mAnimationStartDelayed) {
1995 pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed);
2000 public String toString() {
2001 StringBuffer sb = new StringBuffer("WindowStateAnimator{");
2002 sb.append(Integer.toHexString(System.identityHashCode(this)));
2004 sb.append(mWin.mAttrs.getTitle());
2006 return sb.toString();
2009 void reclaimSomeSurfaceMemory(String operation, boolean secure) {
2010 mService.reclaimSomeSurfaceMemoryLocked(this, operation, secure);
2013 boolean getShown() {
2014 if (mSurfaceController != null) {
2015 return mSurfaceController.getShown();
2020 void destroySurface() {
2022 if (mSurfaceController != null) {
2023 mSurfaceController.destroyInTransaction();
2025 } catch (RuntimeException e) {
2026 Slog.w(TAG, "Exception thrown when destroying surface " + this
2027 + " surface " + mSurfaceController + " session " + mSession + ": " + e);
2029 mWin.setHasSurface(false);
2030 mSurfaceController = null;
2031 mDrawState = NO_SURFACE;
2035 void setMoveAnimation(int left, int top) {
2036 final Animation a = AnimationUtils.loadAnimation(mContext,
2037 com.android.internal.R.anim.window_move_from_decor);
2039 mAnimDx = mWin.mLastFrame.left - left;
2040 mAnimDy = mWin.mLastFrame.top - top;
2041 mAnimateMove = true;
2044 void deferTransactionUntilParentFrame(long frameNumber) {
2045 if (!mWin.isChildWindow()) {
2048 mDeferTransactionUntilFrame = frameNumber;
2049 mDeferTransactionTime = System.currentTimeMillis();
2050 mSurfaceController.deferTransactionUntil(
2051 mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
2055 // Defer the current transaction to the frame number of the last saved transaction.
2056 // We do this to avoid shooting through an unsynchronized transaction while something is
2057 // pending. This is generally fine, as either we will get in on the synchronization,
2058 // or SurfaceFlinger will see that the frame has already occured. The only
2059 // potential problem is in frame number resets so we reset things with a timeout
2060 // every so often to be careful.
2061 void deferToPendingTransaction() {
2062 if (mDeferTransactionUntilFrame < 0) {
2065 long time = System.currentTimeMillis();
2066 if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) {
2067 mDeferTransactionTime = -1;
2068 mDeferTransactionUntilFrame = -1;
2070 mSurfaceController.deferTransactionUntil(
2071 mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
2072 mDeferTransactionUntilFrame);
2077 * Sometimes we need to synchronize the first frame of animation with some external event.
2078 * To achieve this, we prolong the start of the animation and keep producing the first frame of
2081 private long getAnimationFrameTime(Animation animation, long currentTime) {
2082 if (mAnimationStartDelayed) {
2083 animation.setStartTime(currentTime);
2084 return currentTime + 1;
2089 void startDelayingAnimationStart() {
2090 mAnimationStartDelayed = true;
2093 void endDelayingAnimationStart() {
2094 mAnimationStartDelayed = false;
2097 void seamlesslyRotateWindow(int oldRotation, int newRotation) {
2098 final WindowState w = mWin;
2099 if (!w.isVisibleNow() || w.mIsWallpaper) {
2103 final Rect cropRect = mService.mTmpRect;
2104 final Rect displayRect = mService.mTmpRect2;
2105 final RectF frameRect = mService.mTmpRectF;
2106 final Matrix transform = mService.mTmpTransform;
2108 final float x = w.mFrame.left;
2109 final float y = w.mFrame.top;
2110 final float width = w.mFrame.width();
2111 final float height = w.mFrame.height();
2113 mService.getDefaultDisplayContentLocked().getLogicalDisplayRect(displayRect);
2114 final float displayWidth = displayRect.width();
2115 final float displayHeight = displayRect.height();
2117 // Compute a transform matrix to undo the coordinate space transformation,
2118 // and present the window at the same physical position it previously occupied.
2119 final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
2120 switch (deltaRotation) {
2121 case Surface.ROTATION_0:
2124 case Surface.ROTATION_270:
2125 transform.setRotate(270, 0, 0);
2126 transform.postTranslate(0, displayHeight);
2127 transform.postTranslate(y, 0);
2129 case Surface.ROTATION_180:
2132 case Surface.ROTATION_90:
2133 transform.setRotate(90, 0, 0);
2134 transform.postTranslate(displayWidth, 0);
2135 transform.postTranslate(-y, x);
2139 // We have two cases:
2140 // 1. Windows with NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
2141 // These windows never change buffer size when rotating. Rather the window manager
2142 // just updates the scaling factors to fit in the new coordinate system,
2143 // and SurfaceFlinger takes care of updating the buffer contents. So in this case
2144 // we just need we just need to update the scaling factors and things are seamless
2146 // 2. Other windows:
2147 // In this case, we need to apply a rotation matrix to the window. For example
2148 // if we have a portrait window and rotate to landscape, the window is still portrait
2149 // and now extends off the bottom of the screen (and only halfway across). Essentially we
2150 // apply a transform to display the current buffer at it's old position
2151 // (in the new coordinate space). We then freeze layer updates until the resize
2152 // occurs, at which point we undo, them.
2153 if (w.isChildWindow() && mSurfaceController.getTransformToDisplayInverse()) {
2154 frameRect.set(x, y, x+width, y+height);
2155 transform.mapRect(frameRect);
2157 w.mAttrs.x = (int) frameRect.left - w.mAttachedWindow.mFrame.left;
2158 w.mAttrs.y = (int) frameRect.top - w.mAttachedWindow.mFrame.top;
2159 w.mAttrs.width = (int) Math.ceil(frameRect.width());
2160 w.mAttrs.height = (int) Math.ceil(frameRect.height());
2162 w.setWindowScale(w.mRequestedWidth, w.mRequestedHeight);
2164 w.applyGravityAndUpdateFrame(w.mContainingFrame, w.mDisplayFrame);
2165 computeShownFrameLocked();
2166 setSurfaceBoundariesLocked(false);
2168 // The stack bounds will not yet be rotated at this point so setSurfaceBoundaries locked
2169 // will crop us incorrectly. Overwrite the crop, exposing the full surface. By the next
2170 // transaction this will be corrected.
2171 cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight);
2172 mSurfaceController.setCropInTransaction(cropRect, false);
2174 w.mSeamlesslyRotated = true;
2175 transform.getValues(mService.mTmpFloats);
2177 float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
2178 float DtDx = mService.mTmpFloats[Matrix.MSKEW_Y];
2179 float DsDy = mService.mTmpFloats[Matrix.MSKEW_X];
2180 float DtDy = mService.mTmpFloats[Matrix.MSCALE_Y];
2181 float nx = mService.mTmpFloats[Matrix.MTRANS_X];
2182 float ny = mService.mTmpFloats[Matrix.MTRANS_Y];
2183 mSurfaceController.setPositionInTransaction(nx, ny, false);
2184 mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale,
2187 DtDy * w.mVScale, false);