Switching contact name editor to single field by default

Change-Id: I7157a99a9a51fa05188cc50b90f37bb55c15793a
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 085b9ea..43e6489 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1092,6 +1092,8 @@
     <!-- Field title for the country of a structured postal address of a contact -->
     <string name="postal_country">Country</string>
 
+    <!-- Field title for the full name of a contact [CHAR LIMIT=64]-->
+    <string name="full_name">Name</string>
     <!-- Field title for the given name of a contact -->
     <string name="name_given">Given name</string>
     <!-- Field title for the family name of a contact -->
diff --git a/src/com/android/contacts/model/ContactsSource.java b/src/com/android/contacts/model/ContactsSource.java
index d008482..d498398 100644
--- a/src/com/android/contacts/model/ContactsSource.java
+++ b/src/com/android/contacts/model/ContactsSource.java
@@ -297,6 +297,8 @@
         public int inputType;
         public int minLines;
         public boolean optional;
+        public boolean shortForm;
+        public boolean longForm;
 
         public EditField(String column, int titleRes) {
             this.column = column;
@@ -312,6 +314,16 @@
             this.optional = optional;
             return this;
         }
+
+        public EditField setShortForm(boolean shortForm) {
+            this.shortForm = shortForm;
+            return this;
+        }
+
+        public EditField setLongForm(boolean longForm) {
+            this.longForm = longForm;
+            return this;
+        }
     }
 
     /**
diff --git a/src/com/android/contacts/model/Editor.java b/src/com/android/contacts/model/Editor.java
index 473f0d3..04e023b 100644
--- a/src/com/android/contacts/model/Editor.java
+++ b/src/com/android/contacts/model/Editor.java
@@ -44,6 +44,10 @@
 
         public static final int REQUEST_PICK_PHOTO = 1;
         public static final int FIELD_CHANGED = 2;
+
+        // The editor has switched between different representations of the same
+        // data, e.g. from full name to structured name
+        public static final int EDITOR_FORM_CHANGED = 3;
     }
 
     /**
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index f88e27b..4f018a9 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -682,6 +682,11 @@
             mAfter.put(key, value);
         }
 
+        public void putNull(String key) {
+            ensureUpdate();
+            mAfter.putNull(key);
+        }
+
         /**
          * Return set of all keys defined through this object.
          */
diff --git a/src/com/android/contacts/model/FallbackSource.java b/src/com/android/contacts/model/FallbackSource.java
index a23426c..a685e6d 100644
--- a/src/com/android/contacts/model/FallbackSource.java
+++ b/src/com/android/contacts/model/FallbackSource.java
@@ -112,42 +112,47 @@
         }
 
         if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+            kind.fieldList = Lists.newArrayList();
+            kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME,
+                    R.string.full_name, FLAGS_PERSON_NAME).setShortForm(true));
+
             boolean displayOrderPrimary =
                     context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
 
-            kind.fieldList = Lists.newArrayList();
-            kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
-                    FLAGS_PERSON_NAME).setOptional(true));
             if (!displayOrderPrimary) {
+                kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
-                        FLAGS_PERSON_NAME));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
-                        FLAGS_PERSON_NAME).setOptional(true));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
-                        FLAGS_PERSON_NAME));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
-                        FLAGS_PERSON_NAME).setOptional(true));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
-                        R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
+                        R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
-                        R.string.name_phonetic_middle, FLAGS_PHONETIC).setOptional(true));
+                        R.string.name_phonetic_middle, FLAGS_PHONETIC).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
-                        R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
+                        R.string.name_phonetic_given, FLAGS_PHONETIC).setLongForm(true));
             } else {
+                kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
-                        FLAGS_PERSON_NAME));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
-                        FLAGS_PERSON_NAME).setOptional(true));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
-                        FLAGS_PERSON_NAME));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
-                        FLAGS_PERSON_NAME).setOptional(true));
+                        FLAGS_PERSON_NAME).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
-                        R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
+                        R.string.name_phonetic_given, FLAGS_PHONETIC).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
-                        R.string.name_phonetic_middle, FLAGS_PHONETIC).setOptional(true));
+                        R.string.name_phonetic_middle, FLAGS_PHONETIC).setLongForm(true));
                 kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
-                        R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
+                        R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
             }
         }
 
diff --git a/src/com/android/contacts/model/GoogleSource.java b/src/com/android/contacts/model/GoogleSource.java
index 8786fcb..149249a 100644
--- a/src/com/android/contacts/model/GoogleSource.java
+++ b/src/com/android/contacts/model/GoogleSource.java
@@ -17,28 +17,12 @@
 package com.android.contacts.model;
 
 import com.android.contacts.R;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.google.android.collect.Lists;
 
-import android.accounts.Account;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
 import android.content.Context;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.os.RemoteException;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Groups;
-import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Contacts.Data;
-
-import java.util.ArrayList;
+import android.provider.ContactsContract.Groups;
 
 public class GoogleSource extends FallbackSource {
     public static final String ACCOUNT_TYPE = "com.google";
diff --git a/src/com/android/contacts/ui/widget/GenericEditorView.java b/src/com/android/contacts/ui/widget/GenericEditorView.java
index 80982bc..b5e0c4f 100644
--- a/src/com/android/contacts/ui/widget/GenericEditorView.java
+++ b/src/com/android/contacts/ui/widget/GenericEditorView.java
@@ -18,13 +18,13 @@
 
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
-import com.android.contacts.model.Editor;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityModifier;
 import com.android.contacts.model.ContactsSource.DataKind;
 import com.android.contacts.model.ContactsSource.EditField;
 import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor;
+import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.EntityModifier;
 import com.android.contacts.ui.ViewIdGenerator;
 import com.android.contacts.util.DialogManager;
 import com.android.contacts.util.DialogManager.DialogShowingView;
@@ -259,6 +259,9 @@
 
                         // Reconfigure GUI
                         mHideOptional = !mHideOptional;
+                        if (mListener != null) {
+                            mListener.onRequest(EditorListener.EDITOR_FORM_CHANGED);
+                        }
                         rebuildValues();
 
                         // Restore focus
@@ -304,6 +307,13 @@
     }
 
     /**
+     * Returns true if the editor is currently configured to show optional fields.
+     */
+    public boolean areOptionalFieldsVisible() {
+        return !mHideOptional;
+    }
+
+    /**
      * Build the current label state based on selected {@link EditType} and
      * possible custom label string.
      */
@@ -381,8 +391,9 @@
         }
         boolean hidePossible = false;
 
-        mFieldEditTexts = new EditText[kind.fieldList.size()];
-        for (int index = 0; index < kind.fieldList.size(); index++) {
+        int fieldCount = kind.fieldList.size();
+        mFieldEditTexts = new EditText[fieldCount];
+        for (int index = 0; index < fieldCount; index++) {
             final EditField field = kind.fieldList.get(index);
             final EditText fieldView = new EditText(mContext);
             fieldView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
@@ -419,12 +430,21 @@
                 }
             });
 
-            // Hide field when empty and optional value
-            final boolean couldHide = (!ContactsUtils.isGraphic(value) && field.optional);
-            final boolean willHide = (mHideOptional && couldHide);
-            fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
             fieldView.setEnabled(enabled);
-            hidePossible = hidePossible || couldHide;
+
+            if (field.shortForm) {
+                hidePossible = true;
+                fieldView.setVisibility(mHideOptional ? View.VISIBLE : View.GONE);
+            } else if (field.longForm) {
+                hidePossible = true;
+                fieldView.setVisibility(mHideOptional ? View.GONE : View.VISIBLE);
+            } else {
+                // Hide field when empty and optional value
+                final boolean couldHide = (!ContactsUtils.isGraphic(value) && field.optional);
+                final boolean willHide = (mHideOptional && couldHide);
+                fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
+                hidePossible = hidePossible || couldHide;
+            }
 
             addView(fieldView);
         }
diff --git a/src/com/android/contacts/views/editor/ContactEditorFragment.java b/src/com/android/contacts/views/editor/ContactEditorFragment.java
index 681931c..55ec604 100644
--- a/src/com/android/contacts/views/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/views/editor/ContactEditorFragment.java
@@ -73,10 +73,11 @@
 import android.provider.ContactsContract.AggregationExceptions;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.RawContactsEntity;
 import android.provider.MediaStore;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -99,7 +100,6 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.Iterator;
 import java.util.List;
 
 public class ContactEditorFragment extends Fragment implements
@@ -408,12 +408,12 @@
 
             if (editor instanceof ContactEditorView) {
                 final ContactEditorView rawContactEditor = (ContactEditorView) editor;
-                GenericEditorView nameEditor = rawContactEditor.getNameEditor();
+                final GenericEditorView nameEditor = rawContactEditor.getNameEditor();
                 nameEditor.setEditorListener(new EditorListener() {
 
                     @Override
                     public void onRequest(int request) {
-                        acquireAggregationSuggestions(rawContactEditor);
+                        onContactNameChange(request, rawContactEditor, nameEditor);
                     }
 
                     @Override
@@ -1022,6 +1022,106 @@
         return 0;
     }
 
+
+    private void onContactNameChange(int request, final ContactEditorView rawContactEditor,
+            GenericEditorView nameEditor) {
+
+        switch (request) {
+            case EditorListener.EDITOR_FORM_CHANGED:
+                if (nameEditor.areOptionalFieldsVisible()) {
+                    switchFromFullNameToStructuredName(nameEditor);
+                } else {
+                    switchFromStructuredNameToFullName(nameEditor);
+                }
+                break;
+
+            case EditorListener.FIELD_CHANGED:
+                if (nameEditor.areOptionalFieldsVisible()) {
+                    eraseFullName(nameEditor.getValues());
+                } else {
+                    eraseStructuredName(nameEditor.getValues());
+                }
+                acquireAggregationSuggestions(rawContactEditor);
+                break;
+        }
+    }
+
+    private void switchFromFullNameToStructuredName(GenericEditorView nameEditor) {
+        ValuesDelta values = nameEditor.getValues();
+
+        String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
+        if (displayName == null) {
+            displayName = "";
+        }
+
+        Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name")
+                .appendQueryParameter(StructuredName.DISPLAY_NAME, displayName).build();
+        Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{
+                StructuredName.PREFIX,
+                StructuredName.GIVEN_NAME,
+                StructuredName.MIDDLE_NAME,
+                StructuredName.FAMILY_NAME,
+                StructuredName.SUFFIX,
+        }, null, null, null);
+
+        try {
+            if (cursor.moveToFirst()) {
+                eraseFullName(values);
+                values.put(StructuredName.PREFIX, cursor.getString(0));
+                values.put(StructuredName.GIVEN_NAME, cursor.getString(1));
+                values.put(StructuredName.MIDDLE_NAME, cursor.getString(2));
+                values.put(StructuredName.FAMILY_NAME, cursor.getString(3));
+                values.put(StructuredName.SUFFIX, cursor.getString(4));
+            }
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private void switchFromStructuredNameToFullName(GenericEditorView nameEditor) {
+        ValuesDelta values = nameEditor.getValues();
+
+        Uri.Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath(
+                "complete_name");
+        appendQueryParameter(builder, values, StructuredName.PREFIX);
+        appendQueryParameter(builder, values, StructuredName.GIVEN_NAME);
+        appendQueryParameter(builder, values, StructuredName.MIDDLE_NAME);
+        appendQueryParameter(builder, values, StructuredName.FAMILY_NAME);
+        appendQueryParameter(builder, values, StructuredName.SUFFIX);
+        Uri uri = builder.build();
+        Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{
+                StructuredName.DISPLAY_NAME,
+        }, null, null, null);
+
+        try {
+            if (cursor.moveToFirst()) {
+                eraseStructuredName(values);
+                values.put(StructuredName.DISPLAY_NAME, cursor.getString(0));
+            }
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private void eraseFullName(ValuesDelta values) {
+        values.putNull(StructuredName.DISPLAY_NAME);
+    }
+
+    private void eraseStructuredName(ValuesDelta values) {
+        values.putNull(StructuredName.PREFIX);
+        values.putNull(StructuredName.GIVEN_NAME);
+        values.putNull(StructuredName.MIDDLE_NAME);
+        values.putNull(StructuredName.FAMILY_NAME);
+        values.putNull(StructuredName.SUFFIX);
+    }
+
+    private void appendQueryParameter(Uri.Builder builder, ValuesDelta values, String field) {
+        String value = values.getAsString(field);
+        if (!TextUtils.isEmpty(value)) {
+            builder.appendQueryParameter(field, value);
+        }
+    }
+
     /**
      * Triggers an asynchronous search for aggregation suggestions.
      */