Merge "Use separate thread if app doesn't listen to animations" into rvc-dev am: 92fd77548a am: 9d0fc001c3
Change-Id: I33678818ad20fcc2324485779e8b3763ad67810b
This commit is contained in:
@@ -18,6 +18,7 @@ package android.animation;
|
|||||||
|
|
||||||
import android.annotation.CallSuper;
|
import android.annotation.CallSuper;
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.annotation.TestApi;
|
import android.annotation.TestApi;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -268,6 +269,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
|||||||
*/
|
*/
|
||||||
private float mDurationScale = -1f;
|
private float mDurationScale = -1f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation handler used to schedule updates for this animation.
|
||||||
|
*/
|
||||||
|
private AnimationHandler mAnimationHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public constants
|
* Public constants
|
||||||
*/
|
*/
|
||||||
@@ -1684,6 +1690,15 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public AnimationHandler getAnimationHandler() {
|
public AnimationHandler getAnimationHandler() {
|
||||||
return AnimationHandler.getInstance();
|
return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the animation handler used to schedule updates for this animator or {@code null} to use
|
||||||
|
* the default handler.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void setAnimationHandler(@Nullable AnimationHandler animationHandler) {
|
||||||
|
mAnimationHandler = animationHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package android.view;
|
package android.view;
|
||||||
|
|
||||||
import android.view.InsetsController.LayoutInsetsDuringAnimation;
|
|
||||||
import android.view.WindowInsetsAnimation.Bounds;
|
import android.view.WindowInsetsAnimation.Bounds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +36,7 @@ public interface InsetsAnimationControlCallbacks {
|
|||||||
void startAnimation(InsetsAnimationControlImpl controller,
|
void startAnimation(InsetsAnimationControlImpl controller,
|
||||||
WindowInsetsAnimationControlListener listener, int types,
|
WindowInsetsAnimationControlListener listener, int types,
|
||||||
WindowInsetsAnimation animation,
|
WindowInsetsAnimation animation,
|
||||||
Bounds bounds, @LayoutInsetsDuringAnimation int layoutDuringAnimation);
|
Bounds bounds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule the apply by posting the animation callback.
|
* Schedule the apply by posting the animation callback.
|
||||||
@@ -46,10 +45,10 @@ public interface InsetsAnimationControlCallbacks {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the final steps after the animation.
|
* Finish the final steps after the animation.
|
||||||
* @param controller The controller used to control the animation.
|
* @param runner The runner used to run the animation.
|
||||||
* @param shown {@code true} if the insets are shown.
|
* @param shown {@code true} if the insets are shown.
|
||||||
*/
|
*/
|
||||||
void notifyFinished(InsetsAnimationControlImpl controller, boolean shown);
|
void notifyFinished(InsetsAnimationControlRunner runner, boolean shown);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the new params to the surface.
|
* Apply the new params to the surface.
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ import android.util.ArraySet;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.util.SparseSetArray;
|
import android.util.SparseSetArray;
|
||||||
import android.view.InsetsController.LayoutInsetsDuringAnimation;
|
|
||||||
import android.view.InsetsState.InternalInsetsSide;
|
import android.view.InsetsState.InternalInsetsSide;
|
||||||
import android.view.InsetsState.InternalInsetsType;
|
|
||||||
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
|
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
|
||||||
import android.view.WindowInsets.Type.InsetsType;
|
import android.view.WindowInsets.Type.InsetsType;
|
||||||
import android.view.WindowInsetsAnimation.Bounds;
|
import android.view.WindowInsetsAnimation.Bounds;
|
||||||
@@ -49,7 +47,8 @@ import java.util.ArrayList;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public class InsetsAnimationControlImpl implements WindowInsetsAnimationController {
|
public class InsetsAnimationControlImpl implements WindowInsetsAnimationController,
|
||||||
|
InsetsAnimationControlRunner {
|
||||||
|
|
||||||
private final Rect mTmpFrame = new Rect();
|
private final Rect mTmpFrame = new Rect();
|
||||||
|
|
||||||
@@ -84,8 +83,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
InsetsState state, WindowInsetsAnimationControlListener listener,
|
InsetsState state, WindowInsetsAnimationControlListener listener,
|
||||||
@InsetsType int types,
|
@InsetsType int types,
|
||||||
InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
|
InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
|
||||||
boolean fade, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
|
boolean fade, @AnimationType int animationType) {
|
||||||
@AnimationType int animationType) {
|
|
||||||
mControls = controls;
|
mControls = controls;
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
mTypes = types;
|
mTypes = types;
|
||||||
@@ -105,7 +103,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
mAnimation.setAlpha(getCurrentAlpha());
|
mAnimation.setAlpha(getCurrentAlpha());
|
||||||
mAnimationType = animationType;
|
mAnimationType = animationType;
|
||||||
mController.startAnimation(this, listener, types, mAnimation,
|
mController.startAnimation(this, listener, types, mAnimation,
|
||||||
new Bounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation);
|
new Bounds(mHiddenInsets, mShownInsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -133,11 +131,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
return mTypes;
|
return mTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean controlsInternalType(@InternalInsetsType int type) {
|
@Override
|
||||||
return InsetsState.toInternalType(mTypes).contains(type);
|
public @AnimationType int getAnimationType() {
|
||||||
}
|
|
||||||
|
|
||||||
@AnimationType int getAnimationType() {
|
|
||||||
return mAnimationType;
|
return mAnimationType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +200,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
return mAnimation.getFraction();
|
return mAnimation.getFraction();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCancelled() {
|
@Override
|
||||||
|
public void cancel() {
|
||||||
if (mFinished) {
|
if (mFinished) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -217,7 +213,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
return mCancelled;
|
return mCancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowInsetsAnimation getAnimation() {
|
@Override
|
||||||
|
public WindowInsetsAnimation getAnimation() {
|
||||||
return mAnimation;
|
return mAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +222,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
return mListener;
|
return mListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SparseArray<InsetsSourceControl> getControls() {
|
||||||
|
return mControls;
|
||||||
|
}
|
||||||
|
|
||||||
private Insets calculateInsets(InsetsState state, Rect frame,
|
private Insets calculateInsets(InsetsState state, Rect frame,
|
||||||
SparseArray<InsetsSourceControl> controls, boolean shown,
|
SparseArray<InsetsSourceControl> controls, boolean shown,
|
||||||
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
|
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
|
||||||
|
|||||||
56
core/java/android/view/InsetsAnimationControlRunner.java
Normal file
56
core/java/android/view/InsetsAnimationControlRunner.java
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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;
|
||||||
|
|
||||||
|
import android.view.InsetsController.AnimationType;
|
||||||
|
import android.view.InsetsState.InternalInsetsType;
|
||||||
|
import android.view.WindowInsets.Type.InsetsType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface representing a runner for an insets animation.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public interface InsetsAnimationControlRunner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link InsetsType} the animation of this runner is controlling.
|
||||||
|
*/
|
||||||
|
@InsetsType int getTypes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the animation.
|
||||||
|
*/
|
||||||
|
void cancel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The animation this runner is running.
|
||||||
|
*/
|
||||||
|
WindowInsetsAnimation getAnimation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether {@link #getTypes()} maps to a specific {@link InternalInsetsType}.
|
||||||
|
*/
|
||||||
|
default boolean controlsInternalType(@InternalInsetsType int type) {
|
||||||
|
return InsetsState.toInternalType(getTypes()).contains(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The animation type this runner is running.
|
||||||
|
*/
|
||||||
|
@AnimationType int getAnimationType();
|
||||||
|
}
|
||||||
70
core/java/android/view/InsetsAnimationThread.java
Normal file
70
core/java/android/view/InsetsAnimationThread.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Trace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread to be used for inset animations to be running off the main thread.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class InsetsAnimationThread extends HandlerThread {
|
||||||
|
|
||||||
|
private static InsetsAnimationThread sInstance;
|
||||||
|
private static Handler sHandler;
|
||||||
|
|
||||||
|
private InsetsAnimationThread() {
|
||||||
|
// TODO: Should this use higher priority?
|
||||||
|
super("InsetsAnimations");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureThreadLocked() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new InsetsAnimationThread();
|
||||||
|
sInstance.start();
|
||||||
|
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_VIEW);
|
||||||
|
sHandler = new Handler(sInstance.getLooper());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void release() {
|
||||||
|
synchronized (InsetsAnimationThread.class) {
|
||||||
|
if (sInstance == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sInstance.getLooper().quitSafely();
|
||||||
|
sInstance = null;
|
||||||
|
sHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InsetsAnimationThread get() {
|
||||||
|
synchronized (InsetsAnimationThread.class) {
|
||||||
|
ensureThreadLocked();
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Handler getHandler() {
|
||||||
|
synchronized (InsetsAnimationThread.class) {
|
||||||
|
ensureThreadLocked();
|
||||||
|
return sHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
core/java/android/view/InsetsAnimationThreadControlRunner.java
Normal file
130
core/java/android/view/InsetsAnimationThreadControlRunner.java
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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;
|
||||||
|
|
||||||
|
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
|
||||||
|
|
||||||
|
import android.annotation.UiThread;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.InsetsController.AnimationType;
|
||||||
|
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
|
||||||
|
import android.view.WindowInsets.Type.InsetsType;
|
||||||
|
import android.view.WindowInsetsAnimation.Bounds;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insets animation runner that uses {@link InsetsAnimationThread} to run the animation off from the
|
||||||
|
* main thread.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class InsetsAnimationThreadControlRunner implements InsetsAnimationControlRunner {
|
||||||
|
|
||||||
|
private final InsetsAnimationControlImpl mControl;
|
||||||
|
private final InsetsAnimationControlCallbacks mOuterCallbacks;
|
||||||
|
private final Handler mMainThreadHandler;
|
||||||
|
private final InsetsState mState = new InsetsState();
|
||||||
|
private final InsetsAnimationControlCallbacks mCallbacks =
|
||||||
|
new InsetsAnimationControlCallbacks() {
|
||||||
|
|
||||||
|
private final float[] mTmpFloat9 = new float[9];
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@UiThread
|
||||||
|
public void startAnimation(InsetsAnimationControlImpl controller,
|
||||||
|
WindowInsetsAnimationControlListener listener, int types,
|
||||||
|
WindowInsetsAnimation animation, Bounds bounds) {
|
||||||
|
// Animation will be started in constructor already.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduleApplyChangeInsets() {
|
||||||
|
mControl.applyChangeInsets(mState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
|
||||||
|
releaseControls(mControl.getControls());
|
||||||
|
mMainThreadHandler.post(() ->
|
||||||
|
mOuterCallbacks.notifyFinished(InsetsAnimationThreadControlRunner.this, shown));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applySurfaceParams(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();
|
||||||
|
t.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, Rect frame,
|
||||||
|
InsetsState state, WindowInsetsAnimationControlListener listener,
|
||||||
|
@InsetsType int types,
|
||||||
|
InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
|
||||||
|
boolean fade, @AnimationType int animationType, Handler mainThreadHandler) {
|
||||||
|
mMainThreadHandler = mainThreadHandler;
|
||||||
|
mOuterCallbacks = controller;
|
||||||
|
mControl = new InsetsAnimationControlImpl(copyControls(controls), frame, state, listener,
|
||||||
|
types, mCallbacks, durationMs, interpolator, fade, animationType);
|
||||||
|
InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseControls(SparseArray<InsetsSourceControl> controls) {
|
||||||
|
for (int i = controls.size() - 1; i >= 0; i--) {
|
||||||
|
controls.valueAt(i).release(SurfaceControl::release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SparseArray<InsetsSourceControl> copyControls(
|
||||||
|
SparseArray<InsetsSourceControl> controls) {
|
||||||
|
SparseArray<InsetsSourceControl> copy = new SparseArray<>(controls.size());
|
||||||
|
for (int i = 0; i < controls.size(); i++) {
|
||||||
|
copy.append(controls.keyAt(i), new InsetsSourceControl(controls.valueAt(i)));
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@UiThread
|
||||||
|
public int getTypes() {
|
||||||
|
return mControl.getTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@UiThread
|
||||||
|
public void cancel() {
|
||||||
|
InsetsAnimationThread.getHandler().post(mControl::cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@UiThread
|
||||||
|
public WindowInsetsAnimation getAnimation() {
|
||||||
|
return mControl.getAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAnimationType() {
|
||||||
|
return mControl.getAnimationType();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import static android.view.WindowInsets.Type.ime;
|
|||||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
|
||||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
|
||||||
|
|
||||||
|
import android.animation.AnimationHandler;
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
@@ -53,6 +54,7 @@ import android.view.animation.PathInterpolator;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.internal.util.Preconditions;
|
||||||
|
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -167,10 +169,22 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
private WindowInsetsAnimationController mController;
|
private WindowInsetsAnimationController mController;
|
||||||
private ObjectAnimator mAnimator;
|
private ObjectAnimator mAnimator;
|
||||||
protected boolean mShow;
|
private final boolean mShow;
|
||||||
|
private final boolean mUseSfVsync;
|
||||||
|
|
||||||
public InternalAnimationControlListener(boolean show) {
|
private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
|
||||||
|
new ThreadLocal<AnimationHandler>() {
|
||||||
|
@Override
|
||||||
|
protected AnimationHandler initialValue() {
|
||||||
|
AnimationHandler handler = new AnimationHandler();
|
||||||
|
handler.setProvider(new SfVsyncFrameCallbackProvider());
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public InternalAnimationControlListener(boolean show, boolean useSfVsync) {
|
||||||
mShow = show;
|
mShow = show;
|
||||||
|
mUseSfVsync = useSfVsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -193,6 +207,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
onAnimationFinish();
|
onAnimationFinish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (mUseSfVsync) {
|
||||||
|
mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
|
||||||
|
}
|
||||||
mAnimator.start();
|
mAnimator.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,12 +245,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
*/
|
*/
|
||||||
private static class RunningAnimation {
|
private static class RunningAnimation {
|
||||||
|
|
||||||
RunningAnimation(InsetsAnimationControlImpl control, int type) {
|
RunningAnimation(InsetsAnimationControlRunner runner, int type) {
|
||||||
this.control = control;
|
this.runner = runner;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
final InsetsAnimationControlImpl control;
|
final InsetsAnimationControlRunner runner;
|
||||||
final @AnimationType int type;
|
final @AnimationType int type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,7 +269,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
|
PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
|
||||||
long durationMs, Interpolator interpolator, @AnimationType int animationType,
|
long durationMs, Interpolator interpolator, @AnimationType int animationType,
|
||||||
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
|
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
|
||||||
CancellationSignal cancellationSignal) {
|
CancellationSignal cancellationSignal, boolean useInsetsAnimationThread) {
|
||||||
this.types = types;
|
this.types = types;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.durationMs = durationMs;
|
this.durationMs = durationMs;
|
||||||
@@ -260,6 +277,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
this.animationType = animationType;
|
this.animationType = animationType;
|
||||||
this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
|
this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
|
||||||
this.cancellationSignal = cancellationSignal;
|
this.cancellationSignal = cancellationSignal;
|
||||||
|
this.useInsetsAnimationThread = useInsetsAnimationThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
final @InsetsType int types;
|
final @InsetsType int types;
|
||||||
@@ -269,6 +287,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
final @AnimationType int animationType;
|
final @AnimationType int animationType;
|
||||||
final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
|
final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
|
||||||
final CancellationSignal cancellationSignal;
|
final CancellationSignal cancellationSignal;
|
||||||
|
final boolean useInsetsAnimationThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String TAG = "InsetsControllerImpl";
|
private final String TAG = "InsetsControllerImpl";
|
||||||
@@ -347,15 +366,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
InsetsState state = new InsetsState(mState, true /* copySources */);
|
InsetsState state = new InsetsState(mState, true /* copySources */);
|
||||||
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
||||||
RunningAnimation runningAnimation = mRunningAnimations.get(i);
|
RunningAnimation runningAnimation = mRunningAnimations.get(i);
|
||||||
InsetsAnimationControlImpl control = runningAnimation.control;
|
InsetsAnimationControlRunner runner = runningAnimation.runner;
|
||||||
|
if (runner instanceof InsetsAnimationControlImpl) {
|
||||||
|
InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
|
||||||
|
|
||||||
// Keep track of running animation to be dispatched. Aggregate it here such that if
|
// Keep track of running animation to be dispatched. Aggregate it here such that
|
||||||
// it gets finished within applyChangeInsets we still dispatch it to onProgress.
|
// if it gets finished within applyChangeInsets we still dispatch it to
|
||||||
if (runningAnimation.startDispatched) {
|
// onProgress.
|
||||||
mTmpRunningAnims.add(control.getAnimation());
|
if (runningAnimation.startDispatched) {
|
||||||
}
|
mTmpRunningAnims.add(control.getAnimation());
|
||||||
if (control.applyChangeInsets(state)) {
|
}
|
||||||
mTmpFinishedControls.add(control);
|
|
||||||
|
if (control.applyChangeInsets(state)) {
|
||||||
|
mTmpFinishedControls.add(control);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,7 +523,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
pendingRequest.listener, mFrame,
|
pendingRequest.listener, mFrame,
|
||||||
true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
|
true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
|
||||||
false /* fade */, pendingRequest.animationType,
|
false /* fade */, pendingRequest.animationType,
|
||||||
pendingRequest.layoutInsetsDuringAnimation);
|
pendingRequest.layoutInsetsDuringAnimation,
|
||||||
|
pendingRequest.useInsetsAnimationThread);
|
||||||
pendingRequest.cancellationSignal.setOnCancelListener(cancellationSignal::cancel);
|
pendingRequest.cancellationSignal.setOnCancelListener(cancellationSignal::cancel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -563,7 +588,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
return cancellationSignal;
|
return cancellationSignal;
|
||||||
}
|
}
|
||||||
return controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
|
return controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
|
||||||
false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
|
false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types),
|
||||||
|
false /* useInsetsAnimationThread */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkDisplayFramesForControlling() {
|
private boolean checkDisplayFramesForControlling() {
|
||||||
@@ -577,7 +603,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
|
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
|
||||||
long durationMs, Interpolator interpolator, boolean fade,
|
long durationMs, Interpolator interpolator, boolean fade,
|
||||||
@AnimationType int animationType,
|
@AnimationType int animationType,
|
||||||
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
|
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
|
||||||
|
boolean useInsetsAnimationThread) {
|
||||||
CancellationSignal cancellationSignal = new CancellationSignal();
|
CancellationSignal cancellationSignal = new CancellationSignal();
|
||||||
if (types == 0) {
|
if (types == 0) {
|
||||||
// nothing to animate.
|
// nothing to animate.
|
||||||
@@ -600,7 +627,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
abortPendingImeControlRequest();
|
abortPendingImeControlRequest();
|
||||||
final PendingControlRequest request = new PendingControlRequest(types,
|
final PendingControlRequest request = new PendingControlRequest(types,
|
||||||
listener, durationMs,
|
listener, durationMs,
|
||||||
interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal);
|
interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal,
|
||||||
|
useInsetsAnimationThread);
|
||||||
mPendingImeControlRequest = request;
|
mPendingImeControlRequest = request;
|
||||||
mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
|
mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
|
||||||
cancellationSignal.setOnCancelListener(() -> {
|
cancellationSignal.setOnCancelListener(() -> {
|
||||||
@@ -617,11 +645,21 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
return cancellationSignal;
|
return cancellationSignal;
|
||||||
}
|
}
|
||||||
|
|
||||||
final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
|
|
||||||
frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
|
final InsetsAnimationControlRunner runner = useInsetsAnimationThread
|
||||||
layoutInsetsDuringAnimation, animationType);
|
? new InsetsAnimationThreadControlRunner(controls,
|
||||||
mRunningAnimations.add(new RunningAnimation(controller, animationType));
|
frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
|
||||||
cancellationSignal.setOnCancelListener(controller::onCancelled);
|
animationType, mViewRoot.mHandler)
|
||||||
|
: new InsetsAnimationControlImpl(controls,
|
||||||
|
frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
|
||||||
|
animationType);
|
||||||
|
mRunningAnimations.add(new RunningAnimation(runner, animationType));
|
||||||
|
cancellationSignal.setOnCancelListener(runner::cancel);
|
||||||
|
if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
|
||||||
|
showDirectly(types);
|
||||||
|
} else {
|
||||||
|
hideDirectly(types, false /* animationFinished */, animationType);
|
||||||
|
}
|
||||||
return cancellationSignal;
|
return cancellationSignal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,7 +743,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
private void cancelExistingControllers(@InsetsType int types) {
|
private void cancelExistingControllers(@InsetsType int types) {
|
||||||
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
||||||
InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
|
InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
|
||||||
if ((control.getTypes() & types) != 0) {
|
if ((control.getTypes() & types) != 0) {
|
||||||
cancelAnimation(control, true /* invokeCallback */);
|
cancelAnimation(control, true /* invokeCallback */);
|
||||||
}
|
}
|
||||||
@@ -725,13 +763,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@Override
|
@Override
|
||||||
public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
|
public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
|
||||||
cancelAnimation(controller, false /* invokeCallback */);
|
cancelAnimation(runner, false /* invokeCallback */);
|
||||||
if (shown) {
|
if (shown) {
|
||||||
showDirectly(controller.getTypes());
|
showDirectly(runner.getTypes());
|
||||||
} else {
|
} else {
|
||||||
hideDirectly(controller.getTypes(), true /* animationFinished */,
|
hideDirectly(runner.getTypes(), true /* animationFinished */,
|
||||||
controller.getAnimationType());
|
runner.getAnimationType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -756,7 +794,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
void notifyControlRevoked(InsetsSourceConsumer consumer) {
|
void notifyControlRevoked(InsetsSourceConsumer consumer) {
|
||||||
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
||||||
InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
|
InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
|
||||||
if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
|
if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
|
||||||
cancelAnimation(control, true /* invokeCallback */);
|
cancelAnimation(control, true /* invokeCallback */);
|
||||||
}
|
}
|
||||||
@@ -766,12 +804,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) {
|
private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
|
||||||
if (invokeCallback) {
|
if (invokeCallback) {
|
||||||
control.onCancelled();
|
control.cancel();
|
||||||
}
|
}
|
||||||
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
||||||
if (mRunningAnimations.get(i).control == control) {
|
if (mRunningAnimations.get(i).runner == control) {
|
||||||
mRunningAnimations.remove(i);
|
mRunningAnimations.remove(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -844,7 +882,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public @AnimationType int getAnimationType(@InternalInsetsType int type) {
|
public @AnimationType int getAnimationType(@InternalInsetsType int type) {
|
||||||
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
||||||
InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
|
InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
|
||||||
if (control.controlsInternalType(type)) {
|
if (control.controlsInternalType(type)) {
|
||||||
return mRunningAnimations.get(i).type;
|
return mRunningAnimations.get(i).type;
|
||||||
}
|
}
|
||||||
@@ -878,15 +916,24 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean useInsetsAnimationThread = canUseInsetsAnimationThread();
|
||||||
final InternalAnimationControlListener listener =
|
final InternalAnimationControlListener listener =
|
||||||
new InternalAnimationControlListener(show);
|
new InternalAnimationControlListener(show, useInsetsAnimationThread);
|
||||||
// Show/hide animations always need to be relative to the display frame, in order that shown
|
// Show/hide animations always need to be relative to the display frame, in order that shown
|
||||||
// and hidden state insets are correct.
|
// and hidden state insets are correct.
|
||||||
controlAnimationUnchecked(
|
controlAnimationUnchecked(
|
||||||
types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
|
types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
|
||||||
INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
|
INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
|
||||||
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
|
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
|
||||||
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
|
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
|
||||||
|
useInsetsAnimationThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canUseInsetsAnimationThread() {
|
||||||
|
if (mViewRoot.mView == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !mViewRoot.mView.hasWindowInsetsAnimationCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideDirectly(
|
private void hideDirectly(
|
||||||
@@ -921,13 +968,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
@Override
|
@Override
|
||||||
public void startAnimation(InsetsAnimationControlImpl controller,
|
public void startAnimation(InsetsAnimationControlImpl controller,
|
||||||
WindowInsetsAnimationControlListener listener, int types,
|
WindowInsetsAnimationControlListener listener, int types,
|
||||||
WindowInsetsAnimation animation, Bounds bounds, int layoutDuringAnimation) {
|
WindowInsetsAnimation animation, Bounds bounds) {
|
||||||
if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
|
|
||||||
showDirectly(types);
|
|
||||||
} else {
|
|
||||||
hideDirectly(types, false /* animationFinished */, controller.getAnimationType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mViewRoot.mView == null) {
|
if (mViewRoot.mView == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -941,7 +982,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
}
|
}
|
||||||
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
|
||||||
RunningAnimation runningAnimation = mRunningAnimations.get(i);
|
RunningAnimation runningAnimation = mRunningAnimations.get(i);
|
||||||
if (runningAnimation.control == controller) {
|
if (runningAnimation.runner == controller) {
|
||||||
runningAnimation.startDispatched = true;
|
runningAnimation.startDispatched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class InsetsSourceConsumer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastControl != null) {
|
if (lastControl != null) {
|
||||||
lastControl.release(mController);
|
lastControl.release(mController::releaseSurfaceControlFromRt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.view.InsetsState.InternalInsetsType;
|
import android.view.InsetsState.InternalInsetsType;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a parcelable object to allow controlling a single {@link InsetsSource}.
|
* Represents a parcelable object to allow controlling a single {@link InsetsSource}.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -94,9 +96,9 @@ public class InsetsSourceControl implements Parcelable {
|
|||||||
dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
|
dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release(InsetsController controller) {
|
public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
|
||||||
if (mLeash != null) {
|
if (mLeash != null) {
|
||||||
controller.releaseSurfaceControlFromRt(mLeash);
|
surfaceReleaseConsumer.accept(mLeash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11226,6 +11226,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
|||||||
getListenerInfo().mWindowInsetsAnimationCallback = callback;
|
getListenerInfo().mWindowInsetsAnimationCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view
|
||||||
|
* or view tree of the sub-hierarchy {@code false} otherwise.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean hasWindowInsetsAnimationCallback() {
|
||||||
|
return getListenerInfo().mWindowInsetsAnimationCallback != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)}
|
* Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)}
|
||||||
* when Window Insets animation is being prepared.
|
* when Window Insets animation is being prepared.
|
||||||
|
|||||||
@@ -7258,6 +7258,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
|||||||
: DISPATCH_MODE_CONTINUE_ON_SUBTREE;
|
: DISPATCH_MODE_CONTINUE_ON_SUBTREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean hasWindowInsetsAnimationCallback() {
|
||||||
|
if (super.hasWindowInsetsAnimationCallback()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are root-level content view that fits insets, we imitate consuming behavior, so
|
||||||
|
// no child will retrieve window insets animation callback.
|
||||||
|
// See dispatchWindowInsetsAnimationPrepare.
|
||||||
|
boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
|
||||||
|
|| isFrameworkOptionalFitsSystemWindows();
|
||||||
|
if (isOptionalFitSystemWindows && mAttachInfo != null
|
||||||
|
&& mAttachInfo.mContentOnApplyWindowInsetsListener != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int count = getChildCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (getChildAt(i).hasWindowInsetsAnimationCallback()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispatchWindowInsetsAnimationPrepare(
|
public void dispatchWindowInsetsAnimationPrepare(
|
||||||
@NonNull WindowInsetsAnimation animation) {
|
@NonNull WindowInsetsAnimation animation) {
|
||||||
|
|||||||
@@ -504,6 +504,7 @@ public final class WindowManagerGlobal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void doRemoveView(ViewRootImpl root) {
|
void doRemoveView(ViewRootImpl root) {
|
||||||
|
boolean allViewsRemoved;
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final int index = mRoots.indexOf(root);
|
final int index = mRoots.indexOf(root);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@@ -512,10 +513,17 @@ public final class WindowManagerGlobal {
|
|||||||
final View view = mViews.remove(index);
|
final View view = mViews.remove(index);
|
||||||
mDyingViews.remove(view);
|
mDyingViews.remove(view);
|
||||||
}
|
}
|
||||||
|
allViewsRemoved = mRoots.isEmpty();
|
||||||
}
|
}
|
||||||
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
|
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
|
||||||
doTrimForeground();
|
doTrimForeground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we don't have any views anymore in our process, we no longer need the
|
||||||
|
// InsetsAnimationThread to save some resources.
|
||||||
|
if (allViewsRemoved) {
|
||||||
|
InsetsAnimationThread.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findViewLocked(View view, boolean required) {
|
private int findViewLocked(View view, boolean required) {
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public class InsetsAnimationControlImplTest {
|
|||||||
mController = new InsetsAnimationControlImpl(controls,
|
mController = new InsetsAnimationControlImpl(controls,
|
||||||
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
|
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
|
||||||
mMockController, 10 /* durationMs */, new LinearInterpolator(),
|
mMockController, 10 /* durationMs */, new LinearInterpolator(),
|
||||||
false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN, 0 /* animationType */);
|
false /* fade */, 0 /* animationType */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -182,7 +182,7 @@ public class InsetsAnimationControlImplTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelled() {
|
public void testCancelled() {
|
||||||
mController.onCancelled();
|
mController.cancel();
|
||||||
try {
|
try {
|
||||||
mController.setInsetsAndAlpha(Insets.NONE, 1f /*alpha */, 0f /* fraction */);
|
mController.setInsetsAndAlpha(Insets.NONE, 1f /*alpha */, 0f /* fraction */);
|
||||||
fail("Expected exception to be thrown");
|
fail("Expected exception to be thrown");
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -47,6 +48,7 @@ import android.graphics.Point;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
import android.view.InsetsState.InternalInsetsType;
|
||||||
import android.view.SurfaceControl.Transaction;
|
import android.view.SurfaceControl.Transaction;
|
||||||
import android.view.WindowInsets.Type;
|
import android.view.WindowInsets.Type;
|
||||||
import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
|
import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
|
||||||
@@ -169,11 +171,8 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testControlsChanged() {
|
public void testControlsChanged() {
|
||||||
InsetsSourceControl control =
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
|
assertNotNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
|
||||||
mController.onControlsChanged(new InsetsSourceControl[] { control });
|
|
||||||
assertEquals(mLeash,
|
|
||||||
mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
|
|
||||||
mController.addOnControllableInsetsChangedListener(
|
mController.addOnControllableInsetsChangedListener(
|
||||||
((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
|
((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
|
||||||
}
|
}
|
||||||
@@ -183,9 +182,7 @@ public class InsetsControllerTest {
|
|||||||
OnControllableInsetsChangedListener listener
|
OnControllableInsetsChangedListener listener
|
||||||
= mock(OnControllableInsetsChangedListener.class);
|
= mock(OnControllableInsetsChangedListener.class);
|
||||||
mController.addOnControllableInsetsChangedListener(listener);
|
mController.addOnControllableInsetsChangedListener(listener);
|
||||||
InsetsSourceControl control =
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
|
|
||||||
mController.onControlsChanged(new InsetsSourceControl[] { control });
|
|
||||||
mController.onControlsChanged(new InsetsSourceControl[0]);
|
mController.onControlsChanged(new InsetsSourceControl[0]);
|
||||||
assertNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl());
|
assertNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl());
|
||||||
InOrder inOrder = Mockito.inOrder(listener);
|
InOrder inOrder = Mockito.inOrder(listener);
|
||||||
@@ -197,9 +194,7 @@ public class InsetsControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testControlsRevoked_duringAnim() {
|
public void testControlsRevoked_duringAnim() {
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
InsetsSourceControl control =
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
|
|
||||||
mController.onControlsChanged(new InsetsSourceControl[] { control });
|
|
||||||
|
|
||||||
WindowInsetsAnimationControlListener mockListener =
|
WindowInsetsAnimationControlListener mockListener =
|
||||||
mock(WindowInsetsAnimationControlListener.class);
|
mock(WindowInsetsAnimationControlListener.class);
|
||||||
@@ -262,11 +257,8 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyImeVisibility() {
|
public void testApplyImeVisibility() {
|
||||||
final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
|
InsetsSourceControl ime = createControl(ITYPE_IME);
|
||||||
|
mController.onControlsChanged(new InsetsSourceControl[] { ime });
|
||||||
InsetsSourceControl[] controls = new InsetsSourceControl[3];
|
|
||||||
controls[0] = ime;
|
|
||||||
mController.onControlsChanged(controls);
|
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
|
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
|
||||||
mController.applyImeVisibility(true);
|
mController.applyImeVisibility(true);
|
||||||
@@ -429,9 +421,7 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRestoreStartsAnimation() {
|
public void testRestoreStartsAnimation() {
|
||||||
InsetsSourceControl control =
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
|
|
||||||
mController.onControlsChanged(new InsetsSourceControl[]{control});
|
|
||||||
|
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
mController.hide(Type.statusBars());
|
mController.hide(Type.statusBars());
|
||||||
@@ -448,7 +438,7 @@ public class InsetsControllerTest {
|
|||||||
assertTrue(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
|
assertTrue(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
|
||||||
|
|
||||||
// Gaining control
|
// Gaining control
|
||||||
mController.onControlsChanged(new InsetsSourceControl[]{control});
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
|
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
|
||||||
mController.cancelExistingAnimation();
|
mController.cancelExistingAnimation();
|
||||||
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
|
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
|
||||||
@@ -459,8 +449,6 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartImeAnimationAfterGettingControl() {
|
public void testStartImeAnimationAfterGettingControl() {
|
||||||
InsetsSourceControl control =
|
|
||||||
new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
|
|
||||||
|
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
|
|
||||||
@@ -471,7 +459,7 @@ public class InsetsControllerTest {
|
|||||||
mController.show(ime(), true /* fromIme */);
|
mController.show(ime(), true /* fromIme */);
|
||||||
|
|
||||||
// Gaining control shortly after
|
// Gaining control shortly after
|
||||||
mController.onControlsChanged(new InsetsSourceControl[]{control});
|
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
|
||||||
|
|
||||||
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
|
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
|
||||||
mController.cancelExistingAnimation();
|
mController.cancelExistingAnimation();
|
||||||
@@ -483,16 +471,13 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartImeAnimationAfterGettingControl_imeLater() {
|
public void testStartImeAnimationAfterGettingControl_imeLater() {
|
||||||
InsetsSourceControl control =
|
|
||||||
new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
|
|
||||||
|
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
|
|
||||||
mController.show(ime());
|
mController.show(ime());
|
||||||
assertFalse(mController.getState().getSource(ITYPE_IME).isVisible());
|
assertFalse(mController.getState().getSource(ITYPE_IME).isVisible());
|
||||||
|
|
||||||
// Gaining control shortly after
|
// Gaining control shortly after
|
||||||
mController.onControlsChanged(new InsetsSourceControl[]{control});
|
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
|
||||||
|
|
||||||
// Pretend IME is calling
|
// Pretend IME is calling
|
||||||
mController.show(ime(), true /* fromIme */);
|
mController.show(ime(), true /* fromIme */);
|
||||||
@@ -507,9 +492,7 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAnimationEndState_controller() throws Exception {
|
public void testAnimationEndState_controller() throws Exception {
|
||||||
InsetsSourceControl control =
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
|
|
||||||
mController.onControlsChanged(new InsetsSourceControl[] { control });
|
|
||||||
|
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
WindowInsetsAnimationControlListener mockListener =
|
WindowInsetsAnimationControlListener mockListener =
|
||||||
@@ -535,9 +518,7 @@ public class InsetsControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancellation_afterGainingControl() throws Exception {
|
public void testCancellation_afterGainingControl() throws Exception {
|
||||||
InsetsSourceControl control =
|
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
|
||||||
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
|
|
||||||
mController.onControlsChanged(new InsetsSourceControl[] { control });
|
|
||||||
|
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
WindowInsetsAnimationControlListener mockListener =
|
WindowInsetsAnimationControlListener mockListener =
|
||||||
@@ -655,12 +636,23 @@ public class InsetsControllerTest {
|
|||||||
latch.await();
|
latch.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InsetsSourceControl createControl(@InternalInsetsType int type) {
|
||||||
|
|
||||||
|
// Simulate binder behavior by copying SurfaceControl. Otherwise, InsetsController will
|
||||||
|
// attempt to release mLeash directly.
|
||||||
|
SurfaceControl copy = new SurfaceControl();
|
||||||
|
copy.copyFrom(mLeash);
|
||||||
|
return new InsetsSourceControl(type, copy, new Point());
|
||||||
|
}
|
||||||
|
|
||||||
|
private InsetsSourceControl[] createSingletonControl(@InternalInsetsType int type) {
|
||||||
|
return new InsetsSourceControl[] { createControl(type) };
|
||||||
|
}
|
||||||
|
|
||||||
private InsetsSourceControl[] prepareControls() {
|
private InsetsSourceControl[] prepareControls() {
|
||||||
final InsetsSourceControl navBar = new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mLeash,
|
final InsetsSourceControl navBar = createControl(ITYPE_NAVIGATION_BAR);
|
||||||
new Point());
|
final InsetsSourceControl statusBar = createControl(ITYPE_STATUS_BAR);
|
||||||
final InsetsSourceControl statusBar = new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash,
|
final InsetsSourceControl ime = createControl(ITYPE_IME);
|
||||||
new Point());
|
|
||||||
final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
|
|
||||||
|
|
||||||
InsetsSourceControl[] controls = new InsetsSourceControl[3];
|
InsetsSourceControl[] controls = new InsetsSourceControl[3];
|
||||||
controls[0] = navBar;
|
controls[0] = navBar;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import android.util.IntArray;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.InsetsAnimationControlCallbacks;
|
import android.view.InsetsAnimationControlCallbacks;
|
||||||
import android.view.InsetsAnimationControlImpl;
|
import android.view.InsetsAnimationControlImpl;
|
||||||
|
import android.view.InsetsAnimationControlRunner;
|
||||||
import android.view.InsetsController;
|
import android.view.InsetsController;
|
||||||
import android.view.InsetsSourceControl;
|
import android.view.InsetsSourceControl;
|
||||||
import android.view.InsetsState;
|
import android.view.InsetsState;
|
||||||
@@ -44,6 +45,7 @@ import android.view.SurfaceControl;
|
|||||||
import android.view.SyncRtSurfaceTransactionApplier;
|
import android.view.SyncRtSurfaceTransactionApplier;
|
||||||
import android.view.ViewRootImpl;
|
import android.view.ViewRootImpl;
|
||||||
import android.view.WindowInsetsAnimation;
|
import android.view.WindowInsetsAnimation;
|
||||||
|
import android.view.WindowInsetsAnimation.Bounds;
|
||||||
import android.view.WindowInsetsAnimationControlListener;
|
import android.view.WindowInsetsAnimationControlListener;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -327,7 +329,7 @@ class InsetsPolicy {
|
|||||||
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
|
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
|
||||||
|
|
||||||
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
|
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
|
||||||
super(show);
|
super(show, true /* useSfVsync */);
|
||||||
mFinishCallback = finishCallback;
|
mFinishCallback = finishCallback;
|
||||||
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
|
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
|
||||||
}
|
}
|
||||||
@@ -360,8 +362,6 @@ class InsetsPolicy {
|
|||||||
mFocusedWin.getDisplayContent().getBounds(), getState(),
|
mFocusedWin.getDisplayContent().getBounds(), getState(),
|
||||||
mListener, typesReady, this, mListener.getDurationMs(),
|
mListener, typesReady, this, mListener.getDurationMs(),
|
||||||
InsetsController.INTERPOLATOR, true,
|
InsetsController.INTERPOLATOR, true,
|
||||||
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
|
|
||||||
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
|
|
||||||
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
|
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
|
||||||
SurfaceAnimationThread.getHandler().post(
|
SurfaceAnimationThread.getHandler().post(
|
||||||
() -> mListener.onReady(mAnimationControl, typesReady));
|
() -> mListener.onReady(mAnimationControl, typesReady));
|
||||||
@@ -377,7 +377,7 @@ class InsetsPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
|
public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
|
||||||
// Nothing's needed here. Finish steps is handled in the listener
|
// Nothing's needed here. Finish steps is handled in the listener
|
||||||
// onAnimationFinished callback.
|
// onAnimationFinished callback.
|
||||||
}
|
}
|
||||||
@@ -406,14 +406,14 @@ class InsetsPolicy {
|
|||||||
applyParams(t, surfaceParams, mTmpFloat9);
|
applyParams(t, surfaceParams, mTmpFloat9);
|
||||||
}
|
}
|
||||||
t.apply();
|
t.apply();
|
||||||
|
t.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startAnimation(InsetsAnimationControlImpl controller,
|
public void startAnimation(InsetsAnimationControlImpl controller,
|
||||||
WindowInsetsAnimationControlListener listener, int types,
|
WindowInsetsAnimationControlListener listener, int types,
|
||||||
WindowInsetsAnimation animation,
|
WindowInsetsAnimation animation,
|
||||||
WindowInsetsAnimation.Bounds bounds,
|
Bounds bounds) {
|
||||||
int layoutDuringAnimation) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user