• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.incallui.answer.impl.hint;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.AnimatorSet;
22 import android.animation.ObjectAnimator;
23 import android.content.Context;
24 import android.support.annotation.DimenRes;
25 import android.support.v4.view.animation.FastOutSlowInInterpolator;
26 import android.util.TypedValue;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.animation.Interpolator;
31 import android.view.animation.LinearInterpolator;
32 import android.widget.TextView;
33 
34 /** An Answer hint that uses a green swiping dot. */
35 public class DotAnswerHint implements AnswerHint {
36 
37   private static final float ANSWER_HINT_SMALL_ALPHA = 0.8f;
38   private static final float ANSWER_HINT_MID_ALPHA = 0.5f;
39   private static final float ANSWER_HINT_LARGE_ALPHA = 0.2f;
40 
41   private static final long FADE_IN_DELAY_SCALE_MILLIS = 380;
42   private static final long FADE_IN_DURATION_SCALE_MILLIS = 200;
43   private static final long FADE_IN_DELAY_ALPHA_MILLIS = 340;
44   private static final long FADE_IN_DURATION_ALPHA_MILLIS = 50;
45 
46   private static final long SWIPE_UP_DURATION_ALPHA_MILLIS = 500;
47 
48   private static final long FADE_OUT_DELAY_SCALE_SMALL_MILLIS = 90;
49   private static final long FADE_OUT_DELAY_SCALE_MID_MILLIS = 70;
50   private static final long FADE_OUT_DELAY_SCALE_LARGE_MILLIS = 10;
51   private static final long FADE_OUT_DURATION_SCALE_MILLIS = 100;
52   private static final long FADE_OUT_DELAY_ALPHA_MILLIS = 130;
53   private static final long FADE_OUT_DURATION_ALPHA_MILLIS = 170;
54 
55   private final Context context;
56   private final long puckUpDurationMillis;
57   private final long puckUpDelayMillis;
58 
59   private View puck;
60 
61   private View answerHintSmall;
62   private View answerHintMid;
63   private View answerHintLarge;
64   private View answerHintContainer;
65   private AnimatorSet answerGestureHintAnim;
66 
DotAnswerHint(Context context, long puckUpDurationMillis, long puckUpDelayMillis)67   public DotAnswerHint(Context context, long puckUpDurationMillis, long puckUpDelayMillis) {
68     this.context = context;
69     this.puckUpDurationMillis = puckUpDurationMillis;
70     this.puckUpDelayMillis = puckUpDelayMillis;
71   }
72 
73   @Override
onCreateView( LayoutInflater inflater, ViewGroup container, View puck, TextView hintText)74   public void onCreateView(
75       LayoutInflater inflater, ViewGroup container, View puck, TextView hintText) {
76     this.puck = puck;
77     View view = inflater.inflate(R.layout.dot_hint, container, true);
78     answerHintContainer = view.findViewById(R.id.answer_hint_container);
79     answerHintSmall = view.findViewById(R.id.answer_hint_small);
80     answerHintMid = view.findViewById(R.id.answer_hint_mid);
81     answerHintLarge = view.findViewById(R.id.answer_hint_large);
82     hintText.setTextSize(
83         TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.hint_text_size));
84   }
85 
86   @Override
onBounceStart()87   public void onBounceStart() {
88     if (answerGestureHintAnim == null) {
89       answerGestureHintAnim = new AnimatorSet();
90       int[] puckLocation = new int[2];
91       puck.getLocationInWindow(puckLocation);
92       answerHintContainer.setY(puckLocation[1] + getDimension(R.dimen.hint_initial_offset));
93 
94       Animator fadeIn = createFadeIn();
95 
96       Animator swipeUp =
97           ObjectAnimator.ofFloat(
98               answerHintContainer,
99               View.TRANSLATION_Y,
100               puckLocation[1] - getDimension(R.dimen.hint_offset));
101       swipeUp.setInterpolator(new FastOutSlowInInterpolator());
102       swipeUp.setDuration(SWIPE_UP_DURATION_ALPHA_MILLIS);
103 
104       Animator fadeOut = createFadeOut();
105 
106       answerGestureHintAnim.play(fadeIn).after(puckUpDelayMillis);
107       answerGestureHintAnim.play(swipeUp).after(fadeIn);
108       // The fade out should start fading the alpha just as the puck is dropping. Scaling will start
109       // a bit earlier.
110       answerGestureHintAnim
111           .play(fadeOut)
112           .after(puckUpDelayMillis + puckUpDurationMillis - FADE_OUT_DELAY_ALPHA_MILLIS);
113 
114       fadeIn.addListener(
115           new AnimatorListenerAdapter() {
116             @Override
117             public void onAnimationStart(Animator animation) {
118               super.onAnimationStart(animation);
119               answerHintSmall.setAlpha(0);
120               answerHintSmall.setScaleX(1);
121               answerHintSmall.setScaleY(1);
122               answerHintMid.setAlpha(0);
123               answerHintMid.setScaleX(1);
124               answerHintMid.setScaleY(1);
125               answerHintLarge.setAlpha(0);
126               answerHintLarge.setScaleX(1);
127               answerHintLarge.setScaleY(1);
128               answerHintContainer.setY(puckLocation[1] + getDimension(R.dimen.hint_initial_offset));
129               answerHintContainer.setVisibility(View.VISIBLE);
130             }
131           });
132     }
133 
134     answerGestureHintAnim.start();
135   }
136 
createFadeIn()137   private Animator createFadeIn() {
138     AnimatorSet set = new AnimatorSet();
139     set.play(
140             createFadeInScaleAndAlpha(
141                 answerHintSmall,
142                 R.dimen.hint_small_begin_size,
143                 R.dimen.hint_small_end_size,
144                 ANSWER_HINT_SMALL_ALPHA))
145         .with(
146             createFadeInScaleAndAlpha(
147                 answerHintMid,
148                 R.dimen.hint_mid_begin_size,
149                 R.dimen.hint_mid_end_size,
150                 ANSWER_HINT_MID_ALPHA))
151         .with(
152             createFadeInScaleAndAlpha(
153                 answerHintLarge,
154                 R.dimen.hint_large_begin_size,
155                 R.dimen.hint_large_end_size,
156                 ANSWER_HINT_LARGE_ALPHA));
157     return set;
158   }
159 
createFadeInScaleAndAlpha( View target, @DimenRes int beginSize, @DimenRes int endSize, float endAlpha)160   private Animator createFadeInScaleAndAlpha(
161       View target, @DimenRes int beginSize, @DimenRes int endSize, float endAlpha) {
162     Animator scale =
163         createUniformScaleAnimator(
164             target,
165             getDimension(beginSize),
166             getDimension(beginSize),
167             getDimension(endSize),
168             FADE_IN_DURATION_SCALE_MILLIS,
169             FADE_IN_DELAY_SCALE_MILLIS,
170             new LinearInterpolator());
171     Animator alpha =
172         createAlphaAnimator(
173             target,
174             0f,
175             endAlpha,
176             FADE_IN_DURATION_ALPHA_MILLIS,
177             FADE_IN_DELAY_ALPHA_MILLIS,
178             new LinearInterpolator());
179     AnimatorSet set = new AnimatorSet();
180     set.play(scale).with(alpha);
181     return set;
182   }
183 
createFadeOut()184   private Animator createFadeOut() {
185     AnimatorSet set = new AnimatorSet();
186     set.play(
187             createFadeOutScaleAndAlpha(
188                 answerHintSmall,
189                 R.dimen.hint_small_begin_size,
190                 R.dimen.hint_small_end_size,
191                 FADE_OUT_DELAY_SCALE_SMALL_MILLIS,
192                 ANSWER_HINT_SMALL_ALPHA))
193         .with(
194             createFadeOutScaleAndAlpha(
195                 answerHintMid,
196                 R.dimen.hint_mid_begin_size,
197                 R.dimen.hint_mid_end_size,
198                 FADE_OUT_DELAY_SCALE_MID_MILLIS,
199                 ANSWER_HINT_MID_ALPHA))
200         .with(
201             createFadeOutScaleAndAlpha(
202                 answerHintLarge,
203                 R.dimen.hint_large_begin_size,
204                 R.dimen.hint_large_end_size,
205                 FADE_OUT_DELAY_SCALE_LARGE_MILLIS,
206                 ANSWER_HINT_LARGE_ALPHA));
207     return set;
208   }
209 
createFadeOutScaleAndAlpha( View target, @DimenRes int beginSize, @DimenRes int endSize, long scaleDelay, float endAlpha)210   private Animator createFadeOutScaleAndAlpha(
211       View target,
212       @DimenRes int beginSize,
213       @DimenRes int endSize,
214       long scaleDelay,
215       float endAlpha) {
216     Animator scale =
217         createUniformScaleAnimator(
218             target,
219             getDimension(beginSize),
220             getDimension(endSize),
221             getDimension(beginSize),
222             FADE_OUT_DURATION_SCALE_MILLIS,
223             scaleDelay,
224             new LinearInterpolator());
225     Animator alpha =
226         createAlphaAnimator(
227             target,
228             endAlpha,
229             0.0f,
230             FADE_OUT_DURATION_ALPHA_MILLIS,
231             FADE_OUT_DELAY_ALPHA_MILLIS,
232             new LinearInterpolator());
233     AnimatorSet set = new AnimatorSet();
234     set.play(scale).with(alpha);
235     return set;
236   }
237 
238   @Override
onBounceEnd()239   public void onBounceEnd() {
240     if (answerGestureHintAnim != null) {
241       answerGestureHintAnim.end();
242       answerGestureHintAnim = null;
243       answerHintContainer.setVisibility(View.GONE);
244     }
245   }
246 
247   @Override
onAnswered()248   public void onAnswered() {
249     AnswerHintFactory.increaseAnsweredCount(context);
250   }
251 
getDimension(@imenRes int id)252   private float getDimension(@DimenRes int id) {
253     return context.getResources().getDimension(id);
254   }
255 
createUniformScaleAnimator( View target, float original, float begin, float end, long duration, long delay, Interpolator interpolator)256   private static Animator createUniformScaleAnimator(
257       View target,
258       float original,
259       float begin,
260       float end,
261       long duration,
262       long delay,
263       Interpolator interpolator) {
264     float scaleBegin = begin / original;
265     float scaleEnd = end / original;
266     Animator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, scaleBegin, scaleEnd);
267     Animator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, scaleBegin, scaleEnd);
268     scaleX.setDuration(duration);
269     scaleY.setDuration(duration);
270     scaleX.setInterpolator(interpolator);
271     scaleY.setInterpolator(interpolator);
272     AnimatorSet set = new AnimatorSet();
273     set.play(scaleX).with(scaleY).after(delay);
274     return set;
275   }
276 
createAlphaAnimator( View target, float begin, float end, long duration, long delay, Interpolator interpolator)277   private static Animator createAlphaAnimator(
278       View target, float begin, float end, long duration, long delay, Interpolator interpolator) {
279     Animator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, begin, end);
280     alpha.setDuration(duration);
281     alpha.setInterpolator(interpolator);
282     alpha.setStartDelay(delay);
283     return alpha;
284   }
285 }
286