Implement Transient Insets Animation
This implements the transient insets animation. To have InsetsPolicy run
the animation, this patch:
1. Let InsetsPolicy implements InsetsAnimationControlCallbacks;
2. Make several properties, methods and subclasses in InsetsController
public, to let InsetsPolicy re-use them when possible.
3. Do everything necessary in InsetsPolicy to let the animation run
correctly.
Other misc changes in this CL includes:
1. Removed some un-necessary imports;
2. Implemented two toString method, for debug purpose.
Bug: 118118435
Test: Manual test with the new Insets API test app, everything works as
expected;
Test: go/wm-smoke
Test: atest InsetsPolicyTest
Change-Id: I6c45bd557573fcabb1a3f5aea3dcd58229280613
This commit is contained in:
@@ -16,8 +16,6 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
|
||||
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
|
||||
import static android.view.InsetsState.ISIDE_BOTTOM;
|
||||
import static android.view.InsetsState.ISIDE_FLOATING;
|
||||
import static android.view.InsetsState.ISIDE_LEFT;
|
||||
@@ -188,7 +186,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
||||
|
||||
@Override
|
||||
public void finish(boolean shown) {
|
||||
if (mCancelled) {
|
||||
if (mCancelled || mFinished) {
|
||||
return;
|
||||
}
|
||||
setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
|
||||
|
||||
@@ -69,7 +69,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
||||
private static final int ANIMATION_DURATION_HIDE_MS = 340;
|
||||
private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;
|
||||
|
||||
static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
|
||||
public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
|
||||
|
||||
/**
|
||||
* Layout mode during insets animation: The views should be laid out as if the changing inset
|
||||
@@ -77,7 +77,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
||||
* be called as if the changing insets types are shown, which will result in the views being
|
||||
* laid out as if the insets are fully shown.
|
||||
*/
|
||||
static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
|
||||
public static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
|
||||
|
||||
/**
|
||||
* Layout mode during insets animation: The views should be laid out as if the changing inset
|
||||
@@ -85,7 +85,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
||||
* be called as if the changing insets types are hidden, which will result in the views being
|
||||
* laid out as if the insets are fully hidden.
|
||||
*/
|
||||
static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
|
||||
public static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
|
||||
|
||||
/**
|
||||
* Determines the behavior of how the views should be laid out during an insets animation that
|
||||
@@ -148,7 +148,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
||||
@Override
|
||||
public void set(WindowInsetsAnimationController controller, Insets value) {
|
||||
controller.setInsetsAndAlpha(
|
||||
value, 1f /* alpha */, (((DefaultAnimationControlListener)
|
||||
value, 1f /* alpha */, (((InternalAnimationControlListener)
|
||||
((InsetsAnimationControlImpl) controller).getListener())
|
||||
.getRawFraction()));
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
||||
private ObjectAnimator mAnimator;
|
||||
protected boolean mShow;
|
||||
|
||||
InternalAnimationControlListener(boolean show) {
|
||||
public InternalAnimationControlListener(boolean show) {
|
||||
mShow = show;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
||||
return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
|
||||
}
|
||||
|
||||
protected long getDurationMs() {
|
||||
/**
|
||||
* To get the animation duration in MS.
|
||||
*/
|
||||
public long getDurationMs() {
|
||||
if (mAnimator != null) {
|
||||
return mAnimator.getDuration();
|
||||
}
|
||||
|
||||
@@ -181,6 +181,15 @@ public class InsetsSource implements Parcelable {
|
||||
dest.writeBoolean(mVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InsetsSource: {"
|
||||
+ "mType=" + InsetsState.typeToString(mType)
|
||||
+ ", mFrame=" + mFrame.toShortString()
|
||||
+ ", mVisible" + mVisible
|
||||
+ "}";
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<InsetsSource> CREATOR = new Creator<InsetsSource>() {
|
||||
|
||||
public InsetsSource createFromParcel(Parcel in) {
|
||||
|
||||
@@ -21,7 +21,6 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
|
||||
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
|
||||
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
|
||||
import static android.view.ViewRootImpl.sNewInsetsMode;
|
||||
import static android.view.WindowInsets.Type.IME;
|
||||
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
|
||||
import static android.view.WindowInsets.Type.SIZE;
|
||||
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
|
||||
@@ -43,7 +42,6 @@ import android.util.ArraySet;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.WindowInsets.Type;
|
||||
import android.view.WindowInsets.Type.InsetsType;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -366,7 +364,12 @@ public class InsetsState implements Parcelable {
|
||||
return result;
|
||||
}
|
||||
|
||||
static @Type.InsetsType int toPublicType(@InternalInsetsType int type) {
|
||||
/**
|
||||
* Converting a internal type to the public type.
|
||||
* @param type internal insets type, {@code InternalInsetsType}.
|
||||
* @return public insets type, {@code Type.InsetsType}.
|
||||
*/
|
||||
public static @Type.InsetsType int toPublicType(@InternalInsetsType int type) {
|
||||
switch (type) {
|
||||
case ITYPE_STATUS_BAR:
|
||||
return Type.STATUS_BARS;
|
||||
@@ -510,5 +513,13 @@ public class InsetsState implements Parcelable {
|
||||
mSources.put(source.getType(), source);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InsetsState: {"
|
||||
+ "mDisplayFrame=" + mDisplayFrame
|
||||
+ ", mSources=" + mSources
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,31 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
|
||||
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
|
||||
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
|
||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
||||
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.StatusBarManager;
|
||||
import android.util.IntArray;
|
||||
import android.util.SparseArray;
|
||||
import android.view.InsetsAnimationControlCallbacks;
|
||||
import android.view.InsetsAnimationControlImpl;
|
||||
import android.view.InsetsController;
|
||||
import android.view.InsetsSourceControl;
|
||||
import android.view.InsetsState;
|
||||
import android.view.InsetsState.InternalInsetsType;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SyncRtSurfaceTransactionApplier;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.view.WindowInsetsAnimationCallback;
|
||||
import android.view.WindowInsetsAnimationControlListener;
|
||||
|
||||
import com.android.server.DisplayThread;
|
||||
|
||||
/**
|
||||
* Policy that implements who gets control over the windows generating insets.
|
||||
@@ -46,6 +60,8 @@ class InsetsPolicy {
|
||||
private WindowState mFocusedWin;
|
||||
private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
|
||||
private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
|
||||
private boolean mAnimatingShown;
|
||||
private final float[] mTmpFloat9 = new float[9];
|
||||
|
||||
InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
|
||||
mStateController = stateController;
|
||||
@@ -91,11 +107,14 @@ class InsetsPolicy {
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
updateBarControlTarget(mFocusedWin);
|
||||
mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
|
||||
mShowingTransientTypes.toArray());
|
||||
mStateController.notifyInsetsChanged();
|
||||
// TODO(b/118118435): Animation
|
||||
startAnimation(mShowingTransientTypes, true, () -> {
|
||||
synchronized (mDisplayContent.mWmService.mGlobalLock) {
|
||||
mPolicy.getStatusBarManagerInternal().showTransient(
|
||||
mDisplayContent.getDisplayId(),
|
||||
mShowingTransientTypes.toArray());
|
||||
mStateController.notifyInsetsChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,11 +122,13 @@ class InsetsPolicy {
|
||||
if (mShowingTransientTypes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(b/118118435): Animation
|
||||
mShowingTransientTypes.clear();
|
||||
updateBarControlTarget(mFocusedWin);
|
||||
mStateController.notifyInsetsChanged();
|
||||
startAnimation(mShowingTransientTypes, false, () -> {
|
||||
synchronized (mDisplayContent.mWmService.mGlobalLock) {
|
||||
mShowingTransientTypes.clear();
|
||||
mStateController.notifyInsetsChanged();
|
||||
updateBarControlTarget(mFocusedWin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
boolean isTransient(@InternalInsetsType int type) {
|
||||
@@ -242,6 +263,29 @@ class InsetsPolicy {
|
||||
return isDockedStackVisible || isFreeformStackVisible || isResizing;
|
||||
}
|
||||
|
||||
private void startAnimation(IntArray internalTypes, boolean show, Runnable callback) {
|
||||
int typesReady = 0;
|
||||
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
|
||||
updateBarControlTarget(mFocusedWin);
|
||||
for (int i = internalTypes.size() - 1; i >= 0; i--) {
|
||||
InsetsSourceProvider provider =
|
||||
mStateController.getSourceProvider(internalTypes.get(i));
|
||||
if (provider == null) continue;
|
||||
InsetsSourceControl control = provider.getControl(provider.getControlTarget());
|
||||
if (control == null || control.getLeash() == null) continue;
|
||||
typesReady |= InsetsState.toPublicType(internalTypes.get(i));
|
||||
controls.put(control.getType(), control);
|
||||
}
|
||||
controlAnimationUnchecked(typesReady, controls, show, callback);
|
||||
}
|
||||
|
||||
private void controlAnimationUnchecked(int typesReady,
|
||||
SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
|
||||
InsetsPolicyAnimationControlListener listener =
|
||||
new InsetsPolicyAnimationControlListener(show, callback);
|
||||
listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
|
||||
}
|
||||
|
||||
private class BarWindow {
|
||||
|
||||
private final int mId;
|
||||
@@ -262,7 +306,103 @@ class InsetsPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/118118435): Implement animations for it (with SurfaceAnimator)
|
||||
private class InsetsPolicyAnimationControlListener extends
|
||||
InsetsController.InternalAnimationControlListener {
|
||||
Runnable mFinishCallback;
|
||||
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
|
||||
|
||||
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
|
||||
super(show);
|
||||
mFinishCallback = finishCallback;
|
||||
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAnimationFinish() {
|
||||
super.onAnimationFinish();
|
||||
mControlCallbacks.mAnimationControl.finish(mAnimatingShown);
|
||||
DisplayThread.getHandler().post(mFinishCallback);
|
||||
}
|
||||
|
||||
private class InsetsPolicyAnimationControlCallbacks implements
|
||||
InsetsAnimationControlCallbacks {
|
||||
private InsetsAnimationControlImpl mAnimationControl = null;
|
||||
private InsetsPolicyAnimationControlListener mListener;
|
||||
|
||||
InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) {
|
||||
super();
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private void controlAnimationUnchecked(int typesReady,
|
||||
SparseArray<InsetsSourceControl> controls, boolean show) {
|
||||
if (typesReady == 0) {
|
||||
// nothing to animate.
|
||||
return;
|
||||
}
|
||||
mAnimatingShown = show;
|
||||
|
||||
mAnimationControl = new InsetsAnimationControlImpl(controls,
|
||||
mFocusedWin.getDisplayContent().getBounds(), getState(),
|
||||
mListener, typesReady, this, mListener.getDurationMs(),
|
||||
InsetsController.INTERPOLATOR, true,
|
||||
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
|
||||
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
|
||||
}
|
||||
|
||||
/** Called on SurfaceAnimationThread lock without global WM lock held. */
|
||||
@Override
|
||||
public void scheduleApplyChangeInsets() {
|
||||
InsetsState state = getState();
|
||||
if (mAnimationControl.applyChangeInsets(state)) {
|
||||
mAnimationControl.finish(mAnimatingShown);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
|
||||
// Nothing's needed here. Finish steps is handled in the listener
|
||||
// onAnimationFinished callback.
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return a state with fullscreen frame override. No need to make copy
|
||||
* after getting state from this method.
|
||||
* @return The client insets state with full display frame override.
|
||||
*/
|
||||
private InsetsState getState() {
|
||||
// To animate the transient animation correctly, we need to let the state hold
|
||||
// the full display frame.
|
||||
InsetsState overrideState = new InsetsState(mFocusedWin.getRequestedInsetsState(),
|
||||
true);
|
||||
overrideState.setDisplayFrame(mFocusedWin.getDisplayContent().getBounds());
|
||||
return overrideState;
|
||||
}
|
||||
|
||||
/** Called on SurfaceAnimationThread lock without global WM lock held. */
|
||||
@Override
|
||||
public void applySurfaceParams(
|
||||
final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
|
||||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
for (int i = params.length - 1; i >= 0; i--) {
|
||||
SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
|
||||
applyParams(t, surfaceParams, mTmpFloat9);
|
||||
}
|
||||
t.apply();
|
||||
}
|
||||
|
||||
/** Called on SurfaceAnimationThread lock without global WM lock held. */
|
||||
@Override
|
||||
public void startAnimation(InsetsAnimationControlImpl controller,
|
||||
WindowInsetsAnimationControlListener listener, int types,
|
||||
WindowInsetsAnimationCallback.InsetsAnimation animation,
|
||||
WindowInsetsAnimationCallback.AnimationBounds bounds,
|
||||
int layoutDuringAnimation) {
|
||||
SurfaceAnimationThread.getHandler().post(() -> listener.onReady(controller, types));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TransientControlTarget implements InsetsControlTarget {
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user