Add group membership support to compact editor (E9)

Bug 23589603

Change-Id: I71082af35a35dc7d0658ffb671a4436f794f5b0c
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index e7128a4..d5209cb 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -289,7 +289,9 @@
 
     @Override
     protected void setGroupMetaData() {
-        // The compact editor does not support groups.
+        if (mGroupMetaData != null) {
+            getContent().setGroupMetaData(mGroupMetaData);
+        }
     }
 
     @Override
diff --git a/src/com/android/contacts/editor/CompactKindSectionView.java b/src/com/android/contacts/editor/CompactKindSectionView.java
index 50ef405..25712d0 100644
--- a/src/com/android/contacts/editor/CompactKindSectionView.java
+++ b/src/com/android/contacts/editor/CompactKindSectionView.java
@@ -17,7 +17,8 @@
 package com.android.contacts.editor;
 
 import android.content.Context;
-import android.provider.ContactsContract;
+import android.database.Cursor;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.CommonDataKinds.Nickname;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.util.AttributeSet;
@@ -178,6 +179,15 @@
         mHideIfEmpty = hideWhenEmpty;
     }
 
+    public void setGroupMetaData(Cursor cursor) {
+        for (int i = 0; i < mEditors.getChildCount(); i++) {
+            final View view = mEditors.getChildAt(i);
+            if (view instanceof GroupMembershipView) {
+                ((GroupMembershipView) view).setGroupMetaData(cursor);
+            }
+        }
+    }
+
     public void setState(List<KindSectionData> kindSectionDataList, boolean readOnly,
             ViewIdGenerator viewIdGenerator, CompactRawContactsEditorView.Listener listener) {
         mKindSectionDataList = kindSectionDataList;
@@ -208,11 +218,15 @@
         mEditors.removeAllViews();
 
         for (KindSectionData kindSectionData : mKindSectionDataList) {
-            if (StructuredName.CONTENT_ITEM_TYPE.equals(kindSectionData.getDataKind().mimeType)) {
+            final String mimeType = kindSectionData.getDataKind().mimeType;
+            if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
                 for (ValuesDelta valuesDelta : kindSectionData.getValuesDeltas()) {
                     createNameEditorViews(kindSectionData.getAccountType(),
                             valuesDelta, kindSectionData.getRawContactDelta());
                 }
+            } else if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                createGroupEditorView(kindSectionData.getRawContactDelta(),
+                        kindSectionData.getDataKind());
             } else {
                 for (ValuesDelta valuesDelta : kindSectionData.getValuesDeltas()) {
                     createEditorView(kindSectionData.getRawContactDelta(),
@@ -259,6 +273,19 @@
         mEditors.addView(phoneticNameView);
     }
 
+    private void createGroupEditorView(RawContactDelta rawContactDelta, DataKind dataKind) {
+        final GroupMembershipView view = (GroupMembershipView) mInflater.inflate(
+                R.layout.item_group_membership, mEditors, /* attachToRoot =*/ false);
+        view.setKind(dataKind);
+        view.setEnabled(isEnabled());
+        view.setState(rawContactDelta);
+
+        // Correct start margin since there is another icon in the group layout
+        view.findViewById(R.id.kind_icon).setVisibility(View.GONE);
+
+        mEditors.addView(view);
+    }
+
     /**
      * Creates an EditorView for the given values delta. This function must be used while
      * constructing the views corresponding to the the object-model. The resulting EditorView is
@@ -426,8 +453,8 @@
     private List<View> getEmptyEditors() {
         List<View> emptyEditorViews = new ArrayList<View>();
         for (int i = 0; i < mEditors.getChildCount(); i++) {
-            View view = mEditors.getChildAt(i);
-            if (((Editor) view).isEmpty()) {
+            final View view = mEditors.getChildAt(i);
+            if (view instanceof Editor && ((Editor) view).isEmpty()) {
                 emptyEditorViews.add(view);
             }
         }
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 540bf1a..8ca6389 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -31,6 +31,7 @@
 import com.android.contacts.util.UiClosables;
 
 import android.content.Context;
+import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -129,6 +130,7 @@
      *     <li>All names are together at the top.</li>
      *     <li>IM is moved up after addresses</li>
      *     <li>SIP addresses are moved to below phone numbers</li>
+     *     <li>Group membership is palced at the end</li>
      * </ol>
      */
     private static final class MimeTypeComparator implements Comparator<String> {
@@ -145,7 +147,8 @@
                 Organization.CONTENT_ITEM_TYPE,
                 Event.CONTENT_ITEM_TYPE,
                 Relation.CONTENT_ITEM_TYPE,
-                Note.CONTENT_ITEM_TYPE
+                Note.CONTENT_ITEM_TYPE,
+                GroupMembership.CONTENT_ITEM_TYPE
         });
 
         @Override
@@ -271,6 +274,7 @@
 
     private CompactPhotoEditorView mPhotoView;
     private ViewGroup mKindSectionViews;
+    private Map<String,List<CompactKindSectionView>> mKindSectionViewsMap = new HashMap<>();
     private View mMoreFields;
 
     private long mPhotoRawContactId;
@@ -380,15 +384,22 @@
     }
 
     public View getAggregationAnchorView() {
-        // The kind section for the primary account is sorted to the front
-        final List<KindSectionData> kindSectionDataList = getKindSectionDataList(
+        final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
                 StructuredName.CONTENT_ITEM_TYPE);
-        if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
+        if (!kindSectionViews.isEmpty()) {
             return mKindSectionViews.getChildAt(0).findViewById(R.id.anchor_view);
         }
         return null;
     }
 
+    public void setGroupMetaData(Cursor groupMetaData) {
+        final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
+                GroupMembership.CONTENT_ITEM_TYPE);
+        for (CompactKindSectionView kindSectionView : kindSectionViews) {
+            kindSectionView.setGroupMetaData(groupMetaData);
+        }
+    }
+
     public void setState(RawContactDeltaList rawContactDeltas,
             MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
             long photoId, boolean hasNewContact, boolean isUserProfile,
@@ -720,12 +731,6 @@
                 continue;
             }
 
-            // Ignore mime types that we don't handle
-            if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
-                vlog("kind: " + i + " " + mimeType + " dropped");
-                continue;
-            }
-
             if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
                 vlog("kind: " + i + " " + mimeType + ": " + kindSectionDataList.size() +
                         " kindSectionData(s)");
@@ -733,10 +738,22 @@
                 final CompactKindSectionView kindSectionView = inflateKindSectionView(
                         mKindSectionViews, kindSectionDataList, mimeType);
                 mKindSectionViews.addView(kindSectionView);
+
+                // Keep a pointer to all the KindSectionsViews for each mimeType
+                getKindSectionViews(mimeType).add(kindSectionView);
             }
         }
     }
 
+    private List<CompactKindSectionView> getKindSectionViews(String mimeType) {
+        List<CompactKindSectionView> kindSectionViews = mKindSectionViewsMap.get(mimeType);
+        if (kindSectionViews == null) {
+            kindSectionViews = new ArrayList<>();
+            mKindSectionViewsMap.put(mimeType, kindSectionViews);
+        }
+        return kindSectionViews;
+    }
+
     private CompactKindSectionView inflateKindSectionView(ViewGroup viewGroup,
             List<KindSectionData> kindSectionDataList, String mimeType) {
         final CompactKindSectionView kindSectionView = (CompactKindSectionView)