Allow for multiple call icons in the call log.
This commit adds support for having multiple call icons on a single
entry, to handle group entries.
When the group is represented as text, we currently use only the first
call type, but, in a follow-up, I will use an additional counter.
Change-Id: Iaa9d1c84eb926c1500bf0a439d45ce59314bd198
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index a1d2bb7..d08b76a 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -304,8 +304,8 @@
setListAdapter(adapter);
}
mPhoneCallDetailsHelper.setPhoneCallDetails(mPhoneCallDetailsViews,
- new PhoneCallDetails(mNumber, numberText, callType, date, nameText,
- numberType, numberLabel), false);
+ new PhoneCallDetails(mNumber, numberText, new int[]{ callType }, date,
+ nameText, numberType, numberLabel), false);
loadContactPhotos(photoId);
} else {
diff --git a/src/com/android/contacts/PhoneCallDetails.java b/src/com/android/contacts/PhoneCallDetails.java
index c5c37df..7b02a88 100644
--- a/src/com/android/contacts/PhoneCallDetails.java
+++ b/src/com/android/contacts/PhoneCallDetails.java
@@ -27,8 +27,12 @@
public final CharSequence number;
/** The formatted version of {@link #number}. */
public final CharSequence formattedNumber;
- /** The type of call, as defined in the call log table, e.g., {@link Calls#INCOMING_TYPE}. */
- public final int callType;
+ /**
+ * The type of calls, as defined in the call log table, e.g., {@link Calls#INCOMING_TYPE}.
+ * <p>
+ * There might be multiple types if this represents a set of entries grouped together.
+ */
+ public final int[] callTypes;
/** The date of the call, in milliseconds since the epoch. */
public final long date;
/** The name of the contact, or the empty string. */
@@ -39,17 +43,17 @@
public final CharSequence numberLabel;
/** Create the details for a call with a number not associated with a contact. */
- public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int callType,
+ public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
long date) {
- this(number, formattedNumber, callType, date, "", 0, "");
+ this(number, formattedNumber, callTypes, date, "", 0, "");
}
/** Create the details for a call with a number associated with a contact. */
- public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int callType,
+ public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
long date, CharSequence name, int numberType, CharSequence numberLabel) {
this.number = number;
this.formattedNumber = formattedNumber;
- this.callType = callType;
+ this.callTypes = callTypes;
this.date = date;
this.name = name;
this.numberType = numberType;
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index 4605799..7f73b04 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -86,58 +86,22 @@
public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details,
boolean useIcons) {
if (useIcons) {
- final Drawable callTypeDrawable;
- switch (details.callType) {
- case Calls.INCOMING_TYPE:
- callTypeDrawable = mIncomingDrawable;
- break;
-
- case Calls.OUTGOING_TYPE:
- callTypeDrawable = mOutgoingDrawable;
- break;
-
- case Calls.MISSED_TYPE:
- callTypeDrawable = mMissedDrawable;
- break;
-
- case Calls.VOICEMAIL_TYPE:
- callTypeDrawable = mVoicemailDrawable;
- break;
-
- default:
- throw new IllegalArgumentException("invalid call type: " + details.callType);
- }
- ImageView callTypeImage = new ImageView(mContext);
- callTypeImage.setImageDrawable(callTypeDrawable);
views.callTypeIcons.removeAllViews();
- views.callTypeIcons.addView(callTypeImage);
-
+ int count = details.callTypes.length;
+ for (int callType : details.callTypes) {
+ ImageView callTypeImage = new ImageView(mContext);
+ callTypeImage.setImageDrawable(getCallTypeDrawable(callType));
+ views.callTypeIcons.addView(callTypeImage);
+ }
views.callTypeIcons.setVisibility(View.VISIBLE);
views.callTypeText.setVisibility(View.GONE);
views.callTypeSeparator.setVisibility(View.GONE);
} else {
String callTypeName;
- switch (details.callType) {
- case Calls.INCOMING_TYPE:
- callTypeName = mIncomingName;
- break;
-
- case Calls.OUTGOING_TYPE:
- callTypeName = mOutgoingName;
- break;
-
- case Calls.MISSED_TYPE:
- callTypeName = mMissedName;
- break;
-
- case Calls.VOICEMAIL_TYPE:
- callTypeName = mVoicemailName;
- break;
-
- default:
- throw new IllegalArgumentException("invalid call type: " + details.callType);
- }
- views.callTypeText.setText(callTypeName);
+ // Use the name of the first call type.
+ // TODO: We should update this to handle the text for multiple calls as well.
+ int callType = details.callTypes[0];
+ views.callTypeText.setText(getCallTypeText(callType));
views.callTypeIcons.removeAllViews();
views.callTypeText.setVisibility(View.VISIBLE);
@@ -167,7 +131,7 @@
} else {
nameText = details.name;
CharSequence displayNumber = getDisplayNumber(details.number, details.formattedNumber);
- if (details.callType != 0 && numberFormattedLabel != null) {
+ if (numberFormattedLabel != null) {
numberText = FormatUtils.applyStyleToSpan(Typeface.BOLD,
numberFormattedLabel + " " + displayNumber, 0,
numberFormattedLabel.length(),
@@ -191,6 +155,46 @@
}
}
+ /** Returns the text used to represent the given call type. */
+ private String getCallTypeText(int callType) {
+ switch (callType) {
+ case Calls.INCOMING_TYPE:
+ return mIncomingName;
+
+ case Calls.OUTGOING_TYPE:
+ return mOutgoingName;
+
+ case Calls.MISSED_TYPE:
+ return mMissedName;
+
+ case Calls.VOICEMAIL_TYPE:
+ return mVoicemailName;
+
+ default:
+ throw new IllegalArgumentException("invalid call type: " + callType);
+ }
+ }
+
+ /** Returns the drawable of the icon associated with the given call type. */
+ private Drawable getCallTypeDrawable(int callType) {
+ switch (callType) {
+ case Calls.INCOMING_TYPE:
+ return mIncomingDrawable;
+
+ case Calls.OUTGOING_TYPE:
+ return mOutgoingDrawable;
+
+ case Calls.MISSED_TYPE:
+ return mMissedDrawable;
+
+ case Calls.VOICEMAIL_TYPE:
+ return mVoicemailDrawable;
+
+ default:
+ throw new IllegalArgumentException("invalid call type: " + callType);
+ }
+ }
+
private CharSequence getDisplayNumber(CharSequence number, CharSequence formattedNumber) {
if (TextUtils.isEmpty(number)) {
return "";
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 1f8e84b..11f8965 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -635,12 +635,11 @@
* @param c the cursor pointing to the entry in the call log
* @param count the number of entries in the current item, greater than 1 if it is a group
*/
- public void bindView(View view, Cursor c, int count) {
+ private void bindView(View view, Cursor c, int count) {
final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
String number = c.getString(CallLogQuery.NUMBER);
long date = c.getLong(CallLogQuery.DATE);
- int callType = c.getInt(CallLogQuery.CALL_TYPE);
final String formattedNumber;
String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
// Store away the number so we can call it directly if you click on the call icon
@@ -697,11 +696,12 @@
views.callView.setVisibility(View.VISIBLE);
}
+ int[] callTypes = getCallTypes(c, count);
final PhoneCallDetails details;
if (TextUtils.isEmpty(name)) {
- details = new PhoneCallDetails(number, formattedNumber, callType, date);
+ details = new PhoneCallDetails(number, formattedNumber, callTypes, date);
} else {
- details = new PhoneCallDetails(number, formattedNumber, callType, date, name,
+ details = new PhoneCallDetails(number, formattedNumber, callTypes, date, name,
ntype, label);
}
mCallLogViewsHelper.setPhoneCallDetails(views, details , true);
@@ -718,6 +718,24 @@
}
}
+ /**
+ * Returns the call types for the given number of items in the cursor.
+ * <p>
+ * It uses the next {@code count} rows in the cursor to extract the types.
+ * <p>
+ * It position in the cursor is unchanged by this function.
+ */
+ private int[] getCallTypes(Cursor cursor, int count) {
+ int position = cursor.getPosition();
+ int[] callTypes = new int[count];
+ for (int index = 0; index < count; ++index) {
+ callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE);
+ cursor.moveToNext();
+ }
+ cursor.moveToPosition(position);
+ return callTypes;
+ }
+
private void bindQuickContact(QuickContactBadge view, long photoId, long contactId,
String lookupKey) {
view.assignContactUri(getContactUri(contactId, lookupKey));
diff --git a/src/com/android/contacts/calllog/CallLogListItemHelper.java b/src/com/android/contacts/calllog/CallLogListItemHelper.java
index 462b0b3..e4630e9 100644
--- a/src/com/android/contacts/calllog/CallLogListItemHelper.java
+++ b/src/com/android/contacts/calllog/CallLogListItemHelper.java
@@ -61,8 +61,9 @@
boolean useIcons) {
mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details, useIcons);
if (views.callView != null) {
+ // The type of icon, call or play, is determined by the first call in the group.
views.callView.setImageDrawable(
- details.callType == Calls.VOICEMAIL_TYPE ? mPlayDrawable : mCallDrawable);
+ details.callTypes[0] == Calls.VOICEMAIL_TYPE ? mPlayDrawable : mCallDrawable);
views.callView.setVisibility(
canPlaceCallsTo(details.number) ? View.VISIBLE : View.INVISIBLE);
}
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
index 8b8baae..353c2ec 100644
--- a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -131,16 +131,16 @@
}
public void testSetPhoneCallDetails_CallTypeIcons() {
- setPhoneCallDetailsWithCallType(Calls.INCOMING_TYPE, true);
+ setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE);
assertCallTypeIconsEquals(TEST_INCOMING_DRAWABLE);
- setPhoneCallDetailsWithCallType(Calls.OUTGOING_TYPE, true);
+ setPhoneCallDetailsWithCallTypeIcons(Calls.OUTGOING_TYPE);
assertCallTypeIconsEquals(TEST_OUTGOING_DRAWABLE);
- setPhoneCallDetailsWithCallType(Calls.MISSED_TYPE, true);
+ setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE);
assertCallTypeIconsEquals(TEST_MISSED_DRAWABLE);
- setPhoneCallDetailsWithCallType(Calls.VOICEMAIL_TYPE, true);
+ setPhoneCallDetailsWithCallTypeIcons(Calls.VOICEMAIL_TYPE);
assertCallTypeIconsEquals(TEST_VOICEMAIL_DRAWABLE);
}
@@ -148,16 +148,16 @@
LocaleTestUtils localeTestUtils = new LocaleTestUtils(getContext());
localeTestUtils.setLocale(Locale.US);
try {
- setPhoneCallDetailsWithCallType(Calls.INCOMING_TYPE, false);
+ setPhoneCallDetailsWithCallTypeText(Calls.INCOMING_TYPE);
assertCallTypeTextEquals("Incoming call");
- setPhoneCallDetailsWithCallType(Calls.OUTGOING_TYPE, false);
+ setPhoneCallDetailsWithCallTypeText(Calls.OUTGOING_TYPE);
assertCallTypeTextEquals("Outgoing call");
- setPhoneCallDetailsWithCallType(Calls.MISSED_TYPE, false);
+ setPhoneCallDetailsWithCallTypeText(Calls.MISSED_TYPE);
assertCallTypeTextEquals("Missed call");
- setPhoneCallDetailsWithCallType(Calls.VOICEMAIL_TYPE, false);
+ setPhoneCallDetailsWithCallTypeText(Calls.VOICEMAIL_TYPE);
assertCallTypeTextEquals("Voicemail");
} finally {
localeTestUtils.restoreLocale();
@@ -203,21 +203,32 @@
/** Sets the phone call details with default values and the given number. */
private void setPhoneCallDetailsWithNumber(String number, String formattedNumber) {
mHelper.setPhoneCallDetails(mViews,
- new PhoneCallDetails(number, formattedNumber, Calls.INCOMING_TYPE, TEST_DATE),
+ new PhoneCallDetails(number, formattedNumber, new int[]{ Calls.INCOMING_TYPE },
+ TEST_DATE),
false);
}
/** Sets the phone call details with default values and the given date. */
private void setPhoneCallDetailsWithDate(long date) {
mHelper.setPhoneCallDetails(mViews,
- new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, Calls.INCOMING_TYPE, date),
+ new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER,
+ new int[]{ Calls.INCOMING_TYPE }, date),
false);
}
- /** Sets the phone call details with default values and the given call type. */
- private void setPhoneCallDetailsWithCallType(int callType, boolean useIcons) {
+ /** Sets the phone call details with default values and the given call types using icons. */
+ private void setPhoneCallDetailsWithCallTypeIcons(int... callTypes) {
+ setPhoneCallDetailsWithCallTypes(true, callTypes);
+ }
+
+ /** Sets the phone call details with default values and the given call types using text. */
+ private void setPhoneCallDetailsWithCallTypeText(int... callTypes) {
+ setPhoneCallDetailsWithCallTypes(false, callTypes);
+ }
+
+ private void setPhoneCallDetailsWithCallTypes(boolean useIcons, int... callTypes) {
mHelper.setPhoneCallDetails(mViews,
- new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, callType, TEST_DATE),
+ new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, callTypes, TEST_DATE),
useIcons);
}
}
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
index 2665c13..a8714b4 100644
--- a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -86,35 +86,35 @@
super.tearDown();
}
- public void testSetContactNumberOnly() {
+ public void testSetPhoneCallDetails() {
setPhoneCallDetailsWithNumber("12125551234", "1-212-555-1234");
assertEquals(View.VISIBLE, mViews.callView.getVisibility());
assertEquals(TEST_CALL_DRAWABLE, mViews.callView.getDrawable());
}
- public void testSetContactNumberOnly_Unknown() {
+ public void testSetPhoneCallDetails_Unknown() {
setPhoneCallDetailsWithNumber(CallerInfo.UNKNOWN_NUMBER, CallerInfo.UNKNOWN_NUMBER);
assertEquals(View.INVISIBLE, mViews.callView.getVisibility());
}
- public void testSetContactNumberOnly_Private() {
+ public void testSetPhoneCallDetails_Private() {
setPhoneCallDetailsWithNumber(CallerInfo.PRIVATE_NUMBER, CallerInfo.PRIVATE_NUMBER);
assertEquals(View.INVISIBLE, mViews.callView.getVisibility());
}
- public void testSetContactNumberOnly_Payphone() {
+ public void testSetPhoneCallDetails_Payphone() {
setPhoneCallDetailsWithNumber(CallerInfo.PAYPHONE_NUMBER, CallerInfo.PAYPHONE_NUMBER);
assertEquals(View.INVISIBLE, mViews.callView.getVisibility());
}
- public void testSetContactNumberOnly_VoicemailNumber() {
+ public void testSetPhoneCallDetails_VoicemailNumber() {
setPhoneCallDetailsWithNumber(TEST_VOICEMAIL_NUMBER, TEST_VOICEMAIL_NUMBER);
assertEquals(View.VISIBLE, mViews.callView.getVisibility());
assertEquals(TEST_CALL_DRAWABLE, mViews.callView.getDrawable());
}
- public void testSetContactNumberOnly_Voicemail() {
- setPhoneCallDetailsWithType(Calls.VOICEMAIL_TYPE);
+ public void testSetPhoneCallDetails_Voicemail() {
+ setPhoneCallDetailsWithTypes(Calls.VOICEMAIL_TYPE);
assertEquals(View.VISIBLE, mViews.callView.getVisibility());
assertEquals(TEST_PLAY_DRAWABLE, mViews.callView.getDrawable());
}
@@ -122,13 +122,14 @@
/** Sets the details of a phone call using the specified phone number. */
private void setPhoneCallDetailsWithNumber(String number, String formattedNumber) {
mHelper.setPhoneCallDetails(mViews,
- new PhoneCallDetails(number, formattedNumber, Calls.INCOMING_TYPE, TEST_DATE),
+ new PhoneCallDetails(number, formattedNumber, new int[]{ Calls.INCOMING_TYPE },
+ TEST_DATE),
true);
}
/** Sets the details of a phone call using the specified call type. */
- private void setPhoneCallDetailsWithType(int type) {
+ private void setPhoneCallDetailsWithTypes(int... types) {
mHelper.setPhoneCallDetails(mViews,
- new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, type, TEST_DATE), true);
+ new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, types, TEST_DATE), true);
}
}