First pass on showing only non-empty field on compact edit view

Bug 19124091

Change-Id: I49660c326f5829540463295218530f0a2d0fad9d
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
new file mode 100644
index 0000000..2855fff
--- /dev/null
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.editor;
+
+import com.android.contacts.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountType.EditField;
+import com.android.contacts.common.model.dataitem.DataKind;
+
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * View to display information from multiple {@link RawContactDelta}s grouped together
+ * (e.g. all the phone numbers from a {@link com.android.contacts.common.model.Contact} together.
+ */
+public class CompactRawContactsEditorView extends LinearLayout {
+
+    private static final String TAG = "CompactEditorView";
+
+    private AccountTypeManager mAccountTypeManager;
+    private LayoutInflater mLayoutInflater;
+    private ViewIdGenerator mViewIdGenerator;
+
+    private ViewGroup mNames;
+    private ViewGroup mPhoneNumbers;
+    private ViewGroup mEmails;
+    private ViewGroup mOther;
+
+    public CompactRawContactsEditorView(Context context) {
+        super(context);
+    }
+
+    public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mAccountTypeManager = AccountTypeManager.getInstance(getContext());
+        mLayoutInflater = (LayoutInflater)
+                getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        mNames = (LinearLayout) findViewById(R.id.names);
+        mPhoneNumbers = (LinearLayout) findViewById(R.id.phone_numbers);
+        mEmails = (LinearLayout) findViewById(R.id.emails);
+        mOther = (LinearLayout) findViewById(R.id.other);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        setEnabled(enabled, mNames);
+        setEnabled(enabled, mPhoneNumbers);
+        setEnabled(enabled, mEmails);
+        setEnabled(enabled, mOther);
+    }
+
+    private void setEnabled(boolean enabled, ViewGroup viewGroup) {
+        if (viewGroup != null) {
+            final int childCount = viewGroup.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                viewGroup.getChildAt(i).setEnabled(enabled);
+            }
+        }
+    }
+
+    public void setState(RawContactDeltaList rawContactDeltas, ViewIdGenerator viewIdGenerator) {
+        mNames.removeAllViews();
+        mPhoneNumbers.removeAllViews();
+        mEmails.removeAllViews();
+        mOther.removeAllViews();
+
+        if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
+            return;
+        }
+
+        mViewIdGenerator = viewIdGenerator;
+
+        setId(mViewIdGenerator.getId(rawContactDeltas.get(0), /* dataKind =*/ null,
+                /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
+
+        addEditorViews(rawContactDeltas);
+    }
+
+    private void addEditorViews(RawContactDeltaList rawContactDeltas) {
+        for (RawContactDelta rawContactDelta : rawContactDeltas) {
+            if (!rawContactDelta.isVisible()) {
+                continue;
+            }
+            final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+            for (DataKind dataKind : accountType.getSortedDataKinds()) {
+                if (!dataKind.editable) {
+                    continue;
+                }
+                final String mimeType = dataKind.mimeType;
+                log(Log.VERBOSE, mimeType + " " + dataKind.fieldList.size() + " field(s)");
+                if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)
+                        || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    // Photos are handled separately and group membership is not supported
+                    continue;
+                } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
+
+                    if (valuesDelta != null) {
+                        mNames.addView(inflateStructuredNameEditorView(
+                                mNames, accountType, valuesDelta, rawContactDelta));
+                    }
+                } else if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
+                    // Use the StructuredName mime type to get values
+                    if (hasNonEmptyPrimaryValuesDelta(
+                            rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
+                        final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(
+                                StructuredName.CONTENT_ITEM_TYPE);
+                        mNames.addView(inflatePhoneticNameEditorView(
+                                mNames, accountType, valuesDelta, rawContactDelta));
+                    }
+                } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
+                        for (ValuesDelta valuesDelta :
+                                getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind)) {
+                            mNames.addView(inflateNicknameEditorView(
+                                    mNames, accountType, valuesDelta, rawContactDelta));
+                        }
+                    }
+                } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
+                        mPhoneNumbers.addView(inflateKindSectionView(
+                                mPhoneNumbers, dataKind, rawContactDelta));
+                    }
+                } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
+                        mEmails.addView(inflateKindSectionView(
+                                mEmails, dataKind, rawContactDelta));
+                    }
+                } else if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
+                    mOther.addView(inflateKindSectionView(
+                            mOther, dataKind, rawContactDelta));
+                }
+            }
+        }
+    }
+
+    private static boolean hasNonEmptyValuesDelta(RawContactDelta rawContactDelta,
+            String mimeType, DataKind dataKind) {
+        return !getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind).isEmpty();
+    }
+
+    private static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
+            String mimeType, DataKind dataKind) {
+        final List<ValuesDelta> result = new ArrayList<>();
+        if (rawContactDelta == null) {
+            log(Log.VERBOSE, "Null RawContactDelta");
+            return result;
+        }
+        if (!rawContactDelta.hasMimeEntries(mimeType)) {
+            log(Log.VERBOSE, "No ValueDeltas");
+            return result;
+        }
+        for (ValuesDelta valuesDelta : rawContactDelta.getMimeEntries(mimeType)) {
+            if (valuesDelta == null) {
+                log(Log.VERBOSE, "Null valuesDelta");
+            }
+            for (EditField editField : dataKind.fieldList) {
+                final String column = editField.column;
+                final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
+                log(Log.VERBOSE, "Field " + column + " empty=" + TextUtils.isEmpty(value) +
+                        " value=" + value);
+                if (!TextUtils.isEmpty(value)) {
+                    result.add(valuesDelta);
+                }
+            }
+        }
+        return result;
+    }
+
+    private static boolean hasNonEmptyPrimaryValuesDelta(RawContactDelta rawContactDelta,
+            String mimeType, DataKind dataKind) {
+        final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
+        if (valuesDelta == null) {
+            return false;
+        }
+        for (EditField editField : dataKind.fieldList) {
+            final String column = editField.column;
+            final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
+            log(Log.VERBOSE, "Field (primary) " + column + " empty=" + TextUtils.isEmpty(value) +
+                    " value=" + value);
+            if (!TextUtils.isEmpty(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private StructuredNameEditorView inflateStructuredNameEditorView(ViewGroup viewGroup,
+            AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
+        final StructuredNameEditorView result = (StructuredNameEditorView) mLayoutInflater.inflate(
+                R.layout.structured_name_editor_view, viewGroup, /* attachToRoot =*/ false);
+        result.setValues(
+                accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
+                valuesDelta,
+                rawContactDelta,
+                /* readOnly =*/ false,
+                mViewIdGenerator);
+        return result;
+    }
+
+    private PhoneticNameEditorView inflatePhoneticNameEditorView(ViewGroup viewGroup,
+            AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
+        final PhoneticNameEditorView result = (PhoneticNameEditorView) mLayoutInflater.inflate(
+                R.layout.phonetic_name_editor_view, viewGroup, /* attachToRoot =*/ false);
+        result.setValues(
+                accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
+                valuesDelta,
+                rawContactDelta,
+                /* readOnly =*/ false,
+                mViewIdGenerator);
+        return result;
+    }
+
+    private TextFieldsEditorView inflateNicknameEditorView(ViewGroup viewGroup,
+            AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
+        final TextFieldsEditorView result = (TextFieldsEditorView) mLayoutInflater.inflate(
+                R.layout.text_fields_editor_view, viewGroup, /* attachToRoot =*/ false);
+        result.setValues(
+                accountType.getKindForMimetype(Nickname.CONTENT_ITEM_TYPE),
+                valuesDelta,
+                rawContactDelta,
+                /* readOnly =*/ false,
+                mViewIdGenerator);
+        return result;
+    }
+
+    private KindSectionView inflateKindSectionView(ViewGroup viewGroup, DataKind dataKind,
+            RawContactDelta rawContactDelta) {
+        final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(
+                R.layout.item_kind_section, viewGroup, /* attachToRoot =*/ false);
+        result.setState(
+                dataKind,
+                rawContactDelta,
+                /* readOnly =*/ false,
+                mViewIdGenerator);
+        return result;
+    }
+
+    private static void log(int level, String message) {
+        log(TAG, level, message);
+    }
+
+    private static void log(String tag, int level, String message) {
+        if (Log.isLoggable(tag, level)) {
+            switch (level) {
+                case Log.VERBOSE:
+                    Log.v(tag, message);
+                    break;
+                case Log.DEBUG:
+                    Log.d(tag, message);
+                    break;
+                case Log.INFO:
+                    Log.i(tag, message);
+                    break;
+                case Log.WARN:
+                    Log.w(tag, message);
+                    break;
+                case Log.ERROR:
+                    Log.e(tag, message);
+                    break;
+                default:
+                    Log.v(tag, message);
+                    break;
+            }
+        }
+    }
+}