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

Commit 6ce8c4a9 authored by Arthur Hung's avatar Arthur Hung Committed by Automerger Merge Worker
Browse files

Merge "Ignore back invoke when window focus has lost" into tm-qpr-dev am: 14768734

parents d1525033 14768734
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3761,6 +3761,7 @@ public final class ViewRootImpl implements ViewParent,
            }
        }
        mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
        mOnBackInvokedDispatcher.onWindowFocusChanged(hasWindowFocus);

        // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
        // is lost, so we don't need to to force a flush - there might be other events such as
+3 −1
Original line number Diff line number Diff line
@@ -81,8 +81,10 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc
            @OnBackInvokedDispatcher.Priority int priority,
            @NonNull OnBackInvokedCallback callback) {
        final Bundle bundle = new Bundle();
        // Always invoke back for ime without checking the window focus.
        final IOnBackInvokedCallback iCallback =
                new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(callback);
                new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(callback,
                        () -> true);
        bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder());
        bundle.putInt(RESULT_KEY_PRIORITY, priority);
        bundle.putInt(RESULT_KEY_ID, callback.hashCode());
+22 −4
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Supplier;

/**
 * Provides window based implementation of {@link OnBackInvokedDispatcher}.
@@ -64,6 +65,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    private final TreeMap<Integer, ArrayList<OnBackInvokedCallback>>
            mOnBackInvokedCallbacks = new TreeMap<>();
    private final Checker mChecker;
    private boolean mHasFocus;

    public WindowOnBackInvokedDispatcher(boolean applicationCallBackEnabled) {
        mChecker = new Checker(applicationCallBackEnabled);
@@ -189,7 +191,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                                    .ImeOnBackInvokedCallback
                                ? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
                                        callback).getIOnBackInvokedCallback()
                                : new OnBackInvokedCallbackWrapper(callback);
                                : new OnBackInvokedCallbackWrapper(callback, this::hasFocus);
                callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority);
            }
            mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo);
@@ -198,6 +200,17 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        }
    }

    /**
     * Called when window focus changed.
     */
    public void onWindowFocusChanged(boolean hasFocus) {
        mHasFocus = hasFocus;
    }

    private boolean hasFocus() {
        return mHasFocus;
    }

    public OnBackInvokedCallback getTopCallback() {
        if (mAllCallbacks.isEmpty()) {
            return null;
@@ -221,9 +234,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {

    static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
        private final WeakReference<OnBackInvokedCallback> mCallback;

        OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) {
        private final Supplier<Boolean> mHasFocus;
        OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback,
                @NonNull Supplier<Boolean> hasFocus) {
            mCallback = new WeakReference<>(callback);
            mHasFocus = hasFocus;
        }

        @Override
@@ -263,7 +278,10 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                if (callback == null) {
                    return;
                }

                if (!mHasFocus.get()) {
                    Log.w(TAG, "Skip back invoke due to current focus has lost.");
                    return;
                }
                callback.onBackInvoked();
            });
        }
+28 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ public class WindowOnBackInvokedDispatcherTest {
        MockitoAnnotations.initMocks(this);
        mDispatcher = new WindowOnBackInvokedDispatcher(true /* applicationCallbackEnabled */);
        mDispatcher.attachToWindow(mWindowSession, mWindow);
        mDispatcher.onWindowFocusChanged(true);
    }

    private void waitForIdle() {
@@ -152,4 +153,31 @@ public class WindowOnBackInvokedDispatcherTest {
        waitForIdle();
        verify(mCallback2).onBackStarted();
    }

    @Test
    public void skipBackInvokeWhenNoFocus() throws RemoteException {
        ArgumentCaptor<OnBackInvokedCallbackInfo> captor =
                ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class);

        mDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);

        verify(mWindowSession, times(1)).setOnBackInvokedCallbackInfo(
                Mockito.eq(mWindow),
                captor.capture());

        verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture());

        // Should invoke back if it's still in focused.
        captor.getValue().getCallback().onBackInvoked();
        waitForIdle();
        verify(mCallback1).onBackInvoked();

        // In case the focus has lost during back gesture.
        mDispatcher.onWindowFocusChanged(false);

        captor.getValue().getCallback().onBackInvoked();
        waitForIdle();
        verifyZeroInteractions(mCallback1);
    }
}