1 /*
2  * Copyright (C) 2023 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 com.android.systemui.temporarydisplay.chipbar
18 
19 import android.view.View
20 import android.view.ViewGroup
21 import com.android.app.animation.Interpolators
22 import com.android.systemui.animation.ViewHierarchyAnimator
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.util.children
25 import javax.inject.Inject
26 
27 /**
28  * A class controlling chipbar animations. Typically delegates to [ViewHierarchyAnimator].
29  *
30  * Used so that animations can be mocked out in tests.
31  */
32 @SysUISingleton
33 open class ChipbarAnimator @Inject constructor() {
34     /**
35      * Animates [innerView] and its children into view.
36      *
37      * @return true if the animation was successfully started and false if the animation can't be
38      *   run for any reason.
39      *
40      * See [ViewHierarchyAnimator.animateAddition].
41      */
animateViewInnull42     open fun animateViewIn(innerView: ViewGroup, onAnimationEnd: Runnable): Boolean {
43         return ViewHierarchyAnimator.animateAddition(
44             innerView,
45             ViewHierarchyAnimator.Hotspot.TOP,
46             Interpolators.EMPHASIZED_DECELERATE,
47             duration = ANIMATION_IN_DURATION,
48             includeMargins = true,
49             includeFadeIn = true,
50             onAnimationEnd = onAnimationEnd,
51         )
52     }
53 
54     /**
55      * Animates [innerView] and its children out of view.
56      *
57      * @return true if the animation was successfully started and false if the animation can't be
58      *   run for any reason.
59      *
60      * See [ViewHierarchyAnimator.animateRemoval].
61      */
animateViewOutnull62     open fun animateViewOut(innerView: ViewGroup, onAnimationEnd: Runnable): Boolean {
63         return ViewHierarchyAnimator.animateRemoval(
64             innerView,
65             ViewHierarchyAnimator.Hotspot.TOP,
66             Interpolators.EMPHASIZED_ACCELERATE,
67             ANIMATION_OUT_DURATION,
68             includeMargins = true,
69             onAnimationEnd,
70         )
71     }
72 
73     /** Force shows this view and all child views. Should be used in case [animateViewIn] fails. */
forceDisplayViewnull74     fun forceDisplayView(innerView: View) {
75         innerView.alpha = 1f
76         if (innerView is ViewGroup) {
77             innerView.children.forEach { forceDisplayView(it) }
78         }
79     }
80 }
81 
82 private const val ANIMATION_IN_DURATION = 500L
83 private const val ANIMATION_OUT_DURATION = 250L
84