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