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

Commit b5d2db77 authored by Yunfan Chen's avatar Yunfan Chen
Browse files

Implement Transient Insets Animation

This implements the transient insets animation. To have InsetsPolicy run
the animation, this patch:
1. Let InsetsPolicy implements InsetsAnimationControlCallbacks;
2. Make several properties, methods and subclasses in InsetsController
   public, to let InsetsPolicy re-use them when possible.
3. Do everything necessary in InsetsPolicy to let the animation run
   correctly.

Other misc changes in this CL includes:
1. Removed some un-necessary imports;
2. Implemented two toString method, for debug purpose.

Bug: 118118435
Test: Manual test with the new Insets API test app, everything works as
      expected;
Test: go/wm-smoke
Test: atest InsetsPolicyTest

Change-Id: I6c45bd557573fcabb1a3f5aea3dcd58229280613
parent 75f5bf33
Loading
Loading
Loading
Loading
+1 −3
Original line number Original line Diff line number Diff line
@@ -16,8 +16,6 @@


package android.view;
package android.view;


import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ISIDE_BOTTOM;
import static android.view.InsetsState.ISIDE_BOTTOM;
import static android.view.InsetsState.ISIDE_FLOATING;
import static android.view.InsetsState.ISIDE_FLOATING;
import static android.view.InsetsState.ISIDE_LEFT;
import static android.view.InsetsState.ISIDE_LEFT;
@@ -188,7 +186,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll


    @Override
    @Override
    public void finish(boolean shown) {
    public void finish(boolean shown) {
        if (mCancelled) {
        if (mCancelled || mFinished) {
            return;
            return;
        }
        }
        setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
        setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
+9 −6
Original line number Original line Diff line number Diff line
@@ -69,7 +69,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private static final int ANIMATION_DURATION_HIDE_MS = 340;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;
    private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;
    private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;


    static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
    public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);


    /**
    /**
     * Layout mode during insets animation: The views should be laid out as if the changing inset
     * Layout mode during insets animation: The views should be laid out as if the changing inset
@@ -77,7 +77,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
     * be called as if the changing insets types are shown, which will result in the views being
     * be called as if the changing insets types are shown, which will result in the views being
     * laid out as if the insets are fully shown.
     * laid out as if the insets are fully shown.
     */
     */
    static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
    public static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;


    /**
    /**
     * Layout mode during insets animation: The views should be laid out as if the changing inset
     * Layout mode during insets animation: The views should be laid out as if the changing inset
@@ -85,7 +85,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
     * be called as if the changing insets types are hidden, which will result in the views being
     * be called as if the changing insets types are hidden, which will result in the views being
     * laid out as if the insets are fully hidden.
     * laid out as if the insets are fully hidden.
     */
     */
    static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
    public static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;


    /**
    /**
     * Determines the behavior of how the views should be laid out during an insets animation that
     * Determines the behavior of how the views should be laid out during an insets animation that
@@ -148,7 +148,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        @Override
        @Override
        public void set(WindowInsetsAnimationController controller, Insets value) {
        public void set(WindowInsetsAnimationController controller, Insets value) {
            controller.setInsetsAndAlpha(
            controller.setInsetsAndAlpha(
                    value, 1f /* alpha */, (((DefaultAnimationControlListener)
                    value, 1f /* alpha */, (((InternalAnimationControlListener)
                            ((InsetsAnimationControlImpl) controller).getListener())
                            ((InsetsAnimationControlImpl) controller).getListener())
                                    .getRawFraction()));
                                    .getRawFraction()));
        }
        }
@@ -165,7 +165,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        private ObjectAnimator mAnimator;
        private ObjectAnimator mAnimator;
        protected boolean mShow;
        protected boolean mShow;


        InternalAnimationControlListener(boolean show) {
        public InternalAnimationControlListener(boolean show) {
            mShow = show;
            mShow = show;
        }
        }


@@ -213,7 +213,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
            return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
        }
        }


        protected long getDurationMs() {
        /**
         * To get the animation duration in MS.
         */
        public long getDurationMs() {
            if (mAnimator != null) {
            if (mAnimator != null) {
                return mAnimator.getDuration();
                return mAnimator.getDuration();
            }
            }
+9 −0
Original line number Original line Diff line number Diff line
@@ -181,6 +181,15 @@ public class InsetsSource implements Parcelable {
        dest.writeBoolean(mVisible);
        dest.writeBoolean(mVisible);
    }
    }


    @Override
    public String toString() {
        return "InsetsSource: {"
                + "mType=" + InsetsState.typeToString(mType)
                + ", mFrame=" + mFrame.toShortString()
                + ", mVisible" + mVisible
                + "}";
    }

    public static final @android.annotation.NonNull Creator<InsetsSource> CREATOR = new Creator<InsetsSource>() {
    public static final @android.annotation.NonNull Creator<InsetsSource> CREATOR = new Creator<InsetsSource>() {


        public InsetsSource createFromParcel(Parcel in) {
        public InsetsSource createFromParcel(Parcel in) {
+14 −3
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
@@ -43,7 +42,6 @@ import android.util.ArraySet;
import android.util.SparseIntArray;
import android.util.SparseIntArray;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;


import java.io.PrintWriter;
import java.io.PrintWriter;
@@ -366,7 +364,12 @@ public class InsetsState implements Parcelable {
        return result;
        return result;
    }
    }


    static @Type.InsetsType int toPublicType(@InternalInsetsType int type) {
    /**
     * Converting a internal type to the public type.
     * @param type internal insets type, {@code InternalInsetsType}.
     * @return public insets type, {@code Type.InsetsType}.
     */
    public static @Type.InsetsType int toPublicType(@InternalInsetsType int type) {
        switch (type) {
        switch (type) {
            case ITYPE_STATUS_BAR:
            case ITYPE_STATUS_BAR:
                return Type.STATUS_BARS;
                return Type.STATUS_BARS;
@@ -510,5 +513,13 @@ public class InsetsState implements Parcelable {
            mSources.put(source.getType(), source);
            mSources.put(source.getType(), source);
        }
        }
    }
    }

    @Override
    public String toString() {
        return "InsetsState: {"
                + "mDisplayFrame=" + mDisplayFrame
                + ", mSources=" + mSources
                + "}";
    }
}
}
+151 −11
Original line number Original line Diff line number Diff line
@@ -20,17 +20,31 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;


import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.app.StatusBarManager;
import android.util.IntArray;
import android.util.IntArray;
import android.util.SparseArray;
import android.view.InsetsAnimationControlCallbacks;
import android.view.InsetsAnimationControlImpl;
import android.view.InsetsController;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
import android.view.ViewRootImpl;
import android.view.WindowInsetsAnimationCallback;
import android.view.WindowInsetsAnimationControlListener;

import com.android.server.DisplayThread;


/**
/**
 * Policy that implements who gets control over the windows generating insets.
 * Policy that implements who gets control over the windows generating insets.
@@ -46,6 +60,8 @@ class InsetsPolicy {
    private WindowState mFocusedWin;
    private WindowState mFocusedWin;
    private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
    private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
    private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
    private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
    private boolean mAnimatingShown;
    private final float[] mTmpFloat9 = new float[9];


    InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
    InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
        mStateController = stateController;
        mStateController = stateController;
@@ -91,11 +107,14 @@ class InsetsPolicy {
            changed = true;
            changed = true;
        }
        }
        if (changed) {
        if (changed) {
            updateBarControlTarget(mFocusedWin);
            startAnimation(mShowingTransientTypes, true, () -> {
            mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
                synchronized (mDisplayContent.mWmService.mGlobalLock) {
                    mPolicy.getStatusBarManagerInternal().showTransient(
                            mDisplayContent.getDisplayId(),
                            mShowingTransientTypes.toArray());
                            mShowingTransientTypes.toArray());
                    mStateController.notifyInsetsChanged();
                    mStateController.notifyInsetsChanged();
            // TODO(b/118118435): Animation
                }
            });
        }
        }
    }
    }


@@ -103,11 +122,13 @@ class InsetsPolicy {
        if (mShowingTransientTypes.size() == 0) {
        if (mShowingTransientTypes.size() == 0) {
            return;
            return;
        }
        }

        startAnimation(mShowingTransientTypes, false, () -> {
        // TODO(b/118118435): Animation
            synchronized (mDisplayContent.mWmService.mGlobalLock) {
                mShowingTransientTypes.clear();
                mShowingTransientTypes.clear();
        updateBarControlTarget(mFocusedWin);
                mStateController.notifyInsetsChanged();
                mStateController.notifyInsetsChanged();
                updateBarControlTarget(mFocusedWin);
            }
        });
    }
    }


    boolean isTransient(@InternalInsetsType int type) {
    boolean isTransient(@InternalInsetsType int type) {
@@ -242,6 +263,29 @@ class InsetsPolicy {
        return isDockedStackVisible || isFreeformStackVisible || isResizing;
        return isDockedStackVisible || isFreeformStackVisible || isResizing;
    }
    }


    private void startAnimation(IntArray internalTypes, boolean show, Runnable callback) {
        int typesReady = 0;
        final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
        updateBarControlTarget(mFocusedWin);
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
            InsetsSourceProvider provider =
                    mStateController.getSourceProvider(internalTypes.get(i));
            if (provider == null) continue;
            InsetsSourceControl control = provider.getControl(provider.getControlTarget());
            if (control == null || control.getLeash() == null) continue;
            typesReady |= InsetsState.toPublicType(internalTypes.get(i));
            controls.put(control.getType(), control);
        }
        controlAnimationUnchecked(typesReady, controls, show, callback);
    }

    private void controlAnimationUnchecked(int typesReady,
            SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
        InsetsPolicyAnimationControlListener listener =
                new InsetsPolicyAnimationControlListener(show, callback);
        listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
    }

    private class BarWindow {
    private class BarWindow {


        private final int mId;
        private final int mId;
@@ -262,7 +306,103 @@ class InsetsPolicy {
        }
        }
    }
    }


    // TODO(b/118118435): Implement animations for it (with SurfaceAnimator)
    private class InsetsPolicyAnimationControlListener extends
            InsetsController.InternalAnimationControlListener {
        Runnable mFinishCallback;
        InsetsPolicyAnimationControlCallbacks mControlCallbacks;

        InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
            super(show);
            mFinishCallback = finishCallback;
            mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
        }

        @Override
        protected void onAnimationFinish() {
            super.onAnimationFinish();
            mControlCallbacks.mAnimationControl.finish(mAnimatingShown);
            DisplayThread.getHandler().post(mFinishCallback);
        }

        private class InsetsPolicyAnimationControlCallbacks implements
                InsetsAnimationControlCallbacks {
            private InsetsAnimationControlImpl mAnimationControl = null;
            private InsetsPolicyAnimationControlListener mListener;

            InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) {
                super();
                mListener = listener;
            }

            private void controlAnimationUnchecked(int typesReady,
                    SparseArray<InsetsSourceControl> controls, boolean show) {
                if (typesReady == 0) {
                    // nothing to animate.
                    return;
                }
                mAnimatingShown = show;

                mAnimationControl = new InsetsAnimationControlImpl(controls,
                        mFocusedWin.getDisplayContent().getBounds(), getState(),
                        mListener, typesReady, this, mListener.getDurationMs(),
                        InsetsController.INTERPOLATOR, true,
                        show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
                                : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
            }

            /** Called on SurfaceAnimationThread lock without global WM lock held. */
            @Override
            public void scheduleApplyChangeInsets() {
                InsetsState state = getState();
                if (mAnimationControl.applyChangeInsets(state)) {
                    mAnimationControl.finish(mAnimatingShown);
                }
            }

            @Override
            public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
                // Nothing's needed here. Finish steps is handled in the listener
                // onAnimationFinished callback.
            }

            /**
             * This method will return a state with fullscreen frame override. No need to make copy
             * after getting state from this method.
             * @return The client insets state with full display frame override.
             */
            private InsetsState getState() {
                // To animate the transient animation correctly, we need to let the state hold
                // the full display frame.
                InsetsState overrideState = new InsetsState(mFocusedWin.getRequestedInsetsState(),
                        true);
                overrideState.setDisplayFrame(mFocusedWin.getDisplayContent().getBounds());
                return overrideState;
            }

            /** Called on SurfaceAnimationThread lock without global WM lock held. */
            @Override
            public void applySurfaceParams(
                    final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
                SurfaceControl.Transaction t = new SurfaceControl.Transaction();
                for (int i = params.length - 1; i >= 0; i--) {
                    SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
                    applyParams(t, surfaceParams, mTmpFloat9);
                }
                t.apply();
            }

            /** Called on SurfaceAnimationThread lock without global WM lock held. */
            @Override
            public void startAnimation(InsetsAnimationControlImpl controller,
                    WindowInsetsAnimationControlListener listener, int types,
                    WindowInsetsAnimationCallback.InsetsAnimation animation,
                    WindowInsetsAnimationCallback.AnimationBounds bounds,
                    int layoutDuringAnimation) {
                SurfaceAnimationThread.getHandler().post(() -> listener.onReady(controller, types));
            }
        }
    }

    private class TransientControlTarget implements InsetsControlTarget {
    private class TransientControlTarget implements InsetsControlTarget {


        @Override
        @Override