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

Commit a9ae0852 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Decoupling InsetsAnimationControlImpl and the client"

parents 7b197372 02abf55a
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

/**
 * Provide an interface to let InsetsAnimationControlImpl call back into its owner.
 * @hide
 */
public interface InsetsAnimationControlCallbacks {
    /**
     * Dispatch the animation started event to all listeners.
     * @param animation
     */
    void dispatchAnimationStarted(WindowInsetsAnimationCallback.InsetsAnimation animation,
            WindowInsetsAnimationCallback.AnimationBounds bounds);

    /**
     * Schedule the apply by posting the animation callback.
     */
    void scheduleApplyChangeInsets();

    /**
     * Finish the final steps after the animation.
     * @param controller The controller used to control the animation.
     * @param shown {@code true} if the insets are shown.
     */
    void notifyFinished(InsetsAnimationControlImpl controller, boolean shown);

    /**
     * Get the description of the insets state.
     * @return {@link InsetsState} for adjusting corresponding {@link InsetsSource}.
     */
    InsetsState getState();

    /**
     * Apply the new params to the surface.
     * @param params The {@link android.view.SyncRtSurfaceTransactionApplier.SurfaceParams} to
     *               apply.
     */
    void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params);
}
+32 −35
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.function.Supplier;

/**
 * Implements {@link WindowInsetsAnimationController}
@@ -52,9 +51,9 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private final Rect mTmpFrame = new Rect();

    private final WindowInsetsAnimationControlListener mListener;
    private final SparseArray<InsetsSourceConsumer> mConsumers;
    private final SparseArray<InsetsSourceControl> mControls;
    private final SparseIntArray mTypeSideMap = new SparseIntArray();
    private final SparseSetArray<InsetsSourceConsumer> mSideSourceMap = new SparseSetArray<>();
    private final SparseSetArray<InsetsSourceControl> mSideSourceMap = new SparseSetArray<>();

    /** @see WindowInsetsAnimationController#getHiddenStateInsets */
    private final Insets mHiddenInsets;
@@ -64,8 +63,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private final Matrix mTmpMatrix = new Matrix();
    private final InsetsState mInitialInsetsState;
    private final @InsetsType int mTypes;
    private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier;
    private final InsetsController mController;
    private final InsetsAnimationControlCallbacks mController;
    private final WindowInsetsAnimationCallback.InsetsAnimation mAnimation;
    private final Rect mFrame;
    private final boolean mFade;
@@ -79,25 +77,23 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private float mPendingAlpha;

    @VisibleForTesting
    public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
    public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, Rect frame,
            InsetsState state, WindowInsetsAnimationControlListener listener,
            @InsetsType int types,
            Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier,
            InsetsController controller, long durationMs, boolean fade) {
        mConsumers = consumers;
            InsetsAnimationControlCallbacks controller, long durationMs, boolean fade) {
        mControls = controls;
        mListener = listener;
        mTypes = types;
        mFade = fade;
        mTransactionApplierSupplier = transactionApplierSupplier;
        mController = controller;
        mInitialInsetsState = new InsetsState(state, true /* copySources */);
        mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
        mHiddenInsets = calculateInsets(mInitialInsetsState, frame, consumers, false /* shown */,
        mHiddenInsets = calculateInsets(mInitialInsetsState, frame, controls, false /* shown */,
                null /* typeSideMap */);
        mShownInsets = calculateInsets(mInitialInsetsState, frame, consumers, true /* shown */,
        mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
                mTypeSideMap);
        mFrame = new Rect(frame);
        buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mConsumers);
        buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);

        // TODO: Check for controllability first and wait for IME if needed.
        listener.onReady(this, types);
@@ -172,8 +168,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
        updateLeashesForSide(ISIDE_FLOATING, 0 /* offset */, 0 /* inset */, 0 /* maxInset */,
                params, state, alphaOffset);

        SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
        applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
        mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()]));
        mCurrentInsets = mPendingInsets;
        mAnimation.setFraction(mPendingFraction);
        mCurrentAlpha = 1 - alphaOffset;
@@ -189,9 +184,9 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
            return;
        }
        InsetsState state = new InsetsState(mController.getState());
        for (int i = mConsumers.size() - 1; i >= 0; i--) {
            InsetsSourceConsumer consumer = mConsumers.valueAt(i);
            state.getSource(consumer.getType()).setVisible(shown);
        for (int i = mControls.size() - 1; i >= 0; i--) {
            InsetsSourceControl control = mControls.valueAt(i);
            state.getSource(control.getType()).setVisible(shown);
        }
        Insets insets = getInsetsFromState(state, mFrame, null /* typeSideMap */);
        setInsetsAndAlpha(insets, 1f /* alpha */, shown ? 1f : 0f /* fraction */);
@@ -222,10 +217,12 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    }

    private Insets calculateInsets(InsetsState state, Rect frame,
            SparseArray<InsetsSourceConsumer> consumers, boolean shown,
            SparseArray<InsetsSourceControl> controls, boolean shown,
            @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
        for (int i = consumers.size() - 1; i >= 0; i--) {
            state.getSource(consumers.valueAt(i).getType()).setVisible(shown);
        for (int i = controls.size() - 1; i >= 0; i--) {
            // control may be null if it got revoked.
            if (controls.valueAt(i) == null) continue;
            state.getSource(controls.valueAt(i).getType()).setVisible(shown);
        }
        return getInsetsFromState(state, frame, typeSideMap);
    }
@@ -233,7 +230,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private Insets getInsetsFromState(InsetsState state, Rect frame,
            @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
        return state.calculateInsets(frame, false /* isScreenRound */,
                false /* alwaysConsumerNavBar */, null /* displayCutout */,
                false /* alwaysConsumeSystemBars */, null /* displayCutout */,
                null /* legacyContentInsets */, null /* legacyStableInsets */,
                LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/, typeSideMap)
               .getInsets(mTypes);
@@ -252,20 +249,19 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll

    private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset,
            int maxInset, ArrayList<SurfaceParams> surfaceParams, InsetsState state, Float alpha) {
        ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side);
        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 InsetsSourceConsumer consumer = items.valueAt(i);
            final InsetsSource source = mInitialInsetsState.getSource(consumer.getType());
            final InsetsSourceControl control = consumer.getControl();
            final InsetsSourceControl control = items.valueAt(i);
            final InsetsSource source = mInitialInsetsState.getSource(control.getType());
            if (control == null) {
                // Control may not be available for consumer yet or revoked.
                // TODO: remove this check when we ensure the elements will not be null.
                continue;
            }
            final SurfaceControl leash = consumer.getControl().getLeash();
            final SurfaceControl leash = control.getLeash();

            mTmpMatrix.setTranslate(control.getSurfacePosition().x, control.getSurfacePosition().y);
            mTmpFrame.set(source.getFrame());
@@ -279,7 +275,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
                alpha = mFade ? ((float) maxInset / inset * 0.3f + 0.7f) : alpha;
                surfaceParams.add(new SurfaceParams(leash, alpha, mTmpMatrix,
                        null /* windowCrop */, 0 /* layer */, 0f /* cornerRadius*/,
                        side == ISIDE_FLOATING ? consumer.isVisible() : inset != 0 /* visible */));
                        side == ISIDE_FLOATING ? state.getSource(source.getType()).isVisible()
                                : inset != 0 /* visible */));
            }
        }
    }
@@ -307,18 +304,18 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    }

    private static void buildTypeSourcesMap(SparseIntArray typeSideMap,
            SparseSetArray<InsetsSourceConsumer> sideSourcesMap,
            SparseArray<InsetsSourceConsumer> consumers) {
            SparseSetArray<InsetsSourceControl> sideSourcesMap,
            SparseArray<InsetsSourceControl> controls) {
        for (int i = typeSideMap.size() - 1; i >= 0; i--) {
            final int type = typeSideMap.keyAt(i);
            final int side = typeSideMap.valueAt(i);
            final InsetsSourceConsumer consumer = consumers.get(type);
            if (consumer == null) {
            final InsetsSourceControl control = controls.get(type);
            if (control == null) {
                // If the types that we are controlling are less than the types that the system has,
                // there can be some null consumers.
                // there can be some null controllers.
                continue;
            }
            sideSourcesMap.add(side, consumer);
            sideSourcesMap.add(side, control);
        }
    }
}
+29 −21
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ import java.util.ArrayList;
 * Implements {@link WindowInsetsController} on the client.
 * @hide
 */
public class InsetsController implements WindowInsetsController {
public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks {

    private static final int ANIMATION_DURATION_SHOW_MS = 275;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;
@@ -186,6 +186,8 @@ public class InsetsController implements WindowInsetsController {

    private int mLastLegacySoftInputMode;

    private SyncRtSurfaceTransactionApplier mApplier;

    public InsetsController(ViewRootImpl viewRoot) {
        mViewRoot = viewRoot;
        mAnimCallback = () -> {
@@ -375,9 +377,10 @@ public class InsetsController implements WindowInsetsController {

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

        Pair<Integer, Boolean> typesReadyPair = collectConsumers(
                fromIme, internalTypes, consumers, listener);
        Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
                fromIme, internalTypes, controls, listener);
        int typesReady = typesReadyPair.first;
        boolean isReady = typesReadyPair.second;
        if (!isReady) {
@@ -388,24 +391,23 @@ public class InsetsController implements WindowInsetsController {
        }

        // pending types from previous request.
        typesReady = collectPendingConsumers(typesReady, consumers);
        typesReady = collectPendingTypes(typesReady);

        if (typesReady == 0) {
            listener.onCancelled();
            return;
        }

        final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
                frame, mState, listener, typesReady,
                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this, durationMs, fade);
        final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
                frame, mState, listener, typesReady, this, durationMs, fade);
        mAnimationControls.add(controller);
    }

    /**
     * @return Pair of (types ready to animate, is ready to animate).
     */
    private Pair<Integer, Boolean> collectConsumers(boolean fromIme,
            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceConsumer> consumers,
    private Pair<Integer, Boolean> collectSourceControls(boolean fromIme,
            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls,
            WindowInsetsAnimationControlListener listener) {
        int typesReady = 0;
        boolean isReady = true;
@@ -439,22 +441,14 @@ public class InsetsController implements WindowInsetsController {
                }
                typesReady |= InsetsState.toPublicType(consumer.getType());
            }
            consumers.put(consumer.getType(), consumer);
            controls.put(consumer.getType(), consumer.getControl());
        }
        return new Pair<>(typesReady, isReady);
    }

    private int collectPendingConsumers(@InsetsType int typesReady,
            SparseArray<InsetsSourceConsumer> consumers) {
        if (mPendingTypesToShow != 0) {
    private int collectPendingTypes(@InsetsType int typesReady) {
        typesReady |= mPendingTypesToShow;
            final ArraySet<Integer> internalTypes = mState.toInternalType(mPendingTypesToShow);
            for (int i = internalTypes.size() - 1; i >= 0; i--) {
                InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
                consumers.put(consumer.getType(), consumer);
            }
        mPendingTypesToShow = 0;
        }
        return typesReady;
    }

@@ -468,6 +462,7 @@ public class InsetsController implements WindowInsetsController {
    }

    @VisibleForTesting
    @Override
    public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
        mAnimationControls.remove(controller);
        if (shown) {
@@ -477,6 +472,17 @@ public class InsetsController implements WindowInsetsController {
        }
    }

    @Override
    public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
        if (mApplier == null) {
            if (mViewRoot.mView == null) {
                throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
            }
            mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
        }
        mApplier.scheduleApply(params);
    }

    void notifyControlRevoked(InsetsSourceConsumer consumer) {
        for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
            InsetsAnimationControlImpl control = mAnimationControls.get(i);
@@ -620,6 +626,7 @@ public class InsetsController implements WindowInsetsController {
    }

    @VisibleForTesting
    @Override
    public void dispatchAnimationStarted(InsetsAnimation animation, AnimationBounds bounds) {
        mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation, bounds);
    }
@@ -630,6 +637,7 @@ public class InsetsController implements WindowInsetsController {
    }

    @VisibleForTesting
    @Override
    public void scheduleApplyChangeInsets() {
        if (!mAnimCallbackScheduled) {
            mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION,
+6 −7
Original line number Diff line number Diff line
@@ -76,7 +76,6 @@ public class InsetsAnimationControlImplTest {
    @Mock Transaction mMockTransaction;
    @Mock InsetsController mMockController;
    @Mock WindowInsetsAnimationControlListener mMockListener;
    @Mock SyncRtSurfaceTransactionApplier mMockTransactionApplier;

    @BeforeClass
    public static void setupOnce() {
@@ -111,12 +110,12 @@ public class InsetsAnimationControlImplTest {
        navConsumer.setControl(new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mNavLeash,
                new Point(400, 0)));

        SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
        consumers.put(ITYPE_STATUS_BAR, topConsumer);
        consumers.put(ITYPE_NAVIGATION_BAR, navConsumer);
        mController = new InsetsAnimationControlImpl(consumers,
        SparseArray<InsetsSourceControl> controls = new SparseArray<>();
        controls.put(ITYPE_STATUS_BAR, topConsumer.getControl());
        controls.put(ITYPE_NAVIGATION_BAR, navConsumer.getControl());
        mController = new InsetsAnimationControlImpl(controls,
                new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
                () -> mMockTransactionApplier, mMockController, 10 /* durationMs */,
                mMockController, 10 /* durationMs */,
                false /* fade */);
    }

@@ -137,7 +136,7 @@ public class InsetsAnimationControlImplTest {
        assertEquals(1f, mController.getCurrentAlpha(), 1f - mController.getCurrentAlpha());

        ArgumentCaptor<SurfaceParams> captor = ArgumentCaptor.forClass(SurfaceParams.class);
        verify(mMockTransactionApplier).scheduleApply(captor.capture());
        verify(mMockController).applySurfaceParams(captor.capture());
        List<SurfaceParams> params = captor.getAllValues();
        assertEquals(2, params.size());
        SurfaceParams first = params.get(0);