Merge "Ignore back invoke when window focus has lost" into tm-qpr-dev am: 1476873423
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19291068 Change-Id: I30d3f47a89bae0fb6aa768fa00d2cd8b9c3c0f28 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -3761,6 +3761,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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user