"Emergency" dialpad behavior.

Change-Id: I132a119238c8de7249a4944e6dda472b3851637e
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index aefe01f..47e5234 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -1080,6 +1080,15 @@
             }
             mSearchView.setText(normalizedQuery);
         }
+
+        try {
+            if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
+                mDialpadFragment.process_quote_emergency_unquote(normalizedQuery);
+            }
+        } catch (Exception ignored) {
+            // Skip any exceptions for this piece of code
+        }
+
     }
 
     @Override
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 89cab41..766175c 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -22,7 +22,6 @@
 import android.app.DialogFragment;
 import android.app.Fragment;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -68,7 +67,6 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
-import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.GeoUtil;
 import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.common.util.PhoneNumberFormatter;
@@ -79,14 +77,13 @@
 import com.android.dialer.R;
 import com.android.dialer.SpecialCharSequenceMgr;
 import com.android.dialer.calllog.PhoneAccountUtils;
-import com.android.dialer.util.IntentUtil;
 import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.IntentUtil;
 import com.android.phone.common.CallLogAsync;
 import com.android.phone.common.HapticFeedback;
 import com.android.phone.common.animation.AnimUtils;
 import com.android.phone.common.dialpad.DialpadKeyButton;
 import com.android.phone.common.dialpad.DialpadView;
-
 import com.google.common.annotations.VisibleForTesting;
 
 import java.util.HashSet;
@@ -157,6 +154,7 @@
     /** Stream type used to play the DTMF tones off call, and mapped to the volume control keys */
     private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_DTMF;
 
+
     private OnDialpadQueryChangedListener mDialpadQueryListener;
 
     private DialpadView mDialpadView;
@@ -188,6 +186,7 @@
      */
     private String mProhibitedPhoneNumberRegexp;
 
+    private PseudoEmergencyAnimator mPseudoEmergencyAnimator;
 
     // Last number dialed, retrieved asynchronously from the call DB
     // in onCreate. This number is displayed when the user hits the
@@ -307,6 +306,7 @@
         if (mDialpadQueryListener != null) {
             mDialpadQueryListener.onDialpadQueryChanged(mDigits.getText().toString());
         }
+
         updateDeleteButtonEnabledState();
     }
 
@@ -722,6 +722,10 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        if (mPseudoEmergencyAnimator != null) {
+            mPseudoEmergencyAnimator.destroy();
+            mPseudoEmergencyAnimator = null;
+        }
         ((Context) getActivity()).unregisterReceiver(mCallStateReceiver);
     }
 
@@ -1659,4 +1663,24 @@
     public void setYFraction(float yFraction) {
         ((DialpadSlidingRelativeLayout) getView()).setYFraction(yFraction);
     }
+
+    public void process_quote_emergency_unquote(String query) {
+        if (PseudoEmergencyAnimator.PSEUDO_EMERGENCY_NUMBER.equals(query)) {
+            if (mPseudoEmergencyAnimator == null) {
+                mPseudoEmergencyAnimator = new PseudoEmergencyAnimator(
+                        new PseudoEmergencyAnimator.ViewProvider() {
+                            @Override
+                            public View getView() {
+                                return DialpadFragment.this.getView();
+                            }
+                        });
+            }
+            mPseudoEmergencyAnimator.start();
+        } else {
+            if (mPseudoEmergencyAnimator != null) {
+                mPseudoEmergencyAnimator.end();
+            }
+        }
+    }
+
 }
diff --git a/src/com/android/dialer/dialpad/PseudoEmergencyAnimator.java b/src/com/android/dialer/dialpad/PseudoEmergencyAnimator.java
new file mode 100644
index 0000000..d4f32b5
--- /dev/null
+++ b/src/com/android/dialer/dialpad/PseudoEmergencyAnimator.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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.dialer.dialpad;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
+import android.os.Handler;
+import android.os.Vibrator;
+import android.view.View;
+
+import com.android.dialer.R;
+
+/**
+ * Animates the dial button on "emergency" phone numbers.
+ */
+public class PseudoEmergencyAnimator {
+    public interface ViewProvider {
+        View getView();
+    }
+
+    public static final String PSEUDO_EMERGENCY_NUMBER = "01189998819991197253";
+
+    private static final int VIBRATE_LENGTH_MILLIS = 200;
+    private static final int ITERATION_LENGTH_MILLIS = 1000;
+    private static final int ANIMATION_ITERATION_COUNT = 6;
+
+    private ViewProvider mViewProvider;
+    private ValueAnimator mPseudoEmergencyColorAnimator;
+
+    PseudoEmergencyAnimator(ViewProvider viewProvider) {
+        mViewProvider = viewProvider;
+    }
+
+    public void destroy() {
+        end();
+        mViewProvider = null;
+    }
+
+    public void start() {
+        if (mPseudoEmergencyColorAnimator == null) {
+            Integer colorFrom = Color.BLUE;
+            Integer colorTo = Color.RED;
+            mPseudoEmergencyColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
+
+            mPseudoEmergencyColorAnimator.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animator) {
+                    try {
+                        int color = (int) animator.getAnimatedValue();
+                        ColorFilter colorFilter =
+                                new LightingColorFilter(Color.BLACK, color);
+
+                        View floatingActionButtonContainer = getView().findViewById(
+                                R.id.dialpad_floating_action_button_container);
+                        if (floatingActionButtonContainer != null) {
+                            floatingActionButtonContainer.getBackground().setColorFilter(
+                                    colorFilter);
+                        }
+                    } catch (Exception e) {
+                        animator.cancel();
+                    }
+                }
+            });
+
+            mPseudoEmergencyColorAnimator.addListener(new AnimatorListener() {
+                @Override
+                public void onAnimationCancel(Animator animation) { }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                    try {
+                        vibrate(VIBRATE_LENGTH_MILLIS);
+                    } catch (Exception e) {
+                        animation.cancel();
+                    }
+                }
+
+                @Override
+                public void onAnimationStart(Animator animation) { }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    try {
+                        View floatingActionButtonContainer = getView().findViewById(
+                                R.id.dialpad_floating_action_button_container);
+                        if (floatingActionButtonContainer != null) {
+                            floatingActionButtonContainer.getBackground().clearColorFilter();
+                        }
+
+                        new Handler().postDelayed(new Runnable() {
+                            @Override public void run() {
+                                try {
+                                    vibrate(VIBRATE_LENGTH_MILLIS);
+                                } catch (Exception e) {
+                                    // ignored
+                                }
+                            }
+                        }, ITERATION_LENGTH_MILLIS);
+                    } catch (Exception e) {
+                        animation.cancel();
+                    }
+                }
+            });
+
+            mPseudoEmergencyColorAnimator.setDuration(VIBRATE_LENGTH_MILLIS);
+            mPseudoEmergencyColorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+            mPseudoEmergencyColorAnimator.setRepeatCount(ANIMATION_ITERATION_COUNT);
+        }
+        if (!mPseudoEmergencyColorAnimator.isStarted()) {
+            mPseudoEmergencyColorAnimator.start();
+        }
+    }
+
+    public void end() {
+        if (mPseudoEmergencyColorAnimator != null && mPseudoEmergencyColorAnimator.isStarted()) {
+            mPseudoEmergencyColorAnimator.end();
+        }
+    }
+
+    private View getView() {
+        return mViewProvider == null ? null : mViewProvider.getView();
+    }
+
+    private Context getContext() {
+        View view = getView();
+        return view != null ? view.getContext() : null;
+    }
+
+    private void vibrate(long milliseconds) {
+        Context context = getContext();
+        if (context != null) {
+            Vibrator vibrator =
+                    (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+            if (vibrator != null) {
+                vibrator.vibrate(milliseconds);
+            }
+        }
+    }
+}