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

Commit a805cf59 authored by Tiger Huang's avatar Tiger Huang
Browse files

Let the client know the initial visibility of an InsetsSourceControl

Previously, the client compares the requested visibility with the
source visibility to decide if it needs to play the insets animation or
not. However, the source visibility is not stable while the client is
gaining the control. If the source and the control come from
IWindow#insetsControlChanged, the source has the previous visibility. So
the client can detect the visibility change. If the the source and the
control come from IWindowSession#relayout, the visibility of the source
has been overriden by the requested visibility of the client. So the
client cannot detect the change and cannot play the animation.

This CL lets the client know the initial visibility of the control.
While gaining leash, the client can use the information to decide if
it needs to play animation or not.

Fix: 209064170
Fix: 238496738
Test: atest ImeInsetsSourceConsumerTest InsetsAnimationControlImplTest
      InsetsControllerTest InsetsSourceConsumerTest
      DisplayImeControllerTest
Test: 1. Enable shell transitions
      2. Open camera.
      3. Perform back gesture.
      See if there is status bar animation.
Change-Id: I2c02e97e191ebd83238c0c54908e861d200d4c8d
parent 0869abd8
Loading
Loading
Loading
Loading
+8 −34
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import static android.view.InsetsSourceConsumerProto.IS_REQUESTED_VISIBLE;
import static android.view.InsetsSourceConsumerProto.PENDING_FRAME;
import static android.view.InsetsSourceConsumerProto.PENDING_VISIBLE_FRAME;
import static android.view.InsetsSourceConsumerProto.SOURCE_CONTROL;
import static android.view.InsetsSourceControl.INVALID_HINTS;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.getDefaultVisibility;
import static android.view.InsetsState.toPublicType;
@@ -34,7 +33,6 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.ArraySet;
import android.util.Log;
@@ -93,13 +91,6 @@ public class InsetsSourceConsumer {
    private Rect mPendingFrame;
    private Rect mPendingVisibleFrame;

    /**
     * Indicates if we have the pending animation. When we have the control, we need to play the
     * animation if the requested visibility is different from the current state. But if we haven't
     * had a leash yet, we will set this flag, and play the animation once we get the leash.
     */
    private boolean mIsAnimationPending;

    /**
     * @param type The {@link InternalInsetsType} of the consumed insets.
     * @param state The current {@link InsetsState} of the consumed insets.
@@ -138,7 +129,6 @@ public class InsetsSourceConsumer {
            }
            return false;
        }
        SurfaceControl oldLeash = mSourceControl != null ? mSourceControl.getLeash() : null;

        final InsetsSourceControl lastControl = mSourceControl;
        mSourceControl = control;
@@ -163,27 +153,21 @@ public class InsetsSourceConsumer {
            // For updateCompatSysUiVisibility
            applyLocalVisibilityOverride();
        } else {
            // We are gaining control, and need to run an animation since previous state
            // didn't match
            final boolean requestedVisible = isRequestedVisibleAwaitingControl();
            final boolean fakeControl = INVALID_HINTS.equals(control.getInsetsHint());
            final boolean needsAnimation = requestedVisible != mState.getSource(mType).isVisible()
                    && !fakeControl;
            if (control.getLeash() != null && (needsAnimation || mIsAnimationPending)) {
                if (DEBUG) Log.d(TAG, String.format("Gaining control in %s, requestedVisible: %b",
            final SurfaceControl oldLeash = lastControl != null ? lastControl.getLeash() : null;
            final SurfaceControl newLeash = control.getLeash();
            if (newLeash != null && (oldLeash == null || !newLeash.isSameSurface(oldLeash))
                    && requestedVisible != control.isInitiallyVisible()) {
                // We are gaining leash, and need to run an animation since previous state
                // didn't match.
                if (DEBUG) Log.d(TAG, String.format("Gaining leash in %s, requestedVisible: %b",
                        mController.getHost().getRootViewTitle(), requestedVisible));
                if (requestedVisible) {
                    showTypes[0] |= toPublicType(getType());
                } else {
                    hideTypes[0] |= toPublicType(getType());
                }
                mIsAnimationPending = false;
            } else {
                if (needsAnimation) {
                    // We need animation but we haven't had a leash yet. Set this flag that when we
                    // get the leash we can play the deferred animation.
                    mIsAnimationPending = true;
                }
                // We are gaining control, but don't need to run an animation.
                // However make sure that the leash visibility is still up to date.
                if (applyLocalVisibilityOverride()) {
@@ -195,7 +179,7 @@ public class InsetsSourceConsumer {
                applyRequestedVisibilityToControl();

                // Remove the surface that owned by last control when it lost.
                if (!requestedVisible && !mIsAnimationPending && lastControl == null) {
                if (!requestedVisible && lastControl == null) {
                    removeSurface();
                }
            }
@@ -406,16 +390,6 @@ public class InsetsSourceConsumer {
    protected void setRequestedVisible(boolean requestedVisible) {
        if (mRequestedVisible != requestedVisible) {
            mRequestedVisible = requestedVisible;

            // We need an animation later if the leash of a real control (which has an insets hint)
            // is not ready. The !mIsAnimationPending check is in case that the requested visibility
            // is changed twice before playing the animation -- we don't need an animation in this
            // case.
            mIsAnimationPending = !mIsAnimationPending
                    && mSourceControl != null
                    && mSourceControl.getLeash() == null
                    && !Insets.NONE.equals(mSourceControl.getInsetsHint());

            mController.onRequestedVisibilityChanged(this);
            if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible);
        }
+15 −9
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;

import java.io.PrintWriter;
import java.util.Objects;
import java.util.function.Consumer;

/**
@@ -39,10 +40,9 @@ import java.util.function.Consumer;
 */
public class InsetsSourceControl implements Parcelable {

    public static final Insets INVALID_HINTS = Insets.of(-1, -1, -1, -1);

    private final @InternalInsetsType int mType;
    private final @Nullable SurfaceControl mLeash;
    private final boolean mInitiallyVisible;
    private final Point mSurfacePosition;

    // This is used while playing an insets animation regardless of the relative frame. This would
@@ -53,9 +53,10 @@ public class InsetsSourceControl implements Parcelable {
    private int mParcelableFlags;

    public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
            Point surfacePosition, Insets insetsHint) {
            boolean initiallyVisible, Point surfacePosition, Insets insetsHint) {
        mType = type;
        mLeash = leash;
        mInitiallyVisible = initiallyVisible;
        mSurfacePosition = surfacePosition;
        mInsetsHint = insetsHint;
    }
@@ -67,6 +68,7 @@ public class InsetsSourceControl implements Parcelable {
        } else {
            mLeash = null;
        }
        mInitiallyVisible = other.mInitiallyVisible;
        mSurfacePosition = new Point(other.mSurfacePosition);
        mInsetsHint = other.mInsetsHint;
        mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
@@ -75,6 +77,7 @@ public class InsetsSourceControl implements Parcelable {
    public InsetsSourceControl(Parcel in) {
        mType = in.readInt();
        mLeash = in.readTypedObject(SurfaceControl.CREATOR);
        mInitiallyVisible = in.readBoolean();
        mSurfacePosition = in.readTypedObject(Point.CREATOR);
        mInsetsHint = in.readTypedObject(Insets.CREATOR);
        mSkipAnimationOnce = in.readBoolean();
@@ -94,6 +97,10 @@ public class InsetsSourceControl implements Parcelable {
        return mLeash;
    }

    public boolean isInitiallyVisible() {
        return mInitiallyVisible;
    }

    public boolean setSurfacePosition(int left, int top) {
        if (mSurfacePosition.equals(left, top)) {
            return false;
@@ -148,6 +155,7 @@ public class InsetsSourceControl implements Parcelable {
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mType);
        dest.writeTypedObject(mLeash, mParcelableFlags);
        dest.writeBoolean(mInitiallyVisible);
        dest.writeTypedObject(mSurfacePosition, mParcelableFlags);
        dest.writeTypedObject(mInsetsHint, mParcelableFlags);
        dest.writeBoolean(mSkipAnimationOnce);
@@ -172,6 +180,7 @@ public class InsetsSourceControl implements Parcelable {
        return mType == that.mType
                && ((mLeash == thatLeash)
                        || (mLeash != null && thatLeash != null && mLeash.isSameSurface(thatLeash)))
                && mInitiallyVisible == that.mInitiallyVisible
                && mSurfacePosition.equals(that.mSurfacePosition)
                && mInsetsHint.equals(that.mInsetsHint)
                && mSkipAnimationOnce == that.mSkipAnimationOnce;
@@ -179,12 +188,8 @@ public class InsetsSourceControl implements Parcelable {

    @Override
    public int hashCode() {
        int result = mType;
        result = 31 * result + (mLeash != null ? mLeash.hashCode() : 0);
        result = 31 * result + mSurfacePosition.hashCode();
        result = 31 * result + mInsetsHint.hashCode();
        result = 31 * result + (mSkipAnimationOnce ? 1 : 0);
        return result;
        return Objects.hash(mType, mLeash, mInitiallyVisible, mSurfacePosition, mInsetsHint,
                mSkipAnimationOnce);
    }

    @Override
@@ -200,6 +205,7 @@ public class InsetsSourceControl implements Parcelable {
        pw.print(prefix);
        pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
        pw.print(" mLeash="); pw.print(mLeash);
        pw.print(" mInitiallyVisible="); pw.print(mInitiallyVisible);
        pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
        pw.print(" mInsetsHint="); pw.print(mInsetsHint);
        pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
+3 −3
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ public class ImeInsetsSourceConsumerTest {
    @Test
    public void testImeVisibility() {
        final InsetsSourceControl ime =
                new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE);
                new InsetsSourceControl(ITYPE_IME, mLeash, false, new Point(), Insets.NONE);
        mController.onControlsChanged(new InsetsSourceControl[] { ime });

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
@@ -121,7 +121,7 @@ public class ImeInsetsSourceConsumerTest {

            // set control and verify visibility is applied.
            InsetsSourceControl control =
                    new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE);
                    new InsetsSourceControl(ITYPE_IME, mLeash, false, new Point(), Insets.NONE);
            mController.onControlsChanged(new InsetsSourceControl[] { control });
            // IME show animation should be triggered when control becomes available.
            verify(mController).applyAnimation(
@@ -158,7 +158,7 @@ public class ImeInsetsSourceConsumerTest {

            // set control and verify visibility is applied.
            InsetsSourceControl control = Mockito.spy(
                    new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE));
                    new InsetsSourceControl(ITYPE_IME, mLeash, false, new Point(), Insets.NONE));
            // Simulate IME source control set this flag when the target has starting window.
            control.setSkipAnimationOnce(true);

+3 −2
Original line number Diff line number Diff line
@@ -95,12 +95,13 @@ public class InsetsAnimationControlImplTest {
                () -> mMockTransaction, mMockController);
        topConsumer.setControl(
                new InsetsSourceControl(
                        ITYPE_STATUS_BAR, mTopLeash, new Point(0, 0), Insets.of(0, 100, 0, 0)),
                        ITYPE_STATUS_BAR, mTopLeash, true, new Point(0, 0),
                        Insets.of(0, 100, 0, 0)),
                new int[1], new int[1]);

        InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ITYPE_NAVIGATION_BAR,
                mInsetsState, () -> mMockTransaction, mMockController);
        navConsumer.setControl(new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mNavLeash,
        navConsumer.setControl(new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mNavLeash, true,
                new Point(400, 0), Insets.of(0, 0, 100, 0)), new int[1], new int[1]);
        navConsumer.hide();

+3 −2
Original line number Diff line number Diff line
@@ -223,7 +223,7 @@ public class InsetsControllerTest {

            InsetsSourceControl control =
                    new InsetsSourceControl(
                            ITYPE_STATUS_BAR, mLeash, new Point(), Insets.of(0, 10, 0, 0));
                            ITYPE_STATUS_BAR, mLeash, true, new Point(), Insets.of(0, 10, 0, 0));
            mController.onControlsChanged(new InsetsSourceControl[]{control});
            mController.controlWindowInsetsAnimation(0, 0 /* durationMs */,
                    new LinearInterpolator(),
@@ -926,7 +926,8 @@ public class InsetsControllerTest {
        // Simulate binder behavior by copying SurfaceControl. Otherwise, InsetsController will
        // attempt to release mLeash directly.
        SurfaceControl copy = new SurfaceControl(mLeash, "InsetsControllerTest.createControl");
        return new InsetsSourceControl(type, copy, new Point(), Insets.NONE);
        return new InsetsSourceControl(type, copy, InsetsState.getDefaultVisibility(type),
                new Point(), Insets.NONE);
    }

    private InsetsSourceControl[] createSingletonControl(@InternalInsetsType int type) {
Loading