Merge "Import new translations."
diff --git a/res/layout/item_kind_section.xml b/res/layout/item_kind_section.xml
index ebfeddf..d1dec5e 100644
--- a/res/layout/item_kind_section.xml
+++ b/res/layout/item_kind_section.xml
@@ -54,6 +54,7 @@
             android:fadingEdge="horizontal" />
 
         <ImageView
+            android:id="@+id/kind_plus"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:duplicateParentState="true"
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 9badeb6..c4976e2 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -1666,9 +1666,7 @@
                 finish();
             } else if (mMode == MODE_PICK_PHONE || mMode == MODE_QUERY_PICK_PHONE) {
                 Cursor c = (Cursor) mAdapter.getItem(position);
-                long contactId = c.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
-                returnPickerResult(c, c.getString(PHONE_DISPLAY_NAME_COLUMN_INDEX),
-                        ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId));
+                returnPickerResult(c, c.getString(PHONE_DISPLAY_NAME_COLUMN_INDEX), uri);
             } else if ((mMode & MODE_MASK_PICKER) != 0) {
                 Cursor c = (Cursor) mAdapter.getItem(position);
                 returnPickerResult(c, c.getString(getSummaryDisplayNameColumnIndex()), uri);
@@ -1690,10 +1688,10 @@
     }
 
     /**
-     * @param contactUri In most cases, this should be a lookup {@link Uri}, possibly
+     * @param selectedUri In most cases, this should be a lookup {@link Uri}, possibly
      *            generated through {@link Contacts#getLookupUri(long, String)}.
      */
-    private void returnPickerResult(Cursor c, String name, Uri contactUri) {
+    private void returnPickerResult(Cursor c, String name, Uri selectedUri) {
         final Intent intent = new Intent();
 
         if (mShortcutAction != null) {
@@ -1704,13 +1702,13 @@
                 shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                         Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
 
-                shortcutIntent.setData(contactUri);
+                shortcutIntent.setData(selectedUri);
                 shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_MODE,
                         ContactsContract.QuickContact.MODE_LARGE);
                 shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_EXCLUDE_MIMES,
                         (String[]) null);
 
-                final Bitmap icon = framePhoto(loadContactPhoto(contactUri, null));
+                final Bitmap icon = framePhoto(loadContactPhoto(selectedUri, null));
                 if (icon != null) {
                     intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaleToAppIconSize(icon));
                 } else {
@@ -1737,7 +1735,7 @@
                 shortcutIntent = new Intent(mShortcutAction, phoneUri);
 
                 intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
-                        generatePhoneNumberIcon(contactUri, type, resid));
+                        generatePhoneNumberIcon(selectedUri, type, resid));
             }
             shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
@@ -1745,7 +1743,7 @@
             setResult(RESULT_OK, intent);
         } else {
             intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
-            setResult(RESULT_OK, intent.setData(contactUri));
+            setResult(RESULT_OK, intent.setData(selectedUri));
         }
         finish();
     }
@@ -2071,13 +2069,29 @@
         return CONTACTS_SUMMARY_PROJECTION;
     }
 
-    private Bitmap loadContactPhoto(Uri lookupUri, BitmapFactory.Options options) {
+    private Bitmap loadContactPhoto(Uri selectedUri, BitmapFactory.Options options) {
+        Uri contactUri = null;
+        if (Contacts.CONTENT_ITEM_TYPE.equals(getContentResolver().getType(selectedUri))) {
+            // TODO we should have a "photo" directory under the lookup URI itself
+            contactUri = Contacts.lookupContact(getContentResolver(), selectedUri);
+        } else {
+
+            Cursor cursor = getContentResolver().query(selectedUri,
+                    new String[] { Data.CONTACT_ID }, null, null, null);
+            try {
+                if (cursor != null && cursor.moveToFirst()) {
+                    final long contactId = cursor.getLong(0);
+                    contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+                }
+            } finally {
+                if (cursor != null) cursor.close();
+            }
+        }
+
         Cursor cursor = null;
         Bitmap bm = null;
 
         try {
-            // TODO we should have a "photo" directory under the lookup URI itself
-            Uri contactUri = Contacts.lookupContact(getContentResolver(), lookupUri);
             Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
             cursor = getContentResolver().query(photoUri, new String[] {Photo.PHOTO},
                     null, null, null);
diff --git a/src/com/android/contacts/model/ContactsSource.java b/src/com/android/contacts/model/ContactsSource.java
index 1198837..d008482 100644
--- a/src/com/android/contacts/model/ContactsSource.java
+++ b/src/com/android/contacts/model/ContactsSource.java
@@ -141,7 +141,7 @@
     abstract public int getHeaderColor(Context context);
 
     abstract public int getSideBarColor(Context context);
-    
+
     /**
      * {@link Comparator} to sort by {@link DataKind#weight}.
      */
@@ -196,6 +196,12 @@
         public boolean secondary;
         public boolean editable;
 
+        /**
+         * If this is true (default), the user can add and remove values.
+         * If false, the editor will always show a single field (which might be empty).
+         */
+        public boolean isList;
+
         public StringInflater actionHeader;
         public StringInflater actionAltHeader;
         public StringInflater actionBody;
@@ -203,6 +209,11 @@
         public boolean actionBodySocial = false;
 
         public String typeColumn;
+
+        /**
+         * Maximum number of values allowed in the list. -1 represents infinity.
+         * If {@link DataKind#isList} is false, this value is ignored.
+         */
         public int typeOverallMax;
 
         public List<EditType> typeList;
@@ -219,6 +230,7 @@
             this.iconRes = iconRes;
             this.weight = weight;
             this.editable = editable;
+            this.isList = true;
             this.typeOverallMax = -1;
         }
     }
diff --git a/src/com/android/contacts/model/ExchangeSource.java b/src/com/android/contacts/model/ExchangeSource.java
index b26bdeb..2313b33 100644
--- a/src/com/android/contacts/model/ExchangeSource.java
+++ b/src/com/android/contacts/model/ExchangeSource.java
@@ -110,7 +110,7 @@
         final DataKind kind = super.inflateNickname(ContactsSource.LEVEL_MIMETYPES);
 
         if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
-            kind.typeOverallMax = 1;
+            kind.isList = false;
 
             kind.fieldList = Lists.newArrayList();
             kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
@@ -246,8 +246,7 @@
         final DataKind kind = super.inflateOrganization(ContactsSource.LEVEL_MIMETYPES);
 
         if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
-            kind.typeOverallMax = 1;
-
+            kind.isList = false;
             kind.typeColumn = Organization.TYPE;
             kind.typeList = Lists.newArrayList();
             kind.typeList.add(buildOrgType(Organization.TYPE_WORK).setSpecificMax(1));
@@ -284,8 +283,6 @@
         final DataKind kind = super.inflateNote(ContactsSource.LEVEL_MIMETYPES);
 
         if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
-            kind.typeOverallMax = 1;
-
             kind.fieldList = Lists.newArrayList();
             kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
         }
@@ -298,7 +295,7 @@
         final DataKind kind = super.inflateWebsite(ContactsSource.LEVEL_MIMETYPES);
 
         if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
-            kind.typeOverallMax = 1;
+            kind.isList = false;
 
             kind.fieldList = Lists.newArrayList();
             kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup, FLAGS_WEBSITE));
diff --git a/src/com/android/contacts/model/FallbackSource.java b/src/com/android/contacts/model/FallbackSource.java
index 8c3a9d2..08c0e28 100644
--- a/src/com/android/contacts/model/FallbackSource.java
+++ b/src/com/android/contacts/model/FallbackSource.java
@@ -16,6 +16,9 @@
 
 package com.android.contacts.model;
 
+import com.android.contacts.R;
+import com.google.android.collect.Lists;
+
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.res.Resources;
@@ -32,13 +35,8 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.util.Log;
 import android.view.inputmethod.EditorInfo;
 
-import com.google.android.collect.Lists;
-
-import com.android.contacts.R;
-
 import java.util.Locale;
 
 public class FallbackSource extends ContactsSource {
@@ -159,6 +157,7 @@
             kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
                     R.string.nicknameLabelsGroup, -1, 115, true));
             kind.secondary = true;
+            kind.isList = false;
             kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
             kind.actionBody = new SimpleInflater(Nickname.NAME);
         }
@@ -387,6 +386,7 @@
         if (kind == null) {
             kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE,
                     R.string.label_notes, R.drawable.sym_note, 110, true));
+            kind.isList = false;
             kind.secondary = true;
             kind.actionHeader = new SimpleInflater(R.string.label_notes);
             kind.actionBody = new SimpleInflater(Note.NOTE);
diff --git a/src/com/android/contacts/ui/widget/KindSectionView.java b/src/com/android/contacts/ui/widget/KindSectionView.java
index e379b69..46ce514 100644
--- a/src/com/android/contacts/ui/widget/KindSectionView.java
+++ b/src/com/android/contacts/ui/widget/KindSectionView.java
@@ -32,6 +32,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -47,6 +48,7 @@
 
     private ViewGroup mEditors;
     private View mAdd;
+    private ImageView mAddPlusButton;
     private TextView mTitle;
 
     private DataKind mKind;
@@ -77,6 +79,8 @@
         mAdd = findViewById(R.id.kind_header);
         mAdd.setOnClickListener(this);
 
+        mAddPlusButton = (ImageView) findViewById(R.id.kind_plus);
+
         mTitle = (TextView)findViewById(R.id.kind_title);
     }
 
@@ -102,6 +106,9 @@
         // TODO: handle resources from remote packages
         mTitle.setText(kind.titleRes);
 
+        // Only show the add button if this is a list
+        mAddPlusButton.setVisibility(mKind.isList ? View.VISIBLE : View.GONE);
+
         this.rebuildFromState();
         this.updateAddEnabled();
         this.updateEditorsVisible();
@@ -114,17 +121,44 @@
         // Remove any existing editors
         mEditors.removeAllViews();
 
-        // Build individual editors for each entry
-        if (!mState.hasMimeEntries(mKind.mimeType)) return;
-        for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
-            // Skip entries that aren't visible
-            if (!entry.isVisible()) continue;
+        // Check if we are displaying anything here
+        boolean hasEntries = mState.hasMimeEntries(mKind.mimeType);
 
-            final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
-                    R.layout.item_generic_editor, mEditors, false);
-            editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
-            editor.setEditorListener(this);
-            mEditors.addView(editor);
+        if (!mKind.isList) {
+            if (hasEntries) {
+                // we might have no visible entries. check that, too
+                for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
+                    if (!entry.isVisible()) {
+                        hasEntries = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!hasEntries) {
+                EntityModifier.insertChild(mState, mKind);
+                hasEntries = true;
+            }
+        }
+
+        if (hasEntries) {
+            int entryIndex = 0;
+            for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
+                // Skip entries that aren't visible
+                if (!entry.isVisible()) continue;
+
+                final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
+                        R.layout.item_generic_editor, mEditors, false);
+                editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
+                // older versions of android had lists where we now have a single value
+                // in these cases we should show the remove button for all but the first value
+                // to ensure that nothing is removed
+                editor.mDelete.setVisibility((mKind.isList || (entryIndex != 0))
+                        ? View.VISIBLE : View.GONE);
+                editor.setEditorListener(this);
+                mEditors.addView(editor);
+                entryIndex++;
+            }
         }
     }
 
@@ -136,12 +170,17 @@
     protected void updateAddEnabled() {
         // Set enabled state on the "add" view
         final boolean canInsert = EntityModifier.canInsert(mState, mKind);
-	final boolean isEnabled = !mReadOnly && canInsert;
+        final boolean isEnabled = !mReadOnly && canInsert;
         mAdd.setEnabled(isEnabled);
     }
 
     /** {@inheritDoc} */
     public void onClick(View v) {
+        // if this is not a list the plus button is not visible but the user might have clicked
+        // the text.
+        if (!mKind.isList)
+            return;
+
         // Insert a new child and rebuild
         final ValuesDelta newValues = EntityModifier.insertChild(mState, mKind);
         this.rebuildFromState();