Skip to content

Commit b3793ed

Browse files
gsajithcketcham
authored andcommitted
Add initial support for reading values in MotionSpec
PiperOrigin-RevId: 239298785
1 parent 9405a52 commit b3793ed

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

lib/java/com/google/android/material/animation/MotionSpec.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
import android.animation.AnimatorInflater;
2020
import android.animation.AnimatorSet;
2121
import android.animation.ObjectAnimator;
22+
import android.animation.PropertyValuesHolder;
2223
import android.content.Context;
2324
import android.content.res.TypedArray;
2425
import androidx.annotation.AnimatorRes;
2526
import androidx.annotation.Nullable;
2627
import androidx.annotation.StyleableRes;
2728
import androidx.collection.SimpleArrayMap;
2829
import android.util.Log;
30+
import android.util.Property;
31+
import android.view.View;
2932
import java.util.ArrayList;
3033
import java.util.List;
3134

@@ -65,6 +68,8 @@ public class MotionSpec {
6568
private static final String TAG = "MotionSpec";
6669

6770
private final SimpleArrayMap<String, MotionTiming> timings = new SimpleArrayMap<>();
71+
private final SimpleArrayMap<String, PropertyValuesHolder[]> propertyValues =
72+
new SimpleArrayMap<>();
6873

6974
/** Returns whether this motion spec contains a MotionTiming with the given name. */
7075
public boolean hasTiming(String name) {
@@ -87,6 +92,39 @@ public void setTiming(String name, @Nullable MotionTiming timing) {
8792
timings.put(name, timing);
8893
}
8994

95+
/**
96+
* Returns whether this motion spec contains a {@link PropertyValuesHolder[]} with the given name.
97+
*/
98+
public boolean hasPropertyValues(String name) {
99+
return propertyValues.get(name) != null;
100+
}
101+
102+
public PropertyValuesHolder[] getPropertyValues(String name) {
103+
if (!hasPropertyValues(name)) {
104+
throw new IllegalArgumentException();
105+
}
106+
return clonePropertyValuesHolder(propertyValues.get(name));
107+
}
108+
109+
public void setPropertyValues(String name, PropertyValuesHolder[] values) {
110+
propertyValues.put(name, values);
111+
}
112+
113+
private PropertyValuesHolder[] clonePropertyValuesHolder(PropertyValuesHolder[] values) {
114+
PropertyValuesHolder[] ret = new PropertyValuesHolder[values.length];
115+
for (int i = 0; i < values.length; i++) {
116+
ret[i] = values[i].clone();
117+
}
118+
return ret;
119+
}
120+
121+
public ObjectAnimator getAnimator(String name, View view, Property<View, Float> property) {
122+
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, getPropertyValues(name));
123+
animator.setProperty(property);
124+
getTiming(name).apply(animator);
125+
return animator;
126+
}
127+
90128
/**
91129
* Returns the total duration of this motion spec, which is the maximum delay+duration of its
92130
* motion timings.
@@ -140,14 +178,15 @@ public static MotionSpec createFromResource(Context context, @AnimatorRes int id
140178
private static MotionSpec createSpecFromAnimators(List<Animator> animators) {
141179
MotionSpec spec = new MotionSpec();
142180
for (int i = 0, count = animators.size(); i < count; i++) {
143-
addTimingFromAnimator(spec, animators.get(i));
181+
addInfoFromAnimator(spec, animators.get(i));
144182
}
145183
return spec;
146184
}
147185

148-
private static void addTimingFromAnimator(MotionSpec spec, Animator animator) {
186+
private static void addInfoFromAnimator(MotionSpec spec, Animator animator) {
149187
if (animator instanceof ObjectAnimator) {
150188
ObjectAnimator anim = (ObjectAnimator) animator;
189+
spec.setPropertyValues(anim.getPropertyName(), anim.getValues());
151190
spec.setTiming(anim.getPropertyName(), MotionTiming.createFromAnimator(anim));
152191
} else {
153192
throw new IllegalArgumentException("Animator must be an ObjectAnimator: " + animator);

testing/java/com/google/android/material/testapp/animation/res/animator/valid_set_of_object_animator_motion_spec.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,25 @@
2020
android:propertyName="alpha"
2121
android:startOffset="3"
2222
android:duration="5"
23+
android:valueFrom="0.2"
24+
android:valueTo="0.8"
25+
android:valueType="floatType"
2326
android:interpolator="@interpolator/mtrl_fast_out_linear_in"
2427
android:repeatCount="7"
2528
android:repeatMode="restart"/>
2629
<objectAnimator
2730
android:propertyName="translation"
2831
android:startOffset="11"
2932
android:duration="13"
33+
android:valueFrom="0"
34+
android:valueTo="101"
35+
android:valueType="intType"
3036
android:interpolator="@interpolator/mtrl_fast_out_slow_in"
3137
android:repeatCount="17"
3238
android:repeatMode="reverse"/>
39+
<objectAnimator
40+
android:propertyName="foo"
41+
android:duration="10"
42+
android:valueType="floatType"
43+
android:interpolator="@interpolator/mtrl_fast_out_slow_in"/>
3344
</set>

tests/javatests/com/google/android/material/animation/MotionSpecTest.java

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@
2020
import static org.junit.Assert.assertNotNull;
2121
import static org.junit.Assert.assertNull;
2222
import static org.junit.Assert.assertThat;
23+
import static org.junit.Assert.assertTrue;
2324

25+
import android.animation.Animator;
26+
import android.animation.ObjectAnimator;
27+
import android.animation.PropertyValuesHolder;
2428
import android.animation.ValueAnimator;
2529
import android.content.res.TypedArray;
2630
import android.os.Build.VERSION;
2731
import android.os.Build.VERSION_CODES;
2832
import com.google.android.material.testapp.animation.R;
2933
import androidx.appcompat.app.AppCompatActivity;
34+
import android.view.View;
3035
import android.view.animation.PathInterpolator;
3136
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
3237
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
@@ -56,12 +61,14 @@ public void loadMotionSpec() {
5661
}
5762

5863
@Test
59-
public void setOfObjectAnimatorMotionSpecHasAlphaAndTranslationTimings() {
64+
public void setOfObjectAnimatorMotionSpecHasAlphaAndTranslationTimingsAndValues() {
6065
MotionSpec spec =
6166
MotionSpec.createFromResource(
6267
activityTestRule.getActivity(), R.animator.valid_set_of_object_animator_motion_spec);
6368
assertNotNull(spec.getTiming("alpha"));
6469
assertNotNull(spec.getTiming("translation"));
70+
assertEquals(1, spec.getPropertyValues("alpha").length);
71+
assertEquals(1, spec.getPropertyValues("translation").length);
6572
}
6673

6774
@Test
@@ -96,6 +103,17 @@ public void validateSetOfObjectAnimatorAlphaMotionTiming() {
96103
assertEquals(ValueAnimator.RESTART, alpha.getRepeatMode());
97104
}
98105

106+
@Test
107+
public void validateSetOfObjectAnimatorAlphaMotionValues() {
108+
MotionSpec spec =
109+
MotionSpec.createFromResource(
110+
activityTestRule.getActivity(), R.animator.valid_set_of_object_animator_motion_spec);
111+
View view = new View(activityTestRule.getActivity());
112+
Animator alphaAnimator = spec.getAnimator("alpha", view, View.ALPHA);
113+
PropertyValuesHolder propertyValuesHolder = ((ObjectAnimator) alphaAnimator).getValues()[0];
114+
assertTrue(fromAndToValuesMatch(propertyValuesHolder, "0.2", "0.8"));
115+
}
116+
99117
@Test
100118
public void validateSetOfObjectAnimatorTranslationMotionTiming() {
101119
MotionSpec spec =
@@ -114,6 +132,30 @@ public void validateSetOfObjectAnimatorTranslationMotionTiming() {
114132
assertEquals(ValueAnimator.REVERSE, translation.getRepeatMode());
115133
}
116134

135+
@Test
136+
public void validateSetOfObjectAnimatorTranslationMotionValues() {
137+
MotionSpec spec =
138+
MotionSpec.createFromResource(
139+
activityTestRule.getActivity(), R.animator.valid_set_of_object_animator_motion_spec);
140+
View view = new View(activityTestRule.getActivity());
141+
Animator translationAnimator = spec.getAnimator("translation", view, View.TRANSLATION_X);
142+
PropertyValuesHolder propertyValuesHolder =
143+
((ObjectAnimator) translationAnimator).getValues()[0];
144+
assertTrue(fromAndToValuesMatch(propertyValuesHolder, "0", "101"));
145+
}
146+
147+
@Test
148+
public void validateSetOfObjectAnimatorEmptyMotionValues() {
149+
MotionSpec spec =
150+
MotionSpec.createFromResource(
151+
activityTestRule.getActivity(), R.animator.valid_set_of_object_animator_motion_spec);
152+
View view = new View(activityTestRule.getActivity());
153+
Animator translationAnimator = spec.getAnimator("foo", view, View.TRANSLATION_X);
154+
PropertyValuesHolder propertyValuesHolder =
155+
((ObjectAnimator) translationAnimator).getValues()[0];
156+
assertTrue(fromAndToValuesMatch(propertyValuesHolder, "0.0", "0.0"));
157+
}
158+
117159
public void inflateInvalidSetOfSetMotionSpec() {
118160
assertNull(
119161
MotionSpec.createFromResource(
@@ -125,4 +167,19 @@ public void inflateInvalidSetOfValueAnimatorMotionSpec() {
125167
MotionSpec.createFromResource(
126168
activityTestRule.getActivity(), R.animator.invalid_set_of_value_animator_motion_spec));
127169
}
170+
171+
@SuppressWarnings("StringSplitter")
172+
private boolean fromAndToValuesMatch(
173+
PropertyValuesHolder propertyValuesHolder, String fromValue, String toValue) {
174+
String[] valueStringTokens = propertyValuesHolder.toString().split("\\s+");
175+
int length = valueStringTokens.length;
176+
if (length >= 2) {
177+
if (valueStringTokens[length - 2].equals(fromValue)
178+
&& valueStringTokens[length - 1].equals(toValue)) {
179+
return true;
180+
}
181+
}
182+
183+
return false;
184+
}
128185
}

0 commit comments

Comments
 (0)