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

Commit ec1eac9a authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Detach stale IME leash for orientation change with gesture navigation

Once computeImeTarget is called that updates mImeLayeringTarget, the
IME surface container will reparent to the new target when starting
input connection (reportStartInput).

When there is an orientation change, the insets source control may
take time to be ready (drawn). If IME surface container is reparented
before the new insets control target updates the insets leash, the
IME in previous rotation will show on the app in new rotation.
e.g.
 Top: PortraitApp (visible)
        > ImeContainer
          > Ime leash for LandscapeApp
      LandscapeApp (invisible)
 And LandscapeApp may still update visibility/position to the leash.
So simply detach the leash to avoid showing inconsistent content.
The new leash for PortraitApp will be created once IME is drawn.

Bug: 335204769
Test: Launch chrome, click search bar to show IME.
      Rotate device to landscape.
      Swipe from landscape to portrait home.
      A landscape IME should not flicker on portrait home.
Change-Id: Iac6edc569330b0d89c0ee03fbd1143573babe228
parent b3942280
Loading
Loading
Loading
Loading
+30 −8
Original line number Diff line number Diff line
@@ -112,7 +112,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Predicate;

/**
@@ -1430,20 +1429,17 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
                }
            }
            if (mTransientLaunches != null) {
                InsetsControlTarget prevImeTarget = dc.getImeTarget(
                        DisplayContent.IME_TARGET_CONTROL);
                InsetsControlTarget newImeTarget = null;
                TaskDisplayArea transientTDA = null;
                // Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
                // so re-compute in case the IME target is changed after transition.
                for (int t = 0; t < mTransientLaunches.size(); ++t) {
                    if (mTransientLaunches.keyAt(t).getDisplayContent() == dc) {
                        newImeTarget = dc.computeImeTarget(true /* updateImeTarget */);
                        if (hasVisibleTransientLaunch) {
                            updateImeForVisibleTransientLaunch(dc);
                        }
                        transientTDA = mTransientLaunches.keyAt(i).getTaskDisplayArea();
                        break;
                    }
                }
                if (mRecentsDisplayId != INVALID_DISPLAY && prevImeTarget == newImeTarget) {
                if (!hasVisibleTransientLaunch && mRecentsDisplayId == dc.mDisplayId) {
                    // Restore IME icon only when moving the original app task to front from
                    // recents, in case IME icon may missing if the moving task has already been
                    // the current focused task.
@@ -1541,6 +1537,32 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        return null;
    }

    /**
     * Transient-launch activities cannot be IME target (see {@link WindowState#canBeImeTarget}),
     * so re-compute in case the IME target is changed after transition.
     */
    private void updateImeForVisibleTransientLaunch(@NonNull DisplayContent dc) {
        final WindowState imeTarget = dc.computeImeTarget(true /* updateImeTarget */);
        final WindowState imeWindow = dc.mInputMethodWindow;
        if (imeWindow == null || imeTarget == null
                || !mController.hasCollectingRotationChange(dc, dc.getRotation())) {
            return;
        }
        // Drop the insets leash if it is still controlled by previous (invisible) app. This avoids
        // showing IME with old rotation on an app with new rotation if IME parent is updated
        // but insets leash hasn't been refreshed, i.e. DisplayContent#updateImeParent is called
        // but InsetsStateController#notifyControlTargetChanged still waits for IME to redraw.
        final InsetsSourceProvider sourceProvider = imeWindow.getControllableInsetProvider();
        if (sourceProvider == null || sourceProvider.mControl == null
                || imeTarget == sourceProvider.getControlTarget()) {
            return;
        }
        final SurfaceControl imeInsetsLeash = sourceProvider.mControl.getLeash();
        if (imeInsetsLeash != null) {
            dc.getSyncTransaction().reparent(imeInsetsLeash, null);
        }
    }

    void abort() {
        // This calls back into itself via controller.abort, so just early return here.
        if (mState == STATE_ABORT) return;