1 /*
2  * Copyright (C) 2014 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 
17 package com.android.systemui.recents.views;
18 
19 import android.animation.Animator;
20 import android.animation.ObjectAnimator;
21 import android.animation.PropertyValuesHolder;
22 import android.graphics.Rect;
23 import android.graphics.RectF;
24 import android.util.Property;
25 import android.view.View;
26 
27 import com.android.systemui.recents.utilities.AnimationProps;
28 import com.android.systemui.recents.utilities.Utilities;
29 
30 import java.util.ArrayList;
31 
32 /**
33  * The visual properties for a {@link TaskView}.
34  */
35 public class TaskViewTransform {
36 
37     public static final Property<View, Rect> LTRB =
38             new Property<View, Rect>(Rect.class, "leftTopRightBottom") {
39 
40                 private Rect mTmpRect = new Rect();
41 
42                 @Override
43                 public void set(View v, Rect ltrb) {
44                     v.setLeftTopRightBottom(ltrb.left, ltrb.top, ltrb.right, ltrb.bottom);
45                 }
46 
47                 @Override
48                 public Rect get(View v) {
49                     mTmpRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
50                     return mTmpRect;
51                 }
52             };
53 
54     public float translationZ = 0;
55     public float scale = 1f;
56     public float alpha = 1f;
57     public float dimAlpha = 0f;
58     public float viewOutlineAlpha = 0f;
59 
60     public boolean visible = false;
61 
62     // This is a window-space rect used for positioning the task in the stack
63     public RectF rect = new RectF();
64 
65     /**
66      * Fills int this transform from the state of the given TaskView.
67      */
fillIn(TaskView tv)68     public void fillIn(TaskView tv) {
69         translationZ = tv.getTranslationZ();
70         scale = tv.getScaleX();
71         alpha = tv.getAlpha();
72         visible = true;
73         dimAlpha = tv.getDimAlpha();
74         viewOutlineAlpha = tv.getViewBounds().getAlpha();
75         rect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
76     }
77 
78     /**
79      * Copies the transform state from another {@link TaskViewTransform}.
80      */
copyFrom(TaskViewTransform other)81     public void copyFrom(TaskViewTransform other) {
82         translationZ = other.translationZ;
83         scale = other.scale;
84         alpha = other.alpha;
85         visible = other.visible;
86         dimAlpha = other.dimAlpha;
87         viewOutlineAlpha = other.viewOutlineAlpha;
88         rect.set(other.rect);
89     }
90 
91     /**
92      * @return whether {@param other} is the same transform as this
93      */
isSame(TaskViewTransform other)94     public boolean isSame(TaskViewTransform other) {
95         return translationZ == other.translationZ
96                 && scale == other.scale
97                 && other.alpha == alpha
98                 && dimAlpha == other.dimAlpha
99                 && visible == other.visible
100                 && rect.equals(other.rect);
101     }
102 
103     /**
104      * Resets the current transform.
105      */
reset()106     public void reset() {
107         translationZ = 0;
108         scale = 1f;
109         alpha = 1f;
110         dimAlpha = 0f;
111         viewOutlineAlpha = 0f;
112         visible = false;
113         rect.setEmpty();
114     }
115 
116     /** Convenience functions to compare against current property values */
hasAlphaChangedFrom(float v)117     public boolean hasAlphaChangedFrom(float v) {
118         return (Float.compare(alpha, v) != 0);
119     }
120 
hasScaleChangedFrom(float v)121     public boolean hasScaleChangedFrom(float v) {
122         return (Float.compare(scale, v) != 0);
123     }
124 
hasTranslationZChangedFrom(float v)125     public boolean hasTranslationZChangedFrom(float v) {
126         return (Float.compare(translationZ, v) != 0);
127     }
128 
hasRectChangedFrom(View v)129     public boolean hasRectChangedFrom(View v) {
130         return ((int) rect.left != v.getLeft()) || ((int) rect.right != v.getRight()) ||
131                 ((int) rect.top != v.getTop()) || ((int) rect.bottom != v.getBottom());
132     }
133 
134     /**
135      * Applies this transform to a view.
136      */
applyToTaskView(TaskView v, ArrayList<Animator> animators, AnimationProps animation, boolean allowShadows)137     public void applyToTaskView(TaskView v, ArrayList<Animator> animators,
138             AnimationProps animation, boolean allowShadows) {
139         // Return early if not visible
140         if (!visible) {
141             return;
142         }
143 
144         if (animation.isImmediate()) {
145             if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
146                 v.setTranslationZ(translationZ);
147             }
148             if (hasScaleChangedFrom(v.getScaleX())) {
149                 v.setScaleX(scale);
150                 v.setScaleY(scale);
151             }
152             if (hasAlphaChangedFrom(v.getAlpha())) {
153                 v.setAlpha(alpha);
154             }
155             if (hasRectChangedFrom(v)) {
156                 v.setLeftTopRightBottom((int) rect.left, (int) rect.top, (int) rect.right,
157                         (int) rect.bottom);
158             }
159         } else {
160             if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
161                 ObjectAnimator anim = ObjectAnimator.ofFloat(v, View.TRANSLATION_Z,
162                         v.getTranslationZ(), translationZ);
163                 animators.add(animation.apply(AnimationProps.TRANSLATION_Z, anim));
164             }
165             if (hasScaleChangedFrom(v.getScaleX())) {
166                 ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(v,
167                         PropertyValuesHolder.ofFloat(View.SCALE_X, v.getScaleX(), scale),
168                         PropertyValuesHolder.ofFloat(View.SCALE_Y, v.getScaleX(), scale));
169                 animators.add(animation.apply(AnimationProps.SCALE, anim));
170             }
171             if (hasAlphaChangedFrom(v.getAlpha())) {
172                 ObjectAnimator anim = ObjectAnimator.ofFloat(v, View.ALPHA, v.getAlpha(), alpha);
173                 animators.add(animation.apply(AnimationProps.ALPHA, anim));
174             }
175             if (hasRectChangedFrom(v)) {
176                 Rect fromViewRect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
177                 Rect toViewRect = new Rect();
178                 rect.round(toViewRect);
179                 ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(v,
180                         PropertyValuesHolder.ofObject(LTRB, Utilities.RECT_EVALUATOR,
181                                 fromViewRect, toViewRect));
182                 animators.add(animation.apply(AnimationProps.BOUNDS, anim));
183             }
184         }
185     }
186 
187     /** Reset the transform on a view. */
reset(TaskView v)188     public static void reset(TaskView v) {
189         v.setTranslationX(0f);
190         v.setTranslationY(0f);
191         v.setTranslationZ(0f);
192         v.setScaleX(1f);
193         v.setScaleY(1f);
194         v.setAlpha(1f);
195         v.getViewBounds().setClipBottom(0);
196         v.setLeftTopRightBottom(0, 0, 0, 0);
197     }
198 
199     @Override
toString()200     public String toString() {
201         return "R: " + rect + " V: " + visible;
202     }
203 }
204