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

Commit ba77df31 authored by Josh Tsuji's avatar Josh Tsuji Committed by Android (Google) Code Review
Browse files

Merge "After each test, verify that SysUI and WM states match."

parents e454344e 5d3eb299
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -39,9 +39,9 @@ import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTra
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.BroadcastOptions;
import android.app.IActivityTaskManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.WindowConfiguration;
@@ -1178,6 +1178,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

    private Lazy<ActivityLaunchAnimator> mActivityLaunchAnimator;
    private Lazy<ScrimController> mScrimControllerLazy;
    private IActivityTaskManager mActivityTaskManagerService;

    /**
     * Injected constructor. See {@link KeyguardModule}.
@@ -1209,7 +1210,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            Lazy<ShadeController> shadeControllerLazy,
            Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
            Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
            Lazy<ScrimController> scrimControllerLazy) {
            Lazy<ScrimController> scrimControllerLazy,
            IActivityTaskManager activityTaskManagerService) {
        mContext = context;
        mUserTracker = userTracker;
        mFalsingCollector = falsingCollector;
@@ -1257,6 +1259,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

        mActivityLaunchAnimator = activityLaunchAnimator;
        mScrimControllerLazy = scrimControllerLazy;
        mActivityTaskManagerService = activityTaskManagerService;

        mPowerButtonY = context.getResources().getDimensionPixelSize(
                R.dimen.physical_power_button_center_screen_location_y);
@@ -1800,12 +1803,17 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    }

    /**
     * Is the keyguard currently showing and not being force hidden?
     * Is the keyguard currently showing, and not occluded (no activity is drawing over the
     * lockscreen).
     */
    public boolean isShowingAndNotOccluded() {
        return mShowing && !mOccluded;
    }

    public boolean isShowing() {
        return mShowing;
    }

    public boolean isOccludeAnimationPlaying() {
        return mOccludeAnimationPlaying;
    }
@@ -2419,7 +2427,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
            }
            try {
                ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
                mActivityTaskManagerService.setLockScreenShown(showing, aodShowing);
            } catch (RemoteException e) {
            }
        });
@@ -2535,7 +2543,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            final int keyguardFlag = flags;
            mUiBgExecutor.execute(() -> {
                try {
                    ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag);
                    mActivityTaskManagerService.keyguardGoingAway(keyguardFlag);
                } catch (RemoteException e) {
                    Log.e(TAG, "Error while calling WindowManager", e);
                }
@@ -2868,7 +2876,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
            }

            ActivityTaskManager.getService().keyguardGoingAway(flags);
            mActivityTaskManagerService.keyguardGoingAway(flags);
            mKeyguardStateController.notifyKeyguardGoingAway(true);
        } catch (RemoteException e) {
            mSurfaceBehindRemoteAnimationRequested = false;
+5 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.keyguard.dagger;

import android.app.IActivityTaskManager;
import android.app.trust.TrustManager;
import android.content.Context;
import android.os.PowerManager;
@@ -119,7 +120,8 @@ public class KeyguardModule {
            Lazy<ShadeController> shadeController,
            Lazy<NotificationShadeWindowController> notificationShadeWindowController,
            Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
            Lazy<ScrimController> scrimControllerLazy) {
            Lazy<ScrimController> scrimControllerLazy,
            IActivityTaskManager activityTaskManagerService) {
        return new KeyguardViewMediator(
                context,
                userTracker,
@@ -149,7 +151,8 @@ public class KeyguardModule {
                shadeController,
                notificationShadeWindowController,
                activityLaunchAnimator,
                scrimControllerLazy);
                scrimControllerLazy,
                activityTaskManagerService);
    }

    /** */
+146 −32
Original line number Diff line number Diff line
@@ -25,21 +25,28 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -89,9 +96,12 @@ import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -131,6 +141,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
    private @Mock DreamOverlayStateController mDreamOverlayStateController;
    private @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
    private @Mock ScrimController mScrimController;
    private @Mock IActivityTaskManager mActivityTaskManagerService;
    private @Mock SysuiColorExtractor mColorExtractor;
    private @Mock AuthController mAuthController;
    private @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
@@ -142,6 +153,9 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {

    private @Mock CentralSurfaces mCentralSurfaces;

    /** Most recent value passed to {@link KeyguardStateController#notifyKeyguardGoingAway}. */
    private boolean mKeyguardGoingAway = false;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
@@ -163,9 +177,38 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {

        DejankUtils.setImmediate(true);

        // Keep track of what we told KeyguardStateController about whether we're going away or
        // not.
        mKeyguardGoingAway = false;
        doAnswer(invocation -> {
            mKeyguardGoingAway = invocation.getArgument(0);
            return null;
        }).when(mKeyguardStateController).notifyKeyguardGoingAway(anyBoolean());

        createAndStartViewMediator();
    }

    /**
     * After each test, verify that System UI's going away/showing state matches the most recent
     * calls we made to ATMS.
     *
     * This will help us catch showing and going away state mismatch issues.
     */
    @After
    public void assertATMSAndKeyguardViewMediatorStatesMatch() {
        try {
            if (mKeyguardGoingAway) {
                assertATMSKeyguardGoingAway();
            } else {
                assertATMSLockScreenShowing(mViewMediator.isShowing());
            }

        } catch (Exception e) {
            // Just so we don't have to add the exception signature to every test.
            fail();
        }
    }

    @Test
    public void testOnGoingToSleep_UpdatesKeyguardGoingAway() {
        mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
@@ -410,38 +453,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
    public void testStartKeyguardExitAnimation_expectSurfaceBehindRemoteAnimation() {
        startMockKeyguardExitAnimation();
        assertTrue(mViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind());
    }

    /**
     * Configures mocks appropriately, then starts the keyguard exit animation.
     */
    private void startMockKeyguardExitAnimation() {
        mViewMediator.onSystemReady();
        TestableLooper.get(this).processAllMessages();

        mViewMediator.setShowingLocked(true);

        RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
                mock(RemoteAnimationTarget.class)
        };
        RemoteAnimationTarget[] wallpapers = new RemoteAnimationTarget[]{
                mock(RemoteAnimationTarget.class)
        };
        IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);

        when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
        mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
                null, callback);
        TestableLooper.get(this).processAllMessages();
    }

    /**
     * Configures mocks appropriately, then cancels the keyguard exit animation.
     */
    private void cancelMockKeyguardExitAnimation() {
        when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
        mViewMediator.cancelKeyguardExitAnimation();
        TestableLooper.get(this).processAllMessages();
    }

    @Test
@@ -515,6 +527,107 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
        verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean());
    }

    @Test
    @TestableLooper.RunWithLooper(setAsMainLooper = true)
    public void testStartKeyguardExitAnimation_thenCancelImmediately_doesNotResetAndUpdatesWM() {
        startMockKeyguardExitAnimation();
        cancelMockKeyguardExitAnimation();

        // This will trigger doKeyguardLocked and we can verify that we ask ATMS to show the
        // keyguard explicitly, even though we're already showing, because we cancelled immediately.
        mViewMediator.onSystemReady();
        reset(mActivityTaskManagerService);
        processAllMessagesAndBgExecutorMessages();

        verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean());
        assertATMSAndKeyguardViewMediatorStatesMatch();
    }

    /**
     * Interactions with the ActivityTaskManagerService and others are posted to an executor that
     * doesn't use the testable looper. Use this method to ensure those are run as well.
     */
    private void processAllMessagesAndBgExecutorMessages() {
        TestableLooper.get(this).processAllMessages();
        mUiBgExecutor.runAllReady();
    }

    /**
     * Configures mocks appropriately, then starts the keyguard exit animation.
     */
    private void startMockKeyguardExitAnimation() {
        mViewMediator.onSystemReady();
        processAllMessagesAndBgExecutorMessages();

        mViewMediator.setShowingLocked(true);

        RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
                mock(RemoteAnimationTarget.class)
        };
        RemoteAnimationTarget[] wallpapers = new RemoteAnimationTarget[]{
                mock(RemoteAnimationTarget.class)
        };
        IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);

        when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
        mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
                null, callback);
        processAllMessagesAndBgExecutorMessages();
    }

    /**
     * Configures mocks appropriately, then cancels the keyguard exit animation.
     */
    private void cancelMockKeyguardExitAnimation() {
        when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false);
        mViewMediator.cancelKeyguardExitAnimation();
        processAllMessagesAndBgExecutorMessages();
    }
    /**
     * Asserts the last value passed to ATMS#setLockScreenShown. This should be confirmed alongside
     * {@link KeyguardViewMediator#isShowingAndNotOccluded()} to verify that state is not mismatched
     * between SysUI and WM.
     */
    private void assertATMSLockScreenShowing(boolean showing)
            throws RemoteException {
        // ATMS is called via bgExecutor, so make sure to run all of those calls first.
        processAllMessagesAndBgExecutorMessages();

        final InOrder orderedSetLockScreenShownCalls = inOrder(mActivityTaskManagerService);
        final ArgumentCaptor<Boolean> showingCaptor = ArgumentCaptor.forClass(Boolean.class);
        orderedSetLockScreenShownCalls
                .verify(mActivityTaskManagerService, atLeastOnce())
                .setLockScreenShown(showingCaptor.capture(), anyBoolean());

        // The captor will have the most recent setLockScreenShown call's value.
        assertEquals(showing, showingCaptor.getValue());

        // We're now just after the last setLockScreenShown call. If we expect the lockscreen to be
        // showing, ensure that we didn't subsequently ask for it to go away.
        if (showing) {
            orderedSetLockScreenShownCalls.verify(mActivityTaskManagerService, never())
                    .keyguardGoingAway(anyInt());
        }
    }

    /**
     * Asserts that we eventually called ATMS#keyguardGoingAway and did not subsequently call
     * ATMS#setLockScreenShown(true) which would cancel the going away.
     */
    private void assertATMSKeyguardGoingAway() throws RemoteException {
        // ATMS is called via bgExecutor, so make sure to run all of those calls first.
        processAllMessagesAndBgExecutorMessages();

        final InOrder orderedGoingAwayCalls = inOrder(mActivityTaskManagerService);
        orderedGoingAwayCalls.verify(mActivityTaskManagerService, atLeastOnce())
                .keyguardGoingAway(anyInt());

        // Advance the inOrder to just past the last goingAway call. Let's make sure we didn't
        // re-show the lockscreen, which would cancel going away.
        orderedGoingAwayCalls.verify(mActivityTaskManagerService, never())
                .setLockScreenShown(eq(true), anyBoolean());
    }

    private void createAndStartViewMediator() {
        mViewMediator = new KeyguardViewMediator(
                mContext,
@@ -545,7 +658,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
                () -> mShadeController,
                () -> mNotificationShadeWindowController,
                () -> mActivityLaunchAnimator,
                () -> mScrimController);
                () -> mScrimController,
                mActivityTaskManagerService);
        mViewMediator.start();

        mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);