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

Commit 451b7bcb authored by Tiger Huang's avatar Tiger Huang Committed by Android (Google) Code Review
Browse files

Merge "Don't dispatch animation callbacks while hiding transient bar" into main

parents 4ca00f87 9ee20e66
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -221,13 +221,13 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {

    @Override
    public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
            int[] hideTypes, int[] cancelTypes) {
            int[] hideTypes, int[] cancelTypes, int[] transientTypes) {
        if (Flags.refactorInsetsController()) {
            return super.setControl(control, showTypes, hideTypes, cancelTypes);
            return super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
        } else {
            ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
                    mController.getHost().getInputMethodManager(), null /* icProto */);
            if (!super.setControl(control, showTypes, hideTypes, cancelTypes)) {
            if (!super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes)) {
                return false;
            }
            if (control == null && !mIsRequestedVisibleAwaitingLeash) {
+32 −17
Original line number Diff line number Diff line
@@ -959,6 +959,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        final @InsetsType int[] showTypes = new int[1];
        final @InsetsType int[] hideTypes = new int[1];
        final @InsetsType int[] cancelTypes = new int[1];
        final @InsetsType int[] transientTypes = new int[1];
        ImeTracker.Token statsToken = null;

        // Ensure to update all existing source consumers
@@ -984,7 +985,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

            // control may be null, but we still need to update the control to null if it got
            // revoked.
            consumer.setControl(control, showTypes, hideTypes, cancelTypes);
            consumer.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
        }

        // Ensure to create source consumers if not available yet.
@@ -992,7 +993,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
                final InsetsSourceControl control = mTmpControlArray.valueAt(i);
                getSourceConsumer(control.getId(), control.getType())
                        .setControl(control, showTypes, hideTypes, cancelTypes);
                        .setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
            }
        }

@@ -1020,10 +1021,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                handlePendingControlRequest(statsToken);
            } else {
                if (showTypes[0] != 0) {
                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
                            false /* skipsCallbacks */, statsToken);
                }
                if (hideTypes[0] != 0) {
                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
                            // The animation of hiding transient types shouldn't be detected by the
                            // app. Otherwise, it might be able to react to the callbacks and cause
                            // flickering.
                            (hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
                            statsToken);
                }
            }
        } else {
@@ -1033,7 +1040,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                                ImeTracker.TYPE_SHOW, ImeTracker.ORIGIN_CLIENT,
                                SoftInputShowHideReason.CONTROLS_CHANGED,
                                mHost.isHandlingPointerEvent() /* fromUser */);
                applyAnimation(showTypes[0], true /* show */, false /* fromIme */, newStatsToken);
                applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
                        false /* skipsCallbacks */, newStatsToken);
            }
            if (hideTypes[0] != 0) {
                final var newStatsToken =
@@ -1041,7 +1049,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                                ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
                                SoftInputShowHideReason.CONTROLS_CHANGED,
                                mHost.isHandlingPointerEvent() /* fromUser */);
                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, newStatsToken);
                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
                        // The animation of hiding transient types shouldn't be detected by the app.
                        // Otherwise, it might be able to react to the callbacks and cause
                        // flickering.
                        (hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
                        newStatsToken);
            }
        }

@@ -1174,7 +1187,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            // TODO(b/353463205) check if this is needed here
            ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
        }
        applyAnimation(typesReady, true /* show */, fromIme, statsToken);
        applyAnimation(typesReady, true /* show */, fromIme, false /* skipsCallbacks */,
                statsToken);
    }

    /**
@@ -1287,7 +1301,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            handlePendingControlRequest(statsToken);
            getImeSourceConsumer().removeSurface();
        }
        applyAnimation(typesReady, false /* show */, fromIme, statsToken);
        applyAnimation(typesReady, false /* show */, fromIme, false /* skipsCallbacks */,
                statsToken);
    }

    @Override
@@ -2007,24 +2022,24 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

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

    @VisibleForTesting
    public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
            boolean skipAnim, @Nullable ImeTracker.Token statsToken) {
            boolean skipsAnim, boolean skipsCallbacks, @Nullable ImeTracker.Token statsToken) {
        if (types == 0) {
            // nothing to animate.
            if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate. Stopping here");
@@ -2040,7 +2055,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
        final InternalAnimationControlListener listener = new InternalAnimationControlListener(
                show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(),
                skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
                skipsAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
                mLoggingListener, mJankContext);

        // We are about to playing the default animation (show/hide). Passing a null frame indicates
@@ -2050,7 +2065,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                listener /* insetsAnimationSpec */,
                show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                !hasAnimationCallbacks /* useInsetsAnimationThread */, statsToken,
                !hasAnimationCallbacks || skipsCallbacks /* useInsetsAnimationThread */, statsToken,
                false /* fromPredictiveBack */);
    }

@@ -2173,12 +2188,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                        new InsetsSourceControl(ID_IME_CAPTION_BAR, captionBar(),
                                null /* leash */, false /* initialVisible */,
                                new Point(), Insets.NONE),
                        new int[1], new int[1], new int[1]);
                        new int[1], new int[1], new int[1], new int[1]);
            } else {
                mState.removeSource(ID_IME_CAPTION_BAR);
                InsetsSourceConsumer sourceConsumer = mSourceConsumers.get(ID_IME_CAPTION_BAR);
                if (sourceConsumer != null) {
                    sourceConsumer.setControl(null, new int[1], new int[1], new int[1]);
                    sourceConsumer.setControl(null, new int[1], new int[1], new int[1], new int[1]);
                }
            }
            mHost.notifyInsetsChanged();
+7 −1
Original line number Diff line number Diff line
@@ -130,7 +130,10 @@ public class InsetsSourceConsumer {
     * @return Whether the control has changed from the server
     */
    public boolean setControl(@Nullable InsetsSourceControl control,
            @InsetsType int[] showTypes, @InsetsType int[] hideTypes, int[] cancelTypes) {
            @InsetsType int[] showTypes,
            @InsetsType int[] hideTypes,
            @InsetsType int[] cancelTypes,
            @InsetsType int[] transientTypes) {
        if (Objects.equals(mSourceControl, control)) {
            if (mSourceControl != null && mSourceControl != control) {
                mSourceControl.release(SurfaceControl::release);
@@ -185,6 +188,9 @@ public class InsetsSourceConsumer {
                } else {
                    hideTypes[0] |= mType;
                }
                if (lastControl != null && lastControl.isFake()) {
                    transientTypes[0] |= mType;
                }
            } else {
                // We are gaining control, but don't need to run an animation.
                // However make sure that the leash visibility is still up to date.
+4 −0
Original line number Diff line number Diff line
@@ -142,6 +142,10 @@ public class InsetsSourceControl implements Parcelable {
        return mInsetsHint;
    }

    public boolean isFake() {
        return mLeash == null && Insets.NONE.equals(mInsetsHint);
    }

    public void setSkipAnimationOnce(boolean skipAnimation) {
        mSkipAnimationOnce = skipAnimation;
    }
+16 −12
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ public class ImeInsetsSourceConsumerTest {
            // Called once through the show flow.
            verify(mController).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
                    eq(statsToken));
                    eq(false) /* skipsCallbacks */, eq(statsToken));

            // set control and verify visibility is applied.
            InsetsSourceControl control = new InsetsSourceControl(ID_IME,
@@ -142,10 +142,10 @@ public class ImeInsetsSourceConsumerTest {
            // IME show animation should be triggered when control becomes available.
            verify(mController).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
                    and(not(eq(statsToken)), notNull()));
                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
            verify(mController, never()).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
                    and(not(eq(statsToken)), notNull()));
                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
        });
    }

@@ -163,7 +163,7 @@ public class ImeInsetsSourceConsumerTest {
            // Called once through the show flow.
            verify(mController).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
                    eq(statsToken));
                    eq(false) /* skipsCallbacks */, eq(statsToken));
            // Clear previous invocations to verify this is never called with control without leash.
            clearInvocations(mController);

@@ -175,10 +175,10 @@ public class ImeInsetsSourceConsumerTest {
            // as we have no leash.
            verify(mController, never()).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
                    and(not(eq(statsToken)), notNull()));
                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
            verify(mController, never()).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
                    and(not(eq(statsToken)), notNull()));
                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));

            // set control with leash and verify visibility is applied.
            InsetsSourceControl controlWithLeash = new InsetsSourceControl(ID_IME,
@@ -187,10 +187,10 @@ public class ImeInsetsSourceConsumerTest {
            // IME show animation should be triggered when control with leash becomes available.
            verify(mController).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
                    and(not(eq(statsToken)), notNull()));
                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
            verify(mController, never()).applyAnimation(
                    eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
                    and(not(eq(statsToken)), notNull()));
                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
        });
    }

@@ -223,7 +223,8 @@ public class ImeInsetsSourceConsumerTest {
                // Called once through the show flow.
                verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                        eq(true) /* show */, eq(true) /* fromIme */,
                        eq(false) /* skipAnim */, eq(statsToken));
                        eq(false) /* skipsAnim */, eq(false) /* skipsCallbacks */,
                        eq(statsToken));
            }

            // set control and verify visibility is applied.
@@ -241,7 +242,8 @@ public class ImeInsetsSourceConsumerTest {
                // so the statsToken won't match.
                verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                        eq(true) /* show */, eq(false) /* fromIme */,
                        eq(expectSkipAnim) /* skipAnim */, and(not(eq(statsToken)), notNull()));
                        eq(expectSkipAnim) /* skipsAnim */, eq(false) /* skipsCallbacks */,
                        and(not(eq(statsToken)), notNull()));
            }

            // If previously hasViewFocus is false, verify when requesting the IME visible next
@@ -252,14 +254,16 @@ public class ImeInsetsSourceConsumerTest {
                // Called once through the show flow.
                verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                        eq(true) /* show */, eq(true) /* fromIme */,
                        eq(false) /* skipAnim */, eq(statsTokenNext));
                        eq(false) /* skipsAnim */, eq(false) /* skipsCallbacks */,
                        eq(statsTokenNext));
                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 */, and(not(eq(statsToken)), notNull()));
                        eq(true) /* skipsAnim */, eq(false) /* skipsCallbacks */,
                        and(not(eq(statsToken)), notNull()));
            }
        });
    }
Loading