Adds secondary icons and intents to entries if they exist

Bug: 16206384
Change-Id: I759c842d3be6e7c7b28bc4ef52d2d3935dd7931c
diff --git a/res/layout/expanding_entry_card_item.xml b/res/layout/expanding_entry_card_item.xml
index dcf3b02..9195800 100644
--- a/res/layout/expanding_entry_card_item.xml
+++ b/res/layout/expanding_entry_card_item.xml
@@ -31,7 +31,8 @@
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
         android:layout_marginEnd="@dimen/expanding_entry_card_item_image_spacing"
-        android:scaleType="fitCenter" />
+        android:scaleType="fitCenter"
+        android:layout_marginTop="@dimen/expanding_entry_card_item_icon_margin_top" />
 
     <TextView
         android:id="@+id/header"
@@ -76,4 +77,15 @@
         android:layout_marginTop="@dimen/expanding_entry_card_item_text_icon_margin_top"
         android:layout_marginEnd="@dimen/expanding_entry_card_item_text_icon_margin_right" />
 
-</RelativeLayout>
\ No newline at end of file
+    <ImageView
+        android:id="@+id/icon_alternate"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:visibility="gone"
+        android:layout_marginEnd="@dimen/expanding_entry_card_item_alternate_icon_margin_end"
+        android:layout_marginTop="@dimen/expanding_entry_card_item_icon_margin_top"
+        android:layout_marginBottom="@dimen/expanding_entry_card_item_alternate_icon_margin_bottom" />
+
+</RelativeLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3f3f31c..877a68f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -183,6 +183,10 @@
     <dimen name="expanding_entry_card_item_sub_header_icon_margin_right">4dp</dimen>
     <dimen name="expanding_entry_card_item_sub_header_icon_margin_bottom">14dp</dimen>
 
+    <dimen name="expanding_entry_card_item_icon_margin_top">8dp</dimen>
+    <dimen name="expanding_entry_card_item_alternate_icon_margin_end">0dp</dimen>
+    <dimen name="expanding_entry_card_item_alternate_icon_margin_bottom">10dp</dimen>
+
     <dimen name="people_activity_card_elevation">2dp</dimen>
 
     <dimen name="expanding_entry_card_item_icon_height">24dp</dimen>
diff --git a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
index e3c8354..69b0d49 100644
--- a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
+++ b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
@@ -24,11 +24,13 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.ColorFilter;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.TouchDelegate;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -60,17 +62,23 @@
         private final String mText;
         private final Drawable mTextIcon;
         private final Intent mIntent;
+        private final Drawable mAlternateIcon;
+        private final Intent mAlternateIntent;
+        private final String mAlternateContentDescription;
         private final boolean mShouldApplyColor;
         private final boolean mIsEditable;
 
         public Entry(int viewId, Drawable icon, String header, String subHeader, String text,
-                Intent intent, boolean shouldApplyColor, boolean isEditable) {
-            this(viewId, icon, header, subHeader, null, text, null, intent, shouldApplyColor,
-                    isEditable);
+                Intent intent, Drawable alternateIcon, Intent alternateIntent,
+                String alternateContentDescription, boolean shouldApplyColor,
+                boolean isEditable) {
+            this(viewId, icon, header, subHeader, null, text, null, intent, alternateIcon,
+                    alternateIntent, alternateContentDescription, shouldApplyColor, isEditable);
         }
 
         public Entry(int viewId, Drawable mainIcon, String header, String subHeader,
                 Drawable subHeaderIcon, String text, Drawable textIcon, Intent intent,
+                Drawable alternateIcon, Intent alternateIntent, String alternateContentDescription,
                 boolean shouldApplyColor, boolean isEditable) {
             mViewId = viewId;
             mIcon = mainIcon;
@@ -80,6 +88,9 @@
             mText = text;
             mTextIcon = textIcon;
             mIntent = intent;
+            mAlternateIcon = alternateIcon;
+            mAlternateIntent = alternateIntent;
+            mAlternateContentDescription = alternateContentDescription;
             mShouldApplyColor = shouldApplyColor;
             mIsEditable = isEditable;
         }
@@ -112,6 +123,18 @@
             return mIntent;
         }
 
+        Drawable getAlternateIcon() {
+            return mAlternateIcon;
+        }
+
+        Intent getAlternateIntent() {
+            return mAlternateIntent;
+        }
+
+        String getAlternateContentDescription() {
+            return mAlternateContentDescription;
+        }
+
         boolean shouldApplyColor() {
             return mShouldApplyColor;
         }
@@ -397,6 +420,10 @@
                                 icon.setColorFilter(mThemeColorFilter);
                             }
                         }
+                        Drawable alternateIcon = entry.getAlternateIcon();
+                        if (alternateIcon != null) {
+                            alternateIcon.setColorFilter(mThemeColorFilter);
+                        }
                     }
                 }
             }
@@ -410,47 +437,47 @@
 
     // TODO add accessibility content descriptions
     private View createEntryView(LayoutInflater layoutInflater, Entry entry) {
-        View view = layoutInflater.inflate(
+        final View view = layoutInflater.inflate(
                 R.layout.expanding_entry_card_item, this, false);
 
         view.setId(entry.getViewId());
 
-        ImageView icon = (ImageView) view.findViewById(R.id.icon);
+        final ImageView icon = (ImageView) view.findViewById(R.id.icon);
         if (entry.getIcon() != null) {
             icon.setImageDrawable(entry.getIcon());
         } else {
             icon.setVisibility(View.GONE);
         }
 
-        TextView header = (TextView) view.findViewById(R.id.header);
+        final TextView header = (TextView) view.findViewById(R.id.header);
         if (entry.getHeader() != null) {
             header.setText(entry.getHeader());
         } else {
             header.setVisibility(View.GONE);
         }
 
-        TextView subHeader = (TextView) view.findViewById(R.id.sub_header);
+        final TextView subHeader = (TextView) view.findViewById(R.id.sub_header);
         if (entry.getSubHeader() != null) {
             subHeader.setText(entry.getSubHeader());
         } else {
             subHeader.setVisibility(View.GONE);
         }
 
-        ImageView subHeaderIcon = (ImageView) view.findViewById(R.id.icon_sub_header);
+        final ImageView subHeaderIcon = (ImageView) view.findViewById(R.id.icon_sub_header);
         if (entry.getSubHeaderIcon() != null) {
             subHeaderIcon.setImageDrawable(entry.getSubHeaderIcon());
         } else {
             subHeaderIcon.setVisibility(View.GONE);
         }
 
-        TextView text = (TextView) view.findViewById(R.id.text);
+        final TextView text = (TextView) view.findViewById(R.id.text);
         if (entry.getText() != null) {
             text.setText(entry.getText());
         } else {
             text.setVisibility(View.GONE);
         }
 
-        ImageView textIcon = (ImageView) view.findViewById(R.id.icon_text);
+        final ImageView textIcon = (ImageView) view.findViewById(R.id.icon_text);
         if (entry.getTextIcon() != null) {
             textIcon.setImageDrawable(entry.getTextIcon());
         } else {
@@ -462,6 +489,35 @@
             view.setTag(entry.getIntent());
         }
 
+        final ImageView alternateIcon = (ImageView) view.findViewById(R.id.icon_alternate);
+        if (entry.getAlternateIcon() != null && entry.getAlternateIntent() != null) {
+            alternateIcon.setImageDrawable(entry.getAlternateIcon());
+            alternateIcon.setOnClickListener(mOnClickListener);
+            alternateIcon.setTag(entry.getAlternateIntent());
+            alternateIcon.setId(entry.getViewId());
+            alternateIcon.setVisibility(View.VISIBLE);
+            alternateIcon.setContentDescription(entry.getAlternateContentDescription());
+
+            // Expand the clickable area for alternate icon to be top to bottom and to right edge
+            // of the entry view
+            view.post(new Runnable() {
+                @Override
+                public void run() {
+                    final Rect entryRect = new Rect();
+                    view.getHitRect(entryRect);
+
+                    final Rect alternateIconRect = new Rect();
+                    alternateIcon.getHitRect(alternateIconRect);
+                    alternateIconRect.right = entryRect.right;
+                    alternateIconRect.bottom = entryRect.bottom;
+                    alternateIconRect.top = entryRect.top;
+                    final TouchDelegate touchDelegate =
+                            new TouchDelegate(alternateIconRect, alternateIcon);
+                    view.setTouchDelegate(touchDelegate);
+                }
+            });
+        }
+
         return view;
     }
 
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 1868d87..6548b7c 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -31,6 +31,8 @@
 import android.content.ContentValues;
 import android.content.Intent;
 import android.content.Loader;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
@@ -127,7 +129,6 @@
 import com.android.contacts.util.StructuredPostalUtils;
 import com.android.contacts.widget.MultiShrinkScroller;
 import com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener;
-
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
@@ -162,7 +163,6 @@
     private static final int ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION = 150;
     private static final int REQUEST_CODE_CONTACT_EDITOR_ACTIVITY = 1;
     private static final int SCRIM_COLOR = Color.argb(0xB2, 0, 0, 0);
-    private static final String SCHEME_SMSTO = "smsto";
     private static final String MIMETYPE_SMS = "vnd.android-dir/mms-sms";
 
     /** This is the Intent action to install a shortcut in the launcher. */
@@ -210,7 +210,6 @@
     private boolean mIsWaitingForOtherPieceOfExitAnimation;
     private boolean mIsExitAnimationInProgress;
     private boolean mHasComputedThemeColor;
-    private ComponentName mSmsComponent;
 
     private Contact mContactData;
     private ContactLoader mContactLoader;
@@ -299,7 +298,7 @@
             String usageType = DataUsageFeedback.USAGE_TYPE_CALL;
 
             final String scheme = intent.getData().getScheme();
-            if ((scheme != null && scheme.equals(SCHEME_SMSTO)) ||
+            if ((scheme != null && scheme.equals(CallUtil.SCHEME_SMSTO)) ||
                     (intent.getType() != null && intent.getType().equals(MIMETYPE_SMS))) {
                 usageType = DataUsageFeedback.USAGE_TYPE_SHORT_TEXT;
             }
@@ -502,8 +501,6 @@
 
         setContentView(R.layout.quickcontact_activity);
 
-        mSmsComponent = PhoneCapabilityTester.getSmsComponent(this);
-
         mContactCard = (ExpandingEntryCardView) findViewById(R.id.communication_card);
         mNoContactDetailsCard = (ExpandingEntryCardView) findViewById(R.id.no_contact_data_card);
         mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card);
@@ -852,15 +849,18 @@
                 R.drawable.ic_phone_24dp).mutate();
         final Entry phonePromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
                 phoneIcon, getString(R.string.quickcontact_add_phone_number),
-                /* subHeader = */ null, /* text = */ null,
-                getEditContactIntent(), /* shouldApplyColor = */ false, /* isEditable = */ false);
+                /* subHeader = */ null, /* text = */ null, getEditContactIntent(),
+                /* alternateIcon = */ null, /* alternateIntent = */ null,
+                /* alternateContentDescription = */ null, /* shouldApplyColor = */ false,
+                /* isEditable = */ false);
 
         final Drawable emailIcon = getResources().getDrawable(
                 R.drawable.ic_email_24dp).mutate();
         final Entry emailPromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
                 emailIcon, getString(R.string.quickcontact_add_email), /* subHeader = */ null,
-                /* text = */ null, getEditContactIntent(), /* shouldApplyColor = */ false,
-                /* isEditable = */ false);
+                /* text = */ null, getEditContactIntent(), /* alternateIcon = */ null,
+                /* alternateIntent = */ null, /* alternateContentDescription = */ null,
+                /* shouldApplyColor = */ false, /* isEditable = */ false);
 
         final List<List<Entry>> promptEntries = new ArrayList<>();
         promptEntries.add(new ArrayList<Entry>(1));
@@ -963,6 +963,9 @@
         Drawable textIcon = null;
         Intent intent = null;
         boolean shouldApplyColor = true;
+        Drawable alternateIcon = null;
+        Intent alternateIntent = null;
+        String alternateContentDescription = null;
         final boolean isEditable = false;
 
         DataKind kind = dataItem.getDataKind();
@@ -1052,6 +1055,10 @@
                 if (PhoneCapabilityTester.isPhone(this)) {
                     intent = CallUtil.getCallIntent(phone.getNumber());
                 }
+                alternateIntent = new Intent(Intent.ACTION_SENDTO,
+                        Uri.fromParts(CallUtil.SCHEME_SMSTO, phone.getNumber(), null));
+                alternateIcon = getResources().getDrawable(R.drawable.ic_message_24dp);
+                alternateContentDescription = getResources().getString(R.string.sms_other);
             }
         } else if (dataItem instanceof EmailDataItem) {
             final EmailDataItem email = (EmailDataItem) dataItem;
@@ -1154,6 +1161,18 @@
             }
         }
 
+        if (alternateIntent != null) {
+            // Do not set the alternate intent is there are no resolves
+            if (!PhoneCapabilityTester.isIntentRegistered(this, alternateIntent)) {
+                alternateIntent = null;
+            }
+
+            // Attempt to use package manager to find a suitable content description if needed
+            if (TextUtils.isEmpty(alternateContentDescription)) {
+                alternateContentDescription = getIntentResolveLabel(alternateIntent);
+            }
+        }
+
         // If the Entry has no visual elements, return null
         if (icon == null && TextUtils.isEmpty(header) && TextUtils.isEmpty(subHeader) &&
                 subHeaderIcon == null && TextUtils.isEmpty(text) && textIcon == null) {
@@ -1163,8 +1182,9 @@
         final int dataId = dataItem.getId() > Integer.MAX_VALUE ?
                 -1 : (int) dataItem.getId();
 
-        return new Entry(dataId, icon, header, subHeader, subHeaderIcon, text, textIcon,
-                intent, shouldApplyColor, isEditable);
+        return new Entry(dataId, icon, header, subHeader, subHeaderIcon, text, textIcon, intent,
+                alternateIcon, alternateIntent, alternateContentDescription, shouldApplyColor,
+                isEditable);
     }
 
     private List<Entry> dataItemsToEntries(List<DataItem> dataItems) {
@@ -1174,31 +1194,30 @@
             if (entry != null) {
                 entries.add(entry);
             }
-            // TODO merge secondary intents
-            if (dataItem instanceof PhoneDataItem) {
-                final PhoneDataItem phone = (PhoneDataItem) dataItem;
-                Intent smsIntent = null;
-                if (mSmsComponent != null) {
-                    smsIntent = new Intent(Intent.ACTION_SENDTO,
-                            Uri.fromParts(CallUtil.SCHEME_SMSTO, phone.getNumber(), null));
-                    smsIntent.setComponent(mSmsComponent);
-                }
-                final int dataId = dataItem.getId() > Integer.MAX_VALUE ?
-                        -1 : (int) dataItem.getId();
-                entries.add(new Entry(dataId,
-                        getResources().getDrawable(R.drawable.ic_message_24dp),
-                        getResources().getString(R.string.send_message),
-                        /* subHeader = */ null,
-                        /* text = */ phone.buildDataString(this,
-                                dataItem.getDataKind()),
-                        smsIntent,
-                        /* shouldApplyColor = */ true,
-                        /* isEditable = */ false));
-            }
         }
         return entries;
     }
 
+    private String getIntentResolveLabel(Intent intent) {
+        final List<ResolveInfo> matches = getPackageManager().queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY);
+
+        // Pick first match, otherwise best found
+        ResolveInfo bestResolve = null;
+        final int size = matches.size();
+        if (size == 1) {
+            bestResolve = matches.get(0);
+        } else if (size > 1) {
+            bestResolve = ResolveCache.getInstance(this).getBestResolve(intent, matches);
+        }
+
+        if (bestResolve == null) {
+            return null;
+        }
+
+        return String.valueOf(bestResolve.loadLabel(getPackageManager()));
+    }
+
     /**
      * Asynchronously extract the most vibrant color from the PhotoView. Once extracted,
      * apply this tint to {@link MultiShrinkScroller}. This operation takes about 20-30ms
@@ -1330,6 +1349,9 @@
                     interaction.getViewFooter(this),
                     interaction.getFooterIcon(this),
                     interaction.getIntent(),
+                    /* alternateIcon = */ null,
+                    /* alternateIntent = */ null,
+                    /* alternateContentDescription = */ null,
                     /* shouldApplyColor = */ true,
                     /* isEditable = */ false));
         }