WindowManagerService动画分析

  我们知道Android动画主要包括Activity切换动画、窗口动画、转屏动画、窗口内部View动画,前三者在WindowManagerService(简称WMS)中完成,本篇文章重点分析Activity切换动画、窗口动画的设置,动画每一帧计算,及如何快速分析动画类型资源。阅读本文最好有一定的WindowManagerService基础,本文所有代码基于AndroidM。

    典型的Activity切换动画包括:activityOpenEnterAnimation,activityOpenExitAnimation,taskOpenEnterAnimation, taskCloseExitAnimation, wallpaperOpenEnterAnimation, wallpaperCloseEnterAnimation典型的窗口动画包括:windowEnterAnimation,windowExitAnimation。

    我们知道每一个Activity在WMS中对应有一个APPWindowToken,APPWindowToken内部有一个AppWindowAnimator类型对象,Activity切换动画逻辑便是在AppTransition、AppWindowAnimator中完成。每个Activity一般情况下都有一个窗口,窗口是用WindowState来描述的,每个窗口有一个WindowStateAnimator类型对象,这个对象管理着窗口Surface和窗口动画。有了这些基本信息,下面就来分析Activity切换和窗口动画。

    文章会分为四个部分,分别为:Activity切换动画设 置,窗口动画设置,动画每一帧计算, 通过日志快速分析动画资源来自哪里。

第一部分:Activity切换动画设置

    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步中分析。
  1. public void setAppVisibility(IBinder token, boolean visible) {  
  2.     ......  
  3.     synchronized(mWindowMap) {  
  4.         wtoken = findAppWindowToken(token);  
  5.         ......  
  6.         // If we are preparing an app transition, then delay changing  
  7.         // the visibility of this token until we execute that transition.  
  8.         if (okToDisplay() && mAppTransition.isTransitionSet()) {  
  9.             ......  
  10.             wtoken.inPendingTransaction = true;  
  11.             if (visible) {  
  12.                 mOpeningApps.add(wtoken);          //将可见Activity加到mOpeningApps中;  
  13.                 wtoken.startingMoved = false;  
  14.                 wtoken.mEnteringAnimation = true;  
  15.   
  16.                 // If the token is currently hidden (should be the  
  17.                 // common case), then we need to set up to wait for  
  18.                 // its windows to be ready.  
  19.                 if (wtoken.hidden) {  
  20.                     wtoken.allDrawn = false;  
  21.                     wtoken.deferClearAllDrawn = false;  
  22.                     wtoken.waitingToShow = true;  
  23.   
  24.                     if (wtoken.clientHidden) {  
  25.                         // In the case where we are making an app visible  
  26.                         // but holding off for a transition, we still need  
  27.                         // to tell the client to make its windows visible so  
  28.                         // they get drawn.  Otherwise, we will wait on  
  29.                         // performing the transition until all windows have  
  30.                         // been drawn, they never will be, and we are sad.  
  31.                         wtoken.clientHidden = false;  
  32.                         wtoken.sendAppVisibilityToClients();        //这个调用就是通知应用窗口可见性变化;  
  33.                     }  
  34.                 }  
  35.             } else {  
  36.                 mClosingApps.add(wtoken);              //不可见Activity加到mClosingApps中;  
  37.                 wtoken.mEnteringAnimation = false;  
  38.             }  
  39.             ......  
  40.             return;  
  41.         }  
  42.         ......  
  43.         setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET,true, wtoken.voiceInteraction);  
  44.     }  
  45. }  

第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。
  1. boolean commitFinishDrawingLocked() {  
  2.     if (DEBUG_STARTING_WINDOW &&  
  3.             mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {  
  4.         Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="  
  5.                 + drawStateToString());  
  6.     }  
  7.     if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {  
  8.         return false;  
  9.     }  
  10.     if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {  
  11.         Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceControl);  
  12.     }  
  13.     mDrawState = READY_TO_SHOW;           //将窗口状态为COMMIT_DRAW_PENDING或READY_TO_SHOW更新到READY_TO_SHOW;  
  14.     final AppWindowToken atoken = mWin.mAppToken;  
  15.     if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {  
  16.         return performShowLocked();         //对于Activity切换这种场景,此时该条件无法满足,故不会调用。  
  17.     }  
  18.     return false;  
  19. }  

  1. if (w != atoken.startingWindow) {  
  2.     if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {  
  3.         atoken.numInterestingWindows++;      //计算属于该AppWindowToken的窗口总数;  
  4.         if (w.isDrawnLw()) {  
  5.             atoken.numDrawnWindows++;        //计算已经绘制完成的窗口总数;  
  6.             if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,  
  7.                     "tokenMayBeDrawn: " + atoken  
  8.                     + " freezingScreen=" + atoken.mAppAnimator.freezingScreen  
  9.                     + " mAppFreezing=" + w.mAppFreezing);  
  10.             updateAllDrawn = true;  
  11.         }  
  12.     }  

第9步、WMS.updateAllDrawnLocked()
    该函数更新AppWindowToken.allDrawn值。只有属于该AppWindowToken的所有窗口都是绘制完成状态(一般情况下只有一个窗口,有时候会有父窗口、子窗口,这时属于该AppWindowToken的窗口数量就不止一个了),AppWindowToken.allDrawn才会置为true。AppWindowToken.allDrawn为true才会使得第十步中的WMS.handleAppTransitionReadyLocked()完整的执行。
  1. private void updateAllDrawnLocked(DisplayContent displayContent) {  
  2.     // See if any windows have been drawn, so they (and others  
  3.     // associated with them) can now be shown.  
  4.     ArrayList<TaskStack> stacks = displayContent.getStacks();  
  5.     for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {  
  6.         final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();  
  7.         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {  
  8.             final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;  
  9.             for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {  
  10.                 final AppWindowToken wtoken = tokens.get(tokenNdx);  
  11.                 if (!wtoken.allDrawn) {  
  12.                     int numInteresting = wtoken.numInterestingWindows;  
  13.                     if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {    //绘制完成窗口总数>=窗口总数,就代表属于该AppWindowToken的所有窗口均已绘制完成;  
  14.                         if (DEBUG_VISIBILITY) Slog.v(TAG,  
  15.                                 "allDrawn: " + wtoken  
  16.                                 + " interesting=" + numInteresting  
  17.                                 + " drawn=" + wtoken.numDrawnWindows);  
  18.                         wtoken.allDrawn = true;                         //将allDrawn置为true;  
  19.                         // Force an additional layout pass where WindowStateAnimator#  
  20.                         // commitFinishDrawingLocked() will call performShowLocked().  
  21.                         displayContent.layoutNeeded = true;  
  22.                         mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();  
  23.                     }  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28. }  

第10步、WMS.handleAppTransitionReadyLocked()
    设置Activity切换动画选择逻辑就是在该函数中完成。该函数只有在调用了第一步后才会被调用,并且只有在wtoken.allDrawn=true时才会完整的执行完。这个函数接近300行,逻辑看起来非常复杂,下面将仔细分析这个函数。
  1. public int handleAppTransitionReadyLocked(WindowList windows) {  
  2.     int changes = 0;  
  3.     int i;  
  4.     int appsCount = mOpeningApps.size();  
  5.     boolean goodToGo = true;  
  6.     if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  7.             "Checking " + appsCount + " opening apps (frozen="  
  8.             + mDisplayFrozen + " timeout="  
  9.             + mAppTransition.isTimeout() + ")...");  
  10.     if (!mAppTransition.isTimeout()) {  
  11.         for (i = 0; i < appsCount && goodToGo; i++) {  
  12.             AppWindowToken wtoken = mOpeningApps.valueAt(i);  
  13.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  14.                     "Check opening app=" + wtoken + ": allDrawn="  
  15.                     + wtoken.allDrawn + " startingDisplayed="  
  16.                     + wtoken.startingDisplayed + " startingMoved="  
  17.                     + wtoken.startingMoved);  
  18.             if (!wtoken.allDrawn && !wtoken.startingDisplayed  
  19.                     && !wtoken.startingMoved) {         //wtoken.allDrawn=true,goodToGo才不会被置为false,下面的逻辑才能继续执行;  
  20.                 goodToGo = false;  
  21.             }  
  22.         }  
  23.   
  24.         if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {   //如果壁纸需要可见,但是壁纸此时是不可见状态,那么就需要等待壁纸绘制完成。。。才能继续执行下面的Activity切换动画选择逻辑;  
  25.             boolean wallpaperGoodToGo = true;  
  26.             for (int curTokenIndex = mWallpaperTokens.size() - 1;  
  27.                     curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {  
  28.                 WindowToken token = mWallpaperTokens.get(curTokenIndex);  
  29.                 for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;  
  30.                         curWallpaperIndex--) {  
  31.                     WindowState wallpaper = token.windows.get(curWallpaperIndex);  
  32.                     if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {  
  33.                         // We've told this wallpaper to be visible, but it is not drawn yet  
  34.                         wallpaperGoodToGo = false;  
  35.                         if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {  
  36.                             // wait for this wallpaper until it is drawn or timeout  
  37.                             goodToGo = false;  
  38.                         }  
  39.                         if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {  
  40.                             mWallpaperDrawState = WALLPAPER_DRAW_PENDING;  
  41.                             mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);  
  42.                             mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,  
  43.                                     WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);  
  44.                         }  
  45.                         if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,  
  46.                                 "Wallpaper should be visible but has not been drawn yet. " +  
  47.                                 "mWallpaperDrawState=" + mWallpaperDrawState);  
  48.                         break;  
  49.                     }  
  50.                 }  
  51.             }  
  52.             if (wallpaperGoodToGo) {  
  53.                 mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;  
  54.                 mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);  
  55.             }  
  56.         }  
  57.     }  
  58.     if (goodToGo) {  
  59.         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");  
  60.         int transit = mAppTransition.getAppTransition();        //取出第一步中设置的Activity切换动画类型;  
  61.         if (mSkipAppTransitionAnimation) {                      //如果设置了StartingWindow窗口,那么就忽略第一步中设置的Activity切换动画类型;  
  62.             transit = AppTransition.TRANSIT_UNSET;  
  63.         }  
  64.         mSkipAppTransitionAnimation = false;  
  65.         mNoAnimationNotifyOnTransitionFinished.clear();  
  66.   
  67.         mH.removeMessages(H.APP_TRANSITION_TIMEOUT);           //移除超时;  
  68.   
  69.         rebuildAppWindowListLocked();                          //窗口堆栈顺序重排,偶现Activity窗口显示在launcher图标之下就可能就是窗口堆栈顺序没有重排导致,Android4.4就有该问题。  
  70.         // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper  
  71.         WindowState oldWallpaper =  
  72.                 mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()  
  73.                     && !mWallpaperTarget.mWinAnimator.isDummyAnimation()  
  74.                 ? null : mWallpaperTarget;                   //oldWallpaper指向null或mWallpaperTarget  
  75.   
  76.         mInnerFields.mWallpaperMayChange = false;  
  77.   
  78.         // The top-most window will supply the layout params,  
  79.         // and we will determine it below.  
  80.         LayoutParams animLp = null;  
  81.         int bestAnimLayer = -1;  
  82.         boolean fullscreenAnim = false;  
  83.         boolean voiceInteraction = false;  
  84.   
  85.         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  86.                 "New wallpaper target=" + mWallpaperTarget  
  87.                 + ", oldWallpaper=" + oldWallpaper  
  88.                 + ", lower target=" + mLowerWallpaperTarget  
  89.                 + ", upper target=" + mUpperWallpaperTarget);  
  90.   
  91.         boolean openingAppHasWallpaper = false;  
  92.         boolean closingAppHasWallpaper = false;  
  93.         final AppWindowToken lowerWallpaperAppToken;  
  94.         final AppWindowToken upperWallpaperAppToken;  
  95.         if (mLowerWallpaperTarget == null) {  
  96.             lowerWallpaperAppToken = upperWallpaperAppToken = null;  
  97.         } else {  
  98.             lowerWallpaperAppToken = mLowerWallpaperTarget.mAppToken;  
  99.             upperWallpaperAppToken = mUpperWallpaperTarget.mAppToken;  
  100.         }  
  101.   
  102.         // Do a first pass through the tokens for two         
  103.         // things:  
  104.         // (1) Determine if both the closing and opening  
  105.         // app token sets are wallpaper targets, in which  
  106.         // case special animations are needed  
  107.         // (since the wallpaper needs to stay static  
  108.         // behind them).  
  109.         // (2) Find the layout params of the top-most  
  110.         // application window in the tokens, which is  
  111.         // what will control the animation theme.  
  112.         final int closingAppsCount = mClosingApps.size();  
  113.         appsCount = closingAppsCount + mOpeningApps.size();  
  114.         for (i = 0; i < appsCount; i++) {         //这个for循环主要干两件事情,第一事判断closing and opening APP token是否是壁纸目标窗口;第二件事是找到最顶部(全屏窗口)的Activity窗口,取得窗口属性mAttrs的值,其实这个地方有四种情况:全屏Activity-->全屏Activity、全屏Activity-->非全屏Activity、非全屏Activity-->全屏Activity、非全屏Activity-->非全屏Activity,这四种情况使得animLp值会有所差异;  
  115.             final AppWindowToken wtoken;  
  116.             if (i < closingAppsCount) {  
  117.                 wtoken = mClosingApps.valueAt(i);  
  118.                 if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {  
  119.                     closingAppHasWallpaper = true;  
  120.                 }  
  121.             } else {  
  122.                 wtoken = mOpeningApps.valueAt(i - closingAppsCount);  
  123.                 if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {  
  124.                     openingAppHasWallpaper = true;  
  125.                 }  
  126.             }  
  127.   
  128.             voiceInteraction |= wtoken.voiceInteraction;  
  129.   
  130.             if (wtoken.appFullscreen) {  
  131.                 WindowState ws = wtoken.findMainWindow();  
  132.                 if (ws != null) {  
  133.                     animLp = ws.mAttrs;  
  134.                     bestAnimLayer = ws.mLayer;  
  135.                     fullscreenAnim = true;  
  136.                 }  
  137.             } else if (!fullscreenAnim) {  
  138.                 WindowState ws = wtoken.findMainWindow();  
  139.                 if (ws != null) {  
  140.                     if (ws.mLayer > bestAnimLayer) {  
  141.                         animLp = ws.mAttrs;  
  142.                         bestAnimLayer = ws.mLayer;  
  143.                     }  
  144.                 }  
  145.             }  
  146.         }  
  147.   
  148.         mAnimateWallpaperWithTarget = false;  
  149.         if (closingAppHasWallpaper && openingAppHasWallpaper) {      //下面这段逻辑都是根据壁纸目标窗口的各种情况重新设置指定的transit值;  
  150.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");  
  151.             switch (transit) {  
  152.                 case AppTransition.TRANSIT_ACTIVITY_OPEN:  
  153.                 case AppTransition.TRANSIT_TASK_OPEN:  
  154.                 case AppTransition.TRANSIT_TASK_TO_FRONT:  
  155.                     transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;  
  156.                     break;  
  157.                 case AppTransition.TRANSIT_ACTIVITY_CLOSE:  
  158.                 case AppTransition.TRANSIT_TASK_CLOSE:  
  159.                 case AppTransition.TRANSIT_TASK_TO_BACK:  
  160.                     transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;  
  161.                     break;  
  162.             }  
  163.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  164.                     "New transit: " + AppTransition.appTransitionToString(transit));  
  165.         } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()  
  166.                 && !mOpeningApps.contains(oldWallpaper.mAppToken)) {  
  167.             // We are transitioning from an activity with  
  168.             // a wallpaper to one without.  
  169.             transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;  
  170.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  171.                     "New transit away from wallpaper: "  
  172.                     + AppTransition.appTransitionToString(transit));  
  173.         } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {  
  174.             // We are transitioning from an activity without  
  175.             // a wallpaper to now showing the wallpaper  
  176.             transit = AppTransition.TRANSIT_WALLPAPER_OPEN;  
  177.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  178.                     "New transit into wallpaper: "  
  179.                     + AppTransition.appTransitionToString(transit));  
  180.         } else {  
  181.             mAnimateWallpaperWithTarget = true;  
  182.         }  
  183.   
  184.         // If all closing windows are obscured, then there is  
  185.         // no need to do an animation.  This is the case, for  
  186.         // example, when this transition is being done behind  
  187.         // the lock screen.  
  188.         if (!mPolicy.allowAppAnimationsLw()) {  
  189.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,  
  190.                     "Animations disallowed by keyguard or dream.");  
  191.             animLp = null;  
  192.         }  
  193.   
  194.         AppWindowToken topOpeningApp = null;  
  195.         AppWindowToken topClosingApp = null;  
  196.         int topOpeningLayer = 0;  
  197.         int topClosingLayer = 0;  
  198.   
  199.         // Process all applications animating in place  
  200.         if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {       //如果transit == AppTransition.TRANSIT_TASK_IN_PLACE,这段逻辑不知道是干啥的。。。  
  201.             // Find the focused window  
  202.             final WindowState win =  
  203.                     findFocusedWindowLocked(getDefaultDisplayContentLocked());  
  204.             if (win != null) {  
  205.                 final AppWindowToken wtoken = win.mAppToken;  
  206.                 final AppWindowAnimator appAnimator = wtoken.mAppAnimator;  
  207.                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);  
  208.                 appAnimator.clearThumbnail();  
  209.                 appAnimator.animation = null;  
  210.                 updateTokenInPlaceLocked(wtoken, transit);  
  211.                 wtoken.updateReportedVisibilityLocked();  
  212.   
  213.                 appAnimator.mAllAppWinAnimators.clear();  
  214.                 final int N = wtoken.allAppWindows.size();  
  215.                 for (int j = 0; j < N; j++) {  
  216.                     appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);  
  217.                 }  
  218.                 mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();  
  219.                 mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();  
  220.             }  
  221.         }  
  222.   
  223.         appsCount = mOpeningApps.size();  
  224.         for (i = 0; i < appsCount; i++) {           //这个for循环主要干两件事:①调用setTokenVisibilityLocked()设置Activity切换动画;②寻找topOpeningApp值;  
  225.   
  226.             AppWindowToken wtoken = mOpeningApps.valueAt(i);  
  227.             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;  
  228.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);  
  229.   
  230.             if (!appAnimator.usingTransferredAnimation) {  
  231.                 appAnimator.clearThumbnail();  
  232.                 appAnimator.animation = null;  
  233.             }  
  234.             wtoken.inPendingTransaction = false;  
  235.             if (!setTokenVisibilityLocked(              //setTokenVisibilityLocked()函数主要依据第2,3,4,6个参数来决定加载哪个动画;  
  236.                     wtoken, animLp, true, transit, false, voiceInteraction)){  
  237.                 // This token isn't going to be animating. Add it to the list of tokens to  
  238.                 // be notified of app transition complete since the notification will not be  
  239.                 // sent be the app window animator.  
  240.                 mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);  
  241.             }  
  242.             wtoken.updateReportedVisibilityLocked();  
  243.             wtoken.waitingToShow = false;  
  244.   
  245.             appAnimator.mAllAppWinAnimators.clear();  
  246.             final int windowsCount = wtoken.allAppWindows.size();  
  247.             for (int j = 0; j < windowsCount; j++) {  
  248.                 appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);  
  249.             }  
  250.             mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();        //将Activity窗口状态从READY_TO_SHOW更新到HAS_DRAWN.该函数会调用WindowStateAnimator.performShowLocked().可能有细心的人发现了WindowStateAnimator.performShowLocked()函数会调用WindowStateAnimator.applyEnterAnimationLocked()设置窗口动画,但实际上是无法加载出Animation的,读者可将日志开关打开,然后在日志中搜索关键字“applyAnimation: win=”,查看Activity窗口的“a=”是否为null。对于非Activity窗口,WindowStateAnimator.applyEnterAnimationLocked()是可以为其加载出一个Animation的,当然得系统或窗口指定资源样式才行。现在可以总结出:对于Activity窗口是不可能在WindowStateAnimator.applyEnterAnimationLocked()成功设置一个窗口动画的,非Activity窗口才可以,比如PopupWindow、startingWindow、StatusBar、输入法窗口等。  
  251.             mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();  
  252.   
  253.             if (animLp != null) {  
  254.                 int layer = -1;  
  255.                 for (int j = 0; j < wtoken.windows.size(); j++) {  
  256.                     WindowState win = wtoken.windows.get(j);  
  257.                     if (win.mWinAnimator.mAnimLayer > layer) {  
  258.                         layer = win.mWinAnimator.mAnimLayer;  
  259.                     }  
  260.                 }  
  261.                 if (topOpeningApp == null || layer > topOpeningLayer) {  
  262.                     topOpeningApp = wtoken;  
  263.                     topOpeningLayer = layer;  
  264.                 }  
  265.             }  
  266.         }  
  267.         appsCount = mClosingApps.size();  
  268.         for (i = 0; i < appsCount; i++) {    //这个for循环主要干两件事:①调用setTokenVisibilityLocked()设置Activity切换动画;②寻找topClosingApp值;  
  269.             AppWindowToken wtoken = mClosingApps.valueAt(i);  
  270.             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;  
  271.             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);  
  272.             appAnimator.clearThumbnail();  
  273.             appAnimator.animation = null;  
  274.             wtoken.inPendingTransaction = false;  
  275.             setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);  
  276.             wtoken.updateReportedVisibilityLocked();  
  277.             // Force the allDrawn flag, because we want to start  
  278.             // this guy's animations regardless of whether it's  
  279.             // gotten drawn.  
  280.             wtoken.allDrawn = true;  
  281.             wtoken.deferClearAllDrawn = false;  
  282.             // Ensure that apps that are mid-starting are also scheduled to have their  
  283.             // starting windows removed after the animation is complete  
  284.             if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {  
  285.                 scheduleRemoveStartingWindowLocked(wtoken);  
  286.             }  
  287.             mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();  
  288.   
  289.             if (animLp != null) {  
  290.                 int layer = -1;  
  291.                 for (int j = 0; j < wtoken.windows.size(); j++) {  
  292.                     WindowState win = wtoken.windows.get(j);  
  293.                     if (win.mWinAnimator.mAnimLayer > layer) {  
  294.                         layer = win.mWinAnimator.mAnimLayer;  
  295.                     }  
  296.                 }  
  297.                 if (topClosingApp == null || layer > topClosingLayer) {  
  298.                     topClosingApp = wtoken;  
  299.                     topClosingLayer = layer;  
  300.                 }  
  301.             }  
  302.         }  
  303.   
  304.         AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null :  
  305.                 topOpeningApp.mAppAnimator;  
  306.         AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :  
  307.                 topClosingApp.mAppAnimator;  
  308.         Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();      //上层应用调用了WMS.overridePendingAppTransitionAspectScaledThumb()或WMS.overridePendingAppTransitionThumb()进行覆盖Activity切换动画,下面这段代码就是这个覆盖动画逻辑处理;  
  309.         if (nextAppTransitionThumbnail != null  
  310.                 && openingAppAnimator != null && openingAppAnimator.animation != null &&  
  311.                 nextAppTransitionThumbnail.getConfig() != Config.ALPHA_8) {  
  312.             // This thumbnail animation is very special, we need to have  
  313.             // an extra surface with the thumbnail included with the animation.  
  314.             Rect dirty = new Rect(00, nextAppTransitionThumbnail.getWidth(),  
  315.                     nextAppTransitionThumbnail.getHeight());  
  316.             try {  
  317.                 // TODO(multi-display): support other displays  
  318.                 final DisplayContent displayContent = getDefaultDisplayContentLocked();  
  319.                 final Display display = displayContent.getDisplay();  
  320.                 final DisplayInfo displayInfo = displayContent.getDisplayInfo();  
  321.   
  322.                 // Create a new surface for the thumbnail  
  323.                 SurfaceControl surfaceControl = new SurfaceControl(mFxSession,  
  324.                         "thumbnail anim", dirty.width(), dirty.height(),  
  325.                         PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);  
  326.                 surfaceControl.setLayerStack(display.getLayerStack());  
  327.                 if (SHOW_TRANSACTIONS) {  
  328.                     Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");  
  329.                 }  
  330.   
  331.                 // Draw the thumbnail onto the surface  
  332.                 Surface drawSurface = new Surface();  
  333.                 drawSurface.copyFrom(surfaceControl);  
  334.                 Canvas c = drawSurface.lockCanvas(dirty);  
  335.                 c.drawBitmap(nextAppTransitionThumbnail, 00null);  
  336.                 drawSurface.unlockCanvasAndPost(c);  
  337.                 drawSurface.release();  
  338.   
  339.                 // Get the thumbnail animation  
  340.                 Animation anim;  
  341.                 if (mAppTransition.isNextThumbnailTransitionAspectScaled()) {  
  342.                     // For the new aspect-scaled transition, we want it to always show  
  343.                     // above the animating opening/closing window, and we want to  
  344.                     // synchronize its thumbnail surface with the surface for the  
  345.                     // open/close animation (only on the way down)  
  346.                     anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(  
  347.                             displayInfo.appWidth, displayInfo.appHeight,  
  348.                             displayInfo.logicalWidth, transit);  
  349.                     openingAppAnimator.thumbnailForceAboveLayer = Math.max(topOpeningLayer,  
  350.                             topClosingLayer);  
  351.                     openingAppAnimator.deferThumbnailDestruction =  
  352.                             !mAppTransition.isNextThumbnailTransitionScaleUp();  
  353.                 } else {  
  354.                     anim = mAppTransition.createThumbnailScaleAnimationLocked(  
  355.                             displayInfo.appWidth, displayInfo.appHeight, transit);  
  356.                 }  
  357.                 anim.restrictDuration(MAX_ANIMATION_DURATION);  
  358.                 anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());  
  359.   
  360.                 openingAppAnimator.thumbnail = surfaceControl;  
  361.                 openingAppAnimator.thumbnailLayer = topOpeningLayer;  
  362.                 openingAppAnimator.thumbnailAnimation = anim;  
  363.                 openingAppAnimator.thumbnailX = mAppTransition.getStartingX();  
  364.                 openingAppAnimator.thumbnailY = mAppTransition.getStartingY();  
  365.             } catch (OutOfResourcesException e) {  
  366.                 Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()  
  367.                         + " h=" + dirty.height(), e);  
  368.                 openingAppAnimator.clearThumbnail();  
  369.             }  
  370.         }  
  371.   
  372.         mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);  
  373.         mAppTransition.postAnimationCallback();  
  374.         mAppTransition.clear();  
  375.   
  376.         mOpeningApps.clear();  
  377.         mClosingApps.clear();  
  378.   
  379.         // This has changed the visibility of windows, so perform  
  380.         // a new layout to get them all up-to-date.  
  381.         changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT  
  382.                 | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;  
  383.         getDefaultDisplayContentLocked().layoutNeeded = true;  
  384.   
  385.         // TODO(multidisplay): IMEs are only supported on the default display.  
  386.         if (windows == getDefaultWindowListLocked()  
  387.                 && !moveInputMethodWindowsIfNeededLocked(true)) {  
  388.             assignLayersLocked(windows);  
  389.         }  
  390.         updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);  
  391.         mFocusMayChange = false;  
  392.         notifyActivityDrawnForKeyguard();  
  393.     }  
  394.   
  395.     return changes;  
  396. }  
    上面这个函数很长,但是逻辑思路很简单,初看起来确实复杂,仔细分析发现还是比较容易理解的。总结起来就是:确定壁纸目标窗口对transit值的影响、取得顶层窗口的mAttr值、两次调用setTokenVisibilityLocked()来设置APPWindowToken可见性及加载对应的动画。

第11步、WMS.setTokenVisibilityLocked()
    这个函数用来设置APPWindowToken.hidden的可见性、设置Activity切换动画(如果参数transit==AppTransition.TRANSIT_UNSET,那就是会设置窗口动画,否则就会设置Activity切换动画),如果存在Activity切换动画或属于该Activity的窗口正在做窗口动画,那么返回值为true。
  1. boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,  
  2.         boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {  
  3.     boolean delayed = false;  
  4.   
  5.     if (wtoken.clientHidden == visible) {      //AppWindowToken.clientHidden保存着上层应用Activity窗口的可见性,通过AppWindowToken.sendAppVisibilityToClients()来通知上层应用窗口可见性。  
  6.         wtoken.clientHidden = !visible;  
  7.         wtoken.sendAppVisibilityToClients();  
  8.     }  
  9.   
  10.     wtoken.willBeHidden = false;  
  11.     // Allow for state changes and animation to be applied if token is transitioning  
  12.     // visibility state or the token was marked as hidden and is exiting before we had a chance  
  13.     // to play the transition animation.  
  14.     if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting)) {       //只有APPWindowToken.hidden的可见性切换时才进行重置其值及设置Activity切换动画或设置窗口动画;  
  15.         boolean changed = false;  
  16.         if (DEBUG_APP_TRANSITIONS) Slog.v(  
  17.             TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden  
  18.             + " performLayout=" + performLayout);  
  19.   
  20.         boolean runningAppAnimation = false;     //该变量用来确定是否设置了Activity切换动画,后面根据这个值来确定是否需要设置窗口动画;  
  21.   
  22.         if (transit != AppTransition.TRANSIT_UNSET) {    //如果transit != AppTransition.TRANSIT_UNSET表示指定了Activity切换动画,那么调用WMS.applyAnimationLocked()来加载Activity切换动画,同时把runningAppAnimation置为true,这样下面遍历窗口的时候便不会设置窗口动画;  
  23.             if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {  
  24.                 wtoken.mAppAnimator.animation = null;  
  25.             }  
  26.             if (applyAnimationLocked(wtoken, lp, transit, visible, isVoiceInteraction)) {    //加载Activity切换动画,第十二步中会分析这个函数;  
  27.                 delayed = runningAppAnimation = true;  
  28.             }  
  29.             WindowState window = wtoken.findMainWindow();  
  30.             //TODO (multidisplay): Magnification is supported only for the default display.  
  31.             if (window != null && mAccessibilityController != null  
  32.                     && window.getDisplayId() == Display.DEFAULT_DISPLAY) {  
  33.                 mAccessibilityController.onAppWindowTransitionLocked(window, transit);  
  34.             }  
  35.             changed = true;  
  36.         }  
  37.   
  38.         final int windowsCount = wtoken.allAppWindows.size();  
  39.         for (int i = 0; i < windowsCount; i++) {     //for循环遍历属于该APPWindowToken的所有窗口,一般情况下只有一个.  
  40.             WindowState win = wtoken.allAppWindows.get(i);  
  41.             if (win == wtoken.startingWindow) {      //过滤startingWindow;  
  42.                 continue;  
  43.             }  
  44.   
  45.             //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible());  
  46.             //win.dump("  ");  
  47.             if (visible) {            //如果该APPWindowToken要切换为可见,并且所属的窗口当前是不可见状态,并且没有设置Activity切换动画,才设置窗口进入动画;  
  48.                 if (!win.isVisibleNow()) {           
  49.                     if (!runningAppAnimation) {  
  50.                         win.mWinAnimator.applyAnimationLocked(  
  51.                                 WindowManagerPolicy.TRANSIT_ENTER, true);      //WindowStateAnimator.applyAnimationLocked()函数分析见第二部分;  
  52.                         //TODO (multidisplay): Magnification is supported only for the default  
  53.                         if (mAccessibilityController != null  
  54.                                 && win.getDisplayId() == Display.DEFAULT_DISPLAY) {  
  55.                             mAccessibilityController.onWindowTransitionLocked(win,  
  56.                                     WindowManagerPolicy.TRANSIT_ENTER);  
  57.                         }  
  58.                     }  
  59.                     changed = true;  
  60.                     final DisplayContent displayContent = win.getDisplayContent();  
  61.                     if (displayContent != null) {  
  62.                         displayContent.layoutNeeded = true;  
  63.                     }  
  64.                 }  
  65.             } else if (win.isVisibleNow()) {   //如果该APPWindowToken要切换为不可见,并且所属的窗口当前是可见状态,并且没有设置Activity切换动画,才设置窗口退出动画;  
  66.                 if (!runningAppAnimation) {  
  67.                     win.mWinAnimator.applyAnimationLocked(  
  68.                             WindowManagerPolicy.TRANSIT_EXIT, false);  
  69.                     //TODO (multidisplay): Magnification is supported only for the default  
  70.                     if (mAccessibilityController != null  
  71.                             && win.getDisplayId() == Display.DEFAULT_DISPLAY) {  
  72.                         mAccessibilityController.onWindowTransitionLocked(win,  
  73.                                 WindowManagerPolicy.TRANSIT_EXIT);  
  74.                     }  
  75.                 }  
  76.                 changed = true;  
  77.                 final DisplayContent displayContent = win.getDisplayContent();  
  78.                 if (displayContent != null) {  
  79.                     displayContent.layoutNeeded = true;  
  80.                 }  
  81.             }  
  82.         }  
  83.   
  84.         wtoken.hidden = wtoken.hiddenRequested = !visible;        //设置APPWindowToken.hidden值;  
  85.         if (!visible) {  
  86.             unsetAppFreezingScreenLocked(wtoken, truetrue);  
  87.         } else {  
  88.             // If we are being set visible, and the starting window is  
  89.             // not yet displayed, then make sure it doesn't get displayed.  
  90.             WindowState swin = wtoken.startingWindow;  
  91.             if (swin != null && !swin.isDrawnLw()) {      //如果该APPWindowToken设为可见时,此时如果startingWindow还没显示,那么就无需显示startingWindow了,即将mPolicyVisibility置为false;  
  92.                 swin.mPolicyVisibility = false;  
  93.                 swin.mPolicyVisibilityAfterAnim = false;  
  94.              }  
  95.         }  
  96.   
  97.         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken  
  98.                   + ": hidden=" + wtoken.hidden + " hiddenRequested="  
  99.                   + wtoken.hiddenRequested);  
  100.   
  101.         if (changed) {           //changed=true代表上面有窗口可见性更改,那么就要更新输入法窗口在堆栈中的位置了;  
  102.             mInputMonitor.setUpdateInputWindowsNeededLw();  
  103.             if (performLayout) {  
  104.                 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,  
  105.                         false /*updateInputWindows*/);  
  106.                 performLayoutAndPlaceSurfacesLocked();  
  107.             }  
  108.             mInputMonitor.updateInputWindowsLw(false /*force*/);      //将窗口堆栈信息更新到Input中去;  
  109.         }  
  110.     }  
  111.   
  112.     if (wtoken.mAppAnimator.animation != null) {  
  113.         delayed = true;  
  114.     }  
  115.   
  116.     for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {  
  117.         if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {  
  118.             delayed = true;  
  119.         }  
  120.     }  
  121.   
  122.     return delayed;  
  123. }  

第12步、WMS.applyAnimationLocked()
    该函数首先会根据AppWindowToken所属窗口是否是全屏窗口来确定containingFrame、contentInsets、appFrame三个值,然后调用AppTransition.loadAnimation()取得一个Activity切换动画Animation,最后将这个Animation通过AppTransition.setAnimation()接口设置到AppTransition中去。
  1. private boolean applyAnimationLocked(AppWindowToken atoken,  
  2.         WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) {  
  3.     // Only apply an animation if the display isn't frozen.  If it is  
  4.     // frozen, there is no reason to animate and it can cause strange  
  5.     // artifacts when we unfreeze the display if some different animation  
  6.     // is running.  
  7.     if (okToDisplay()) {  
  8.         DisplayInfo displayInfo = getDefaultDisplayInfoLocked();  
  9.         final int width = displayInfo.appWidth;  
  10.         final int height = displayInfo.appHeight;  
  11.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  12.                 "applyAnimation: atoken=" + atoken);  
  13.   
  14.         // Determine the visible rect to calculate the thumbnail clip  
  15.         WindowState win = atoken.findMainWindow();  
  16.         Rect containingFrame = new Rect(00, width, height);  
  17.         Rect contentInsets = new Rect();  
  18.         Rect appFrame = new Rect(00, width, height);  
  19.         if (win != null && win.isFullscreen(width, height)) {  //只有窗口大于等于屏幕时,才会使用窗口的mContainingFrame、mContentInsets、mFrame值,这三个值会作为AppTransition.loadAnimation()的参数;  
  20.             // For fullscreen windows use the window frames and insets to set the thumbnail  
  21.             // clip. For none-fullscreen windows we use the app display region so the clip  
  22.             // isn't affected by the window insets.  
  23.             containingFrame.set(win.mContainingFrame);  
  24.             contentInsets.set(win.mContentInsets);  
  25.             appFrame.set(win.mFrame);  
  26.         }  
  27.   
  28.         if (atoken.mLaunchTaskBehind) {  
  29.             // Differentiate the two animations. This one which is briefly on the screen  
  30.             // gets the !enter animation, and the other activity which remains on the  
  31.             // screen gets the enter animation. Both appear in the mOpeningApps set.  
  32.             enter = false;  
  33.         }  
  34.         Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,  
  35.                 mCurConfiguration.orientation, containingFrame, contentInsets, appFrame,  
  36.                 isVoiceInteraction);       //调用AppTransition.loadAnimation(),每个参数均会影响具体加载哪个动画,将在第十三步分析该函数;  
  37.         if (a != null) {  
  38.             if (DEBUG_ANIM) {  
  39.                 RuntimeException e = null;  
  40.                 if (!HIDE_STACK_CRAWLS) {  
  41.                     e = new RuntimeException();  
  42.                     e.fillInStackTrace();  
  43.                 }  
  44.                 Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);  
  45.             }  
  46.             atoken.mAppAnimator.setAnimation(a, width, height,      //将前面加载的Animation设置到AppTransition中去;  
  47.                     mAppTransition.canSkipFirstFrame());      
  48.         }  
  49.     } else {  
  50.         atoken.mAppAnimator.clearAnimation();  
  51.     }  
  52.   
  53.     return atoken.mAppAnimator.animation != null;          //如果成功设置Activity切换动画,那么该函数返回true;  
  54. }  


第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切换动画这个流程在文章第四部分会简单分析。
  1. Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,  
  2.         int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,  
  3.         Rect appFrame, boolean isVoiceInteraction) {  
  4.     Animation a;  
  5.     if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN  
  6.             || transit == TRANSIT_TASK_OPEN  
  7.             || transit == TRANSIT_TASK_TO_FRONT)) {                  //语音交互相关;  
  8.         a = loadAnimationRes(lp, enter  
  9.                 ? com.android.internal.R.anim.voice_activity_open_enter  
  10.                 : com.android.internal.R.anim.voice_activity_open_exit);  
  11.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  12.                 "applyAnimation voice:"  
  13.                 + " anim=" + a + " transit=" + appTransitionToString(transit)  
  14.                 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));  
  15.     } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE  
  16.             || transit == TRANSIT_TASK_CLOSE  
  17.             || transit == TRANSIT_TASK_TO_BACK)) {                      //语音交互相关;  
  18.         a = loadAnimationRes(lp, enter  
  19.                 ? com.android.internal.R.anim.voice_activity_close_enter  
  20.                 : com.android.internal.R.anim.voice_activity_close_exit);  
  21.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  22.                 "applyAnimation voice:"  
  23.                 + " anim=" + a + " transit=" + appTransitionToString(transit)  
  24.                 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));  
  25.     } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {          //调用过overridePendingAppTransition()接口设置动画。使用startActivity()携带ActivityOptions.ANIM_CUSTOM自定义Activity切换动画就是走这个逻辑的;  
  26.         a = loadAnimationRes(mNextAppTransitionPackage, enter ?  
  27.                 mNextAppTransitionEnter : mNextAppTransitionExit);  
  28.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  29.                 "applyAnimation:"  
  30.                 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"  
  31.                 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter  
  32.                 + " Callers=" + Debug.getCallers(3));  
  33.     } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {   //调用过overrideInPlaceAppTransition()接口设置动画;  
  34.         a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);  
  35.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  36.                 "applyAnimation:"  
  37.                 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"  
  38.                 + " transit=" + appTransitionToString(transit)  
  39.                 + " Callers=" + Debug.getCallers(3));  
  40.     } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {  
  41.         a = createClipRevealAnimationLocked(transit, enter, appFrame);  
  42.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  43.                 "applyAnimation:"  
  44.                         + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"  
  45.                         + " Callers=" + Debug.getCallers(3));  
  46.     } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {           //调用过overridePendingAppTransitionScaleUp()接口设置动画;  
  47.         a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);  
  48.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  49.                 "applyAnimation:"  
  50.                 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"  
  51.                 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter  
  52.                 + " Callers=" + Debug.getCallers(3));  
  53.     } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||  
  54.             mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {        //调用过overridePendingAppTransitionThumb()接口设置动画;  
  55.         mNextAppTransitionScaleUp =  
  56.                 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);  
  57.         a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),  
  58.                 appWidth, appHeight, transit);  
  59.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {  
  60.             String animName = mNextAppTransitionScaleUp ?  
  61.                     "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";  
  62.             Slog.v(TAG, "applyAnimation:"  
  63.                     + " anim=" + a + " nextAppTransition=" + animName  
  64.                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter  
  65.                     + " Callers=" + Debug.getCallers(3));  
  66.         }  
  67.     } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||  
  68.             mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {       //调用过overridePendingAppTransitionAspectScaledThumb()接口设置动画;  
  69.         mNextAppTransitionScaleUp =  
  70.                 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);  
  71.         a = createAspectScaledThumbnailEnterExitAnimationLocked(  
  72.                 getThumbnailTransitionState(enter), appWidth, appHeight, orientation,  
  73.                 transit, containingFrame, contentInsets);  
  74.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {  
  75.             String animName = mNextAppTransitionScaleUp ?  
  76.                     "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";  
  77.             Slog.v(TAG, "applyAnimation:"  
  78.                     + " anim=" + a + " nextAppTransition=" + animName  
  79.                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter  
  80.                     + " Callers=" + Debug.getCallers(3));  
  81.         }  
  82.     } else {                  //这个就是普通Activity切换动画选择逻辑啦,根据transit、enter组合计算出一个animAttr值;  
  83.         int animAttr = 0;  
  84.         switch (transit) {  
  85.             case TRANSIT_ACTIVITY_OPEN:  
  86.                 animAttr = enter  
  87.                         ? WindowAnimation_activityOpenEnterAnimation  
  88.                         : WindowAnimation_activityOpenExitAnimation;  
  89.                 break;  
  90.             case TRANSIT_ACTIVITY_CLOSE:  
  91.                 animAttr = enter  
  92.                         ? WindowAnimation_activityCloseEnterAnimation  
  93.                         : WindowAnimation_activityCloseExitAnimation;  
  94.                 break;  
  95.             case TRANSIT_TASK_OPEN:  
  96.                 animAttr = enter  
  97.                         ? WindowAnimation_taskOpenEnterAnimation  
  98.                         : WindowAnimation_taskOpenExitAnimation;  
  99.                 break;  
  100.             case TRANSIT_TASK_CLOSE:  
  101.                 animAttr = enter  
  102.                         ? WindowAnimation_taskCloseEnterAnimation  
  103.                         : WindowAnimation_taskCloseExitAnimation;  
  104.                 break;  
  105.             case TRANSIT_TASK_TO_FRONT:  
  106.                 animAttr = enter  
  107.                         ? WindowAnimation_taskToFrontEnterAnimation  
  108.                         : WindowAnimation_taskToFrontExitAnimation;  
  109.                 break;  
  110.             case TRANSIT_TASK_TO_BACK:  
  111.                 animAttr = enter  
  112.                         ? WindowAnimation_taskToBackEnterAnimation  
  113.                         : WindowAnimation_taskToBackExitAnimation;  
  114.                 break;  
  115.             case TRANSIT_WALLPAPER_OPEN:  
  116.                 animAttr = enter  
  117.                         ? WindowAnimation_wallpaperOpenEnterAnimation  
  118.                         : WindowAnimation_wallpaperOpenExitAnimation;  
  119.                 break;  
  120.             case TRANSIT_WALLPAPER_CLOSE:  
  121.                 animAttr = enter  
  122.                         ? WindowAnimation_wallpaperCloseEnterAnimation  
  123.                         : WindowAnimation_wallpaperCloseExitAnimation;  
  124.                 break;  
  125.             case TRANSIT_WALLPAPER_INTRA_OPEN:  
  126.                 animAttr = enter  
  127.                         ? WindowAnimation_wallpaperIntraOpenEnterAnimation  
  128.                         : WindowAnimation_wallpaperIntraOpenExitAnimation;  
  129.                 break;  
  130.             case TRANSIT_WALLPAPER_INTRA_CLOSE:  
  131.                 animAttr = enter  
  132.                         ? WindowAnimation_wallpaperIntraCloseEnterAnimation  
  133.                         : WindowAnimation_wallpaperIntraCloseExitAnimation;  
  134.                 break;  
  135.             case TRANSIT_TASK_OPEN_BEHIND:  
  136.                 animAttr = enter  
  137.                         ? WindowAnimation_launchTaskBehindSourceAnimation  
  138.                         : WindowAnimation_launchTaskBehindTargetAnimation;  
  139.         }  
  140.         a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;       //调用loadAnimationAttr()加载动画;  
  141.         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,  
  142.                 "applyAnimation:"  
  143.                 + " anim=" + a  
  144.                 + " animAttr=0x" + Integer.toHexString(animAttr)  
  145.                 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter  
  146.                 + " Callers=" + Debug.getCallers(3));  
  147.     }  
  148.     return a;  
  149. }  
    从上面可以看到对于普通Activity切换,会调用AppTransition.loadAnimationAttr()来加载一个动画。
  1. Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {  
  2.     int anim = 0;  
  3.     Context context = mContext;  
  4.     if (animAttr >= 0) {  
  5.         AttributeCache.Entry ent = getCachedAnimations(lp);  
  6.         if (ent != null) {  
  7.             context = ent.context;  
  8.             anim = ent.array.getResourceId(animAttr, 0);  
  9.         }  
  10.     }  
  11.     if (anim != 0) {  
  12.         return AnimationUtils.loadAnimation(context, anim);  
  13.     }  
  14.     return null;  
  15. }  

第15步、WMS.scheduleAnimationLocked()
    触发动画下一帧计算逻辑。Activity切换动画、窗口动画究竟是如何实现的?说直白点就是调用scheduleAnimationLocked()后,使得在下一个vsync信号来临时触发调用计算窗口透明度、尺寸、旋转角度等值,然后将这些值设置到SurfaceFlinger中去。如果这一帧动画计算完成发现动画仍未结束,便会再次调用scheduleAnimationLocked()使得下一个vsync信号来临时重复之前的计算工作,依次往复,便达实现了想要的动画效果。至于这个一帧动画计算逻辑是如何执行的,请看下面第三部分。

第二部分:窗口动画设置

    窗口动画的设置没那么复杂,我们就看一个比较常见的设置途径,流程如下。窗口动画设置关键函数在WindowStateAnimator.applyAnimationLocked()中,其他函数在第一部分已经分析过了,下面将重点分析这个函数。

    WindowStateAnimator.applyAnimationLocked()函数对于Activity窗口来说并不会为其设置一个窗口动画,而对于非Activity窗口来说其窗口动画设置就是在这个函数中完成的,关 于这一点已经在上面第一部分中的 第十步 WMS.handleAppTransitionReadyLocked()函数分析中讲的非常详细了,在此不多说 。而对于非Activity窗口,比如popupwindow,可通过 setAnimationStyle(int id) 方法设置一个指定的样式窗口动画,样式如下:
  1. <style name="popwin_anim_style">  
  2.      <item name="android:windowEnterAnimation">@anim/menushow</item>  
  3.      <item name="android:windowExitAnimation">@anim/menuhide</item>  
  4. </style>  

    下面将详细分析WindowStateAnimator.applyAnimationLocked()函数。
  1. boolean applyAnimationLocked(int transit, boolean isEntrance) {  
  2.     if ((mLocalAnimating && mAnimationIsEntrance == isEntrance)  
  3.             || mKeyguardGoingAwayAnimation) {          //mLocalAnimating=true表示该窗口正在做动画。如果该窗口将要设置的动画(进入或退出)当前已经正在做,那么直接返回。  
  4.         // If we are trying to apply an animation, but already running  
  5.         // an animation of the same type, then just leave that one alone.  
  6.   
  7.         // If we are in a keyguard exit animation, and the window should animate away, modify  
  8.         // keyguard exit animation such that it also fades out.  
  9.         if (mAnimation != null && mKeyguardGoingAwayAnimation  
  10.                 && transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) {  
  11.             applyFadeoutDuringKeyguardExitAnimation();  
  12.         }  
  13.         return true;  
  14.     }  
  15.   
  16.     // Only apply an animation if the display isn't frozen.  If it is  
  17.     // frozen, there is no reason to animate and it can cause strange  
  18.     // artifacts when we unfreeze the display if some different animation  
  19.     // is running.  
  20.     if (mService.okToDisplay()) {  
  21.         int anim = mPolicy.selectAnimationLw(mWin, transit);  //调用PhoneWindowManager.selectAnimationLw(),如果该窗口是StatusBar、NavigationBar或startingWindow,那么该函数会返回一个指定的动画资源id;  
  22.         int attr = -1;  
  23.         Animation a = null;  
  24.         if (anim != 0) {        
  25.             a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;  
  26.         } else {          
  27.             switch (transit) {                //根据transit值选择对应的样式id;  
  28.                 case WindowManagerPolicy.TRANSIT_ENTER:  
  29.                     attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;  
  30.                     break;  
  31.                 case WindowManagerPolicy.TRANSIT_EXIT:  
  32.                     attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;  
  33.                     break;  
  34.                 case WindowManagerPolicy.TRANSIT_SHOW:  
  35.                     attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;  
  36.                     break;  
  37.                 case WindowManagerPolicy.TRANSIT_HIDE:  
  38.                     attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;  
  39.                     break;  
  40.             }  
  41.             if (attr >= 0) {  
  42.                 a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);    //调用AppTransition.loadAnimationAttr()加载Animation;  
  43.             }  
  44.         }  
  45.         if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,  
  46.                 "applyAnimation: win=" + this  
  47.                 + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)  
  48.                 + " a=" + a  
  49.                 + " transit=" + transit  
  50.                 + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));  
  51.         if (a != null) {                     //对于Activity窗口,a=null,对于非Activity窗口,如果指定了窗口动画,那么a!=null;  
  52.             if (WindowManagerService.DEBUG_ANIM) {  
  53.                 RuntimeException e = null;  
  54.                 if (!WindowManagerService.HIDE_STACK_CRAWLS) {  
  55.                     e = new RuntimeException();  
  56.                     e.fillInStackTrace();  
  57.                 }  
  58.                 Slog.v(TAG, "Loaded animation " + a + " for " + this, e);  
  59.             }  
  60.             setAnimation(a);              //将Animation设置到WindowStateAnimator.mAnimation中;  
  61.             mAnimationIsEntrance = isEntrance;  
  62.         }  
  63.     } else {  
  64.         clearAnimation();  
  65.     }  
  66.   
  67.     return mAnimation != null;  
  68. }  
    如果Activity窗口调用此函数设置一个窗口动画,而从前面第一部分知道对于Activity会设置一个Activity切换动画,那这两个动画搅在一起岂不是乱套了。

    对于WindowStateAnimator.applyAnimationLocked()函数还有其他地方会调用,下面调用栈就是一个例子。
  1. at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:1947)  
  2. at com.android.server.wm.WindowManagerService.removeWindowLocked(WindowManagerService.java:3022)  
  3. at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2977)  
  4. at com.android.server.wm.Session.remove(Session.java:193)  
  5. at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:233)  
  6. 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。
  1. void scheduleAnimationLocked() {  
  2.     if (!mAnimationScheduled) {  
  3.         mAnimationScheduled = true;  
  4.         mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);      //mAnimationFrameCallback是一个Choreographer.FrameCallback对象,在WindowAnimator类构造函数中赋值;  
  5.     }  
  6. }  

  1. WindowAnimator(final WindowManagerService service) {  
  2.     mService = service;  
  3.     mContext = service.mContext;  
  4.     mPolicy = service.mPolicy;  
  5.     mAnimationFrameCallback = new Choreographer.FrameCallback() {  
  6.         public void doFrame(long frameTimeNs) {  
  7.             synchronized (mService.mWindowMap) {  
  8.                 mService.mAnimationScheduled = false;  
  9.                 animateLocked(frameTimeNs);                                        //调用父类animateLocked()函数;  
  10.             }  
  11.         }  
  12.     };  
  13. }  

第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中去,完成一帧动画的显示。
  1. private void animateLocked(long frameTimeNs) {  
  2.     if (!mInitialized) {               //对于默认显示设备准备好后,该mInitialized就会一直为true;  
  3.         return;  
  4.     }  
  5.   
  6.     mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;         //将时间从纳秒折算成毫秒;  
  7.     mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;  
  8.     boolean wasAnimating = mAnimating;  
  9.     mAnimating = false;                                      //将mAnimating和mAppWindowAnimating重置为false。mAnimating是理解动画框架的关键,如果这一帧动画执行完成发现仍需接着执行下一帧动画,那么mAnimating就会被置为true。mAppWindowAnimating是AndroidM新增的一个变量,用来完善handleAnimatingStoppedAndTransitionLocked()被调用逻辑,AndroidM之前的版本在窗口做完动画也会触发调用handleAnimatingStoppedAndTransitionLocked(),AndroidM变成了只有在Activity切换动画完成时才会触发调用handleAnimatingStoppedAndTransitionLocked()。mAppWindowAnimating会在handleAppTransitionReadyLocked()中设置Activity切换动画时就置为true。  
  10.     mAppWindowAnimating = false;  
  11.     if (WindowManagerService.DEBUG_WINDOW_TRACE) {  
  12.         Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);  
  13.     }  
  14.   
  15.     if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(  
  16.             TAG, ">>> OPEN TRANSACTION animateLocked");  
  17.     SurfaceControl.openTransaction();          //打开一次跟SurfaceFlinger的事务传输,待后面调用SurfaceControl.closeTransaction()时,会将这中间所有对surface的设置一次性传递给SurfaceFlinger,这样达到减少频繁进程间通信带来的损耗。  
  18.     SurfaceControl.setAnimationTransaction();  
  19.     try {  
  20.         final int numDisplays = mDisplayContentsAnimators.size();  
  21.         for (int i = 0; i < numDisplays; i++) {        //所有动画的计算就在这个for循环中,实际上这个只会循环一次,除非有多个显示设备。  
  22.             final int displayId = mDisplayContentsAnimators.keyAt(i);  
  23.             updateAppWindowsLocked(displayId);          //计算Activity切换动画Transformation值;  
  24.             DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);  
  25.   
  26.             final ScreenRotationAnimation screenRotationAnimation =  
  27.                     displayAnimator.mScreenRotationAnimation;  
  28.             if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {  
  29.                 if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {       //计算转屏动画Transformation值;  
  30.                     mAnimating = true;  
  31.                 } else {  
  32.                     mBulkUpdateParams |= SET_UPDATE_ROTATION;  
  33.                     screenRotationAnimation.kill();  
  34.                     displayAnimator.mScreenRotationAnimation = null;  
  35.   
  36.                     //TODO (multidisplay): Accessibility supported only for the default display.  
  37.                     if (mService.mAccessibilityController != null  
  38.                             && displayId == Display.DEFAULT_DISPLAY) {  
  39.                         // We just finished rotation animation which means we did not  
  40.                         // anounce the rotation and waited for it to end, announce now.  
  41.                         mService.mAccessibilityController.onRotationChangedLocked(  
  42.                                 mService.getDefaultDisplayContentLocked(), mService.mRotation);  
  43.                     }  
  44.                 }  
  45.             }  
  46.   
  47.             // Update animations of all applications, including those  
  48.             // associated with exiting/removed apps  
  49.             updateWindowsLocked(displayId);                    //计算窗口动画Transformation值;  
  50.             updateWallpaperLocked(displayId);  
  51.   
  52.             final WindowList windows = mService.getWindowListLocked(displayId);  
  53.             final int N = windows.size();  
  54.             for (int j = 0; j < N; j++) {//遍历所有窗口,根据Transformation值,计算更新窗口的surface属性;  
  55.                 windows.get(j).mWinAnimator.prepareSurfaceLocked(true);   
  56.             }  
  57.         }  
  58.   
  59.         for (int i = 0; i < numDisplays; i++) {  
  60.             final int displayId = mDisplayContentsAnimators.keyAt(i);  
  61.   
  62.             testTokenMayBeDrawnLocked(displayId);  
  63.   
  64.             final ScreenRotationAnimation screenRotationAnimation =  
  65.                     mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;  
  66.             if (screenRotationAnimation != null) {  
  67.                 screenRotationAnimation.updateSurfacesInTransaction();  
  68.             }  
  69.   
  70.             mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();  
  71.   
  72.             //TODO (multidisplay): Magnification is supported only for the default display.  
  73.             if (mService.mAccessibilityController != null  
  74.                     && displayId == Display.DEFAULT_DISPLAY) {  
  75.                 mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked();  
  76.             }  
  77.         }  
  78.   
  79.         if (mAnimating) {                     //如果动画仍未结束,那么触发执行下一帧动画;  
  80.             mService.scheduleAnimationLocked();  
  81.         }  
  82.   
  83.         mService.setFocusedStackLayer();  
  84.   
  85.         if (mService.mWatermark != null) {  
  86.             mService.mWatermark.drawIfNeeded();         //如果打开了水印,重绘水印;  
  87.         }  
  88.     } catch (RuntimeException e) {  
  89.         Slog.wtf(TAG, "Unhandled exception in Window Manager", e);  
  90.     } finally {  
  91.         SurfaceControl.closeTransaction();  
  92.         if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(  
  93.                 TAG, "<<< CLOSE TRANSACTION animateLocked");  
  94.     }  
  95.   
  96.     boolean hasPendingLayoutChanges = false;  
  97.     final int numDisplays = mService.mDisplayContents.size();  
  98.     for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {  
  99.         final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);  
  100.         final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());  
  101.         if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {  
  102.             mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;  
  103.         }  
  104.         if (pendingChanges != 0) {  
  105.             hasPendingLayoutChanges = true;  
  106.         }  
  107.     }  
  108.   
  109.     boolean doRequest = false;  
  110.     if (mBulkUpdateParams != 0) {  
  111.         doRequest = mService.copyAnimToLayoutParamsLocked();  
  112.     }  
  113.   
  114.     if (hasPendingLayoutChanges || doRequest) {  
  115.         mService.requestTraversalLocked();  
  116.     }  
  117.   
  118.     if (!mAnimating && wasAnimating) {  
  119.         mService.requestTraversalLocked();  
  120.     }  
  121.     if (WindowManagerService.DEBUG_WINDOW_TRACE) {  
  122.         Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating  
  123.             + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)  
  124.             + " mPendingLayoutChanges(DEFAULT_DISPLAY)="  
  125.             + Integer.toHexString(getPendingLayoutChanges(Display.DEFAULT_DISPLAY)));  
  126.     }  
  127. }  

第4、5、6步、WindowAnimator.updateAppWindowsLocked()
    updateAppWindowsLocked()函数遍历所有AppWindowAnimator,调用AppWindowAnimator.stepAnimationLocked()函数,根据时间、Animation来更新AppWindowAnimator.transformation值。更具体的计算逻辑请自行分析Animation.getTransformation()函数,里面包含了插值器逻辑。
  1. private void updateAppWindowsLocked(int displayId) {  
  2.     ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();  
  3.     for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {       //for循环遍历所有Stack,我们知道在AMS中一个ActivityStack对应WMS中一个TaskStack,目前只有两个Stack;  
  4.         final TaskStack stack = stacks.get(stackNdx);  
  5.         final ArrayList<Task> tasks = stack.getTasks();  
  6.         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {       //for循环遍历Stack中所有Task;  
  7.             final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;  
  8.             for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {  
  9.                 final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;  
  10.                 appAnimator.wasAnimating = appAnimator.animating;  
  11.                 if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {    //调用AppWindowAnimator.stepAnimationLocked(),如果还有下一帧动画,那么函数返回true,该函数根据时间和插值器计算并更新AppWindowAnimator.transformation值;  
  12.                     appAnimator.animating = true;  
  13.                     mAnimating = mAppWindowAnimating = true;  
  14.                 } else if (appAnimator.wasAnimating) {  
  15.                     // stopped animating, do one more pass through the layout  
  16.                     setAppLayoutChanges(appAnimator,  
  17.                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,  
  18.                             "appToken " + appAnimator.mAppToken + " done", displayId);  
  19.                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,  
  20.                             "updateWindowsApps...: done animating " + appAnimator.mAppToken);  
  21.                 }  
  22.             }  
  23.         }  
  24.         final AppTokenList exitingAppTokens = stack.mExitingAppTokens;       //mExitingAppTokens中保存着延迟remove的AppWindowToken,为啥要延迟remove,因为需要一个退出动画或已经设置了一个退出动画;  
  25.         final int exitingCount = exitingAppTokens.size();  
  26.         for (int i = 0; i < exitingCount; i++) {  
  27.             final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;  
  28.             appAnimator.wasAnimating = appAnimator.animating;  
  29.             if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {      //调用AppWindowAnimator.stepAnimationLocked();  
  30.                 mAnimating = mAppWindowAnimating = true;  
  31.             } else if (appAnimator.wasAnimating) {  
  32.                 // stopped animating, do one more pass through the layout  
  33.                 setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,  
  34.                     "exiting appToken " + appAnimator.mAppToken + " done", displayId);  
  35.                 if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,  
  36.                         "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);  
  37.             }  
  38.         }  
  39.     }  
  40. }  

第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退出动画等,在此不细细分析。
  1. private void updateWindowsLocked(final int displayId) {  
  2.     ++mAnimTransactionSequence;  
  3.   
  4.     final WindowList windows = mService.getWindowListLocked(displayId);  
  5.   
  6.     if (mKeyguardGoingAway) {          //mKeyguardGoingAway=true表示keyguard正在退出,那么对于窗口privateFlags & PRIVATE_FLAG_KEYGUARD!= 0窗口设置一个退出动画;  
  7.         for (int i = windows.size() - 1; i >= 0; i--) {  
  8.             WindowState win = windows.get(i);  
  9.             if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {  
  10.                 continue;  
  11.             }  
  12.             final WindowStateAnimator winAnimator = win.mWinAnimator;  
  13.             if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {  
  14.                 if (!winAnimator.mAnimating) {  
  15.                     if (DEBUG_KEYGUARD) Slog.d(TAG,  
  16.                             "updateWindowsLocked: creating delay animation");  
  17.   
  18.                     // Create a new animation to delay until keyguard is gone on its own.  
  19.                     winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);  
  20.                     winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);  
  21.                     winAnimator.mAnimationIsEntrance = false;  
  22.                     winAnimator.mAnimationStartTime = -1;  
  23.                     winAnimator.mKeyguardGoingAwayAnimation = true;  
  24.                 }  
  25.             } else {  
  26.                 if (DEBUG_KEYGUARD) Slog.d(TAG,  
  27.                         "updateWindowsLocked: StatusBar is no longer keyguard");  
  28.                 mKeyguardGoingAway = false;  
  29.                 winAnimator.clearAnimation();  
  30.             }  
  31.             break;  
  32.         }  
  33.     }  
  34.   
  35.     mForceHiding = KEYGUARD_NOT_SHOWN;  
  36.   
  37.     boolean wallpaperInUnForceHiding = false;  
  38.     boolean startingInUnForceHiding = false;  
  39.     ArrayList<WindowStateAnimator> unForceHiding = null;  
  40.     WindowState wallpaper = null;  
  41.     for (int i = windows.size() - 1; i >= 0; i--) {      //for循环遍历堆栈中所有窗口;  
  42.         WindowState win = windows.get(i);  
  43.         WindowStateAnimator winAnimator = win.mWinAnimator;  
  44.         final int flags = win.mAttrs.flags;  
  45.         boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);     //canBeForceHidden()对于TYPE_STATUS_BAR、TYPE_WALLPAPER等窗口返回false,对于其他类型窗口如位于TYPE_STATUS_BAR之下的,那么返回true;  
  46.         boolean shouldBeForceHidden = shouldForceHide(win);                       //shouldForceHide()返回true表示keyguard是显示状态,并且win必须被隐藏;  
  47.         if (winAnimator.mSurfaceControl != null) {  
  48.             final boolean wasAnimating = winAnimator.mWasAnimating;  
  49.             final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);     //根据时间计算窗口动画Transition值,返回值为true表示还有下一帧动画,按理说该函数到这里就行了,为毛还有下面这一堆逻辑,下面来看下这些是干嘛的;  
  50.             winAnimator.mWasAnimating = nowAnimating;  
  51.             mAnimating |= nowAnimating;  
  52.   
  53.             boolean appWindowAnimating = winAnimator.mAppAnimator != null  
  54.                     && winAnimator.mAppAnimator.animating;  
  55.             boolean wasAppWindowAnimating = winAnimator.mAppAnimator != null  
  56.                     && winAnimator.mAppAnimator.wasAnimating;  
  57.             boolean anyAnimating = appWindowAnimating || nowAnimating;          //当前是否正在做Activity切换动画或窗口动画;  
  58.             boolean anyWasAnimating = wasAppWindowAnimating || wasAnimating;    //前一次动画逻辑计算时,该Activity或窗口是否在做动画;  
  59.   
  60.             try {              
  61.                 if (anyAnimating && !anyWasAnimating) {                          //根据anyAnimating和anyWasAnimating组合判断当前是动画开始还是动画结束,进而通知上层应用窗口,这个是AndroidM新增的接口,非常棒的接口,AndroidM终于把动画这一块逻辑理清楚了。  
  62.                     win.mClient.onAnimationStarted(winAnimator.mAnimatingMove ? -1  
  63.                             : winAnimator.mKeyguardGoingAwayAnimation ? 1  
  64.                             : 0);  
  65.                 } else if (!anyAnimating && anyWasAnimating) {  
  66.                     win.mClient.onAnimationStopped();  
  67.                 }  
  68.             } catch (RemoteException e) {  
  69.                 Slog.w(TAG, "Failed to dispatch window animation state change.", e);  
  70.             }  
  71.   
  72.             if (WindowManagerService.DEBUG_WALLPAPER) {  
  73.                 Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +  
  74.                         ", nowAnimating=" + nowAnimating);  
  75.             }  
  76.   
  77.             if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {   //对于窗口动画结束时,如果该窗口是壁纸目标窗口,那么给pendingLayoutChanges加上FINISH_LAYOUT_REDO_WALLPAPER;  
  78.                 mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;  
  79.                 setPendingLayoutChanges(Display.DEFAULT_DISPLAY,  
  80.                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);               
  81.                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {  
  82.                     mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",  
  83.                             getPendingLayoutChanges(Display.DEFAULT_DISPLAY));  
  84.                 }  
  85.             }  
  86.             //下面这些逻辑主要计算在keyguard状态下各种窗口可见性逻辑,及设置keyguard退出动画之类的,在此不细分析,省略;  
  87.   
  88.             ........  

第12步、WindowStateAnimator.prepareSurfaceLocked()
    对窗口堆栈中所有窗口执行WindowStateAnimator.prepareSurfaceLocked()设置每个窗口的动画帧。在前面已经根据时间、Animation值将AppWindowAnimator.transformation和WindowStateAnimator.mTransformation计算出来,接着就该将这两个Transformation转换成Surface的属性并设置到SurfaceFlinger中去。
  1. public void prepareSurfaceLocked(final boolean recoveringMemory) {  
  2.     final WindowState w = mWin;  
  3.     if (mSurfaceControl == null) {               //对于没有Surface的窗口直接return,也就是说下面那些计算窗口surface显示相关的逻辑只针对有Surface的窗口;  
  4.         if (w.mOrientationChanging) {  
  5.             if (DEBUG_ORIENTATION) {  
  6.                 Slog.v(TAG, "Orientation change skips hidden " + w);  
  7.             }  
  8.             w.mOrientationChanging = false;  
  9.         }  
  10.         return;  
  11.     }  
  12.   
  13.     boolean displayed = false;  
  14.   
  15.     computeShownFrameLocked();    //调用computeShownFrameLocked()计算Surface的mShownAlpha、mShownFrame,及缩放矩阵[mDsDx,mDtDx,mDsDy,mDtDy];  
  16.   
  17.     setSurfaceBoundariesLocked(recoveringMemory);    //这个函数更新Surface的起始位置、大小、偏移缩放矩阵、clipRect区域。  
  18.   
  19.     if (mIsWallpaper && !mWin.mWallpaperVisible) {  
  20.         // Wallpaper is no longer visible and there is no wp target => hide it.  
  21.         hide();  
  22.     } else if (w.mAttachedHidden || !w.isOnScreen()) {  
  23.         hide();  
  24.         mService.hideWallpapersLocked(w);  
  25.   
  26.         // If we are waiting for this window to handle an  
  27.         // orientation change, well, it is hidden, so  
  28.         // doesn't really matter.  Note that this does  
  29.         // introduce a potential glitch if the window  
  30.         // becomes unhidden before it has drawn for the  
  31.         // new orientation.  
  32.         if (w.mOrientationChanging) {  
  33.             w.mOrientationChanging = false;  
  34.             if (DEBUG_ORIENTATION) Slog.v(TAG,  
  35.                     "Orientation change skips hidden " + w);  
  36.         }  
  37.     } else if (mLastLayer != mAnimLayer  
  38.             || mLastAlpha != mShownAlpha  
  39.             || mLastDsDx != mDsDx  
  40.             || mLastDtDx != mDtDx  
  41.             || mLastDsDy != mDsDy  
  42.             || mLastDtDy != mDtDy  
  43.             || w.mLastHScale != w.mHScale  
  44.             || w.mLastVScale != w.mVScale  
  45.             || mLastHidden) {  
  46.         displayed = true;  
  47.         mLastAlpha = mShownAlpha;  
  48.         mLastLayer = mAnimLayer;  
  49.         mLastDsDx = mDsDx;  
  50.         mLastDtDx = mDtDx;  
  51.         mLastDsDy = mDsDy;  
  52.         mLastDtDy = mDtDy;  
  53.         w.mLastHScale = w.mHScale;  
  54.         w.mLastVScale = w.mVScale;  
  55.         if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,  
  56.                 "alpha=" + mShownAlpha + " layer=" + mAnimLayer  
  57.                 + " matrix=[" + mDsDx + "*" + w.mHScale  
  58.                 + "," + mDtDx + "*" + w.mVScale  
  59.                 + "][" + mDsDy + "*" + w.mHScale  
  60.                 + "," + mDtDy + "*" + w.mVScale + "]"null);  
  61.         if (mSurfaceControl != null) {        //更新surface的Alpha、Layer高度、2阶偏移缩放矩阵;  
  62.             try {  
  63.                 mSurfaceAlpha = mShownAlpha;  
  64.                 mSurfaceControl.setAlpha(mShownAlpha);  
  65.                 mSurfaceLayer = mAnimLayer;  
  66.                 mSurfaceControl.setLayer(mAnimLayer);  
  67.                 mSurfaceControl.setMatrix(  
  68.                         mDsDx * w.mHScale, mDtDx * w.mVScale,  
  69.                         mDsDy * w.mHScale, mDtDy * w.mVScale);  
  70.   
  71.                 if (mLastHidden && mDrawState == HAS_DRAWN) {        //前一次状态是隐藏,并且绘制状态是HAS_DRAWN绘制完成状态,那么调用showSurfaceRobustlyLocked()将窗口正真显示出来;  
  72.                     if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,  
  73.                             "SHOW (performLayout)"null);  
  74.                     if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w  
  75.                             + " during relayout");  
  76.                     if (showSurfaceRobustlyLocked()) {  
  77.                         mLastHidden = false;  
  78.                         if (mIsWallpaper) {  
  79.                             mService.dispatchWallpaperVisibility(w, true);  
  80.                         }  
  81.                         // This draw means the difference between unique content and mirroring.  
  82.                         // Run another pass through performLayout to set mHasContent in the  
  83.                         // LogicalDisplay.  
  84.                         mAnimator.setPendingLayoutChanges(w.getDisplayId(),  
  85.                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);  
  86.                     } else {  
  87.                         w.mOrientationChanging = false;  
  88.                     }  
  89.                 }  
  90.                 if (mSurfaceControl != null) {  
  91.                     w.mToken.hasVisible = true;  
  92.                 }  
  93.             } catch (RuntimeException e) {  
  94.                 Slog.w(TAG, "Error updating surface in " + w, e);  
  95.                 if (!recoveringMemory) {  
  96.                     mService.reclaimSomeSurfaceMemoryLocked(this"update"true);  
  97.                 }  
  98.             }  
  99.         }  
  100.     } else {  
  101.         if (DEBUG_ANIM && isAnimating()) {  
  102.             Slog.v(TAG, "prepareSurface: No changes in animation for " + this);  
  103.         }  
  104.         displayed = true;  
  105.     }  
  106.   
  107.     if (displayed) {  
  108.         if (w.mOrientationChanging) {  
  109.             if (!w.isDrawnLw()) {  
  110.                 mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;  
  111.                 mAnimator.mLastWindowFreezeSource = w;  
  112.                 if (DEBUG_ORIENTATION) Slog.v(TAG,  
  113.                         "Orientation continue waiting for draw in " + w);  
  114.             } else {  
  115.                 w.mOrientationChanging = false;  
  116.                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);  
  117.             }  
  118.         }  
  119.         w.mToken.hasVisible = true;  
  120.     }  
  121. }  

第13步、WindowStateAnimator.computeShownFrameLocked()
    该函数 根据转屏动画、窗口动画、父窗口动画、Activity切换动画的 Transformation 计算出Matrix矩阵值,及 mShownFrame和 mShownAlpha值,当然这些计算只针对有surface的窗口。
  1. void computeShownFrameLocked() {  
  2.     final boolean selfTransformation = mHasLocalTransformation;    //mHasLocalTransformation=true表示在准备或正在做窗口动画;  
  3.     Transformation attachedTransformation =  
  4.             (mAttachedWinAnimator != null && mAttachedWinAnimator.mHasLocalTransformation)  
  5.             ? mAttachedWinAnimator.mTransformation : null;          //如果该窗口有父窗口,那么取得父窗口的Transformation值;  
  6.     Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)  
  7.             ? mAppAnimator.transformation : null;                    //hasTransformation=true表示在准备货正在做Activity切换动画;  
  8.   
  9.     // Wallpapers are animated based on the "real" window they  
  10.     // are currently targeting.  
  11.     final WindowState wallpaperTarget = mService.mWallpaperTarget;  
  12.     if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {   //这个逻辑基本上不会走,因为wallpaperTarget != null和mService.mAnimateWallpaperWithTarget基本不可能同时满足;  
  13.         final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;  
  14.         if (wallpaperAnimator.mHasLocalTransformation &&  
  15.                 wallpaperAnimator.mAnimation != null &&  
  16.                 !wallpaperAnimator.mAnimation.getDetachWallpaper()) {  
  17.             attachedTransformation = wallpaperAnimator.mTransformation;  
  18.             if (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) {  
  19.                 Slog.v(TAG, "WP target attached xform: " + attachedTransformation);  
  20.             }  
  21.         }  
  22.         final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?  
  23.                 null : wallpaperTarget.mAppToken.mAppAnimator;  
  24.             if (wpAppAnimator != null && wpAppAnimator.hasTransformation  
  25.                 && wpAppAnimator.animation != null  
  26.                 && !wpAppAnimator.animation.getDetachWallpaper()) {  
  27.             appTransformation = wpAppAnimator.transformation;  
  28.             if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) {  
  29.                 Slog.v(TAG, "WP target app xform: " + appTransformation);  
  30.             }  
  31.         }  
  32.     }  
  33.   
  34.     final int displayId = mWin.getDisplayId();  
  35.     final ScreenRotationAnimation screenRotationAnimation =  
  36.             mAnimator.getScreenRotationAnimationLocked(displayId);  
  37.     final boolean screenAnimation =  
  38.             screenRotationAnimation != null && screenRotationAnimation.isAnimating();  
  39.     if (selfTransformation || attachedTransformation != null  
  40.             || appTransformation != null || screenAnimation) {      //如果正在做窗口动画、父窗口有窗口动画、Activity切换动画、转屏动画中一种,那么需更新Surface属性。这个地方有个坑,为毛执行转屏动画时,无关窗口的Surface也被强制改了。  
  41.         // cache often used attributes locally  
  42.         final Rect frame = mWin.mFrame;  
  43.         final float tmpFloats[] = mService.mTmpFloats;  
  44.         final Matrix tmpMatrix = mWin.mTmpMatrix;  
  45.         //下面这大段逻辑是根据转屏动画、窗口动画、父窗口动画、Activity切换动画计算一个tmpMatrix临时矩阵值;  
  46.         // Compute the desired transformation.  
  47.         if (screenAnimation && screenRotationAnimation.isRotating()) {  
  48.             // If we are doing a screen animation, the global rotation  
  49.             // applied to windows can result in windows that are carefully  
  50.             // aligned with each other to slightly separate, allowing you  
  51.             // to see what is behind them.  An unsightly mess.  This...  
  52.             // thing...  magically makes it call good: scale each window  
  53.             // slightly (two pixels larger in each dimension, from the  
  54.             // window's center).  
  55.             final float w = frame.width();  
  56.             final float h = frame.height();  
  57.             if (w>=1 && h>=1) {  
  58.                 tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);  
  59.             } else {  
  60.                 tmpMatrix.reset();  
  61.             }  
  62.         } else {  
  63.             tmpMatrix.reset();  
  64.         }  
  65.         tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);  
  66.         if (selfTransformation) {  
  67.             tmpMatrix.postConcat(mTransformation.getMatrix());  
  68.         }  
  69.         tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);  
  70.         if (attachedTransformation != null) {  
  71.             tmpMatrix.postConcat(attachedTransformation.getMatrix());  
  72.         }  
  73.         if (appTransformation != null) {  
  74.             tmpMatrix.postConcat(appTransformation.getMatrix());  
  75.         }  
  76.         if (screenAnimation) {  
  77.             tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());  
  78.         }  
  79.   
  80.         //TODO (multidisplay): Magnification is supported only for the default display.  
  81.         if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {  
  82.             MagnificationSpec spec = mService.mAccessibilityController  
  83.                     .getMagnificationSpecForWindowLocked(mWin);  
  84.             if (spec != null && !spec.isNop()) {  
  85.                 tmpMatrix.postScale(spec.scale, spec.scale);  
  86.                 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);  
  87.             }  
  88.         }  
  89.   
  90.         // "convert" it into SurfaceFlinger's format  
  91.         // (a 2x2 matrix + an offset)  
  92.         // Here we must not transform the position of the surface  
  93.         // since it is already included in the transformation.  
  94.         //Slog.i(TAG, "Transform: " + matrix);  
  95.   
  96.         mHaveMatrix = true;  
  97.         tmpMatrix.getValues(tmpFloats);  
  98.         mDsDx = tmpFloats[Matrix.MSCALE_X];   //将tmpMatrix矩阵值分别保存在mDsDx、mDtDx、mDsDy、mDtDy中;  
  99.         mDtDx = tmpFloats[Matrix.MSKEW_Y];  
  100.         mDsDy = tmpFloats[Matrix.MSKEW_X];  
  101.         mDtDy = tmpFloats[Matrix.MSCALE_Y];  
  102.         float x = tmpFloats[Matrix.MTRANS_X];    //(x,y)表示窗口在X、Y轴起始位置;  
  103.         float y = tmpFloats[Matrix.MTRANS_Y];  
  104.         int w = frame.width();  
  105.         int h = frame.height();  
  106.         mWin.mShownFrame.set(x, y, x+w, y+h);  
  107.   
  108.         // Now set the alpha...  but because our current hardware  
  109.         // can't do alpha transformation on a non-opaque surface,  
  110.         // turn it off if we are running an animation that is also  
  111.         // transforming since it is more important to have that  
  112.         // animation be smooth.  
  113.         mShownAlpha = mAlpha;  
  114.         mHasClipRect = false;  
  115.         if (!mService.mLimitedAlphaCompositing  
  116.                 || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)  
  117.                 || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)  
  118.                         && x == frame.left && y == frame.top))) {       //将转屏动画、窗口动画、父窗口动画、Activity切换动画的Alpha值apply到mShownAlpha上;  
  119.             //Slog.i(TAG, "Applying alpha transform");  
  120.             if (selfTransformation) {  
  121.                 mShownAlpha *= mTransformation.getAlpha();  
  122.             }  
  123.             if (attachedTransformation != null) {  
  124.                 mShownAlpha *= attachedTransformation.getAlpha();  
  125.             }  
  126.             if (appTransformation != null) {  
  127.                 mShownAlpha *= appTransformation.getAlpha();  
  128.                 if (appTransformation.hasClipRect()) {  
  129.                     mClipRect.set(appTransformation.getClipRect());  
  130.                     if (mWin.mHScale > 0) {  
  131.                         mClipRect.left /= mWin.mHScale;  
  132.                         mClipRect.right /= mWin.mHScale;  
  133.                     }  
  134.                     if (mWin.mVScale > 0) {  
  135.                         mClipRect.top /= mWin.mVScale;  
  136.                         mClipRect.bottom /= mWin.mVScale;  
  137.                     }  
  138.                     mHasClipRect = true;  
  139.                 }  
  140.             }  
  141.             if (screenAnimation) {  
  142.                 mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();  
  143.             }  
  144.         } else {  
  145.             //Slog.i(TAG, "Not applying alpha transform");  
  146.         }  
  147.   
  148.         if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)  
  149.                 && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(  
  150.                 TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha  
  151.                 + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")  
  152.                 + " attached=" + (attachedTransformation == null ?  
  153.                         "null" : attachedTransformation.getAlpha())  
  154.                 + " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())  
  155.                 + " screen=" + (screenAnimation ?  
  156.                         screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));  
  157.         return;              //注意这个return,有动画时在此返回;  
  158.     } else if (mIsWallpaper && mService.mInnerFields.mWallpaperActionPending) {  
  159.         return;  
  160.     }  
  161.     //下面这些逻辑都是无动画时会走的逻辑;  
  162.     if (WindowManagerService.localLOGV) Slog.v(  
  163.             TAG, "computeShownFrameLocked: " + this +  
  164.             " not attached, mAlpha=" + mAlpha);  
  165.   
  166.     MagnificationSpec spec = null;  
  167.     //TODO (multidisplay): Magnification is supported only for the default display.  
  168.     if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {  
  169.         spec = mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);  
  170.     }  
  171.     if (spec != null) {            //如果开启了系统访问控制,那么就会使用预设好的属性,一般情况这个是关闭的;  
  172.         final Rect frame = mWin.mFrame;  
  173.         final float tmpFloats[] = mService.mTmpFloats;  
  174.         final Matrix tmpMatrix = mWin.mTmpMatrix;  
  175.   
  176.         tmpMatrix.setScale(mWin.mGlobalScale, mWin.mGlobalScale);  
  177.         tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);  
  178.   
  179.         if (spec != null && !spec.isNop()) {  
  180.             tmpMatrix.postScale(spec.scale, spec.scale);  
  181.             tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);  
  182.         }  
  183.   
  184.         tmpMatrix.getValues(tmpFloats);  
  185.   
  186.         mHaveMatrix = true;  
  187.         mDsDx = tmpFloats[Matrix.MSCALE_X];  
  188.         mDtDx = tmpFloats[Matrix.MSKEW_Y];  
  189.         mDsDy = tmpFloats[Matrix.MSKEW_X];  
  190.         mDtDy = tmpFloats[Matrix.MSCALE_Y];  
  191.         float x = tmpFloats[Matrix.MTRANS_X];  
  192.         float y = tmpFloats[Matrix.MTRANS_Y];  
  193.         int w = frame.width();  
  194.         int h = frame.height();  
  195.         mWin.mShownFrame.set(x, y, x + w, y + h);  
  196.   
  197.         mShownAlpha = mAlpha;  
  198.     } else {                       //没有动画,并且没有开启系统访问控制,那么就使用如下逻辑设定这些属性值;  
  199.         mWin.mShownFrame.set(mWin.mFrame);  
  200.         if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {  
  201.             mWin.mShownFrame.offset(mWin.mXOffset, mWin.mYOffset);  
  202.         }  
  203.         mShownAlpha = mAlpha;  
  204.         mHaveMatrix = false;  
  205.         mDsDx = mWin.mGlobalScale;  
  206.         mDtDx = 0;  
  207.         mDsDy = 0;  
  208.         mDtDy = mWin.mGlobalScale;  
  209.     }  
  210. }  

第14步、WindowStateAnimator.setSurfaceBoundariesLocked()
    这个函数更新Surface的起始位置、大小、偏 移缩放矩阵、 clipRect区域。
  1. void setSurfaceBoundariesLocked(final boolean recoveringMemory) {  
  2.     final WindowState w = mWin;  
  3.   
  4.     int width;  
  5.     int height;  
  6.     if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {   //目前只有SurfaceView设了这个flag;  
  7.         // for a scaled surface, we always want the requested  
  8.         // size.  
  9.         width  = w.mRequestedWidth;  
  10.         height = w.mRequestedHeight;  
  11.     } else {  
  12.         width = w.mCompatFrame.width();  
  13.         height = w.mCompatFrame.height();  
  14.     }  
  15.   
  16.     // Something is wrong and SurfaceFlinger will not like this,  
  17.     // try to revert to sane values  
  18.     if (width < 1) {  
  19.         width = 1;  
  20.     }  
  21.     if (height < 1) {  
  22.         height = 1;  
  23.     }  
  24.   
  25.     float left = w.mShownFrame.left;     
  26.     float top = w.mShownFrame.top;  
  27.   
  28.     // Adjust for surface insets.  
  29.     final LayoutParams attrs = w.getAttrs();  
  30.     final int displayId = w.getDisplayId();  
  31.     float scale = 1.0f;  
  32.     // Magnification is supported only for the default display.  
  33.     if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {  
  34.         MagnificationSpec spec =  
  35.                 mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w);  
  36.         if (spec != null && !spec.isNop()) {  
  37.             scale = spec.scale;  
  38.         }  
  39.     }  
  40.     //mShownFrame的X、Y轴起始值和mCompatFrame的宽高还需加上一个LayoutParams.surfaceInsets矫正值;  
  41.     width += scale * (attrs.surfaceInsets.left + attrs.surfaceInsets.right);    
  42.     height += scale * (attrs.surfaceInsets.top + attrs.surfaceInsets.bottom);  
  43.     left -= scale * attrs.surfaceInsets.left;  
  44.     top -= scale * attrs.surfaceInsets.top;  
  45.   
  46.     final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;  
  47.     if (surfaceMoved) {        //起始位置有偏移;  
  48.         mSurfaceX = left;  
  49.         mSurfaceY = top;  
  50.   
  51.         try {  
  52.             if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,  
  53.                     "POS " + left + ", " + top, null);  
  54.             mSurfaceControl.setPosition(left, top);      //更新surface的起始位置;  
  55.         } catch (RuntimeException e) {  
  56.             Slog.w(TAG, "Error positioning surface of " + w  
  57.                     + " pos=(" + left + "," + top + ")", e);  
  58.             if (!recoveringMemory) {  
  59.                 mService.reclaimSomeSurfaceMemoryLocked(this"position"true);  
  60.             }  
  61.         }  
  62.     }  
  63.   
  64.     final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height;  
  65.     if (surfaceResized) {       //surface大小有更改;  
  66.         mSurfaceW = width;  
  67.         mSurfaceH = height;  
  68.         mSurfaceResized = true;  
  69.   
  70.         try {  
  71.             if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,  
  72.                     "SIZE " + width + "x" + height, null);  
  73.             mSurfaceControl.setSize(width, height);      //设置surface大小;  
  74.             mSurfaceControl.setMatrix(  
  75.                     mDsDx * w.mHScale, mDtDx * w.mVScale,  
  76.                     mDsDy * w.mHScale, mDtDy * w.mVScale);      //设置surface的2阶偏移缩放矩阵。这个矩阵是如何用的?就是用这个二阶矩阵乘以(x,y)这个一阶矩阵,得出的坐标位置就是最终显示的坐标位置;  
  77.             mAnimator.setPendingLayoutChanges(w.getDisplayId(),  
  78.                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);  
  79.             if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {  
  80.                 final TaskStack stack = w.getStack();  
  81.                 if (stack != null) {  
  82.                     stack.startDimmingIfNeeded(this);  
  83.                 }  
  84.             }  
  85.         } catch (RuntimeException e) {  
  86.             // If something goes wrong with the surface (such  
  87.             // as running out of memory), don't take down the  
  88.             // entire system.  
  89.             Slog.e(TAG, "Error resizing surface of " + w  
  90.                     + " size=(" + width + "x" + height + ")", e);  
  91.             if (!recoveringMemory) {  
  92.                 mService.reclaimSomeSurfaceMemoryLocked(this"size"true);  
  93.             }  
  94.         }  
  95.     }  
  96.   
  97.     updateSurfaceWindowCrop(recoveringMemory);       //调用updateSurfaceWindowCrop()设置surface的窗口切割区域,什么是窗口切割区域clipRect,比如图库中放大显示一张图片,这张图片大小大过屏幕尺寸,用户看到的区域就是切割区域大小,为啥要切割,因为用户看不到的区域没必要合成显示,SurfaceFlinger会根据这个clipRect区域进行合成;该函数调用SurfaceControl.setWindowCrop()来设置窗口clipRect区域。  
  98. }  

第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切换动画。读者可尝试根据上面所说的自行分析动画资源究竟取自哪里。
  1. 10-16 08:40:27.149   825   917 V AppTransition: Loading animations: package=com.meizu.flyme.launcher resId=0xa040040  
  2. 10-16 08:40:27.149   825   917 V AppTransition: Loading animations: picked package=com.meizu.flyme.launcher      //关键字“Loading animations: picked package=”  
  3. 10-16 08:40:27.149   825   917 I AppTransition:  id = a040040 overlayId = 0  
  4. 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   
  5. 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}}}  
  6. 10-16 08:40:27.151   825   917 V WindowManager: java.lang.RuntimeException  
  7. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:3886)  
  8. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.setTokenVisibilityLocked(WindowManagerService.java:4991)  
  9. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked(WindowManagerService.java:10053)  
  10. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:10788)  
  11. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:9601)  
  12. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:9543)  
  13. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.access$700(WindowManagerService.java:182)  
  14. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:8457)  
  15. 10-16 08:40:27.151   825   917 V WindowManager:     at android.os.Handler.dispatchMessage(Handler.java:111)  
  16. 10-16 08:40:27.151   825   917 V WindowManager:     at android.os.Looper.loop(Looper.java:192)  
  17. 10-16 08:40:27.151   825   917 V WindowManager:     at android.os.HandlerThread.run(HandlerThread.java:61)  
  18. 10-16 08:40:27.151   825   917 V WindowManager:     at com.android.server.ServiceThread.run(ServiceThread.java:46)        //“Setting animation in”关键字  
  19. 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  
  20. 10-16 08:40:27.151   825   917 V AppWindowAnimator: Updating layer Window{1e5b3c6c u0 Starting com.android.mms}: 22015  
   上面这份日志表明动画资源取自com.meizu.flyme.launcher。

  1. 10-16 16:48:12.874   825  1863 V AppTransition: Loading animations: layout params pkg=com.android.mms resId=0x7f0e0087  
  2. 10-16 16:48:12.874   825  1863 V AppTransition: Loading animations: picked package=com.android.mms  
  3. 10-16 16:48:12.874   825  1863 I AppTransition:  id = 7f050018 overlayId = 0  
  4. 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   
  5. 10-16 16:48:12.875   825  1863 V WindowStateAnimator: Loaded animation android.view.animation.AnimationSet@8928a66 for WindowStateAnimator{8c23690 PopupWindow:2d5ab621}  
  6. 10-16 16:48:12.875   825  1863 V WindowStateAnimator: java.lang.RuntimeException  
  7. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:1947)  
  8. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at com.android.server.wm.WindowManagerService.removeWindowLocked(WindowManagerService.java:3022)  
  9. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2977)  
  10. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at com.android.server.wm.Session.remove(Session.java:193)  
  11. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:233)  
  12. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at com.android.server.wm.Session.onTransact(Session.java:136)  
  13. 10-16 16:48:12.875   825  1863 V WindowStateAnimator:   at android.os.Binder.execTransact(Binder.java:451)  
  14. 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。

  1. 10-16 16:58:18.414   825   917 V AppTransition: Loading animations: layout params pkg=android resId=0xa1000d4  
  2. 10-16 16:58:18.414   825   917 V AppTransition: Loading animations: picked package=android  
  3. 10-16 16:58:18.414   825   917 I AppTransition:  id = a04002d overlayId = 0  
  4. 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   
  5. 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}}}  
  6. 10-16 16:58:18.416   825   917 V WindowManager: java.lang.RuntimeException  
  7. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:3886)  
  8. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.setTokenVisibilityLocked(WindowManagerService.java:4991)  
  9. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked(WindowManagerService.java:10053)  
  10. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:10788)  
  11. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:9601)  
  12. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:9543)  
  13. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService.access$700(WindowManagerService.java:182)  
  14. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:8457)  
  15. 10-16 16:58:18.416   825   917 V WindowManager:     at android.os.Handler.dispatchMessage(Handler.java:111)  
  16. 10-16 16:58:18.416   825   917 V WindowManager:     at android.os.Looper.loop(Looper.java:192)  
  17. 10-16 16:58:18.416   825   917 V WindowManager:     at android.os.HandlerThread.run(HandlerThread.java:61)  
  18. 10-16 16:58:18.416   825   917 V WindowManager:     at com.android.server.ServiceThread.run(ServiceThread.java:46)  
  19. 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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值