Merge "Use ActionBar in call log details activity."
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index fa0ffb2..4078598 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -16,9 +16,12 @@
package com.android.contacts;
+import com.android.contacts.model.AccountType;
+import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
+import com.google.android.collect.Lists;
import com.google.common.annotations.VisibleForTesting;
import android.content.ContentResolver;
@@ -44,23 +47,20 @@
import android.provider.ContactsContract.DisplayNameSources;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.StreamItems;
import android.provider.ContactsContract.StreamItemPhotos;
+import android.provider.ContactsContract.StreamItems;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* Loads a single Contact and all it constituent RawContacts.
@@ -71,6 +71,7 @@
private Uri mLookupUri;
private boolean mLoadGroupMetaData;
private boolean mLoadStreamItems;
+ private final boolean mLoadInvitableAccountTypes;
private Result mContact;
private ForceLoadContentObserver mObserver;
private boolean mDestroyed;
@@ -113,6 +114,7 @@
private final ArrayList<Entity> mEntities;
private ArrayList<StreamItemEntry> mStreamItems;
private final HashMap<Long, DataStatus> mStatuses;
+ private final ArrayList<String> mInvitableAccountTypes;
private String mDirectoryDisplayName;
private String mDirectoryType;
@@ -147,6 +149,7 @@
mPhoneticName = null;
mStarred = false;
mPresence = null;
+ mInvitableAccountTypes = null;
}
/**
@@ -173,6 +176,7 @@
mPhoneticName = phoneticName;
mStarred = starred;
mPresence = presence;
+ mInvitableAccountTypes = Lists.newArrayList();
}
private Result(Result from) {
@@ -193,6 +197,7 @@
mEntities = from.mEntities;
mStreamItems = from.mStreamItems;
mStatuses = from.mStatuses;
+ mInvitableAccountTypes = from.mInvitableAccountTypes;
mDirectoryDisplayName = from.mDirectoryDisplayName;
mDirectoryType = from.mDirectoryType;
@@ -279,6 +284,10 @@
return mPresence;
}
+ public ArrayList<String> getInvitableAccontTypes() {
+ return mInvitableAccountTypes;
+ }
+
public ArrayList<Entity> getEntities() {
return mEntities;
}
@@ -568,6 +577,9 @@
loadStreamItems(result);
}
loadPhotoBinaryData(result);
+ if (mLoadInvitableAccountTypes) {
+ loadInvitableAccountTypes(result);
+ }
}
return result;
} catch (Exception e) {
@@ -718,6 +730,27 @@
}
}
+ private void loadInvitableAccountTypes(Result contactData) {
+ Map<String, AccountType> allInvitables =
+ AccountTypeManager.getInstance(getContext()).getInvitableAccountTypes();
+ if (allInvitables.isEmpty()) {
+ return;
+ }
+
+ HashMap<String, AccountType> result = new HashMap<String, AccountType>(allInvitables);
+
+ // Remove the ones that already has a raw contact in the current contact
+ for (Entity entity : contactData.getEntities()) {
+ final String type = entity.getEntityValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ if (!TextUtils.isEmpty(type)) {
+ result.remove(type);
+ }
+ }
+
+ // Set to mInvitableAccountTypes
+ contactData.mInvitableAccountTypes.addAll(result.keySet());
+ }
+
/**
* Extracts Contact level columns from the cursor.
*/
@@ -1058,15 +1091,16 @@
}
public ContactLoader(Context context, Uri lookupUri) {
- this(context, lookupUri, false, false);
+ this(context, lookupUri, false, false, false);
}
public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
- boolean loadStreamItems) {
+ boolean loadStreamItems, boolean loadInvitableAccountTypes) {
super(context);
mLookupUri = lookupUri;
mLoadGroupMetaData = loadGroupMetaData;
mLoadStreamItems = loadStreamItems;
+ mLoadInvitableAccountTypes = loadInvitableAccountTypes;
}
public Uri getLookupUri() {
diff --git a/src/com/android/contacts/ContactStatusUtil.java b/src/com/android/contacts/ContactStatusUtil.java
new file mode 100644
index 0000000..4aa24b0
--- /dev/null
+++ b/src/com/android/contacts/ContactStatusUtil.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.ContactsContract.StatusUpdates;
+
+/**
+ * Provides static function to get default contact status message.
+ */
+public class ContactStatusUtil {
+
+ private static final String TAG = "ContactStatusUtil";
+
+ public static String getStatusString(Context context, int presence) {
+ Resources resources = context.getResources();
+ switch (presence) {
+ case StatusUpdates.AVAILABLE:
+ return resources.getString(R.string.status_available);
+ case StatusUpdates.IDLE:
+ case StatusUpdates.AWAY:
+ return resources.getString(R.string.status_away);
+ case StatusUpdates.DO_NOT_DISTURB:
+ return resources.getString(R.string.status_busy);
+ case StatusUpdates.OFFLINE:
+ case StatusUpdates.INVISIBLE:
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index 034a8cc..daa6012 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -171,7 +171,7 @@
public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
Uri lookupUri = args.getParcelable(LOADER_ARG_CONTACT_URI);
return new ContactLoader(mContext, lookupUri, true /* loadGroupMetaData */,
- true /* loadStreamItems */);
+ true /* loadStreamItems */, false /* load invitable account types */);
}
@Override
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index e51fd5c..7322fc6 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -45,12 +45,13 @@
Contacts.STARRED, // 4
Contacts.CONTACT_PRESENCE, // 5
Contacts.CONTACT_CHAT_CAPABILITY, // 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
+ 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
};
protected static final String[] PROJECTION_DATA = new String[] {
@@ -61,11 +62,12 @@
Data.STARRED, // 4
Data.CONTACT_PRESENCE, // 5
Data.CONTACT_CHAT_CAPABILITY, // 6
- Data.PHOTO_ID, // 7
- Data.PHOTO_THUMBNAIL_URI, // 8
- Data.LOOKUP_KEY, // 9
- Data.PHONETIC_NAME, // 10
- Data.HAS_PHONE_NUMBER, // 11
+ 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
};
protected static final String[] FILTER_PROJECTION = new String[] {
@@ -76,13 +78,14 @@
Contacts.STARRED, // 4
Contacts.CONTACT_PRESENCE, // 5
Contacts.CONTACT_CHAT_CAPABILITY, // 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
+ 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
};
protected static final int CONTACT_ID_COLUMN_INDEX = 0;
@@ -92,13 +95,14 @@
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_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;
+ 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;
private CharSequence mUnknownNameText;
private int mDisplayNameColumnIndex;
@@ -304,9 +308,9 @@
view.showPhoneticName(cursor, CONTACT_PHONETIC_NAME_COLUMN_INDEX);
}
- protected void bindPresence(final ContactListItemView view, Cursor cursor) {
- view.showPresence(cursor, CONTACT_PRESENCE_STATUS_COLUMN_INDEX,
- CONTACT_CHAT_CAPABILITY_COLUMN_INDEX);
+ 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);
}
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 4fb6f1d..d69f880 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -17,6 +17,7 @@
package com.android.contacts.list;
import com.android.contacts.ContactPresenceIconUtil;
+import com.android.contacts.ContactStatusUtil;
import com.android.contacts.R;
import com.android.contacts.format.DisplayNameFormatter;
import com.android.contacts.format.PrefixHighlighter;
@@ -916,7 +917,7 @@
mStatusView.setSingleLine(true);
mStatusView.setEllipsize(getTextEllipsis());
mStatusView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
- mStatusView.setText("Put Status here"); // Temporary
+ mStatusView.setTextColor(Color.GRAY);
addView(mStatusView);
}
return mStatusView;
@@ -996,20 +997,33 @@
}
/**
- * Sets the proper icon (star or presence or nothing)
+ * Sets the proper icon (star or presence or nothing) and/or status message.
*/
- public void showPresence(Cursor cursor, int presenceColumnIndex, int capabilityColumnIndex) {
+ public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
+ int capabilityColumnIndex, int contactStatusColumnIndex) {
Drawable icon = null;
+ int presence = 0;
+ int chatCapability = 0;
if (!cursor.isNull(presenceColumnIndex)) {
- int status = cursor.getInt(presenceColumnIndex);
- int chatCapability = 0;
+ presence = cursor.getInt(presenceColumnIndex);
if (capabilityColumnIndex != 0 && !cursor.isNull(presenceColumnIndex)) {
chatCapability = cursor.getInt(capabilityColumnIndex);
}
icon = ContactPresenceIconUtil.getChatCapabilityIcon(
- getContext(), status, chatCapability);
+ getContext(), presence, chatCapability);
}
setPresence(icon);
+
+ String statusMessage = null;
+ if (contactStatusColumnIndex != 0 && !cursor.isNull(contactStatusColumnIndex)) {
+ statusMessage = cursor.getString(contactStatusColumnIndex);
+ }
+ // 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(getContext(), presence);
+ }
+ setStatus(statusMessage);
}
/**
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 715c331..6374c23 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -16,6 +16,7 @@
package com.android.contacts.list;
import com.android.contacts.ContactPhotoManager;
+import com.android.contacts.ContactStatusUtil;
import com.android.contacts.R;
import com.android.contacts.list.ContactTileAdapter.ContactEntry;
@@ -90,7 +91,8 @@
statusText = null;
} else {
statusText =
- (entry.status == null ? getStatusString(entry.presence) : entry.status);
+ (entry.status != null ? entry.status :
+ ContactStatusUtil.getStatusString(mContext, entry.presence));
}
mStatus.setText(statusText);
}
@@ -119,23 +121,6 @@
}
}
- private String getStatusString(int presence) {
- Resources resources = getResources();
- switch (presence) {
- case StatusUpdates.AVAILABLE:
- return resources.getString(R.string.status_available);
- case StatusUpdates.IDLE:
- case StatusUpdates.AWAY:
- return resources.getString(R.string.status_away);
- case StatusUpdates.DO_NOT_DISTURB:
- return resources.getString(R.string.status_busy);
- case StatusUpdates.OFFLINE:
- case StatusUpdates.INVISIBLE:
- default:
- return null;
- }
- }
-
public Uri getLookupUri() {
return mLookupUri;
}
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index c93b544..8b93888 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -234,7 +234,7 @@
}
bindName(view, cursor);
- bindPresence(view, cursor);
+ bindPresenceAndStatusMessage(view, cursor);
if (isSearchMode()) {
bindSearchSnippet(view, cursor);
diff --git a/src/com/android/contacts/list/LegacyContactListAdapter.java b/src/com/android/contacts/list/LegacyContactListAdapter.java
index ffc8fc3..b3ab2af 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.showPresence(cursor, PERSON_PRESENCE_STATUS_COLUMN_INDEX, 0);
+ view.showPresenceAndStatusMessage(cursor, PERSON_PRESENCE_STATUS_COLUMN_INDEX, 0, 0);
}
}
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/AccountType.java
index 70aa430..5de4340 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/AccountType.java
@@ -33,6 +33,7 @@
import android.provider.ContactsContract.RawContacts;
import android.widget.EditText;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -120,7 +121,7 @@
*/
public CharSequence getInviteContactActionLabel(Context context) {
return getResourceText(context, summaryResPackageName, getInviteContactActionResId(context),
- null);
+ "");
}
/**
@@ -342,4 +343,28 @@
public CharSequence inflateUsing(Context context, Cursor cursor);
public CharSequence inflateUsing(Context context, ContentValues values);
}
+
+ /**
+ * Compare two {@link AccountType} by their {@link AccountType#getDisplayLabel} with the
+ * current locale.
+ */
+ public static class DisplayLabelComparator implements Comparator<AccountType> {
+ private final Context mContext;
+ /** {@link Comparator} for the current locale. */
+ private final Collator mCollator = Collator.getInstance();
+
+ public DisplayLabelComparator(Context context) {
+ mContext = context;
+ }
+
+ private String getDisplayLabel(AccountType type) {
+ CharSequence label = type.getDisplayLabel(mContext);
+ return (label == null) ? "" : label.toString();
+ }
+
+ @Override
+ public int compare(AccountType lhs, AccountType rhs) {
+ return mCollator.compare(getDisplayLabel(lhs), getDisplayLabel(rhs));
+ }
+ }
}
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index d59aebd..3d7881b 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -111,7 +111,8 @@
// Not yet set-up (this can happen while the Configuration activity is visible)
return;
}
- final ContactLoader contactLoader = new ContactLoader(context, contactUri, false, true);
+ final ContactLoader contactLoader = new ContactLoader(context, contactUri, false, true,
+ false);
contactLoader.registerListener(0,
new ContactLoader.OnLoadCompleteListener<ContactLoader.Result>() {
@Override
diff --git a/tests/src/com/android/contacts/model/AccountTypeTest.java b/tests/src/com/android/contacts/model/AccountTypeTest.java
index 4898cf3..de66694 100644
--- a/tests/src/com/android/contacts/model/AccountTypeTest.java
+++ b/tests/src/com/android/contacts/model/AccountTypeTest.java
@@ -17,9 +17,14 @@
package com.android.contacts.model;
import com.android.contacts.tests.R;
+import com.google.common.collect.Lists;
import android.content.Context;
import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+
+import java.util.ArrayList;
+import java.util.Collections;
/**
* Test case for {@link AccountType}.
@@ -87,4 +92,53 @@
assertEquals(getTestContext().getString(externalResID),
accountType.getInviteContactActionLabel(c));
}
+
+ public void testDisplayLabelComparator() {
+ final AccountTypeForDisplayLabelTest EMPTY = new AccountTypeForDisplayLabelTest("");
+ final AccountTypeForDisplayLabelTest NULL = new AccountTypeForDisplayLabelTest(null);
+ final AccountTypeForDisplayLabelTest AA = new AccountTypeForDisplayLabelTest("aa");
+ final AccountTypeForDisplayLabelTest BBB = new AccountTypeForDisplayLabelTest("bbb");
+ final AccountTypeForDisplayLabelTest C = new AccountTypeForDisplayLabelTest("c");
+
+ assertTrue(compareDisplayLabel(AA, BBB) < 0);
+ assertTrue(compareDisplayLabel(BBB, C) < 0);
+ assertTrue(compareDisplayLabel(AA, C) < 0);
+ assertTrue(compareDisplayLabel(AA, AA) == 0);
+ assertTrue(compareDisplayLabel(BBB, AA) > 0);
+
+ assertTrue(compareDisplayLabel(EMPTY, AA) < 0);
+ assertTrue(compareDisplayLabel(EMPTY, NULL) == 0);
+ }
+
+ private int compareDisplayLabel(AccountType lhs, AccountType rhs) {
+ return new AccountType.DisplayLabelComparator(getContext()).compare(lhs, rhs);
+ }
+
+ private class AccountTypeForDisplayLabelTest extends AccountType {
+ private final String mDisplayLabel;
+
+ public AccountTypeForDisplayLabelTest(String displayLabel) {
+ mDisplayLabel = displayLabel;
+ }
+
+ @Override
+ public CharSequence getDisplayLabel(Context context) {
+ return mDisplayLabel;
+ }
+
+ @Override
+ public int getHeaderColor(Context context) {
+ return 0;
+ }
+
+ @Override
+ public int getSideBarColor(Context context) {
+ return 0;
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+ }
}