Merge "Insets Animation: Add CancellationSignal to controlWindowInsetsAnimation"

This commit is contained in:
Adrian Roos
2020-02-12 02:45:41 +00:00
committed by Android (Google) Code Review
4 changed files with 92 additions and 18 deletions

View File

@@ -55209,7 +55209,7 @@ package android.view {
}
public interface WindowInsetsController {
method public void controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public int getSystemBarsAppearance();
method public int getSystemBarsBehavior();
method public void hide(int);

View File

@@ -32,6 +32,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.RemoteException;
import android.util.ArraySet;
@@ -39,7 +40,6 @@ import android.util.Log;
import android.util.Pair;
import android.util.Property;
import android.util.SparseArray;
import android.view.InputDevice.MotionRange;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
@@ -242,13 +242,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
long durationMs, Interpolator interpolator, @AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
CancellationSignal cancellationSignal) {
this.types = types;
this.listener = listener;
this.durationMs = durationMs;
this.interpolator = interpolator;
this.animationType = animationType;
this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
this.cancellationSignal = cancellationSignal;
}
final @InsetsType int types;
@@ -257,6 +259,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
final Interpolator interpolator;
final @AnimationType int animationType;
final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
final CancellationSignal cancellationSignal;
}
private final String TAG = "InsetsControllerImpl";
@@ -455,10 +458,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
PendingControlRequest pendingRequest = mPendingImeControlRequest;
mPendingImeControlRequest = null;
mHandler.removeCallbacks(mPendingControlTimeout);
controlAnimationUnchecked(pendingRequest.types, pendingRequest.listener, mFrame,
CancellationSignal cancellationSignal = controlAnimationUnchecked(
pendingRequest.types,
pendingRequest.listener, mFrame,
true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
false /* fade */, pendingRequest.animationType,
pendingRequest.layoutInsetsDuringAnimation);
pendingRequest.cancellationSignal.setOnCancelListener(cancellationSignal::cancel);
return;
}
@@ -504,35 +510,39 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
@Override
public void controlWindowInsetsAnimation(@InsetsType int types, long durationMs,
public CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMs,
@Nullable Interpolator interpolator,
@NonNull WindowInsetsAnimationControlListener listener) {
controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs, interpolator,
ANIMATION_TYPE_USER);
return controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs,
interpolator, ANIMATION_TYPE_USER);
}
private void controlWindowInsetsAnimation(@InsetsType int types,
private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types,
WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs,
@Nullable Interpolator interpolator, @AnimationType int animationType) {
// If the frame of our window doesn't span the entire display, the control API makes very
// little sense, as we don't deal with negative insets. So just cancel immediately.
if (!mState.getDisplayFrame().equals(mFrame)) {
listener.onCancelled();
return;
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.cancel();
return cancellationSignal;
}
controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
return controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
}
private void controlAnimationUnchecked(@InsetsType int types,
private CancellationSignal controlAnimationUnchecked(@InsetsType int types,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
long durationMs, Interpolator interpolator, boolean fade,
@AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
CancellationSignal cancellationSignal = new CancellationSignal();
if (types == 0) {
// nothing to animate.
listener.onCancelled();
return;
cancellationSignal.cancel();
return cancellationSignal;
}
cancelExistingControllers(types);
@@ -546,21 +556,31 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (!imeReady) {
// IME isn't ready, all requested types will be animated once IME is ready
abortPendingImeControlRequest();
mPendingImeControlRequest = new PendingControlRequest(types, listener, durationMs,
interpolator, animationType, layoutInsetsDuringAnimation);
final PendingControlRequest request = new PendingControlRequest(types,
listener, durationMs,
interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal);
mPendingImeControlRequest = request;
mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
return;
cancellationSignal.setOnCancelListener(() -> {
if (mPendingImeControlRequest == request) {
abortPendingImeControlRequest();
}
});
return cancellationSignal;
}
if (typesReady == 0) {
listener.onCancelled();
return;
cancellationSignal.cancel();
return cancellationSignal;
}
final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
layoutInsetsDuringAnimation);
mRunningAnimations.add(new RunningAnimation(controller, animationType));
cancellationSignal.setOnCancelListener(controller::onCancelled);
return cancellationSignal;
}
/**

View File

@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
import android.os.CancellationSignal;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.animation.Interpolator;
@@ -154,13 +155,15 @@ public interface WindowInsetsController {
* {@link InsetsAnimation#getInterpolatedFraction()}.
* @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
* windows are ready to be controlled, among other callbacks.
*
* @return A cancellation signal that the caller can use to cancel the request to obtain
* control, or once they have control, to cancel the control.
* @see InsetsAnimation#getFraction()
* @see InsetsAnimation#getInterpolatedFraction()
* @see InsetsAnimation#getInterpolator()
* @see InsetsAnimation#getDurationMillis()
*/
void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
@NonNull
CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
@Nullable Interpolator interpolator,
@NonNull WindowInsetsAnimationControlListener listener);

View File

@@ -45,6 +45,7 @@ import android.content.Context;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type;
@@ -515,6 +516,34 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testCancellation_afterGainingControl() throws Exception {
InsetsSourceControl control =
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
mController.onControlsChanged(new InsetsSourceControl[] { control });
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener mockListener =
mock(WindowInsetsAnimationControlListener.class);
CancellationSignal cancellationSignal = mController.controlWindowInsetsAnimation(
statusBars(), 0 /* durationMs */,
new LinearInterpolator(), mockListener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
verify(mockListener).onReady(any(), anyInt());
cancellationSignal.cancel();
verify(mockListener).onCancelled();
});
waitUntilNextFrame();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testControlImeNotReady() {
prepareControls();
@@ -580,6 +609,28 @@ public class InsetsControllerTest {
});
}
@Test
public void testControlImeNotReady_cancel() {
prepareControls();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener)
.cancel();
verify(listener).onCancelled();
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
verify(listener, never()).onReady(any(), anyInt());
// Pretend that timeout is happening
mTestClock.fastForward(2500);
mTestHandler.timeAdvance();
});
}
private void waitUntilNextFrame() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,