/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.anim; import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.graphics.drawable.ColorDrawable; import android.util.FloatProperty; import android.util.IntProperty; import android.view.View; import androidx.annotation.NonNull; import java.util.function.Consumer; /** * Extension of {@link PropertySetter} which applies the property through an animation */ public class AnimatedPropertySetter extends PropertySetter { protected final AnimatorSet mAnim = new AnimatorSet(); protected ValueAnimator mProgressAnimator; @Override public Animator setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { if (view == null) { return NO_OP; } // Short-circuit if the view already has this alpha value, but make sure the visibility is // set correctly for the requested alpha. if (Float.compare(view.getAlpha(), alpha) == 0) { AlphaUpdateListener.updateVisibility(view); return NO_OP; } ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha); anim.addListener(new AlphaUpdateListener(view)); anim.setInterpolator(interpolator); add(anim); return anim; } @Override public Animator setViewBackgroundColor(View view, int color, TimeInterpolator interpolator) { if (view == null || (view.getBackground() instanceof ColorDrawable && ((ColorDrawable) view.getBackground()).getColor() == color)) { return NO_OP; } ObjectAnimator anim = ObjectAnimator.ofArgb(view, VIEW_BACKGROUND_COLOR, color); anim.setInterpolator(interpolator); add(anim); return anim; } @Override public Animator setFloat(T target, FloatProperty property, float value, TimeInterpolator interpolator) { if (property.get(target) == value) { return NO_OP; } Animator anim = ObjectAnimator.ofFloat(target, property, value); anim.setInterpolator(interpolator); add(anim); return anim; } @Override public Animator setInt(T target, IntProperty property, int value, TimeInterpolator interpolator) { if (property.get(target) == value) { return NO_OP; } Animator anim = ObjectAnimator.ofInt(target, property, value); anim.setInterpolator(interpolator); add(anim); return anim; } @NonNull @Override public Animator setColor(T target, IntProperty property, int value, TimeInterpolator interpolator) { if (property.get(target) == value) { return NO_OP; } Animator anim = ObjectAnimator.ofArgb(target, property, value); anim.setInterpolator(interpolator); add(anim); return anim; } /** * Adds a callback to be run on every frame of the animation */ public void addOnFrameCallback(Runnable runnable) { addOnFrameListener(anim -> runnable.run()); } /** * Adds a listener to be run on every frame of the animation */ public void addOnFrameListener(ValueAnimator.AnimatorUpdateListener listener) { if (mProgressAnimator == null) { mProgressAnimator = ValueAnimator.ofFloat(0, 1); } mProgressAnimator.addUpdateListener(listener); } @Override public void addEndListener(Consumer listener) { if (mProgressAnimator == null) { mProgressAnimator = ValueAnimator.ofFloat(0, 1); } mProgressAnimator.addListener(AnimatorListeners.forEndCallback(listener)); } /** * @see AnimatorSet#addListener(AnimatorListener) */ public void addListener(Animator.AnimatorListener listener) { mAnim.addListener(listener); } @Override public void add(Animator a) { mAnim.play(a); } /** * Creates and returns the underlying AnimatorSet */ @NonNull public AnimatorSet buildAnim() { // Add progress animation to the end, so that frame callback is called after all the other // animation update. if (mProgressAnimator != null) { add(mProgressAnimator); mProgressAnimator = null; } return mAnim; } }