Improve anti-falsing on emergency dialer

Bug: 19841919
Change-Id: Iba453e50e1cebc507ab8cb2caa599e863b3910cc
diff --git a/res/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index a68f5de..acb7033 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -30,6 +30,7 @@
 
         <!-- FrameLayout -->
         <com.android.phone.EmergencyActionGroup
+                android:id="@+id/emergency_action_group"
                 android:layout_height="64dp"
                 android:layout_width="match_parent"
                 android:layout_marginTop="16dp"
diff --git a/src/com/android/phone/EmergencyActionGroup.java b/src/com/android/phone/EmergencyActionGroup.java
index 96adc5d..dbacbf8 100644
--- a/src/com/android/phone/EmergencyActionGroup.java
+++ b/src/com/android/phone/EmergencyActionGroup.java
@@ -30,6 +30,7 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
@@ -56,6 +57,10 @@
 
     private View mLastRevealed;
 
+    private MotionEvent mPendingTouchEvent;
+
+    private boolean mHiding;
+
     public EmergencyActionGroup(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
@@ -80,6 +85,36 @@
         mLaunchHint = findViewById(R.id.launch_hint);
     }
 
+    /**
+     * Called by the activity before a touch event is dispatched to the view hierarchy.
+     */
+    public void onPreTouchEvent(MotionEvent event) {
+        mPendingTouchEvent = event;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        boolean handled = super.dispatchTouchEvent(event);
+        if (mPendingTouchEvent == event && handled) {
+            mPendingTouchEvent = null;
+        }
+        return handled;
+    }
+
+    /**
+     * Called by the activity after a touch event is dispatched to the view hierarchy.
+     */
+    public void onPostTouchEvent(MotionEvent event) {
+        // Hide the confirmation button if a touch event was delivered to the activity but not to
+        // this view.
+        if (mPendingTouchEvent != null) {
+            hideTheButton();
+        }
+        mPendingTouchEvent = null;
+    }
+
+
+
     private void setupAssistActions() {
         int[] buttonIds = new int[] {R.id.action1, R.id.action2, R.id.action3};
 
@@ -173,6 +208,8 @@
 
     @Override
     public void onClick(View v) {
+        Intent intent = (Intent) v.getTag(R.id.tag_intent);
+
         switch (v.getId()) {
             case R.id.action1:
             case R.id.action2:
@@ -180,7 +217,9 @@
                 revealTheButton(v);
                 break;
             case R.id.selected_container:
-                getContext().startActivity((Intent) v.getTag(R.id.tag_intent));
+                if (!mHiding) {
+                    getContext().startActivity(intent);
+                }
                 break;
         }
     }
@@ -204,8 +243,11 @@
         mSelectedLabel.setText(((Button) v).getText());
         mSelectedContainer.setTag(R.id.tag_intent, v.getTag(R.id.tag_intent));
         mLastRevealed = v;
-        mSelectedContainer.postDelayed(mHideRunnable, HIDE_DELAY);
-        mSelectedContainer.postDelayed(mRippleRunnable, RIPPLE_PAUSE / 2);
+        postDelayed(mHideRunnable, HIDE_DELAY);
+        postDelayed(mRippleRunnable, RIPPLE_PAUSE / 2);
+
+        // Transfer focus from the originally clicked button to the expanded button.
+        mSelectedContainer.requestFocus();
     }
 
     private void animateHintText(View selectedView, View v, Animator reveal) {
@@ -220,6 +262,14 @@
     }
 
     private void hideTheButton() {
+        if (mHiding || mSelectedContainer.getVisibility() != VISIBLE) {
+            return;
+        }
+
+        mHiding = true;
+
+        removeCallbacks(mHideRunnable);
+
         View v = mLastRevealed;
         int centerX = v.getLeft() + v.getWidth() / 2;
         int centerY = v.getTop() + v.getHeight() / 2;
@@ -234,10 +284,16 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mSelectedContainer.setVisibility(INVISIBLE);
-                mSelectedContainer.removeCallbacks(mRippleRunnable);
+                removeCallbacks(mRippleRunnable);
+                mHiding = false;
             }
         });
         reveal.start();
+
+        // Transfer focus back to the originally clicked button.
+        if (mSelectedContainer.isFocused()) {
+            v.requestFocus();
+        }
     }
 
     private void startRipple() {
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 6995d89..b9597c1 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -40,6 +40,7 @@
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
@@ -115,6 +116,8 @@
     // Haptic feedback (vibration) for dialer key presses.
     private HapticFeedback mHaptic = new HapticFeedback();
 
+    private EmergencyActionGroup mEmergencyActionGroup;
+
     // close activity when screen turns off
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -239,6 +242,8 @@
         } catch (Resources.NotFoundException nfe) {
              Log.e(LOG_TAG, "Vibrate control bool missing.", nfe);
         }
+
+        mEmergencyActionGroup = (EmergencyActionGroup) findViewById(R.id.emergency_action_group);
     }
 
     @Override
@@ -340,6 +345,14 @@
     }
 
     @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        mEmergencyActionGroup.onPreTouchEvent(ev);
+        boolean handled = super.dispatchTouchEvent(ev);
+        mEmergencyActionGroup.onPostTouchEvent(ev);
+        return handled;
+    }
+
+    @Override
     public void onClick(View view) {
         switch (view.getId()) {
             case R.id.deleteButton: {