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.support.v17.leanback.widget;
18
19import android.animation.ObjectAnimator;
20import android.animation.PropertyValuesHolder;
21import android.util.Property;
22import android.view.animation.LinearInterpolator;
23
24/**
25 * ParallaxTarget is responsible for updating the target through the {@link #update(float)} method
26 * or the {@link #directUpdate(Number)} method when {@link #isDirectMapping()} is true.
27 * When {@link #isDirectMapping()} is false, {@link ParallaxEffect} transforms the values of
28 * {@link Parallax}, which represents the current state of UI, into a float value between 0 and 1.
29 * That float value is passed into {@link #update(float)} method.
30 */
31public abstract class ParallaxTarget {
32
33    /**
34     * Implementation class is supposed to update target with the provided fraction
35     * (between 0 and 1). The fraction represents percentage of completed change (e.g. scroll) on
36     * target. Called only when {@link #isDirectMapping()} is false.
37     *
38     * @param fraction Fraction between 0 to 1.
39     * @see #isDirectMapping()
40     */
41    public void update(float fraction) {
42    }
43
44    /**
45     * Returns true if the ParallaxTarget is directly mapping from source value,
46     * {@link #directUpdate(Number)} will be used to update value, otherwise update(fraction) will
47     * be called to update value. Default implementation returns false.
48     *
49     * @return True if direct mapping, false otherwise.
50     * @see #directUpdate(Number)
51     * @see #update(float)
52     */
53    public boolean isDirectMapping() {
54        return false;
55    }
56
57    /**
58     * Directly update the target using a float or int value. Called when {@link #isDirectMapping()}
59     * is true.
60     *
61     * @param value Either int or float value.
62     * @see #isDirectMapping()
63     */
64    public void directUpdate(Number value) {
65    }
66
67    /**
68     * PropertyValuesHolderTarget is an implementation of {@link ParallaxTarget} that uses
69     * {@link PropertyValuesHolder} to update the target object.
70     */
71    public static final class PropertyValuesHolderTarget extends ParallaxTarget {
72
73        /**
74         * We simulate a parallax effect on target object using an ObjectAnimator. PSEUDO_DURATION
75         * is used on the ObjectAnimator.
76         */
77        private static final long PSEUDO_DURATION = 1000000;
78
79        private final ObjectAnimator mAnimator;
80        private float mFraction;
81
82        public PropertyValuesHolderTarget(Object targetObject, PropertyValuesHolder values) {
83            mAnimator = ObjectAnimator.ofPropertyValuesHolder(targetObject, values);
84            mAnimator.setInterpolator(new LinearInterpolator());
85            mAnimator.setDuration(PSEUDO_DURATION);
86        }
87
88        @Override
89        public void update(float fraction) {
90            mFraction = fraction;
91            mAnimator.setCurrentPlayTime((long) (PSEUDO_DURATION * fraction));
92        }
93
94    }
95
96    /**
97     * DirectPropertyTarget is to support direct mapping into either Integer Property or Float
98     * Property. App uses convenient method {@link ParallaxEffect#target(Object, Property)} to
99     * add a direct mapping.
100     * @param <T> Type of target object.
101     * @param <V> Type of value, either Integer or Float.
102     */
103    public static final class DirectPropertyTarget<T extends Object, V extends Number>
104            extends ParallaxTarget {
105
106        Object mObject;
107        Property<T, V> mProperty;
108
109        /**
110         * @param targetObject Target object for perform Parallax
111         * @param property     Target property, either an Integer Property or a Float Property.
112         */
113        public DirectPropertyTarget(Object targetObject, Property<T, V> property) {
114            mObject = targetObject;
115            mProperty = property;
116        }
117
118        /**
119         * Returns true as DirectPropertyTarget receives a number to update Property in
120         * {@link #directUpdate(Number)}.
121         */
122        @Override
123        public boolean isDirectMapping() {
124            return true;
125        }
126
127        @Override
128        public void directUpdate(Number value) {
129            mProperty.set((T) mObject, (V) value);
130        }
131    }
132}
133