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

Commit de912328 authored by Louis Chang's avatar Louis Chang
Browse files

Do not change focus when back gesture starts

...because that may cause unnecessary focused app change.

We now just replacing the back-invoked-callback to the
right window while keeping the focus unchanged. With
that, the ViewRootImpl is no longer dropping back event
when the window is not focused because it is now a valid
use case.

Bug: 351071991
Test: Focused on LHS/RHS activity and swipe back on the
      LHS/RHS of the screen.
Test: Same as above with IME shown
Test: wm presubmit
Flag: EXEMPT bugfix
Change-Id: I7d25e953c27954eb1e36f19bd3ac8452d42f9e7d
parent 2bebdf21
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -366,13 +366,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                        Log.e(TAG, "Received invalid input event");
                        return;
                    }
                    try {
                        vri.processingBackKey(true);
                    vri.enqueueInputEvent(keyEvent, null /* receiver */, 0 /* flags */,
                            true /* processImmediately */);
                    } finally {
                        vri.processingBackKey(false);
                    }
                });
        }
    };
+3 −17
Original line number Diff line number Diff line
@@ -727,8 +727,6 @@ public final class ViewRootImpl implements ViewParent,
    boolean mUpcomingWindowFocus;
    @GuardedBy("this")
    boolean mUpcomingInTouchMode;
    // While set, allow this VRI to handle back key without drop it.
    private boolean mProcessingBackKey;
    /**
     * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back
     * key event host app.
@@ -7265,7 +7263,7 @@ public final class ViewRootImpl implements ViewParent,
            // Find a reason for dropping or canceling the event.
            final String reason;
            // The embedded window is focused, allow this VRI to handle back key.
            if (!mAttachInfo.mHasWindowFocus && !(mProcessingBackKey && isBack(q.mEvent))
            if (!mAttachInfo.mHasWindowFocus && !isBack(q.mEvent)
                    && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
                    && !isAutofillUiShowing()) {
                // This is a non-pointer event and the window doesn't currently have input focus
@@ -11213,11 +11211,6 @@ public final class ViewRootImpl implements ViewParent,
        mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
    }
    // Make this VRI able to process back key without drop it.
    void processingBackKey(boolean processing) {
        mProcessingBackKey = processing;
    }
    /**
     * Collect and include any ScrollCaptureCallback instances registered with the window.
     *
@@ -12549,15 +12542,8 @@ public final class ViewRootImpl implements ViewParent,
     * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true)
     */
    public boolean injectBackKeyEvents(boolean preImeOnly) {
        boolean consumed;
        try {
            processingBackKey(true);
        sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
            consumed = sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
        } finally {
            processingBackKey(false);
        }
        return consumed;
        return sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
    }
    private boolean sendBackKeyEvent(int action, boolean preImeOnly) {
+7 −8
Original line number Diff line number Diff line
@@ -166,15 +166,14 @@ class BackNavigationController {
                return null;
            }

            // Move focus to the top embedded window if possible
            if (mWindowManagerService.moveFocusToAdjacentEmbeddedWindow(window)) {
                window = wmService.getFocusedWindowLocked();
                if (window == null) {
                    Slog.e(TAG, "New focused window is null, returning null.");
                    return null;
            // Updating the window to the most recently used one among the embedded windows
            // that are displayed adjacently, unless the IME is visible.
            // When the IME is visible, the IME is displayed on top of embedded activities.
            // In that case, the back event should still be delivered to focused activity in
            // order to dismiss the IME.
            if (!window.getDisplayContent().getImeContainer().isVisible()) {
                window = mWindowManagerService.getMostRecentUsedEmbeddedWindowForBack(window);
            }
            }

            if (!window.isDrawn()) {
                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
                        "Focused window didn't have a valid surface drawn.");
+16 −0
Original line number Diff line number Diff line
@@ -3894,6 +3894,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        return mTmpWindow;
    }

    /**
     * Returns the focused window of the given Activity if the Activity is focused.
     */
    WindowState findFocusedWindow(ActivityRecord activityRecord) {
        final ActivityRecord tmpApp = mFocusedApp;
        mTmpWindow = null;
        try {
            mFocusedApp = activityRecord;
            // mFindFocusedWindow will populate mTmpWindow with the new focused window when found.
            activityRecord.forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
        } finally {
            mFocusedApp = tmpApp;
        }
        return mTmpWindow;
    }

    /**
     * Update the focused window and make some adjustments if the focus has changed.
     *
+54 −17
Original line number Diff line number Diff line
@@ -54,7 +54,6 @@ import static android.service.dreams.Flags.dreamHandlesConfirmKeys;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -97,6 +96,7 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.window.WindowProviderService.isWindowProviderService;

import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -9379,40 +9379,77 @@ public class WindowManagerService extends IWindowManager.Stub
    }

    /**
     * Move focus to the adjacent embedded activity if the adjacent activity is more recently
     * created or has a window more recently added.
     * Returns the Activity that has the most recently created window in the adjacent activities
     * if any.
     */
    boolean moveFocusToAdjacentEmbeddedWindow(@NonNull WindowState focusedWindow) {
        final TaskFragment taskFragment = focusedWindow.getTaskFragment();
    @NonNull
    ActivityRecord getMostRecentActivityInAdjacent(@NonNull ActivityRecord focusedActivity) {
        final TaskFragment taskFragment = focusedActivity.getTaskFragment();
        if (taskFragment == null) {
            // Skip if not an Activity window.
            return false;
            // Return if activity no attached.
            return focusedActivity;
        }

        if (!Flags.embeddedActivityBackNavFlag()) {
            // Skip if flag is not enabled.
            return false;
            // Return if flag is not enabled.
            return focusedActivity;
        }

        if (!focusedWindow.mActivityRecord.isEmbedded()) {
            // Skip if the focused activity is not embedded
            return false;
        if (!focusedActivity.isEmbedded()) {
            // Return if the focused activity is not embedded.
            return focusedActivity;
        }

        final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
        final ActivityRecord adjacentTopActivity =
                adjacentTaskFragment != null ? adjacentTaskFragment.topRunningActivity() : null;
        if (adjacentTopActivity == null) {
            return false;
            // Return if no adjacent activity.
            return focusedActivity;
        }

        if (adjacentTopActivity.getLastWindowCreateTime()
                < focusedWindow.mActivityRecord.getLastWindowCreateTime()) {
            // Skip if the current focus activity has more recently active window.
            return false;
                < focusedActivity.getLastWindowCreateTime()) {
            // Return if the current focus activity has more recently active window.
            return focusedActivity;
        }

        return adjacentTopActivity;
    }

        moveFocusToActivity(adjacentTopActivity);
    @NonNull
    WindowState getMostRecentUsedEmbeddedWindowForBack(@NonNull WindowState focusedWindow) {
        final ActivityRecord focusedActivity = focusedWindow.getActivityRecord();
        if (focusedActivity == null) {
            // Not an Activity.
            return focusedWindow;
        }

        final ActivityRecord mostRecentActivityInAdjacent = getMostRecentActivityInAdjacent(
                focusedActivity);
        if (mostRecentActivityInAdjacent == focusedActivity) {
            // Already be the most recent window.
            return focusedWindow;
        }

        // Looks for a candidate focused window on the adjacent Activity for the back event.
        final WindowState candidate =
                mostRecentActivityInAdjacent.getDisplayContent().findFocusedWindow(
                        mostRecentActivityInAdjacent);
        return candidate != null ? candidate : focusedWindow;
    }

    /**
     * Move focus to the adjacent embedded activity if the adjacent activity is more recently
     * created or has a window more recently added.
     * <p>
     * Returns {@code true} if the focused window is changed. Otherwise, returns {@code false}.
     */
    boolean moveFocusToAdjacentEmbeddedWindow(@NonNull WindowState focusedWindow) {
        final ActivityRecord mostRecentActivityInAdjacent = getMostRecentActivityInAdjacent(
                focusedWindow.getActivityRecord());

        moveFocusToActivity(mostRecentActivityInAdjacent);
        return !focusedWindow.isFocused();
    }

Loading