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

Commit fd0c9bfa authored by Rahul Banerjee's avatar Rahul Banerjee Committed by Android (Google) Code Review
Browse files

Merge "Migrate StatusBarKeyguardViewManager to Predictive Back" into tm-qpr-dev

parents 8ae63801 9d8a96e3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -416,6 +416,9 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn

    void endAffordanceLaunch();

    /** Should the keyguard be hidden immediately in response to a back press/gesture. */
    boolean shouldKeyguardHideImmediately();

    boolean onBackPressed();

    boolean onSpacePressed();
+13 −9
Original line number Diff line number Diff line
@@ -3312,19 +3312,23 @@ public class CentralSurfacesImpl extends CoreStartable implements
        mNotificationPanelViewController.onAffordanceLaunchEnded();
    }

    /**
     * Returns whether the keyguard should hide immediately (as opposed to via an animation).
     * Non-scrimmed bouncers have a special animation tied to the notification panel expansion.
     * @return whether the keyguard should be immediately hidden.
     */
    @Override
    public boolean onBackPressed() {
    public boolean shouldKeyguardHideImmediately() {
        final boolean isScrimmedBouncer =
                mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
        final boolean isBouncerOverDream = isBouncerShowingOverDream();

        if (mStatusBarKeyguardViewManager.onBackPressed(
                isScrimmedBouncer || isBouncerOverDream /* hideImmediately */)) {
            if (isScrimmedBouncer || isBouncerOverDream) {
                mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
            } else {
                mNotificationPanelViewController.expandWithoutQs();
        return (isScrimmedBouncer || isBouncerOverDream);
    }

    @Override
    public boolean onBackPressed() {
        if (mStatusBarKeyguardViewManager.canHandleBackPressed()) {
            mStatusBarKeyguardViewManager.onBackPressed(false /* unused */);
            return true;
        }
        if (mNotificationPanelViewController.isQsCustomizing()) {
@@ -3339,7 +3343,7 @@ public class CentralSurfacesImpl extends CoreStartable implements
            return true;
        }
        if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
                && !isBouncerOverDream) {
                && !isBouncerShowingOverDream()) {
            if (mNotificationPanelViewController.canPanelBeCollapsed()) {
                mShadeController.animateCollapsePanels();
            }
+107 −16
Original line number Diff line number Diff line
@@ -31,12 +31,15 @@ import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -119,6 +122,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;

    private static String TAG = "StatusBarKeyguardViewManager";
    private static final boolean DEBUG = false;

    protected final Context mContext;
    private final ConfigurationController mConfigurationController;
@@ -184,8 +188,25 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
            if (mAlternateAuthInterceptor != null) {
                mAlternateAuthInterceptor.onBouncerVisibilityChanged();
            }

            /* Register predictive back callback when keyguard becomes visible, and unregister
            when it's hidden. */
            if (isVisible) {
                registerBackCallback();
            } else {
                unregisterBackCallback();
            }
        }
    };

    private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
        if (DEBUG) {
            Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
        }
        onBackPressed(false /* unused */);
    };
    private boolean mIsBackCallbackRegistered = false;

    private final DockManager.DockEventListener mDockEventListener =
            new DockManager.DockEventListener() {
                @Override
@@ -378,6 +399,46 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
        }
    }

    /** Register a callback, to be invoked by the Predictive Back system. */
    private void registerBackCallback() {
        if (!mIsBackCallbackRegistered) {
            ViewRootImpl viewRoot = getViewRootImpl();
            if (viewRoot != null) {
                viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
                        OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
                mIsBackCallbackRegistered = true;
            } else {
                if (DEBUG) {
                    Log.d(TAG, "view root was null, could not register back callback");
                }
            }
        } else {
            if (DEBUG) {
                Log.d(TAG, "prevented registering back callback twice");
            }
        }
    }

    /** Unregister the callback formerly registered with the Predictive Back system. */
    private void unregisterBackCallback() {
        if (mIsBackCallbackRegistered) {
            ViewRootImpl viewRoot = getViewRootImpl();
            if (viewRoot != null) {
                viewRoot.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
                        mOnBackInvokedCallback);
                mIsBackCallbackRegistered = false;
            } else {
                if (DEBUG) {
                    Log.d(TAG, "view root was null, could not unregister back callback");
                }
            }
        } else {
            if (DEBUG) {
                Log.d(TAG, "prevented unregistering back callback twice");
            }
        }
    }

    @Override
    public void onDensityOrFontScaleChanged() {
        hideBouncer(true /* destroyView */);
@@ -1025,25 +1086,47 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
    }

    /**
     * Notifies this manager that the back button has been pressed.
     * Returns whether a back invocation can be handled, which depends on whether the keyguard
     * is currently showing (which itself is derived from multiple states).
     *
     * @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise.
     *                        Non-scrimmed bouncers have a special animation tied to the expansion
     *                        of the notification panel.
     * @return whether the back press has been handled
     * @return whether a back press can be handled right now.
     */
    public boolean onBackPressed(boolean hideImmediately) {
        if (bouncerIsShowing()) {
    public boolean canHandleBackPressed() {
        return mBouncer.isShowing();
    }

    /**
     * Notifies this manager that the back button has been pressed.
     */
    // TODO(b/244635782): This "accept boolean and ignore it, and always return false" was done
    //                    to make it possible to check this in *and* allow merging to master,
    //                    where ArcStatusBarKeyguardViewManager inherits this class, and its
    //                    build will break if we change this interface.
    //                    So, overall, while this function refactors the behavior of onBackPressed,
    //                    (it now handles the back press, and no longer returns *whether* it did so)
    //                    its interface is not changing right now (but will, in a follow-up CL).
    public boolean onBackPressed(boolean ignored) {
        if (!canHandleBackPressed()) {
            return false;
        }

        mCentralSurfaces.endAffordanceLaunch();
        // The second condition is for SIM card locked bouncer
            if (bouncerIsScrimmed()
                    && !needsFullscreenBouncer()) {
        if (bouncerIsScrimmed() && needsFullscreenBouncer()) {
            hideBouncer(false);
            updateStates();
        } else {
            /* Non-scrimmed bouncers have a special animation tied to the expansion
             * of the notification panel. We decide whether to kick this animation off
             * by computing the hideImmediately boolean.
             */
            boolean hideImmediately = mCentralSurfaces.shouldKeyguardHideImmediately();
            reset(hideImmediately);
            if (hideImmediately) {
                mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
            } else {
                mNotificationPanelViewController.expandWithoutQs();
            }
            return true;
        }
        return false;
    }
@@ -1318,7 +1401,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb

    @Override
    public ViewRootImpl getViewRootImpl() {
        return mNotificationShadeWindowController.getNotificationShadeView().getViewRootImpl();
        ViewGroup viewGroup = mNotificationShadeWindowController.getNotificationShadeView();
        if (viewGroup != null) {
            return viewGroup.getViewRootImpl();
        } else {
            if (DEBUG) {
                Log.d(TAG, "ViewGroup was null, cannot get ViewRootImpl");
            }
            return null;
        }
    }

    public void launchPendingWakeupAction() {
+50 −1
Original line number Diff line number Diff line
@@ -35,6 +35,10 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.WindowOnBackInvokedDispatcher;

import androidx.test.filters.SmallTest;

@@ -73,6 +77,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -119,6 +124,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback;

    @Mock private ViewRootImpl mViewRootImpl;
    @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
    @Captor
    private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -154,7 +165,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
                        mFeatureFlags,
                        mBouncerCallbackInteractor,
                        mBouncerInteractor,
                        mBouncerView);
                        mBouncerView) {
                    @Override
                    public ViewRootImpl getViewRootImpl() {
                        return mViewRootImpl;
                    }
                };
        when(mViewRootImpl.getOnBackInvokedDispatcher())
                .thenReturn(mOnBackInvokedDispatcher);
        mStatusBarKeyguardViewManager.registerCentralSurfaces(
                mCentralSurfaces,
                mNotificationPanelView,
@@ -508,6 +526,37 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
                fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
    }

    @Test
    public void testPredictiveBackCallback_registration() {
        /* verify that a predictive back callback is registered when the bouncer becomes visible */
        mBouncerExpansionCallback.onVisibilityChanged(true);
        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
                mOnBackInvokedCallback.capture());

        /* verify that the same callback is unregistered when the bouncer becomes invisible */
        mBouncerExpansionCallback.onVisibilityChanged(false);
        verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
                eq(mOnBackInvokedCallback.getValue()));
    }

    @Test
    public void testPredictiveBackCallback_invocationHidesBouncer() {
        mBouncerExpansionCallback.onVisibilityChanged(true);
        /* capture the predictive back callback during registration */
        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
                mOnBackInvokedCallback.capture());

        when(mBouncer.isShowing()).thenReturn(true);
        when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
        /* invoke the back callback directly */
        mOnBackInvokedCallback.getValue().onBackInvoked();

        /* verify that the bouncer will be hidden as a result of the invocation */
        verify(mCentralSurfaces).setBouncerShowing(eq(false));
    }

    @Test
    public void testReportBouncerOnDreamWhenVisible() {
        mBouncerExpansionCallback.onVisibilityChanged(true);