diff options
Diffstat (limited to 'java/com/android/incallui/answer/impl/hint/PawAnswerHint.java')
-rw-r--r-- | java/com/android/incallui/answer/impl/hint/PawAnswerHint.java | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/java/com/android/incallui/answer/impl/hint/PawAnswerHint.java b/java/com/android/incallui/answer/impl/hint/PawAnswerHint.java new file mode 100644 index 000000000..36b761f57 --- /dev/null +++ b/java/com/android/incallui/answer/impl/hint/PawAnswerHint.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.incallui.answer.impl.hint; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.DimenRes; +import android.support.annotation.NonNull; +import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.dialer.common.Assert; + +/** + * An Answer hint that animates a {@link Drawable} payload with animation similar to {@link + * DotAnswerHint}. + */ +public final class PawAnswerHint implements AnswerHint { + + private static final long FADE_IN_DELAY_SCALE_MILLIS = 380; + private static final long FADE_IN_DURATION_SCALE_MILLIS = 200; + private static final long FADE_IN_DELAY_ALPHA_MILLIS = 340; + private static final long FADE_IN_DURATION_ALPHA_MILLIS = 50; + + private static final long SWIPE_UP_DURATION_ALPHA_MILLIS = 500; + + private static final long FADE_OUT_DELAY_SCALE_SMALL_MILLIS = 90; + private static final long FADE_OUT_DURATION_SCALE_MILLIS = 100; + private static final long FADE_OUT_DELAY_ALPHA_MILLIS = 130; + private static final long FADE_OUT_DURATION_ALPHA_MILLIS = 170; + + private static final float IMAGE_SCALE = 1.5f; + private static final float FADE_SCALE = 2.0f; + + private final Context context; + private final Drawable payload; + private final long puckUpDurationMillis; + private final long puckUpDelayMillis; + + private View puck; + private View payloadView; + private View answerHintContainer; + private AnimatorSet answerGestureHintAnim; + + public PawAnswerHint( + @NonNull Context context, + @NonNull Drawable payload, + long puckUpDurationMillis, + long puckUpDelayMillis) { + this.context = Assert.isNotNull(context); + this.payload = Assert.isNotNull(payload); + this.puckUpDurationMillis = puckUpDurationMillis; + this.puckUpDelayMillis = puckUpDelayMillis; + } + + @Override + public void onCreateView( + LayoutInflater inflater, ViewGroup container, View puck, TextView hintText) { + this.puck = puck; + View view = inflater.inflate(R.layout.paw_hint, container, true); + answerHintContainer = view.findViewById(R.id.answer_hint_container); + payloadView = view.findViewById(R.id.paw_image); + hintText.setTextSize( + TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.hint_text_size)); + ((ImageView) payloadView).setImageDrawable(payload); + } + + @Override + public void onBounceStart() { + if (answerGestureHintAnim == null) { + + answerGestureHintAnim = new AnimatorSet(); + answerHintContainer.setY(puck.getY() + getDimension(R.dimen.hint_initial_offset)); + + Animator fadeIn = createFadeIn(); + + Animator swipeUp = + ObjectAnimator.ofFloat( + answerHintContainer, + View.TRANSLATION_Y, + puck.getY() - getDimension(R.dimen.hint_offset)); + swipeUp.setInterpolator(new FastOutSlowInInterpolator()); + swipeUp.setDuration(SWIPE_UP_DURATION_ALPHA_MILLIS); + + Animator fadeOut = createFadeOut(); + + answerGestureHintAnim.play(fadeIn).after(puckUpDelayMillis); + answerGestureHintAnim.play(swipeUp).after(fadeIn); + // The fade out should start fading the alpha just as the puck is dropping. Scaling will start + // a bit earlier. + answerGestureHintAnim + .play(fadeOut) + .after(puckUpDelayMillis + puckUpDurationMillis - FADE_OUT_DELAY_ALPHA_MILLIS); + + fadeIn.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + payloadView.setAlpha(0); + payloadView.setScaleX(1); + payloadView.setScaleY(1); + answerHintContainer.setY(puck.getY() + getDimension(R.dimen.hint_initial_offset)); + answerHintContainer.setVisibility(View.VISIBLE); + } + }); + } + + answerGestureHintAnim.start(); + } + + private Animator createFadeIn() { + AnimatorSet set = new AnimatorSet(); + set.play(createFadeInScaleAndAlpha(payloadView)); + return set; + } + + private static Animator createFadeInScaleAndAlpha(View target) { + Animator scale = + createUniformScaleAnimator( + target, + FADE_SCALE, + IMAGE_SCALE, + FADE_IN_DURATION_SCALE_MILLIS, + FADE_IN_DELAY_SCALE_MILLIS, + new LinearInterpolator()); + Animator alpha = + createAlphaAnimator( + target, + 0f, + 1.0f, + FADE_IN_DURATION_ALPHA_MILLIS, + FADE_IN_DELAY_ALPHA_MILLIS, + new LinearInterpolator()); + AnimatorSet set = new AnimatorSet(); + set.play(scale).with(alpha); + return set; + } + + private Animator createFadeOut() { + AnimatorSet set = new AnimatorSet(); + set.play(createFadeOutScaleAndAlpha(payloadView, FADE_OUT_DELAY_SCALE_SMALL_MILLIS)); + return set; + } + + private static Animator createFadeOutScaleAndAlpha(View target, long scaleDelay) { + Animator scale = + createUniformScaleAnimator( + target, + IMAGE_SCALE, + FADE_SCALE, + FADE_OUT_DURATION_SCALE_MILLIS, + scaleDelay, + new LinearInterpolator()); + Animator alpha = + createAlphaAnimator( + target, + 1.0f, + 0.0f, + FADE_OUT_DURATION_ALPHA_MILLIS, + FADE_OUT_DELAY_ALPHA_MILLIS, + new LinearInterpolator()); + AnimatorSet set = new AnimatorSet(); + set.play(scale).with(alpha); + return set; + } + + @Override + public void onBounceEnd() { + if (answerGestureHintAnim != null) { + answerGestureHintAnim.end(); + answerGestureHintAnim = null; + answerHintContainer.setVisibility(View.GONE); + } + } + + @Override + public void onAnswered() { + // Do nothing + } + + private float getDimension(@DimenRes int id) { + return context.getResources().getDimension(id); + } + + private static Animator createUniformScaleAnimator( + View target, + float scaleBegin, + float scaleEnd, + long duration, + long delay, + Interpolator interpolator) { + Animator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, scaleBegin, scaleEnd); + Animator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, scaleBegin, scaleEnd); + scaleX.setDuration(duration); + scaleY.setDuration(duration); + scaleX.setInterpolator(interpolator); + scaleY.setInterpolator(interpolator); + AnimatorSet set = new AnimatorSet(); + set.play(scaleX).with(scaleY).after(delay); + return set; + } + + private static Animator createAlphaAnimator( + View target, float begin, float end, long duration, long delay, Interpolator interpolator) { + Animator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, begin, end); + alpha.setDuration(duration); + alpha.setInterpolator(interpolator); + alpha.setStartDelay(delay); + return alpha; + } +} |