Merge "Contacts NFC sharing: address review comments."
diff --git a/res/layout-xlarge/account_selector_list_item.xml b/res/layout-xlarge/account_selector_list_item.xml
index 38acfc5..32fd0a5 100644
--- a/res/layout-xlarge/account_selector_list_item.xml
+++ b/res/layout-xlarge/account_selector_list_item.xml
@@ -16,9 +16,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
->
+ android:layout_height="?android:attr/listPreferredItemHeight">
<ImageView android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/account_selector_list_item.xml b/res/layout/account_selector_list_item.xml
index 6fe2a50..7930f54 100644
--- a/res/layout/account_selector_list_item.xml
+++ b/res/layout/account_selector_list_item.xml
@@ -16,10 +16,9 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/account_selector_min_item_height"
android:paddingLeft="@dimen/account_selector_horizontal_margin"
- android:paddingRight="@dimen/account_selector_horizontal_margin"
- android:minHeight="@dimen/account_selector_min_item_height" >
+ android:paddingRight="@dimen/account_selector_horizontal_margin" >
<TextView android:id="@android:id/text1"
android:layout_width="match_parent"
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index eff5c41..b3043d4 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -44,7 +44,6 @@
import android.os.Message;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
@@ -53,7 +52,6 @@
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -154,25 +152,6 @@
public static ContactInfo EMPTY = new ContactInfo();
}
- public static final class CallLogListItemViews {
- public TextView line1View;
- public TextView labelView;
- public TextView numberView;
- public TextView dateView;
- public ImageView iconView;
- /** The icon used to place a call to the contact. Only present for non-group entries. */
- public View callView;
- /** The icon used to expand and collapse an entry. Only present for group entries. */
- public ImageView groupIndicator;
- /**
- * The text view containing the number of items in the group. Only present for group
- * entries.
- */
- public TextView groupSize;
- /** The contact photo for the contact. Only present for group and stand alone entries. */
- public ImageView photoView;
- }
-
public static final class CallerInfoQuery {
public String number;
public int position;
@@ -195,9 +174,8 @@
private boolean mFirst;
private Thread mCallerIdThread;
- private Drawable mDrawableIncoming;
- private Drawable mDrawableOutgoing;
- private Drawable mDrawableMissed;
+ /** Instance of helper class for managing views. */
+ private final CallLogListItemHelper mCallLogViewsHelper;
/**
* Reusable char array buffers.
@@ -254,14 +232,16 @@
mRequests = new LinkedList<CallerInfoQuery>();
mPreDrawListener = null;
- mDrawableIncoming = getResources().getDrawable(
+ Drawable drawableIncoming = getResources().getDrawable(
R.drawable.ic_call_log_list_incoming_call);
- mDrawableOutgoing = getResources().getDrawable(
+ Drawable drawableOutgoing = getResources().getDrawable(
R.drawable.ic_call_log_list_outgoing_call);
- mDrawableMissed = getResources().getDrawable(
+ Drawable drawableMissed = getResources().getDrawable(
R.drawable.ic_call_log_list_missed_call);
mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
+ mCallLogViewsHelper = new CallLogListItemHelper(getResources(), mVoiceMailNumber,
+ drawableIncoming, drawableOutgoing, drawableMissed);
}
/**
@@ -702,7 +682,7 @@
// Format the cached call_log phone number
formattedNumber = formatPhoneNumber(number, null, countryIso);
}
- // Set the text lines and call icon.
+
// Assumes the call back feature is on most of the
// time. For private and unknown numbers: hide it.
if (views.callView != null) {
@@ -710,102 +690,21 @@
}
if (!TextUtils.isEmpty(name)) {
- views.line1View.setText(name);
- views.labelView.setVisibility(View.VISIBLE);
-
- // "type" and "label" are currently unused for SIP addresses.
- CharSequence numberLabel = null;
- if (!PhoneNumberUtils.isUriNumber(number)) {
- numberLabel = Phone.getTypeLabel(getResources(), ntype, label);
- }
- views.numberView.setVisibility(View.VISIBLE);
- views.numberView.setText(formattedNumber);
- if (!TextUtils.isEmpty(numberLabel)) {
- views.labelView.setText(numberLabel);
- views.labelView.setVisibility(View.VISIBLE);
-
- // Zero out the numberView's left margin (see below)
- ViewGroup.MarginLayoutParams numberLP =
- (ViewGroup.MarginLayoutParams) views.numberView.getLayoutParams();
- numberLP.leftMargin = 0;
- views.numberView.setLayoutParams(numberLP);
- } else {
- // There's nothing to display in views.labelView, so hide it.
- // We can't set it to View.GONE, since it's the anchor for
- // numberView in the RelativeLayout, so make it INVISIBLE.
- // Also, we need to manually *subtract* some left margin from
- // numberView to compensate for the right margin built in to
- // labelView (otherwise the number will be indented by a very
- // slight amount).
- // TODO: a cleaner fix would be to contain both the label and
- // number inside a LinearLayout, and then set labelView *and*
- // its padding to GONE when there's no label to display.
- views.labelView.setText(null);
- views.labelView.setVisibility(View.INVISIBLE);
-
- ViewGroup.MarginLayoutParams labelLP =
- (ViewGroup.MarginLayoutParams) views.labelView.getLayoutParams();
- ViewGroup.MarginLayoutParams numberLP =
- (ViewGroup.MarginLayoutParams) views.numberView.getLayoutParams();
- // Equivalent to setting android:layout_marginLeft in XML
- numberLP.leftMargin = -labelLP.rightMargin;
- views.numberView.setLayoutParams(numberLP);
- }
+ mCallLogViewsHelper.setContactNameLabelAndNumber(views, name, number, ntype, label,
+ formattedNumber);
} else {
- if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
- number = getString(R.string.unknown);
- if (views.callView != null) {
- views.callView.setVisibility(View.INVISIBLE);
- }
- } else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
- number = getString(R.string.private_num);
- if (views.callView != null) {
- views.callView.setVisibility(View.INVISIBLE);
- }
- } else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
- number = getString(R.string.payphone);
- } else if (PhoneNumberUtils.extractNetworkPortion(number)
- .equals(mVoiceMailNumber)) {
- number = getString(R.string.voicemail);
- } else {
- // Just a raw number, and no cache, so format it nicely
- number = formatPhoneNumber(number, null, countryIso);
- }
-
- views.line1View.setText(number);
- views.numberView.setVisibility(View.GONE);
- views.labelView.setVisibility(View.GONE);
+ // TODO: Do we need to format the number again? Is formattedNumber already storing
+ // this value?
+ mCallLogViewsHelper.setContactNumberOnly(views, number,
+ formatPhoneNumber(number, null, countryIso));
}
-
+ mCallLogViewsHelper.setDate(views, c.getLong(CallLogQuery.DATE),
+ System.currentTimeMillis());
+ mCallLogViewsHelper.setCallType(views, c.getInt(CallLogQuery.CALL_TYPE));
if (views.photoView != null) {
mContactPhotoManager.loadPhoto(views.photoView, photoId);
}
- long date = c.getLong(CallLogQuery.DATE);
-
- // Set the date/time field by mixing relative and absolute times.
- int flags = DateUtils.FORMAT_ABBREV_RELATIVE;
-
- views.dateView.setText(DateUtils.getRelativeTimeSpanString(date,
- System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, flags));
-
- if (views.iconView != null) {
- int type = c.getInt(CallLogQuery.CALL_TYPE);
- // Set the icon
- switch (type) {
- case Calls.INCOMING_TYPE:
- views.iconView.setImageDrawable(mDrawableIncoming);
- break;
-
- case Calls.OUTGOING_TYPE:
- views.iconView.setImageDrawable(mDrawableOutgoing);
- break;
-
- case Calls.MISSED_TYPE:
- views.iconView.setImageDrawable(mDrawableMissed);
- break;
- }
- }
// Listen for the first draw
if (mPreDrawListener == null) {
diff --git a/src/com/android/contacts/calllog/CallLogListItemHelper.java b/src/com/android/contacts/calllog/CallLogListItemHelper.java
new file mode 100644
index 0000000..7697872
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallLogListItemHelper.java
@@ -0,0 +1,197 @@
+/*
+ * 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.calllog;
+
+import com.android.contacts.R;
+import com.android.internal.telephony.CallerInfo;
+
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Helper class to fill in the views of a call log entry.
+ */
+/*package*/ class CallLogListItemHelper {
+ /** The resources used to look up strings. */
+ private final Resources mResources;
+ /** The voicemail number. */
+ private final String mVoiceMailNumber;
+ /** Icon for incoming calls. */
+ private final Drawable mDrawableIncoming;
+ /** Icon for outgoing calls. */
+ private final Drawable mDrawableOutgoing;
+ /** Icon for missed calls. */
+ private final Drawable mDrawableMissed;
+
+ /**
+ * Creates a new helper instance.
+ *
+ * @param resources used to look up strings
+ * @param voicemailNumber the voicemail number, used to determine if a call was to voicemail
+ * @param drawableIncoming the icon drawn besides an incoming call entry
+ * @param drawableOutgoing the icon drawn besides an outgoing call entry
+ * @param drawableMissed the icon drawn besides a missed call entry
+ */
+ public CallLogListItemHelper(Resources resources, String voicemailNumber,
+ Drawable drawableIncoming, Drawable drawableOutgoing, Drawable drawableMissed) {
+ mResources = resources;
+ mVoiceMailNumber = voicemailNumber;
+ mDrawableIncoming = drawableIncoming;
+ mDrawableOutgoing = drawableOutgoing;
+ mDrawableMissed = drawableMissed;
+ }
+
+ /**
+ * Sets the name, label, and number for a contact.
+ *
+ * @param views the views to populate
+ * @param name the name of the contact
+ * @param number the number of the contact
+ * @param numberType the type of the number as it appears in the contact, e.g.,
+ * {@link Phone#TYPE_HOME}
+ * @param label the label of the number, only used if numberType is {@link Phone#TYPE_CUSTOM}
+ * @param formattedNumber the formatted version of the number above
+ */
+ public void setContactNameLabelAndNumber(CallLogListItemViews views, String name, String number,
+ int numberType, String label, String formattedNumber) {
+ views.line1View.setText(name);
+ views.labelView.setVisibility(View.VISIBLE);
+
+ // "type" and "label" are currently unused for SIP addresses.
+ CharSequence numberLabel = null;
+ if (!PhoneNumberUtils.isUriNumber(number)) {
+ numberLabel = Phone.getTypeLabel(mResources, numberType, label);
+ }
+ views.numberView.setVisibility(View.VISIBLE);
+ views.numberView.setText(formattedNumber);
+ if (!TextUtils.isEmpty(numberLabel)) {
+ views.labelView.setText(numberLabel);
+ views.labelView.setVisibility(View.VISIBLE);
+
+ // Zero out the numberView's left margin (see below)
+ ViewGroup.MarginLayoutParams numberLP =
+ (ViewGroup.MarginLayoutParams) views.numberView.getLayoutParams();
+ numberLP.leftMargin = 0;
+ views.numberView.setLayoutParams(numberLP);
+ } else {
+ // There's nothing to display in views.labelView, so hide it.
+ // We can't set it to View.GONE, since it's the anchor for
+ // numberView in the RelativeLayout, so make it INVISIBLE.
+ // Also, we need to manually *subtract* some left margin from
+ // numberView to compensate for the right margin built in to
+ // labelView (otherwise the number will be indented by a very
+ // slight amount).
+ // TODO: a cleaner fix would be to contain both the label and
+ // number inside a LinearLayout, and then set labelView *and*
+ // its padding to GONE when there's no label to display.
+ views.labelView.setText(null);
+ views.labelView.setVisibility(View.INVISIBLE);
+
+ ViewGroup.MarginLayoutParams labelLP =
+ (ViewGroup.MarginLayoutParams) views.labelView.getLayoutParams();
+ ViewGroup.MarginLayoutParams numberLP =
+ (ViewGroup.MarginLayoutParams) views.numberView.getLayoutParams();
+ // Equivalent to setting android:layout_marginLeft in XML
+ numberLP.leftMargin = -labelLP.rightMargin;
+ views.numberView.setLayoutParams(numberLP);
+ }
+ }
+
+ /**
+ * Sets the number in a call log entry.
+ * <p>
+ * To be used if we do not have a contact with this number.
+ *
+ * @param views the views to populate
+ * @param number the number of the contact
+ * @param formattedNumber the formatted version of the number above
+ */
+ public void setContactNumberOnly(final CallLogListItemViews views, String number,
+ String formattedNumber) {
+ if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
+ number = mResources.getString(R.string.unknown);
+ if (views.callView != null) {
+ views.callView.setVisibility(View.INVISIBLE);
+ }
+ } else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
+ number = mResources.getString(R.string.private_num);
+ if (views.callView != null) {
+ views.callView.setVisibility(View.INVISIBLE);
+ }
+ } else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
+ number = mResources.getString(R.string.payphone);
+ if (views.callView != null) {
+ views.callView.setVisibility(View.INVISIBLE);
+ }
+ } else if (PhoneNumberUtils.extractNetworkPortion(number)
+ .equals(mVoiceMailNumber)) {
+ number = mResources.getString(R.string.voicemail);
+ } else {
+ // Just a phone number, so use the formatted version of the number.
+ number = formattedNumber;
+ }
+
+ views.line1View.setText(number);
+ views.numberView.setVisibility(View.GONE);
+ views.labelView.setVisibility(View.GONE);
+ }
+
+ /**
+ * Sets the date in the views.
+ *
+ * @param views the views to populate
+ * @param date the date of the call log entry
+ * @param now the current time relative to which the date should be formatted
+ */
+ public void setDate(final CallLogListItemViews views, long date, long now) {
+ views.dateView.setText(
+ DateUtils.getRelativeTimeSpanString(
+ date, now, DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE));
+ }
+
+ /**
+ * Sets the type of the call in the views.
+ *
+ * @param views the views to populate
+ * @param type the type of call log entry, e.g., {@link Calls#INCOMING_TYPE}
+ */
+ public void setCallType(final CallLogListItemViews views, int type) {
+ if (views.iconView != null) {
+ // Set the icon
+ switch (type) {
+ case Calls.INCOMING_TYPE:
+ views.iconView.setImageDrawable(mDrawableIncoming);
+ break;
+
+ case Calls.OUTGOING_TYPE:
+ views.iconView.setImageDrawable(mDrawableOutgoing);
+ break;
+
+ case Calls.MISSED_TYPE:
+ views.iconView.setImageDrawable(mDrawableMissed);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/com/android/contacts/calllog/CallLogListItemViews.java b/src/com/android/contacts/calllog/CallLogListItemViews.java
new file mode 100644
index 0000000..65b92e2
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallLogListItemViews.java
@@ -0,0 +1,52 @@
+/*
+ * 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.calllog;
+
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Simple value object containing the various views within a call log entry.
+ */
+public final class CallLogListItemViews {
+ /** The first line in the call log entry, containing either the name or the number. */
+ public TextView line1View;
+ /** The label associated with the phone number. */
+ public TextView labelView;
+ /**
+ * The number the call was from or to.
+ * <p>
+ * Only filled in if the number is not already in the first line, i.e., {@link #line1View}.
+ */
+ public TextView numberView;
+ /** The date of the call. */
+ public TextView dateView;
+ /** The icon indicating the type of call. */
+ public ImageView iconView;
+ /** The icon used to place a call to the contact. Only present for non-group entries. */
+ public View callView;
+ /** The icon used to expand and collapse an entry. Only present for group entries. */
+ public ImageView groupIndicator;
+ /**
+ * The text view containing the number of items in the group. Only present for group
+ * entries.
+ */
+ public TextView groupSize;
+ /** The contact photo for the contact. Only present for group and stand alone entries. */
+ public ImageView photoView;
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 8cab92a..ba2794d 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -670,7 +670,8 @@
@Override
public void onClick(View v) {
final ListPopupWindow popup = new ListPopupWindow(mContext, null);
- final AccountsListAdapter adapter = new AccountsListAdapter(mContext, true);
+ final AccountsListAdapter adapter =
+ new AccountsListAdapter(mContext, true, currentAccount);
popup.setWidth(anchorView.getWidth());
popup.setAnchorView(anchorView);
popup.setAdapter(adapter);
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index 97a9f84..1a8b3ea 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -17,8 +17,8 @@
package com.android.contacts.util;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountType;
+import com.android.contacts.model.AccountTypeManager;
import android.accounts.Account;
import android.content.Context;
@@ -29,6 +29,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -41,9 +42,25 @@
private final Context mContext;
public AccountsListAdapter(Context context, boolean writableOnly) {
+ this(context, writableOnly, null);
+ }
+
+ /**
+ * @param currentAccount the Account currently selected by the user, which should come
+ * first in the list. Can be null.
+ */
+ public AccountsListAdapter(Context context, boolean writableOnly,
+ Account currentAccount) {
mContext = context;
mAccountTypes = AccountTypeManager.getInstance(context);
- mAccounts = mAccountTypes.getAccounts(writableOnly);
+ // We don't want possible side-effect toward AccountTypeManager
+ mAccounts = new ArrayList<Account>(mAccountTypes.getAccounts(writableOnly));
+ if (currentAccount != null
+ && !mAccounts.isEmpty()
+ && !mAccounts.get(0).equals(currentAccount)
+ && mAccounts.remove(currentAccount)) {
+ mAccounts.add(0, currentAccount);
+ }
mInflater = LayoutInflater.from(context);
}
diff --git a/tests/src/com/android/contacts/activities/CallLogActivityTests.java b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
index 1dbd56f..8e08280 100644
--- a/tests/src/com/android/contacts/activities/CallLogActivityTests.java
+++ b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
@@ -18,7 +18,7 @@
import com.android.contacts.R;
import com.android.contacts.calllog.CallLogFragment;
-import com.android.contacts.calllog.CallLogFragment.CallLogListItemViews;
+import com.android.contacts.calllog.CallLogListItemViews;
import com.android.internal.telephony.CallerInfo;
import android.content.res.Resources;
@@ -93,7 +93,7 @@
private HashMap<Integer, Bitmap> mCallTypeIcons;
// An item in the call list. All the methods performing checks use it.
- private CallLogFragment.CallLogListItemViews mItem;
+ private CallLogListItemViews mItem;
// The list of views representing the data in the DB. View are in
// reverse order compare to the DB.
private View[] mList;
@@ -300,7 +300,7 @@
if (null == mList[i]) {
break;
}
- mItem = (CallLogFragment.CallLogListItemViews) mList[i].getTag();
+ mItem = (CallLogListItemViews) mList[i].getTag();
// callView tag is the phone number.
String number = (String) mItem.callView.getTag();
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
new file mode 100644
index 0000000..958ece5
--- /dev/null
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.calllog;
+
+import com.android.contacts.R;
+import com.android.contacts.util.LocaleTestUtils;
+import com.android.internal.telephony.CallerInfo;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+import android.test.AndroidTestCase;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
+/**
+ * Unit tests for {@link CallLogListItemHelper}.
+ */
+public class CallLogListItemHelperTest extends AndroidTestCase {
+ /** A test voicemail number. */
+ private static final String TEST_VOICEMAIL_NUMBER = "123";
+ /** A drawable to be used for incoming calls. */
+ private static final Drawable TEST_INCOMING_DRAWABLE = new ColorDrawable(Color.BLACK);
+ /** A drawable to be used for outgoing calls. */
+ private static final Drawable TEST_OUTGOING_DRAWABLE = new ColorDrawable(Color.BLUE);
+ /** A drawable to be used for missed calls. */
+ private static final Drawable TEST_MISSED_DRAWABLE = new ColorDrawable(Color.RED);
+
+ /** The object under test. */
+ private CallLogListItemHelper mHelper;
+
+ /** The views used in the tests. */
+ private CallLogListItemViews mViews;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ Context context = getContext();
+ mHelper = new CallLogListItemHelper(context.getResources(), TEST_VOICEMAIL_NUMBER,
+ TEST_INCOMING_DRAWABLE, TEST_OUTGOING_DRAWABLE, TEST_MISSED_DRAWABLE);
+ mViews = new CallLogListItemViews();
+ // Only set the views that are needed in the tests.
+ mViews.iconView = new ImageView(context);
+ mViews.dateView = new TextView(context);
+ mViews.callView = new View(context);
+ mViews.line1View = new TextView(context);
+ mViews.labelView = new TextView(context);
+ mViews.numberView = new TextView(context);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mHelper = null;
+ mViews = null;
+ super.tearDown();
+ }
+
+ public void testSetContactNumberOnly() {
+ mHelper.setContactNumberOnly(mViews, "12125551234", "1-212-555-1234");
+ assertEquals("1-212-555-1234", mViews.line1View.getText());
+ assertEquals(View.GONE, mViews.labelView.getVisibility());
+ assertEquals(View.GONE, mViews.numberView.getVisibility());
+ assertEquals(View.VISIBLE, mViews.callView.getVisibility());
+ }
+
+ public void testSetContactNumberOnly_Unknown() {
+ mHelper.setContactNumberOnly(mViews, CallerInfo.UNKNOWN_NUMBER, "");
+ assertEquals(getContext().getString(R.string.unknown), mViews.line1View.getText());
+ assertEquals(View.GONE, mViews.labelView.getVisibility());
+ assertEquals(View.GONE, mViews.numberView.getVisibility());
+ assertEquals(View.INVISIBLE, mViews.callView.getVisibility());
+ }
+
+ public void testSetContactNumberOnly_Private() {
+ mHelper.setContactNumberOnly(mViews, CallerInfo.PRIVATE_NUMBER, "");
+ assertEquals(getContext().getString(R.string.private_num), mViews.line1View.getText());
+ assertEquals(View.GONE, mViews.labelView.getVisibility());
+ assertEquals(View.GONE, mViews.numberView.getVisibility());
+ assertEquals(View.INVISIBLE, mViews.callView.getVisibility());
+ }
+
+ public void testSetContactNumberOnly_Payphone() {
+ mHelper.setContactNumberOnly(mViews, CallerInfo.PAYPHONE_NUMBER, "");
+ assertEquals(getContext().getString(R.string.payphone), mViews.line1View.getText());
+ assertEquals(View.GONE, mViews.labelView.getVisibility());
+ assertEquals(View.GONE, mViews.numberView.getVisibility());
+ assertEquals(View.INVISIBLE, mViews.callView.getVisibility());
+ }
+
+ public void testSetContactNumberOnly_Voicemail() {
+ mHelper.setContactNumberOnly(mViews, TEST_VOICEMAIL_NUMBER, "");
+ assertEquals(getContext().getString(R.string.voicemail), mViews.line1View.getText());
+ assertEquals(View.GONE, mViews.labelView.getVisibility());
+ assertEquals(View.GONE, mViews.numberView.getVisibility());
+ assertEquals(View.VISIBLE, mViews.callView.getVisibility());
+ }
+
+ public void testSetDate() {
+ // This test requires the locale to be set to US.
+ LocaleTestUtils localeTestUtils = new LocaleTestUtils(getContext());
+ localeTestUtils.setLocale(Locale.US);
+ try {
+ mHelper.setDate(mViews,
+ new GregorianCalendar(2011, 5, 1, 12, 0, 0).getTimeInMillis(),
+ new GregorianCalendar(2011, 5, 1, 13, 0, 0).getTimeInMillis());
+ assertEquals("1 hour ago", mViews.dateView.getText());
+ mHelper.setDate(mViews,
+ new GregorianCalendar(2010, 5, 1, 12, 0, 0).getTimeInMillis(),
+ new GregorianCalendar(2011, 5, 1, 13, 0, 0).getTimeInMillis());
+ assertEquals("June 1, 2010", mViews.dateView.getText());
+ } finally {
+ localeTestUtils.restoreLocale();
+ }
+ }
+
+ public void testSetCallType_Icon() {
+ mHelper.setCallType(mViews, Calls.INCOMING_TYPE);
+ assertEquals(TEST_INCOMING_DRAWABLE, mViews.iconView.getDrawable());
+ mHelper.setCallType(mViews, Calls.OUTGOING_TYPE);
+ assertEquals(TEST_OUTGOING_DRAWABLE, mViews.iconView.getDrawable());
+ mHelper.setCallType(mViews, Calls.MISSED_TYPE);
+ assertEquals(TEST_MISSED_DRAWABLE, mViews.iconView.getDrawable());
+ }
+}
diff --git a/tests/src/com/android/contacts/util/LocaleTestUtils.java b/tests/src/com/android/contacts/util/LocaleTestUtils.java
new file mode 100644
index 0000000..e0a8670
--- /dev/null
+++ b/tests/src/com/android/contacts/util/LocaleTestUtils.java
@@ -0,0 +1,119 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+
+import java.util.Locale;
+
+/**
+ * Utility class to save and restore the locale of the system.
+ * <p>
+ * This can be used for tests that assume to be run in a certain locale, e.g., because they
+ * check against strings in a particular language or require an assumption on how the system
+ * will behave in a specific locale.
+ * <p>
+ * In your test, you can change the locale with the following code:
+ * <pre>
+ * public class CanadaFrenchTest extends AndroidTestCase {
+ * private LocaleTestUtils mLocaleTestUtils;
+ *
+ * @Override
+ * public void setUp() throws Exception {
+ * super.setUp();
+ * mLocaleTestUtils = new LocaleTestUtils(getContext());
+ * mLocaleTestUtils.setLocale(Locale.CANADA_FRENCH);
+ * }
+ *
+ * @Override
+ * public void tearDown() throws Exception {
+ * mLocaleTestUtils.restoreLocale();
+ * mLocaleTestUtils = null;
+ * super.tearDown();
+ * }
+ *
+ * ...
+ * }
+ * </pre>
+ * Note that one should not call {@link #setLocale(Locale)} more than once without calling
+ * {@link #restoreLocale()} first.
+ * <p>
+ * This class is not thread-safe. Usually its methods should be invoked only from the test thread.
+ */
+public class LocaleTestUtils {
+ private final Context mContext;
+ private boolean mSaved;
+ private Locale mSavedContextLocale;
+ private Locale mSavedSystemLocale;
+
+ /**
+ * Create a new instance that can be used to set and reset the locale for the given context.
+ *
+ * @param context the context on which to alter the locale
+ */
+ public LocaleTestUtils(Context context) {
+ mContext = context;
+ mSaved = false;
+ }
+
+ /**
+ * Set the locale to the given value and saves the previous value.
+ *
+ * @param locale the value to which the locale should be set
+ * @throws IllegalStateException if the locale was already set
+ */
+ public void setLocale(Locale locale) {
+ if (mSaved) {
+ throw new IllegalStateException(
+ "call restoreLocale() before calling setLocale() again");
+ }
+ mSavedContextLocale = setResourcesLocale(mContext.getResources(), locale);
+ mSavedSystemLocale = setResourcesLocale(Resources.getSystem(), locale);
+ mSaved = true;
+ }
+
+ /**
+ * Restores the previously set locale.
+ *
+ * @throws IllegalStateException if the locale was not set using {@link #setLocale(Locale)}
+ */
+ public void restoreLocale() {
+ if (!mSaved) {
+ throw new IllegalStateException("call setLocale() before calling restoreLocale()");
+ }
+ setResourcesLocale(mContext.getResources(), mSavedContextLocale);
+ setResourcesLocale(Resources.getSystem(), mSavedSystemLocale);
+ mSaved = false;
+ }
+
+ /**
+ * Sets the locale for the given resources and returns the previous locale.
+ *
+ * @param resources the resources on which to set the locale
+ * @param locale the value to which to set the locale
+ * @return the previous value of the locale for the resources
+ */
+ private Locale setResourcesLocale(Resources resources, Locale locale) {
+ Configuration contextConfiguration = new Configuration(resources.getConfiguration());
+ Locale savedLocale = contextConfiguration.locale;
+ contextConfiguration.locale = locale;
+ resources.updateConfiguration(contextConfiguration, null);
+ return savedLocale;
+ }
+}
\ No newline at end of file