Loading services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java +27 −8 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ class AnimatingAppWindowTokenRegistry { private ArrayList<Runnable> mTmpRunnableList = new ArrayList<>(); private boolean mEndingDeferredFinish; /** * Notifies that an {@link AppWindowToken} has started animating. */ Loading @@ -50,6 +52,11 @@ class AnimatingAppWindowTokenRegistry { void notifyFinished(AppWindowToken token) { mAnimatingTokens.remove(token); mFinishedTokens.remove(token); // If we were the last token, make sure the end all deferred finishes. if (mAnimatingTokens.isEmpty()) { endDeferringFinished(); } } /** Loading Loading @@ -78,8 +85,17 @@ class AnimatingAppWindowTokenRegistry { } private void endDeferringFinished() { // Copy it into a separate temp list to avoid modifying the collection while iterating as // calling the callback may call back into notifyFinished. // Don't start recursing. Running the finished listener invokes notifyFinished, which may // invoked us again. if (mEndingDeferredFinish) { return; } try { mEndingDeferredFinish = true; // Copy it into a separate temp list to avoid modifying the collection while iterating // as calling the callback may call back into notifyFinished. for (int i = mFinishedTokens.size() - 1; i >= 0; i--) { mTmpRunnableList.add(mFinishedTokens.valueAt(i)); } Loading @@ -88,6 +104,9 @@ class AnimatingAppWindowTokenRegistry { mTmpRunnableList.get(i).run(); } mTmpRunnableList.clear(); } finally { mEndingDeferredFinish = false; } } void dump(PrintWriter pw, String header, String prefix) { Loading services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -88,4 +88,25 @@ public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { verify(mMockEndDeferFinishCallback1).run(); verifyZeroInteractions(mMockEndDeferFinishCallback2); } @Test public void testContainerRemoved() throws Exception { final AppWindowToken window1 = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD, "window2").mAppToken; final AnimatingAppWindowTokenRegistry registry = window1.getStack().getAnimatingAppWindowTokenRegistry(); window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); assertTrue(window1.isSelfAnimating()); assertTrue(window2.isSelfAnimating()); // Make sure that first animation finish is deferred, and removing the second window stops // finishes all pending deferred finishings. registry.notifyAboutToFinish(window1, mMockEndDeferFinishCallback1); window2.setParent(null); verify(mMockEndDeferFinishCallback1).run(); } } Loading
services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java +27 −8 Original line number Diff line number Diff line Loading @@ -37,6 +37,8 @@ class AnimatingAppWindowTokenRegistry { private ArrayList<Runnable> mTmpRunnableList = new ArrayList<>(); private boolean mEndingDeferredFinish; /** * Notifies that an {@link AppWindowToken} has started animating. */ Loading @@ -50,6 +52,11 @@ class AnimatingAppWindowTokenRegistry { void notifyFinished(AppWindowToken token) { mAnimatingTokens.remove(token); mFinishedTokens.remove(token); // If we were the last token, make sure the end all deferred finishes. if (mAnimatingTokens.isEmpty()) { endDeferringFinished(); } } /** Loading Loading @@ -78,8 +85,17 @@ class AnimatingAppWindowTokenRegistry { } private void endDeferringFinished() { // Copy it into a separate temp list to avoid modifying the collection while iterating as // calling the callback may call back into notifyFinished. // Don't start recursing. Running the finished listener invokes notifyFinished, which may // invoked us again. if (mEndingDeferredFinish) { return; } try { mEndingDeferredFinish = true; // Copy it into a separate temp list to avoid modifying the collection while iterating // as calling the callback may call back into notifyFinished. for (int i = mFinishedTokens.size() - 1; i >= 0; i--) { mTmpRunnableList.add(mFinishedTokens.valueAt(i)); } Loading @@ -88,6 +104,9 @@ class AnimatingAppWindowTokenRegistry { mTmpRunnableList.get(i).run(); } mTmpRunnableList.clear(); } finally { mEndingDeferredFinish = false; } } void dump(PrintWriter pw, String header, String prefix) { Loading
services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -88,4 +88,25 @@ public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { verify(mMockEndDeferFinishCallback1).run(); verifyZeroInteractions(mMockEndDeferFinishCallback2); } @Test public void testContainerRemoved() throws Exception { final AppWindowToken window1 = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD, "window2").mAppToken; final AnimatingAppWindowTokenRegistry registry = window1.getStack().getAnimatingAppWindowTokenRegistry(); window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); assertTrue(window1.isSelfAnimating()); assertTrue(window2.isSelfAnimating()); // Make sure that first animation finish is deferred, and removing the second window stops // finishes all pending deferred finishings. registry.notifyAboutToFinish(window1, mMockEndDeferFinishCallback1); window2.setParent(null); verify(mMockEndDeferFinishCallback1).run(); } }