Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b39eb56d authored by Shan Huang's avatar Shan Huang
Browse files

Fix IME callback being unexpectedly garbage-collected and breaking back

gesture.

Bug: 266528689
Test: Open GMail, Calendar, Launcher, find UI surfaces to bring up IME,
then swipe back. Repeat in different combinations of the steps and make
sure back always works.
Test: atest WindowOnBackInvokedDispatcherTest

Change-Id: I0cba6d6963c6b988f02a7baf56f2901d17b5c9b3
parent 4f767358
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -82,8 +82,13 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc
            @NonNull OnBackInvokedCallback callback) {
        final Bundle bundle = new Bundle();
        // Always invoke back for ime without checking the window focus.
        // We use strong reference in the binder wrapper to avoid accidentally GC the callback.
        // This is necessary because the callback is sent to and registered from
        // the app process, which may treat the IME callback as weakly referenced. This will not
        // cause a memory leak because the app side already clears the reference correctly.
        final IOnBackInvokedCallback iCallback =
                new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(callback);
                new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(
                        callback, false /* useWeakRef */);
        bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder());
        bundle.putInt(RESULT_KEY_PRIORITY, priority);
        bundle.putInt(RESULT_KEY_ID, callback.hashCode());
+29 −4
Original line number Diff line number Diff line
@@ -233,10 +233,34 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    }

    static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
        private final WeakReference<OnBackInvokedCallback> mCallback;
        static class CallbackRef {
            final WeakReference<OnBackInvokedCallback> mWeakRef;
            final OnBackInvokedCallback mStrongRef;
            CallbackRef(@NonNull OnBackInvokedCallback callback, boolean useWeakRef) {
                if (useWeakRef) {
                    mWeakRef = new WeakReference<>(callback);
                    mStrongRef = null;
                } else {
                    mStrongRef = callback;
                    mWeakRef = null;
                }
            }

            OnBackInvokedCallback get() {
                if (mStrongRef != null) {
                    return mStrongRef;
                }
                return mWeakRef.get();
            }
        }
        final CallbackRef mCallbackRef;

        OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) {
            mCallback = new WeakReference<>(callback);
            mCallbackRef = new CallbackRef(callback, true /* useWeakRef */);
        }

        OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback, boolean useWeakRef) {
            mCallbackRef = new CallbackRef(callback, useWeakRef);
        }

        @Override
@@ -279,8 +303,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        public void onBackInvoked() throws RemoteException {
            Handler.getMain().post(() -> {
                mProgressAnimator.reset();
                final OnBackInvokedCallback callback = mCallback.get();
                final OnBackInvokedCallback callback = mCallbackRef.get();
                if (callback == null) {
                    Log.d(TAG, "Trying to call onBackInvoked() on a null callback reference.");
                    return;
                }
                callback.onBackInvoked();
@@ -289,7 +314,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {

        @Nullable
        private OnBackAnimationCallback getBackAnimationCallback() {
            OnBackInvokedCallback callback = mCallback.get();
            OnBackInvokedCallback callback = mCallbackRef.get();
            return callback instanceof OnBackAnimationCallback ? (OnBackAnimationCallback) callback
                    : null;
        }