1 /*
2  * Copyright (C) 2021 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 package com.android.quickstep.interaction;
17 
18 import android.animation.Animator;
19 import android.animation.AnimatorListenerAdapter;
20 import android.animation.AnimatorSet;
21 import android.animation.ObjectAnimator;
22 import android.content.Context;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.view.ViewGroup;
26 
27 import androidx.annotation.NonNull;
28 import androidx.annotation.Nullable;
29 import androidx.constraintlayout.widget.ConstraintLayout;
30 
31 import com.android.launcher3.R;
32 
33 import java.util.ArrayList;
34 
35 
36 /**
37  * Helper View for the gesture tutorial mock taskbar view.
38  *
39  * This helper class allows animating this mock taskview to and from a mock hotseat and the bottom
40  * of the screen.
41  */
42 public class AnimatedTaskbarView extends ConstraintLayout {
43 
44     private View mBackground;
45     private View mIconContainer;
46     private View mAllAppsButton;
47     private View mIcon1;
48     private View mIcon2;
49     private View mIcon3;
50     private View mIcon4;
51     private View mIcon5;
52 
53     @Nullable private Animator mRunningAnimator;
54 
AnimatedTaskbarView(@onNull Context context)55     public AnimatedTaskbarView(@NonNull Context context) {
56         super(context);
57     }
58 
AnimatedTaskbarView(@onNull Context context, @Nullable AttributeSet attrs)59     public AnimatedTaskbarView(@NonNull Context context,
60             @Nullable AttributeSet attrs) {
61         super(context, attrs);
62     }
63 
AnimatedTaskbarView(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)64     public AnimatedTaskbarView(@NonNull Context context, @Nullable AttributeSet attrs,
65             int defStyleAttr) {
66         super(context, attrs, defStyleAttr);
67     }
68 
AnimatedTaskbarView(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)69     public AnimatedTaskbarView(@NonNull Context context, @Nullable AttributeSet attrs,
70             int defStyleAttr,
71             int defStyleRes) {
72         super(context, attrs, defStyleAttr, defStyleRes);
73     }
74 
75     @Override
onFinishInflate()76     protected void onFinishInflate() {
77         super.onFinishInflate();
78 
79         mBackground = findViewById(R.id.taskbar_background);
80         mIconContainer = findViewById(R.id.icon_container);
81         mAllAppsButton = findViewById(R.id.taskbar_all_apps);
82         mIcon1 = findViewById(R.id.taskbar_icon_1);
83         mIcon2 = findViewById(R.id.taskbar_icon_2);
84         mIcon3 = findViewById(R.id.taskbar_icon_3);
85         mIcon4 = findViewById(R.id.taskbar_icon_4);
86         mIcon5 = findViewById(R.id.taskbar_icon_5);
87     }
88 
89     /**
90      * Animates this fake taskbar's disappearance into the given hotseat view.
91      */
animateDisappearanceToHotseat(ViewGroup hotseat)92     public void animateDisappearanceToHotseat(ViewGroup hotseat) {
93         ArrayList<Animator> animators = new ArrayList<>();
94         int hotseatTop = hotseat.getTop();
95         int hotseatLeft = hotseat.getLeft();
96 
97         animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f));
98         animators.add(ObjectAnimator.ofFloat(mAllAppsButton, View.ALPHA, 1f, 0f));
99         animators.add(createIconDisappearanceToHotseatAnimator(
100                 mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop, hotseatLeft));
101         animators.add(createIconDisappearanceToHotseatAnimator(
102                 mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop, hotseatLeft));
103         animators.add(createIconDisappearanceToHotseatAnimator(
104                 mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop, hotseatLeft));
105         animators.add(createIconDisappearanceToHotseatAnimator(
106                 mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop, hotseatLeft));
107         animators.add(createIconDisappearanceToHotseatAnimator(
108                 mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop, hotseatLeft));
109 
110         AnimatorSet animatorSet = new AnimatorSet();
111 
112         animatorSet.playTogether(animators);
113         animatorSet.addListener(new AnimatorListenerAdapter() {
114             @Override
115             public void onAnimationEnd(Animator animation) {
116                 super.onAnimationEnd(animation);
117                 setVisibility(INVISIBLE);
118             }
119 
120             @Override
121             public void onAnimationStart(Animator animation) {
122                 super.onAnimationStart(animation);
123                 setVisibility(VISIBLE);
124             }
125         });
126 
127         start(animatorSet);
128     }
129 
130     /**
131      * Animates this fake taskbar's appearance from the given hotseat view.
132      */
animateAppearanceFromHotseat(ViewGroup hotseat)133     public void animateAppearanceFromHotseat(ViewGroup hotseat) {
134         ArrayList<Animator> animators = new ArrayList<>();
135         int hotseatTop = hotseat.getTop();
136         int hotseatLeft = hotseat.getLeft();
137 
138         animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f));
139         animators.add(ObjectAnimator.ofFloat(mAllAppsButton, View.ALPHA, 0f, 1f));
140         animators.add(createIconAppearanceFromHotseatAnimator(
141                 mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop, hotseatLeft));
142         animators.add(createIconAppearanceFromHotseatAnimator(
143                 mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop, hotseatLeft));
144         animators.add(createIconAppearanceFromHotseatAnimator(
145                 mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop, hotseatLeft));
146         animators.add(createIconAppearanceFromHotseatAnimator(
147                 mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop, hotseatLeft));
148         animators.add(createIconAppearanceFromHotseatAnimator(
149                 mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop, hotseatLeft));
150 
151         AnimatorSet animatorSet = new AnimatorSet();
152 
153         animatorSet.playTogether(animators);
154         animatorSet.addListener(new AnimatorListenerAdapter() {
155             @Override
156             public void onAnimationStart(Animator animation) {
157                 super.onAnimationStart(animation);
158                 setVisibility(VISIBLE);
159             }
160         });
161 
162         start(animatorSet);
163     }
164 
start(Animator animator)165     private void start(Animator animator) {
166         if (mRunningAnimator != null) {
167             mRunningAnimator.cancel();
168         }
169 
170         animator.addListener(new AnimatorListenerAdapter() {
171             @Override
172             public void onAnimationCancel(Animator animation) {
173                 super.onAnimationCancel(animation);
174                 mRunningAnimator = null;
175             }
176 
177             @Override
178             public void onAnimationEnd(Animator animation) {
179                 super.onAnimationEnd(animation);
180                 mRunningAnimator = null;
181             }
182 
183             @Override
184             public void onAnimationStart(Animator animation) {
185                 super.onAnimationStart(animation);
186                 mRunningAnimator = animator;
187             }
188         });
189 
190         animator.start();
191     }
192 
createIconDisappearanceToHotseatAnimator( View taskbarIcon, View hotseatIcon, int hotseatTop, int hotseatLeft)193     private Animator createIconDisappearanceToHotseatAnimator(
194             View taskbarIcon, View hotseatIcon, int hotseatTop, int hotseatLeft) {
195         ArrayList<Animator> animators = new ArrayList<>();
196 
197         animators.add(ObjectAnimator.ofFloat(
198                 taskbarIcon,
199                 View.TRANSLATION_Y,
200                 0,
201                 (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop())));
202         animators.add(ObjectAnimator.ofFloat(
203                 taskbarIcon,
204                 View.TRANSLATION_X,
205                 0,
206                 (hotseatLeft + hotseatIcon.getLeft()) - (getLeft() + taskbarIcon.getLeft())));
207         animators.add(ObjectAnimator.ofFloat(
208                 taskbarIcon,
209                 View.SCALE_X,
210                 1f,
211                 (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth()));
212         animators.add(ObjectAnimator.ofFloat(
213                 taskbarIcon,
214                 View.SCALE_Y,
215                 1f,
216                 (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight()));
217         animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 1f, 0f));
218 
219         AnimatorSet animatorSet = new AnimatorSet();
220 
221         animatorSet.playTogether(animators);
222         animatorSet.addListener(new AnimatorListenerAdapter() {
223             @Override
224             public void onAnimationEnd(Animator animation) {
225                 super.onAnimationEnd(animation);
226                 taskbarIcon.setVisibility(INVISIBLE);
227             }
228 
229             @Override
230             public void onAnimationStart(Animator animation) {
231                 super.onAnimationStart(animation);
232                 taskbarIcon.setVisibility(VISIBLE);
233             }
234         });
235 
236         return animatorSet;
237     }
238 
createIconAppearanceFromHotseatAnimator( View taskbarIcon, View hotseatIcon, int hotseatTop, int hotseatLeft)239     private Animator createIconAppearanceFromHotseatAnimator(
240             View taskbarIcon, View hotseatIcon, int hotseatTop, int hotseatLeft) {
241         ArrayList<Animator> animators = new ArrayList<>();
242 
243         animators.add(ObjectAnimator.ofFloat(
244                 taskbarIcon,
245                 View.TRANSLATION_Y,
246                 (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop()),
247                 0));
248         animators.add(ObjectAnimator.ofFloat(
249                 taskbarIcon,
250                 View.TRANSLATION_X,
251                 (hotseatLeft + hotseatIcon.getLeft()) - (getLeft() + taskbarIcon.getLeft()),
252                 0));
253         animators.add(ObjectAnimator.ofFloat(
254                 taskbarIcon,
255                 View.SCALE_X,
256                 (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth(),
257                 1f));
258         animators.add(ObjectAnimator.ofFloat(
259                 taskbarIcon,
260                 View.SCALE_Y,
261                 (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight(),
262                 1f));
263         animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 0f, 1f));
264 
265         AnimatorSet animatorSet = new AnimatorSet();
266 
267         animatorSet.playTogether(animators);
268         animatorSet.addListener(new AnimatorListenerAdapter() {
269             @Override
270             public void onAnimationStart(Animator animation) {
271                 super.onAnimationStart(animation);
272                 taskbarIcon.setVisibility(VISIBLE);
273             }
274         });
275 
276         return animatorSet;
277     }
278 }
279