Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 442aff2d authored by Arthur Hung's avatar Arthur Hung
Browse files

Fix window didn't disappear if enable/disable ime at same time

When starting to freeze display, AppTransition also clear all status and
data, but if the RemoteAnimation didn't start. The window can't recevice the
finish animation callback, that would make the state is always EXITING.

Bug: 130618911
Test: atest DocumentsTest
Test: atest WmTests:RemoteAnimationControllerTest
Test: atest WmTests:AppTransitionTests
Change-Id: I5695a291f26323eb78cced435722b459b963a9f1
parent 906e4169
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -452,6 +452,13 @@ public class AppTransition implements Dump {

    void freeze() {
        final int transit = mNextAppTransition;
        // The RemoteAnimationControl didn't register AppTransitionListener and
        // only initialized the finish and timeout callback when goodToGo().
        // So cancel the remote animation here to prevent the animation can't do
        // finish after transition state cleared.
        if (mRemoteAnimationController != null) {
            mRemoteAnimationController.cancelAnimation("freeze");
        }
        setAppTransition(TRANSIT_UNSET, 0 /* flags */);
        clear();
        setReady();
+1 −1
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ class RemoteAnimationController implements DeathRecipient {
        sendRunningRemoteAnimation(true);
    }

    private void cancelAnimation(String reason) {
    void cancelAnimation(String reason) {
        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
        synchronized (mService.getWindowManagerLock()) {
            if (mCanceled) {
+64 −4
Original line number Diff line number Diff line
@@ -18,30 +18,40 @@ package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.Display;

import org.junit.Before;
import org.junit.Test;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;

import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.Test;

/**
 * Test class for {@link AppTransition}.
 *
@@ -51,7 +61,6 @@ import androidx.test.filters.SmallTest;
@SmallTest
@Presubmit
public class AppTransitionTests extends WindowTestsBase {

    private DisplayContent mDc;

    @Before
@@ -181,4 +190,55 @@ public class AppTransitionTests extends WindowTestsBase {
                getInstrumentation().getTargetContext(), -1));
    }

    @Test
    public void testCancelRemoteAnimationWhenFreeze() {
        final DisplayContent dc = createNewDisplay(Display.STATE_ON);
        final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
                dc, "exiting app");
        final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
        // Wait until everything in animation handler get executed to prevent the exiting window
        // from being removed during WindowSurfacePlacer Traversal.
        waitUntilHandlersIdle();

        // Set a remote animator.
        final TestRemoteAnimationRunner runner = new TestRemoteAnimationRunner();
        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                runner, 100, 50, true /* changeNeedsSnapshot */);
        // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid.
        adapter.setCallingPid(123);

        // Simulate activity finish flows to prepare app transition & set visibility,
        // make sure transition is set as expected.
        dc.prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
                false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
        assertEquals(TRANSIT_ACTIVITY_CLOSE, dc.mAppTransition.getAppTransition());
        dc.mAppTransition.overridePendingAppTransitionRemote(adapter);
        exitingAppToken.setVisibility(false, false);
        assertTrue(dc.mClosingApps.size() > 0);

        // Make sure window is in animating stage before freeze, and cancel after freeze.
        assertTrue(dc.isAppAnimating());
        assertFalse(runner.mCancelled);
        dc.mAppTransition.freeze();
        assertFalse(dc.isAppAnimating());
        assertTrue(runner.mCancelled);
    }

    private class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
        boolean mCancelled = false;
        @Override
        public void onAnimationStart(RemoteAnimationTarget[] apps,
                IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
        }

        @Override
        public void onAnimationCancelled() {
            mCancelled = true;
        }

        @Override
        public IBinder asBinder() {
            return null;
        }
    }
}