1/*
2 * Copyright (C) 2016 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
17package android.graphics.drawable;
18
19import com.android.ide.common.rendering.api.LayoutLog;
20import com.android.internal.view.animation.NativeInterpolatorFactoryHelper_Delegate;
21import com.android.layoutlib.bridge.Bridge;
22import com.android.layoutlib.bridge.impl.DelegateManager;
23import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
24
25import android.animation.Animator;
26import android.animation.AnimatorSet;
27import android.animation.ObjectAnimator;
28import android.animation.PropertyValuesHolder;
29import android.annotation.NonNull;
30import android.annotation.Nullable;
31import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
32import android.graphics.drawable.VectorDrawable_Delegate.VFullPath_Delegate;
33import android.graphics.drawable.VectorDrawable_Delegate.VGroup_Delegate;
34import android.graphics.drawable.VectorDrawable_Delegate.VNativeObject;
35import android.graphics.drawable.VectorDrawable_Delegate.VPathRenderer_Delegate;
36
37import java.util.ArrayList;
38import java.util.function.Consumer;
39
40/**
41 * Delegate used to provide new implementation of a select few methods of {@link
42 * AnimatedVectorDrawable}
43 * <p>
44 * Through the layoutlib_create tool, the original  methods of AnimatedVectorDrawable have been
45 * replaced by calls to methods of the same name in this delegate class.
46 */
47@SuppressWarnings("unused")
48public class AnimatedVectorDrawable_Delegate {
49    private static DelegateManager<AnimatorSetHolder> sAnimatorSets = new
50            DelegateManager<>(AnimatorSetHolder.class);
51    private static DelegateManager<PropertySetter> sHolders = new
52            DelegateManager<>(PropertySetter.class);
53
54
55    @LayoutlibDelegate
56    /*package*/ static long nCreateAnimatorSet() {
57        return sAnimatorSets.addNewDelegate(new AnimatorSetHolder());
58    }
59
60    @LayoutlibDelegate
61    /*package*/ static void nAddAnimator(long setPtr, long propertyValuesHolder,
62            long nativeInterpolator, long startDelay, long duration, int repeatCount) {
63        PropertySetter holder = sHolders.getDelegate(propertyValuesHolder);
64        if (holder == null || holder.getValues() == null) {
65            return;
66        }
67
68        ObjectAnimator animator = new ObjectAnimator();
69        animator.setValues(holder.getValues());
70        animator.setInterpolator(
71                NativeInterpolatorFactoryHelper_Delegate.getDelegate(nativeInterpolator));
72        animator.setStartDelay(startDelay);
73        animator.setDuration(duration);
74        animator.setRepeatCount(repeatCount);
75        animator.setTarget(holder);
76        animator.setPropertyName(holder.getValues().getPropertyName());
77
78        AnimatorSetHolder set = sAnimatorSets.getDelegate(setPtr);
79        assert set != null;
80        set.addAnimator(animator);
81    }
82
83    @LayoutlibDelegate
84    /*package*/ static long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
85            float startValue, float endValue) {
86        VGroup_Delegate group = VNativeObject.getDelegate(nativePtr);
87        Consumer<Float> setter = group.getPropertySetter(propertyId);
88
89        return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
90                endValue));
91    }
92
93    @LayoutlibDelegate
94    /*package*/ static long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
95            long endValuePtr) {
96        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "AnimatedVectorDrawable path " +
97                "animations are not supported.", null, null);
98        return 0;
99    }
100
101    @LayoutlibDelegate
102    /*package*/ static long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
103            int startValue, int endValue) {
104        VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
105        Consumer<Integer> setter = path.getIntPropertySetter(propertyId);
106
107        return sHolders.addNewDelegate(IntPropertySetter.of(setter, startValue,
108                endValue));
109    }
110
111    @LayoutlibDelegate
112    /*package*/ static long nCreatePathPropertyHolder(long nativePtr, int propertyId,
113            float startValue, float endValue) {
114        VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
115        Consumer<Float> setter = path.getFloatPropertySetter(propertyId);
116
117        return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
118                endValue));
119    }
120
121    @LayoutlibDelegate
122    /*package*/ static long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
123            float endValue) {
124        VPathRenderer_Delegate renderer = VNativeObject.getDelegate(nativePtr);
125
126        return sHolders.addNewDelegate(FloatPropertySetter.of(renderer::setRootAlpha,
127                startValue,
128                endValue));
129    }
130
131    @LayoutlibDelegate
132    /*package*/ static void nSetPropertyHolderData(long nativePtr, float[] data, int length) {
133        PropertySetter setter = sHolders.getDelegate(nativePtr);
134        assert setter != null;
135
136        setter.setValues(data);
137    }
138
139    @LayoutlibDelegate
140    /*package*/ static void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
141        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
142        assert animatorSet != null;
143
144        animatorSet.start();
145    }
146
147    @LayoutlibDelegate
148    /*package*/ static void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
149        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
150        assert animatorSet != null;
151
152        animatorSet.reverse();
153    }
154
155    @LayoutlibDelegate
156    /*package*/ static void nEnd(long animatorSetPtr) {
157        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
158        assert animatorSet != null;
159
160        animatorSet.end();
161    }
162
163    @LayoutlibDelegate
164    /*package*/ static void nReset(long animatorSetPtr) {
165        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
166        assert animatorSet != null;
167
168        animatorSet.end();
169        animatorSet.start();
170    }
171
172    private static class AnimatorSetHolder {
173        private ArrayList<Animator> mAnimators = new ArrayList<>();
174        private AnimatorSet mAnimatorSet = null;
175
176        private void addAnimator(@NonNull Animator animator) {
177            mAnimators.add(animator);
178        }
179
180        private void ensureAnimatorSet() {
181            if (mAnimatorSet == null) {
182                mAnimatorSet = new AnimatorSet();
183                mAnimatorSet.playTogether(mAnimators);
184            }
185        }
186
187        private void start() {
188            ensureAnimatorSet();
189
190            mAnimatorSet.start();
191        }
192
193        private void end() {
194            mAnimatorSet.end();
195        }
196
197        private void reset() {
198            end();
199            start();
200        }
201
202        private void reverse() {
203            mAnimatorSet.reverse();
204        }
205    }
206
207    /**
208     * Class that allows setting a value and holds the range of values for the given property.
209     *
210     * @param <T> the type of the property
211     */
212    private static class PropertySetter<T> {
213        final Consumer<T> mValueSetter;
214        private PropertyValuesHolder mValues;
215
216        private PropertySetter(@NonNull Consumer<T> valueSetter) {
217            mValueSetter = valueSetter;
218        }
219
220        /**
221         * Method to set an {@link Integer} value for this property. The default implementation of
222         * this method doesn't do anything. This method is accessed via reflection by the
223         * PropertyValuesHolder.
224         */
225        public void setIntValue(Integer value) {
226        }
227
228        /**
229         * Method to set an {@link Integer} value for this property. The default implementation of
230         * this method doesn't do anything. This method is accessed via reflection by the
231         * PropertyValuesHolder.
232         */
233        public void setFloatValue(Float value) {
234        }
235
236        void setValues(float... values) {
237            mValues = PropertyValuesHolder.ofFloat("floatValue", values);
238        }
239
240        @Nullable
241        PropertyValuesHolder getValues() {
242            return mValues;
243        }
244
245        void setValues(int... values) {
246            mValues = PropertyValuesHolder.ofInt("intValue", values);
247        }
248    }
249
250    private static class IntPropertySetter extends PropertySetter<Integer> {
251        private IntPropertySetter(Consumer<Integer> valueSetter) {
252            super(valueSetter);
253        }
254
255        private static PropertySetter of(Consumer<Integer> valueSetter, int... values) {
256            PropertySetter setter = new IntPropertySetter(valueSetter);
257            setter.setValues(values);
258
259            return setter;
260        }
261
262        public void setIntValue(Integer value) {
263            mValueSetter.accept(value);
264        }
265    }
266
267    private static class FloatPropertySetter extends PropertySetter<Float> {
268        private FloatPropertySetter(Consumer<Float> valueSetter) {
269            super(valueSetter);
270        }
271
272        private static PropertySetter of(Consumer<Float> valueSetter, float... values) {
273            PropertySetter setter = new FloatPropertySetter(valueSetter);
274            setter.setValues(values);
275
276            return setter;
277        }
278
279        public void setFloatValue(Float value) {
280            mValueSetter.accept(value);
281        }
282
283    }
284}
285