Merge "Prevent callback registration when back flag is disabled" into tm-dev

This commit is contained in:
Vadim Caen
2022-06-20 18:53:00 +00:00
committed by Android (Google) Code Review
10 changed files with 113 additions and 27 deletions

View File

@@ -1482,8 +1482,6 @@ public class Dialog implements DialogInterface, Window.Callback,
/**
* Returns the {@link OnBackInvokedDispatcher} instance associated with the window that this
* dialog is attached to.
*
* Returns null if the dialog is not attached to a window with a decor.
*/
@NonNull
public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {

View File

@@ -135,6 +135,7 @@ import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.window.CompatOnBackInvokedCallback;
import android.window.ImeOnBackInvokedDispatcher;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
@@ -350,7 +351,7 @@ public class InputMethodService extends AbstractInputMethodService {
private RingBuffer<MotionEvent> mPendingEvents;
private ImeOnBackInvokedDispatcher mImeDispatcher;
private Boolean mBackCallbackRegistered = false;
private final OnBackInvokedCallback mCompatBackCallback = this::compatHandleBack;
private final CompatOnBackInvokedCallback mCompatBackCallback = this::compatHandleBack;
/**
* Returns whether {@link InputMethodService} is responsible for rendering the back button and

View File

@@ -196,6 +196,7 @@ import android.view.contentcapture.MainContentCaptureSession;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
import android.window.ClientWindowFrames;
import android.window.CompatOnBackInvokedCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.SurfaceSyncer;
@@ -339,13 +340,12 @@ public final class ViewRootImpl implements ViewParent,
/**
* The top level {@link OnBackInvokedDispatcher}.
*/
private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher =
new WindowOnBackInvokedDispatcher();
private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
/**
* Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events
* to view root for apps using legacy back behavior.
*/
private OnBackInvokedCallback mCompatOnBackInvokedCallback;
private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback;
/**
* Callback for notifying about global configuration changes.
@@ -959,6 +959,8 @@ public final class ViewRootImpl implements ViewParent,
mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(
context.getApplicationInfo().isOnBackInvokedCallbackEnabled());
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -10836,13 +10838,6 @@ public final class ViewRootImpl implements ViewParent,
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
}
private void unregisterCompatOnBackInvokedCallback() {
if (mCompatOnBackInvokedCallback != null) {
mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mCompatOnBackInvokedCallback);
mCompatOnBackInvokedCallback = null;
}
}
@Override
public void setTouchableRegion(Region r) {
if (r != null) {

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.window;
/**
* Marker interface for {@link OnBackInvokedCallback} used for backward compatibility between the
* new system back and the old back event dispatching. Callbacks implementing this interface are
* allowed to be registered even if <code>enableOnbackInvoked</code> is set to false in the
* application manifest.
* @hide
*/
public interface CompatOnBackInvokedCallback extends OnBackInvokedCallback{
@Override
void onBackInvoked();
}

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
import android.util.Pair;
import android.window.WindowOnBackInvokedDispatcher.Checker;
import java.util.ArrayList;
import java.util.List;
@@ -50,6 +51,11 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private final Object mLock = new Object();
private OnBackInvokedDispatcher mActualDispatcher = null;
private ImeOnBackInvokedDispatcher mImeDispatcher;
private final Checker mChecker;
public ProxyOnBackInvokedDispatcher(boolean applicationCallBackEnabled) {
mChecker = new Checker(applicationCallBackEnabled);
}
@Override
public void registerOnBackInvokedCallback(
@@ -58,11 +64,9 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
Log.v(TAG, String.format("Proxy register %s. mActualDispatcher=%s", callback,
mActualDispatcher));
}
if (priority < 0) {
throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+ "cannot have negative priority. Priority: " + priority);
if (mChecker.checkApplicationCallbackRegistration(priority, callback)) {
registerOnBackInvokedCallbackUnchecked(callback, priority);
}
registerOnBackInvokedCallbackUnchecked(callback, priority);
}
@Override

View File

@@ -30,6 +30,7 @@ import android.view.IWindowSession;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
/**
@@ -62,6 +63,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
/** Holds all callbacks by priorities. */
private final TreeMap<Integer, ArrayList<OnBackInvokedCallback>>
mOnBackInvokedCallbacks = new TreeMap<>();
private final Checker mChecker;
public WindowOnBackInvokedDispatcher(boolean applicationCallBackEnabled) {
mChecker = new Checker(applicationCallBackEnabled);
}
/**
* Sends the pending top callback (if one exists) to WM when the view root
@@ -86,14 +92,16 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@Override
public void registerOnBackInvokedCallback(
@Priority int priority, @NonNull OnBackInvokedCallback callback) {
if (priority < 0) {
throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+ "cannot have negative priority. Priority: " + priority);
if (mChecker.checkApplicationCallbackRegistration(priority, callback)) {
registerOnBackInvokedCallbackUnchecked(callback, priority);
}
registerOnBackInvokedCallbackUnchecked(callback, priority);
}
private void registerOnBackInvokedCallbackUnchecked(
/**
* Register a callback bypassing platform checks. This is used to register compatibility
* callbacks.
*/
public void registerOnBackInvokedCallbackUnchecked(
@NonNull OnBackInvokedCallback callback, @Priority int priority) {
if (mImeDispatcher != null) {
mImeDispatcher.registerOnBackInvokedCallback(priority, callback);
@@ -203,6 +211,14 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
return null;
}
/**
* Returns the checker used to check whether a callback can be registered
*/
@NonNull
public Checker getChecker() {
return mChecker;
}
static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
private final WeakReference<OnBackInvokedCallback> mCallback;
@@ -289,4 +305,41 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
mImeDispatcher = imeDispatcher;
}
/**
* Class used to check whether a callback can be registered or not. This is meant to be
* shared with {@link ProxyOnBackInvokedDispatcher} which needs to do the same checks.
*/
public static class Checker {
private final boolean mApplicationCallBackEnabled;
public Checker(boolean applicationCallBackEnabled) {
mApplicationCallBackEnabled = applicationCallBackEnabled;
}
/**
* Checks whether the given callback can be registered with the given priority.
* @return true if the callback can be added.
* @throws IllegalArgumentException if the priority is negative.
*/
public boolean checkApplicationCallbackRegistration(int priority,
OnBackInvokedCallback callback) {
if (!mApplicationCallBackEnabled
&& !(callback instanceof CompatOnBackInvokedCallback)) {
Log.w("OnBackInvokedCallback",
"OnBackInvokedCallback is not enabled for the application."
+ "\nSet 'android:enableOnBackInvokedCallback=\"true\"' in the"
+ " application manifest.");
return false;
}
if (priority < 0) {
throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+ "cannot have negative priority. Priority: " + priority);
}
Objects.requireNonNull(callback);
return true;
}
}
}

View File

@@ -342,8 +342,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
boolean mDecorFitsSystemWindows = true;
private final ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher =
new ProxyOnBackInvokedDispatcher();
private final ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher;
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -358,6 +357,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mLayoutInflater = LayoutInflater.from(context);
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
mProxyOnBackInvokedDispatcher = new ProxyOnBackInvokedDispatcher(
context.getApplicationInfo().isOnBackInvokedCallbackEnabled());
}
/**

View File

@@ -161,7 +161,10 @@
<!-- ChooserActivityTest permissions-->
<uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
<application android:theme="@style/Theme" android:supportsRtl="true">
<application
android:theme="@style/Theme"
android:supportsRtl="true"
android:enableOnBackInvokedCallback="true">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<meta-data

View File

@@ -64,7 +64,7 @@ public class WindowOnBackInvokedDispatcherTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mDispatcher = new WindowOnBackInvokedDispatcher();
mDispatcher = new WindowOnBackInvokedDispatcher(true /* applicationCallbackEnabled */);
mDispatcher.attachToWindow(mWindowSession, mWindow);
}

View File

@@ -181,7 +181,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
Task task = createTopTaskWithActivity();
WindowState appWindow = task.getTopVisibleAppMainWindow();
WindowOnBackInvokedDispatcher dispatcher = new WindowOnBackInvokedDispatcher();
WindowOnBackInvokedDispatcher dispatcher =
new WindowOnBackInvokedDispatcher(true /* applicationCallbackEnabled */);
doAnswer(invocation -> {
appWindow.setOnBackInvokedCallbackInfo(invocation.getArgument(1));
return null;