Merge "Ignore back invoke when window focus has lost" into tm-qpr-dev
This commit is contained in:
@@ -3759,6 +3759,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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user