1 /*
2  * Copyright (C) 2022 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 android.view.animation;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.graphics.Insets;
22 import android.util.AttributeSet;
23 
24 /**
25  * An animation that controls the outset of an object.
26  *
27  * @hide
28  */
29 public class ExtendAnimation extends Animation {
30     protected Insets mFromInsets = Insets.NONE;
31     protected Insets mToInsets = Insets.NONE;
32 
33     private int mFromLeftType = ABSOLUTE;
34     private int mFromTopType = ABSOLUTE;
35     private int mFromRightType = ABSOLUTE;
36     private int mFromBottomType = ABSOLUTE;
37 
38     private int mToLeftType = ABSOLUTE;
39     private int mToTopType = ABSOLUTE;
40     private int mToRightType = ABSOLUTE;
41     private int mToBottomType = ABSOLUTE;
42 
43     private float mFromLeftValue;
44     private float mFromTopValue;
45     private float mFromRightValue;
46     private float mFromBottomValue;
47 
48     private float mToLeftValue;
49     private float mToTopValue;
50     private float mToRightValue;
51     private float mToBottomValue;
52 
53     /**
54      * Constructor used when an ExtendAnimation is loaded from a resource.
55      *
56      * @param context Application context to use
57      * @param attrs Attribute set from which to read values
58      */
ExtendAnimation(Context context, AttributeSet attrs)59     public ExtendAnimation(Context context, AttributeSet attrs) {
60         super(context, attrs);
61 
62         TypedArray a = context.obtainStyledAttributes(attrs,
63                 com.android.internal.R.styleable.ExtendAnimation);
64 
65         Description d = Description.parseValue(a.peekValue(
66                 com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft), context);
67         mFromLeftType = d.type;
68         mFromLeftValue = d.value;
69 
70         d = Description.parseValue(a.peekValue(
71                 com.android.internal.R.styleable.ExtendAnimation_fromExtendTop), context);
72         mFromTopType = d.type;
73         mFromTopValue = d.value;
74 
75         d = Description.parseValue(a.peekValue(
76                 com.android.internal.R.styleable.ExtendAnimation_fromExtendRight), context);
77         mFromRightType = d.type;
78         mFromRightValue = d.value;
79 
80         d = Description.parseValue(a.peekValue(
81                 com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom), context);
82         mFromBottomType = d.type;
83         mFromBottomValue = d.value;
84 
85 
86         d = Description.parseValue(a.peekValue(
87                 com.android.internal.R.styleable.ExtendAnimation_toExtendLeft), context);
88         mToLeftType = d.type;
89         mToLeftValue = d.value;
90 
91         d = Description.parseValue(a.peekValue(
92                 com.android.internal.R.styleable.ExtendAnimation_toExtendTop), context);
93         mToTopType = d.type;
94         mToTopValue = d.value;
95 
96         d = Description.parseValue(a.peekValue(
97                 com.android.internal.R.styleable.ExtendAnimation_toExtendRight), context);
98         mToRightType = d.type;
99         mToRightValue = d.value;
100 
101         d = Description.parseValue(a.peekValue(
102                 com.android.internal.R.styleable.ExtendAnimation_toExtendBottom), context);
103         mToBottomType = d.type;
104         mToBottomValue = d.value;
105 
106         a.recycle();
107     }
108 
109     /**
110      * Constructor to use when building an ExtendAnimation from code
111      *
112      * @param fromInsets the insets to animate from
113      * @param toInsets the insets to animate to
114      */
ExtendAnimation(Insets fromInsets, Insets toInsets)115     public ExtendAnimation(Insets fromInsets, Insets toInsets) {
116         if (fromInsets == null || toInsets == null) {
117             throw new RuntimeException("Expected non-null animation outsets");
118         }
119         mFromLeftValue = -fromInsets.left;
120         mFromTopValue = -fromInsets.top;
121         mFromRightValue = -fromInsets.right;
122         mFromBottomValue = -fromInsets.bottom;
123 
124         mToLeftValue = -toInsets.left;
125         mToTopValue = -toInsets.top;
126         mToRightValue = -toInsets.right;
127         mToBottomValue = -toInsets.bottom;
128     }
129 
130     /**
131      * Constructor to use when building an ExtendAnimation from code
132      */
ExtendAnimation(int fromL, int fromT, int fromR, int fromB, int toL, int toT, int toR, int toB)133     public ExtendAnimation(int fromL, int fromT, int fromR, int fromB,
134             int toL, int toT, int toR, int toB) {
135         this(Insets.of(-fromL, -fromT, -fromR, -fromB), Insets.of(-toL, -toT, -toR, -toB));
136     }
137 
138     @Override
applyTransformation(float it, Transformation tr)139     protected void applyTransformation(float it, Transformation tr) {
140         int l = mFromInsets.left + (int) ((mToInsets.left - mFromInsets.left) * it);
141         int t = mFromInsets.top + (int) ((mToInsets.top - mFromInsets.top) * it);
142         int r = mFromInsets.right + (int) ((mToInsets.right - mFromInsets.right) * it);
143         int b = mFromInsets.bottom + (int) ((mToInsets.bottom - mFromInsets.bottom) * it);
144         tr.setInsets(l, t, r, b);
145     }
146 
147     @Override
willChangeTransformationMatrix()148     public boolean willChangeTransformationMatrix() {
149         return false;
150     }
151 
152     /** @hide */
153     @Override
hasExtension()154     public boolean hasExtension() {
155         return mFromInsets.left < 0 || mFromInsets.top < 0 || mFromInsets.right < 0
156                 || mFromInsets.bottom < 0;
157     }
158 
159     @Override
initialize(int width, int height, int parentWidth, int parentHeight)160     public void initialize(int width, int height, int parentWidth, int parentHeight) {
161         super.initialize(width, height, parentWidth, parentHeight);
162         // We remove any negative extension (i.e. positive insets) and set those to 0
163         mFromInsets = Insets.min(Insets.of(
164                     -(int) resolveSize(mFromLeftType, mFromLeftValue, width, parentWidth),
165                     -(int) resolveSize(mFromTopType, mFromTopValue, height, parentHeight),
166                     -(int) resolveSize(mFromRightType, mFromRightValue, width, parentWidth),
167                     -(int) resolveSize(mFromBottomType, mFromBottomValue, height, parentHeight)
168                 ), Insets.NONE);
169         mToInsets = Insets.min(Insets.of(
170                     -(int) resolveSize(mToLeftType, mToLeftValue, width, parentWidth),
171                     -(int) resolveSize(mToTopType, mToTopValue, height, parentHeight),
172                     -(int) resolveSize(mToRightType, mToRightValue, width, parentWidth),
173                     -(int) resolveSize(mToBottomType, mToBottomValue, height, parentHeight)
174                 ), Insets.NONE);
175     }
176 }
177