blob: d2881417721822bf1bcbe45499e598edc5528b0f [file] [log] [blame]
/*
* 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.server.wm;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.graphics.Insets;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
import android.view.WindowInsetsController;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class WindowInsetsAnimationUtils {
private static final int DURATION = 1000;
/** Interpolates {@link Insets} for use with {@link ValueAnimator}. */
public static TypeEvaluator<Insets> INSETS_EVALUATOR =
(fraction, startValue, endValue) -> Insets.of(
(int) (startValue.left + fraction * (endValue.left - startValue.left)),
(int) (startValue.top + fraction * (endValue.top - startValue.top)),
(int) (startValue.right + fraction * (endValue.right - startValue.right)),
(int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
/**
* Requests control of the given {@code types} and animates them according to {@code show}.
*
* @param show if true, animate the inset in, otherwise animate it out.
*/
public static void requestControlThenTransitionToVisibility(WindowInsetsController wic,
int types, boolean show) {
wic.controlWindowInsetsAnimation(types, -1, null,
null, new WindowInsetsAnimationControlListener() {
Animator mAnimator;
@Override
public void onReady(@NonNull WindowInsetsAnimationController controller,
int types) {
mAnimator = runTransition(controller, show);
}
@Override
public void onFinished(
@NonNull WindowInsetsAnimationController controller) {
}
@Override
public void onCancelled(
@Nullable WindowInsetsAnimationController controller) {
if (mAnimator != null) {
mAnimator.cancel();
}
}
});
}
private static ValueAnimator runTransition(WindowInsetsAnimationController controller,
boolean show) {
ValueAnimator animator = ValueAnimator.ofObject(
INSETS_EVALUATOR,
show ? controller.getHiddenStateInsets()
: controller.getShownStateInsets(),
show ? controller.getShownStateInsets()
: controller.getHiddenStateInsets()
);
animator.setDuration(DURATION);
animator.addUpdateListener((animator1) -> {
if (!controller.isReady()) {
// Lost control
animator.cancel();
return;
}
Insets insets = (Insets) animator.getAnimatedValue();
controller.setInsetsAndAlpha(insets, 1.0f, animator.getAnimatedFraction());
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (!controller.isCancelled()) {
controller.finish(show);
}
}
});
animator.start();
return animator;
}
}