Craig Mautner | a2c7705 | 2012-03-26 12:14:43 -0700 | [diff] [blame] | 1 | // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 | |
| 3 | package com.android.server.wm; |
| 4 | |
| 5 | import android.util.Slog; |
| 6 | import android.view.WindowManager; |
| 7 | import android.view.WindowManagerPolicy; |
| 8 | import android.view.animation.Animation; |
| 9 | import android.view.animation.Transformation; |
| 10 | |
| 11 | import com.android.server.wm.WindowManagerService.H; |
| 12 | |
| 13 | import java.io.PrintWriter; |
| 14 | |
| 15 | /** |
| 16 | * @author cmautner@google.com (Craig Mautner) |
| 17 | * |
| 18 | */ |
| 19 | class WindowStateAnimator { |
| 20 | |
| 21 | final WindowManagerService mService; |
| 22 | final WindowState mWin; |
| 23 | final WindowState mAttachedWindow; |
Craig Mautner | e7ae250 | 2012-03-26 17:11:19 -0700 | [diff] [blame^] | 24 | final WindowAnimator mAnimator; |
Craig Mautner | a2c7705 | 2012-03-26 12:14:43 -0700 | [diff] [blame] | 25 | |
| 26 | // Currently running animation. |
| 27 | boolean mAnimating; |
| 28 | boolean mLocalAnimating; |
| 29 | Animation mAnimation; |
| 30 | boolean mAnimationIsEntrance; |
| 31 | boolean mHasTransformation; |
| 32 | boolean mHasLocalTransformation; |
| 33 | final Transformation mTransformation = new Transformation(); |
| 34 | boolean mWasAnimating; // Were we animating going into the most recent animation step? |
| 35 | |
| 36 | public WindowStateAnimator(final WindowManagerService service, final WindowState win, |
| 37 | final WindowState attachedWindow) { |
| 38 | mService = service; |
| 39 | mWin = win; |
| 40 | mAttachedWindow = attachedWindow; |
Craig Mautner | e7ae250 | 2012-03-26 17:11:19 -0700 | [diff] [blame^] | 41 | mAnimator = mService.mAnimator; |
Craig Mautner | a2c7705 | 2012-03-26 12:14:43 -0700 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | public void setAnimation(Animation anim) { |
| 45 | if (WindowManagerService.localLOGV) Slog.v( |
| 46 | WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); |
| 47 | mAnimating = false; |
| 48 | mLocalAnimating = false; |
| 49 | mAnimation = anim; |
| 50 | mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); |
| 51 | mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale); |
| 52 | // Start out animation gone if window is gone, or visible if window is visible. |
| 53 | mTransformation.clear(); |
| 54 | mTransformation.setAlpha(mWin.mLastHidden ? 0 : 1); |
| 55 | mHasLocalTransformation = true; |
| 56 | } |
| 57 | |
| 58 | public void clearAnimation() { |
| 59 | if (mAnimation != null) { |
| 60 | mAnimating = true; |
| 61 | mLocalAnimating = false; |
| 62 | mAnimation.cancel(); |
| 63 | mAnimation = null; |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | /** Is the window or its container currently animating? */ |
| 68 | boolean isAnimating() { |
| 69 | final WindowState attached = mAttachedWindow; |
| 70 | final AppWindowToken atoken = mWin.mAppToken; |
| 71 | return mAnimation != null |
| 72 | || (attached != null && attached.mWinAnimator.mAnimation != null) |
| 73 | || (atoken != null && |
| 74 | (atoken.animation != null |
| 75 | || atoken.inPendingTransaction)); |
| 76 | } |
| 77 | |
| 78 | /** Is this window currently animating? */ |
| 79 | boolean isWindowAnimating() { |
| 80 | return mAnimation != null; |
| 81 | } |
| 82 | |
| 83 | // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked() |
| 84 | // for avoiding the code duplication. |
| 85 | void cancelExitAnimationForNextAnimationLocked() { |
| 86 | if (!mWin.mExiting) return; |
| 87 | if (mAnimation != null) { |
| 88 | mAnimation.cancel(); |
| 89 | mAnimation = null; |
| 90 | mWin.destroySurfaceLocked(); |
| 91 | } |
| 92 | mWin.mExiting = false; |
| 93 | } |
| 94 | |
| 95 | private boolean stepAnimation(long currentTime) { |
| 96 | if ((mAnimation == null) || !mLocalAnimating) { |
| 97 | return false; |
| 98 | } |
| 99 | mTransformation.clear(); |
| 100 | final boolean more = mAnimation.getTransformation(currentTime, mTransformation); |
| 101 | if (WindowManagerService.DEBUG_ANIM) Slog.v( |
| 102 | WindowManagerService.TAG, "Stepped animation in " + this + |
| 103 | ": more=" + more + ", xform=" + mTransformation); |
| 104 | return more; |
| 105 | } |
| 106 | |
| 107 | // This must be called while inside a transaction. Returns true if |
| 108 | // there is more animation to run. |
| 109 | boolean stepAnimationLocked(long currentTime) { |
| 110 | // Save the animation state as it was before this step so WindowManagerService can tell if |
| 111 | // we just started or just stopped animating by comparing mWasAnimating with isAnimating(). |
| 112 | mWasAnimating = mAnimating; |
| 113 | if (mService.okToDisplay()) { |
| 114 | // We will run animations as long as the display isn't frozen. |
| 115 | |
| 116 | if (mWin.isDrawnLw() && mAnimation != null) { |
| 117 | mHasTransformation = true; |
| 118 | mHasLocalTransformation = true; |
| 119 | if (!mLocalAnimating) { |
| 120 | if (WindowManagerService.DEBUG_ANIM) Slog.v( |
| 121 | WindowManagerService.TAG, "Starting animation in " + this + |
| 122 | " @ " + currentTime + ": ww=" + mWin.mFrame.width() + |
| 123 | " wh=" + mWin.mFrame.height() + |
| 124 | " dw=" + mWin.mAnimDw + " dh=" + mWin.mAnimDh + |
| 125 | " scale=" + mService.mWindowAnimationScale); |
| 126 | mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mWin.mAnimDw, |
| 127 | mWin.mAnimDh); |
| 128 | mAnimation.setStartTime(currentTime); |
| 129 | mLocalAnimating = true; |
| 130 | mAnimating = true; |
| 131 | } |
| 132 | if ((mAnimation != null) && mLocalAnimating) { |
| 133 | if (stepAnimation(currentTime)) { |
| 134 | return true; |
| 135 | } |
| 136 | } |
| 137 | if (WindowManagerService.DEBUG_ANIM) Slog.v( |
| 138 | WindowManagerService.TAG, "Finished animation in " + this + |
| 139 | " @ " + currentTime); |
| 140 | //WindowManagerService.this.dump(); |
| 141 | } |
| 142 | mHasLocalTransformation = false; |
| 143 | if ((!mLocalAnimating || mAnimationIsEntrance) && mWin.mAppToken != null |
| 144 | && mWin.mAppToken.animation != null) { |
| 145 | // When our app token is animating, we kind-of pretend like |
| 146 | // we are as well. Note the mLocalAnimating mAnimationIsEntrance |
| 147 | // part of this check means that we will only do this if |
| 148 | // our window is not currently exiting, or it is not |
| 149 | // locally animating itself. The idea being that one that |
| 150 | // is exiting and doing a local animation should be removed |
| 151 | // once that animation is done. |
| 152 | mAnimating = true; |
| 153 | mHasTransformation = true; |
| 154 | mTransformation.clear(); |
| 155 | return false; |
| 156 | } else if (mHasTransformation) { |
| 157 | // Little trick to get through the path below to act like |
| 158 | // we have finished an animation. |
| 159 | mAnimating = true; |
| 160 | } else if (isAnimating()) { |
| 161 | mAnimating = true; |
| 162 | } |
| 163 | } else if (mAnimation != null) { |
| 164 | // If the display is frozen, and there is a pending animation, |
| 165 | // clear it and make sure we run the cleanup code. |
| 166 | mAnimating = true; |
| 167 | mLocalAnimating = true; |
| 168 | mAnimation.cancel(); |
| 169 | mAnimation = null; |
| 170 | } |
| 171 | |
| 172 | if (!mAnimating && !mLocalAnimating) { |
| 173 | return false; |
| 174 | } |
| 175 | |
| 176 | if (WindowManagerService.DEBUG_ANIM) Slog.v( |
| 177 | WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting |
| 178 | + ", reportedVisible=" |
| 179 | + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false)); |
| 180 | |
| 181 | mAnimating = false; |
| 182 | mLocalAnimating = false; |
| 183 | if (mAnimation != null) { |
| 184 | mAnimation.cancel(); |
| 185 | mAnimation = null; |
| 186 | } |
Craig Mautner | e7ae250 | 2012-03-26 17:11:19 -0700 | [diff] [blame^] | 187 | if (mAnimator.mWindowDetachedWallpaper == mWin) { |
| 188 | mAnimator.mWindowDetachedWallpaper = null; |
Craig Mautner | a2c7705 | 2012-03-26 12:14:43 -0700 | [diff] [blame] | 189 | } |
| 190 | mWin.mAnimLayer = mWin.mLayer; |
| 191 | if (mWin.mIsImWindow) { |
| 192 | mWin.mAnimLayer += mService.mInputMethodAnimLayerAdjustment; |
| 193 | } else if (mWin.mIsWallpaper) { |
| 194 | mWin.mAnimLayer += mService.mWallpaperAnimLayerAdjustment; |
| 195 | } |
| 196 | if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this |
| 197 | + " anim layer: " + mWin.mAnimLayer); |
| 198 | mHasTransformation = false; |
| 199 | mHasLocalTransformation = false; |
| 200 | if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) { |
| 201 | if (WindowState.DEBUG_VISIBILITY) { |
| 202 | Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": " |
| 203 | + mWin.mPolicyVisibilityAfterAnim); |
| 204 | } |
| 205 | mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim; |
| 206 | mService.mLayoutNeeded = true; |
| 207 | if (!mWin.mPolicyVisibility) { |
| 208 | if (mService.mCurrentFocus == mWin) { |
| 209 | mService.mFocusMayChange = true; |
| 210 | } |
| 211 | // Window is no longer visible -- make sure if we were waiting |
| 212 | // for it to be displayed before enabling the display, that |
| 213 | // we allow the display to be enabled now. |
| 214 | mService.enableScreenIfNeededLocked(); |
| 215 | } |
| 216 | } |
| 217 | mTransformation.clear(); |
| 218 | if (mWin.mHasDrawn |
| 219 | && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING |
| 220 | && mWin.mAppToken != null |
| 221 | && mWin.mAppToken.firstWindowDrawn |
| 222 | && mWin.mAppToken.startingData != null) { |
| 223 | if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting " |
| 224 | + mWin.mToken + ": first real window done animating"); |
| 225 | mService.mFinishedStarting.add(mWin.mAppToken); |
| 226 | mService.mH.sendEmptyMessage(H.FINISHED_STARTING); |
| 227 | } |
| 228 | |
| 229 | finishExit(); |
| 230 | mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; |
| 231 | if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState"); |
| 232 | |
| 233 | if (mWin.mAppToken != null) { |
| 234 | mWin.mAppToken.updateReportedVisibilityLocked(); |
| 235 | } |
| 236 | |
| 237 | return false; |
| 238 | } |
| 239 | |
| 240 | void finishExit() { |
| 241 | if (WindowManagerService.DEBUG_ANIM) Slog.v( |
| 242 | WindowManagerService.TAG, "finishExit in " + this |
| 243 | + ": exiting=" + mWin.mExiting |
| 244 | + " remove=" + mWin.mRemoveOnExit |
| 245 | + " windowAnimating=" + isWindowAnimating()); |
| 246 | |
| 247 | final int N = mWin.mChildWindows.size(); |
| 248 | for (int i=0; i<N; i++) { |
| 249 | mWin.mChildWindows.get(i).mWinAnimator.finishExit(); |
| 250 | } |
| 251 | |
| 252 | if (!mWin.mExiting) { |
| 253 | return; |
| 254 | } |
| 255 | |
| 256 | if (isWindowAnimating()) { |
| 257 | return; |
| 258 | } |
| 259 | |
| 260 | if (WindowManagerService.localLOGV) Slog.v( |
| 261 | WindowManagerService.TAG, "Exit animation finished in " + this |
| 262 | + ": remove=" + mWin.mRemoveOnExit); |
| 263 | if (mWin.mSurface != null) { |
| 264 | mService.mDestroySurface.add(mWin); |
| 265 | mWin.mDestroying = true; |
| 266 | if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface( |
| 267 | mWin, "HIDE (finishExit)", null); |
| 268 | mWin.mSurfaceShown = false; |
| 269 | try { |
| 270 | mWin.mSurface.hide(); |
| 271 | } catch (RuntimeException e) { |
| 272 | Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e); |
| 273 | } |
| 274 | mWin.mLastHidden = true; |
| 275 | } |
| 276 | mWin.mExiting = false; |
| 277 | if (mWin.mRemoveOnExit) { |
| 278 | mService.mPendingRemove.add(mWin); |
| 279 | mWin.mRemoveOnExit = false; |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | public void dump(PrintWriter pw, String prefix, boolean dumpAll) { |
| 284 | if (mAnimating || mLocalAnimating || mAnimationIsEntrance |
| 285 | || mAnimation != null) { |
| 286 | pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating); |
| 287 | pw.print(" mLocalAnimating="); pw.print(mLocalAnimating); |
| 288 | pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance); |
| 289 | pw.print(" mAnimation="); pw.println(mAnimation); |
| 290 | } |
| 291 | if (mHasTransformation || mHasLocalTransformation) { |
| 292 | pw.print(prefix); pw.print("XForm: has="); |
| 293 | pw.print(mHasTransformation); |
| 294 | pw.print(" hasLocal="); pw.print(mHasLocalTransformation); |
| 295 | pw.print(" "); mTransformation.printShortString(pw); |
| 296 | pw.println(); |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | } |