Activity切换动画设置主要包含下面这些步骤,每个步骤按时序图中的顺序依次执行,对于重要的步骤我已标注并附上简单的解释,下面将仔细分析每一步。
第1步、WMS.prepareAppTransition()
AMS调用
WMS.
prepareAppTransition()设置Activity切换动画类型。比较常见的就是TRANSIT_ACTIVITY_OPEN、TRANSIT_ACTIVITY_CLOSE、TRANSIT_TASK_OPEN、TRANSIT_TASK_CLOSE、TRANSIT_TASK_TO_FRONT、TRANSIT_TASK_TO_BACK这几种Activity切换动画类型了。prepareAppTransition()函数做了两件事:①将动画类型设置到AppTransition中,后面将用到这个值;②发送一个APP_TRANSITION_TIMEOUT的5s超时消息。
第2步、WMS.setAppVisibility()
AMS调用WMS.setAppVisibility()设置Activity可见性。一般情况下在一次Activity切换过程中会有两个Activity的可见性发生变化,pre Activity变为不可见,next Activity变为可见。这个函数有两条逻辑:①前面已经调用WMS.prepareAppTransition()设置了Activity切换动画类型,那么将可见Activity加入mOpeningApps,不可见Activity加入mClosingApps,同时调用AppWindowToken.sendAppVisibilityToClients()通知应用窗口可见性变化。mOpeningApps、mClosingApps这两个变量就是为Activity切换动画而存在的,将在后面用到;②没有调用过WMS.prepareAppTransition(),那么直接调用WMS.setTokenVisibilityLocked(),这个函数将在第11步中分析。
- public void setAppVisibility(IBinder token, boolean visible) {
- ......
- synchronized(mWindowMap) {
- wtoken = findAppWindowToken(token);
- ......
-
-
- if (okToDisplay() && mAppTransition.isTransitionSet()) {
- ......
- wtoken.inPendingTransaction = true;
- if (visible) {
- mOpeningApps.add(wtoken);
- wtoken.startingMoved = false;
- wtoken.mEnteringAnimation = true;
-
-
-
-
- if (wtoken.hidden) {
- wtoken.allDrawn = false;
- wtoken.deferClearAllDrawn = false;
- wtoken.waitingToShow = true;
-
- if (wtoken.clientHidden) {
-
-
-
-
-
-
- wtoken.clientHidden = false;
- wtoken.sendAppVisibilityToClients();
- }
- }
- } else {
- mClosingApps.add(wtoken);
- wtoken.mEnteringAnimation = false;
- }
- ......
- return;
- }
- ......
- setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET,true, wtoken.voiceInteraction);
- }
- }
第3、4步、AppWindowToken.sendAppVisibilityToClients()/dispatchAppVisibility()
这个函数就是通知上层应用窗口可见性发生变化。如果next Activity是冷启动,那么该函数并不能通知next Activity的窗口变为可见,因为此时该函数调用时,next Activity的窗口还没add到WMS中来。
第5、6步、WMS.finishDrawingWindow()
next Activity被Resume起来后,添加窗口、measure、layout、draw等一系列操作完成后便会调用WMS.finishDrawingWindow()来通知WMS,该窗口已经绘制好了,可以开始做动画了。WMS.finishDrawingWindow()会调用WindowStateAnimator.finishDrawingLocked()更新窗口状态mDrawState为COMMIT_DRAW_PENDING。同时还会调用requestTraversalLocked()来触发一次界面刷新函数performLayoutAndPlaceSurfacesLockedInner()调用。
第7步、performLayoutAndPlaceSurfacesLockedInner()
该函数就是鼎鼎大名的界面刷新函数。该函数里面跟Activity切换动画相关的调用拆分到接下来的那些步骤中。
第8步、WindowStateAnimator.commitFinishDrawingLocked()
performLayoutAndPlaceSurfacesLockedInner()函数中,对于窗口堆栈中有Surface的窗口均会调用WindowStateAnimator.commitFinishDrawingLocked(),该函数将窗口状态为COMMIT_DRAW_PENDING或READY_TO_SHOW的窗口,全部更新到READY_TO_SHOW状态。将状态从第五中中的COMMIT_DRAW_PENDING更新到READY_TO_SHOW,WindowState.isDrawnLw()便会返回true,代表窗口已经是绘制完成状态。w.isDrawnLw()返回为true,那么才有updateAllDrawn = true,接着才会触发调用第九步中的WMS.updateAllDrawnLocked()函数,将AppWindowToken.allDrawn置为true。
- boolean commitFinishDrawingLocked() {
- if (DEBUG_STARTING_WINDOW &&
- mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
- Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
- + drawStateToString());
- }
- if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
- return false;
- }
- if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
- Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceControl);
- }
- mDrawState = READY_TO_SHOW;
- final AppWindowToken atoken = mWin.mAppToken;
- if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
- return performShowLocked();
- }
- return false;
- }
- if (w != atoken.startingWindow) {
- if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
- atoken.numInterestingWindows++;
- if (w.isDrawnLw()) {
- atoken.numDrawnWindows++;
- if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
- "tokenMayBeDrawn: " + atoken
- + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
- + " mAppFreezing=" + w.mAppFreezing);
- updateAllDrawn = true;
- }
- }
第9步、WMS.updateAllDrawnLocked()
该函数更新AppWindowToken.allDrawn值。只有属于该AppWindowToken的所有窗口都是绘制完成状态(一般情况下只有一个窗口,有时候会有父窗口、子窗口,这时属于该AppWindowToken的窗口数量就不止一个了),AppWindowToken.allDrawn才会置为true。AppWindowToken.allDrawn为true才会使得第十步中的WMS.handleAppTransitionReadyLocked()完整的执行。
- private void updateAllDrawnLocked(DisplayContent displayContent) {
-
-
- ArrayList stacks = displayContent.getStacks();
- for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ArrayList tasks = stacks.get(stackNdx).getTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- if (!wtoken.allDrawn) {
- int numInteresting = wtoken.numInterestingWindows;
- if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
- if (DEBUG_VISIBILITY) Slog.v(TAG,
- "allDrawn: " + wtoken
- + " interesting=" + numInteresting
- + " drawn=" + wtoken.numDrawnWindows);
- wtoken.allDrawn = true;
-
-
- displayContent.layoutNeeded = true;
- mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
- }
- }
- }
- }
- }
- }
第10步、WMS.handleAppTransitionReadyLocked()
设置Activity切换动画选择逻辑就是在该函数中完成。该函数只有在调用了第一步后才会被调用,并且只有在wtoken.allDrawn=true时才会完整的执行完。这个函数接近300行,逻辑看起来非常复杂,下面将仔细分析这个函数。
- public int handleAppTransitionReadyLocked(WindowList windows) {
- int changes = 0;
- int i;
- int appsCount = mOpeningApps.size();
- boolean goodToGo = true;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Checking " + appsCount + " opening apps (frozen="
- + mDisplayFrozen + " timeout="
- + mAppTransition.isTimeout() + ")...");
- if (!mAppTransition.isTimeout()) {
- for (i = 0; i < appsCount && goodToGo; i++) {
- AppWindowToken wtoken = mOpeningApps.valueAt(i);
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Check opening app=" + wtoken + ": allDrawn="
- + wtoken.allDrawn + " startingDisplayed="
- + wtoken.startingDisplayed + " startingMoved="
- + wtoken.startingMoved);
- if (!wtoken.allDrawn && !wtoken.startingDisplayed
- && !wtoken.startingMoved) {
- goodToGo = false;
- }
- }
-
- if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
- boolean wallpaperGoodToGo = true;
- for (int curTokenIndex = mWallpaperTokens.size() - 1;
- curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
- for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
- curWallpaperIndex--) {
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
- if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
-
- wallpaperGoodToGo = false;
- if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
-
- goodToGo = false;
- }
- if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
- mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
- mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
- mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
- WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
- }
- if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
- "Wallpaper should be visible but has not been drawn yet. " +
- "mWallpaperDrawState=" + mWallpaperDrawState);
- break;
- }
- }
- }
- if (wallpaperGoodToGo) {
- mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
- mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
- }
- }
- }
- if (goodToGo) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
- int transit = mAppTransition.getAppTransition();
- if (mSkipAppTransitionAnimation) {
- transit = AppTransition.TRANSIT_UNSET;
- }
- mSkipAppTransitionAnimation = false;
- mNoAnimationNotifyOnTransitionFinished.clear();
-
- mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-
- rebuildAppWindowListLocked();
-
- WindowState oldWallpaper =
- mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
- && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
- ? null : mWallpaperTarget;
-
- mInnerFields.mWallpaperMayChange = false;
-
-
-
- LayoutParams animLp = null;
- int bestAnimLayer = -1;
- boolean fullscreenAnim = false;
- boolean voiceInteraction = false;
-
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New wallpaper target=" + mWallpaperTarget
- + ", oldWallpaper=" + oldWallpaper
- + ", lower target=" + mLowerWallpaperTarget
- + ", upper target=" + mUpperWallpaperTarget);
-
- boolean openingAppHasWallpaper = false;
- boolean closingAppHasWallpaper = false;
- final AppWindowToken lowerWallpaperAppToken;
- final AppWindowToken upperWallpaperAppToken;
- if (mLowerWallpaperTarget == null) {
- lowerWallpaperAppToken = upperWallpaperAppToken = null;
- } else {
- lowerWallpaperAppToken = mLowerWallpaperTarget.mAppToken;
- upperWallpaperAppToken = mUpperWallpaperTarget.mAppToken;
- }
-
-
-
-
-
-
-
-
-
-
-
- final int closingAppsCount = mClosingApps.size();
- appsCount = closingAppsCount + mOpeningApps.size();
- for (i = 0; i < appsCount; i++) {
- final AppWindowToken wtoken;
- if (i < closingAppsCount) {
- wtoken = mClosingApps.valueAt(i);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
- closingAppHasWallpaper = true;
- }
- } else {
- wtoken = mOpeningApps.valueAt(i - closingAppsCount);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
- openingAppHasWallpaper = true;
- }
- }
-
- voiceInteraction |= wtoken.voiceInteraction;
-
- if (wtoken.appFullscreen) {
- WindowState ws = wtoken.findMainWindow();
- if (ws != null) {
- animLp = ws.mAttrs;
- bestAnimLayer = ws.mLayer;
- fullscreenAnim = true;
- }
- } else if (!fullscreenAnim) {
- WindowState ws = wtoken.findMainWindow();
- if (ws != null) {
- if (ws.mLayer > bestAnimLayer) {
- animLp = ws.mAttrs;
- bestAnimLayer = ws.mLayer;
- }
- }
- }
- }
-
- mAnimateWallpaperWithTarget = false;
- if (closingAppHasWallpaper && openingAppHasWallpaper) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
- switch (transit) {
- case AppTransition.TRANSIT_ACTIVITY_OPEN:
- case AppTransition.TRANSIT_TASK_OPEN:
- case AppTransition.TRANSIT_TASK_TO_FRONT:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
- break;
- case AppTransition.TRANSIT_ACTIVITY_CLOSE:
- case AppTransition.TRANSIT_TASK_CLOSE:
- case AppTransition.TRANSIT_TASK_TO_BACK:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
- break;
- }
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit: " + AppTransition.appTransitionToString(transit));
- } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
- && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
-
-
- transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit away from wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
-
-
- transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit into wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else {
- mAnimateWallpaperWithTarget = true;
- }
-
-
-
-
-
- if (!mPolicy.allowAppAnimationsLw()) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Animations disallowed by keyguard or dream.");
- animLp = null;
- }
-
- AppWindowToken topOpeningApp = null;
- AppWindowToken topClosingApp = null;
- int topOpeningLayer = 0;
- int topClosingLayer = 0;
-
-
- if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
-
- final WindowState win =
- findFocusedWindowLocked(getDefaultDisplayContentLocked());
- if (win != null) {
- final AppWindowToken wtoken = win.mAppToken;
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- updateTokenInPlaceLocked(wtoken, transit);
- wtoken.updateReportedVisibilityLocked();
-
- appAnimator.mAllAppWinAnimators.clear();
- final int N = wtoken.allAppWindows.size();
- for (int j = 0; j < N; j++) {
- appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
- }
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
- mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
- }
- }
-
- appsCount = mOpeningApps.size();
- for (i = 0; i < appsCount; i++) {
-
- AppWindowToken wtoken = mOpeningApps.valueAt(i);
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
-
- if (!appAnimator.usingTransferredAnimation) {
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- }
- wtoken.inPendingTransaction = false;
- if (!setTokenVisibilityLocked(
- wtoken, animLp, true, transit, false, voiceInteraction)){
-
-
-
- mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
- }
- wtoken.updateReportedVisibilityLocked();
- wtoken.waitingToShow = false;
-
- appAnimator.mAllAppWinAnimators.clear();
- final int windowsCount = wtoken.allAppWindows.size();
- for (int j = 0; j < windowsCount; j++) {
- appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
- }
- mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
- if (animLp != null) {
- int layer = -1;
- for (int j = 0; j < wtoken.windows.size(); j++) {
- WindowState win = wtoken.windows.get(j);
- if (win.mWinAnimator.mAnimLayer > layer) {
- layer = win.mWinAnimator.mAnimLayer;
- }
- }
- if (topOpeningApp == null || layer > topOpeningLayer) {
- topOpeningApp = wtoken;
- topOpeningLayer = layer;
- }
- }
- }
- appsCount = mClosingApps.size();
- for (i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mClosingApps.valueAt(i);
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- wtoken.inPendingTransaction = false;
- setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
- wtoken.updateReportedVisibilityLocked();
-
-
-
- wtoken.allDrawn = true;
- wtoken.deferClearAllDrawn = false;
-
-
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
- scheduleRemoveStartingWindowLocked(wtoken);
- }
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
- if (animLp != null) {
- int layer = -1;
- for (int j = 0; j < wtoken.windows.size(); j++) {
- WindowState win = wtoken.windows.get(j);
- if (win.mWinAnimator.mAnimLayer > layer) {
- layer = win.mWinAnimator.mAnimLayer;
- }
- }
- if (topClosingApp == null || layer > topClosingLayer) {
- topClosingApp = wtoken;
- topClosingLayer = layer;
- }
- }
- }
-
- AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null :
- topOpeningApp.mAppAnimator;
- AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
- topClosingApp.mAppAnimator;
- Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
- if (nextAppTransitionThumbnail != null
- && openingAppAnimator != null && openingAppAnimator.animation != null &&
- nextAppTransitionThumbnail.getConfig() != Config.ALPHA_8) {
-
-
- Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
- nextAppTransitionThumbnail.getHeight());
- try {
-
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final Display display = displayContent.getDisplay();
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-
-
- SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
- "thumbnail anim", dirty.width(), dirty.height(),
- PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
- surfaceControl.setLayerStack(display.getLayerStack());
- if (SHOW_TRANSACTIONS) {
- Slog.i(TAG, " THUMBNAIL " + surfaceControl + ": CREATE");
- }
-
-
- Surface drawSurface = new Surface();
- drawSurface.copyFrom(surfaceControl);
- Canvas c = drawSurface.lockCanvas(dirty);
- c.drawBitmap(nextAppTransitionThumbnail, 0, 0, null);
- drawSurface.unlockCanvasAndPost(c);
- drawSurface.release();
-
-
- Animation anim;
- if (mAppTransition.isNextThumbnailTransitionAspectScaled()) {
-
-
-
-
- anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(
- displayInfo.appWidth, displayInfo.appHeight,
- displayInfo.logicalWidth, transit);
- openingAppAnimator.thumbnailForceAboveLayer = Math.max(topOpeningLayer,
- topClosingLayer);
- openingAppAnimator.deferThumbnailDestruction =
- !mAppTransition.isNextThumbnailTransitionScaleUp();
- } else {
- anim = mAppTransition.createThumbnailScaleAnimationLocked(
- displayInfo.appWidth, displayInfo.appHeight, transit);
- }
- anim.restrictDuration(MAX_ANIMATION_DURATION);
- anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());
-
- openingAppAnimator.thumbnail = surfaceControl;
- openingAppAnimator.thumbnailLayer = topOpeningLayer;
- openingAppAnimator.thumbnailAnimation = anim;
- openingAppAnimator.thumbnailX = mAppTransition.getStartingX();
- openingAppAnimator.thumbnailY = mAppTransition.getStartingY();
- } catch (OutOfResourcesException e) {
- Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
- + " h=" + dirty.height(), e);
- openingAppAnimator.clearThumbnail();
- }
- }
-
- mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
- mAppTransition.postAnimationCallback();
- mAppTransition.clear();
-
- mOpeningApps.clear();
- mClosingApps.clear();
-
-
-
- changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
- | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
- getDefaultDisplayContentLocked().layoutNeeded = true;
-
-
- if (windows == getDefaultWindowListLocked()
- && !moveInputMethodWindowsIfNeededLocked(true)) {
- assignLayersLocked(windows);
- }
- updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true );
- mFocusMayChange = false;
- notifyActivityDrawnForKeyguard();
- }
-
- return changes;
- }
上面这个函数很长,但是逻辑思路很简单,初看起来确实复杂,仔细分析发现还是比较容易理解的。总结起来就是:确定壁纸目标窗口对transit值的影响、取得顶层窗口的mAttr值、两次调用setTokenVisibilityLocked()来设置APPWindowToken可见性及加载对应的动画。
第11步、WMS.setTokenVisibilityLocked()
这个函数用来设置APPWindowToken.hidden的可见性、设置Activity切换动画(如果参数transit==AppTransition.TRANSIT_UNSET,那就是会设置窗口动画,否则就会设置Activity切换动画),如果存在Activity切换动画或属于该Activity的窗口正在做窗口动画,那么返回值为true。
- boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
- boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
- boolean delayed = false;
-
- if (wtoken.clientHidden == visible) {
- wtoken.clientHidden = !visible;
- wtoken.sendAppVisibilityToClients();
- }
-
- wtoken.willBeHidden = false;
-
-
-
- if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting)) {
- boolean changed = false;
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
- + " performLayout=" + performLayout);
-
- boolean runningAppAnimation = false;
-
- if (transit != AppTransition.TRANSIT_UNSET) {
- if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
- wtoken.mAppAnimator.animation = null;
- }
- if (applyAnimationLocked(wtoken, lp, transit, visible, isVoiceInteraction)) {
- delayed = runningAppAnimation = true;
- }
- WindowState window = wtoken.findMainWindow();
-
- if (window != null && mAccessibilityController != null
- && window.getDisplayId() == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onAppWindowTransitionLocked(window, transit);
- }
- changed = true;
- }
-
- final int windowsCount = wtoken.allAppWindows.size();
- for (int i = 0; i < windowsCount; i++) {
- WindowState win = wtoken.allAppWindows.get(i);
- if (win == wtoken.startingWindow) {
- continue;
- }
-
-
-
- if (visible) {
- if (!win.isVisibleNow()) {
- if (!runningAppAnimation) {
- win.mWinAnimator.applyAnimationLocked(
- WindowManagerPolicy.TRANSIT_ENTER, true);
-
- if (mAccessibilityController != null
- && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onWindowTransitionLocked(win,
- WindowManagerPolicy.TRANSIT_ENTER);
- }
- }
- changed = true;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
- }
- } else if (win.isVisibleNow()) {
- if (!runningAppAnimation) {
- win.mWinAnimator.applyAnimationLocked(
- WindowManagerPolicy.TRANSIT_EXIT, false);
-
- if (mAccessibilityController != null
- && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onWindowTransitionLocked(win,
- WindowManagerPolicy.TRANSIT_EXIT);
- }
- }
- changed = true;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent != null) {
- displayContent.layoutNeeded = true;
- }
- }
- }
-
- wtoken.hidden = wtoken.hiddenRequested = !visible;
- if (!visible) {
- unsetAppFreezingScreenLocked(wtoken, true, true);
- } else {
-
-
- WindowState swin = wtoken.startingWindow;
- if (swin != null && !swin.isDrawnLw()) {
- swin.mPolicyVisibility = false;
- swin.mPolicyVisibilityAfterAnim = false;
- }
- }
-
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken
- + ": hidden=" + wtoken.hidden + " hiddenRequested="
- + wtoken.hiddenRequested);
-
- if (changed) {
- mInputMonitor.setUpdateInputWindowsNeededLw();
- if (performLayout) {
- updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
- false );
- performLayoutAndPlaceSurfacesLocked();
- }
- mInputMonitor.updateInputWindowsLw(false );
- }
- }
-
- if (wtoken.mAppAnimator.animation != null) {
- delayed = true;
- }
-
- for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
- if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {
- delayed = true;
- }
- }
-
- return delayed;
- }
第12步、WMS.applyAnimationLocked()
该函数首先会根据AppWindowToken所属窗口是否是全屏窗口来确定containingFrame、contentInsets、appFrame三个值,然后调用AppTransition.loadAnimation()取得一个Activity切换动画Animation,最后将这个Animation通过AppTransition.setAnimation()接口设置到AppTransition中去。
- private boolean applyAnimationLocked(AppWindowToken atoken,
- WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) {
-
-
-
-
- if (okToDisplay()) {
- DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
- final int width = displayInfo.appWidth;
- final int height = displayInfo.appHeight;
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation: atoken=" + atoken);
-
-
- WindowState win = atoken.findMainWindow();
- Rect containingFrame = new Rect(0, 0, width, height);
- Rect contentInsets = new Rect();
- Rect appFrame = new Rect(0, 0, width, height);
- if (win != null && win.isFullscreen(width, height)) {
-
-
-
- containingFrame.set(win.mContainingFrame);
- contentInsets.set(win.mContentInsets);
- appFrame.set(win.mFrame);
- }
-
- if (atoken.mLaunchTaskBehind) {
-
-
-
- enter = false;
- }
- Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
- mCurConfiguration.orientation, containingFrame, contentInsets, appFrame,
- isVoiceInteraction);
- if (a != null) {
- if (DEBUG_ANIM) {
- RuntimeException e = null;
- if (!HIDE_STACK_CRAWLS) {
- e = new RuntimeException();
- e.fillInStackTrace();
- }
- Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);
- }
- atoken.mAppAnimator.setAnimation(a, width, height,
- mAppTransition.canSkipFirstFrame());
- }
- } else {
- atoken.mAppAnimator.clearAnimation();
- }
-
- return atoken.mAppAnimator.animation != null;
- }
第13、14步、AppTransition.loadAnimation()/AppTransition.setAnimation()
AppTransition.loadAnimation()函数就是根据mNextAppTransitionType、transit、enter、isVoiceInteraction来决定出一个animAttr值,然后调用loadAnimationRes()或loadAnimationAttr()或其他创建Animation接口来加载一个Animation出来。现在很多应用使用startActivity(Intent intent, Bundle options)时在options参数中携带了自定义动画来取代系统默认Activity切换动画,那究竟是如何做到替换系统默认Activity切换动画的呢?秘密在于startActivity时,AMS会主动根据options携带的动画类型type,调用WMS.overridePendingAppTransition()等接口来覆盖Activity默认切换动画,当然上层应用也可直接调用WMS.overridePendingAppTransition()来覆盖Activity默认切换动画,关于startActivity()携带自定义Activity切换动画这个流程在文章第四部分会简单分析。
- Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
- Rect appFrame, boolean isVoiceInteraction) {
- Animation a;
- if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
- || transit == TRANSIT_TASK_OPEN
- || transit == TRANSIT_TASK_TO_FRONT)) {
- a = loadAnimationRes(lp, enter
- ? com.android.internal.R.anim.voice_activity_open_enter
- : com.android.internal.R.anim.voice_activity_open_exit);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation voice:"
- + " anim=" + a + " transit=" + appTransitionToString(transit)
- + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
- } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
- || transit == TRANSIT_TASK_CLOSE
- || transit == TRANSIT_TASK_TO_BACK)) {
- a = loadAnimationRes(lp, enter
- ? com.android.internal.R.anim.voice_activity_close_enter
- : com.android.internal.R.anim.voice_activity_close_exit);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation voice:"
- + " anim=" + a + " transit=" + appTransitionToString(transit)
- + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
- } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
- a = loadAnimationRes(mNextAppTransitionPackage, enter ?
- mNextAppTransitionEnter : mNextAppTransitionExit);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation:"
- + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
- + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
- + " Callers=" + Debug.getCallers(3));
- } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
- a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation:"
- + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
- + " transit=" + appTransitionToString(transit)
- + " Callers=" + Debug.getCallers(3));
- } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
- a = createClipRevealAnimationLocked(transit, enter, appFrame);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation:"
- + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
- + " Callers=" + Debug.getCallers(3));
- } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
- a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation:"
- + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
- + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
- + " Callers=" + Debug.getCallers(3));
- } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
- mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
- mNextAppTransitionScaleUp =
- (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
- a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
- appWidth, appHeight, transit);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- String animName = mNextAppTransitionScaleUp ?
- "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
- Slog.v(TAG, "applyAnimation:"
- + " anim=" + a + " nextAppTransition=" + animName
- + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
- + " Callers=" + Debug.getCallers(3));
- }
- } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
- mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
- mNextAppTransitionScaleUp =
- (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
- a = createAspectScaledThumbnailEnterExitAnimationLocked(
- getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
- transit, containingFrame, contentInsets);
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- String animName = mNextAppTransitionScaleUp ?
- "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
- Slog.v(TAG, "applyAnimation:"
- + " anim=" + a + " nextAppTransition=" + animName
- + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
- + " Callers=" + Debug.getCallers(3));
- }
- } else {
- int animAttr = 0;
- switch (transit) {
- case TRANSIT_ACTIVITY_OPEN:
- animAttr = enter
- ? WindowAnimation_activityOpenEnterAnimation
- : WindowAnimation_activityOpenExitAnimation;
- break;
- case TRANSIT_ACTIVITY_CLOSE:
- animAttr = enter
- ? WindowAnimation_activityCloseEnterAnimation
- : WindowAnimation_activityCloseExitAnimation;
- break;
- case TRANSIT_TASK_OPEN:
- animAttr = enter
- ? WindowAnimation_taskOpenEnterAnimation
- : WindowAnimation_taskOpenExitAnimation;
- break;
- case TRANSIT_TASK_CLOSE:
- animAttr = enter
- ? WindowAnimation_taskCloseEnterAnimation
- : WindowAnimation_taskCloseExitAnimation;
- break;
- case TRANSIT_TASK_TO_FRONT:
- animAttr = enter
- ? WindowAnimation_taskToFrontEnterAnimation
- : WindowAnimation_taskToFrontExitAnimation;
- break;
- case TRANSIT_TASK_TO_BACK:
- animAttr = enter
- ? WindowAnimation_taskToBackEnterAnimation
- : WindowAnimation_taskToBackExitAnimation;
- break;
- case TRANSIT_WALLPAPER_OPEN:
- animAttr = enter
- ? WindowAnimation_wallpaperOpenEnterAnimation
- : WindowAnimation_wallpaperOpenExitAnimation;
- break;
- case TRANSIT_WALLPAPER_CLOSE:
- animAttr = enter
- ? WindowAnimation_wallpaperCloseEnterAnimation
- : WindowAnimation_wallpaperCloseExitAnimation;
- break;
- case TRANSIT_WALLPAPER_INTRA_OPEN:
- animAttr = enter
- ? WindowAnimation_wallpaperIntraOpenEnterAnimation
- : WindowAnimation_wallpaperIntraOpenExitAnimation;
- break;
- case TRANSIT_WALLPAPER_INTRA_CLOSE:
- animAttr = enter
- ? WindowAnimation_wallpaperIntraCloseEnterAnimation
- : WindowAnimation_wallpaperIntraCloseExitAnimation;
- break;
- case TRANSIT_TASK_OPEN_BEHIND:
- animAttr = enter
- ? WindowAnimation_launchTaskBehindSourceAnimation
- : WindowAnimation_launchTaskBehindTargetAnimation;
- }
- a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation:"
- + " anim=" + a
- + " animAttr=0x" + Integer.toHexString(animAttr)
- + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
- + " Callers=" + Debug.getCallers(3));
- }
- return a;
- }
从上面可以看到对于普通Activity切换,会调用AppTransition.loadAnimationAttr()来加载一个动画。
- Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
- int anim = 0;
- Context context = mContext;
- if (animAttr >= 0) {
- AttributeCache.Entry ent = getCachedAnimations(lp);
- if (ent != null) {
- context = ent.context;
- anim = ent.array.getResourceId(animAttr, 0);
- }
- }
- if (anim != 0) {
- return AnimationUtils.loadAnimation(context, anim);
- }
- return null;
- }
第15步、WMS.scheduleAnimationLocked()
触发动画下一帧计算逻辑。Activity切换动画、窗口动画究竟是如何实现的?说直白点就是调用scheduleAnimationLocked()后,使得在下一个vsync信号来临时触发调用计算窗口透明度、尺寸、旋转角度等值,然后将这些值设置到SurfaceFlinger中去。如果这一帧动画计算完成发现动画仍未结束,便会再次调用scheduleAnimationLocked()使得下一个vsync信号来临时重复之前的计算工作,依次往复,便达实现了想要的动画效果。至于这个一帧动画计算逻辑是如何执行的,请看下面第三部分。
第二部分:窗口动画设置
窗口动画的设置没那么复杂,我们就看一个比较常见的设置途径,流程如下。窗口动画设置关键函数在WindowStateAnimator.applyAnimationLocked()中,其他函数在第一部分已经分析过了,下面将重点分析这个函数。
WindowStateAnimator.applyAnimationLocked()函数对于Activity窗口来说并不会为其设置一个窗口动画,而对于非Activity窗口来说其窗口动画设置就是在这个函数中完成的,关
于这一点已经在上面第一部分中的
第十步
WMS.handleAppTransitionReadyLocked()函数分析中讲的非常详细了,在此不多说
。而对于非Activity窗口,比如popupwindow,可通过
setAnimationStyle(int id)
方法设置一个指定的样式窗口动画,样式如下:
下面将详细分析WindowStateAnimator.applyAnimationLocked()函数。
- boolean applyAnimationLocked(int transit, boolean isEntrance) {
- if ((mLocalAnimating && mAnimationIsEntrance == isEntrance)
- || mKeyguardGoingAwayAnimation) {
-
-
-
-
-
- if (mAnimation != null && mKeyguardGoingAwayAnimation
- && transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) {
- applyFadeoutDuringKeyguardExitAnimation();
- }
- return true;
- }
-
-
-
-
-
- if (mService.okToDisplay()) {
- int anim = mPolicy.selectAnimationLw(mWin, transit);
- int attr = -1;
- Animation a = null;
- if (anim != 0) {
- a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
- } else {
- switch (transit) {
- case WindowManagerPolicy.TRANSIT_ENTER:
- attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_EXIT:
- attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_SHOW:
- attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_HIDE:
- attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
- break;
- }
- if (attr >= 0) {
- a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);
- }
- }
- if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
- "applyAnimation: win=" + this
- + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
- + " a=" + a
- + " transit=" + transit
- + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
- if (a != null) {
- if (WindowManagerService.DEBUG_ANIM) {
- RuntimeException e = null;
- if (!WindowManagerService.HIDE_STACK_CRAWLS) {
- e = new RuntimeException();
- e.fillInStackTrace();
- }
- Slog.v(TAG, "Loaded animation " + a + " for " + this, e);
- }
- setAnimation(a);
- mAnimationIsEntrance = isEntrance;
- }
- } else {
- clearAnimation();
- }
-
- return mAnimation != null;
- }
如果Activity窗口调用此函数设置一个窗口动画,而从前面第一部分知道对于Activity会设置一个Activity切换动画,那这两个动画搅在一起岂不是乱套了。
对于WindowStateAnimator.applyAnimationLocked()函数还有其他地方会调用,下面调用栈就是一个例子。
- at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:1947)
- at com.android.server.wm.WindowManagerService.removeWindowLocked(WindowManagerService.java:3022)
- at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2977)
- at com.android.server.wm.Session.remove(Session.java:193)
- at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:233)
- at com.android.server.wm.Session.onTransact(Session.java:136)
第三部分:动画每一帧计算
动画每一帧计算本质上就是根据第一部分加载出来的Animation(可能是Activity切换动画或窗口动画),结合时间变量计算出Transformation值,然后将
Transformation值apply到窗口Surface的各个属性上,最后将窗口Surface属性设置到SurfaceFlinger中,完成动画一帧显示。下图就是动画一帧计算的时序图,下面将分析每一步调用。
第1、2步、WMS.performLayoutAndPlaceSurfacesLockedInner()
该函数是界面刷新函数,是WMS最核心的函数,窗口堆栈管理、各种特殊窗口处理、窗口layout计算等等均在该函数中完成,该函数最后会调用scheduleAnimationLocked()触发下一帧动画计算。scheduleAnimationLocked()只是简单的往Choreographer添加一个callback回调,待下一个vsync信号来临时便可触发调用callback。
- void scheduleAnimationLocked() {
- if (!mAnimationScheduled) {
- mAnimationScheduled = true;
- mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
- }
- }
- WindowAnimator(final WindowManagerService service) {
- mService = service;
- mContext = service.mContext;
- mPolicy = service.mPolicy;
- mAnimationFrameCallback = new Choreographer.FrameCallback() {
- public void doFrame(long frameTimeNs) {
- synchronized (mService.mWindowMap) {
- mService.mAnimationScheduled = false;
- animateLocked(frameTimeNs);
- }
- }
- };
- }
第3步、WindowAnimator.animateLocked()
该函数掌管着Activity切换动画、窗口动画、转屏动画,乃动画执行核心函数。从前面的动画设置部分我们已经知道,WMS会综合选择一个动画进入退出类型,然后根据resId从xml资源中加载出一个Animation对象,对于Activity切换动画、窗口动画会分别保存在AppWindowAnimator.animation和WindowStateAnimator.mAnimation中。WindowAnimator.animateLocked()函数会首先会根据Animation与时间值计算出一个Transformation值,Transformation中记录动画每一帧的透明度、裁剪尺寸、3*3阶旋转和缩放矩阵,然后在遍历窗口堆栈中所有窗口,调用WindowStateAnimator.prepareSurfaceLocked()来将Transformation值落实到更具体的surface属性上面,并设置到SurfaceFlinger中去,完成一帧动画的显示。
第4、5、6步、WindowAnimator.updateAppWindowsLocked()
updateAppWindowsLocked()函数遍历所有AppWindowAnimator,调用AppWindowAnimator.stepAnimationLocked()函数,根据时间、Animation来更新AppWindowAnimator.transformation值。更具体的计算逻辑请自行分析Animation.getTransformation()函数,里面包含了插值器逻辑。
- private void updateAppWindowsLocked(int displayId) {
- ArrayList stacks = mService.getDisplayContentLocked(displayId).getStacks();
- for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = stacks.get(stackNdx);
- final ArrayList tasks = stack.getTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
- final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
- appAnimator.wasAnimating = appAnimator.animating;
- if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
- appAnimator.animating = true;
- mAnimating = mAppWindowAnimating = true;
- } else if (appAnimator.wasAnimating) {
-
- setAppLayoutChanges(appAnimator,
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "appToken " + appAnimator.mAppToken + " done", displayId);
- if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
- "updateWindowsApps...: done animating " + appAnimator.mAppToken);
- }
- }
- }
- final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
- final int exitingCount = exitingAppTokens.size();
- for (int i = 0; i < exitingCount; i++) {
- final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
- appAnimator.wasAnimating = appAnimator.animating;
- if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
- mAnimating = mAppWindowAnimating = true;
- } else if (appAnimator.wasAnimating) {
-
- setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "exiting appToken " + appAnimator.mAppToken + " done", displayId);
- if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
- "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
- }
- }
- }
- }
第7、8步、ScreenRotationAnimation.stepAnimationLocked()
转屏动画计算便在ScreenRotationAnimation.stepAnimationLocked()中完成,主要计算更新ScreenRotationAnimation.mEnterTransformation值。转屏动画的本质就是截一张图单独做转屏旋转,其Surface名为"ScreenshotSurface",也就是说转屏动画并不是通过控制应用窗口的surface属性来达到转屏效果的,而是单独创建了一个surface,该surface显示内容来自SurfaceControl.screenshot()接口,前面计算出来的mEnterTransformation等值通过控制这个单独surface的属性来达到转屏动画效果,
关于转屏动画在此不多说,有兴趣的可以自行研究。但是有一个疑问,为啥做转屏动画时,比如从竖屏应用启动一个默认横屏的应用,系统并不会设置Activity切换动画?这个问题后面有空再分析解答。
第9、10、11步、WindowAnimator.updateWindowsLocked()
该函数会遍历所有窗口计算其窗口动画一帧值,即调用WindowStateAnimator.stepAnimationLocked()计算更新WindowStateAnimator.mTransformation值。其他逻辑主要涉及到keyguard显示后,某些窗口是否隐藏或显示,及keyguard退出动画等,在此不细细分析。
- private void updateWindowsLocked(final int displayId) {
- ++mAnimTransactionSequence;
-
- final WindowList windows = mService.getWindowListLocked(displayId);
-
- if (mKeyguardGoingAway) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState win = windows.get(i);
- if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {
- continue;
- }
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
- if (!winAnimator.mAnimating) {
- if (DEBUG_KEYGUARD) Slog.d(TAG,
- "updateWindowsLocked: creating delay animation");
-
-
- winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
- winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
- winAnimator.mAnimationIsEntrance = false;
- winAnimator.mAnimationStartTime = -1;
- winAnimator.mKeyguardGoingAwayAnimation = true;
- }
- } else {
- if (DEBUG_KEYGUARD) Slog.d(TAG,
- "updateWindowsLocked: StatusBar is no longer keyguard");
- mKeyguardGoingAway = false;
- winAnimator.clearAnimation();
- }
- break;
- }
- }
-
- mForceHiding = KEYGUARD_NOT_SHOWN;
-
- boolean wallpaperInUnForceHiding = false;
- boolean startingInUnForceHiding = false;
- ArrayList unForceHiding = null;
- WindowState wallpaper = null;
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState win = windows.get(i);
- WindowStateAnimator winAnimator = win.mWinAnimator;
- final int flags = win.mAttrs.flags;
- boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);
- boolean shouldBeForceHidden = shouldForceHide(win);
- if (winAnimator.mSurfaceControl != null) {
- final boolean wasAnimating = winAnimator.mWasAnimating;
- final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
- winAnimator.mWasAnimating = nowAnimating;
- mAnimating |= nowAnimating;
-
- boolean appWindowAnimating = winAnimator.mAppAnimator != null
- && winAnimator.mAppAnimator.animating;
- boolean wasAppWindowAnimating = winAnimator.mAppAnimator != null
- && winAnimator.mAppAnimator.wasAnimating;
- boolean anyAnimating = appWindowAnimating || nowAnimating;
- boolean anyWasAnimating = wasAppWindowAnimating || wasAnimating;
-
- try {
- if (anyAnimating && !anyWasAnimating) {
- win.mClient.onAnimationStarted(winAnimator.mAnimatingMove ? -1
- : winAnimator.mKeyguardGoingAwayAnimation ? 1
- : 0);
- } else if (!anyAnimating && anyWasAnimating) {
- win.mClient.onAnimationStopped();
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to dispatch window animation state change.", e);
- }
-
- if (WindowManagerService.DEBUG_WALLPAPER) {
- Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +
- ", nowAnimating=" + nowAnimating);
- }
-
- if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
- mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
- setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
- if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
- mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
- getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
- }
- }
-
-
- ........
第12步、WindowStateAnimator.prepareSurfaceLocked()
对窗口堆栈中所有窗口执行WindowStateAnimator.prepareSurfaceLocked()设置每个窗口的动画帧。在前面已经根据时间、Animation值将AppWindowAnimator.transformation和WindowStateAnimator.mTransformation计算出来,接着就该将这两个Transformation转换成Surface的属性并设置到SurfaceFlinger中去。
- public void prepareSurfaceLocked(final boolean recoveringMemory) {
- final WindowState w = mWin;
- if (mSurfaceControl == null) {
- if (w.mOrientationChanging) {
- if (DEBUG_ORIENTATION) {
- Slog.v(TAG, "Orientation change skips hidden " + w);
- }
- w.mOrientationChanging = false;
- }
- return;
- }
-
- boolean displayed = false;
-
- computeShownFrameLocked();
-
- setSurfaceBoundariesLocked(recoveringMemory);
-
- if (mIsWallpaper && !mWin.mWallpaperVisible) {
-
- hide();
- } else if (w.mAttachedHidden || !w.isOnScreen()) {
- hide();
- mService.hideWallpapersLocked(w);
-
-
-
-
-
-
-
- if (w.mOrientationChanging) {
- w.mOrientationChanging = false;
- if (DEBUG_ORIENTATION) Slog.v(TAG,
- "Orientation change skips hidden " + w);
- }
- } else if (mLastLayer != mAnimLayer
- || mLastAlpha != mShownAlpha
- || mLastDsDx != mDsDx
- || mLastDtDx != mDtDx
- || mLastDsDy != mDsDy
- || mLastDtDy != mDtDy
- || w.mLastHScale != w.mHScale
- || w.mLastVScale != w.mVScale
- || mLastHidden) {
- displayed = true;
- mLastAlpha = mShownAlpha;
- mLastLayer = mAnimLayer;
- mLastDsDx = mDsDx;
- mLastDtDx = mDtDx;
- mLastDsDy = mDsDy;
- mLastDtDy = mDtDy;
- w.mLastHScale = w.mHScale;
- w.mLastVScale = w.mVScale;
- if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "alpha=" + mShownAlpha + " layer=" + mAnimLayer
- + " matrix=[" + mDsDx + "*" + w.mHScale
- + "," + mDtDx + "*" + w.mVScale
- + "][" + mDsDy + "*" + w.mHScale
- + "," + mDtDy + "*" + w.mVScale + "]", null);
- if (mSurfaceControl != null) {
- try {
- mSurfaceAlpha = mShownAlpha;
- mSurfaceControl.setAlpha(mShownAlpha);
- mSurfaceLayer = mAnimLayer;
- mSurfaceControl.setLayer(mAnimLayer);
- mSurfaceControl.setMatrix(
- mDsDx * w.mHScale, mDtDx * w.mVScale,
- mDsDy * w.mHScale, mDtDy * w.mVScale);
-
- if (mLastHidden && mDrawState == HAS_DRAWN) {
- if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "SHOW (performLayout)", null);
- if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
- + " during relayout");
- if (showSurfaceRobustlyLocked()) {
- mLastHidden = false;
- if (mIsWallpaper) {
- mService.dispatchWallpaperVisibility(w, true);
- }
-
-
-
- mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
- } else {
- w.mOrientationChanging = false;
- }
- }
- if (mSurfaceControl != null) {
- w.mToken.hasVisible = true;
- }
- } catch (RuntimeException e) {
- Slog.w(TAG, "Error updating surface in " + w, e);
- if (!recoveringMemory) {
- mService.reclaimSomeSurfaceMemoryLocked(this, "update", true);
- }
- }
- }
- } else {
- if (DEBUG_ANIM && isAnimating()) {
- Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
- }
- displayed = true;
- }
-
- if (displayed) {
- if (w.mOrientationChanging) {
- if (!w.isDrawnLw()) {
- mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
- mAnimator.mLastWindowFreezeSource = w;
- if (DEBUG_ORIENTATION) Slog.v(TAG,
- "Orientation continue waiting for draw in " + w);
- } else {
- w.mOrientationChanging = false;
- if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
- }
- }
- w.mToken.hasVisible = true;
- }
- }
第13步、WindowStateAnimator.computeShownFrameLocked()
该函数
根据转屏动画、窗口动画、父窗口动画、Activity切换动画的
Transformation
计算出Matrix矩阵值,及
mShownFrame和
mShownAlpha值,当然这些计算只针对有surface的窗口。
- void computeShownFrameLocked() {
- final boolean selfTransformation = mHasLocalTransformation;
- Transformation attachedTransformation =
- (mAttachedWinAnimator != null && mAttachedWinAnimator.mHasLocalTransformation)
- ? mAttachedWinAnimator.mTransformation : null;
- Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
- ? mAppAnimator.transformation : null;
-
-
-
- final WindowState wallpaperTarget = mService.mWallpaperTarget;
- if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
- final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
- if (wallpaperAnimator.mHasLocalTransformation &&
- wallpaperAnimator.mAnimation != null &&
- !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
- attachedTransformation = wallpaperAnimator.mTransformation;
- if (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) {
- Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
- }
- }
- final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
- null : wallpaperTarget.mAppToken.mAppAnimator;
- if (wpAppAnimator != null && wpAppAnimator.hasTransformation
- && wpAppAnimator.animation != null
- && !wpAppAnimator.animation.getDetachWallpaper()) {
- appTransformation = wpAppAnimator.transformation;
- if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) {
- Slog.v(TAG, "WP target app xform: " + appTransformation);
- }
- }
- }
-
- final int displayId = mWin.getDisplayId();
- final ScreenRotationAnimation screenRotationAnimation =
- mAnimator.getScreenRotationAnimationLocked(displayId);
- final boolean screenAnimation =
- screenRotationAnimation != null && screenRotationAnimation.isAnimating();
- if (selfTransformation || attachedTransformation != null
- || appTransformation != null || screenAnimation) {
-
- final Rect frame = mWin.mFrame;
- final float tmpFloats[] = mService.mTmpFloats;
- final Matrix tmpMatrix = mWin.mTmpMatrix;
-
-
- if (screenAnimation && screenRotationAnimation.isRotating()) {
-
-
-
-
-
-
-
- final float w = frame.width();
- final float h = frame.height();
- if (w>=1 && h>=1) {
- tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);
- } else {
- tmpMatrix.reset();
- }
- } else {
- tmpMatrix.reset();
- }
- tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
- if (selfTransformation) {
- tmpMatrix.postConcat(mTransformation.getMatrix());
- }
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
- if (attachedTransformation != null) {
- tmpMatrix.postConcat(attachedTransformation.getMatrix());
- }
- if (appTransformation != null) {
- tmpMatrix.postConcat(appTransformation.getMatrix());
- }
- if (screenAnimation) {
- tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
- }
-
-
- if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
- MagnificationSpec spec = mService.mAccessibilityController
- .getMagnificationSpecForWindowLocked(mWin);
- if (spec != null && !spec.isNop()) {
- tmpMatrix.postScale(spec.scale, spec.scale);
- tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
- }
- }
-
-
-
-
-
-
-
- mHaveMatrix = true;
- tmpMatrix.getValues(tmpFloats);
- mDsDx = tmpFloats[Matrix.MSCALE_X];
- mDtDx = tmpFloats[Matrix.MSKEW_Y];
- mDsDy = tmpFloats[Matrix.MSKEW_X];
- mDtDy = tmpFloats[Matrix.MSCALE_Y];
- float x = tmpFloats[Matrix.MTRANS_X];
- float y = tmpFloats[Matrix.MTRANS_Y];
- int w = frame.width();
- int h = frame.height();
- mWin.mShownFrame.set(x, y, x+w, y+h);
-
-
-
-
-
-
- mShownAlpha = mAlpha;
- mHasClipRect = false;
- if (!mService.mLimitedAlphaCompositing
- || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
- || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
- && x == frame.left && y == frame.top))) {
-
- if (selfTransformation) {
- mShownAlpha *= mTransformation.getAlpha();
- }
- if (attachedTransformation != null) {
- mShownAlpha *= attachedTransformation.getAlpha();
- }
- if (appTransformation != null) {
- mShownAlpha *= appTransformation.getAlpha();
- if (appTransformation.hasClipRect()) {
- mClipRect.set(appTransformation.getClipRect());
- if (mWin.mHScale > 0) {
- mClipRect.left /= mWin.mHScale;
- mClipRect.right /= mWin.mHScale;
- }
- if (mWin.mVScale > 0) {
- mClipRect.top /= mWin.mVScale;
- mClipRect.bottom /= mWin.mVScale;
- }
- mHasClipRect = true;
- }
- }
- if (screenAnimation) {
- mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
- }
- } else {
-
- }
-
- if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)
- && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
- TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
- + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
- + " attached=" + (attachedTransformation == null ?
- "null" : attachedTransformation.getAlpha())
- + " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
- + " screen=" + (screenAnimation ?
- screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
- return;
- } else if (mIsWallpaper && mService.mInnerFields.mWallpaperActionPending) {
- return;
- }
-
- if (WindowManagerService.localLOGV) Slog.v(
- TAG, "computeShownFrameLocked: " + this +
- " not attached, mAlpha=" + mAlpha);
-
- MagnificationSpec spec = null;
-
- if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
- spec = mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);
- }
- if (spec != null) {
- final Rect frame = mWin.mFrame;
- final float tmpFloats[] = mService.mTmpFloats;
- final Matrix tmpMatrix = mWin.mTmpMatrix;
-
- tmpMatrix.setScale(mWin.mGlobalScale, mWin.mGlobalScale);
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
-
- if (spec != null && !spec.isNop()) {
- tmpMatrix.postScale(spec.scale, spec.scale);
- tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
- }
-
- tmpMatrix.getValues(tmpFloats);
-
- mHaveMatrix = true;
- mDsDx = tmpFloats[Matrix.MSCALE_X];
- mDtDx = tmpFloats[Matrix.MSKEW_Y];
- mDsDy = tmpFloats[Matrix.MSKEW_X];
- mDtDy = tmpFloats[Matrix.MSCALE_Y];
- float x = tmpFloats[Matrix.MTRANS_X];
- float y = tmpFloats[Matrix.MTRANS_Y];
- int w = frame.width();
- int h = frame.height();
- mWin.mShownFrame.set(x, y, x + w, y + h);
-
- mShownAlpha = mAlpha;
- } else {
- mWin.mShownFrame.set(mWin.mFrame);
- if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
- mWin.mShownFrame.offset(mWin.mXOffset, mWin.mYOffset);
- }
- mShownAlpha = mAlpha;
- mHaveMatrix = false;
- mDsDx = mWin.mGlobalScale;
- mDtDx = 0;
- mDsDy = 0;
- mDtDy = mWin.mGlobalScale;
- }
- }
第14步、WindowStateAnimator.setSurfaceBoundariesLocked()
这个函数更新Surface的起始位置、大小、偏
移缩放矩阵、
clipRect区域。
- void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
- final WindowState w = mWin;
-
- int width;
- int height;
- if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
-
-
- width = w.mRequestedWidth;
- height = w.mRequestedHeight;
- } else {
- width = w.mCompatFrame.width();
- height = w.mCompatFrame.height();
- }
-
-
-
- if (width < 1) {
- width = 1;
- }
- if (height < 1) {
- height = 1;
- }
-
- float left = w.mShownFrame.left;
- float top = w.mShownFrame.top;
-
-
- final LayoutParams attrs = w.getAttrs();
- final int displayId = w.getDisplayId();
- float scale = 1.0f;
-
- if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
- MagnificationSpec spec =
- mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w);
- if (spec != null && !spec.isNop()) {
- scale = spec.scale;
- }
- }
-
- width += scale * (attrs.surfaceInsets.left + attrs.surfaceInsets.right);
- height += scale * (attrs.surfaceInsets.top + attrs.surfaceInsets.bottom);
- left -= scale * attrs.surfaceInsets.left;
- top -= scale * attrs.surfaceInsets.top;
-
- final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
- if (surfaceMoved) {
- mSurfaceX = left;
- mSurfaceY = top;
-
- try {
- if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "POS " + left + ", " + top, null);
- mSurfaceControl.setPosition(left, top);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Error positioning surface of " + w
- + " pos=(" + left + "," + top + ")", e);
- if (!recoveringMemory) {
- mService.reclaimSomeSurfaceMemoryLocked(this, "position", true);
- }
- }
- }
-
- final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height;
- if (surfaceResized) {
- mSurfaceW = width;
- mSurfaceH = height;
- mSurfaceResized = true;
-
- try {
- if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "SIZE " + width + "x" + height, null);
- mSurfaceControl.setSize(width, height);
- mSurfaceControl.setMatrix(
- mDsDx * w.mHScale, mDtDx * w.mVScale,
- mDsDy * w.mHScale, mDtDy * w.mVScale);
- mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
- if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
- final TaskStack stack = w.getStack();
- if (stack != null) {
- stack.startDimmingIfNeeded(this);
- }
- }
- } catch (RuntimeException e) {
-
-
-
- Slog.e(TAG, "Error resizing surface of " + w
- + " size=(" + width + "x" + height + ")", e);
- if (!recoveringMemory) {
- mService.reclaimSomeSurfaceMemoryLocked(this, "size", true);
- }
- }
- }
-
- updateSurfaceWindowCrop(recoveringMemory);
- }
第15、16步、SurfaceControl.setXXX()/showSurfaceRobustlyLocked()
这两步已经在上面的prepareSurfaceLocked()函数中分析过了,对showSurfaceRobustlyLocked()函数多说一句,该函数只有从不可见要变为可见状态时才会被调用,函数里面调用SurfaceControl.show()来通知SurfaceFlinger该窗口可以显示出来。
总结:
上面主要对每一步的函数调用进行了分析,动画每一帧计算就是由这些函数组成。希望读者要明白每个函数是干什么的,理解动画计算大概流程,待出问题时走一遍流程,找到问题点。动画每一帧计算主要可以概括成三步:第一步,将Animation根据时间值求出Transformation。第二步、根据计算出的Transformation值计算窗口Surface各个属性值。第三步、将Surface属性值设置到SurfaceFlinger中。
第四部分:通过日志快速分析动画资源来自哪里
分析步骤:
①首先打开WMS中所有日志开关,对于MTK平台,使用“
adb shell dumpsys window -d enable a”便可打开WMS的日志开关。
②抓取日志,在日志中搜索“Setting animation in”关键字,定位到目标窗口日志行,再向上翻日志查到最近的“applyAnimation:”、“Loading animations: picked package=”和“Loading animations:”关键字;
③“Loading animations:”关键字
如果关键字是“Loading animations: layout params pkg=”,
那么resId取自某个窗口的WindowManager.LayoutParams.windowAnimations值(
可通过“adb shell dumpsys window w”打印窗口的属性查看究竟是哪个窗口的LayoutParams.windowAnimations值)。如果((resId&0xFF000000) == 0x01000000)为true,那么资源取自系统自带,否则取自应用程序。
如果关键字是"Loading animations: package=" ,那么该资源resId是应用程序调用overrideInPlaceAppTransition()或overridePendingAppTransition()接口传进来的,该resId自然取自应用程序。
③“Loading animations: picked package=”关键字
关键字后面接的就是这个动画资源来自哪里。如果"package = android"那这个可能是不准的,需要自己用((resId&0xFF000000) == 0x01000000)公式来算比较靠谱;如果package = 应用包名,那么资源就取自应用程序。
④“applyAnimation:”关键字
关键字可以判断出这个动画是什么类型的:如果后面接的是“win=”,那么就是窗口动画;如果后面接的是" anim=",那么就是Activity切换动画,对于Activity切换动画,这条日志可以推出更多的信息,比如transit值等;
下面是三份日志,第一份是设置Activity切换动画,第二份是设置PopupWindow窗口动画,第三份是设置Activity切换动画。读者可尝试根据上面所说的自行分析动画资源究竟取自哪里。
- 10-16 08:40:27.149 825 917 V AppTransition: Loading animations: package=com.meizu.flyme.launcher resId=0xa040040
- 10-16 08:40:27.149 825 917 V AppTransition: Loading animations: picked package=com.meizu.flyme.launcher
- 10-16 08:40:27.149 825 917 I AppTransition: id = a040040 overlayId = 0
- 10-16 08:40:27.151 825 917 V AppTransition: applyAnimation: anim=android.view.animation.AnimationSet@11689517 nextAppTransition=ANIM_CUSTOM transit=12 isEntrance=true Callers=com.android.server.wm.WindowManagerService.applyAnimationLocked:3878 com.android.server.wm.WindowManagerService.setTokenVisibilityLocked:4991 com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked:10053
- 10-16 08:40:27.151 825 917 V WindowManager: Loaded animation android.view.animation.AnimationSet@11689517 for AppWindowToken{1281e4b token=Token{234d731a ActivityRecord{1c78edc5 u0 com.android.mms/.ui.ConversationList t106}}}
- 10-16 08:40:27.151 825 917 V WindowManager: java.lang.RuntimeException
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:3886)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.setTokenVisibilityLocked(WindowManagerService.java:4991)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked(WindowManagerService.java:10053)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:10788)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:9601)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:9543)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.access$700(WindowManagerService.java:182)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:8457)
- 10-16 08:40:27.151 825 917 V WindowManager: at android.os.Handler.dispatchMessage(Handler.java:111)
- 10-16 08:40:27.151 825 917 V WindowManager: at android.os.Looper.loop(Looper.java:192)
- 10-16 08:40:27.151 825 917 V WindowManager: at android.os.HandlerThread.run(HandlerThread.java:61)
- 10-16 08:40:27.151 825 917 V WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:46)
- 10-16 08:40:27.151 825 917 V AppWindowAnimator: Setting animation in AppWindowToken{1281e4b token=Token{234d731a ActivityRecord{1c78edc5 u0 com.android.mms/.ui.ConversationList t106}}}: android.view.animation.AnimationSet@11689517 wxh=1080x1920 isVisible=true
- 10-16 08:40:27.151 825 917 V AppWindowAnimator: Updating layer Window{1e5b3c6c u0 Starting com.android.mms}: 22015
上面这份日志表明动画资源取自com.meizu.flyme.launcher。
- 10-16 16:48:12.874 825 1863 V AppTransition: Loading animations: layout params pkg=com.android.mms resId=0x7f0e0087
- 10-16 16:48:12.874 825 1863 V AppTransition: Loading animations: picked package=com.android.mms
- 10-16 16:48:12.874 825 1863 I AppTransition: id = 7f050018 overlayId = 0
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: applyAnimation: win=WindowStateAnimator{8c23690 PopupWindow:2d5ab621} anim=0 attr=0x1 a=android.view.animation.AnimationSet@8928a66 transit=2 isEntrance=false Callers com.android.server.wm.WindowManagerService.removeWindowLocked:3022 com.android.server.wm.WindowManagerService.removeWindow:2977 com.android.server.wm.Session.remove:193
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: Loaded animation android.view.animation.AnimationSet@8928a66 for WindowStateAnimator{8c23690 PopupWindow:2d5ab621}
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: java.lang.RuntimeException
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:1947)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at com.android.server.wm.WindowManagerService.removeWindowLocked(WindowManagerService.java:3022)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2977)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at com.android.server.wm.Session.remove(Session.java:193)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:233)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at com.android.server.wm.Session.onTransact(Session.java:136)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: at android.os.Binder.execTransact(Binder.java:451)
- 10-16 16:48:12.875 825 1863 V WindowStateAnimator: Setting animation in WindowStateAnimator{8c23690 PopupWindow:2d5ab621}: android.view.animation.AnimationSet@8928a66
上面这份日志表明动画资源取自com.android.mms。
- 10-16 16:58:18.414 825 917 V AppTransition: Loading animations: layout params pkg=android resId=0xa1000d4
- 10-16 16:58:18.414 825 917 V AppTransition: Loading animations: picked package=android
- 10-16 16:58:18.414 825 917 I AppTransition: id = a04002d overlayId = 0
- 10-16 16:58:18.415 825 917 V AppTransition: applyAnimation: anim=android.view.animation.AnimationSet@185fc32b animAttr=0x4 transit=6 isEntrance=true Callers=com.android.server.wm.WindowManagerService.applyAnimationLocked:3878 com.android.server.wm.WindowManagerService.setTokenVisibilityLocked:4991 com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked:10053
- 10-16 16:58:18.416 825 917 V WindowManager: Loaded animation android.view.animation.AnimationSet@185fc32b for AppWindowToken{3583ca17 token=Token{987e96 ActivityRecord{233b49b1 u0 android/com.android.internal.app.MzResolverActivity t109}}}
- 10-16 16:58:18.416 825 917 V WindowManager: java.lang.RuntimeException
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:3886)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.setTokenVisibilityLocked(WindowManagerService.java:4991)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked(WindowManagerService.java:10053)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:10788)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:9601)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:9543)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService.access$700(WindowManagerService.java:182)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:8457)
- 10-16 16:58:18.416 825 917 V WindowManager: at android.os.Handler.dispatchMessage(Handler.java:111)
- 10-16 16:58:18.416 825 917 V WindowManager: at android.os.Looper.loop(Looper.java:192)
- 10-16 16:58:18.416 825 917 V WindowManager: at android.os.HandlerThread.run(HandlerThread.java:61)
- 10-16 16:58:18.416 825 917 V WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:46)
- 10-16 16:58:18.416 825 917 V AppWindowAnimator: Setting animation in AppWindowToken{3583ca17 token=Token{987e96 ActivityRecord{233b49b1 u0 android/com.android.internal.app.MzResolverActivity t109}}}: android.view.animation.AnimationSet@185fc32b wxh=1080x1920 isVisible=true
上面这份日志表明动画资源取自android/com.android.internal.app.MzResolverActivity窗口,说明MzResolverActivity这个Activity肯定是内部重新设了窗口的Activity切换动画资源,检查源码果然发现在onCreate()函数内部使用setTheme(com.flyme.internal.R.style.Theme_Flyme_Resolver)重置了Activity切换动画。
最后总结一下:
Activity切换动画可能来源包括系统默认、调用startActivity()或
overridePendingAppTransition()指定、应用Activity内部重置窗口LayoutParams.windowAnimations值(可通过setTheme()来重置),这三者取其一,互斥关系;窗口动画来源包括:系统默认、窗口指定的LayoutParams.windowAnimations。
原文地址
http://blog.csdn.net/guoqifa29/article/details/49273065