Home | History | Annotate | Download | only in hint
      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 
     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
     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
     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 
    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 
    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 
    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 
    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
    239   public void onBounceEnd() {
    240     if (answerGestureHintAnim != null) {
    241       answerGestureHintAnim.end();
    242       answerGestureHintAnim = null;
    243       answerHintContainer.setVisibility(View.GONE);
    244     }
    245   }
    246 
    247   @Override
    248   public void onAnswered() {
    249     AnswerHintFactory.increaseAnsweredCount(context);
    250   }
    251 
    252   private float getDimension(@DimenRes int id) {
    253     return context.getResources().getDimension(id);
    254   }
    255 
    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 
    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