1 /* 2 * Copyright (C) 2020 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.systemui.bubbles.animation; 17 18 import android.graphics.Matrix; 19 20 import androidx.dynamicanimation.animation.DynamicAnimation; 21 import androidx.dynamicanimation.animation.FloatPropertyCompat; 22 23 /** 24 * Matrix whose scale properties can be animated using physics animations, via the {@link #SCALE_X} 25 * and {@link #SCALE_Y} FloatProperties. 26 * 27 * This is useful when you need to perform a scale animation with a pivot point, since pivot points 28 * are not supported by standard View scale operations but are supported by matrices. 29 * 30 * NOTE: DynamicAnimation assumes that all custom properties are denominated in pixels, and thus 31 * considers 1 to be the smallest user-visible change for custom properties. This means that if you 32 * animate {@link #SCALE_X} and {@link #SCALE_Y} to 3f, for example, the animation would have only 33 * three frames. 34 * 35 * To work around this, whenever animating to a desired scale value, animate to the value returned 36 * by {@link #getAnimatableValueForScaleFactor} instead. The SCALE_X and SCALE_Y properties will 37 * convert that (larger) value into the appropriate scale factor when scaling the matrix. 38 */ 39 public class AnimatableScaleMatrix extends Matrix { 40 41 /** 42 * The X value of the scale. 43 * 44 * NOTE: This must be set or animated to the value returned by 45 * {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself. 46 */ 47 public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_X = 48 new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleX") { 49 @Override 50 public float getValue(AnimatableScaleMatrix object) { 51 return getAnimatableValueForScaleFactor(object.mScaleX); 52 } 53 54 @Override 55 public void setValue(AnimatableScaleMatrix object, float value) { 56 object.setScaleX(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE); 57 } 58 }; 59 60 /** 61 * The Y value of the scale. 62 * 63 * NOTE: This must be set or animated to the value returned by 64 * {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself. 65 */ 66 public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_Y = 67 new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleY") { 68 @Override 69 public float getValue(AnimatableScaleMatrix object) { 70 return getAnimatableValueForScaleFactor(object.mScaleY); 71 } 72 73 @Override 74 public void setValue(AnimatableScaleMatrix object, float value) { 75 object.setScaleY(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE); 76 } 77 }; 78 79 private float mScaleX = 1f; 80 private float mScaleY = 1f; 81 82 private float mPivotX = 0f; 83 private float mPivotY = 0f; 84 85 /** 86 * Return the value to animate SCALE_X or SCALE_Y to in order to achieve the desired scale 87 * factor. 88 */ getAnimatableValueForScaleFactor(float scale)89 public static float getAnimatableValueForScaleFactor(float scale) { 90 return scale * (1f / DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE); 91 } 92 93 @Override setScale(float sx, float sy, float px, float py)94 public void setScale(float sx, float sy, float px, float py) { 95 mScaleX = sx; 96 mScaleY = sy; 97 mPivotX = px; 98 mPivotY = py; 99 super.setScale(mScaleX, mScaleY, mPivotX, mPivotY); 100 } 101 setScaleX(float scaleX)102 public void setScaleX(float scaleX) { 103 mScaleX = scaleX; 104 super.setScale(mScaleX, mScaleY, mPivotX, mPivotY); 105 } 106 setScaleY(float scaleY)107 public void setScaleY(float scaleY) { 108 mScaleY = scaleY; 109 super.setScale(mScaleX, mScaleY, mPivotX, mPivotY); 110 } 111 setPivotX(float pivotX)112 public void setPivotX(float pivotX) { 113 mPivotX = pivotX; 114 super.setScale(mScaleX, mScaleY, mPivotX, mPivotY); 115 } 116 setPivotY(float pivotY)117 public void setPivotY(float pivotY) { 118 mPivotY = pivotY; 119 super.setScale(mScaleX, mScaleY, mPivotX, mPivotY); 120 } 121 getScaleX()122 public float getScaleX() { 123 return mScaleX; 124 } 125 getScaleY()126 public float getScaleY() { 127 return mScaleY; 128 } 129 getPivotX()130 public float getPivotX() { 131 return mPivotX; 132 } 133 getPivotY()134 public float getPivotY() { 135 return mPivotY; 136 } 137 138 @Override equals(Object obj)139 public boolean equals(Object obj) { 140 // Use object equality to allow this matrix to be used as a map key (which is required for 141 // PhysicsAnimator's animator caching). 142 return obj == this; 143 } 144 } 145