Merge "Implement custom EditText to correctly suppress IME"
diff --git a/res/layout-sw580dp/contact_detail_fragment.xml b/res/layout-sw580dp/contact_detail_fragment.xml
index c9dad2a..f05dc56 100644
--- a/res/layout-sw580dp/contact_detail_fragment.xml
+++ b/res/layout-sw580dp/contact_detail_fragment.xml
@@ -30,8 +30,9 @@
 
     <!-- Real list -->
     <ListView android:id="@android:id/list"
+        android:layout_weight="1"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="0dip"
         android:cacheColorHint="#00000000"
         android:divider="@null"
     />
diff --git a/src/com/android/contacts/ContactTileLoaderFactory.java b/src/com/android/contacts/ContactTileLoaderFactory.java
index 30bd7e4..28f2164 100644
--- a/src/com/android/contacts/ContactTileLoaderFactory.java
+++ b/src/com/android/contacts/ContactTileLoaderFactory.java
@@ -23,7 +23,6 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Contacts.Data;
 
 /**
  * Used to create {@link CursorLoader}s to load different groups of {@link ContactTileView}s
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 1da1c97..68e9cbb 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -156,6 +156,7 @@
     /** ViewPager for swipe, used only on the phone (i.e. one-pane mode) */
     private ViewPager mTabPager;
     private TabPagerAdapter mTabPagerAdapter;
+    private final TabPagerListener mTabPagerListener = new TabPagerListener();
 
     private ContactDetailLayoutController mContactDetailLayoutController;
 
@@ -315,7 +316,7 @@
             mTabPager = getView(R.id.tab_pager);
             mTabPagerAdapter = new TabPagerAdapter();
             mTabPager.setAdapter(mTabPagerAdapter);
-            mTabPager.setOnPageChangeListener(new TabPagerListener());
+            mTabPager.setOnPageChangeListener(mTabPagerListener);
 
             final String FAVORITE_TAG = "tab-pager-favorite";
             final String ALL_TAG = "tab-pager-all";
@@ -450,6 +451,9 @@
         // Re-register the listener, which may have been cleared when onSaveInstanceState was
         // called.  See also: onSaveInstanceState
         mActionBarAdapter.setListener(this);
+        if (mTabPager != null) {
+            mTabPager.setOnPageChangeListener(mTabPagerListener);
+        }
         // Current tab may have changed since the last onSaveInstanceState().  Make sure
         // the actual contents match the tab.
         updateFragmentsVisibility();
@@ -1527,6 +1531,9 @@
         // in order to avoid doing fragment transactions after it.
         // TODO Figure out a better way to deal with the issue.
         mActionBarAdapter.setListener(null);
+        if (mTabPager != null) {
+            mTabPager.setOnPageChangeListener(null);
+        }
     }
 
     @Override
diff --git a/src/com/android/contacts/editor/ExternalRawContactEditorView.java b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
index cabf639..eb496f2 100644
--- a/src/com/android/contacts/editor/ExternalRawContactEditorView.java
+++ b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
@@ -168,7 +168,8 @@
 
         // Name
         primary = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
-        mName.setText(primary.getAsString(StructuredName.DISPLAY_NAME));
+        mName.setText(primary != null ? primary.getAsString(StructuredName.DISPLAY_NAME) :
+                mContext.getString(R.string.missing_name));
 
         if (type.readOnly) {
             mAccountContainer.setOnClickListener(new OnClickListener() {
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index 51cc965..2e511bc 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -45,14 +45,13 @@
         Contacts.SORT_KEY_PRIMARY,              // 3
         Contacts.STARRED,                       // 4
         Contacts.CONTACT_PRESENCE,              // 5
-        Contacts.CONTACT_CHAT_CAPABILITY,       // 6
-        Contacts.CONTACT_STATUS,                // 7
-        Contacts.PHOTO_ID,                      // 8
-        Contacts.PHOTO_THUMBNAIL_URI,           // 9
-        Contacts.LOOKUP_KEY,                    // 10
-        Contacts.PHONETIC_NAME,                 // 11
-        Contacts.HAS_PHONE_NUMBER,              // 12
-        Contacts.IS_USER_PROFILE,               // 13
+        Contacts.CONTACT_STATUS,                // 6
+        Contacts.PHOTO_ID,                      // 7
+        Contacts.PHOTO_THUMBNAIL_URI,           // 8
+        Contacts.LOOKUP_KEY,                    // 9
+        Contacts.PHONETIC_NAME,                 // 10
+        Contacts.HAS_PHONE_NUMBER,              // 11
+        Contacts.IS_USER_PROFILE,               // 12
     };
 
     protected static final String[] PROJECTION_DATA = new String[] {
@@ -62,13 +61,12 @@
         Data.SORT_KEY_PRIMARY,                  // 3
         Data.STARRED,                           // 4
         Data.CONTACT_PRESENCE,                  // 5
-        Data.CONTACT_CHAT_CAPABILITY,           // 6
-        Data.CONTACT_STATUS,                    // 7
-        Data.PHOTO_ID,                          // 8
-        Data.PHOTO_THUMBNAIL_URI,               // 9
-        Data.LOOKUP_KEY,                        // 10
-        Data.PHONETIC_NAME,                     // 11
-        Data.HAS_PHONE_NUMBER,                  // 12
+        Data.CONTACT_STATUS,                    // 6
+        Data.PHOTO_ID,                          // 7
+        Data.PHOTO_THUMBNAIL_URI,               // 8
+        Data.LOOKUP_KEY,                        // 9
+        Data.PHONETIC_NAME,                     // 10
+        Data.HAS_PHONE_NUMBER,                  // 11
     };
 
     protected static final String[] FILTER_PROJECTION = new String[] {
@@ -78,15 +76,14 @@
         Contacts.SORT_KEY_PRIMARY,              // 3
         Contacts.STARRED,                       // 4
         Contacts.CONTACT_PRESENCE,              // 5
-        Contacts.CONTACT_CHAT_CAPABILITY,       // 6
-        Contacts.CONTACT_STATUS,                // 7
-        Contacts.PHOTO_ID,                      // 8
-        Contacts.PHOTO_THUMBNAIL_URI,           // 9
-        Contacts.LOOKUP_KEY,                    // 10
-        Contacts.PHONETIC_NAME,                 // 11
-        Contacts.HAS_PHONE_NUMBER,              // 12
-        Contacts.IS_USER_PROFILE,               // 13
-        SearchSnippetColumns.SNIPPET,           // 14
+        Contacts.CONTACT_STATUS,                // 6
+        Contacts.PHOTO_ID,                      // 7
+        Contacts.PHOTO_THUMBNAIL_URI,           // 8
+        Contacts.LOOKUP_KEY,                    // 9
+        Contacts.PHONETIC_NAME,                 // 10
+        Contacts.HAS_PHONE_NUMBER,              // 11
+        Contacts.IS_USER_PROFILE,               // 12
+        SearchSnippetColumns.SNIPPET,           // 13
     };
 
     protected static final int CONTACT_ID_COLUMN_INDEX = 0;
@@ -95,15 +92,14 @@
     protected static final int CONTACT_SORT_KEY_PRIMARY_COLUMN_INDEX = 3;
     protected static final int CONTACT_STARRED_COLUMN_INDEX = 4;
     protected static final int CONTACT_PRESENCE_STATUS_COLUMN_INDEX = 5;
-    protected static final int CONTACT_CHAT_CAPABILITY_COLUMN_INDEX = 6;
-    protected static final int CONTACT_CONTACT_STATUS_COLUMN_INDEX = 7;
-    protected static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 8;
-    protected static final int CONTACT_PHOTO_URI_COLUMN_INDEX = 9;
-    protected static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 10;
-    protected static final int CONTACT_PHONETIC_NAME_COLUMN_INDEX = 11;
-    protected static final int CONTACT_HAS_PHONE_COLUMN_INDEX = 12;
-    protected static final int CONTACT_IS_USER_PROFILE = 13;
-    protected static final int CONTACT_SNIPPET_COLUMN_INDEX = 14;
+    protected static final int CONTACT_CONTACT_STATUS_COLUMN_INDEX = 6;
+    protected static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 7;
+    protected static final int CONTACT_PHOTO_URI_COLUMN_INDEX = 8;
+    protected static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 9;
+    protected static final int CONTACT_PHONETIC_NAME_COLUMN_INDEX = 10;
+    protected static final int CONTACT_HAS_PHONE_COLUMN_INDEX = 11;
+    protected static final int CONTACT_IS_USER_PROFILE = 12;
+    protected static final int CONTACT_SNIPPET_COLUMN_INDEX = 13;
 
     private CharSequence mUnknownNameText;
     private int mDisplayNameColumnIndex;
@@ -281,7 +277,7 @@
 
     protected void bindPresenceAndStatusMessage(final ContactListItemView view, Cursor cursor) {
         view.showPresenceAndStatusMessage(cursor, CONTACT_PRESENCE_STATUS_COLUMN_INDEX,
-                CONTACT_CHAT_CAPABILITY_COLUMN_INDEX, CONTACT_CONTACT_STATUS_COLUMN_INDEX);
+                CONTACT_CONTACT_STATUS_COLUMN_INDEX);
     }
 
     protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index 4c4b780..ce1b119 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -1050,17 +1050,12 @@
      * Sets the proper icon (star or presence or nothing) and/or status message.
      */
     public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
-            int capabilityColumnIndex, int contactStatusColumnIndex) {
+            int contactStatusColumnIndex) {
         Drawable icon = null;
         int presence = 0;
-        int chatCapability = 0;
         if (!cursor.isNull(presenceColumnIndex)) {
             presence = cursor.getInt(presenceColumnIndex);
-            if (capabilityColumnIndex != 0 && !cursor.isNull(presenceColumnIndex)) {
-                chatCapability = cursor.getInt(capabilityColumnIndex);
-            }
-            icon = ContactPresenceIconUtil.getChatCapabilityIcon(
-                    getContext(), presence, chatCapability);
+            icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
         }
         setPresence(icon);
 
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 63d44be..b7434b1 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -16,6 +16,8 @@
 package com.android.contacts.list;
 
 import com.android.contacts.ContactPhotoManager;
+import com.android.contacts.ContactPresenceIconUtil;
+import com.android.contacts.ContactStatusUtil;
 import com.android.contacts.ContactTileLoaderFactory;
 import com.android.contacts.GroupMemberLoader;
 import com.android.contacts.R;
@@ -25,6 +27,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
@@ -238,8 +241,8 @@
         contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
         contact.lookupKey = ContentUris.withAppendedId(
                 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
-        contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
 
+        // Set phone number and label
         if (mDisplayType == DisplayType.STREQUENT_PHONE_ONLY) {
             int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
             String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
@@ -247,8 +250,25 @@
                     phoneNumberCustomLabel);
             contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
         } else {
-            contact.status = cursor.getString(mStatusIndex);
-            contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
+            // Set presence icon and status message
+            Drawable icon = null;
+            int presence = 0;
+            if (!cursor.isNull(mPresenceIndex)) {
+                presence = cursor.getInt(mPresenceIndex);
+                icon = ContactPresenceIconUtil.getPresenceIcon(mContext, presence);
+            }
+            contact.presenceIcon = icon;
+
+            String statusMessage = null;
+            if (mStatusIndex != 0 && !cursor.isNull(mStatusIndex)) {
+                statusMessage = cursor.getString(mStatusIndex);
+            }
+            // If there is no status message from the contact, but there was a presence value,
+            // then use the default status message string
+            if (statusMessage == null && presence != 0) {
+                statusMessage = ContactStatusUtil.getStatusString(mContext, presence);
+            }
+            contact.status = statusMessage;
         }
 
         return contact;
@@ -530,7 +550,7 @@
         public String phoneNumber;
         public Uri photoUri;
         public Uri lookupKey;
-        public Integer presence;
+        public Drawable presenceIcon;
     }
 
     private static class ViewTypes {
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 25edd7f..bfc4a2e 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -96,22 +96,12 @@
             mLookupUri = entry.lookupKey;
 
             if (mStatus != null) {
-                String statusText;
-                if (entry.presence == null) {
+                if (entry.status == null) {
                     mStatus.setVisibility(View.GONE);
                 } else {
-                    statusText =
-                          (entry.status != null ? entry.status :
-                          ContactStatusUtil.getStatusString(mContext, entry.presence));
-                    mStatus.setText(statusText);
-                    int presenceDrawableResId = (entry.presence == null ? 0 :
-                            StatusUpdates.getPresenceIconResourceId(entry.presence));
-                    if (presenceDrawableResId != 0) {
-                        Log.i(TAG, "iconId = " + presenceDrawableResId);
-                        mStatus.setCompoundDrawablesWithIntrinsicBounds(
-                                getResources().getDrawable(presenceDrawableResId),
-                                null, null, null);
-                    }
+                    mStatus.setText(entry.status);
+                    mStatus.setCompoundDrawablesWithIntrinsicBounds(entry.presenceIcon,
+                            null, null, null);
                     mStatus.setVisibility(View.VISIBLE);
                 }
             }
diff --git a/src/com/android/contacts/list/LegacyContactListAdapter.java b/src/com/android/contacts/list/LegacyContactListAdapter.java
index b3ab2af..b21d484 100644
--- a/src/com/android/contacts/list/LegacyContactListAdapter.java
+++ b/src/com/android/contacts/list/LegacyContactListAdapter.java
@@ -91,6 +91,6 @@
     }
 
     protected void bindPresence(final ContactListItemView view, Cursor cursor) {
-        view.showPresenceAndStatusMessage(cursor, PERSON_PRESENCE_STATUS_COLUMN_INDEX, 0, 0);
+        view.showPresenceAndStatusMessage(cursor, PERSON_PRESENCE_STATUS_COLUMN_INDEX, 0);
     }
 }
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 60a7357..2d821e6 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -338,6 +338,17 @@
                         // Skip external account types that couldn't be initialized.
                         continue;
                     }
+                    if (!accountType.hasContactsMetadata()) {
+                        Log.w(TAG, "Skipping extension package " + extensionPackage + " because"
+                                + " it doesn't have the CONTACTS_STRUCTURE metadata");
+                        continue;
+                    }
+                    if (TextUtils.isEmpty(accountType.accountType)) {
+                        Log.w(TAG, "Skipping extension package " + extensionPackage + " because"
+                                + " the CONTACTS_STRUCTURE metadata doesn't have the accountType"
+                                + " attribute");
+                        continue;
+                    }
                     Log.d(TAG, "Registering extension package account type="
                             + accountType.accountType + ", dataSet=" + accountType.dataSet
                             + ", packageName=" + extensionPackage);
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/ExternalAccountType.java
index 791f0ae..b6649c9 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/ExternalAccountType.java
@@ -22,11 +22,9 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -46,7 +44,6 @@
 public class ExternalAccountType extends BaseAccountType {
     private static final String TAG = "ExternalAccountType";
 
-    private static final String ACTION_SYNC_ADAPTER = "android.content.SyncAdapter";
     private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE";
 
     private static final String TAG_CONTACTS_SOURCE_LEGACY = "ContactsSource";
@@ -85,6 +82,7 @@
     private String mAccountTypeLabelAttribute;
     private String mAccountTypeIconAttribute;
     private boolean mInitSuccessful;
+    private boolean mHasContactsMetadata;
 
     public ExternalAccountType(Context context, String resPackageName) {
         this.resPackageName = resPackageName;
@@ -137,6 +135,13 @@
         return mInitSuccessful;
     }
 
+    /**
+     * Whether this account type has the android.provider.CONTACTS_STRUCTURE metadata xml.
+     */
+    public boolean hasContactsMetadata() {
+        return mHasContactsMetadata;
+    }
+
     @Override
     public String getEditContactActivityClassName() {
         return mEditContactActivityClassName;
@@ -207,6 +212,8 @@
                         + TAG_CONTACTS_ACCOUNT_TYPE + ", not " + rootTag);
             }
 
+            mHasContactsMetadata = true;
+
             int attributeCount = parser.getAttributeCount();
             for (int i = 0; i < attributeCount; i++) {
                 String attr = parser.getAttributeName(i);
diff --git a/src/com/android/contacts/util/ContactBadgeUtil.java b/src/com/android/contacts/util/ContactBadgeUtil.java
index 806264d..a89177a 100644
--- a/src/com/android/contacts/util/ContactBadgeUtil.java
+++ b/src/com/android/contacts/util/ContactBadgeUtil.java
@@ -57,10 +57,15 @@
 
         final String statusLabelRes = streamItem.getLabelRes();
         final String statusResPackage = streamItem.getResPackage();
+
+        // Package name used for resources.getIdentifier()
+        String identiferPackage = statusResPackage;
         if (statusLabelRes  != null) {
             Resources resources;
             if (TextUtils.isEmpty(statusResPackage)) {
                 resources = context.getResources();
+                // In this case, we're using the framework resources.
+                identiferPackage = "android";
             } else {
                 PackageManager pm = context.getPackageManager();
                 try {
@@ -74,7 +79,7 @@
 
             if (resources != null) {
                 final int resId = resources.getIdentifier(statusLabelRes, "string",
-                        statusResPackage);
+                        identiferPackage);
                 if (resId == 0) {
                     Log.w(TAG, "Contact status update resource not found: " + statusLabelRes +
                             " in " + statusResPackage);