1faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/*
2faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Copyright (C) 2013 The Android Open Source Project
3faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
4faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * you may not use this file except in compliance with the License.
6faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * You may obtain a copy of the License at
7faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
8faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
10faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Unless required by applicable law or agreed to in writing, software
11faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * See the License for the specific language governing permissions and
14faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * limitations under the License.
15faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
166ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase
17d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haasepackage android.transition;
18faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
19faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.Animator;
20faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.AnimatorListenerAdapter;
21c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haaseimport android.animation.AnimatorSet;
22faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.ValueAnimator;
23c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haaseimport android.graphics.Color;
249b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haaseimport android.util.Log;
25faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewGroup;
26d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haaseimport android.widget.EditText;
27faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.widget.TextView;
28faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
2908735185f8105710e18ad02297461bec9268e514Chet Haaseimport java.util.Map;
30faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
31faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/**
32faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * This transition tracks changes to the text in TextView targets. If the text
33faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * changes between the start and end scenes, the transition ensures that the
34faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * starting text stays until the transition ends, at which point it changes
35faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * to the end text.  This is useful in situations where you want to resize a
36faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * text view to its new size before displaying the text that goes there.
37d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase *
38d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * @hide
39faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
40b7a7fc9d233bad507ce893882352618b13647058Chet Haasepublic class ChangeText extends Transition {
419b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase
429b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    private static final String LOG_TAG = "TextChange";
439b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase
44faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private static final String PROPNAME_TEXT = "android:textchange:text";
45d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase    private static final String PROPNAME_TEXT_SELECTION_START =
46d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            "android:textchange:textSelectionStart";
47d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase    private static final String PROPNAME_TEXT_SELECTION_END =
48d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            "android:textchange:textSelectionEnd";
49c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    private static final String PROPNAME_TEXT_COLOR = "android:textchange:textColor";
50faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
51c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    private int mChangeBehavior = CHANGE_BEHAVIOR_KEEP;
52c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase
53c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    /**
54c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * Flag specifying that the text in affected/changing TextView targets will keep
55c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * their original text during the transition, setting it to the final text when
56c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * the transition ends. This is the default behavior.
57c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     *
58c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * @see #setChangeBehavior(int)
59c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     */
60c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    public static final int CHANGE_BEHAVIOR_KEEP = 0;
61c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    /**
62c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * Flag specifying that the text changing animation should first fade
63c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * out the original text completely. The new text is set on the target
64c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * view at the end of the fade-out animation. This transition is typically
65c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * used with a later {@link #CHANGE_BEHAVIOR_IN} transition, allowing more
66c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * flexibility than the {@link #CHANGE_BEHAVIOR_OUT_IN} by allowing other
67c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * transitions to be run sequentially or in parallel with these fades.
68c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     *
69c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * @see #setChangeBehavior(int)
70c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     */
71c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    public static final int CHANGE_BEHAVIOR_OUT = 1;
72c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    /**
73c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * Flag specifying that the text changing animation should fade in the
74c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * end text into the affected target view(s). This transition is typically
75c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * used in conjunction with an earlier {@link #CHANGE_BEHAVIOR_OUT}
76c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * transition, possibly with other transitions running as well, such as
77c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * a sequence to fade out, then resize the view, then fade in.
78c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     *
79c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * @see #setChangeBehavior(int)
80c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     */
81c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    public static final int CHANGE_BEHAVIOR_IN = 2;
82c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    /**
83c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * Flag specifying that the text changing animation should first fade
84c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * out the original text completely and then fade in the
85c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * new text.
86c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     *
87c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * @see #setChangeBehavior(int)
88c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     */
89c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    public static final int CHANGE_BEHAVIOR_OUT_IN = 3;
90c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase
91af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase    private static final String[] sTransitionProperties = {
92d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            PROPNAME_TEXT,
93d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            PROPNAME_TEXT_SELECTION_START,
94d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            PROPNAME_TEXT_SELECTION_END
95af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase    };
96af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase
97c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    /**
98c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * Sets the type of changing animation that will be run, one of
99d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT},
100d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * {@link #CHANGE_BEHAVIOR_IN}, and {@link #CHANGE_BEHAVIOR_OUT_IN}.
101c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     *
102c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * @param changeBehavior The type of fading animation to use when this
103c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     * transition is run.
104d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @return this textChange object.
105c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase     */
106b7a7fc9d233bad507ce893882352618b13647058Chet Haase    public ChangeText setChangeBehavior(int changeBehavior) {
107c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase        if (changeBehavior >= CHANGE_BEHAVIOR_KEEP && changeBehavior <= CHANGE_BEHAVIOR_OUT_IN) {
108c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            mChangeBehavior = changeBehavior;
109c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase        }
110d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        return this;
111c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase    }
112faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
113faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    @Override
114af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase    public String[] getTransitionProperties() {
115af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase        return sTransitionProperties;
116af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase    }
117af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase
118d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    /**
119d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Returns the type of changing animation that will be run.
120d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     *
121d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @return either {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT},
122d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * {@link #CHANGE_BEHAVIOR_IN}, or {@link #CHANGE_BEHAVIOR_OUT_IN}.
123d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     */
124d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public int getChangeBehavior() {
125d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        return mChangeBehavior;
126d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    }
127d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase
128d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    private void captureValues(TransitionValues transitionValues) {
129d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        if (transitionValues.view instanceof TextView) {
130d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            TextView textview = (TextView) transitionValues.view;
131d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase            transitionValues.values.put(PROPNAME_TEXT, textview.getText());
132d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            if (textview instanceof EditText) {
133d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                transitionValues.values.put(PROPNAME_TEXT_SELECTION_START,
134d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                        textview.getSelectionStart());
135d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                transitionValues.values.put(PROPNAME_TEXT_SELECTION_END,
136d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                        textview.getSelectionEnd());
137d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            }
138c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
139d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase                transitionValues.values.put(PROPNAME_TEXT_COLOR, textview.getCurrentTextColor());
140c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            }
141faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
142faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
143faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
144faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    @Override
145d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public void captureStartValues(TransitionValues transitionValues) {
146d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        captureValues(transitionValues);
147d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    }
148d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase
149d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    @Override
150d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public void captureEndValues(TransitionValues transitionValues) {
151d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        captureValues(transitionValues);
152d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    }
153d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase
154d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    @Override
155d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
156faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            TransitionValues endValues) {
1578529b30b91a3af235cda52ea0889ae9af7590129Chet Haase        if (startValues == null || endValues == null ||
1588529b30b91a3af235cda52ea0889ae9af7590129Chet Haase                !(startValues.view instanceof TextView) || !(endValues.view instanceof TextView)) {
159faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            return null;
160faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
161faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        final TextView view = (TextView) endValues.view;
16208735185f8105710e18ad02297461bec9268e514Chet Haase        Map<String, Object> startVals = startValues.values;
16308735185f8105710e18ad02297461bec9268e514Chet Haase        Map<String, Object> endVals = endValues.values;
1648529b30b91a3af235cda52ea0889ae9af7590129Chet Haase        final CharSequence startText = startVals.get(PROPNAME_TEXT) != null ?
1658529b30b91a3af235cda52ea0889ae9af7590129Chet Haase                (CharSequence) startVals.get(PROPNAME_TEXT) : "";
1668529b30b91a3af235cda52ea0889ae9af7590129Chet Haase        final CharSequence endText = endVals.get(PROPNAME_TEXT) != null ?
1678529b30b91a3af235cda52ea0889ae9af7590129Chet Haase                (CharSequence) endVals.get(PROPNAME_TEXT) : "";
168d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase        final int startSelectionStart, startSelectionEnd, endSelectionStart, endSelectionEnd;
169d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase        if (view instanceof EditText) {
170d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            startSelectionStart = startVals.get(PROPNAME_TEXT_SELECTION_START) != null ?
171d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                    (Integer) startVals.get(PROPNAME_TEXT_SELECTION_START) : -1;
172d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            startSelectionEnd = startVals.get(PROPNAME_TEXT_SELECTION_END) != null ?
173d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                    (Integer) startVals.get(PROPNAME_TEXT_SELECTION_END) : startSelectionStart;
174d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            endSelectionStart = endVals.get(PROPNAME_TEXT_SELECTION_START) != null ?
175d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                    (Integer) endVals.get(PROPNAME_TEXT_SELECTION_START) : -1;
176d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            endSelectionEnd = endVals.get(PROPNAME_TEXT_SELECTION_END) != null ?
177d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                    (Integer) endVals.get(PROPNAME_TEXT_SELECTION_END) : endSelectionStart;
178d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase        } else {
179d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            startSelectionStart = startSelectionEnd = endSelectionStart = endSelectionEnd = -1;
180d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase        }
181faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (!startText.equals(endText)) {
182aa006133228facf2f9b61e0492fd8f724fac472fChet Haase            final int startColor;
183aa006133228facf2f9b61e0492fd8f724fac472fChet Haase            final int endColor;
184b7a7fc9d233bad507ce893882352618b13647058Chet Haase            if (mChangeBehavior != CHANGE_BEHAVIOR_IN) {
185b7a7fc9d233bad507ce893882352618b13647058Chet Haase                view.setText(startText);
186b7a7fc9d233bad507ce893882352618b13647058Chet Haase                if (view instanceof EditText) {
187b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    setSelection(((EditText) view), startSelectionStart, startSelectionEnd);
188b7a7fc9d233bad507ce893882352618b13647058Chet Haase                }
189d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            }
190c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            Animator anim;
191c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            if (mChangeBehavior == CHANGE_BEHAVIOR_KEEP) {
192aa006133228facf2f9b61e0492fd8f724fac472fChet Haase                startColor = endColor = 0;
193c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                anim = ValueAnimator.ofFloat(0, 1);
194c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                anim.addListener(new AnimatorListenerAdapter() {
195c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    @Override
196c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    public void onAnimationEnd(Animator animation) {
197af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                        if (startText.equals(view.getText())) {
198af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                            // Only set if it hasn't been changed since anim started
199af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                            view.setText(endText);
200d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                            if (view instanceof EditText) {
201d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                                setSelection(((EditText) view), endSelectionStart, endSelectionEnd);
202d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                            }
203af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                        }
204c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    }
205c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                });
206c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            } else {
207aa006133228facf2f9b61e0492fd8f724fac472fChet Haase                startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR);
208aa006133228facf2f9b61e0492fd8f724fac472fChet Haase                endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR);
209c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                // Fade out start text
210c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                ValueAnimator outAnim = null, inAnim = null;
211c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN ||
212c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        mChangeBehavior == CHANGE_BEHAVIOR_OUT) {
213bbeafd1199fc12b57b32b2e86820e227b3efd149Doris Liu                    outAnim = ValueAnimator.ofInt(Color.alpha(startColor), 0);
214c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    outAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
215c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        @Override
216c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        public void onAnimationUpdate(ValueAnimator animation) {
217c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                            int currAlpha = (Integer) animation.getAnimatedValue();
218bbeafd1199fc12b57b32b2e86820e227b3efd149Doris Liu                            view.setTextColor(currAlpha << 24 | startColor & 0xffffff);
219c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        }
220c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    });
221c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    outAnim.addListener(new AnimatorListenerAdapter() {
222c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        @Override
223c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        public void onAnimationEnd(Animator animation) {
224af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                            if (startText.equals(view.getText())) {
225af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                                // Only set if it hasn't been changed since anim started
226af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                                view.setText(endText);
227d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                                if (view instanceof EditText) {
228d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                                    setSelection(((EditText) view), endSelectionStart,
229d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                                            endSelectionEnd);
230d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                                }
231af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                            }
232b7a7fc9d233bad507ce893882352618b13647058Chet Haase                            // restore opaque alpha and correct end color
233b7a7fc9d233bad507ce893882352618b13647058Chet Haase                            view.setTextColor(endColor);
234c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        }
235c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    });
236c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                }
237c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN ||
238c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        mChangeBehavior == CHANGE_BEHAVIOR_IN) {
239bbeafd1199fc12b57b32b2e86820e227b3efd149Doris Liu                    inAnim = ValueAnimator.ofInt(0, Color.alpha(endColor));
240c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    inAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
241c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        @Override
242c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        public void onAnimationUpdate(ValueAnimator animation) {
243c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                            int currAlpha = (Integer) animation.getAnimatedValue();
244bbeafd1199fc12b57b32b2e86820e227b3efd149Doris Liu                            view.setTextColor(currAlpha << 24 | endColor & 0xffffff);
245c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                        }
246c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    });
247b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    inAnim.addListener(new AnimatorListenerAdapter() {
248b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        @Override
249b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        public void onAnimationCancel(Animator animation) {
250b7a7fc9d233bad507ce893882352618b13647058Chet Haase                            // restore opaque alpha and correct end color
251b7a7fc9d233bad507ce893882352618b13647058Chet Haase                            view.setTextColor(endColor);
252b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        }
253b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    });
254c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                }
255c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                if (outAnim != null && inAnim != null) {
256c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    anim = new AnimatorSet();
257c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    ((AnimatorSet) anim).playSequentially(outAnim, inAnim);
258c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                } else if (outAnim != null) {
259c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    anim = outAnim;
260c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                } else {
261c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    // Must be an in-only animation
262c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase                    anim = inAnim;
263faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
264c81a8493884c7f432d6bd5b98aca3fbdc93b355bChet Haase            }
265af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase            TransitionListener transitionListener = new TransitionListenerAdapter() {
266b7a7fc9d233bad507ce893882352618b13647058Chet Haase                int mPausedColor = 0;
267af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase
268af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                @Override
269af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                public void onTransitionPause(Transition transition) {
270b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    if (mChangeBehavior != CHANGE_BEHAVIOR_IN) {
271b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        view.setText(endText);
272b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        if (view instanceof EditText) {
273b7a7fc9d233bad507ce893882352618b13647058Chet Haase                            setSelection(((EditText) view), endSelectionStart, endSelectionEnd);
274b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        }
275b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    }
276b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
277b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        mPausedColor = view.getCurrentTextColor();
278b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        view.setTextColor(endColor);
279d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                    }
280af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                }
281af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase
282af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                @Override
283af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                public void onTransitionResume(Transition transition) {
284b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    if (mChangeBehavior != CHANGE_BEHAVIOR_IN) {
285b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        view.setText(startText);
286b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        if (view instanceof EditText) {
287b7a7fc9d233bad507ce893882352618b13647058Chet Haase                            setSelection(((EditText) view), startSelectionStart, startSelectionEnd);
288b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        }
289b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    }
290b7a7fc9d233bad507ce893882352618b13647058Chet Haase                    if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
291b7a7fc9d233bad507ce893882352618b13647058Chet Haase                        view.setTextColor(mPausedColor);
292d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase                    }
293af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase                }
29425f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount
29525f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount                @Override
29625f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount                public void onTransitionEnd(Transition transition) {
29725f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount                    transition.removeListener(this);
29825f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount                }
299af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase            };
300af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase            addListener(transitionListener);
3019b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            if (DBG) {
3029b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                Log.d(LOG_TAG, "createAnimator returning " + anim);
3039b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            }
304faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            return anim;
305faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
306faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return null;
307faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
308d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase
309d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase    private void setSelection(EditText editText, int start, int end) {
310d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase        if (start >= 0 && end >= 0) {
311d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase            editText.setSelection(start, end);
312d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase        }
313d8d7c38533d20062166e5e7ef89b80ff9dbd8903Chet Haase    }
314faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase}
315