105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu/*
205de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu * Copyright (C) 2016 The Android Open Source Project
305de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu *
4e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * Licensed under the Apache License, Version 2.0 (the "License");
5e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * you may not use this file except in compliance with the License.
6e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * You may obtain a copy of the License at
705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu *
8e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu *      http://www.apache.org/licenses/LICENSE-2.0
905de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu *
10e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * Unless required by applicable law or agreed to in writing, software
11e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * distributed under the License is distributed on an "AS IS" BASIS,
12e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * See the License for the specific language governing permissions and
14e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * limitations under the License.
1505de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu */
1605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
17e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gupackage android.support.v17.leanback.widget;
1805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
19e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Guimport android.support.annotation.CallSuper;
2005de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Guimport android.support.v17.leanback.widget.ParallaxEffect.FloatEffect;
2105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Guimport android.support.v17.leanback.widget.ParallaxEffect.IntEffect;
22e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Guimport android.util.Property;
23e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
24e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Guimport java.util.ArrayList;
25e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Guimport java.util.Collections;
26e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Guimport java.util.List;
2705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
2805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu/**
29e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * Parallax tracks a list of dynamic {@link Property}s typically representing foreground UI
30e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * element positions on screen. Parallax keeps a list of {@link ParallaxEffect} objects which define
31e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * rules to mapping property values to {@link ParallaxTarget}.
32e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu *
33e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <p>
34bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * Example:
35bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * <code>
36bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *     // when Property "var1" changes from 15 to max value, perform parallax effect to
37bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *     // change myView's translationY from 0 to 100.
38bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *     Parallax<IntProperty> parallax = new Parallax<IntProperty>() {...};
39bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *     p1 = parallax.addProperty("var1");
40bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *     parallax.addEffect(p1.at(15), p1.atMax())
41bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *             .target(myView, PropertyValuesHolder.ofFloat("translationY", 0, 100));
42bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * </code>
43bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * </p>
44bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu *
45bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * <p>
46bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * To create a {@link ParallaxEffect}, user calls {@link #addEffect(PropertyMarkerValue[])} with a
47bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * list of {@link PropertyMarkerValue} which defines the range of {@link Parallax.IntProperty} or
48bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * {@link Parallax.FloatProperty}. Then user adds {@link ParallaxTarget} into
49bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * {@link ParallaxEffect}.
50bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * </p>
51bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * <p>
52bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * App may subclass {@link Parallax.IntProperty} or {@link Parallax.FloatProperty} to supply
53bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * additional information about how to retrieve Property value.  {@link RecyclerViewParallax} is
54bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * a great example of Parallax implementation tracking child view positions on screen.
55e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * </p>
56e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <p>
57e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <ul>Restrictions of properties
58bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * <li>FloatProperty and IntProperty cannot be mixed in one Parallax</li>
59e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <li>Values must be in ascending order.</li>
60e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <li>If the UI element is unknown above screen, use UNKNOWN_BEFORE.</li>
61e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <li>if the UI element is unknown below screen, use UNKNOWN_AFTER.</li>
62e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * <li>UNKNOWN_BEFORE and UNKNOWN_AFTER are not allowed to be next to each other.</li>
63e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * </ul>
64bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * These rules will be verified at runtime.
65e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * </p>
66bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * <p>
67bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * Subclass must override {@link #updateValues()} to update property values and perform
68e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * {@link ParallaxEffect}s. Subclass may call {@link #updateValues()} automatically e.g.
69e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * {@link RecyclerViewParallax} calls {@link #updateValues()} in RecyclerView scrolling. App might
70e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * call {@link #updateValues()} manually when Parallax is unaware of the value change. For example,
71e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * when a slide transition is running, {@link RecyclerViewParallax} is unaware of translation value
72e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * changes; it's the app's responsibility to call {@link #updateValues()} in every frame of
73e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * animation.
74e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu * </p>
75bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu * @param  Subclass of {@link Parallax.IntProperty} or {@link Parallax.FloatProperty}
7605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu */
77bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gupublic abstract class Parallax<PropertyT extends android.util.Property> {
7805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
79e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
80e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * Class holding a fixed value for a Property in {@link Parallax}.
81e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * @param  Class of the property, e.g. {@link IntProperty} or {@link FloatProperty}.
82e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
83e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    public static class PropertyMarkerValue<PropertyT> {
84e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final PropertyT mProperty;
85e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
86e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public PropertyMarkerValue(PropertyT property) {
87e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mProperty = property;
88e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
89e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
90e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
91e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * @return Associated property.
92e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
93e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public PropertyT getProperty() {
94e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            return mProperty;
95e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
96e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    }
97e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
98e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
99e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * IntProperty provide access to an index based integer type property inside
100bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * {@link Parallax}. The IntProperty typically represents UI element position inside
101bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * {@link Parallax}.
102e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
103bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public static class IntProperty extends Property<Parallax, Integer> {
104e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
105e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
106e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * Property value is unknown and it's smaller than minimal value of Parallax. For
107e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * example if a child is not created and before the first visible child of RecyclerView.
108e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
109e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public static final int UNKNOWN_BEFORE = Integer.MIN_VALUE;
110e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
111e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
112bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Property value is unknown and it's larger than {@link Parallax#getMaxValue()}. For
113e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * example if a child is not created and after the last visible child of RecyclerView.
114e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
115e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public static final int UNKNOWN_AFTER = Integer.MAX_VALUE;
116e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
117e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final int mIndex;
118e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
119e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
120e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * Constructor.
121e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
122e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * @param name Name of this Property.
123bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param index Index of this Property inside {@link Parallax}.
124e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
125e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public IntProperty(String name, int index) {
126e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            super(Integer.class, name);
127e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mIndex = index;
128e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
129e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
130e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        @Override
131bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final Integer get(Parallax object) {
132bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return object.getIntPropertyValue(mIndex);
133e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
134e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
135e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        @Override
136bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final void set(Parallax object, Integer value) {
137bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            object.setIntPropertyValue(mIndex, value);
138e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
139e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
140e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
141bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return Index of this Property in {@link Parallax}.
142e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
143e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public final int getIndex() {
144e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            return mIndex;
145e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
146e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
147e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
148bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Fast version of get() method that returns a primitive int value of the Property.
149bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param object The Parallax object that owns this Property.
150bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return Int value of the Property.
151e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
152bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final int getValue(Parallax object) {
153bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return object.getIntPropertyValue(mIndex);
154e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
155e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
156e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
157bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Fast version of set() method that takes a primitive int value into the Property.
158e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
159bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param object The Parallax object that owns this Property.
160bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param value Int value of the Property.
161e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
162bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final void setValue(Parallax object, int value) {
163bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            object.setIntPropertyValue(mIndex, value);
164e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
165e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
166e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
167bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for the absolute marker value.
168e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
169bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param absoluteValue The integer marker value.
170bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
171e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
172bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atAbsolute(int absoluteValue) {
173bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new IntPropertyMarkerValue(this, absoluteValue, 0f);
174e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
175e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
176e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
177bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for the marker value representing
178bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * {@link Parallax#getMaxValue()}.
179e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
180bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
181e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
182bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atMax() {
183bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new IntPropertyMarkerValue(this, 0, 1f);
184e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
185e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
186e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
187bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for the marker value representing 0.
188e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
189bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
190e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
191bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atMin() {
192bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new IntPropertyMarkerValue(this, 0);
193e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
194e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
195e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
196bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for a fraction of
197bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * {@link Parallax#getMaxValue()}.
198e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
199bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param fractionOfMaxValue 0 to 1 fraction to multiply with
200bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       {@link Parallax#getMaxValue()} for
201bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       the marker value.
202bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
203e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
204bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atFraction(float fractionOfMaxValue) {
205bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new IntPropertyMarkerValue(this, 0, fractionOfMaxValue);
20605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        }
207e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
208bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        /**
209bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Create an {@link PropertyMarkerValue} object by multiplying the fraction with
210bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * {@link Parallax#getMaxValue()} and adding offsetValue to it.
211bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *
212bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param offsetValue                    An offset integer value to be added to marker
213bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       value.
214bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
215bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       {@link Parallax#getMaxValue()} for
216bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       the marker value.
217bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
218bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         */
219bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue at(int offsetValue,
220bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                float fractionOfMaxParentVisibleSize) {
221bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new IntPropertyMarkerValue(this, offsetValue, fractionOfMaxParentVisibleSize);
222e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
223e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    }
22405de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
22505de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    /**
226e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * Implementation of {@link PropertyMarkerValue} for {@link IntProperty}.
227e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
228bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    static class IntPropertyMarkerValue extends PropertyMarkerValue<IntProperty> {
229e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final int mValue;
230e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final float mFactionOfMax;
231e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
232bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        IntPropertyMarkerValue(IntProperty property, int value) {
233e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            this(property, value, 0f);
234e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
235e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
236bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        IntPropertyMarkerValue(IntProperty property, int value, float fractionOfMax) {
237e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            super(property);
238e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mValue = value;
239e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mFactionOfMax = fractionOfMax;
240e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
241e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
242e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
243e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * @return The marker value of integer type.
244e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
245bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        final int getMarkerValue(Parallax source) {
246e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            return mFactionOfMax == 0 ? mValue : mValue + Math.round(source
247e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu                    .getMaxValue() * mFactionOfMax);
248e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
249e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    }
250e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
251e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
252e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * FloatProperty provide access to an index based integer type property inside
253bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * {@link Parallax}. The FloatProperty typically represents UI element position inside
254bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * {@link Parallax}.
255e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
256bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public static class FloatProperty extends Property<Parallax, Float> {
257e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
258e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
259e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * Property value is unknown and it's smaller than minimal value of Parallax. For
260e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * example if a child is not created and before the first visible child of RecyclerView.
261e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
262e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public static final float UNKNOWN_BEFORE = -Float.MAX_VALUE;
263e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
264e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
265bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Property value is unknown and it's larger than {@link Parallax#getMaxValue()}. For
266e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * example if a child is not created and after the last visible child of RecyclerView.
267e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
268e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public static final float UNKNOWN_AFTER = Float.MAX_VALUE;
269e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
270e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final int mIndex;
271e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
272e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
273e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * Constructor.
274e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
275e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * @param name Name of this Property.
276bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param index Index of this Property inside {@link Parallax}.
277e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
278e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public FloatProperty(String name, int index) {
279e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            super(Float.class, name);
280e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mIndex = index;
281e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
282e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
283e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        @Override
284bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final Float get(Parallax object) {
285bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return object.getFloatPropertyValue(mIndex);
286e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
287e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
288e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        @Override
289bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final void set(Parallax object, Float value) {
290bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            object.setFloatPropertyValue(mIndex, value);
291e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
292e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
293e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
294bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return Index of this Property in {@link Parallax}.
295e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
296e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        public final int getIndex() {
297e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            return mIndex;
298e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
299e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
300e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
301bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Fast version of get() method that returns a primitive int value of the Property.
302bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param object The Parallax object that owns this Property.
303bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return Float value of the Property.
304e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
305bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final float getValue(Parallax object) {
306bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return object.getFloatPropertyValue(mIndex);
307e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
308e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
309e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
310bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Fast version of set() method that takes a primitive float value into the Property.
311e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
312bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param object The Parallax object that owns this Property.
313bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param value Float value of the Property.
314e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
315bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final void setValue(Parallax object, float value) {
316bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            object.setFloatPropertyValue(mIndex, value);
317e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
318e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
319e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
320bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for the absolute marker value.
321e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
322bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param markerValue The float marker value.
323bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
324e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
325bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atAbsolute(float markerValue) {
326bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new FloatPropertyMarkerValue(this, markerValue, 0f);
327e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
328e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
329e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
330bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for the marker value representing
331bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * {@link Parallax#getMaxValue()}.
332e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
333bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
334e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
335bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atMax() {
336bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new FloatPropertyMarkerValue(this, 0, 1f);
33705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        }
338e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
339e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
340bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for the marker value representing 0.
341e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
342bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
343e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
344bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atMin() {
345bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new FloatPropertyMarkerValue(this, 0);
346e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
347e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
348e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
349bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Creates an {@link PropertyMarkerValue} object for a fraction of
350bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * {@link Parallax#getMaxValue()}.
351e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         *
352bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
353bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       {@link Parallax#getMaxValue()} for
354bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       the marker value.
355bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
356e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
357bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue atFraction(float fractionOfMaxParentVisibleSize) {
358bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new FloatPropertyMarkerValue(this, 0, fractionOfMaxParentVisibleSize);
359e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
360e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
361bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        /**
362bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * Create an {@link PropertyMarkerValue} object by multiplying the fraction with
363bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * {@link Parallax#getMaxValue()} and adding offsetValue to it.
364bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *
365bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param offsetValue                    An offset float value to be added to marker value.
366bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
367bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       {@link Parallax#getMaxValue()} for
368bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         *                                       the marker value.
369bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         * @return A new {@link PropertyMarkerValue} object.
370bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu         */
371bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        public final PropertyMarkerValue at(float offsetValue,
372bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                float fractionOfMaxParentVisibleSize) {
373bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return new FloatPropertyMarkerValue(this, offsetValue, fractionOfMaxParentVisibleSize);
374e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
375e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    }
376e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
377e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
378e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * Implementation of {@link PropertyMarkerValue} for {@link FloatProperty}.
379e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
380bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    static class FloatPropertyMarkerValue extends PropertyMarkerValue<FloatProperty> {
381e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final float mValue;
382e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        private final float mFactionOfMax;
383e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
384bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        FloatPropertyMarkerValue(FloatProperty property, float value) {
385e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            this(property, value, 0f);
386e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
387e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
388bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        FloatPropertyMarkerValue(FloatProperty property, float value, float fractionOfMax) {
389e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            super(property);
390e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mValue = value;
391e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mFactionOfMax = fractionOfMax;
392e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
393e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
394e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        /**
395e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         * @return The marker value.
396e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu         */
397bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        final float getMarkerValue(Parallax source) {
398e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            return mFactionOfMax == 0 ? mValue : mValue + source.getMaxValue()
399e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu                    * mFactionOfMax;
40005de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        }
40105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    }
40205de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
403e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    final List<PropertyT> mProperties = new ArrayList<PropertyT>();
404e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    final List<PropertyT> mPropertiesReadOnly = Collections.unmodifiableList(mProperties);
405e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
406bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    private int[] mValues = new int[4];
407bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    private float[] mFloatValues = new float[4];
408bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
409bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    private final List<ParallaxEffect> mEffects = new ArrayList<ParallaxEffect>(4);
410bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
41105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    /**
412bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Return the max value which is typically size of parent visible area, e.g. RecyclerView's
413bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * height if we are tracking Y position of a child. The size can be used to calculate marker
414bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * value using the provided fraction of FloatPropertyMarkerValue.
415bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     *
416bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @return Size of parent visible area.
417bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @see IntPropertyMarkerValue#IntPropertyMarkerValue(IntProperty, int, float)
418bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @see FloatPropertyMarkerValue#FloatPropertyMarkerValue(FloatProperty, float, float)
419e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
420bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public abstract float getMaxValue();
421bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
422bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    /**
423bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Get index based property value.
424bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     *
425bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param index Index of the property.
426bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @return Value of the property.
427bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     */
428bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    final int getIntPropertyValue(int index) {
429bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        return mValues[index];
430e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    }
431e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
432e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
433bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Set index based property value.
43405de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     *
435bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param index Index of the property.
436bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param value Value of the property.
43705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     */
438bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    final void setIntPropertyValue(int index, int value) {
439bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        if (index >= mProperties.size()) {
440bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            throw new ArrayIndexOutOfBoundsException();
441bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
442bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        mValues[index] = value;
443bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
444e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
445e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
446bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Add a new IntProperty in the Parallax object. App may override
447bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * {@link #createProperty(String, int)}.
448e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     *
449bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param name Name of the property.
450e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * @return Newly created Property object.
451bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @see #createProperty(String, int)
452e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
453bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public final PropertyT addProperty(String name) {
454bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        int newPropertyIndex = mProperties.size();
455bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        PropertyT property = createProperty(name, newPropertyIndex);
456bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        if (property instanceof IntProperty) {
457bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            int size = mValues.length;
458bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            if (size == newPropertyIndex) {
459bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                int[] newValues = new int[size * 2];
460bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                for (int i = 0; i < size; i++) {
461bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                    newValues[i] = mValues[i];
462bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                }
463bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                mValues = newValues;
464bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            }
465bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            mValues[newPropertyIndex] = IntProperty.UNKNOWN_AFTER;
466bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        } else if (property instanceof FloatProperty) {
467bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            int size = mFloatValues.length;
468bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            if (size == newPropertyIndex) {
469bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                float[] newValues = new float[size * 2];
470bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                for (int i = 0; i < size; i++) {
471bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                    newValues[i] = mFloatValues[i];
472bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                }
473bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                mFloatValues = newValues;
474bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            }
475bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            mFloatValues[newPropertyIndex] = FloatProperty.UNKNOWN_AFTER;
476bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        } else {
477bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            throw new IllegalArgumentException("Invalid Property type");
478bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
479bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        mProperties.add(property);
480bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        return property;
481bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
482e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
483e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
484e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * Verify sanity of property values, throws RuntimeException if fails. The property values
485e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * must be in ascending order. UNKNOW_BEFORE and UNKNOWN_AFTER are not allowed to be next to
486e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * each other.
487e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
488bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    void verifyIntProperties() throws IllegalStateException {
489bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        if (mProperties.size() < 2) {
490bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return;
491bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
492bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        int last = getIntPropertyValue(0);
493bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        for (int i = 1; i < mProperties.size(); i++) {
494bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            int v = getIntPropertyValue(i);
495bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            if (v < last) {
496bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
497bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                                + " smaller than Property[%d]\"%s\"",
498bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i, mProperties.get(i).getName(),
499bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i - 1, mProperties.get(i - 1).getName()));
500bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            } else if (last == IntProperty.UNKNOWN_BEFORE && v == IntProperty.UNKNOWN_AFTER) {
501bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
502bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                                + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
503bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i - 1, mProperties.get(i - 1).getName(),
504bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i, mProperties.get(i).getName()));
505bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            }
506bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            last = v;
507bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
508bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
509bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
510bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    final void verifyFloatProperties() throws IllegalStateException {
511bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        if (mProperties.size() < 2) {
512bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            return;
513bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
514bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        float last = getFloatPropertyValue(0);
515bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        for (int i = 1; i < mProperties.size(); i++) {
516bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            float v = getFloatPropertyValue(i);
517bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            if (v < last) {
518bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
519bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                                + " smaller than Property[%d]\"%s\"",
520bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i, mProperties.get(i).getName(),
521bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i - 1, mProperties.get(i - 1).getName()));
522bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            } else if (last == FloatProperty.UNKNOWN_BEFORE && v
523bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                    == FloatProperty.UNKNOWN_AFTER) {
524bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
525bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                                + " UNKNOWN_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
526bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i - 1, mProperties.get(i - 1).getName(),
527bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu                        i, mProperties.get(i).getName()));
528bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            }
529bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            last = v;
530bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
531bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
532bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
533bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    /**
534bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Get index based property value.
535bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     *
536bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param index Index of the property.
537bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @return Value of the property.
538bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     */
539bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    final float getFloatPropertyValue(int index) {
540bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        return mFloatValues[index];
541bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
542bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
543bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    /**
544bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Set index based property value.
545bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     *
546bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param index Index of the property.
547bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param value Value of the property.
548bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     */
549bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    final void setFloatPropertyValue(int index, float value) {
550bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        if (index >= mProperties.size()) {
551bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            throw new ArrayIndexOutOfBoundsException();
552bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
553bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        mFloatValues[index] = value;
554bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
555bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
556bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    /**
557bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @return A unmodifiable list of properties.
558bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     */
559bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public final List<PropertyT> getProperties() {
560bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        return mPropertiesReadOnly;
561bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    }
562bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu
563bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    /**
564bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * Create a new Property object. App does not directly call this method.  See
565bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * {@link #addProperty(String)}.
566bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     *
567bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @param index  Index of the property in this Parallax object.
568bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     * @return Newly created Property object.
569bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu     */
570bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public abstract PropertyT createProperty(String name, int index);
571e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu
572e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    /**
573e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * Update property values and perform {@link ParallaxEffect}s. Subclass may override and call
574e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * super.updateValues() after updated properties values.
575e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     */
576e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    @CallSuper
577e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu    public void updateValues() {
578e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        for (int i = 0; i < mEffects.size(); i++) {
579e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu            mEffects.get(i).performMapping(this);
580e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu        }
58105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    }
58205de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
58305de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    /**
584e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * Returns a list of {@link ParallaxEffect} object which defines rules to perform mapping to
585e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * multiple {@link ParallaxTarget}s.
58605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     *
58705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * @return A list of {@link ParallaxEffect} object.
58805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     */
58905de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    public List<ParallaxEffect> getEffects() {
59005de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        return mEffects;
59105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    }
59205de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
59305de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    /**
59405de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * Remove the {@link ParallaxEffect} object.
59505de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     *
59605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * @param effect The {@link ParallaxEffect} object to remove.
59705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     */
59805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    public void removeEffect(ParallaxEffect effect) {
59905de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        mEffects.remove(effect);
60005de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    }
60105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
60205de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    /**
60305de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * Remove all {@link ParallaxEffect} objects.
60405de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     */
60505de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    public void removeAllEffects() {
60605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        mEffects.clear();
60705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    }
60805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
60905de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    /**
61005de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * Create a {@link ParallaxEffect} object that will track source variable changes within a
61105de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * provided set of ranges.
61205de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     *
613e1cde4d4ac42a6e9e16aad2b4df970c7c7d0771cDake Gu     * @param ranges A list of marker values that defines the ranges.
61405de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     * @return Newly created ParallaxEffect object.
61505de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu     */
616bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu    public ParallaxEffect addEffect(PropertyMarkerValue... ranges) {
617bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        ParallaxEffect effect;
618bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        if (ranges[0].getProperty() instanceof IntProperty) {
619bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            effect = new IntEffect();
620bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        } else {
621bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu            effect = new FloatEffect();
622bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        }
6233778c4eaa62895085d33965ee391c8b21783cffaDake Gu        effect.setPropertyRanges(ranges);
624bf4318c67254bc11307796601b9fb4a8bbfe67b2Dake Gu        mEffects.add(effect);
62505de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu        return effect;
62605de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu    }
62705de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu
62805de4b68e45fc22c867d49ab88e2bdfd599bf7ccDake Gu}
629