From 338e956022d1d45e6728570d68803e2a97db45a8 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Fri, 6 Jan 2023 08:06:26 +0000 Subject: [PATCH] DO NOT MERGE Prevent back navigation not working after activity re-created When recreating the Activity, if the window is preserved, we would set the actual dispatcher from the preserved window to the new Activiy's proxy dispatcher, and expect the new callback could be re-registered in the recreating flow. This CL clears the old callbacks of the preserved dispatcher before it attach to the new proxy dispatcher, this could prevent it access the wrong top callback after other new callbacks have been unregistered. Also provide dump log for WindowOnBackInvokedDispatcher. Bug: 259500250 Test: atest BackNavigationTests Change-Id: Idc9a6a95f5669a009762570d7bc9acc2c538e4cb --- core/java/android/view/ViewRootImpl.java | 2 ++ .../window/ImeOnBackInvokedDispatcher.java | 6 ++++++ .../window/ProxyOnBackInvokedDispatcher.java | 11 +--------- .../window/WindowOnBackInvokedDispatcher.java | 21 +++++++++++++++++++ .../android/internal/policy/PhoneWindow.java | 8 +++++-- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 43bbcfb1e94ae..800b6a3e48191 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -8617,6 +8617,8 @@ public final class ViewRootImpl implements ViewParent, mInsetsController.dump(prefix, writer); + mOnBackInvokedDispatcher.dump(prefix, writer); + writer.println(prefix + "View Hierarchy:"); dumpViewHierarchy(innerPrefix, writer, mView); } diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java index a0bd7f70ca585..34b75a4788c40 100644 --- a/core/java/android/window/ImeOnBackInvokedDispatcher.java +++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java @@ -211,6 +211,12 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc IOnBackInvokedCallback getIOnBackInvokedCallback() { return mIOnBackInvokedCallback; } + + @Override + public String toString() { + return "ImeCallback=ImeOnBackInvokedCallback@" + mId + + " Callback=" + mIOnBackInvokedCallback; + } } /** diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java index 49acde9dc2953..eb3bcaec003a3 100644 --- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java +++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java @@ -179,16 +179,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher { return; } clearCallbacksOnDispatcher(); - if (actualDispatcher instanceof ProxyOnBackInvokedDispatcher) { - // We don't want to nest ProxyDispatchers, so if we are given on, we unwrap its - // actual dispatcher. - // This can happen when an Activity is recreated but the Window is preserved (e.g. - // when going from split-screen back to single screen) - mActualDispatcher = - ((ProxyOnBackInvokedDispatcher) actualDispatcher).mActualDispatcher; - } else { - mActualDispatcher = actualDispatcher; - } + mActualDispatcher = actualDispatcher; transferCallbacksToDispatcher(); } } diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index dd9483a9c759e..e234071a419bd 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -27,6 +27,7 @@ import android.util.Log; import android.view.IWindow; import android.view.IWindowSession; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; @@ -221,6 +222,26 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { @NonNull private static final BackProgressAnimator mProgressAnimator = new BackProgressAnimator(); + /** + * Dump information about this WindowOnBackInvokedDispatcher + * @param prefix the prefix that will be prepended to each line of the produced output + * @param writer the writer that will receive the resulting text + */ + public void dump(String prefix, PrintWriter writer) { + String innerPrefix = prefix + " "; + writer.println(prefix + "WindowOnBackDispatcher:"); + if (mAllCallbacks.isEmpty()) { + writer.println(prefix + ""); + return; + } + + writer.println(innerPrefix + "Top Callback: " + getTopCallback()); + writer.println(innerPrefix + "Callbacks: "); + mAllCallbacks.forEach((callback, priority) -> { + writer.println(innerPrefix + " Callback: " + callback + " Priority=" + priority); + }); + } + static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub { private final WeakReference mCallback; diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index fb38bba8ee167..bb69192f187fe 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -379,8 +379,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // window, as we'll be skipping the addView in handleResumeActivity(), and // the token will not be updated as for a new window. getAttributes().token = preservedWindow.getAttributes().token; - mProxyOnBackInvokedDispatcher.setActualDispatcher( - preservedWindow.getOnBackInvokedDispatcher()); + final ViewRootImpl viewRoot = mDecor.getViewRootImpl(); + if (viewRoot != null) { + // Clear the old callbacks and attach to the new window. + viewRoot.getOnBackInvokedDispatcher().clear(); + onViewRootImplSet(viewRoot); + } } // Even though the device doesn't support picture-in-picture mode, // an user can force using it through developer options.