平台
RK3399 + Android 8.1
调试应用: com.android.documentsui
问题
切换后显示异常, 如下图所示, 窗口明显被拉伸了:
正确的显示效果:
调试
dumpsys window
显示异常
Window #5 Window{82f86c3 u0 com.android.documentsui/com.android.documentsui.files.FilesActivity}: mDisplayId=0 stackId=2 mSession=Session{8e3c127 1593:u0a10012} mClient=android.os.BinderProxy@4d7d272 mOwnerUid=10012 mShowToOwnerOnly=true package=com.android.documentsui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x20000 fmt=-3 wanim=0x10302f6 vsysui=0x600 surfaceInsets=Rect(40, 40 - 40, 40) (manual) (!preservePreviousSurfaceInsets) needsMenuKey=2 colorMode=0} Requested w=960 h=512 mLayoutSeq=577 mHasSurface=true mShownPosition=[484,90] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{a17f258 com.android.documentsui/com.android.documentsui.files.FilesActivity}: mAnimating=true mLocalAnimating=false mAnimationIsEntrance=false mAnimation=null mStackClip=1 XForm: has=true hasLocal=false {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} Surface: shown=true layer=21010 alpha=1.0 rect=(444.0,50.0) 1040.0 x 592.0 transform=(0.99166936, 0.0, 1.5310801, 0.0) mGlobalScale=1.0 mDsDx=0.99166936 mDtDx=0.0 mDtDy=0.0 mDsDy=1.5310801 isOnScreen=true isVisible=true
正常显示
Window #5 Window{82f86c3 u0 com.android.documentsui/com.android.documentsui.files.FilesActivity}: mDisplayId=0 stackId=2 mSession=Session{8e3c127 1593:u0a10012} mClient=android.os.BinderProxy@4d7d272 mOwnerUid=10012 mShowToOwnerOnly=true package=com.android.documentsui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x20000 fmt=-3 wanim=0x10302f6 vsysui=0x600 surfaceInsets=Rect(40, 40 - 40, 40) (manual) (!preservePreviousSurfaceInsets) needsMenuKey=2 colorMode=0} Requested w=960 h=512 mLayoutSeq=595 mHasSurface=true mShownPosition=[480,256] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{a17f258 com.android.documentsui/com.android.documentsui.files.FilesActivity}: Surface: shown=true layer=21010 alpha=1.0 rect=(440.0,216.0) 1040.0 x 592.0 transform=(1.0, 0.0, 1.0, 0.0) isOnScreen=true isVisible=true
从近期任务切换为FreeForm模式:
com.android.server.am.ActivityManagerService.startActivityFromRecents(ActivityManagerService.java:4935) com.android.server.am.ActivityStackSupervisor.startActivityFromRecentsInner(ActivityStackSupervisor.java:4882) com.android.server.wm.WindowManagerService.continueSurfaceLayout(WindowManagerService.java:2979) com.android.server.wm.WindowSurfacePlacer.continueLayout(WindowSurfacePlacer.java:126) com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:135) com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:145) com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:197) com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:608) com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:865) com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:2784) com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:633) com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:1533) com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:616) com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:616) com.android.server.wm.WindowState.forAllWindows(WindowState.java:4034) com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4127) com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:777) com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:779)
AppWindowAnimator.java
com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:623) com.android.server.wm.WindowSurfacePlacer.handleAppTransitionReadyLocked(WindowSurfacePlacer.java:344) com.android.server.wm.WindowSurfacePlacer.handleOpeningApps(WindowSurfacePlacer.java:404) com.android.server.wm.AppWindowToken.setVisibility(AppWindowToken.java:372) com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:2435) com.android.server.wm.AppWindowAnimator.setAnimation(AppWindowAnimator.java:127)
在APP切换动画启动后,
WindowStateAnimator中计算并重新设置上面dump出来的相关变量: mShownPosition 和 transform
问题的根源在于 startProlongAnimation 调用了, 但 endProlongedAnimation 却迟迟未调用, 导致动画被无限推后, mShownPosition 和 transform 也一直无变化:
AppWindowAnimator
/** * Sometimes we need to synchronize the first frame of animation with some external event, e.g. * Recents hiding some of its content. To achieve this, we prolong the start of the animaiton * and keep producing the first frame of the animation. */ private long getAnimationFrameTime(Animation animation, long currentTime) { if (mProlongAnimation == PROLONG_ANIMATION_AT_START) { animation.setStartTime(currentTime); return currentTime + 1; } return currentTime; } private boolean stepAnimation(long currentTime) { if (animation == null) { return false; } transformation.clear(); final long animationFrameTime = getAnimationFrameTime(animation, currentTime); ... } void startProlongAnimation(int prolongType) { if(!ffNoCaption)mProlongAnimation = prolongType; mClearProlongedAnimation = false; } void endProlongedAnimation() { mProlongAnimation = PROLONG_ANIMATION_DISABLED; }
WindowManagerService.java
@Override public void endProlongedAnimations() { synchronized (mWindowMap) { for (final WindowState win : mWindowMap.values()) { final AppWindowToken appToken = win.mAppToken; if (appToken != null && appToken.mAppAnimator != null) { appToken.mAppAnimator.endProlongedAnimation(); } } mAppTransition.notifyProlongedAnimationsEnded(); } }
加上调试LOG后输出:
//开始切换: 05-30 05:13:25.287 D/AppWindowAnimator 497): startProlongAnimation 80261794 05-30 05:13:25.298 D/RecentsActivity( 670): addOnPreDrawListener 2 05-30 05:13:25.301 D/RecentsActivity( 670): onPreDraw //从mWindowMap 中删除 com.android.documentsui 05-30 05:13:25.309 D/WindowManagerService( 497): postWindowRemoveCleanupLocked remove com.android.documentsui/com.android.documentsui.files.FilesActivity 05-30 05:13:25.336 D/RecentsActivity( 670): Recents.getSystemServices().endProlongedAnimations(); //开始遍历并调用 AppWindowAnimator.endProlongedAnimation 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui/com.android.systemui.recents.RecentsActivity 05-30 05:13:25.337 D/AppWindowAnimator( 497): endProlongedAnimation 43221400 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=NavigationBar 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=NavigationBar mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=AssistPreviewPanel 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=AssistPreviewPanel mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=DockedStackDivider 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=DockedStackDivider mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.launcher3/com.android.launcher3.Launcher 05-30 05:13:25.337 D/AppWindowAnimator( 497): endProlongedAnimation 73295989 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=StatusBar 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=StatusBar mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui.ImageWallpaper 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui.ImageWallpaper mAppAnimator is NULL //重新将 com.android.documentsui 加入 mWindowMap 中 05-30 05:13:25.404 D/WindowManagerService( 497): addWindow com.android.documentsui/com.android.documentsui.files.FilesActivity
从调试的LOG看, 对应com.android.documentsui的Window在循环调用 AppWindowAnimator.endProlongedAnimation时, 完美地错过了…
解决:
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { int[] appOp = new int[1]; int res = mPolicy.checkAddPermission(attrs, appOp); //...省略代码... } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { atoken = token.asAppWindowToken(); //增加代码 if(atoken != null && atoken.mAppAnimator != null){atoken.mAppAnimator.endProlongedAnimation();} //....省略代码....