Merge "Minor UI tweak" into lmp-mr1-dev
diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java
index 0bfcc80..5c67862 100644
--- a/InCallUI/src/com/android/incallui/CallButtonFragment.java
+++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.telecom.AudioState;
 import android.view.ContextThemeWrapper;
+import android.view.HapticFeedbackConstants;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -152,6 +153,7 @@
         int id = view.getId();
         Log.d(this, "onClick(View " + view + ", id " + id + ")...");
 
+        boolean isClickHandled = true;
         switch(id) {
             case R.id.audioButton:
                 onAudioButtonClicked();
@@ -197,9 +199,16 @@
                 mOverflowPopup.show();
                 break;
             default:
+                isClickHandled = false;
                 Log.wtf(this, "onClick: unexpected");
                 break;
         }
+
+        if (isClickHandled) {
+            view.performHapticFeedback(
+                    HapticFeedbackConstants.VIRTUAL_KEY,
+                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+        }
     }
 
     public void updateColors() {
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 9d11b4c..c70bd6e 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Point;
+import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.telecom.DisconnectCause;
@@ -48,6 +49,7 @@
 import android.widget.TextView;
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
 import com.android.contacts.common.widget.FloatingActionButtonController;
+import com.android.incallui.service.PhoneNumberService;
 import com.android.phone.common.animation.AnimUtils;
 
 import java.util.List;
@@ -373,7 +375,9 @@
         if (TextUtils.isEmpty(name)) {
             mPrimaryName.setText(null);
         } else {
-            mPrimaryName.setText(name);
+            mPrimaryName.setText(nameIsNumber
+                    ? PhoneNumberUtils.ttsSpanAsPhoneNumber(name)
+                    : name);
 
             // Set direction of the name field
             int nameDirection = View.TEXT_DIRECTION_INHERIT;
@@ -398,7 +402,7 @@
             mPhoneNumber.setText(null);
             mPhoneNumber.setVisibility(View.GONE);
         } else {
-            mPhoneNumber.setText(number);
+            mPhoneNumber.setText(PhoneNumberUtils.ttsSpanAsPhoneNumber(number));
             mPhoneNumber.setVisibility(View.VISIBLE);
             mPhoneNumber.setTextDirection(View.TEXT_DIRECTION_LTR);
         }
@@ -455,7 +459,9 @@
 
             mSecondaryCallConferenceCallIcon.setVisibility(isConference ? View.VISIBLE : View.GONE);
 
-            mSecondaryCallName.setText(name);
+            mSecondaryCallName.setText(nameIsNumber
+                    ? PhoneNumberUtils.ttsSpanAsPhoneNumber(name)
+                    : name);
             if (hasProvider) {
                 mSecondaryCallProviderLabel.setText(providerLabel);
             }
@@ -526,6 +532,10 @@
             } else {
                 mCallStateIcon.startAnimation(mPulseAnimation);
             }
+
+            if (callStateIcon instanceof AnimationDrawable) {
+                ((AnimationDrawable) callStateIcon).start();
+            }
         } else {
             Animation callStateIconAnimation = mCallStateIcon.getAnimation();
             if (callStateIconAnimation != null) {
diff --git a/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java b/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java
index 0d59772..7825dc1 100644
--- a/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java
+++ b/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -417,7 +418,7 @@
             numberTypeTextView.setVisibility(View.GONE);
         } else {
             numberTextView.setVisibility(View.VISIBLE);
-            numberTextView.setText(callerNumber);
+            numberTextView.setText(PhoneNumberUtils.ttsSpanAsPhoneNumber(callerNumber));
             numberTypeTextView.setVisibility(View.VISIBLE);
             numberTypeTextView.setText(callerNumberType);
         }
diff --git a/InCallUI/src/com/android/incallui/DialpadFragment.java b/InCallUI/src/com/android/incallui/DialpadFragment.java
index 63f6379..da3f0cb 100644
--- a/InCallUI/src/com/android/incallui/DialpadFragment.java
+++ b/InCallUI/src/com/android/incallui/DialpadFragment.java
@@ -20,6 +20,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.telephony.PhoneNumberUtils;
 import android.text.Editable;
 import android.text.method.DialerKeyListener;
 import android.util.AttributeSet;
@@ -513,7 +514,7 @@
      * @param text Text to set Dialpad EditText to.
      */
     public void setDtmfText(String text) {
-        mDtmfDialerField.setText(text);
+        mDtmfDialerField.setText(PhoneNumberUtils.ttsSpanAsPhoneNumber(text));
     }
 
     @Override
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 0069364..f75c33b 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -330,6 +330,13 @@
             return;
         }
 
+        // Always disable the Back key while an incoming call is ringing
+        final Call call = CallList.getInstance().getIncomingCall();
+        if (call != null) {
+            Log.d(this, "Consume Back press for an incoming call");
+            return;
+        }
+
         // Nothing special to do.  Fall back to the default behavior.
         super.onBackPressed();
     }
@@ -512,20 +519,10 @@
                         intent.getBooleanExtra(SHOW_CIRCULAR_REVEAL_EXTRA, false);
                 mCallCardFragment.animateForNewOutgoingCall(touchPoint, showCircularReveal);
 
-                /*
-                 * If both a phone account handle and a list of phone accounts to choose from are
-                 * missing, then disconnect the call because there is no way to place an outgoing
-                 * call.
-                 * The exception is emergency calls, which may be waiting for the ConnectionService
-                 * to set the PhoneAccount during the PENDING_OUTGOING state.
-                 */
-                if (call != null && !isEmergencyCall(call)) {
-                    final List<PhoneAccountHandle> phoneAccountHandles = extras
-                            .getParcelableArrayList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS);
-                    if (call.getAccountHandle() == null &&
-                            (phoneAccountHandles == null || phoneAccountHandles.isEmpty())) {
-                        TelecomAdapter.getInstance().disconnectCall(call.getId());
-                    }
+                // InCallActivity is responsible for disconnecting a new outgoing call if there
+                // is no way of making it (i.e. no valid call capable accounts)
+                if (InCallPresenter.isCallWithNoValidAccounts(call)) {
+                    TelecomAdapter.getInstance().disconnectCall(call.getId());
                 }
 
                 dismissKeyguard(true);
@@ -569,14 +566,6 @@
         }
     }
 
-    private boolean isEmergencyCall(Call call) {
-        final Uri handle = call.getHandle();
-        if (handle == null) {
-            return false;
-        }
-        return PhoneNumberUtils.isEmergencyNumber(handle.getSchemeSpecificPart());
-    }
-
     private void relaunchedFromDialer(boolean showDialpad) {
         mShowDialpadRequested = showDialpad;
         mAnimateDialpadOnShow = true;
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 0004d46..dc41d41 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.graphics.Point;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.telecom.DisconnectCause;
@@ -29,6 +30,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
+import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.view.Surface;
 import android.view.View;
@@ -60,6 +62,8 @@
     private static final String EXTRA_FIRST_TIME_SHOWN =
             "com.android.incallui.intent.extra.FIRST_TIME_SHOWN";
 
+    private static final Bundle EMPTY_EXTRAS = new Bundle();
+
     private static InCallPresenter sInCallPresenter;
 
     /**
@@ -258,7 +262,12 @@
 
     private void attemptFinishActivity() {
         mWaitForRevealAnimationStart = false;
-        CircularRevealActivity.sendClearDisplayBroadcast(mContext);
+
+        Context context = mContext != null ? mContext : mInCallActivity;
+        if (context != null) {
+            CircularRevealActivity.sendClearDisplayBroadcast(context);
+        }
+
         final boolean doFinish = (mInCallActivity != null && isActivityStarted());
         Log.i(this, "Hide in call UI: " + doFinish);
         if (doFinish) {
@@ -926,6 +935,17 @@
         showCallUi |= (InCallState.PENDING_OUTGOING == mInCallState
                 && InCallState.INCALL == newState && !isActivityStarted());
 
+        // Another exception - InCallActivity is in charge of disconnecting a call with no
+        // valid accounts set. Bring the UI up if this is true for the current pending outgoing
+        // call so that:
+        // 1) The call can be disconnected correctly
+        // 2) The UI comes up and correctly displays the error dialog.
+        // TODO: Remove these special case conditions by making InCallPresenter a true state
+        // machine. Telecom should also be the component responsible for disconnecting a call
+        // with no valid accounts.
+        showCallUi |= InCallState.PENDING_OUTGOING == newState && mainUiNotVisible
+                && isCallWithNoValidAccounts(CallList.getInstance().getPendingOutgoingCall());
+
         // The only time that we have an instance of mInCallActivity and it isn't started is
         // when it is being destroyed.  In that case, lets avoid bringing up another instance of
         // the activity.  When it is finally destroyed, we double check if we should bring it back
@@ -963,6 +983,43 @@
     }
 
     /**
+     * Determines whether or not a call has no valid phone accounts that can be used to make the
+     * call with. Emergency calls do not require a phone account.
+     *
+     * @param call to check accounts for.
+     * @return {@code true} if the call has no call capable phone accounts set, {@code false} if
+     * the call contains a phone account that could be used to initiate it with, or is an emergency
+     * call.
+     */
+    public static boolean isCallWithNoValidAccounts(Call call) {
+        if (call != null && !isEmergencyCall(call)) {
+            Bundle extras = call.getTelecommCall().getDetails().getExtras();
+
+            if (extras == null) {
+                extras = EMPTY_EXTRAS;
+            }
+
+            final List<PhoneAccountHandle> phoneAccountHandles = extras
+                    .getParcelableArrayList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS);
+
+            if ((call.getAccountHandle() == null &&
+                    (phoneAccountHandles == null || phoneAccountHandles.isEmpty()))) {
+                Log.i(InCallPresenter.getInstance(), "No valid accounts for call " + call);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isEmergencyCall(Call call) {
+        final Uri handle = call.getHandle();
+        if (handle == null) {
+            return false;
+        }
+        return PhoneNumberUtils.isEmergencyNumber(handle.getSchemeSpecificPart());
+    }
+
+    /**
      * Sets the DisconnectCause for a call that was disconnected because it was missing a
      * PhoneAccount or PhoneAccounts to select from.
      * @param call