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

Commit 14768734 authored by Arthur Hung's avatar Arthur Hung Committed by Android (Google) Code Review
Browse files

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

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


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


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


    public WindowOnBackInvokedDispatcher(boolean applicationCallBackEnabled) {
    public WindowOnBackInvokedDispatcher(boolean applicationCallBackEnabled) {
        mChecker = new Checker(applicationCallBackEnabled);
        mChecker = new Checker(applicationCallBackEnabled);
@@ -189,7 +191,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                                    .ImeOnBackInvokedCallback
                                    .ImeOnBackInvokedCallback
                                ? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
                                ? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
                                        callback).getIOnBackInvokedCallback()
                                        callback).getIOnBackInvokedCallback()
                                : new OnBackInvokedCallbackWrapper(callback);
                                : new OnBackInvokedCallbackWrapper(callback, this::hasFocus);
                callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority);
                callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority);
            }
            }
            mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo);
            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() {
    public OnBackInvokedCallback getTopCallback() {
        if (mAllCallbacks.isEmpty()) {
        if (mAllCallbacks.isEmpty()) {
            return null;
            return null;
@@ -221,9 +234,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {


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

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


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

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


    private void waitForIdle() {
    private void waitForIdle() {
@@ -152,4 +153,31 @@ public class WindowOnBackInvokedDispatcherTest {
        waitForIdle();
        waitForIdle();
        verify(mCallback2).onBackStarted();
        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);
    }
}
}