Loading core/java/android/view/InsetsAnimationControlCallbacks.java 0 → 100644 +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); } core/java/android/view/InsetsAnimationControlImpl.java +32 −35 Original line number Diff line number Diff line Loading @@ -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} Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; Loading @@ -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 */); Loading Loading @@ -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); } Loading @@ -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); Loading @@ -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()); Loading @@ -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 */)); } } } Loading Loading @@ -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); } } } core/java/android/view/InsetsController.java +29 −21 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -186,6 +186,8 @@ public class InsetsController implements WindowInsetsController { private int mLastLegacySoftInputMode; private SyncRtSurfaceTransactionApplier mApplier; public InsetsController(ViewRootImpl viewRoot) { mViewRoot = viewRoot; mAnimCallback = () -> { Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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; } Loading @@ -468,6 +462,7 @@ public class InsetsController implements WindowInsetsController { } @VisibleForTesting @Override public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) { mAnimationControls.remove(controller); if (shown) { Loading @@ -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); Loading Loading @@ -620,6 +626,7 @@ public class InsetsController implements WindowInsetsController { } @VisibleForTesting @Override public void dispatchAnimationStarted(InsetsAnimation animation, AnimationBounds bounds) { mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation, bounds); } Loading @@ -630,6 +637,7 @@ public class InsetsController implements WindowInsetsController { } @VisibleForTesting @Override public void scheduleApplyChangeInsets() { if (!mAnimCallbackScheduled) { mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, Loading core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +6 −7 Original line number Diff line number Diff line Loading @@ -76,7 +76,6 @@ public class InsetsAnimationControlImplTest { @Mock Transaction mMockTransaction; @Mock InsetsController mMockController; @Mock WindowInsetsAnimationControlListener mMockListener; @Mock SyncRtSurfaceTransactionApplier mMockTransactionApplier; @BeforeClass public static void setupOnce() { Loading Loading @@ -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 */); } Loading @@ -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); Loading Loading
core/java/android/view/InsetsAnimationControlCallbacks.java 0 → 100644 +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); }
core/java/android/view/InsetsAnimationControlImpl.java +32 −35 Original line number Diff line number Diff line Loading @@ -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} Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; Loading @@ -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 */); Loading Loading @@ -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); } Loading @@ -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); Loading @@ -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()); Loading @@ -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 */)); } } } Loading Loading @@ -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); } } }
core/java/android/view/InsetsController.java +29 −21 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -186,6 +186,8 @@ public class InsetsController implements WindowInsetsController { private int mLastLegacySoftInputMode; private SyncRtSurfaceTransactionApplier mApplier; public InsetsController(ViewRootImpl viewRoot) { mViewRoot = viewRoot; mAnimCallback = () -> { Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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; } Loading @@ -468,6 +462,7 @@ public class InsetsController implements WindowInsetsController { } @VisibleForTesting @Override public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) { mAnimationControls.remove(controller); if (shown) { Loading @@ -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); Loading Loading @@ -620,6 +626,7 @@ public class InsetsController implements WindowInsetsController { } @VisibleForTesting @Override public void dispatchAnimationStarted(InsetsAnimation animation, AnimationBounds bounds) { mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation, bounds); } Loading @@ -630,6 +637,7 @@ public class InsetsController implements WindowInsetsController { } @VisibleForTesting @Override public void scheduleApplyChangeInsets() { if (!mAnimCallbackScheduled) { mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, Loading
core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +6 −7 Original line number Diff line number Diff line Loading @@ -76,7 +76,6 @@ public class InsetsAnimationControlImplTest { @Mock Transaction mMockTransaction; @Mock InsetsController mMockController; @Mock WindowInsetsAnimationControlListener mMockListener; @Mock SyncRtSurfaceTransactionApplier mMockTransactionApplier; @BeforeClass public static void setupOnce() { Loading Loading @@ -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 */); } Loading @@ -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); Loading