Merge "Decoupling InsetsAnimationControlImpl and the client"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a9ae085264
55
core/java/android/view/InsetsAnimationControlCallbacks.java
Normal file
55
core/java/android/view/InsetsAnimationControlCallbacks.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
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;
|
||||
}
|
||||
private int collectPendingTypes(@InsetsType int typesReady) {
|
||||
typesReady |= mPendingTypesToShow;
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user