From a2e45f1ed1a3f74ca413f5d4ef815d50f7399c26 Mon Sep 17 00:00:00 2001 From: Vadim Caen Date: Wed, 30 Mar 2022 16:52:30 +0200 Subject: 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 Merged-In: I54d843f11130a78ed5a68cbe4722e601a2086ee1 (cherry picked from commit aa48dc3c2db92189055804878b88a51f0cf8e955) --- core/java/android/app/Dialog.java | 2 - .../inputmethodservice/InputMethodService.java | 3 +- core/java/android/view/ViewRootImpl.java | 15 ++---- .../window/CompatOnBackInvokedCallback.java | 30 +++++++++++ .../window/ProxyOnBackInvokedDispatcher.java | 12 +++-- .../window/WindowOnBackInvokedDispatcher.java | 63 ++++++++++++++++++++-- .../com/android/internal/policy/PhoneWindow.java | 5 +- core/tests/coretests/AndroidManifest.xml | 5 +- .../window/WindowOnBackInvokedDispatcherTest.java | 2 +- .../server/wm/BackNavigationControllerTests.java | 3 +- 10 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 core/java/android/window/CompatOnBackInvokedCallback.java diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 33cf71256d51..de0f7522f36d 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -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() { diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 334a659d7f23..8e67705c5cf0 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -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 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 diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 97e0692a3f3c..e46e44b4115b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -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) { diff --git a/core/java/android/window/CompatOnBackInvokedCallback.java b/core/java/android/window/CompatOnBackInvokedCallback.java new file mode 100644 index 000000000000..81d7291d9f88 --- /dev/null +++ b/core/java/android/window/CompatOnBackInvokedCallback.java @@ -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 enableOnbackInvoked is set to false in the + * application manifest. + * @hide + */ +public interface CompatOnBackInvokedCallback extends OnBackInvokedCallback{ + + @Override + void onBackInvoked(); +} diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java index 10d43e89a09d..8ad109317f4b 100644 --- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java +++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java @@ -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 diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 1d0bc5a6f0ba..d147524d3b3d 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -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> 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 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; + } + } } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index f727d80bba12..9c0fad902a52 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -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()); } /** diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 04857ec756d2..3e4b1cc87ef8 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -161,7 +161,10 @@ - + { appWindow.setOnBackInvokedCallbackInfo(invocation.getArgument(1)); return null; -- cgit v1.2.3 From d38bf5adac36e478aeadb5ffaaec51eb5c633057 Mon Sep 17 00:00:00 2001 From: Elis Elliott Date: Mon, 20 Jun 2022 09:38:08 +0000 Subject: Update the docs for the provisioning extra AllowOffline. update to reflect the new usage of the extra in forcing platform side provisioning. Bug: 236597525 Test: n/a Change-Id: Ie98e9aaa790d1c0bd4b2d5e2b85a81bd8e3c92e3 --- core/java/android/app/admin/DevicePolicyManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 0e1a5461840e..34c91c360dbe 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -770,6 +770,10 @@ public class DevicePolicyManager { *

If this extra is set to {@code true}, the provisioning flow will still try to connect to * the internet, but if it fails it will start the offline provisioning flow. * + *

For T if this extra is set to {@code true}, the provisioning flow will be forced through + * the platform and there will be no attempt to download and install the device policy + * management role holder. + * *

The default value is {@code false}. * *

This extra is respected when provided via the provisioning intent actions such as {@link -- cgit v1.2.3 From 832730d33a389cd7f3e566a139a799a6d68c7bf6 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Fri, 17 Jun 2022 19:07:29 +0800 Subject: Use top activity for fixed rotation from snapshot starting window Assume T=trampoline activity, M=main activity. When launching T into an existing task which contains the existing M: The task will have Top = T (no window) = 'activity' Bottom = M (has window) = 'topFullscreenActivity' Because the real top launching activity is T, we should use it for checking whether to apply fix rotation. Otherwise fixed rotation will be skipped because M is not the current top activity, which will cause the snapshot starting window to be half cropped. Also make sure the trampoline activity has the same rotation as the snapshot. Because the snapshot starting window will be shown on the trampoline first and then transfer to the existing activity. This relates to commit a95bd4a that enables snapshot starting window to take effect across trampoline activity. Bug: 236200669 Test: Assume A,B are landscape singleTask activities with the same task affinity. A will be finished (clear-task-stack) after starting B. Launch the app and return to home and launch it again. The starting window should not be cropped. Change-Id: I11cea671c0e6b9a58ba28f28ce0f735eb576c55d --- services/core/java/com/android/server/wm/ActivityRecord.java | 12 ++++++++++-- .../com/android/server/wm/StartingSurfaceController.java | 5 ++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5c473d8c67f5..ab936a6954d6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2462,8 +2462,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!newTask && taskSwitch && processRunning && !activityCreated && task.intent != null && mActivityComponent.equals(task.intent.getComponent())) { final ActivityRecord topAttached = task.getActivity(ActivityRecord::attachedToProcess); - if (topAttached != null && topAttached.isSnapshotCompatible(snapshot)) { - return STARTING_WINDOW_TYPE_SNAPSHOT; + if (topAttached != null) { + if (topAttached.isSnapshotCompatible(snapshot) + // This trampoline must be the same rotation. + && mDisplayContent.getDisplayRotation().rotationForOrientation(mOrientation, + mDisplayContent.getRotation()) == snapshot.getRotation()) { + return STARTING_WINDOW_TYPE_SNAPSHOT; + } + // No usable snapshot. And a splash screen may also be weird because an existing + // activity may be shown right after the trampoline is finished. + return STARTING_WINDOW_TYPE_NONE; } } final boolean isActivityHome = isActivityTypeHome(); diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index e8445ab8c35e..f83173bd46c0 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -158,14 +158,13 @@ public class StartingSurfaceController { + topFullscreenActivity); return null; } - if (topFullscreenActivity.getWindowConfiguration().getRotation() - != taskSnapshot.getRotation()) { + if (activity.mDisplayContent.getRotation() != taskSnapshot.getRotation()) { // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible // that the activity will be updated to the same rotation as the snapshot. Since // the transition is not started yet, fixed rotation transform needs to be applied // earlier to make the snapshot show in a rotated container. activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation( - topFullscreenActivity, false /* checkOpening */); + activity, false /* checkOpening */); } mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity, 0 /* launchTheme */, taskSnapshot); -- cgit v1.2.3