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 mIcon1; 47 private View mIcon2; 48 private View mIcon3; 49 private View mIcon4; 50 private View mIcon5; 51 private View mIcon6; 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 mIcon1 = findViewById(R.id.taskbar_icon_1); 82 mIcon2 = findViewById(R.id.taskbar_icon_2); 83 mIcon3 = findViewById(R.id.taskbar_icon_3); 84 mIcon4 = findViewById(R.id.taskbar_icon_4); 85 mIcon5 = findViewById(R.id.taskbar_icon_5); 86 mIcon6 = findViewById(R.id.taskbar_icon_6); 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 96 animators.add(ObjectAnimator.ofFloat( 97 mBackground, View.TRANSLATION_Y, 0, mBackground.getHeight())); 98 animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f)); 99 animators.add(createIconDisappearanceToHotseatAnimator( 100 mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop)); 101 animators.add(createIconDisappearanceToHotseatAnimator( 102 mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop)); 103 animators.add(createIconDisappearanceToHotseatAnimator( 104 mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop)); 105 animators.add(createIconDisappearanceToHotseatAnimator( 106 mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop)); 107 animators.add(createIconDisappearanceToHotseatAnimator( 108 mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop)); 109 animators.add(createIconDisappearanceToHotseatAnimator( 110 mIcon6, hotseat.findViewById(R.id.hotseat_icon_6), hotseatTop)); 111 112 AnimatorSet animatorSet = new AnimatorSet(); 113 114 animatorSet.playTogether(animators); 115 animatorSet.addListener(new AnimatorListenerAdapter() { 116 @Override 117 public void onAnimationEnd(Animator animation) { 118 super.onAnimationEnd(animation); 119 setVisibility(INVISIBLE); 120 } 121 122 @Override 123 public void onAnimationStart(Animator animation) { 124 super.onAnimationStart(animation); 125 setVisibility(VISIBLE); 126 } 127 }); 128 129 start(animatorSet); 130 } 131 132 /** 133 * Animates this fake taskbar's appearance from the given hotseat view. 134 */ animateAppearanceFromHotseat(ViewGroup hotseat)135 public void animateAppearanceFromHotseat(ViewGroup hotseat) { 136 ArrayList<Animator> animators = new ArrayList<>(); 137 int hotseatTop = hotseat.getTop(); 138 139 animators.add(ObjectAnimator.ofFloat( 140 mBackground, View.TRANSLATION_Y, mBackground.getHeight(), 0)); 141 animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f)); 142 animators.add(createIconAppearanceFromHotseatAnimator( 143 mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop)); 144 animators.add(createIconAppearanceFromHotseatAnimator( 145 mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop)); 146 animators.add(createIconAppearanceFromHotseatAnimator( 147 mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop)); 148 animators.add(createIconAppearanceFromHotseatAnimator( 149 mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop)); 150 animators.add(createIconAppearanceFromHotseatAnimator( 151 mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop)); 152 animators.add(createIconAppearanceFromHotseatAnimator( 153 mIcon6, hotseat.findViewById(R.id.hotseat_icon_6), hotseatTop)); 154 155 AnimatorSet animatorSet = new AnimatorSet(); 156 157 animatorSet.playTogether(animators); 158 animatorSet.addListener(new AnimatorListenerAdapter() { 159 @Override 160 public void onAnimationStart(Animator animation) { 161 super.onAnimationStart(animation); 162 setVisibility(VISIBLE); 163 } 164 }); 165 166 start(animatorSet); 167 } 168 169 /** 170 * Animates this fake taskbar's disappearance to the bottom of the screen. 171 */ animateDisappearanceToBottom()172 public void animateDisappearanceToBottom() { 173 ArrayList<Animator> animators = new ArrayList<>(); 174 175 animators.add(ObjectAnimator.ofFloat( 176 mBackground, View.TRANSLATION_Y, 0, mBackground.getHeight())); 177 animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f)); 178 animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_X, 1f, 0f)); 179 animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_Y, 1f, 0f)); 180 181 initializeIconContainerPivot(); 182 183 AnimatorSet animatorSet = new AnimatorSet(); 184 185 animatorSet.playTogether(animators); 186 animatorSet.addListener(new AnimatorListenerAdapter() { 187 @Override 188 public void onAnimationEnd(Animator animation) { 189 super.onAnimationEnd(animation); 190 setVisibility(INVISIBLE); 191 resetIconContainerPivot(); 192 } 193 194 @Override 195 public void onAnimationCancel(Animator animation) { 196 super.onAnimationCancel(animation); 197 resetIconContainerPivot(); 198 } 199 200 @Override 201 public void onAnimationStart(Animator animation) { 202 super.onAnimationStart(animation); 203 setVisibility(VISIBLE); 204 } 205 }); 206 207 start(animatorSet); 208 } 209 210 /** 211 * Animates this fake taskbar's appearance from the bottom of the screen. 212 */ animateAppearanceFromBottom()213 public void animateAppearanceFromBottom() { 214 ArrayList<Animator> animators = new ArrayList<>(); 215 216 animators.add(ObjectAnimator.ofFloat( 217 mBackground, View.TRANSLATION_Y, mBackground.getHeight(), 0)); 218 animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f)); 219 animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_X, 0f, 1f)); 220 animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_Y, 0f, 1f)); 221 222 initializeIconContainerPivot(); 223 224 AnimatorSet animatorSet = new AnimatorSet(); 225 226 animatorSet.playTogether(animators); 227 animatorSet.addListener(new AnimatorListenerAdapter() { 228 @Override 229 public void onAnimationStart(Animator animation) { 230 super.onAnimationStart(animation); 231 setVisibility(VISIBLE); 232 } 233 234 @Override 235 public void onAnimationEnd(Animator animation) { 236 super.onAnimationEnd(animation); 237 resetIconContainerPivot(); 238 } 239 240 @Override 241 public void onAnimationCancel(Animator animation) { 242 super.onAnimationCancel(animation); 243 resetIconContainerPivot(); 244 } 245 }); 246 247 start(animatorSet); 248 } 249 initializeIconContainerPivot()250 private void initializeIconContainerPivot() { 251 mIconContainer.setPivotX(getWidth() / 2f); 252 mIconContainer.setPivotY(getHeight() * 0.8f); 253 } 254 resetIconContainerPivot()255 private void resetIconContainerPivot() { 256 mIconContainer.resetPivot(); 257 mIconContainer.setScaleX(1f); 258 mIconContainer.setScaleY(1f); 259 } 260 start(Animator animator)261 private void start(Animator animator) { 262 if (mRunningAnimator != null) { 263 mRunningAnimator.cancel(); 264 } 265 266 animator.addListener(new AnimatorListenerAdapter() { 267 @Override 268 public void onAnimationCancel(Animator animation) { 269 super.onAnimationCancel(animation); 270 mRunningAnimator = null; 271 } 272 273 @Override 274 public void onAnimationEnd(Animator animation) { 275 super.onAnimationEnd(animation); 276 mRunningAnimator = null; 277 } 278 279 @Override 280 public void onAnimationStart(Animator animation) { 281 super.onAnimationStart(animation); 282 mRunningAnimator = animator; 283 } 284 }); 285 286 animator.start(); 287 } 288 createIconDisappearanceToHotseatAnimator( View taskbarIcon, View hotseatIcon, int hotseatTop)289 private Animator createIconDisappearanceToHotseatAnimator( 290 View taskbarIcon, View hotseatIcon, int hotseatTop) { 291 ArrayList<Animator> animators = new ArrayList<>(); 292 293 animators.add(ObjectAnimator.ofFloat( 294 taskbarIcon, 295 View.TRANSLATION_Y, 296 0, 297 (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop()))); 298 animators.add(ObjectAnimator.ofFloat( 299 taskbarIcon, View.TRANSLATION_X, 0, hotseatIcon.getLeft() - taskbarIcon.getLeft())); 300 animators.add(ObjectAnimator.ofFloat( 301 taskbarIcon, 302 View.SCALE_X, 303 1f, 304 (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth())); 305 animators.add(ObjectAnimator.ofFloat( 306 taskbarIcon, 307 View.SCALE_Y, 308 1f, 309 (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight())); 310 animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 1f, 0f)); 311 312 AnimatorSet animatorSet = new AnimatorSet(); 313 314 animatorSet.playTogether(animators); 315 animatorSet.addListener(new AnimatorListenerAdapter() { 316 @Override 317 public void onAnimationEnd(Animator animation) { 318 super.onAnimationEnd(animation); 319 taskbarIcon.setVisibility(INVISIBLE); 320 } 321 322 @Override 323 public void onAnimationStart(Animator animation) { 324 super.onAnimationStart(animation); 325 taskbarIcon.setVisibility(VISIBLE); 326 } 327 }); 328 329 return animatorSet; 330 } 331 createIconAppearanceFromHotseatAnimator( View taskbarIcon, View hotseatIcon, int hotseatTop)332 private Animator createIconAppearanceFromHotseatAnimator( 333 View taskbarIcon, View hotseatIcon, int hotseatTop) { 334 ArrayList<Animator> animators = new ArrayList<>(); 335 336 animators.add(ObjectAnimator.ofFloat( 337 taskbarIcon, 338 View.TRANSLATION_Y, 339 (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop()), 340 0)); 341 animators.add(ObjectAnimator.ofFloat( 342 taskbarIcon, View.TRANSLATION_X, hotseatIcon.getLeft() - taskbarIcon.getLeft(), 0)); 343 animators.add(ObjectAnimator.ofFloat( 344 taskbarIcon, 345 View.SCALE_X, 346 (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth(), 347 1f)); 348 animators.add(ObjectAnimator.ofFloat( 349 taskbarIcon, 350 View.SCALE_Y, 351 (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight(), 352 1f)); 353 animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 0f, 1f)); 354 355 AnimatorSet animatorSet = new AnimatorSet(); 356 357 animatorSet.playTogether(animators); 358 animatorSet.addListener(new AnimatorListenerAdapter() { 359 @Override 360 public void onAnimationStart(Animator animation) { 361 super.onAnimationStart(animation); 362 taskbarIcon.setVisibility(VISIBLE); 363 } 364 }); 365 366 return animatorSet; 367 } 368 } 369