当前位置:   article > 正文

Insets动画 - 安卓R

insets动画

Insets相关重要类

Insets

Insets定义在frameworks/base/graphics/java/android/graphics/Insets.java,其分别定义了窗口上下左右有其它systemui等系统窗口的偏移:

/**
 * An Insets instance holds four integer offsets which describe changes to the four
 * edges of a Rectangle. By convention, positive values move edges towards the
 * centre of the rectangle.
 * <p>
 * Insets are immutable so may be treated as values.
 *
 */
public final class Insets implements Parcelable {
    public static final @NonNull Insets NONE = new Insets(0, 0, 0, 0);

    public final int left;
    public final int top;
    public final int right;
    public final int bottom;

    ......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

InsetsSource

InsetsSource定义在frameworks/base/core/java/android/view/InsetsSource.java,是一种产生Insets的窗口:

/**
 * Represents the state of a single window generating insets for clients.
 * @hide
 */
public class InsetsSource implements Parcelable {

    private final @InternalInsetsType int mType;

    /** Frame of the source in screen coordinate space */
    private final Rect mFrame;
    private @Nullable Rect mVisibleFrame;
    private boolean mVisible;

    private final Rect mTmpFrame = new Rect();

    public InsetsSource(@InternalInsetsType int type) {
        mType = type;
        mFrame = new Rect();
        mVisible = InsetsState.getDefaultVisibility(type);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

这个mType定义在InsetsState中。

InsetsState

InsetsState定义在frameworks/base/core/java/android/view/InsetsState.java,是InsetsSource的集合:

/**
 * Holder for state of system windows that cause window insets for all other windows in the system.
 * @hide
 */
public class InsetsState implements Parcelable {

    public static final InsetsState EMPTY = new InsetsState();

    /**
     * Internal representation of inset source types. This is different from the public API in
     * {@link WindowInsets.Type} as one type from the public API might indicate multiple windows
     * at the same time.
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "ITYPE", value = {
            ITYPE_STATUS_BAR,
            ITYPE_NAVIGATION_BAR,
            ITYPE_CAPTION_BAR,
            ITYPE_TOP_GESTURES,
            ITYPE_BOTTOM_GESTURES,
            ITYPE_LEFT_GESTURES,
            ITYPE_RIGHT_GESTURES,
            ITYPE_TOP_MANDATORY_GESTURES,
            ITYPE_BOTTOM_MANDATORY_GESTURES,
            ITYPE_LEFT_MANDATORY_GESTURES,
            ITYPE_RIGHT_MANDATORY_GESTURES,
            ITYPE_TOP_TAPPABLE_ELEMENT,
            ITYPE_BOTTOM_TAPPABLE_ELEMENT,
            ITYPE_LEFT_DISPLAY_CUTOUT,
            ITYPE_TOP_DISPLAY_CUTOUT,
            ITYPE_RIGHT_DISPLAY_CUTOUT,
            ITYPE_BOTTOM_DISPLAY_CUTOUT,
            ITYPE_IME,
            ITYPE_CLIMATE_BAR,
            ITYPE_EXTRA_NAVIGATION_BAR
    })
    public @interface InternalInsetsType {}

    /**
     * Special value to be used to by methods returning an {@link InternalInsetsType} to indicate
     * that the objects/parameters aren't associated with an {@link InternalInsetsType}
     */
    public static final int ITYPE_INVALID = -1;

    static final int FIRST_TYPE = 0;

    public static final int ITYPE_STATUS_BAR = FIRST_TYPE;
    public static final int ITYPE_NAVIGATION_BAR = 1;
    public static final int ITYPE_CAPTION_BAR = 2;

    public static final int ITYPE_TOP_GESTURES = 3;
    public static final int ITYPE_BOTTOM_GESTURES = 4;
    public static final int ITYPE_LEFT_GESTURES = 5;
    public static final int ITYPE_RIGHT_GESTURES = 6;

    /** Additional gesture inset types that map into {@link Type.MANDATORY_SYSTEM_GESTURES}. */
    public static final int ITYPE_TOP_MANDATORY_GESTURES = 7;
    public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8;
    public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
    public static final int ITYPE_RIGHT_MANDATORY_GESTURES = 10;

    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 11;
    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 12;

    public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 13;
    public static final int ITYPE_TOP_DISPLAY_CUTOUT = 14;
    public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 15;
    public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 16;

    /** Input method window. */
    public static final int ITYPE_IME = 17;

    /** Additional system decorations inset type. */
    public static final int ITYPE_CLIMATE_BAR = 18;
    public static final int ITYPE_EXTRA_NAVIGATION_BAR = 19;

    static final int LAST_TYPE = ITYPE_EXTRA_NAVIGATION_BAR;
    public static final int SIZE = LAST_TYPE + 1;

    // Derived types

    /** A shelf is the same as the navigation bar. */
    public static final int ITYPE_SHELF = ITYPE_NAVIGATION_BAR;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "IINSETS_SIDE", value = {
            ISIDE_LEFT,
            ISIDE_TOP,
            ISIDE_RIGHT,
            ISIDE_BOTTOM,
            ISIDE_FLOATING,
            ISIDE_UNKNOWN
    })
    public @interface InternalInsetsSide {}
    static final int ISIDE_LEFT = 0;
    static final int ISIDE_TOP = 1;
    static final int ISIDE_RIGHT = 2;
    static final int ISIDE_BOTTOM = 3;
    static final int ISIDE_FLOATING = 4;
    static final int ISIDE_UNKNOWN = 5;

    private InsetsSource[] mSources = new InsetsSource[SIZE];

    /**
     * The frame of the display these sources are relative to.
     */
    private final Rect mDisplayFrame = new Rect();

    ......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

这其中定义了InsetsSource有哪些类型,并且有一个类型为InsetsSource[]的成员变量mSources保存了所有类型的InsetsSource。

InsetsSourceControl

InsetsSourceControl定义在frameworks/base/core/java/android/view/InsetsSourceControl.java:

/**
 * Represents a parcelable object to allow controlling a single {@link InsetsSource}.
 * @hide
 */
public class InsetsSourceControl implements Parcelable {

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

    public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
            Point surfacePosition) {
        mType = type;
        mLeash = leash;
        mSurfacePosition = surfacePosition;
    }
    ......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

其成员变量mType指定了自己的类型,mLeash是这个Insets窗口的一个父结点,可以用来控制这个窗口的属性。

Insets动画流程

在frameworks/base/core/java/android/view/ViewRootImpl.java的relayoutWindow方法中:

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
        ......
        int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
                mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                mTempControls, mSurfaceSize, mBlastSurfaceControl);
        ......
        mInsetsController.onStateChanged(mTempInsets);
        mInsetsController.onControlsChanged(mTempControls);
        return relayoutResult;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这个方法首先通过binder调用了frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java的relayoutWindow方法:

    public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            long frameNumber, Rect outFrame, Rect outContentInsets,
            Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
            SurfaceControl outBLASTSurfaceControl) {
        Arrays.fill(outActiveControls, null);
        ......
        synchronized (mGlobalLock) {
            final WindowState win = windowForClientLocked(session, client, false);
            ......
            outInsetsState.set(win.getInsetsState(), win.isClientLocal());
            ......
            getInsetsSourceControls(win, outActiveControls);
        }
        ......
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

这样app端就拿到了InsetsState和InsetsSourceControl[],在ViewRootImpl的relayoutWindow方法最后还调用了frameworks/base/core/java/android/view/InsetsController.java的onControlsChanged方法:

    /**
     * Called when the server has dispatched us a new set of inset controls.
     */
    public void onControlsChanged(InsetsSourceControl[] activeControls) {
        if (activeControls != null) {
            for (InsetsSourceControl activeControl : activeControls) {
                if (activeControl != null) {
                    // TODO(b/122982984): Figure out why it can be null.
                    mTmpControlArray.put(activeControl.getType(), activeControl);
                }
            }
        }

        boolean requestedStateStale = false;
        final int[] showTypes = new int[1];
        final int[] hideTypes = new int[1];

        // Ensure to update all existing source consumers
        for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
            final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
            final InsetsSourceControl control = mTmpControlArray.get(consumer.getType());

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

        // Ensure to create source consumers if not available yet.
        for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
            final InsetsSourceControl control = mTmpControlArray.valueAt(i);
            final @InternalInsetsType int type = control.getType();
            final InsetsSourceConsumer consumer = getSourceConsumer(type);
            consumer.setControl(control, showTypes, hideTypes);

            if (!requestedStateStale) {
                final boolean requestedVisible = consumer.isRequestedVisible();

                // We might have changed our requested visibilities while we don't have the control,
                // so we need to update our requested state once we have control. Otherwise, our
                // requested state at the server side might be incorrect.
                final boolean requestedVisibilityChanged =
                        requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type);

                // The IME client visibility will be reset by insets source provider while updating
                // control, so if IME is requested visible, we need to send the request to server.
                final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible;

                requestedStateStale = requestedVisibilityChanged || imeRequestedVisible;
            }

        }
        mTmpControlArray.clear();

        // Do not override any animations that the app started in the OnControllableInsetsChanged
        // listeners.
        int animatingTypes = invokeControllableInsetsChangedListeners();
        showTypes[0] &= ~animatingTypes;
        hideTypes[0] &= ~animatingTypes;

        if (showTypes[0] != 0) {
            applyAnimation(showTypes[0], true /* show */, false /* fromIme */);
        }
        if (hideTypes[0] != 0) {
            applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
        }
        if (requestedStateStale) {
            updateRequestedState();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

调用了InsetsController的applyAnimation方法:

    @VisibleForTesting
    public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) {
        if (types == 0) {
            // nothing to animate.
            if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate");
            return;
        }

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

        // Show/hide animations always need to be relative to the display frame, in order that shown
        // and hidden state insets are correct.
        controlAnimationUnchecked(
                types, null /* cancellationSignal */, listener, mState.getDisplayFrame(), fromIme,
                listener.getDurationMs(), listener.getInterpolator(),
                show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                !hasAnimationCallbacks /* useInsetsAnimationThread */);

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

首先创建了一个InsetsController的内部静态类InternalAnimationControlListener,调用了InsetsController的controlAnimationUnchecked方法:

    private void controlAnimationUnchecked(@InsetsType int types,
            @Nullable CancellationSignal cancellationSignal,
            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
            long durationMs, Interpolator interpolator,
            @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
            boolean useInsetsAnimationThread) {
        if ((types & mTypesBeingCancelled) != 0) {
            throw new IllegalStateException("Cannot start a new insets animation of "
                    + Type.toString(types)
                    + " while an existing " + Type.toString(mTypesBeingCancelled)
                    + " is being cancelled.");
        }
        if (animationType == ANIMATION_TYPE_USER) {
            final @InsetsType int disabledTypes = types & mDisabledUserAnimationInsetsTypes;
            if (DEBUG) Log.d(TAG, "user animation disabled types: " + disabledTypes);
            types &= ~mDisabledUserAnimationInsetsTypes;

            if (fromIme && (disabledTypes & ime()) != 0
                    && !mState.getSource(ITYPE_IME).isVisible()) {
                // We've requested IMM to show IME, but the IME is not controllable. We need to
                // cancel the request.
                getSourceConsumer(ITYPE_IME).hide(true, animationType);
            }
        }
        if (types == 0) {
            // nothing to animate.
            listener.onCancelled(null);
            if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked");
            return;
        }
        cancelExistingControllers(types);  // 这里取消现有的与types有重合的动画
        if (DEBUG) Log.d(TAG, "controlAnimation types: " + types);
        mLastStartedAnimTypes |= types;

        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
        final SparseArray<InsetsSourceControl> controls = new SparseArray<>();

        Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
                fromIme, internalTypes, controls, animationType);
        int typesReady = typesReadyPair.first;
        boolean imeReady = typesReadyPair.second;
        if (DEBUG) Log.d(TAG, String.format(
                "controlAnimationUnchecked, typesReady: %s imeReady: %s", typesReady, imeReady));
        if (!imeReady) {
            // IME isn't ready, all requested types will be animated once IME is ready
            abortPendingImeControlRequest();
            final PendingControlRequest request = new PendingControlRequest(types,
                    listener, durationMs,
                    interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal,
                    useInsetsAnimationThread);
            mPendingImeControlRequest = request;
            mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
            if (DEBUG) Log.d(TAG, "Ime not ready. Create pending request");
            if (cancellationSignal != null) {
                cancellationSignal.setOnCancelListener(() -> {
                    if (mPendingImeControlRequest == request) {
                        if (DEBUG) Log.d(TAG,
                                "Cancellation signal abortPendingImeControlRequest");
                        abortPendingImeControlRequest();
                    }
                });
            }
            return;
        }

        if (typesReady == 0) {
            if (DEBUG) Log.d(TAG, "No types ready. onCancelled()");
            listener.onCancelled(null);
            return;
        }


        final InsetsAnimationControlRunner runner = useInsetsAnimationThread  // 在这里开始动画
                ? new InsetsAnimationThreadControlRunner(controls,
                        frame, mState, listener, typesReady, this, durationMs, interpolator,
                        animationType, mHost.getHandler())
                : new InsetsAnimationControlImpl(controls,
                        frame, mState, listener, typesReady, this, durationMs, interpolator,
                        animationType);
        mRunningAnimations.add(new RunningAnimation(runner, animationType));
        if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
                + useInsetsAnimationThread);
        if (cancellationSignal != null) {
            cancellationSignal.setOnCancelListener(() -> {
                cancelAnimation(runner, true /* invokeCallback */);
            });
        }
        if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
            showDirectly(types);
        } else {
            hideDirectly(types, false /* animationFinished */, animationType);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

首先调用了InsetsController的cancelExistingControllers方法:

    private void cancelExistingControllers(@InsetsType int types) {
        final int originalmTypesBeingCancelled = mTypesBeingCancelled;
        mTypesBeingCancelled |= types;
        try {
            for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
                if ((control.getTypes() & types) != 0) {
                    cancelAnimation(control, true /* invokeCallback */);
                }
            }
            if ((types & ime()) != 0) {
                abortPendingImeControlRequest();
            }
        } finally {
            mTypesBeingCancelled = originalmTypesBeingCancelled;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

检查了所有现有的动画,只要动画的InsetsType有任何相同的部分,就调用了InsetsController的cancelAnimation方法:

    private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
        if (DEBUG) Log.d(TAG, String.format("cancelAnimation of types: %d, animType: %d",
                control.getTypes(), control.getAnimationType()));
        if (invokeCallback) {
            control.cancel();
        }
        boolean stateChanged = false;
        for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
            RunningAnimation runningAnimation = mRunningAnimations.get(i);
            if (runningAnimation.runner == control) {
                mRunningAnimations.remove(i);
                ArraySet<Integer> types = toInternalType(control.getTypes());
                for (int j = types.size() - 1; j >= 0; j--) {
                    stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
                }
                if (invokeCallback && runningAnimation.startDispatched) {
                    dispatchAnimationEnd(runningAnimation.runner.getAnimation());
                }
                break;
            }
        }
        if (stateChanged) {
            mHost.notifyInsetsChanged();
            updateRequestedState();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

回到InsetsController的controlAnimationUnchecked方法,后面还创建了类型为InsetsAnimationControlRunner接口的runner对象,runner的实际类型有两种情况,此时暂时只看第一种情况,继续看frameworks/base/core/java/android/view/InsetsAnimationThreadControlRunner.java的构造器:

    @UiThread
    public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, Rect frame,
            InsetsState state, WindowInsetsAnimationControlListener listener,
            @InsetsType int types,
            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
            @AnimationType int animationType, Handler mainThreadHandler) {
        mMainThreadHandler = mainThreadHandler;
        mOuterCallbacks = controller;
        mControl = new InsetsAnimationControlImpl(controls, frame, state, listener,
                types, mCallbacks, durationMs, interpolator, animationType);
        InsetsAnimationThread.getHandler().post(() -> {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
                    "InsetsAsyncAnimation: " + WindowInsets.Type.toString(types), types);
            listener.onReady(mControl, types);
        });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这里首先创建了一个frameworks/base/core/java/android/view/InsetsAnimationControlImpl.java对象:

    @VisibleForTesting
    public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, Rect frame,
            InsetsState state, WindowInsetsAnimationControlListener listener,
            @InsetsType int types,
            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
            @AnimationType int animationType) {
        mControls = controls;
        mListener = listener;
        mTypes = types;
        mController = controller;
        mInitialInsetsState = new InsetsState(state, true /* copySources */);
        mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
        mPendingInsets = mCurrentInsets;
        mHiddenInsets = calculateInsets(mInitialInsetsState, frame, controls, false /* shown */,
                null /* typeSideMap */);
        mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
                mTypeSideMap);
        mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
        if (mHasZeroInsetsIme) {
            // IME has shownInsets of ZERO, and can't map to a side by default.
            // Map zero insets IME to bottom, making it a special case of bottom insets.
            mTypeSideMap.put(ITYPE_IME, ISIDE_BOTTOM);
        }
        buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);

        mAnimation = new WindowInsetsAnimation(mTypes, interpolator,
                durationMs);
        mAnimation.setAlpha(getCurrentAlpha());
        mAnimationType = animationType;
        mController.startAnimation(this, listener, types, mAnimation,
                new Bounds(mHiddenInsets, mShownInsets));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

最后调用了mController的startAnimation方法,这个mController是InsetsAnimationThreadControlRunner的类型为InsetsAnimationControlCallbacks的成员变量mCallbacks,其定义的startAnimation方法:

    private final InsetsAnimationControlCallbacks mCallbacks =
            new InsetsAnimationControlCallbacks() {
        ......
        @Override
        @UiThread
        public void startAnimation(InsetsAnimationControlImpl controller,
                WindowInsetsAnimationControlListener listener, int types,
                WindowInsetsAnimation animation, Bounds bounds) {
            // Animation will be started in constructor already.
        }
        ......
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这个方法什么都没有做。

回到InsetsAnimationThreadControlRunner的构造器中,最后切换到InsetsAnimationThread线程,调用了listener的onReady方法,这个listener正是之前创建的InsetsController的内部静态类InternalAnimationControlListener,其onReady方法:

        @Override
        public void onReady(WindowInsetsAnimationController controller, int types) {
            mController = controller;
            if (DEBUG) Log.d(TAG, "default animation onReady types: " + types);

            if (mDisable) {
                onAnimationFinish();
                return;
            }
            mAnimator = ValueAnimator.ofFloat(0f, 1f);
            mAnimator.setDuration(mDurationMs);
            mAnimator.setInterpolator(new LinearInterpolator());
            Insets hiddenInsets = controller.getHiddenStateInsets();
            // IME with zero insets is a special case: it will animate-in from offscreen and end
            // with final insets of zero and vice-versa.
            hiddenInsets = controller.hasZeroInsetsIme()
                    ? Insets.of(hiddenInsets.left, hiddenInsets.top, hiddenInsets.right,
                            mFloatingImeBottomInset)
                    : hiddenInsets;
            Insets start = mShow
                    ? hiddenInsets
                    : controller.getShownStateInsets();
            Insets end = mShow
                    ? controller.getShownStateInsets()
                    : hiddenInsets;
            Interpolator insetsInterpolator = getInterpolator();
            Interpolator alphaInterpolator = getAlphaInterpolator();
            mAnimator.addUpdateListener(animation -> {
                float rawFraction = animation.getAnimatedFraction();
                float alphaFraction = mShow
                        ? rawFraction
                        : 1 - rawFraction;
                float insetsFraction = insetsInterpolator.getInterpolation(rawFraction);
                controller.setInsetsAndAlpha(
                        sEvaluator.evaluate(insetsFraction, start, end),
                        alphaInterpolator.getInterpolation(alphaFraction),
                        rawFraction);
                if (DEBUG) Log.d(TAG, "Default animation setInsetsAndAlpha fraction: "
                        + insetsFraction);
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {

                @Override
                public void onAnimationEnd(Animator animation) {
                    onAnimationFinish();
                }
            });
            if (!mHasAnimationCallbacks) {
                mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
            }
            mAnimator.start();
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

这里使用ValueAnimator执行动画,注意mAnimator.addUpdateListener方法中传入的lambda,这个lambda函数会在动画的每帧调用,其中调用了frameworks/base/core/java/android/view/InsetsAnimationControlImpl.java的setInsetsAndAlpha方法:

    @Override
    public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
        setInsetsAndAlpha(insets, alpha, fraction, false /* allowWhenFinished */);
    }

    private void setInsetsAndAlpha(Insets insets, float alpha, float fraction,
            boolean allowWhenFinished) {
        if (!allowWhenFinished && mFinished) {
            throw new IllegalStateException(
                    "Can't change insets on an animation that is finished.");
        }
        if (mCancelled) {
            throw new IllegalStateException(
                    "Can't change insets on an animation that is cancelled.");
        }
        mPendingFraction = sanitize(fraction);
        mPendingInsets = sanitize(insets);
        mPendingAlpha = sanitize(alpha);
        mController.scheduleApplyChangeInsets(this);
        boolean perceptible = calculatePerceptible(mPendingInsets, mPendingAlpha);
        if (mPerceptible == null || perceptible != mPerceptible) {
            mController.reportPerceptible(mTypes, perceptible);
            mPerceptible = perceptible;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

调用了InsetsAnimationThreadControlRunner.mCallbacks的scheduleApplyChangeInsets方法:

    private final InsetsAnimationControlCallbacks mCallbacks =
            new InsetsAnimationControlCallbacks() {
        ......
        @Override
        public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
            mControl.applyChangeInsets(mState);
        }
        ......
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调用了InsetsAnimationControlImpl的applyChangeInsets方法:

    @VisibleForTesting
    /**
     * @return Whether the finish callback of this animation should be invoked.
     */
    public boolean applyChangeInsets(InsetsState state) {
        if (mCancelled) {
            if (DEBUG) Log.d(TAG, "applyChangeInsets canceled");
            return false;
        }
        final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
        ArrayList<SurfaceParams> params = new ArrayList<>();
        updateLeashesForSide(ISIDE_LEFT, offset.left, mShownInsets.left, mPendingInsets.left,
                params, state, mPendingAlpha);
        updateLeashesForSide(ISIDE_TOP, offset.top, mShownInsets.top, mPendingInsets.top, params,
                state, mPendingAlpha);
        updateLeashesForSide(ISIDE_RIGHT, offset.right, mShownInsets.right, mPendingInsets.right,
                params, state, mPendingAlpha);
        updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom,
                mPendingInsets.bottom, params, state, mPendingAlpha);

        mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()]));
        mCurrentInsets = mPendingInsets;
        mAnimation.setFraction(mPendingFraction);
        mCurrentAlpha = mPendingAlpha;
        mAnimation.setAlpha(mPendingAlpha);
        if (mFinished) {
            if (DEBUG) Log.d(TAG, String.format(
                    "notifyFinished shown: %s, currentAlpha: %f, currentInsets: %s",
                    mShownOnFinish, mCurrentAlpha, mCurrentInsets));
            mController.notifyFinished(this, mShownOnFinish);
            releaseLeashes();
        }
        if (DEBUG) Log.d(TAG, "Animation finished abruptly.");
        return mFinished;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

这里调用的InsetsAnimationControlImpl的updateLeashesForSide方法:

    private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int maxInset,
            int inset, ArrayList<SurfaceParams> surfaceParams, InsetsState state, Float alpha) {
        ArraySet<InsetsSourceControl> items = mSideSourceMap.get(side);
        if (items == null) {
            return;
        }
        // TODO: Implement behavior when inset spans over multiple types
        for (int i = items.size() - 1; i >= 0; i--) {
            final InsetsSourceControl control = items.valueAt(i);
            final InsetsSource source = mInitialInsetsState.getSource(control.getType());
            final SurfaceControl leash = control.getLeash();

            mTmpMatrix.setTranslate(control.getSurfacePosition().x, control.getSurfacePosition().y);
            mTmpFrame.set(source.getFrame());
            addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);

            final boolean visible = mHasZeroInsetsIme && side == ISIDE_BOTTOM
                    ? (mAnimationType == ANIMATION_TYPE_SHOW ? true : !mFinished)
                    : inset != 0;

            state.getSource(source.getType()).setVisible(visible);
            state.getSource(source.getType()).setFrame(mTmpFrame);

            // If the system is controlling the insets source, the leash can be null.
            if (leash != null) {
                SurfaceParams params = new SurfaceParams.Builder(leash)
                        .withAlpha(alpha)
                        .withMatrix(mTmpMatrix)
                        .withVisibility(visible)
                        .build();
                surfaceParams.add(params);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

对上下左右四个边分别处理,对其leash的属性修改作为SurfaceParams保存到类型为ArrayList的params中。

InsetsAnimationControlImpl的applyChangeInsets方法接下来调用了InsetsAnimationThreadControlRunner.mCallbacks的applySurfaceParams方法:

    private final InsetsAnimationControlCallbacks mCallbacks =
            new InsetsAnimationControlCallbacks() {
        ......
        @Override
        public void applySurfaceParams(SurfaceParams... params) {
            if (DEBUG) Log.d(TAG, "applySurfaceParams");
            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();
            t.close();
        }
        ......
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

调用了frameworks/base/core/java/android/view/SyncRtSurfaceTransactionApplier.java的applyParams方法:

    public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
        if ((params.flags & FLAG_MATRIX) != 0) {
            t.setMatrix(params.surface, params.matrix, tmpFloat9);
        }
        if ((params.flags & FLAG_WINDOW_CROP) != 0) {
            t.setWindowCrop(params.surface, params.windowCrop);
        }
        if ((params.flags & FLAG_ALPHA) != 0) {
            t.setAlpha(params.surface, params.alpha);
        }
        if ((params.flags & FLAG_LAYER) != 0) {
            t.setLayer(params.surface, params.layer);
        }
        if ((params.flags & FLAG_CORNER_RADIUS) != 0) {
            t.setCornerRadius(params.surface, params.cornerRadius);
        }
        if ((params.flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
            t.setBackgroundBlurRadius(params.surface, params.backgroundBlurRadius);
        }
        if ((params.flags & FLAG_VISIBILITY) != 0) {
            if (params.visible) {
                t.show(params.surface);
            } else {
                t.hide(params.surface);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

就这样每帧都根据之前的SurfaceParams属性修改leash对应的layer的属性。

在之前InsetsController的内部静态类InternalAnimationControlListener的onReady方法中,属性动画结束时会调用InternalAnimationControlListener的onAnimationFinish方法:

        protected void onAnimationFinish() {
            mController.finish(mShow);
            if (DEBUG) Log.d(TAG, "onAnimationFinish showOnFinish: " + mShow);
        }
  • 1
  • 2
  • 3
  • 4

这个mController是InsetsAnimationControlImpl,调用了其finish方法:

    @Override
    public void finish(boolean shown) {
        if (mCancelled || mFinished) {
            if (DEBUG) Log.d(TAG, "Animation already canceled or finished, not notifying.");
            return;
        }
        mShownOnFinish = shown;
        mFinished = true;
        setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */,
                true /* allowWhenFinished */);

        if (DEBUG) Log.d(TAG, "notify control request finished for types: " + mTypes);
        mListener.onFinished(this);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

最后一次调用了InsetsAnimationControlImpl的setInsetsAndAlpha方法,将visible的最终状态与InternalAnimationControlListener的成员变量mShow保持一致。

InsetsAnimationControlImpl的applyChangeInsets方法最后在mFinished为true时还调用了InsetsAnimationThreadControlRunner.mCallbacks的notifyFinished方法:

    private final InsetsAnimationControlCallbacks mCallbacks =
            new InsetsAnimationControlCallbacks() {
        ......
        @Override
        public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
            Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
                    "InsetsAsyncAnimation: " + WindowInsets.Type.toString(runner.getTypes()),
                    runner.getTypes());
            releaseControls(mControl.getControls());
            mMainThreadHandler.post(() ->
                    mOuterCallbacks.notifyFinished(InsetsAnimationThreadControlRunner.this, shown));
        }
        ......
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这里的mOuterCallbacks就是InsetsController,切换到主线程调用了InsetsController的notifyFinished方法:

    @VisibleForTesting
    @Override
    public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
        cancelAnimation(runner, false /* invokeCallback */);
        if (DEBUG) Log.d(TAG, "notifyFinished. shown: " + shown);
        if (shown) {
            showDirectly(runner.getTypes());
        } else {
            hideDirectly(runner.getTypes(), true /* animationFinished */,
                    runner.getAnimationType());
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里会再次确保最终visible的状态正确。

但是,如果这个动画被提前cancel了,就无法保证最终visible的状态的正确性。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/732873
推荐阅读
相关标签
  

闽ICP备14008679号