Replace the list of call symbols by a single custom view to paint them.
Saves about 7-21 views per screen and should be more efficient to recycle
Bug:5099652
Change-Id: I10a1b1d188c5c58329de4ba063d41f8c116c3497
diff --git a/res/layout/call_detail_history_item.xml b/res/layout/call_detail_history_item.xml
index 069ade9..b225369 100644
--- a/res/layout/call_detail_history_item.xml
+++ b/res/layout/call_detail_history_item.xml
@@ -22,7 +22,8 @@
android:background="?attr/call_log_secondary_background_color"
android:padding="@dimen/call_log_indent_margin"
>
- <FrameLayout
+ <view
+ class="com.android.contacts.calllog.CallTypeIconsView"
android:id="@+id/call_type_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/call_log_phone_call_details.xml b/res/layout/call_log_phone_call_details.xml
index 5a4131e..4d12a1d 100644
--- a/res/layout/call_log_phone_call_details.xml
+++ b/res/layout/call_log_phone_call_details.xml
@@ -45,13 +45,13 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
>
- <LinearLayout
+ <view
+ class="com.android.contacts.calllog.CallTypeIconsView"
android:id="@+id/call_type_icons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/call_log_icon_margin"
android:layout_gravity="center_vertical"
- android:orientation="horizontal"
/>
<TextView
android:id="@+id/call_type_name"
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index a46d2e2..614613c 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -148,7 +148,7 @@
mResources = getResources();
mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
- mCallTypeHelper = new CallTypeHelper(getResources(), mInflater);
+ mCallTypeHelper = new CallTypeHelper(getResources());
mPhoneNumberHelper = new PhoneNumberHelper(mResources, getVoicemailNumber());
mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(mResources, mCallTypeHelper,
mPhoneNumberHelper);
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index f312a5d..8cdd0d0 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -61,10 +61,10 @@
public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details,
boolean useIcons, boolean isHighlighted, boolean nameOnly) {
if (useIcons) {
- views.callTypeIcons.removeAllViews();
+ views.callTypeIcons.clear();
int count = details.callTypes.length;
for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) {
- mCallTypeHelper.inflateCallTypeIcon(details.callTypes[index], views.callTypeIcons);
+ views.callTypeIcons.add(details.callTypes[index]);
}
views.callTypeIcons.setVisibility(View.VISIBLE);
if (count > MAX_CALL_TYPE_ICONS) {
@@ -77,14 +77,13 @@
views.callTypeSeparator.setVisibility(View.GONE);
}
} else {
- String 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(
isHighlighted ? mCallTypeHelper.getHighlightedCallTypeText(callType)
: mCallTypeHelper.getCallTypeText(callType));
- views.callTypeIcons.removeAllViews();
+ views.callTypeIcons.clear();
views.callTypeText.setVisibility(View.VISIBLE);
views.callTypeSeparator.setVisibility(View.VISIBLE);
diff --git a/src/com/android/contacts/PhoneCallDetailsViews.java b/src/com/android/contacts/PhoneCallDetailsViews.java
index 19e931f..c07e337 100644
--- a/src/com/android/contacts/PhoneCallDetailsViews.java
+++ b/src/com/android/contacts/PhoneCallDetailsViews.java
@@ -16,9 +16,10 @@
package com.android.contacts;
+import com.android.contacts.calllog.CallTypeIconsView;
+
import android.content.Context;
import android.view.View;
-import android.widget.LinearLayout;
import android.widget.TextView;
/**
@@ -27,14 +28,15 @@
public final class PhoneCallDetailsViews {
public final TextView nameView;
public final View callTypeView;
- public final LinearLayout callTypeIcons;
+ public final CallTypeIconsView callTypeIcons;
public final TextView callTypeText;
public final View callTypeSeparator;
public final TextView dateView;
public final TextView numberView;
- private PhoneCallDetailsViews(TextView nameView, View callTypeView, LinearLayout callTypeIcons,
- TextView callTypeText, View callTypeSeparator, TextView dateView, TextView numberView) {
+ private PhoneCallDetailsViews(TextView nameView, View callTypeView,
+ CallTypeIconsView callTypeIcons, TextView callTypeText, View callTypeSeparator,
+ TextView dateView, TextView numberView) {
this.nameView = nameView;
this.callTypeView = callTypeView;
this.callTypeIcons = callTypeIcons;
@@ -54,7 +56,7 @@
public static PhoneCallDetailsViews fromView(View view) {
return new PhoneCallDetailsViews((TextView) view.findViewById(R.id.name),
view.findViewById(R.id.call_type),
- (LinearLayout) view.findViewById(R.id.call_type_icons),
+ (CallTypeIconsView) view.findViewById(R.id.call_type_icons),
(TextView) view.findViewById(R.id.call_type_name),
view.findViewById(R.id.call_type_separator),
(TextView) view.findViewById(R.id.date),
@@ -65,7 +67,7 @@
return new PhoneCallDetailsViews(
new TextView(context),
new View(context),
- new LinearLayout(context),
+ new CallTypeIconsView(context),
new TextView(context),
new View(context),
new TextView(context),
diff --git a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
index 26275af..3e3ba36 100644
--- a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -64,19 +64,20 @@
@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);
- }
+ final View result = convertView == null
+ ? mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false)
+ : convertView;
PhoneCallDetails details = mPhoneCallDetails[position];
- FrameLayout callTypeIconView = (FrameLayout) convertView.findViewById(R.id.call_type_icon);
- TextView callTypeTextView = (TextView) convertView.findViewById(R.id.call_type_text);
- TextView dateView = (TextView) convertView.findViewById(R.id.date);
- TextView durationView = (TextView) convertView.findViewById(R.id.duration);
+ CallTypeIconsView callTypeIconView =
+ (CallTypeIconsView) result.findViewById(R.id.call_type_icon);
+ TextView callTypeTextView = (TextView) result.findViewById(R.id.call_type_text);
+ TextView dateView = (TextView) result.findViewById(R.id.date);
+ TextView durationView = (TextView) result.findViewById(R.id.duration);
int callType = details.callTypes[0];
- callTypeIconView.removeAllViews();
- mCallTypeHelper.inflateCallTypeIcon(callType, callTypeIconView);
+ callTypeIconView.clear();
+ callTypeIconView.add(callType);
callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
// Set the date.
CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
@@ -91,7 +92,7 @@
durationView.setText(formatDuration(details.duration));
}
- return convertView;
+ return result;
}
private String formatDuration(long elapsedSeconds) {
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index ae22489..0999b44 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -313,11 +313,7 @@
mPreDrawListener = null;
Resources resources = getResources();
- LayoutInflater layoutInflater = getActivity().getLayoutInflater();
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
- Drawable callDrawable = resources.getDrawable(R.drawable.ic_dial_action_call);
- Drawable playDrawable = resources.getDrawable(
- R.drawable.ic_call_log_list_action_play);
+ CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
mPhoneNumberHelper = new PhoneNumberHelper(getResources(), mVoiceMailNumber);
diff --git a/src/com/android/contacts/calllog/CallTypeHelper.java b/src/com/android/contacts/calllog/CallTypeHelper.java
index 465e2bf..d27d4f9 100644
--- a/src/com/android/contacts/calllog/CallTypeHelper.java
+++ b/src/com/android/contacts/calllog/CallTypeHelper.java
@@ -25,16 +25,11 @@
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
/**
* Helper class to perform operations related to call types.
*/
public class CallTypeHelper {
- /** Used to create the views for the call types. */
- private final LayoutInflater mLayoutInflater;
/** Name used to identify incoming calls. */
private final CharSequence mIncomingName;
/** Name used to identify outgoing calls. */
@@ -48,8 +43,7 @@
/** Name used to identify new voicemail calls. */
private final CharSequence mNewVoicemailName;
- public CallTypeHelper(Resources resources, LayoutInflater layoutInflater) {
- mLayoutInflater = layoutInflater;
+ public CallTypeHelper(Resources resources) {
// 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);
@@ -103,26 +97,6 @@
}
}
- /** Returns a new view for the icon to be used to represent a given call type. */
- public View inflateCallTypeIcon(int callType, ViewGroup root) {
- switch (callType) {
- case Calls.INCOMING_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_incoming_call_icon, root);
-
- case Calls.OUTGOING_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_outgoing_call_icon, root);
-
- case Calls.MISSED_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_missed_call_icon, root);
-
- case Calls.VOICEMAIL_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_voicemail_icon, root);
-
- default:
- throw new IllegalArgumentException("invalid call type: " + callType);
- }
- }
-
/** Creates a SpannableString for the given text which is bold and in the given color. */
private CharSequence addBoldAndColor(CharSequence text, int color) {
int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
diff --git a/src/com/android/contacts/calllog/CallTypeIconsView.java b/src/com/android/contacts/calllog/CallTypeIconsView.java
new file mode 100644
index 0000000..4fbe7d7
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallTypeIconsView.java
@@ -0,0 +1,123 @@
+/*
+ * 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.google.common.collect.Lists;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.List;
+
+/**
+ * View that draws one or more symbols for different types of calls (missed calls, outgoing etc).
+ * The symbols are set up horizontally. As this view doesn't create subviews, it is better suited
+ * for ListView-recycling that a regular LinearLayout using ImageViews.
+ */
+public class CallTypeIconsView extends View {
+ private List<Integer> mCallTypes = Lists.newArrayListWithCapacity(3);
+ private Resources mResources;
+ private int mWidth;
+ private int mHeight;
+
+ public CallTypeIconsView(Context context) {
+ this(context, null);
+ }
+
+ public CallTypeIconsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mResources = new Resources(context);
+ }
+
+ public void clear() {
+ mCallTypes.clear();
+ mWidth = 0;
+ mHeight = 0;
+ invalidate();
+ }
+
+ public void add(int callType) {
+ mCallTypes.add(callType);
+
+ final Drawable drawable = getCallTypeDrawable(callType);
+ mWidth += drawable.getIntrinsicWidth() + mResources.iconMargin;
+ mHeight = Math.max(mHeight, drawable.getIntrinsicHeight());
+ invalidate();
+ }
+
+ public int getCount() {
+ return mCallTypes.size();
+ }
+
+ public int getCallType(int index) {
+ return mCallTypes.get(index);
+ }
+
+ private Drawable getCallTypeDrawable(int callType) {
+ switch (callType) {
+ case Calls.INCOMING_TYPE:
+ return mResources.incoming;
+ case Calls.OUTGOING_TYPE:
+ return mResources.outgoing;
+ case Calls.MISSED_TYPE:
+ return mResources.missed;
+ case Calls.VOICEMAIL_TYPE:
+ return mResources.voicemail;
+ default:
+ throw new IllegalArgumentException("invalid call type: " + callType);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(mWidth, mHeight);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left = 0;
+ for (Integer callType : mCallTypes) {
+ final Drawable drawable = getCallTypeDrawable(callType);
+ final int right = left + drawable.getIntrinsicWidth();
+ drawable.setBounds(left, 0, right, drawable.getIntrinsicHeight());
+ drawable.draw(canvas);
+ left = right + mResources.iconMargin;
+ }
+ }
+
+ private static class Resources {
+ public final Drawable incoming;
+ public final Drawable outgoing;
+ public final Drawable missed;
+ public final Drawable voicemail;
+ public final int iconMargin;
+
+ public Resources(Context context) {
+ final android.content.res.Resources r = context.getResources();
+ incoming = r.getDrawable(R.drawable.ic_call_incoming_holo_dark);
+ outgoing = r.getDrawable(R.drawable.ic_call_outgoing_holo_dark);
+ missed = r.getDrawable(R.drawable.ic_call_missed_holo_dark);
+ voicemail = r.getDrawable(R.drawable.ic_call_voicemail_holo_dark);
+ iconMargin = r.getDimensionPixelSize(R.dimen.call_log_icon_margin);
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
index 8feca19..1e5d879 100644
--- a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -25,7 +25,6 @@
import android.content.res.Resources;
import android.provider.CallLog.Calls;
import android.test.AndroidTestCase;
-import android.view.LayoutInflater;
import android.view.View;
import java.util.GregorianCalendar;
@@ -59,9 +58,7 @@
super.setUp();
Context context = getContext();
Resources resources = context.getResources();
- LayoutInflater layoutInflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
+ CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
mPhoneNumberHelper = new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
mHelper = new PhoneCallDetailsHelper(resources, callTypeHelper, mPhoneNumberHelper);
mViews = PhoneCallDetailsViews.createForTest(context);
@@ -128,25 +125,30 @@
public void testSetPhoneCallDetails_CallTypeIcons() {
setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_incoming_call_icon);
+ assertCallTypeIconsEquals(Calls.INCOMING_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.OUTGOING_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_outgoing_call_icon);
+ assertCallTypeIconsEquals(Calls.OUTGOING_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_missed_call_icon);
+ assertCallTypeIconsEquals(Calls.MISSED_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.VOICEMAIL_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_voicemail_icon);
+ assertCallTypeIconsEquals(Calls.VOICEMAIL_TYPE);
}
public void testSetPhoneCallDetails_MultipleCallTypeIcons() {
setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_incoming_call_icon,
- R.id.call_log_outgoing_call_icon);
+ assertCallTypeIconsEquals(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_missed_call_icon, R.id.call_log_missed_call_icon);
+ assertCallTypeIconsEquals(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
+ }
+
+ public void testSetPhoneCallDetails_MultipleCallTypeIconsLastOneDropped() {
+ setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE, Calls.MISSED_TYPE,
+ Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
+ assertCallTypeIconsEquals(Calls.MISSED_TYPE, Calls.MISSED_TYPE, Calls.INCOMING_TYPE);
}
public void testSetPhoneCallDetails_CallTypeText() {
@@ -222,10 +224,10 @@
/** Asserts that the call type contains the images with the given drawables. */
private void assertCallTypeIconsEquals(int... ids) {
- assertEquals(ids.length, mViews.callTypeIcons.getChildCount());
+ assertEquals(ids.length, mViews.callTypeIcons.getCount());
for (int index = 0; index < ids.length; ++index) {
int id = ids[index];
- assertEquals(id, mViews.callTypeIcons.getChildAt(index).getId());
+ assertEquals(id, mViews.callTypeIcons.getCallType(index));
}
assertEquals(View.VISIBLE, mViews.callTypeIcons.getVisibility());
assertEquals(View.GONE, mViews.callTypeText.getVisibility());
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
index 79ebf4d..4628b8e 100644
--- a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -24,7 +24,6 @@
import android.content.res.Resources;
import android.provider.CallLog.Calls;
import android.test.AndroidTestCase;
-import android.view.LayoutInflater;
import android.view.View;
/**
@@ -56,9 +55,7 @@
super.setUp();
Context context = getContext();
Resources resources = context.getResources();
- LayoutInflater layoutInflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
+ CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
mPhoneNumberHelper = new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
resources, callTypeHelper, mPhoneNumberHelper);