Merge change I1dd85cfe into eclair

* changes:
  New icons
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 546238a..b6a2045 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -195,11 +195,6 @@
             </intent-filter>
 
             <intent-filter>
-                <action android:name="com.android.contacts.action.JOIN_AGGREGATE" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-
-            <intent-filter>
                 <action android:name="android.intent.action.INSERT_OR_EDIT" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="vnd.android.cursor.item/person" />
@@ -239,6 +234,18 @@
             />
         </activity>
 
+        <!-- An activity for joining contacts -->
+        <activity android:name="ContactsListActivity$JoinContactActivity"
+            android:theme="@style/TallTitleBarTheme"
+            android:clearTaskOnLaunch="true"
+        >
+            <intent-filter>
+                <action android:name="com.android.contacts.action.JOIN_AGGREGATE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+
         <!-- Used to select display and sync groups -->
         <activity android:name=".ui.DisplayGroupsActivity" android:label="@string/displayGroups" />
 
diff --git a/res/layout-finger/contacts_list_content_join.xml b/res/layout-finger/contacts_list_content_join.xml
new file mode 100644
index 0000000..ce82d2c
--- /dev/null
+++ b/res/layout-finger/contacts_list_content_join.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="vertical">
+
+    <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content" 
+            android:orientation="horizontal"
+            android:background="@*android:drawable/title_bar_medium"
+            android:padding="5dip"
+            android:gravity="center_vertical"
+            >
+    
+        <ImageView
+            android:layout_width="48dip"
+            android:layout_height="48dip"
+            android:src="@drawable/ic_menu_merge"
+            android:gravity="center"
+            android:scaleType="fitCenter"
+        />
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingLeft="10dip">
+            <TextView
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/titleJoinContactDataWith"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+            />
+            <TextView
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/blurbJoinContactDataWith"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+            />
+        </LinearLayout>
+    </LinearLayout>
+
+    <ListView android:id="@android:id/list"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:fastScrollEnabled="true"
+    />
+</LinearLayout>
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 141c166..fdbaab6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -138,6 +138,13 @@
     <!-- Activity title for the Join Contact list -->
     <string name="titleJoinAggregate">Join contact</string>
 
+    <!-- Heading of the Join Contact screen -->
+    <string name="titleJoinContactDataWith">Join contact data with:</string>
+
+    <!-- Info blurb on the Join Contact screen -->
+    <string name="blurbJoinContactDataWith">Contact data will be combined with
+        another contact selected from the list.</string>
+
     <!-- List separator for the Join Contact list: Suggestions -->
     <string name="separatorJoinAggregateSuggestions">Suggestions</string>
 
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index e03d5db..cc2f02f 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -86,6 +86,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AbsListView;
@@ -116,8 +117,13 @@
 /**
  * Displays a list of contacts. Usually is embedded into the ContactsActivity.
  */
-public final class ContactsListActivity extends ListActivity implements
+public class ContactsListActivity extends ListActivity implements
         View.OnCreateContextMenuListener, View.OnClickListener {
+
+    public static class JoinContactActivity extends ContactsListActivity {
+
+    }
+
     private static final String TAG = "ContactsListActivity";
 
     private static final boolean ENABLE_ACTION_ICON_OVERLAYS = true;
@@ -382,8 +388,6 @@
         final String action = intent.getAction();
         mMode = MODE_UNKNOWN;
 
-        setContentView(R.layout.contacts_list_content);
-
         Log.i(TAG, "Called with action: " + action);
         if (UI.LIST_DEFAULT.equals(action)) {
             mMode = MODE_DEFAULT;
@@ -529,6 +533,7 @@
             return;
         }
 
+
         if (JOIN_AGGREGATE.equals(action)) {
             mMode = MODE_JOIN_CONTACT;
             mQueryAggregateId = intent.getLongExtra(EXTRA_AGGREGATE_ID, -1);
@@ -538,16 +543,21 @@
                 setResult(RESULT_CANCELED);
                 finish();
             }
-
-            setTitle(R.string.titleJoinAggregate);
         }
 
         if (mMode == MODE_UNKNOWN) {
             mMode = MODE_DEFAULT;
         }
 
+        if (mMode == MODE_JOIN_CONTACT) {
+            setContentView(R.layout.contacts_list_content_join);
+        } else {
+            setContentView(R.layout.contacts_list_content);
+        }
+
         // Setup the UI
         final ListView list = getListView();
+
         // Tell list view to not show dividers. We'll do it ourself so that we can *not* show
         // them when an A-Z headers is visible.
         list.setDividerHeight(0);
@@ -623,6 +633,10 @@
     }
 
     private void setEmptyText() {
+        if (mMode == MODE_JOIN_CONTACT) {
+            return;
+        }
+
         TextView empty = (TextView) findViewById(R.id.emptyText);
         int gravity = Gravity.NO_GRAVITY;
 
@@ -747,6 +761,7 @@
         // be there and show up while the new query is happening. After the async query finished
         // in response to onRestart() setLoading(false) will be called.
         mAdapter.setLoading(true);
+        mAdapter.setSuggestionsCursor(null);
         mAdapter.changeCursor(null);
         mAdapter.clearImageFetching();
 
@@ -1605,7 +1620,7 @@
             case MODE_JOIN_CONTACT:
                 mQueryHandler.setLoadingJoinSuggestions(true);
                 mQueryHandler.startQuery(QUERY_TOKEN, null, getJoinSuggestionsUri(null), projection,
-                        Contacts._ID + " != " + mQueryAggregateId, null, null);
+                        null, null, null);
                 break;
         }
     }
@@ -1681,8 +1696,8 @@
                         null, null);
                 mAdapter.setSuggestionsCursor(cursor);
                 return resolver.query(getContactFilterUri(filter), projection,
-                        Contacts._ID + " != " + mQueryAggregateId, null,
-                        getSortOrder(projection));
+                        Contacts._ID + " != " + mQueryAggregateId + " AND " + CLAUSE_ONLY_VISIBLE,
+                        null, getSortOrder(projection));
             }
         }
         throw new UnsupportedOperationException("filtering not allowed in mode " + mMode);
@@ -1822,7 +1837,8 @@
 
                     startQuery(QUERY_TOKEN, null, activity.getContactFilterUri(activity.mQuery),
                             CONTACTS_SUMMARY_PROJECTION,
-                            Contacts._ID + " != " + activity.mQueryAggregateId, null,
+                            Contacts._ID + " != " + activity.mQueryAggregateId
+                                    + " AND " + CLAUSE_ONLY_VISIBLE, null,
                             getSortOrder(CONTACTS_SUMMARY_PROJECTION));
                     return;
                 }
diff --git a/src/com/android/contacts/model/Editor.java b/src/com/android/contacts/model/Editor.java
index d6f7003..b7ae045 100644
--- a/src/com/android/contacts/model/Editor.java
+++ b/src/com/android/contacts/model/Editor.java
@@ -49,7 +49,7 @@
      * builds any needed views. Any changes performed by the user will be
      * written back to that same object.
      */
-    public void setValues(DataKind kind, ValuesDelta values, EntityDelta state);
+    public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly);
 
     /**
      * Add a specific {@link EditorListener} to this {@link Editor}.
diff --git a/src/com/android/contacts/model/ExchangeSource.java b/src/com/android/contacts/model/ExchangeSource.java
index 0a7fb23..6d4e357 100644
--- a/src/com/android/contacts/model/ExchangeSource.java
+++ b/src/com/android/contacts/model/ExchangeSource.java
@@ -125,8 +125,6 @@
                     .add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true).setSpecificMax(1));
             kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true)
                     .setSpecificMax(1).setCustomColumn(Phone.LABEL));
-            kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true)
-                    .setSpecificMax(1).setCustomColumn(Phone.LABEL));
 
             kind.fieldList = Lists.newArrayList();
             kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
diff --git a/src/com/android/contacts/ui/widget/ContactEditorView.java b/src/com/android/contacts/ui/widget/ContactEditorView.java
index 35a32cf..cd94e52 100644
--- a/src/com/android/contacts/ui/widget/ContactEditorView.java
+++ b/src/com/android/contacts/ui/widget/ContactEditorView.java
@@ -173,6 +173,8 @@
         EntityModifier.ensureKindExists(state, source, Photo.CONTENT_ITEM_TYPE);
         mHasPhotoEditor = (source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null);
         mPhoto.setVisibility(mHasPhotoEditor ? View.VISIBLE : View.GONE);
+	mPhoto.setEnabled(!source.readOnly);
+	mName.setEnabled(!source.readOnly);
 
         mReadOnly.setVisibility(source.readOnly ? View.VISIBLE : View.GONE);
 
@@ -185,18 +187,18 @@
             if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
                 // Handle special case editor for structured name
                 final ValuesDelta primary = state.getPrimaryEntry(mimeType);
-                mName.setValues(kind, primary, state);
+                mName.setValues(kind, primary, state, source.readOnly);
             } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
                 // Handle special case editor for photos
                 final ValuesDelta primary = state.getPrimaryEntry(mimeType);
-                mPhoto.setValues(kind, primary, state);
+                mPhoto.setValues(kind, primary, state, source.readOnly);
             } else {
                 // Otherwise use generic section-based editors
                 if (kind.fieldList == null) continue;
                 final ViewGroup parent = kind.secondary ? mSecondary : mGeneral;
                 final KindSectionView section = (KindSectionView)mInflater.inflate(
                         R.layout.item_kind_section, parent, false);
-                section.setState(kind, state);
+                section.setState(kind, state, source.readOnly);
                 section.setId(kind.weight);
                 parent.addView(section);
             }
diff --git a/src/com/android/contacts/ui/widget/GenericEditorView.java b/src/com/android/contacts/ui/widget/GenericEditorView.java
index 53dd2e0..6387374 100644
--- a/src/com/android/contacts/ui/widget/GenericEditorView.java
+++ b/src/com/android/contacts/ui/widget/GenericEditorView.java
@@ -70,6 +70,7 @@
     protected DataKind mKind;
     protected ValuesDelta mEntry;
     protected EntityDelta mState;
+    protected boolean mReadOnly;
 
     protected boolean mHideOptional = true;
 
@@ -113,6 +114,16 @@
         mDelete.setVisibility(deletable ? View.VISIBLE : View.INVISIBLE);
     }
 
+    public void setEnabled(boolean enabled) {
+        mLabel.setEnabled(enabled);
+	final int count = mFields.getChildCount();
+        for (int pos = 0; pos < count; pos++) {
+            final View v = mFields.getChildAt(pos);
+            v.setEnabled(enabled);
+        }
+        mMore.setEnabled(enabled);
+    }
+
     /**
      * Build the current label state based on selected {@link EditType} and
      * possible custom label string.
@@ -144,17 +155,20 @@
     }
 
     private void rebuildValues() {
-        setValues(mKind, mEntry, mState);
+        setValues(mKind, mEntry, mState, mReadOnly);
     }
 
     /**
      * Prepare this editor using the given {@link DataKind} for defining
      * structure and {@link ValuesDelta} describing the content to edit.
      */
-    public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state) {
+    public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly) {
         mKind = kind;
         mEntry = entry;
         mState = state;
+	mReadOnly = readOnly;
+
+	final boolean enabled = !readOnly;
 
         if (!entry.isVisible()) {
             // Hide ourselves entirely if deleted
@@ -167,6 +181,7 @@
         // Display label selector if multiple types available
         final boolean hasTypes = EntityModifier.hasEditTypes(kind);
         mLabel.setVisibility(hasTypes ? View.VISIBLE : View.GONE);
+	mLabel.setEnabled(enabled);
         if (hasTypes) {
             mType = EntityModifier.getCurrentType(entry, kind);
             rebuildLabel();
@@ -207,6 +222,7 @@
             final boolean couldHide = (TextUtils.isEmpty(value) && field.optional);
             final boolean willHide = (mHideOptional && couldHide);
             fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
+	    fieldView.setEnabled(enabled);
             hidePossible = hidePossible || couldHide;
 
             mFields.addView(fieldView);
@@ -214,6 +230,7 @@
 
         // When hiding fields, place expandable
         mMore.setVisibility(hidePossible ? View.VISIBLE : View.GONE);
+	mMore.setEnabled(enabled);
     }
 
     /**
diff --git a/src/com/android/contacts/ui/widget/KindSectionView.java b/src/com/android/contacts/ui/widget/KindSectionView.java
index 5a63992..b52cfd0 100644
--- a/src/com/android/contacts/ui/widget/KindSectionView.java
+++ b/src/com/android/contacts/ui/widget/KindSectionView.java
@@ -50,6 +50,7 @@
 
     private DataKind mKind;
     private EntityDelta mState;
+    private boolean mReadOnly;
 
     public KindSectionView(Context context) {
         super(context);
@@ -87,9 +88,10 @@
         // Ignore requests
     }
 
-    public void setState(DataKind kind, EntityDelta state) {
+    public void setState(DataKind kind, EntityDelta state, boolean readOnly) {
         mKind = kind;
         mState = state;
+        mReadOnly = readOnly;
 
         // TODO: handle resources from remote packages
         mTitle.setText(kind.titleRes);
@@ -114,7 +116,7 @@
 
             final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
                     R.layout.item_generic_editor, mEditors, false);
-            editor.setValues(mKind, entry, mState);
+            editor.setValues(mKind, entry, mState, mReadOnly);
             editor.setEditorListener(this);
             editor.setId(entry.getViewId());
             mEditors.addView(editor);
@@ -129,7 +131,8 @@
     protected void updateAddEnabled() {
         // Set enabled state on the "add" view
         final boolean canInsert = EntityModifier.canInsert(mState, mKind);
-        mAdd.setEnabled(canInsert);
+	final boolean isEnabled = !mReadOnly && canInsert;
+        mAdd.setEnabled(isEnabled);
     }
 
     /** {@inheritDoc} */
diff --git a/src/com/android/contacts/ui/widget/PhotoEditorView.java b/src/com/android/contacts/ui/widget/PhotoEditorView.java
index cde314d..184b907 100644
--- a/src/com/android/contacts/ui/widget/PhotoEditorView.java
+++ b/src/com/android/contacts/ui/widget/PhotoEditorView.java
@@ -74,7 +74,7 @@
     }
 
     /** {@inheritDoc} */
-    public void setValues(DataKind kind, ValuesDelta values, EntityDelta state) {
+    public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly) {
         mEntry = values;
         if (values != null) {
             // Try decoding photo if actual entry
@@ -85,6 +85,7 @@
 
                 setScaleType(ImageView.ScaleType.CENTER_CROP);
                 setImageBitmap(photo);
+		setEnabled(!readOnly);
                 mHasSetPhoto = true;
             } else {
                 resetDefault();