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

Commit 72c8673b authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

Consolidate disabling fixed-rotation when IME may visible on activity

CL[1],[2] disables fixed-rotation when the IME may possible to shown on
the launching activity for fixing Bug the IME janking issue that seeing
both portrait and landscape IME surface.

The CLs use ImeSourceProvider#getSource().mVisibleFrame to predict if
the IME may visible during activity launching, which is not very
predictable to reflect the true IME client visiblity, like when user
intentially presses back key to hide keyboard but somehow mVisibleFrame
may not always be null. So that the issue will happen when launching
the activity from the caller with different orientation, even previously
the IME has been hidden, the fixed-rotation won't happen as expected.

The reason is the visible insets of visibleFrame
is reported from InputMethodService#onComputeInsets that
can be overrided by IME developer, so we can't expect the visibleFrame
should always null.

Another reason is TaskSnapshot#hasImeVisible is not correct because
setHasImeVisible uses isDrawn instead of isVisible to reflect the actual
IME visiblity when snapshoting the task.

To fix this issue, we should remove and fix those misleading checks as
the above, and add reliable visiblity checks to see if the IME window
is really possible to show on the launching activity.
(e.g. mHasSurface, mViewVisibility, softInputMode of the activity
window..)

[1]: Idfdf129adbfbee6634d8a27aa78da1f631bd213b
[2]: I966ab69f260f828b6e96b3479a36467181288504

Fix: 189014002
Bug: 160451808
Test: manual as below steps:
1) launching the app (e.g. Chrome) with focusing IME in portrait mode
2) swiping out to launcher
3) rotate the device in landscape
4) tapping the shortcut to launch the app again
5) see if the app will be launched with normal rotation animation
6) press back key to hide IME
7) swiping out to launcher
8) tapping the shortcut to launch the app again
9) see if the app will be launched with fixed-rotation.

Change-Id: Idef12249806e4a6860b8cd190df4f0f8cad13c19
parent 6b0741b3
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -646,6 +646,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    private boolean mLastContainsDismissKeyguardWindow;
    private boolean mLastContainsTurnScreenOnWindow;

    /** Whether the IME is showing when transitioning away from this activity. */
    boolean mLastImeShown;

    /**
     * A flag to determine if this AR is in the process of closing or entering PIP. This is needed
     * to help AR know that the app is in the process of closing but hasn't yet started closing on
@@ -4696,6 +4699,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            setClientVisible(visible);
        }

        if (!visible) {
            final InsetsControlTarget imeInputTarget = mDisplayContent.getImeTarget(
                    DisplayContent.IME_TARGET_INPUT);
            mLastImeShown = imeInputTarget != null && imeInputTarget.getWindow() != null
                    && imeInputTarget.getWindow().mActivityRecord == this
                    && mDisplayContent.mInputMethodWindow != null
                    && mDisplayContent.mInputMethodWindow.isVisible();
        }

        final DisplayContent displayContent = getDisplayContent();
        if (!displayContent.mClosingApps.contains(this)
                && !displayContent.mOpeningApps.contains(this)) {
+22 −3
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
@@ -208,6 +210,7 @@ import android.view.Surface.Rotation;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
@@ -1556,9 +1559,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            // to cover the activity configuration change.
            return false;
        }
        if ((r.mStartingData != null && r.mStartingData.hasImeSurface())
                || (mInsetsStateController.getImeSourceProvider()
                        .getSource().getVisibleFrame() != null)) {
        if (r.attachedToProcess() && mayImeShowOnLaunchingActivity(r)) {
            // Currently it is unknown that when will IME window be ready. Reject the case to
            // avoid flickering by showing IME in inconsistent orientation.
            return false;
@@ -1614,6 +1615,24 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        return true;
    }

    /** Returns {@code true} if the IME is possible to show on the launching activity. */
    private boolean mayImeShowOnLaunchingActivity(@NonNull ActivityRecord r) {
        final WindowState win = r.findMainWindow();
        if (win == null) {
            return false;
        }
        // See InputMethodManagerService#shouldRestoreImeVisibility that we expecting the IME
        // should be hidden when the window set the hidden softInputMode.
        final int softInputMode = win.mAttrs.softInputMode;
        switch (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
            case SOFT_INPUT_STATE_ALWAYS_HIDDEN:
            case SOFT_INPUT_STATE_HIDDEN:
                return false;
        }
        return r.mLastImeShown && mInputMethodWindow != null && mInputMethodWindow.mHasSurface
                && mInputMethodWindow.mViewVisibility == View.VISIBLE;
    }

    /** Returns {@code true} if the top activity is transformed with the new rotation of display. */
    boolean hasTopFixedRotationLaunchingApp() {
        return mFixedRotationLaunchingApp != null
+2 −1
Original line number Diff line number Diff line
@@ -443,7 +443,8 @@ class TaskSnapshotController {
        } else {
            excludeLayers = new SurfaceControl[0];
        }
        builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isDrawn());
        builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isVisible());

        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                SurfaceControl.captureLayersExcluding(
                        task.getSurfaceControl(), mTmpRect, scaleFraction,
+2 −2
Original line number Diff line number Diff line
@@ -214,8 +214,8 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
        spyOn(mDisplayContent);
        spyOn(mDisplayContent.mInputMethodWindow);
        when(task.getDisplayContent().shouldImeAttachedToApp()).thenReturn(true);
        // Intentionally set the IME window is in drawn state.
        doReturn(true).when(mDisplayContent.mInputMethodWindow).isDrawn();
        // Intentionally set the IME window is in visible state.
        doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
        // Verify no NPE happens when calling createTaskSnapshot.
        try {
            final TaskSnapshot.Builder builder = new TaskSnapshot.Builder();