Fix NPE when animation doesn't get started
If animation start is delayed, there is no guarantee that startAnimation is called on the adapter. Thus, protect RemoteAnimationController against this case, as leash and finishedCallback would be null. Furthermore don't even try to start remote animation that is delayed as it would leave it hanging forever. Test: SurfaceAnimatorTest/RemoteAnimationControllerTest Change-Id: I72c492c4fb6ca8eeae481d2c281e9c1fee95f921 Fixes: 76096628
This commit is contained in:
@@ -1698,7 +1698,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
||||
stack.getBounds(mTmpRect);
|
||||
mTmpRect.offsetTo(0, 0);
|
||||
}
|
||||
if (mService.mAppTransition.getRemoteAnimationController() != null) {
|
||||
|
||||
// Delaying animation start isn't compatible with remote animations at all.
|
||||
if (mService.mAppTransition.getRemoteAnimationController() != null
|
||||
&& !mSurfaceAnimator.isAnimationStartDelayed()) {
|
||||
adapter = mService.mAppTransition.getRemoteAnimationController()
|
||||
.createAnimationAdapter(this, mTmpPoint, mTmpRect);
|
||||
} else {
|
||||
|
||||
@@ -99,6 +99,10 @@ class RemoteAnimationController {
|
||||
mFinishedCallback = new FinishedCallback(this);
|
||||
|
||||
final RemoteAnimationTarget[] animations = createAnimations();
|
||||
if (animations.length == 0) {
|
||||
onAnimationFinished();
|
||||
return;
|
||||
}
|
||||
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
|
||||
try {
|
||||
mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
|
||||
@@ -132,6 +136,8 @@ class RemoteAnimationController {
|
||||
mPendingAnimations.get(i).createRemoteAppAnimation();
|
||||
if (target != null) {
|
||||
targets.add(target);
|
||||
} else {
|
||||
mPendingAnimations.remove(i);
|
||||
}
|
||||
}
|
||||
return targets.toArray(new RemoteAnimationTarget[targets.size()]);
|
||||
@@ -225,10 +231,8 @@ class RemoteAnimationController {
|
||||
RemoteAnimationTarget createRemoteAppAnimation() {
|
||||
final Task task = mAppWindowToken.getTask();
|
||||
final WindowState mainWindow = mAppWindowToken.findMainWindow();
|
||||
if (task == null) {
|
||||
return null;
|
||||
}
|
||||
if (mainWindow == null) {
|
||||
if (task == null || mainWindow == null || mCapturedFinishCallback == null
|
||||
|| mCapturedLeash == null) {
|
||||
return null;
|
||||
}
|
||||
mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
|
||||
|
||||
@@ -234,6 +234,10 @@ class SurfaceAnimator {
|
||||
mService.mAnimationTransferMap.put(mAnimation, this);
|
||||
}
|
||||
|
||||
boolean isAnimationStartDelayed() {
|
||||
return mAnimationStartDelayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation, and resets the leash.
|
||||
*
|
||||
|
||||
@@ -68,6 +68,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
super.setUp();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50);
|
||||
mAdapter.setCallingPid(123);
|
||||
sWm.mH.runWithScissors(() -> {
|
||||
mHandler = new TestHandler(null, mClock);
|
||||
}, 0);
|
||||
@@ -83,7 +84,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
new Point(50, 100), new Rect(50, 100, 150, 150));
|
||||
adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
|
||||
mController.goodToGo();
|
||||
|
||||
sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
|
||||
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
|
||||
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
|
||||
@@ -167,4 +168,33 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
mController.goodToGo();
|
||||
verifyZeroInteractions(mMockRunner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotReallyStarted() throws Exception {
|
||||
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
|
||||
mController.createAnimationAdapter(win.mAppToken,
|
||||
new Point(50, 100), new Rect(50, 100, 150, 150));
|
||||
mController.goodToGo();
|
||||
verifyZeroInteractions(mMockRunner);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneNotStarted() throws Exception {
|
||||
final WindowState win1 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin1");
|
||||
final WindowState win2 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin2");
|
||||
mController.createAnimationAdapter(win1.mAppToken,
|
||||
new Point(50, 100), new Rect(50, 100, 150, 150));
|
||||
final AnimationAdapter adapter = mController.createAnimationAdapter(win2.mAppToken,
|
||||
new Point(50, 100), new Rect(50, 100, 150, 150));
|
||||
adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
|
||||
mController.goodToGo();
|
||||
sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
|
||||
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
|
||||
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
|
||||
ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
|
||||
verify(mMockRunner).onAnimationStart(appsCaptor.capture(), finishedCaptor.capture());
|
||||
assertEquals(1, appsCaptor.getValue().length);
|
||||
assertEquals(mMockLeash, appsCaptor.getValue()[0].leash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
|
||||
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
|
||||
verifyZeroInteractions(mSpec);
|
||||
assertAnimating(mAnimatable);
|
||||
assertTrue(mAnimatable.mSurfaceAnimator.isAnimationStartDelayed());
|
||||
mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
|
||||
verify(mSpec).startAnimation(any(), any(), any());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user