Android6.0 WMS(六) WMS动画管理

转载: https://blog.csdn.net/kc58236582/article/details/53835998

Android的应用启动时,或者切换Activity时都会以动画的方式显示前后两屏的切换过程。动画的原理很简单,把一帧一帧的图像按一定时间间隔显示出来就完成了。

动画的绘制需要定时驱动,通常的做法是启动一个定时消息,每隔一定时间发一个消息,收到消息后输出一帧画面。Android支持VSync信号后,动画的驱动就有VSync信号承担了。

窗口动画的基本元素是窗口Surface中保存的图像,通过对窗口的Surface设置不同的变换矩阵和透明度,然后强制Surface刷新,就能在屏幕上显示出窗口的变化过程。


Choreographer对象初始化

我们先来看WMS中的mChoreographer 变量

    final Choreographer mChoreographer = Choreographer.getInstance();
  
  

该变量是一个线程局部存储变量,在它的initialValue中创建了Choreographer对象并返回。这里使用线程局部存储的目录就是保证在线程中只有一个Choreographer对象。


  
  
  1. public static Choreographer getInstance() {
  2. return sThreadInstance.get();
  3. }

  
  
  1. private static final ThreadLocal<Choreographer> sThreadInstance =
  2. new ThreadLocal<Choreographer>() {
  3. @Override
  4. protected Choreographer initialValue() {
  5. Looper looper = Looper.myLooper();
  6. if (looper == null) {
  7. throw new IllegalStateException( "The current thread must have a looper!");
  8. }
  9. return new Choreographer(looper);
  10. }
  11. };

再来看下Choreographer的构造函数,这里主要是创建了FrameDisplayEventReceiver用来接受VSync信号的对象。


  
  
  1. private Choreographer(Looper looper) {
  2. mLooper = looper;
  3. mHandler = new FrameHandler(looper);
  4. mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; //接受VSync信号对象
  5. mLastFrameTimeNanos = Long.MIN_VALUE;
  6. mFrameIntervalNanos = ( long)( 1000000000 / getRefreshRate()); //计算刷新的时间间隔
  7. mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
  8. for ( int i = 0; i <= CALLBACK_LAST; i++) {
  9. mCallbackQueues[i] = new CallbackQueue();
  10. }
  11. }


FrameDisplayEventReceiver接受VSync信号

我们在http://blog.csdn.net/kc58236582/article/details/52892384( Android6.0 VSync信号如何到用户进程 )这篇博客已经分析过FrameDisplayEventReceiver的原理了,当VSync信号过来时,最后会调用到FrameDisplayEventReceiver类的onVsync函数:


  
  
  1. @ Override
  2. public void onVsync (long timestampNanos, int builtInDisplayId, int frame) {
  3. if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
  4. scheduleVsync();
  5. return;
  6. }
  7. long now = System.nanoTime();
  8. if (timestampNanos > now) {
  9. Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
  10. + " ms in the future! Check that graphics HAL is generating vsync "
  11. + "timestamps using the correct timebase.");
  12. timestampNanos = now;
  13. }
  14. if (mHavePendingVsync) {
  15. Log.w(TAG, "Already have a pending vsync event. There should only be "
  16. + "one at a time.");
  17. } else {
  18. mHavePendingVsync = true;
  19. }
  20. mTimestampNanos = timestampNanos;
  21. mFrame = frame;
  22. Message msg = Message.obtain(mHandler, this);
  23. msg.setAsynchronous( true);
  24. mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
  25. }

这主要是发送了一个信号,而是是Runnable的那种消息。

因此我们主要看下这个类的run函数,这里就是调用了Choreographer的doFrame函数。


  
  
  1. @ Override
  2. public void run () {
  3. mHavePendingVsync = false;
  4. doFrame(mTimestampNanos, mFrame);
  5. }


doFrame函数

doFrame函数主要有一些VSync时间逻辑处理如果抛弃该VSync信号的话会调用scheduleVsyncLocked函数让SurfaceFlinger发送一个VSync信号,如果正常会调用4个doCallBacks函数。


  
  
  1. void doFrame(long frameTimeNanos, int frame) {
  2. final long startNanos;
  3. synchronized (mLock) {
  4. ......
  5. long intendedFrameTimeNanos = frameTimeNanos;
  6. startNanos = System.nanoTime();
  7. final long jitterNanos = startNanos - frameTimeNanos;
  8. if (jitterNanos >= mFrameIntervalNanos) {
  9. final long skippedFrames = jitterNanos / mFrameIntervalNanos;
  10. final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
  11. frameTimeNanos = startNanos - lastFrameOffset;
  12. }
  13. if (frameTimeNanos < mLastFrameTimeNanos) {
  14. if (DEBUG_JANK) {
  15. Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
  16. + "previously skipped frame. Waiting for next vsync.");
  17. }
  18. scheduleVsyncLocked(); //让SurfaceFlinger立马发送一个VSync信号
  19. return;
  20. }
  21. mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
  22. mFrameScheduled = false;
  23. mLastFrameTimeNanos = frameTimeNanos;
  24. }
  25. try {
  26. Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
  27. mFrameInfo.markInputHandlingStart();
  28. doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); //按键相关
  29. mFrameInfo.markAnimationsStart();
  30. doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); //动画相关
  31. mFrameInfo.markPerformTraversalsStart();
  32. doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); //power相关
  33. doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
  34. } finally {
  35. Trace.traceEnd(Trace.TRACE_TAG_VIEW);
  36. }
  37. }

doCallbacks函数,我们首先会检查当前这个CallBackType是否有对应的CallBack回调,如果没有直接return,如果有的话会调用其回调的run函数。


  
  
  1. void doCallbacks(int callbackType, long frameTimeNanos) {
  2. CallbackRecord callbacks;
  3. synchronized (mLock) {
  4. final long now = System.nanoTime();
  5. callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
  6. now / TimeUtils.NANOS_PER_MS);
  7. if (callbacks == null) { //没有对应CallBack回调
  8. return;
  9. }
  10. mCallbacksRunning = true;
  11. // safe by ensuring the commit time is always at least one frame behind.
  12. if (callbackType == Choreographer.CALLBACK_COMMIT) {
  13. final long jitterNanos = now - frameTimeNanos;
  14. Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", ( int) jitterNanos);
  15. if (jitterNanos >= 2 * mFrameIntervalNanos) {
  16. final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
  17. + mFrameIntervalNanos;
  18. if (DEBUG_JANK) {
  19. mDebugPrintNextFrameTimeDelta = true;
  20. }
  21. frameTimeNanos = now - lastFrameOffset;
  22. mLastFrameTimeNanos = frameTimeNanos;
  23. }
  24. }
  25. }
  26. try {
  27. for (CallbackRecord c = callbacks; c != null; c = c.next) {
  28. c.run(frameTimeNanos); //调用回调run函数
  29. }
  30. }
  31. ......
  32. }

这也就意味着当你没有CallBackType对应的回调,每次VSync信号过来到doFrame函数再到doCallBacks函数都是没有意义的。


WMS启动动画

那我们下面看在哪里把CallBackType对应的回调加入了,这里我们只关注动画相关的。

上面我们说到VSync会不断的发送,每秒60多次,但是动画不会不停的播放,就是这个CallBackType对应的回调没有。哪动画的启动和结束也就是受这个影响,而就是在WMS中调用scheduleAnimationLocked函数发起的动画启动。


  
  
  1. void scheduleAnimationLocked() {
  2. if (!mAnimationScheduled) {
  3. mAnimationScheduled = true;
  4. mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
  5. }
  6. }

这里就是调用Choreographer设置CallBackType,相关的回调。这里我们的callbackType是CALLBACK_ANIMATION


  
  
  1. public void postFrameCallback(FrameCallback callback) {
  2. postFrameCallbackDelayed(callback, 0);
  3. }
  4. public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
  5. if (callback == null) {
  6. throw new IllegalArgumentException( "callback must not be null");
  7. }
  8. postCallbackDelayedInternal(CALLBACK_ANIMATION,
  9. callback, FRAME_CALLBACK_TOKEN, delayMillis);
  10. }

我们最后看postCallbackDelayedInternal函数,就是在mCallBackQueues对应的CallBackType中增加相应的回调。这里也就是前面在WMS的scheduleAnimationLocked的参数mAnimator.mAnimationFrameCallback就是回调。


  
  
  1. private void postCallbackDelayedInternal(int callbackType,
  2. Object action, Object token, long delayMillis) {
  3. synchronized (mLock) {
  4. final long now = SystemClock.uptimeMillis();
  5. final long dueTime = now + delayMillis;
  6. mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
  7. if (dueTime <= now) {
  8. scheduleFrameLocked(now);
  9. } else {
  10. Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
  11. msg.arg1 = callbackType;
  12. msg.setAsynchronous( true);
  13. mHandler.sendMessageAtTime(msg, dueTime);
  14. }
  15. }
  16. }

我们来看下scheduleFrameLocked函数,我们注意mFrameScheduled这个变量,这个时候赋值为true,后面就是用这个变量来控制每次VSync信号过来调用doFrame函数的时候是否要播放动画


  
  
  1. private void scheduleFrameLocked(long now) {
  2. if (!mFrameScheduled) {
  3. mFrameScheduled = true; //注意这个变量
  4. if (USE_VSYNC) {
  5. if (isRunningOnLooperThreadLocked()) {
  6. scheduleVsyncLocked(); //尽快让SurfaceFlinger中的EventThread发送一个VSync信号
  7. } else {
  8. Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
  9. msg.setAsynchronous( true);
  10. mHandler.sendMessageAtFrontOfQueue(msg);
  11. }
  12. } else {
  13. final long nextFrameTime = Math.max(
  14. mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
  15. if (DEBUG_FRAMES) {
  16. Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
  17. }
  18. Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
  19. msg.setAsynchronous( true);
  20. mHandler.sendMessageAtTime(msg, nextFrameTime);
  21. }
  22. }
  23. }

我们再回过头来看doFrame函数,当mFrameScheduled为false时,VSync信号过来该函数直接return不会播放动画。


  
  
  1. void doFrame(long frameTimeNanos, int frame) {
  2. final long startNanos;
  3. synchronized (mLock) {
  4. if (!mFrameScheduled) {
  5. return; // no work to do
  6. }

继续看postCallbackDelayedInternal函数中增加的回调,这个回调在WindowAnimator的构造函数中就新建了Choreographer.FrameCallback回调


  
  
  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);
  10. }
  11. }
  12. };
  13. }

我们最后看回调的run函数,如果是FRAME_CALLBACK_TOKEN,就是调用回调的doFrame函数。


  
  
  1. private static final class CallbackRecord {
  2. public CallbackRecord next;
  3. public long dueTime;
  4. public Object action; // Runnable or FrameCallback
  5. public Object token;
  6. public void run(long frameTimeNanos) {
  7. if (token == FRAME_CALLBACK_TOKEN) {
  8. ((FrameCallback)action).doFrame(frameTimeNanos);
  9. } else {
  10. ((Runnable)action).run();
  11. }
  12. }
  13. }


播放动画

在上面doFrame函数启动动画,而动画的播放主要在WindowAnimator的animateLocked函数。


  
  
  1. private void animateLocked(long frameTimeNs) {
  2. ......
  3. boolean wasAnimating = mAnimating;
  4. mAnimating = false; //设置mAnimating为false
  5. mAppWindowAnimating = false;
  6. SurfaceControl.openTransaction();
  7. SurfaceControl.setAnimationTransaction();
  8. try {
  9. final int numDisplays = mDisplayContentsAnimators.size();
  10. for ( int i = 0; i < numDisplays; i++) {
  11. final int displayId = mDisplayContentsAnimators.keyAt(i);
  12. updateAppWindowsLocked(displayId);
  13. ......
  14. // Update animations of all applications, including those
  15. // associated with exiting/removed apps
  16. updateWindowsLocked(displayId);
  17. updateWallpaperLocked(displayId);
  18. final WindowList windows = mService.getWindowListLocked(displayId);
  19. final int N = windows.size();
  20. for ( int j = 0; j < N; j++) {
  21. windows.get(j).mWinAnimator.prepareSurfaceLocked( true); //输出动画帧
  22. }
  23. }
  24. for ( int i = 0; i < numDisplays; i++) {
  25. final int displayId = mDisplayContentsAnimators.keyAt(i);
  26. testTokenMayBeDrawnLocked(displayId);
  27. final ScreenRotationAnimation screenRotationAnimation =
  28. mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
  29. if (screenRotationAnimation != null) {
  30. screenRotationAnimation.updateSurfacesInTransaction();
  31. }
  32. mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();
  33. if (mService.mAccessibilityController != null
  34. && displayId == Display.DEFAULT_DISPLAY) {
  35. mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
  36. }
  37. }
  38. if (mAnimating) { //为true,继续调用WMS的scheduleAnimationLocked播放下一帧
  39. mService.scheduleAnimationLocked();
  40. }
  41. ......
  42. finally {
  43. SurfaceControl.closeTransaction();
  44. }
  45. ......
  46. boolean doRequest = false;
  47. if (mBulkUpdateParams != 0) {
  48. doRequest = mService.copyAnimToLayoutParamsLocked();
  49. }
  50. if (hasPendingLayoutChanges || doRequest) {
  51. mService.requestTraversalLocked(); //重新刷新UI
  52. }
  53. if (!mAnimating && wasAnimating) {
  54. mService.requestTraversalLocked();
  55. }
  56. }

animateLocked方法先将mAnimating 设置为false,然后调用updateWindowsLocked函数和updateWallpaperLocked函数,updateWindowsLocked这个函数会调用WindowStateAnimator类的stepAnimationLocker方法,如果动画已经显示完最后一帧,stepAnimationLocker方法将会WindowStateAnimator类的mAnimating设置为false,表示该窗口的动画已经结束。而在updateWallpaperLocked函数中会判断所有窗口的动画是否已经结束,只要有一个动画没结束,就会将winAnimator的mAnimating设置为true。


  
  
  1. for ( int i = windows.size() - 1; i >= 0; i--) {
  2. final WindowState win = windows.get(i);
  3. WindowStateAnimator winAnimator = win.mWinAnimator;
  4. if (winAnimator.mSurfaceControl == null) {
  5. continue;
  6. }
  7. final int flags = win.mAttrs.flags;
  8. if (winAnimator.mAnimating) {
  9. ......
  10. mAnimating = true;
  11. }
  12. ......

再回到animatelocked方法,当mAnimating为true是会调用WMS的scheduleAnimationLocked方法继续显示动画,否则动画显示就结束了。

下面我们总结下动画的播放过程:需要播放动画时,先会调用WMS的scheduleAnimationLocked方法。调用这个方法后,才会接受并处理一次VSync信号,对VSync信号的处理,就是所有需要绘制的窗口根据各自动画的谁知重新调整窗口Surface的变化矩阵和透明度;如果还有窗口动画需要显示,继续调用scheduleAnimationLocked方法准备下一帧。

准备一帧动画的时间可以跨越多个VSync信号周期,但是只有收到VSync信号才能更新窗口的Surface的属性和内容,对应用而言收到VSync信号意味着SurfaceFlinger中已经把上次设置的动画数据取走了,可以安全地设置下一帧动画的属性和内容了。


窗口动画对象WindowStateAnimator

窗口对象WindowState中定义了一个类型为WindowStateAnimator的成员变量mWinAnimator,用来表示窗口的动画对象。

下面是一些成员变量


  
  
  1. boolean mAnimating; //表示是否正在显示动画
  2. boolean mLocalAnimating; //表示窗口动画是否已经初始化
  3. Animation mAnimation; //表示窗口动画对象
  4. boolean mAnimationIsEntrance; //
  5. boolean mHasTransformation; //表示当前动画的mTransformation是否可用
  6. boolean mHasLocalTransformation; //表示当前动画时一个窗口动画还是Activity动画
  7. final Transformation mTransformation = new Transformation(); //变换矩阵对象

当前正在显示的动画有两种类型,一种的窗口切换动画,一种是Activity切换动画,这里使用了mLocalAnimating和mHasLocalTransformation分别表示窗口动画的状态。

stepAnimationLocked是WindowStateAnimator类中显示动画首先调用的方法,它会初始化WindowStateAnimator对象的一些成员变量


  
  
  1. boolean stepAnimationLocked(long currentTime) {
  2. final DisplayContent displayContent = mWin.getDisplayContent();
  3. if (displayContent != null && mService.okToDisplay()) {
  4. if (mWin.isDrawnLw() && mAnimation != null) { //窗口准备好绘制了,窗口动画对象不为空
  5. mHasTransformation = true;
  6. mHasLocalTransformation = true;
  7. if (!mLocalAnimating) { //还没有初始化窗口对象
  8. final DisplayInfo displayInfo = displayContent.getDisplayInfo();
  9. if (mAnimateMove) {
  10. mAnimateMove = false;
  11. mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), //初始化窗口对象
  12. mAnimDw, mAnimDh);
  13. } else {
  14. mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
  15. displayInfo.appWidth, displayInfo.appHeight);
  16. }
  17. mAnimDw = displayInfo.appWidth;
  18. mAnimDh = displayInfo.appHeight;
  19. mAnimation.setStartTime(mAnimationStartTime != -1
  20. ? mAnimationStartTime
  21. : currentTime);
  22. mLocalAnimating = true; // 设置为true代表已经初始化窗口对象
  23. mAnimating = true;
  24. }
  25. if ((mAnimation != null) && mLocalAnimating) {
  26. mLastAnimationTime = currentTime;
  27. if (stepAnimation(currentTime)) { //通过时间判断动画是否显示完毕
  28. return true;
  29. }
  30. }
  31. }
  32. mHasLocalTransformation = false;
  33. if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null //没有设置窗口动画或者窗口动画结束了
  34. && mAppAnimator.animation != null) {
  35. // 如果有Activity动画,将mAnimating设为true
  36. mAnimating = true;
  37. mHasTransformation = true;
  38. mTransformation.clear();
  39. return false;
  40. } else if (mHasTransformation) {
  41. // Little trick to get through the path below to act like
  42. // we have finished an animation.
  43. mAnimating = true;
  44. } else if (isAnimating()) {
  45. mAnimating = true;
  46. }
  47. } else if (mAnimation != null) {
  48. mAnimating = true;
  49. }
  50. if (!mAnimating && !mLocalAnimating) {
  51. return false;
  52. }
  53. mAnimating = false;
  54. mKeyguardGoingAwayAnimation = false;
  55. mAnimatingMove = false;
  56. mLocalAnimating = false;
  57. ......
  58. mHasLocalTransformation = false;
  59. ......
  60. mTransformation.clear();
  61. ......
  62. return false;
  63. }

该方法的工作就是设置WindowStateAnimator对象的几个成员变量,首先调用WindowState对象的isDrawnLw来判断窗口系统的状态,只有准备好了才能显示,接着判断mAnimation是否为空,不为空代表已经设置好了动画对象。

接下来判断mLocalAnimating变量的值,为false则调用mAnimation的intialize方法来完成动画对象的初始化(主要设置动画的高度和宽度),然后将mLocalAnimating和mAnimating设为true。完成初始化后,接着调用stepAnimation方法来判断动画是否已经显示完成,没有完成返回true。

如果没有设置动画或者动画已经结束了,则还有判断窗口所在的Activity是否还存在动画,如果有,将mAnimating设置true(表示还要继续播放动画),如果同时mHasTransformation的值仍然为true,或者isAnimating方法返回true,也将mAnimating设置为true。

isAnimating会根据当前动画对象mAnimation是否为空,它的附加窗口的动画对象是否为空,以及窗口所在的Activity的动画对象是否为空等条件来判断,这表示只要有可能mAnimating就会设置为true。这样的目的尽量让动画完成显示,即使没有可显示的动画,多刷新几次不会有副作用,但如果少画了一次,屏幕上就可能留下不正确画面了。


  
  
  1. boolean isAnimating() {
  2. return mAnimation != null
  3. || (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)
  4. || (mAppAnimator != null && mAppAnimator.isAnimating());
  5. }


动画生成及显示

我们再看看动画的生成过程,WindowStateAnimator的prepareSurfaceLocked方法来完成计算一帧动画并显示工作:


  
  
  1. public void prepareSurfaceLocked(final boolean recoveringMemory) {
  2. ......
  3. computeShownFrameLocked(); //计算要显示的动画帧
  4. setSurfaceBoundariesLocked(recoveringMemory);
  5. if (mIsWallpaper && !mWin.mWallpaperVisible) {
  6. hide(); //如果是壁纸窗口,隐藏
  7. } else if (w.mAttachedHidden || !w.isOnScreen()) {
  8. hide(); //如果窗口不可见,隐藏
  9. ......
  10. } else if (mLastLayer != mAnimLayer
  11. || mLastAlpha != mShownAlpha
  12. || mLastDsDx != mDsDx
  13. || mLastDtDx != mDtDx
  14. || mLastDsDy != mDsDy
  15. || mLastDtDy != mDtDy
  16. || w.mLastHScale != w.mHScale
  17. || w.mLastVScale != w.mVScale
  18. || mLastHidden) { //每个值是否有变化
  19. displayed = true;
  20. mLastAlpha = mShownAlpha;
  21. mLastLayer = mAnimLayer;
  22. mLastDsDx = mDsDx;
  23. mLastDtDx = mDtDx;
  24. mLastDsDy = mDsDy;
  25. mLastDtDy = mDtDy;
  26. w.mLastHScale = w.mHScale;
  27. w.mLastVScale = w.mVScale;
  28. if (mSurfaceControl != null) {
  29. try {
  30. mSurfaceAlpha = mShownAlpha;
  31. mSurfaceControl.setAlpha(mShownAlpha);
  32. mSurfaceLayer = mAnimLayer;
  33. mSurfaceControl.setLayer(mAnimLayer);
  34. mSurfaceControl.setMatrix(
  35. mDsDx * w.mHScale, mDtDx * w.mVScale,
  36. mDsDy * w.mHScale, mDtDy * w.mVScale);
  37. if (mLastHidden && mDrawState == HAS_DRAWN) {
  38. if (showSurfaceRobustlyLocked()) { //输出动画帧
  39. mLastHidden = false;
  40. if (mIsWallpaper) {
  41. mService.dispatchWallpaperVisibility(w, true);
  42. }
  43. mAnimator.setPendingLayoutChanges(w.getDisplayId(),
  44. WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
  45. } else {
  46. w.mOrientationChanging = false;
  47. }
  48. }
  49. if (mSurfaceControl != null) {
  50. w.mToken.hasVisible = true;
  51. }
  52. } catch (RuntimeException e) {
  53. Slog.w(TAG, "Error updating surface in " + w, e);
  54. if (!recoveringMemory) {
  55. mService.reclaimSomeSurfaceMemoryLocked( this, "update", true);
  56. }
  57. }
  58. }
  59. }
  60. ......
  61. }

该函数先调用了computeShownFrameLocked函数计算当前需要显示的动画帧数据,mAnimLayer表示窗口的Z轴、mShownAlpha窗口透明度;mDsDx、mDtDx、mDsDy和mDtDy表示二维变换矩阵;w.mHScale w.mVScale表示窗口的缩放比例

只有计算出的数据和上一次数据不一样才会调用showSurfaceRobustlyLocked输出动画帧。

我们再来看WindowStateAnimator的prepareSurfaceLocked函数中下面一段代码,会调用showSurfaceRobustlyLocked函数显示window,当返回true代表成功,会把mLastHidden为false,代表上次没有隐藏。


    
    
  1. if (showSurfaceRobustlyLocked()) {
  2. mLastHidden = false;
  3. if (mIsWallpaper) {
  4. mService.dispatchWallpaperVisibility(w, true);
  5. }
  6. // This draw means the difference between unique content and mirroring.
  7. // Run another pass through performLayout to set mHasContent in the
  8. // LogicalDisplay.
  9. mAnimator.setPendingLayoutChanges(w.getDisplayId(),
  10. WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
  11. } else {
  12. w.mOrientationChanging = false;
  13. }

我们再来看下showSurfaceRobustlyLocked函数,会调用mSurfaceControl的show函数显示窗口,当然这中间如果出错,或者没有mSurfaceControl对象,会调用WMS的reclaimSomeSurfaceMemoryLocked来回收系统资源。


   
   
  1. boolean showSurfaceRobustlyLocked() {
  2. try {
  3. if (mSurfaceControl != null) {
  4. mSurfaceShown = true;
  5. mSurfaceControl.show();
  6. if (mWin.mTurnOnScreen) {
  7. if (DEBUG_VISIBILITY) Slog.v(TAG,
  8. "Show surface turning screen on: " + mWin);
  9. mWin.mTurnOnScreen = false;
  10. mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
  11. }
  12. }
  13. return true;
  14. } catch (RuntimeException e) {
  15. Slog.w(TAG, "Failure showing surface " + mSurfaceControl + " in " + mWin, e);
  16. }
  17. mService.reclaimSomeSurfaceMemoryLocked( this, "show", true);
  18. return false;
  19. }



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值