Prevent callback registration when back flag is disabled
When the enableOnBackInvokedCallback is set to false (or not set), registering an OnBackInvokedCallback should be a no-op to avoid overriding the default compat callback. Test: Manual testing registering a callback on an app with the flag disabled and doing a back gesture. Currently we don't have test executing a back gesture so automated tests are not possible Bug: 235206960 Change-Id: I54d843f11130a78ed5a68cbe4722e601a2086ee1
This commit is contained in:
@@ -800,6 +800,7 @@ package android.content.pm {
|
||||
|
||||
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
|
||||
method public boolean hasRequestForegroundServiceExemption();
|
||||
method public boolean isOnBackInvokedCallbackEnabled();
|
||||
method public boolean isPrivilegedApp();
|
||||
method public boolean isSystemApp();
|
||||
method public void setEnableOnBackInvokedCallback(boolean);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -2588,6 +2588,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public boolean isOnBackInvokedCallbackEnabled() {
|
||||
return ((privateFlagsExt & PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)) != 0;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -366,7 +367,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;
|
||||
private Runnable mImeSurfaceRemoverRunnable;
|
||||
private Runnable mFinishHwRunnable;
|
||||
private long mStylusHwSessionsTimeout = STYLUS_HANDWRITING_IDLE_TIMEOUT_MS;
|
||||
|
||||
@@ -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.
|
||||
@@ -963,6 +963,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) {
|
||||
@@ -10857,13 +10859,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) {
|
||||
|
||||
30
core/java/android/window/CompatOnBackInvokedCallback.java
Normal file
30
core/java/android/window/CompatOnBackInvokedCallback.java
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user