Details for multiple calls.

Add the details of the call at the bottom of the call details in a list.

The code allows having multiple details listed at the bottom, but
currently we only have one. A follow-up will add details for multiple
calls.

Change-Id: I0a91cc372f658bada603e22b9438a6db771dc124
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index d3818ba..eca4835 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -87,42 +87,12 @@
         android:layout_below="@id/contact_background"
         android:background="?attr/call_log_primary_background_color"
     />
-    <RelativeLayout
+    <ListView
         android:id="@+id/history"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_below="@android:id/list"
-        android:paddingBottom="10dp"
-        android:paddingTop="10dp"
-        android:paddingLeft="80dp"
         android:background="?attr/call_log_secondary_background_color"
-    >
-        <TextView
-            android:id="@+id/time"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:textColor="?attr/call_log_secondary_text_color"
-        />
-        <TextView
-            android:id="@+id/duration"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_below="@id/time"
-            android:layout_alignLeft="@id/time"
-            android:textColor="?attr/call_log_secondary_text_color"
-        />
-        <ImageView
-            android:id="@+id/delete"
-            android:layout_width="?attr/call_detail_action_icon_size"
-            android:layout_height="?attr/call_detail_action_icon_size"
-            android:layout_alignParentRight="true"
-            android:scaleType="center"
-            android:gravity="center_vertical"
-            android:src="@android:drawable/sym_action_call"
-            android:visibility="gone"
-        />
-    </RelativeLayout>
+    />
 </RelativeLayout>
diff --git a/res/layout/call_detail_history_item.xml b/res/layout/call_detail_history_item.xml
new file mode 100644
index 0000000..9377404
--- /dev/null
+++ b/res/layout/call_detail_history_item.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<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:background="?attr/call_log_secondary_background_color"
+    android:padding="5dip"
+>
+    <ImageView
+        android:id="@+id/call_type_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:layout_marginRight="5dip"
+    />
+    <TextView
+        android:id="@+id/call_type_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_toRightOf="@id/call_type_icon"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+    <TextView
+        android:id="@+id/number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/call_type_text"
+        android:layout_alignLeft="@id/call_type_text"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+    <TextView
+        android:id="@+id/date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/number"
+        android:layout_alignLeft="@id/number"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+    <TextView
+        android:id="@+id/duration"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/date"
+        android:layout_alignLeft="@id/date"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+</RelativeLayout>
diff --git a/res/layout/call_detail_list_item.xml b/res/layout/call_detail_list_item.xml
index 78a5294..8b90e25 100644
--- a/res/layout/call_detail_list_item.xml
+++ b/res/layout/call_detail_list_item.xml
@@ -1,26 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 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.
- */
+<!-- 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="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
     android:orientation="horizontal"
     android:paddingLeft="9dip"
     android:paddingRight="5dip"
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index d08b76a..ca17e7b 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallDetailHistoryAdapter;
+import com.android.contacts.calllog.CallTypeHelper;
 import com.android.internal.telephony.CallerInfo;
 
 import android.app.ListActivity;
@@ -35,7 +37,6 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -43,6 +44,7 @@
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
+import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -58,9 +60,8 @@
 
     /** The views representing the details of a phone call. */
     private PhoneCallDetailsViews mPhoneCallDetailsViews;
+    private CallTypeHelper mCallTypeHelper;
     private PhoneCallDetailsHelper mPhoneCallDetailsHelper;
-    private TextView mCallTimeView;
-    private TextView mCallDurationView;
     private View mHomeActionView;
     private ImageView mMainActionView;
     private ImageView mContactBackgroundView;
@@ -72,7 +73,6 @@
     /* package */ Resources mResources;
     /** Helper to load contact photos. */
     private ContactPhotoManager mContactPhotoManager;
-    /** Attached to the call action button in the UI. */
 
     static final String[] CALL_LOG_PROJECTION = new String[] {
         CallLog.Calls.DATE,
@@ -115,17 +115,16 @@
         mResources = getResources();
 
         mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
-        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(this, getResources(),
-                getVoicemailNumber(),
+        mCallTypeHelper = new CallTypeHelper(getResources(),
                 getResources().getDrawable(R.drawable.ic_call_log_list_incoming_call),
                 getResources().getDrawable(R.drawable.ic_call_log_list_outgoing_call),
                 getResources().getDrawable(R.drawable.ic_call_log_list_missed_call),
                 getResources().getDrawable(R.drawable.ic_call_log_list_voicemail));
+        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(this, getResources(),
+                getVoicemailNumber(), mCallTypeHelper);
         mHomeActionView = findViewById(R.id.action_bar_home);
         mMainActionView = (ImageView) findViewById(R.id.main_action);
         mContactBackgroundView = (ImageView) findViewById(R.id.contact_background);
-        mCallTimeView = (TextView) findViewById(R.id.time);
-        mCallDurationView = (TextView) findViewById(R.id.duration);
         mDefaultCountryIso = ContactsUtils.getCurrentCountryIso(this);
         mContactPhotoManager = ContactPhotoManager.getInstance(this);
         getListView().setOnItemClickListener(this);
@@ -183,19 +182,6 @@
                 if (TextUtils.isEmpty(countryIso)) {
                     countryIso = mDefaultCountryIso;
                 }
-                // Pull out string in format [relative], [date]
-                CharSequence dateClause = DateUtils.formatDateRange(this, date, date,
-                        DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
-                        DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
-                mCallTimeView.setText(dateClause);
-
-                // Set the duration
-                if (callType == Calls.MISSED_TYPE) {
-                    mCallDurationView.setVisibility(View.GONE);
-                } else {
-                    mCallDurationView.setVisibility(View.VISIBLE);
-                    mCallDurationView.setText(formatDuration(duration));
-                }
 
                 long photoId = 0L;
                 CharSequence nameText = "";
@@ -303,9 +289,14 @@
                     ViewAdapter adapter = new ViewAdapter(this, actions);
                     setListAdapter(adapter);
                 }
+                PhoneCallDetails details = new PhoneCallDetails(mNumber, numberText,
+                        new int[]{ callType }, duration, date, nameText, numberType, numberLabel);
                 mPhoneCallDetailsHelper.setPhoneCallDetails(mPhoneCallDetailsViews,
-                        new PhoneCallDetails(mNumber, numberText, new int[]{ callType }, date,
-                                nameText, numberType, numberLabel), false);
+                        details, false);
+                ListView historyList = (ListView) findViewById(R.id.history);
+                historyList.setAdapter(
+                        new CallDetailHistoryAdapter(this, mInflater, mCallTypeHelper,
+                                    new PhoneCallDetails[]{ details }));
 
                 loadContactPhotos(photoId);
             } else {
@@ -327,19 +318,6 @@
         mContactPhotoManager.loadPhoto(mContactBackgroundView, photoId);
     }
 
-    private String formatDuration(long elapsedSeconds) {
-        long minutes = 0;
-        long seconds = 0;
-
-        if (elapsedSeconds >= 60) {
-            minutes = elapsedSeconds / 60;
-            elapsedSeconds -= minutes * 60;
-        }
-        seconds = elapsedSeconds;
-
-        return getString(R.string.callDetailsDurationFormat, minutes, seconds);
-    }
-
     private String getVoicemailNumber() {
         TelephonyManager telephonyManager =
                 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/src/com/android/contacts/PhoneCallDetails.java b/src/com/android/contacts/PhoneCallDetails.java
index 7b02a88..39620b2 100644
--- a/src/com/android/contacts/PhoneCallDetails.java
+++ b/src/com/android/contacts/PhoneCallDetails.java
@@ -35,6 +35,8 @@
     public final int[] callTypes;
     /** The date of the call, in milliseconds since the epoch. */
     public final long date;
+    /** The duration of the call in milliseconds, or 0 for missed calls. */
+    public final long duration;
     /** The name of the contact, or the empty string. */
     public final CharSequence name;
     /** The type of phone, e.g., {@link Phone#TYPE_HOME}, 0 if not available. */
@@ -44,17 +46,18 @@
 
     /** Create the details for a call with a number not associated with a contact. */
     public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
-            long date) {
-        this(number, formattedNumber, callTypes, date, "", 0, "");
+            long date, long duration) {
+        this(number, formattedNumber, callTypes, date, duration, "", 0, "");
     }
 
     /** Create the details for a call with a number associated with a contact. */
     public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
-            long date, CharSequence name, int numberType, CharSequence numberLabel) {
+            long date, long duration, CharSequence name, int numberType, CharSequence numberLabel) {
         this.number = number;
         this.formattedNumber = formattedNumber;
         this.callTypes = callTypes;
         this.date = date;
+        this.duration = duration;
         this.name = name;
         this.numberType = numberType;
         this.numberLabel = numberLabel;
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index 7f73b04..cbf3c5c 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -16,14 +16,13 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallTypeHelper;
 import com.android.contacts.format.FormatUtils;
 import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.telephony.PhoneNumberUtils;
 import android.text.Spanned;
@@ -39,24 +38,9 @@
     private final Context mContext;
     private final Resources mResources;
     private final String mVoicemailNumber;
-    /** Icon for incoming calls. */
-    private final Drawable mIncomingDrawable;
-    /** Icon for outgoing calls. */
-    private final Drawable mOutgoingDrawable;
-    /** Icon for missed calls. */
-    private final Drawable mMissedDrawable;
-    /** Icon for voicemails. */
-    private final Drawable mVoicemailDrawable;
-    /** Name used to identify incoming calls. */
-    private final String mIncomingName;
-    /** Name used to identify outgoing calls. */
-    private final String mOutgoingName;
-    /** Name used to identify missed calls. */
-    private final String mMissedName;
-    /** Name used to identify voicemail calls. */
-    private final String mVoicemailName;
     /** The injected current time in milliseconds since the epoch. Used only by tests. */
     private Long mCurrentTimeMillisForTest;
+    private final CallTypeHelper mCallTypeHelper;
 
     /**
      * Creates a new instance of the helper.
@@ -66,20 +50,11 @@
      * @param resources used to look up strings
      */
     public PhoneCallDetailsHelper(Context context, Resources resources, String voicemailNumber,
-            Drawable incomingDrawable, Drawable outgoingDrawable, Drawable missedDrawable,
-            Drawable voicemailDrawable) {
+            CallTypeHelper callTypeHelper) {
         mContext = context;
         mResources = resources;
         mVoicemailNumber = voicemailNumber;
-        mIncomingDrawable = incomingDrawable;
-        mOutgoingDrawable = outgoingDrawable;
-        mMissedDrawable = missedDrawable;
-        mVoicemailDrawable = voicemailDrawable;
-        // Cache these values so that we do not need to look them up each time.
-        mIncomingName = mResources.getString(R.string.type_incoming);
-        mOutgoingName = mResources.getString(R.string.type_outgoing);
-        mMissedName = mResources.getString(R.string.type_missed);
-        mVoicemailName = mResources.getString(R.string.type_voicemail);
+        mCallTypeHelper = callTypeHelper;
     }
 
     /** Fills the call details views with content. */
@@ -90,7 +65,7 @@
             int count = details.callTypes.length;
             for (int callType : details.callTypes) {
                 ImageView callTypeImage = new ImageView(mContext);
-                callTypeImage.setImageDrawable(getCallTypeDrawable(callType));
+                callTypeImage.setImageDrawable(mCallTypeHelper.getCallTypeDrawable(callType));
                 views.callTypeIcons.addView(callTypeImage);
             }
             views.callTypeIcons.setVisibility(View.VISIBLE);
@@ -101,7 +76,7 @@
             // 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.callTypeText.setText(mCallTypeHelper.getCallTypeText(callType));
             views.callTypeIcons.removeAllViews();
 
             views.callTypeText.setVisibility(View.VISIBLE);
@@ -155,46 +130,6 @@
         }
     }
 
-    /** 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/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
new file mode 100644
index 0000000..82ac971
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * 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.PhoneCallDetails;
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.provider.CallLog.Calls;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Adapter for a ListView containing history items from the details of a call.
+ */
+public class CallDetailHistoryAdapter extends BaseAdapter {
+    private final Context mContext;
+    private final LayoutInflater mLayoutInflater;
+    private final CallTypeHelper mCallTypeHelper;
+    private final PhoneCallDetails[] mPhoneCallDetails;
+
+    public CallDetailHistoryAdapter(Context context, LayoutInflater layoutInflater,
+            CallTypeHelper callTypeHelper, PhoneCallDetails[] phoneCallDetails) {
+        mContext = context;
+        mLayoutInflater = layoutInflater;
+        mCallTypeHelper = callTypeHelper;
+        mPhoneCallDetails = phoneCallDetails;
+    }
+
+    @Override
+    public int getCount() {
+        return mPhoneCallDetails.length;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mPhoneCallDetails[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        // Make sure we have a valid convertView to start with
+        if (convertView == null) {
+            convertView = mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false);
+        }
+
+        PhoneCallDetails details = mPhoneCallDetails[position];
+        ImageView callTypeIconView = (ImageView) convertView.findViewById(R.id.call_type_icon);
+        TextView callTypeTextView = (TextView) convertView.findViewById(R.id.call_type_text);
+        TextView numberView = (TextView) convertView.findViewById(R.id.number);
+        TextView dateView = (TextView) convertView.findViewById(R.id.date);
+        TextView durationView = (TextView) convertView.findViewById(R.id.duration);
+
+        int callType = details.callTypes[0];
+        callTypeIconView.setImageDrawable(mCallTypeHelper.getCallTypeDrawable(callType));
+        callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
+        // TODO: Add the label for this number as well.
+        numberView.setText(details.number);
+        // Set the date.
+        CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
+                DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
+                DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
+        dateView.setText(dateValue);
+        // Set the duration
+        if (callType == Calls.MISSED_TYPE) {
+            durationView.setVisibility(View.GONE);
+        } else {
+            durationView.setVisibility(View.VISIBLE);
+            durationView.setText(formatDuration(details.duration));
+        }
+
+        return convertView;
+    }
+
+    private String formatDuration(long elapsedSeconds) {
+        long minutes = 0;
+        long seconds = 0;
+
+        if (elapsedSeconds >= 60) {
+            minutes = elapsedSeconds / 60;
+            elapsedSeconds -= minutes * 60;
+        }
+        seconds = elapsedSeconds;
+
+        return mContext.getString(R.string.callDetailsDurationFormat, minutes, seconds);
+    }
+}
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 11f8965..901ebd8 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -35,6 +35,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.CharArrayBuffer;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabaseCorruptException;
@@ -64,7 +65,6 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.AdapterView;
@@ -261,23 +261,25 @@
             mRequests = new LinkedList<CallerInfoQuery>();
             mPreDrawListener = null;
 
-            Drawable incomingDrawable = getResources().getDrawable(
+            Resources resources = getResources();
+            Drawable incomingDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_incoming_call);
-            Drawable outgoingDrawable = getResources().getDrawable(
+            Drawable outgoingDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_outgoing_call);
-            Drawable missedDrawable = getResources().getDrawable(
+            Drawable missedDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_missed_call);
-            Drawable voicemailDrawable = getResources().getDrawable(
+            Drawable voicemailDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_voicemail);
-            Drawable callDrawable = getResources().getDrawable(
+            Drawable callDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_action_call);
-            Drawable playDrawable = getResources().getDrawable(
+            Drawable playDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_action_play);
 
             mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
-            PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
-                    getActivity(), getResources(), mVoiceMailNumber, incomingDrawable,
+            CallTypeHelper callTypeHelper = new CallTypeHelper(resources, incomingDrawable,
                     outgoingDrawable, missedDrawable, voicemailDrawable);
+            PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
+                    getActivity(), resources, mVoiceMailNumber, callTypeHelper);
             mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper, callDrawable,
                     playDrawable);
         }
@@ -640,6 +642,7 @@
 
             String number = c.getString(CallLogQuery.NUMBER);
             long date = c.getLong(CallLogQuery.DATE);
+            long duration = c.getLong(CallLogQuery.DURATION);
             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
@@ -699,10 +702,10 @@
             int[] callTypes = getCallTypes(c, count);
             final PhoneCallDetails details;
             if (TextUtils.isEmpty(name)) {
-                details = new PhoneCallDetails(number, formattedNumber, callTypes, date);
+                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, duration);
             } else {
-                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, name,
-                        ntype, label);
+                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, duration,
+                        name, ntype, label);
             }
             mCallLogViewsHelper.setPhoneCallDetails(views, details , true);
             if (views.photoView != null) {
diff --git a/src/com/android/contacts/calllog/CallTypeHelper.java b/src/com/android/contacts/calllog/CallTypeHelper.java
new file mode 100644
index 0000000..b06a1c1
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallTypeHelper.java
@@ -0,0 +1,98 @@
+/*
+ * 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 android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+
+/**
+ * Helper class to perform operations related to call types.
+ */
+public class CallTypeHelper {
+    /** Icon for incoming calls. */
+    private final Drawable mIncomingDrawable;
+    /** Icon for outgoing calls. */
+    private final Drawable mOutgoingDrawable;
+    /** Icon for missed calls. */
+    private final Drawable mMissedDrawable;
+    /** Icon for voicemails. */
+    private final Drawable mVoicemailDrawable;
+    /** Name used to identify incoming calls. */
+    private final String mIncomingName;
+    /** Name used to identify outgoing calls. */
+    private final String mOutgoingName;
+    /** Name used to identify missed calls. */
+    private final String mMissedName;
+    /** Name used to identify voicemail calls. */
+    private final String mVoicemailName;
+
+    public CallTypeHelper(Resources resources, Drawable incomingDrawable, Drawable outgoingDrawable,
+            Drawable missedDrawable, Drawable voicemailDrawable) {
+        mIncomingDrawable = incomingDrawable;
+        mOutgoingDrawable = outgoingDrawable;
+        mMissedDrawable = missedDrawable;
+        mVoicemailDrawable = voicemailDrawable;
+        // Cache these values so that we do not need to look them up each time.
+        mIncomingName = resources.getString(R.string.type_incoming);
+        mOutgoingName = resources.getString(R.string.type_outgoing);
+        mMissedName = resources.getString(R.string.type_missed);
+        mVoicemailName = resources.getString(R.string.type_voicemail);
+    }
+
+    /** Returns the text used to represent the given call type. */
+    public 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. */
+    public 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);
+        }
+    }
+}
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
index 353c2ec..9ac3b05 100644
--- a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -16,10 +16,12 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallTypeHelper;
 import com.android.contacts.util.LocaleTestUtils;
 import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -41,6 +43,8 @@
     private static final String TEST_VOICEMAIL_NUMBER = "125";
     /** The date of the call log entry. */
     private static final long TEST_DATE = 1300000000;
+    /** A test duration value for phone calls. */
+    private static final long TEST_DURATION = 62300;
     /** The number of the caller/callee in the log entry. */
     private static final String TEST_NUMBER = "14125555555";
     /** The formatted version of {@link #TEST_NUMBER}. */
@@ -63,9 +67,11 @@
     protected void setUp() throws Exception {
         super.setUp();
         Context context = getContext();
-        mHelper = new PhoneCallDetailsHelper(context, context.getResources(),
-                TEST_VOICEMAIL_NUMBER, TEST_INCOMING_DRAWABLE, TEST_OUTGOING_DRAWABLE,
-                TEST_MISSED_DRAWABLE, TEST_VOICEMAIL_DRAWABLE);
+        Resources resources = context.getResources();
+        CallTypeHelper callTypeHelper = new CallTypeHelper(resources, TEST_INCOMING_DRAWABLE,
+                TEST_OUTGOING_DRAWABLE, TEST_MISSED_DRAWABLE, TEST_VOICEMAIL_DRAWABLE);
+        mHelper = new PhoneCallDetailsHelper(context, resources,
+                TEST_VOICEMAIL_NUMBER, callTypeHelper);
         mViews = PhoneCallDetailsViews.createForTest(new TextView(context),
                 new LinearLayout(context), new TextView(context), new View(context),
                 new TextView(context), new TextView(context));
@@ -204,7 +210,7 @@
     private void setPhoneCallDetailsWithNumber(String number, String formattedNumber) {
         mHelper.setPhoneCallDetails(mViews,
                 new PhoneCallDetails(number, formattedNumber, new int[]{ Calls.INCOMING_TYPE },
-                        TEST_DATE),
+                        TEST_DATE, TEST_DURATION),
                 false);
     }
 
@@ -212,7 +218,7 @@
     private void setPhoneCallDetailsWithDate(long date) {
         mHelper.setPhoneCallDetails(mViews,
                 new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER,
-                        new int[]{ Calls.INCOMING_TYPE }, date),
+                        new int[]{ Calls.INCOMING_TYPE }, date, TEST_DURATION),
                 false);
     }
 
@@ -228,7 +234,8 @@
 
     private void setPhoneCallDetailsWithCallTypes(boolean useIcons, int... callTypes) {
         mHelper.setPhoneCallDetails(mViews,
-                new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, callTypes, TEST_DATE),
+                new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, callTypes, TEST_DATE,
+                        TEST_DURATION),
                 useIcons);
     }
 }
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
index a8714b4..fc50275 100644
--- a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -22,6 +22,7 @@
 import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -43,6 +44,8 @@
     private static final String TEST_FORMATTED_NUMBER = "1-412-255-5555";
     /** A test date value for phone calls. */
     private static final long TEST_DATE = 1300000000;
+    /** A test duration value for phone calls. */
+    private static final long TEST_DURATION = 62300;
     /** A test voicemail number. */
     private static final String TEST_VOICEMAIL_NUMBER = "123";
     /** A drawable to be used for incoming calls. */
@@ -68,9 +71,12 @@
     protected void setUp() throws Exception {
         super.setUp();
         Context context = getContext();
+        Resources resources = context.getResources();
+        CallTypeHelper callTypeHelper = new CallTypeHelper(resources,
+                TEST_INCOMING_DRAWABLE, TEST_OUTGOING_DRAWABLE, TEST_MISSED_DRAWABLE,
+                TEST_VOICEMAIL_DRAWABLE);
         PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(context,
-                context.getResources(), TEST_VOICEMAIL_NUMBER, TEST_INCOMING_DRAWABLE,
-                TEST_OUTGOING_DRAWABLE, TEST_MISSED_DRAWABLE, TEST_VOICEMAIL_DRAWABLE);
+                resources, TEST_VOICEMAIL_NUMBER, callTypeHelper);
         mHelper = new CallLogListItemHelper(phoneCallDetailsHelper, TEST_CALL_DRAWABLE,
                 TEST_PLAY_DRAWABLE);
         mViews = CallLogListItemViews.createForTest(new QuickContactBadge(context),
@@ -123,13 +129,15 @@
     private void setPhoneCallDetailsWithNumber(String number, String formattedNumber) {
         mHelper.setPhoneCallDetails(mViews,
                 new PhoneCallDetails(number, formattedNumber, new int[]{ Calls.INCOMING_TYPE },
-                        TEST_DATE),
+                        TEST_DATE, TEST_DURATION),
                 true);
     }
 
     /** Sets the details of a phone call using the specified call type. */
     private void setPhoneCallDetailsWithTypes(int... types) {
         mHelper.setPhoneCallDetails(mViews,
-                new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, types, TEST_DATE), true);
+                new PhoneCallDetails(
+                        TEST_NUMBER, TEST_FORMATTED_NUMBER, types, TEST_DATE, TEST_DURATION),
+                true);
     }
 }