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

Commit b1c7838d authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Automerger Merge Worker
Browse files

Merge "Do not animate dialogs into activites when locked (1/n)" into tm-qpr-dev am: 4dd23413

parents 950a202d 4dd23413
Loading
Loading
Loading
Loading
+27 −7
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.app.Dialog
import android.graphics.Color
import android.graphics.Rect
import android.os.Looper
import android.service.dreams.IDreamManager
import android.util.Log
import android.util.MathUtils
import android.view.GhostView
@@ -54,7 +53,7 @@ private const val TAG = "DialogLaunchAnimator"
class DialogLaunchAnimator
@JvmOverloads
constructor(
    private val dreamManager: IDreamManager,
    private val callback: Callback,
    private val interactionJankMonitor: InteractionJankMonitor,
    private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS),
    private val isForTesting: Boolean = false
@@ -126,7 +125,7 @@ constructor(
        val animatedDialog =
            AnimatedDialog(
                launchAnimator,
                dreamManager,
                callback,
                interactionJankMonitor,
                animateFrom,
                onDialogDismissed = { openedDialogs.remove(it) },
@@ -194,8 +193,12 @@ constructor(

        val dialog = animatedDialog.dialog

        // Don't animate if the dialog is not showing.
        if (!dialog.isShowing) {
        // Don't animate if the dialog is not showing or if we are locked and going to show the
        // bouncer.
        if (
            !dialog.isShowing ||
            (!callback.isUnlocked() && !callback.isShowingAlternateAuthOnUnlock())
        ) {
            return null
        }

@@ -285,6 +288,23 @@ constructor(
            ?.let { it.touchSurface = it.prepareForStackDismiss() }
        dialog.dismiss()
    }

    interface Callback {
        /** Whether the device is currently in dreaming (screensaver) mode. */
        fun isDreaming(): Boolean

        /**
         * Whether the device is currently unlocked, i.e. if it is *not* on the keyguard or if the
         * keyguard can be dismissed.
         */
        fun isUnlocked(): Boolean

        /**
         * Whether we are going to show alternate authentication (like UDFPS) instead of the
         * traditional bouncer when unlocking the device.
         */
        fun isShowingAlternateAuthOnUnlock(): Boolean
    }
}

/**
@@ -296,7 +316,7 @@ data class DialogCuj(@CujType val cujType: Int, val tag: String? = null)

private class AnimatedDialog(
    private val launchAnimator: LaunchAnimator,
    private val dreamManager: IDreamManager,
    private val callback: DialogLaunchAnimator.Callback,
    private val interactionJankMonitor: InteractionJankMonitor,

    /** The view that triggered the dialog after being tapped. */
@@ -850,7 +870,7 @@ private class AnimatedDialog(

        // If we are dreaming, the dialog was probably closed because of that so we don't animate
        // into the touchSurface.
        if (dreamManager.isDreaming) {
        if (callback.isDreaming()) {
            return false
        }

+28 −1
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.systemui.statusbar.dagger;
import android.app.IActivityManager;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
import android.util.Log;

import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.statusbar.IStatusBarService;
@@ -60,10 +62,12 @@ import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconList;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallFlags;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tracing.ProtoTracer;
@@ -274,7 +278,30 @@ public interface CentralSurfacesDependenciesModule {
    @Provides
    @SysUISingleton
    static DialogLaunchAnimator provideDialogLaunchAnimator(IDreamManager dreamManager,
            KeyguardStateController keyguardStateController,
            Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManager,
            InteractionJankMonitor interactionJankMonitor) {
        return new DialogLaunchAnimator(dreamManager, interactionJankMonitor);
        DialogLaunchAnimator.Callback callback = new DialogLaunchAnimator.Callback() {
            @Override
            public boolean isDreaming() {
                try {
                    return dreamManager.isDreaming();
                } catch (RemoteException e) {
                    Log.e("DialogLaunchAnimator.Callback", "dreamManager.isDreaming failed", e);
                    return false;
                }
            }

            @Override
            public boolean isUnlocked() {
                return keyguardStateController.isUnlocked();
            }

            @Override
            public boolean isShowingAlternateAuthOnUnlock() {
                return statusBarKeyguardViewManager.get().shouldShowAltAuth();
            }
        };
        return new DialogLaunchAnimator(callback, interactionJankMonitor);
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -471,7 +471,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
        showBouncer(scrimmed);
    }

    private boolean shouldShowAltAuth() {
    /** Whether we should show the alternate authentication instead of the traditional bouncer. */
    public boolean shouldShowAltAuth() {
        return mAlternateAuthInterceptor != null
                && mKeyguardUpdateManager.isUnlockingWithBiometricAllowed(true);
    }
+29 −17
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
import junit.framework.Assert.assertTrue
import junit.framework.AssertionFailedError
import kotlin.concurrent.thread
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -34,19 +35,18 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import kotlin.concurrent.thread

@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class ActivityLaunchAnimatorTest : SysuiTestCase() {
    private val launchContainer = LinearLayout(mContext)
    private val testLaunchAnimator = LaunchAnimator(TEST_TIMINGS, TEST_INTERPOLATORS)
    private val testLaunchAnimator = fakeLaunchAnimator()
    @Mock lateinit var callback: ActivityLaunchAnimator.Callback
    @Mock lateinit var listener: ActivityLaunchAnimator.Listener
    @Spy private val controller = TestLaunchAnimatorController(launchContainer)
@@ -82,7 +82,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
                    animate = animate,
                    intentStarter = intentStarter
                )
        }.join()
            }
            .join()
    }

    @Test
@@ -197,14 +198,25 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
        val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
        val taskInfo = ActivityManager.RunningTaskInfo()
        taskInfo.topActivity = ComponentName("com.android.systemui", "FakeActivity")
        taskInfo.topActivityInfo = ActivityInfo().apply {
            applicationInfo = ApplicationInfo()
        }
        taskInfo.topActivityInfo = ActivityInfo().apply { applicationInfo = ApplicationInfo() }

        return RemoteAnimationTarget(
                0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
                Point(), Rect(), bounds, WindowConfiguration(), false, SurfaceControl(), Rect(),
                taskInfo, false
            0,
            RemoteAnimationTarget.MODE_OPENING,
            SurfaceControl(),
            false,
            Rect(),
            Rect(),
            0,
            Point(),
            Rect(),
            bounds,
            WindowConfiguration(),
            false,
            SurfaceControl(),
            Rect(),
            taskInfo,
            false
        )
    }
}
@@ -213,10 +225,10 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
 * A simple implementation of [ActivityLaunchAnimator.Controller] which throws if it is called
 * outside of the main thread.
 */
private class TestLaunchAnimatorController(
    override var launchContainer: ViewGroup
) : ActivityLaunchAnimator.Controller {
    override fun createAnimatorState() = LaunchAnimator.State(
private class TestLaunchAnimatorController(override var launchContainer: ViewGroup) :
    ActivityLaunchAnimator.Controller {
    override fun createAnimatorState() =
        LaunchAnimator.State(
            top = 100,
            bottom = 200,
            left = 300,
+22 −8
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.service.dreams.IDreamManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
@@ -38,19 +37,16 @@ import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class DialogLaunchAnimatorTest : SysuiTestCase() {
    private val launchAnimator = LaunchAnimator(TEST_TIMINGS, TEST_INTERPOLATORS)
    private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
    private val attachedViews = mutableSetOf<View>()

    @Mock lateinit var dreamManager: IDreamManager
    @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
    @get:Rule val rule = MockitoJUnit.rule()

    @Before
    fun setUp() {
        dialogLaunchAnimator = DialogLaunchAnimator(
            dreamManager, interactionJankMonitor, launchAnimator, isForTesting = true
        )
        dialogLaunchAnimator =
            fakeDialogLaunchAnimator(interactionJankMonitor = interactionJankMonitor)
    }

    @After
@@ -152,6 +148,22 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
        assertNull(dialogLaunchAnimator.createActivityLaunchController(dialog.contentView))
    }

    @Test
    fun testActivityLaunchWhenLockedWithoutAlternateAuth() {
        val dialogLaunchAnimator =
            fakeDialogLaunchAnimator(isUnlocked = false, isShowingAlternateAuthOnUnlock = false)
        val dialog = createAndShowDialog(dialogLaunchAnimator)
        assertNull(dialogLaunchAnimator.createActivityLaunchController(dialog.contentView))
    }

    @Test
    fun testActivityLaunchWhenLockedWithAlternateAuth() {
        val dialogLaunchAnimator =
            fakeDialogLaunchAnimator(isUnlocked = false, isShowingAlternateAuthOnUnlock = true)
        val dialog = createAndShowDialog(dialogLaunchAnimator)
        assertNotNull(dialogLaunchAnimator.createActivityLaunchController(dialog.contentView))
    }

    @Test
    fun testDialogAnimationIsChangedByAnimator() {
        // Important: the power menu animation relies on this behavior to know when to animate (see
@@ -193,11 +205,13 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
        verify(interactionJankMonitor).end(InteractionJankMonitor.CUJ_USER_DIALOG_OPEN)
    }

    private fun createAndShowDialog(): TestDialog {
    private fun createAndShowDialog(
        animator: DialogLaunchAnimator = dialogLaunchAnimator,
    ): TestDialog {
        val touchSurface = createTouchSurface()
        return runOnMainThreadAndWaitForIdleSync {
            val dialog = TestDialog(context)
            dialogLaunchAnimator.showFromView(dialog, touchSurface)
            animator.showFromView(dialog, touchSurface)
            dialog
        }
    }
Loading