Merge "Fix another animation leak" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-04-06 20:43:40 +00:00
committed by Android (Google) Code Review
2 changed files with 48 additions and 8 deletions

View File

@@ -37,6 +37,8 @@ class AnimatingAppWindowTokenRegistry {
private ArrayList<Runnable> mTmpRunnableList = new ArrayList<>();
private boolean mEndingDeferredFinish;
/**
* Notifies that an {@link AppWindowToken} has started animating.
*/
@@ -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();
}
}
/**
@@ -78,16 +85,28 @@ 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.
for (int i = mFinishedTokens.size() - 1; i >= 0; i--) {
mTmpRunnableList.add(mFinishedTokens.valueAt(i));
// Don't start recursing. Running the finished listener invokes notifyFinished, which may
// invoked us again.
if (mEndingDeferredFinish) {
return;
}
mFinishedTokens.clear();
for (int i = mTmpRunnableList.size() - 1; i >= 0; i--) {
mTmpRunnableList.get(i).run();
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));
}
mFinishedTokens.clear();
for (int i = mTmpRunnableList.size() - 1; i >= 0; i--) {
mTmpRunnableList.get(i).run();
}
mTmpRunnableList.clear();
} finally {
mEndingDeferredFinish = false;
}
mTmpRunnableList.clear();
}
void dump(PrintWriter pw, String header, String prefix) {

View File

@@ -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();
}
}