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

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

Better IME transition while switching app with recents (3/N)

- Add hasImeWindowSurface in TaskSnapShot
- Add InsetsSourceControl#getAndClearSkipAnimationOnce for skiping
      IME showing animation once when starting window with IME surface

Bug: 166736352
Bug: 153145997
Test: manual as below steps
    0) Enabling developer options -> Quick settings developer tiles ->
       Window animation scale to slow down transition animation.
    1) Launch an app with focusing an editor to show soft-input
    2) Swipe out app task to back to launcher
    3) Using quick switch or taping shortcut to bring back the app task
    4) Verify that should be no IME showing animation happens during
       task transition.

Change-Id: I83ffc03119e01da71ad12f8ad8043cf0730dfd50
parent 6080e03a
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -1334,6 +1334,23 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    @VisibleForTesting
    public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) {
        // TODO(b/166736352): We should only skip the animation of specific types, not all types.
        boolean skipAnim = false;
        if ((types & ime()) != 0) {
            final InsetsSourceConsumer consumer = mSourceConsumers.get(ITYPE_IME);
            final InsetsSourceControl imeControl = consumer != null ? consumer.getControl() : null;
            // Skip showing animation once that made by system for some reason.
            // (e.g. starting window with IME snapshot)
            if (imeControl != null && show) {
                skipAnim = imeControl.getAndClearSkipAnimationOnce();
            }
        }
        applyAnimation(types, show, fromIme, skipAnim);
    }

    @VisibleForTesting
    public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
            boolean skipAnim) {
        if (types == 0) {
            // nothing to animate.
            if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate");
@@ -1342,7 +1359,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
        final InternalAnimationControlListener listener = new InternalAnimationControlListener(
                show, hasAnimationCallbacks, types, mAnimationsDisabled,
                show, hasAnimationCallbacks, types, skipAnim || mAnimationsDisabled,
                mHost.dipToPx(InternalAnimationControlListener.FLOATING_IME_BOTTOM_INSET));

        // Show/hide animations always need to be relative to the display frame, in order that shown
+22 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ public class InsetsSourceControl implements Parcelable {
    private final @InternalInsetsType int mType;
    private final @Nullable SurfaceControl mLeash;
    private final Point mSurfacePosition;
    private boolean mSkipAnimationOnce;

    public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
            Point surfacePosition) {
@@ -57,6 +58,7 @@ public class InsetsSourceControl implements Parcelable {
            mLeash = null;
        }
        mSurfacePosition = new Point(other.mSurfacePosition);
        mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
    }

    public int getType() {
@@ -77,6 +79,7 @@ public class InsetsSourceControl implements Parcelable {
        mType = in.readInt();
        mLeash = in.readParcelable(null /* loader */);
        mSurfacePosition = in.readParcelable(null /* loader */);
        mSkipAnimationOnce = in.readBoolean();
    }

    public boolean setSurfacePosition(int left, int top) {
@@ -87,10 +90,27 @@ public class InsetsSourceControl implements Parcelable {
        return true;
    }

    public void setSkipAnimationOnce(boolean skipAnimation) {
        mSkipAnimationOnce = skipAnimation;
    }

    public Point getSurfacePosition() {
        return mSurfacePosition;
    }

    /**
     * Get the state whether the current control needs to skip animation or not.
     *
     * Note that this is a one-time check that the state is only valid and can be called when
     * {@link InsetsController#applyAnimation} to check if the current control can skip animation
     * at this time, and then will clear the state value.
     */
    public boolean getAndClearSkipAnimationOnce() {
        final boolean result = mSkipAnimationOnce;
        mSkipAnimationOnce = false;
        return result;
    }

    @Override
    public int describeContents() {
        return 0;
@@ -101,6 +121,7 @@ public class InsetsSourceControl implements Parcelable {
        dest.writeInt(mType);
        dest.writeParcelable(mLeash, 0 /* flags*/);
        dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
        dest.writeBoolean(mSkipAnimationOnce);
    }

    public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
@@ -114,6 +135,7 @@ public class InsetsSourceControl implements Parcelable {
        pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
        pw.print(" mLeash="); pw.print(mLeash);
        pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
        pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
        pw.println();
    }

+29 −11
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ public class TaskSnapshot implements Parcelable {
    private final @WindowInsetsController.Appearance
    int mAppearance;
    private final boolean mIsTranslucent;
    private final boolean mHasImeSurface;
    // Must be one of the named color spaces, otherwise, always use SRGB color space.
    private final ColorSpace mColorSpace;

@@ -68,7 +69,7 @@ public class TaskSnapshot implements Parcelable {
            @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
            Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot,
            int windowingMode, @WindowInsetsController.Appearance int appearance,
            boolean isTranslucent) {
            boolean isTranslucent, boolean hasImeSurface) {
        mId = id;
        mTopActivityComponent = topActivityComponent;
        mSnapshot = snapshot;
@@ -83,6 +84,7 @@ public class TaskSnapshot implements Parcelable {
        mWindowingMode = windowingMode;
        mAppearance = appearance;
        mIsTranslucent = isTranslucent;
        mHasImeSurface = hasImeSurface;
    }

    private TaskSnapshot(Parcel source) {
@@ -102,6 +104,7 @@ public class TaskSnapshot implements Parcelable {
        mWindowingMode = source.readInt();
        mAppearance = source.readInt();
        mIsTranslucent = source.readBoolean();
        mHasImeSurface = source.readBoolean();
    }

    /**
@@ -200,6 +203,13 @@ public class TaskSnapshot implements Parcelable {
        return mIsTranslucent;
    }

    /**
     * @return Whether or not the snapshot has the IME surface.
     */
    public boolean hasImeSurface() {
        return mHasImeSurface;
    }

    /**
     * @return The windowing mode of the task when this snapshot was taken.
     */
@@ -237,6 +247,7 @@ public class TaskSnapshot implements Parcelable {
        dest.writeInt(mWindowingMode);
        dest.writeInt(mAppearance);
        dest.writeBoolean(mIsTranslucent);
        dest.writeBoolean(mHasImeSurface);
    }

    @Override
@@ -256,7 +267,8 @@ public class TaskSnapshot implements Parcelable {
                + " mIsRealSnapshot=" + mIsRealSnapshot
                + " mWindowingMode=" + mWindowingMode
                + " mAppearance=" + mAppearance
                + " mIsTranslucent=" + mIsTranslucent;
                + " mIsTranslucent=" + mIsTranslucent
                + " mHasImeSurface=" + mHasImeSurface;
    }

    public static final @NonNull Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
@@ -283,6 +295,7 @@ public class TaskSnapshot implements Parcelable {
        private @WindowInsetsController.Appearance
        int mAppearance;
        private boolean mIsTranslucent;
        private boolean mHasImeSurface;
        private int mPixelFormat;

        public Builder setId(long id) {
@@ -290,8 +303,7 @@ public class TaskSnapshot implements Parcelable {
            return this;
        }

        public Builder setTopActivityComponent(
                ComponentName name) {
        public Builder setTopActivityComponent(ComponentName name) {
            mTopActivity = name;
            return this;
        }
@@ -329,8 +341,7 @@ public class TaskSnapshot implements Parcelable {
            return this;
        }

        public Builder setIsRealSnapshot(
                boolean realSnapshot) {
        public Builder setIsRealSnapshot(boolean realSnapshot) {
            mIsRealSnapshot = realSnapshot;
            return this;
        }
@@ -340,18 +351,24 @@ public class TaskSnapshot implements Parcelable {
            return this;
        }

        public Builder setAppearance(
                @WindowInsetsController.Appearance int appearance) {
        public Builder setAppearance(@WindowInsetsController.Appearance int appearance) {
            mAppearance = appearance;
            return this;
        }

        public Builder setIsTranslucent(
                boolean isTranslucent) {
        public Builder setIsTranslucent(boolean isTranslucent) {
            mIsTranslucent = isTranslucent;
            return this;
        }

        /**
         * Sets the IME visibility when taking the snapshot of the task.
         */
        public Builder setHasImeSurface(boolean hasImeSurface) {
            mHasImeSurface = hasImeSurface;
            return this;
        }

        public int getPixelFormat() {
            return mPixelFormat;
        }
@@ -378,7 +395,8 @@ public class TaskSnapshot implements Parcelable {
                    mIsRealSnapshot,
                    mWindowingMode,
                    mAppearance,
                    mIsTranslucent);
                    mIsTranslucent,
                    mHasImeSurface);

        }
    }
+22 −0
Original line number Diff line number Diff line
@@ -128,4 +128,26 @@ public class ImeInsetsSourceConsumerTest {
                    eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(true) /* fromIme */);
        });
    }

    @Test
    public void testImeGetAndClearSkipAnimationOnce() {
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            // Request IME visible before control is available.
            mImeConsumer.onWindowFocusGained();
            mImeConsumer.applyImeVisibility(true /* setVisible */);

            // set control and verify visibility is applied.
            InsetsSourceControl control = Mockito.spy(
                    new InsetsSourceControl(ITYPE_IME, mLeash, new Point()));
            // Simulate IME source control set this flag when the target has starting window.
            control.setSkipAnimationOnce(true);
            mController.onControlsChanged(new InsetsSourceControl[] { control });
            // Verify IME show animation should be triggered when control becomes available and
            // the animation will be skipped by getAndClearSkipAnimationOnce invoked.
            verify(control).getAndClearSkipAnimationOnce();
            verify(mController).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
                    eq(true) /* skipAnim */);
        });
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ public class TaskSnapshotWindowTest {
                ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
                Surface.ROTATION_0, taskSize, contentInsets, false,
                true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
                0 /* systemUiVisibility */, false /* isTranslucent */);
                0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */);
    }

    private static TaskDescription createTaskDescription(int background, int statusBar,
Loading