Merge "Use custom ViewOutlineProvider to enable shadows" into lmp-dev
diff --git a/res/layout/expanding_entry_card_item.xml b/res/layout/expanding_entry_card_item.xml
index 16571a7..138a3a5 100644
--- a/res/layout/expanding_entry_card_item.xml
+++ b/res/layout/expanding_entry_card_item.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<RelativeLayout
+<view
+    class="com.android.contacts.quickcontact.ExpandingEntryCardView$EntryView"
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/SelectableItem"
     android:layout_width="match_parent"
@@ -93,4 +94,4 @@
         android:layout_marginTop="@dimen/expanding_entry_card_item_icon_margin_top"
         android:layout_marginBottom="@dimen/expanding_entry_card_item_alternate_icon_margin_bottom" />
 
-</RelativeLayout>
+</view>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 8f6e022..84ecea0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -24,18 +24,17 @@
 
     <color name="background_social_updates">#ffeeeeee</color>
 
-    <!-- Color of the background of the action bar -->
-    <color name="action_bar_background">#e6e6e6</color>
-
-    <!-- Color used for system bar and navigation bar. -->
-    <color name="primary_dark">#008aa1</color>
-
-    <!-- Color of the background of the action bar when highlighted (ie. pressed, focused) -->
+    <!-- TODO: remove these colors once we delete the group code (b/16522929) -->
+    <color name="action_bar_background">#0288d1</color>
     <color name="action_bar_background_highlight">#cecece</color>
-
-    <!-- Color of the text for buttons in the action bar  -->
     <color name="action_bar_button_text_color">#FFFFFF</color>
 
+    <color name="actionbar_background_color">@color/primary_color</color>
+    <color name="actionbar_background_color_dark">@color/primary_color_dark</color>
+
+    <color name="primary_color_dark">#0277bd</color>
+    <color name="primary_color">#0288d1</color>
+
     <!-- Color of the selected tab underline (overriding value in ContactsCommon) -->
     <color name="contacts_accent_color">#00acc1</color>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 37d0c94..12fafbc 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -64,8 +64,8 @@
         <item name="android:icon">@android:color/transparent</item>
         <item name="android:listViewStyle">@style/ListViewStyle</item>
         <item name="android:windowBackground">@color/background_primary</item>
-        <item name="android:colorPrimaryDark">@color/primary_dark</item>
-        <item name="android:colorPrimary">@color/actionbar_background_color</item>
+        <item name="android:colorPrimaryDark">@color/primary_color_dark</item>
+        <item name="android:colorPrimary">@color/primary_color</item>
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
         <item name="section_header_background">@drawable/list_title_holo</item>
diff --git a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
index 49a2b85..a536f8c 100644
--- a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
+++ b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
@@ -33,9 +33,11 @@
 import android.transition.TransitionSet;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.LayoutInflater;
 import android.view.TouchDelegate;
 import android.view.View;
+import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -78,19 +80,22 @@
         private final String mAlternateContentDescription;
         private final boolean mShouldApplyColor;
         private final boolean mIsEditable;
+        private final EntryContextMenuInfo mEntryContextMenuInfo;
 
         public Entry(int viewId, Drawable icon, String header, String subHeader, String text,
                 Intent intent, Drawable alternateIcon, Intent alternateIntent,
                 String alternateContentDescription, boolean shouldApplyColor,
-                boolean isEditable) {
+                boolean isEditable, EntryContextMenuInfo entryContextMenuInfo) {
             this(viewId, icon, header, subHeader, null, text, null, intent, alternateIcon,
-                    alternateIntent, alternateContentDescription, shouldApplyColor, isEditable);
+                    alternateIntent, alternateContentDescription, shouldApplyColor, isEditable,
+                    entryContextMenuInfo);
         }
 
         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) {
+                boolean shouldApplyColor, boolean isEditable,
+                EntryContextMenuInfo entryContextMenuInfo) {
             mViewId = viewId;
             mIcon = mainIcon;
             mHeader = header;
@@ -104,6 +109,7 @@
             mAlternateContentDescription = alternateContentDescription;
             mShouldApplyColor = shouldApplyColor;
             mIsEditable = isEditable;
+            mEntryContextMenuInfo = entryContextMenuInfo;
         }
 
         Drawable getIcon() {
@@ -157,6 +163,10 @@
         int getViewId() {
             return mViewId;
         }
+
+        EntryContextMenuInfo getEntryContextMenuInfo() {
+            return mEntryContextMenuInfo;
+        }
     }
 
     public interface ExpandingEntryCardViewListener {
@@ -170,6 +180,7 @@
     private CharSequence mExpandButtonText;
     private CharSequence mCollapseButtonText;
     private OnClickListener mOnClickListener;
+    private OnCreateContextMenuListener mOnCreateContextMenuListener;
     private boolean mIsExpanded = false;
     private int mCollapsedEntriesCount;
     private ExpandingEntryCardViewListener mListener;
@@ -292,6 +303,11 @@
         mOnClickListener = listener;
     }
 
+    @Override
+    public void setOnCreateContextMenuListener (OnCreateContextMenuListener listener) {
+        mOnCreateContextMenuListener = listener;
+    }
+
     private void insertEntriesIntoViewGroup() {
         mEntriesViewGroup.removeAllViews();
 
@@ -469,10 +485,12 @@
         }
     }
 
-    private View createEntryView(LayoutInflater layoutInflater, Entry entry, int iconVisibility) {
-        final View view = layoutInflater.inflate(
+    private View createEntryView(LayoutInflater layoutInflater, final Entry entry,
+            int iconVisibility) {
+        final EntryView view = (EntryView) layoutInflater.inflate(
                 R.layout.expanding_entry_card_item, this, false);
 
+        view.setContextMenuInfo(entry.getEntryContextMenuInfo());
         view.setId(entry.getViewId());
 
         final ImageView icon = (ImageView) view.findViewById(R.id.icon);
@@ -570,6 +588,9 @@
                     view.getPaddingBottom());
         }
 
+
+        view.setOnCreateContextMenuListener(mOnCreateContextMenuListener);
+
         return view;
     }
 
@@ -748,4 +769,43 @@
     public boolean shouldShow() {
         return mEntries != null && mEntries.size() > 0;
     }
+
+    public static final class EntryView extends RelativeLayout {
+        private EntryContextMenuInfo mEntryContextMenuInfo;
+
+        public EntryView(Context context) {
+            super(context);
+        }
+
+        public EntryView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public void setContextMenuInfo(EntryContextMenuInfo info) {
+            mEntryContextMenuInfo = info;
+        }
+
+        @Override
+        protected ContextMenuInfo getContextMenuInfo() {
+            return mEntryContextMenuInfo;
+        }
+    }
+
+    public static final class EntryContextMenuInfo implements ContextMenuInfo {
+        private final String mCopyText;
+        private final String mCopyLabel;
+
+        public EntryContextMenuInfo(String copyText, String copyLabel) {
+            mCopyText = copyText;
+            mCopyLabel = copyLabel;
+        }
+
+        public String getCopyText() {
+            return mCopyText;
+        }
+
+        public String getCopyLabel() {
+            return mCopyLabel;
+        }
+    }
 }
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index e168f2b..f5d4951 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -70,11 +70,14 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.View.OnCreateContextMenuListener;
 import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -86,6 +89,7 @@
 import com.android.contacts.NfcHandler;
 import com.android.contacts.R;
 import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.ClipboardUtils;
 import com.android.contacts.common.Collapser;
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.editor.SelectAccountDialogFragment;
@@ -123,6 +127,7 @@
 import com.android.contacts.interactions.ContactInteraction;
 import com.android.contacts.interactions.SmsInteractionsLoader;
 import com.android.contacts.quickcontact.ExpandingEntryCardView.Entry;
+import com.android.contacts.quickcontact.ExpandingEntryCardView.EntryContextMenuInfo;
 import com.android.contacts.quickcontact.ExpandingEntryCardView.ExpandingEntryCardViewListener;
 import com.android.contacts.util.ImageViewDrawableSetter;
 import com.android.contacts.util.PhoneCapabilityTester;
@@ -338,6 +343,33 @@
         }
     };
 
+    private final OnCreateContextMenuListener mEntryContextMenuListener =
+            new OnCreateContextMenuListener() {
+        @Override
+        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+            if (menuInfo == null) {
+                return;
+            }
+            EntryContextMenuInfo info = (EntryContextMenuInfo) menuInfo;
+            menu.setHeaderTitle(info.getCopyText());
+            menu.add(R.string.copy_text);
+        }
+    };
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        EntryContextMenuInfo menuInfo;
+        try {
+            menuInfo = (EntryContextMenuInfo) item.getMenuInfo();
+        } catch (ClassCastException e) {
+            Log.e(TAG, "bad menuInfo", e);
+            return false;
+        }
+
+        ClipboardUtils.copyText(this, menuInfo.getCopyLabel(), menuInfo.getCopyText(), true);
+        return true;
+    }
+
     /**
      * Headless fragment used to handle account selection callbacks invoked from
      * {@link DirectoryContactUtil}.
@@ -520,11 +552,13 @@
         mContactCard.setOnClickListener(mEntryClickHandler);
         mContactCard.setExpandButtonText(
         getResources().getString(R.string.expanding_entry_card_view_see_all));
+        mContactCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
 
         mRecentCard.setOnClickListener(mEntryClickHandler);
         mRecentCard.setTitle(getResources().getString(R.string.recent_card_title));
 
         mAboutCard.setOnClickListener(mEntryClickHandler);
+        mAboutCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
 
         mPhotoView = (ImageView) findViewById(R.id.photo);
         mTransparentView = findViewById(R.id.transparent_view);
@@ -863,12 +897,13 @@
                     /* alternateIntent = */ null,
                     /* alternateContentDescription = */ null,
                     /* shouldApplyColor = */ false,
-                    /* isEditable = */ false
-                    );
+                    /* isEditable = */ false,
+                    /* EntryContextMenuInfo = */ new EntryContextMenuInfo(phoneticName,
+                            getResources().getString(R.string.name_phonetic)));
             List<Entry> phoneticList = new ArrayList<>();
             phoneticList.add(phoneticEntry);
             // Phonetic name comes after nickname. Check to see if the first entry type is nickname
-            if (aboutCardEntries.get(0).get(0).getHeader().equals(
+            if (aboutCardEntries.size() > 0 && aboutCardEntries.get(0).get(0).getHeader().equals(
                     getResources().getString(R.string.header_nickname_entry))) {
                 aboutCardEntries.add(1, phoneticList);
             } else {
@@ -908,7 +943,7 @@
                 /* subHeader = */ null, /* text = */ null, getEditContactIntent(),
                 /* alternateIcon = */ null, /* alternateIntent = */ null,
                 /* alternateContentDescription = */ null, /* shouldApplyColor = */ true,
-                /* isEditable = */ false);
+                /* isEditable = */ false, /* EntryContextMenuInfo = */ null);
 
         final Drawable emailIcon = getResources().getDrawable(
                 R.drawable.ic_email_24dp).mutate();
@@ -916,7 +951,8 @@
                 emailIcon, getString(R.string.quickcontact_add_email), /* subHeader = */ null,
                 /* text = */ null, getEditContactIntent(), /* alternateIcon = */ null,
                 /* alternateIntent = */ null, /* alternateContentDescription = */ null,
-                /* shouldApplyColor = */ true, /* isEditable = */ false);
+                /* shouldApplyColor = */ true, /* isEditable = */ false,
+                /* EntryContextMenuInfo = */ null);
 
         final List<List<Entry>> promptEntries = new ArrayList<>();
         promptEntries.add(new ArrayList<Entry>(1));
@@ -1023,6 +1059,7 @@
         Intent alternateIntent = null;
         String alternateContentDescription = null;
         final boolean isEditable = false;
+        EntryContextMenuInfo entryContextMenuInfo = null;
 
         DataKind kind = dataItem.getDataKind();
 
@@ -1048,10 +1085,12 @@
                         im.getCustomProtocol()).toString();
                 subHeader = im.getData();
             }
+            entryContextMenuInfo = new EntryContextMenuInfo(im.getData(), header);
         } else if (dataItem instanceof OrganizationDataItem) {
             final OrganizationDataItem organization = (OrganizationDataItem) dataItem;
             header = getResources().getString(R.string.header_organization_entry);
             subHeader = organization.getCompany();
+            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header);
             text = organization.getTitle();
         } else if (dataItem instanceof NicknameDataItem) {
             final NicknameDataItem nickname = (NicknameDataItem) dataItem;
@@ -1066,15 +1105,18 @@
             if (!duplicatesTitle) {
                 header = getResources().getString(R.string.header_nickname_entry);
                 subHeader = nickname.getName();
+                entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header);
             }
         } else if (dataItem instanceof NoteDataItem) {
             final NoteDataItem note = (NoteDataItem) dataItem;
             header = getResources().getString(R.string.header_note_entry);
             subHeader = note.getNote();
+            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header);
         } else if (dataItem instanceof WebsiteDataItem) {
             final WebsiteDataItem website = (WebsiteDataItem) dataItem;
             header = getResources().getString(R.string.header_website_entry);
             subHeader = website.getUrl();
+            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header);
             try {
                 final WebAddress webAddress = new WebAddress(website.buildDataString(this, kind));
                 intent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
@@ -1109,6 +1151,7 @@
             }
             header = getResources().getString(R.string.header_relation_entry);
             subHeader = relation.getName();
+            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header);
             if (relation.hasKindTypeColumn(kind)) {
                 text = Relation.getTypeLabel(getResources(), relation.getKindTypeColumn(kind),
                         relation.getLabel()).toString();
@@ -1117,6 +1160,8 @@
             final PhoneDataItem phone = (PhoneDataItem) dataItem;
             if (!TextUtils.isEmpty(phone.getNumber())) {
                 header = phone.buildDataString(this, kind);
+                entryContextMenuInfo = new EntryContextMenuInfo(header,
+                        getResources().getString(R.string.phoneLabelsGroup));
                 if (phone.hasKindTypeColumn(kind)) {
                     text = Phone.getTypeLabel(getResources(), phone.getKindTypeColumn(kind),
                             phone.getLabel()).toString();
@@ -1137,6 +1182,8 @@
                 final Uri mailUri = Uri.fromParts(CallUtil.SCHEME_MAILTO, address, null);
                 intent = new Intent(Intent.ACTION_SENDTO, mailUri);
                 header = email.getAddress();
+                entryContextMenuInfo = new EntryContextMenuInfo(header,
+                        getResources().getString(R.string.emailLabelsGroup));
                 if (email.hasKindTypeColumn(kind)) {
                     text = Email.getTypeLabel(getResources(), email.getKindTypeColumn(kind),
                             email.getLabel()).toString();
@@ -1149,6 +1196,8 @@
             if (!TextUtils.isEmpty(postalAddress)) {
                 intent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
                 header = postal.getFormattedAddress();
+                entryContextMenuInfo = new EntryContextMenuInfo(header,
+                        getResources().getString(R.string.postalLabelsGroup));
                 if (postal.hasKindTypeColumn(kind)) {
                     text = StructuredPostal.getTypeLabel(getResources(),
                             postal.getKindTypeColumn(kind), postal.getLabel()).toString();
@@ -1166,6 +1215,8 @@
                     final Uri callUri = Uri.fromParts(CallUtil.SCHEME_SIP, address, null);
                     intent = CallUtil.getCallIntent(callUri);
                     header = address;
+                    entryContextMenuInfo = new EntryContextMenuInfo(header,
+                            getResources().getString(R.string.phoneLabelsGroup));
                     if (sip.hasKindTypeColumn(kind)) {
                         text = SipAddress.getTypeLabel(getResources(), sip.getKindTypeColumn(kind),
                             sip.getLabel()).toString();
@@ -1221,6 +1272,7 @@
                         }
                         break;
                     default:
+                        entryContextMenuInfo = new EntryContextMenuInfo(header, mimetype);
                         icon = ResolveCache.getInstance(this).getIcon(
                                 dataItem.getMimeType(), intent);
                         // Call mutate to create a new Drawable.ConstantState for color filtering
@@ -1262,7 +1314,7 @@
 
         return new Entry(dataId, icon, header, subHeader, subHeaderIcon, text, textIcon, intent,
                 alternateIcon, alternateIntent, alternateContentDescription, shouldApplyColor,
-                isEditable);
+                isEditable, entryContextMenuInfo);
     }
 
     private List<Entry> dataItemsToEntries(List<DataItem> dataItems) {
@@ -1428,7 +1480,8 @@
                     /* alternateIntent = */ null,
                     /* alternateContentDescription = */ null,
                     /* shouldApplyColor = */ true,
-                    /* isEditable = */ false));
+                    /* isEditable = */ false,
+                    /* EntryContextMenuInfo = */ null));
         }
         return entries;
     }