1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.server.wm;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.TypeEvaluator;
22 import android.animation.ValueAnimator;
23 import android.graphics.Insets;
24 import android.view.WindowInsetsAnimationControlListener;
25 import android.view.WindowInsetsAnimationController;
26 import android.view.WindowInsetsController;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 
31 public class WindowInsetsAnimationUtils {
32 
33     private static final int DURATION = 1000;
34 
35     /** Interpolates {@link Insets} for use with {@link ValueAnimator}. */
36     public static TypeEvaluator<Insets> INSETS_EVALUATOR =
37             (fraction, startValue, endValue) -> Insets.of(
38                     (int) (startValue.left + fraction * (endValue.left - startValue.left)),
39                     (int) (startValue.top + fraction * (endValue.top - startValue.top)),
40                     (int) (startValue.right + fraction * (endValue.right - startValue.right)),
41                     (int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
42 
43 
44     /**
45      * Requests control of the given {@code types} and animates them according to {@code show}.
46      *
47      * @param show if true, animate the inset in, otherwise animate it out.
48      */
requestControlThenTransitionToVisibility(WindowInsetsController wic, int types, boolean show)49     public static void requestControlThenTransitionToVisibility(WindowInsetsController wic,
50             int types, boolean show) {
51         wic.controlWindowInsetsAnimation(types, -1, null,
52                 null, new WindowInsetsAnimationControlListener() {
53                     Animator mAnimator;
54 
55                     @Override
56                     public void onReady(@NonNull WindowInsetsAnimationController controller,
57                             int types) {
58                         mAnimator = runTransition(controller, show);
59                     }
60 
61                     @Override
62                     public void onFinished(
63                             @NonNull WindowInsetsAnimationController controller) {
64                     }
65 
66                     @Override
67                     public void onCancelled(
68                             @Nullable WindowInsetsAnimationController controller) {
69                         if (mAnimator != null) {
70                             mAnimator.cancel();
71                         }
72                     }
73                 });
74     }
75 
runTransition(WindowInsetsAnimationController controller, boolean show)76     private static ValueAnimator runTransition(WindowInsetsAnimationController controller,
77             boolean show) {
78         ValueAnimator animator = ValueAnimator.ofObject(
79                 INSETS_EVALUATOR,
80                 show ? controller.getHiddenStateInsets()
81                         : controller.getShownStateInsets(),
82                 show ? controller.getShownStateInsets()
83                         : controller.getHiddenStateInsets()
84         );
85         animator.setDuration(DURATION);
86         animator.addUpdateListener((animator1) -> {
87             if (!controller.isReady()) {
88                 // Lost control
89                 animator.cancel();
90                 return;
91             }
92             Insets insets = (Insets) animator.getAnimatedValue();
93             controller.setInsetsAndAlpha(insets, 1.0f, animator.getAnimatedFraction());
94         });
95         animator.addListener(new AnimatorListenerAdapter() {
96             @Override
97             public void onAnimationEnd(Animator animation) {
98                 if (!controller.isCancelled()) {
99                     controller.finish(show);
100                 }
101             }
102         });
103         animator.start();
104         return animator;
105     }
106 }
107