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

Commit 359bc335 authored by Rahul Banerjee's avatar Rahul Banerjee Committed by Automerger Merge Worker
Browse files

Merge "Migrate StatusBarKeyguardViewManager to Predictive Back" into...

Merge "Migrate StatusBarKeyguardViewManager to Predictive Back" into tm-qpr-dev am: fd0c9bfa am: 4bbf2a4d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20093581



Change-Id: I57795c92e1538ba75025749d98dbe6bc92e1a97d
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 671ad863 4bbf2a4d
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
@@ -3292,19 +3292,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()) {
@@ -3319,7 +3323,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
@@ -380,6 +401,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 */);
@@ -1026,25 +1087,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;
    }
@@ -1322,7 +1405,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);