1 /*
2  * Copyright (C) 2015 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.dialer.app.dialpad;
18 
19 import android.animation.Animator;
20 import android.animation.Animator.AnimatorListener;
21 import android.animation.ArgbEvaluator;
22 import android.animation.ValueAnimator;
23 import android.animation.ValueAnimator.AnimatorUpdateListener;
24 import android.content.Context;
25 import android.graphics.Color;
26 import android.graphics.ColorFilter;
27 import android.graphics.LightingColorFilter;
28 import android.os.Handler;
29 import android.os.Vibrator;
30 import android.view.View;
31 import com.android.dialer.app.R;
32 
33 /** Animates the dial button on "emergency" phone numbers. */
34 public class PseudoEmergencyAnimator {
35 
36   public static final String PSEUDO_EMERGENCY_NUMBER = "01189998819991197253";
37   private static final int VIBRATE_LENGTH_MILLIS = 200;
38   private static final int ITERATION_LENGTH_MILLIS = 1000;
39   private static final int ANIMATION_ITERATION_COUNT = 6;
40   private ViewProvider mViewProvider;
41   private ValueAnimator mPseudoEmergencyColorAnimator;
42 
PseudoEmergencyAnimator(ViewProvider viewProvider)43   PseudoEmergencyAnimator(ViewProvider viewProvider) {
44     mViewProvider = viewProvider;
45   }
46 
destroy()47   public void destroy() {
48     end();
49     mViewProvider = null;
50   }
51 
start()52   public void start() {
53     if (mPseudoEmergencyColorAnimator == null) {
54       Integer colorFrom = Color.BLUE;
55       Integer colorTo = Color.RED;
56       mPseudoEmergencyColorAnimator =
57           ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
58 
59       mPseudoEmergencyColorAnimator.addUpdateListener(
60           new AnimatorUpdateListener() {
61             @Override
62             public void onAnimationUpdate(ValueAnimator animator) {
63               try {
64                 int color = (int) animator.getAnimatedValue();
65                 ColorFilter colorFilter = new LightingColorFilter(Color.BLACK, color);
66 
67                 View floatingActionButtonContainer =
68                     getView().findViewById(R.id.floating_action_button);
69                 if (floatingActionButtonContainer != null) {
70                   floatingActionButtonContainer.getBackground().setColorFilter(colorFilter);
71                 }
72               } catch (Exception e) {
73                 animator.cancel();
74               }
75             }
76           });
77 
78       mPseudoEmergencyColorAnimator.addListener(
79           new AnimatorListener() {
80             @Override
81             public void onAnimationCancel(Animator animation) {}
82 
83             @Override
84             public void onAnimationRepeat(Animator animation) {
85               try {
86                 vibrate(VIBRATE_LENGTH_MILLIS);
87               } catch (Exception e) {
88                 animation.cancel();
89               }
90             }
91 
92             @Override
93             public void onAnimationStart(Animator animation) {}
94 
95             @Override
96             public void onAnimationEnd(Animator animation) {
97               try {
98                 View floatingActionButtonContainer =
99                     getView().findViewById(R.id.floating_action_button);
100                 if (floatingActionButtonContainer != null) {
101                   floatingActionButtonContainer.getBackground().clearColorFilter();
102                 }
103 
104                 new Handler()
105                     .postDelayed(
106                         new Runnable() {
107                           @Override
108                           public void run() {
109                             try {
110                               vibrate(VIBRATE_LENGTH_MILLIS);
111                             } catch (Exception e) {
112                               // ignored
113                             }
114                           }
115                         },
116                         ITERATION_LENGTH_MILLIS);
117               } catch (Exception e) {
118                 animation.cancel();
119               }
120             }
121           });
122 
123       mPseudoEmergencyColorAnimator.setDuration(VIBRATE_LENGTH_MILLIS);
124       mPseudoEmergencyColorAnimator.setRepeatMode(ValueAnimator.REVERSE);
125       mPseudoEmergencyColorAnimator.setRepeatCount(ANIMATION_ITERATION_COUNT);
126     }
127     if (!mPseudoEmergencyColorAnimator.isStarted()) {
128       mPseudoEmergencyColorAnimator.start();
129     }
130   }
131 
end()132   public void end() {
133     if (mPseudoEmergencyColorAnimator != null && mPseudoEmergencyColorAnimator.isStarted()) {
134       mPseudoEmergencyColorAnimator.end();
135     }
136   }
137 
getView()138   private View getView() {
139     return mViewProvider == null ? null : mViewProvider.getView();
140   }
141 
getContext()142   private Context getContext() {
143     View view = getView();
144     return view != null ? view.getContext() : null;
145   }
146 
vibrate(long milliseconds)147   private void vibrate(long milliseconds) {
148     Context context = getContext();
149     if (context != null) {
150       Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
151       if (vibrator != null) {
152         vibrator.vibrate(milliseconds);
153       }
154     }
155   }
156 
157   public interface ViewProvider {
158 
getView()159     View getView();
160   }
161 }
162