Move view-specific logic to ViewHolders.
There's a lot of logic around inflating/initializing which lives in
the adapter, but only really applies to the views. Move this into
the View Holder for now. This may not be its final resting place,
but in any case this seems like it can be extracted from the adapter.
Bug: 19372817
Change-Id: Ib3436ad4d8e666a8df8cb2f894e71b321ecb68da
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index aa2c1df..1065131 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -36,7 +36,6 @@
import android.view.View;
import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
@@ -44,7 +43,6 @@
import android.widget.Toast;
import com.android.common.widget.GroupingListAdapter;
-import com.android.contacts.common.CallUtil;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.util.UriUtils;
@@ -273,7 +271,14 @@
private final View.OnClickListener mActionListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
- startActivityForAction(view);
+ final IntentProvider intentProvider = (IntentProvider) view.getTag();
+ if (intentProvider != null) {
+ final Intent intent = intentProvider.getIntent(mContext);
+ // See IntentProvider.getCallDetailIntentProvider() for why this may be null.
+ if (intent != null) {
+ DialerUtils.startActivityWithErrorToast(mContext, intent);
+ }
+ }
}
};
@@ -301,17 +306,6 @@
}
};
- private void startActivityForAction(View view) {
- final IntentProvider intentProvider = (IntentProvider) view.getTag();
- if (intentProvider != null) {
- final Intent intent = intentProvider.getIntent(mContext);
- // See IntentProvider.getCallDetailIntentProvider() for why this may be null.
- if (intent != null) {
- DialerUtils.startActivityWithErrorToast(mContext, intent);
- }
- }
- }
-
@Override
public boolean onPreDraw() {
// We only wanted to listen for the first draw (and this is it).
@@ -370,8 +364,7 @@
PhoneCallDetailsHelper phoneCallDetailsHelper =
new PhoneCallDetailsHelper(mContext, resources, mPhoneNumberUtilsWrapper);
mCallLogViewsHelper =
- new CallLogListItemHelper(
- phoneCallDetailsHelper, mPhoneNumberHelper, resources);
+ new CallLogListItemHelper(phoneCallDetailsHelper, mPhoneNumberHelper, resources);
mCallLogGroupBuilder = new CallLogGroupBuilder(this);
}
@@ -589,7 +582,7 @@
View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
// Get the views to bind to and cache them.
- CallLogListItemViews views = CallLogListItemViews.fromView(view);
+ CallLogListItemViews views = CallLogListItemViews.fromView(context, view);
view.setTag(views);
// Set text height to false on the TextViews so they don't have extra padding.
@@ -673,7 +666,7 @@
mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
// Expand/collapse an actions section for the call log entry when the primary view is tapped.
- views.primaryActionView.setOnClickListener(this.mExpandCollapseListener);
+ views.primaryActionView.setOnClickListener(mExpandCollapseListener);
// Note: Binding of the action buttons is done as required in configureActionViews when the
// user expands the actions ViewStub.
@@ -864,12 +857,13 @@
* @param isExpanded The new expansion state of the view.
*/
private void expandOrCollapseActions(View callLogItem, boolean isExpanded) {
- final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
+ final CallLogListItemViews views = (CallLogListItemViews) callLogItem.getTag();
expandVoicemailTranscriptionView(views, isExpanded);
if (isExpanded) {
// Inflate the view stub if necessary, and wire up the event handlers.
- inflateActionViewStub(callLogItem);
+ views.inflateActionViewStub(callLogItem, mOnReportButtonClickListener, mActionListener,
+ mPhoneNumberUtilsWrapper, mCallLogViewsHelper);
views.actionsView.setVisibility(View.VISIBLE);
views.actionsView.setAlpha(1.0f);
@@ -903,135 +897,6 @@
view.setSingleLine(!isExpanded);
}
- /**
- * Configures the action buttons in the expandable actions ViewStub. The ViewStub is not
- * inflated during initial binding, so click handlers, tags and accessibility text must be set
- * here, if necessary.
- *
- * @param callLogItem The call log list item view.
- */
- private void inflateActionViewStub(final View callLogItem) {
- final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
-
- ViewStub stub = (ViewStub)callLogItem.findViewById(R.id.call_log_entry_actions_stub);
- if (stub != null) {
- views.actionsView = (ViewGroup) stub.inflate();
- }
-
- if (views.callBackButtonView == null) {
- views.callBackButtonView = (TextView)views.actionsView.findViewById(
- R.id.call_back_action);
- }
-
- if (views.videoCallButtonView == null) {
- views.videoCallButtonView = (TextView)views.actionsView.findViewById(
- R.id.video_call_action);
- }
-
- if (views.voicemailButtonView == null) {
- views.voicemailButtonView = (TextView)views.actionsView.findViewById(
- R.id.voicemail_action);
- }
-
- if (views.detailsButtonView == null) {
- views.detailsButtonView = (TextView)views.actionsView.findViewById(R.id.details_action);
- }
-
- if (views.reportButtonView == null) {
- views.reportButtonView = (TextView)views.actionsView.findViewById(R.id.report_action);
- views.reportButtonView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mOnReportButtonClickListener != null) {
- mOnReportButtonClickListener.onReportButtonClick(views.number);
- }
- }
- });
- }
-
- bindActionButtons(views);
- }
-
- /***
- * Binds text titles, click handlers and intents to the voicemail, details and callback action
- * buttons.
- *
- * @param views The call log item views.
- */
- private void bindActionButtons(CallLogListItemViews views) {
- boolean canPlaceCallToNumber =
- PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation);
- // Set return call intent, otherwise null.
- if (canPlaceCallToNumber) {
- boolean isVoicemailNumber =
- mPhoneNumberUtilsWrapper.isVoicemailNumber(views.accountHandle, views.number);
- if (isVoicemailNumber) {
- // Make a general call to voicemail to ensure that if there are multiple accounts
- // it does not call the voicemail number of a specific phone account.
- views.callBackButtonView.setTag(
- IntentProvider.getReturnVoicemailCallIntentProvider());
- } else {
- // Sets the primary action to call the number.
- views.callBackButtonView.setTag(
- IntentProvider.getReturnCallIntentProvider(views.number));
- }
- views.callBackButtonView.setVisibility(View.VISIBLE);
- views.callBackButtonView.setOnClickListener(mActionListener);
-
- final int titleId;
- if (views.callType == Calls.VOICEMAIL_TYPE || views.callType == Calls.OUTGOING_TYPE) {
- titleId = R.string.call_log_action_redial;
- } else {
- titleId = R.string.call_log_action_call_back;
- }
- views.callBackButtonView.setText(mContext.getString(titleId));
- } else {
- // Number is not callable, so hide button.
- views.callBackButtonView.setTag(null);
- views.callBackButtonView.setVisibility(View.GONE);
- }
-
- // If one of the calls had video capabilities, show the video call button.
- if (CallUtil.isVideoEnabled(mContext) && canPlaceCallToNumber &&
- views.phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
- views.videoCallButtonView.setTag(
- IntentProvider.getReturnVideoCallIntentProvider(views.number));
- views.videoCallButtonView.setVisibility(View.VISIBLE);
- views.videoCallButtonView.setOnClickListener(mActionListener);
- } else {
- views.videoCallButtonView.setTag(null);
- views.videoCallButtonView.setVisibility(View.GONE);
- }
-
- // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise.
- if (views.callType == Calls.VOICEMAIL_TYPE) {
- views.voicemailButtonView.setOnClickListener(mActionListener);
- views.voicemailButtonView.setTag(
- IntentProvider.getPlayVoicemailIntentProvider(
- views.rowId, views.voicemailUri));
- views.voicemailButtonView.setVisibility(View.VISIBLE);
-
- views.detailsButtonView.setVisibility(View.GONE);
- } else {
- views.voicemailButtonView.setTag(null);
- views.voicemailButtonView.setVisibility(View.GONE);
-
- views.detailsButtonView.setOnClickListener(mActionListener);
- views.detailsButtonView.setTag(
- IntentProvider.getCallDetailIntentProvider(
- views.rowId, views.callIds, null)
- );
-
- if (views.canBeReportedAsInvalid && !views.reported) {
- views.reportButtonView.setVisibility(View.VISIBLE);
- } else {
- views.reportButtonView.setVisibility(View.GONE);
- }
- }
-
- mCallLogViewsHelper.setActionContentDescriptions(views);
- }
-
/** Checks whether the contact info from the call log matches the one from the contacts db. */
private boolean callLogInfoMatches(ContactInfo callLogInfo, ContactInfo info) {
// The call log only contains a subset of the fields in the contacts db.
@@ -1208,7 +1073,9 @@
@VisibleForTesting
void bindViewForTest(View view, Context context, Cursor cursor) {
bindStandAloneView(view, context, cursor);
- inflateActionViewStub(view);
+ CallLogListItemViews views = CallLogListItemViews.fromView(context, view);
+ views.inflateActionViewStub(view, mOnReportButtonClickListener, mActionListener,
+ mPhoneNumberUtilsWrapper, mCallLogViewsHelper);
}
/**
diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViews.java
index 0ccdf00..b9a76a8 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViews.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViews.java
@@ -17,17 +17,27 @@
package com.android.dialer.calllog;
import android.content.Context;
+import android.provider.CallLog.Calls;
import android.telecom.PhoneAccountHandle;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
import android.widget.QuickContactBadge;
import android.widget.TextView;
+import com.android.contacts.common.CallUtil;
import com.android.contacts.common.testing.NeededForTesting;
import com.android.dialer.PhoneCallDetailsViews;
import com.android.dialer.R;
/**
- * Simple value object containing the various views within a call log entry.
+ * This is an object containing the various views within a call log entry. It contains values
+ * pointing to views contained by a call log list item view, so that we can improve performance
+ * by reducing the frequency with which we need to find views by IDs.
+ *
+ * This object also contains methods for inflating action views and binding action behaviors. This
+ * is a way of isolating view logic from the CallLogAdapter. We should consider moving that logic
+ * if the call log list item is eventually represented as a UI component.
*/
public final class CallLogListItemViews {
/** The quick contact badge for the contact. */
@@ -113,9 +123,17 @@
*/
public boolean canBeReportedAsInvalid;
- private CallLogListItemViews(QuickContactBadge quickContactView, View primaryActionView,
- PhoneCallDetailsViews phoneCallDetailsViews, View callLogEntryView,
+ private Context mContext;
+
+ private CallLogListItemViews(
+ Context context,
+ QuickContactBadge quickContactView,
+ View primaryActionView,
+ PhoneCallDetailsViews phoneCallDetailsViews,
+ View callLogEntryView,
TextView dayGroupHeader) {
+ mContext = context;
+
this.quickContactView = quickContactView;
this.primaryActionView = primaryActionView;
this.phoneCallDetailsViews = phoneCallDetailsViews;
@@ -123,8 +141,134 @@
this.dayGroupHeader = dayGroupHeader;
}
- public static CallLogListItemViews fromView(View view) {
+ /**
+ * Configures the action buttons in the expandable actions ViewStub. The ViewStub is not
+ * inflated during initial binding, so click handlers, tags and accessibility text must be set
+ * here, if necessary.
+ *
+ * @param callLogItem The call log list item view.
+ */
+ public void inflateActionViewStub(
+ final View callLogItem,
+ final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener,
+ View.OnClickListener actionListener,
+ PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
+ CallLogListItemHelper callLogViewsHelper) {
+ ViewStub stub = (ViewStub) callLogItem.findViewById(R.id.call_log_entry_actions_stub);
+ if (stub != null) {
+ actionsView = (ViewGroup) stub.inflate();
+ }
+
+ if (callBackButtonView == null) {
+ callBackButtonView = (TextView) actionsView.findViewById(R.id.call_back_action);
+ }
+
+ if (videoCallButtonView == null) {
+ videoCallButtonView = (TextView) actionsView.findViewById(R.id.video_call_action);
+ }
+
+ if (voicemailButtonView == null) {
+ voicemailButtonView = (TextView) actionsView.findViewById(R.id.voicemail_action);
+ }
+
+ if (detailsButtonView == null) {
+ detailsButtonView = (TextView) actionsView.findViewById(R.id.details_action);
+ }
+
+ if (reportButtonView == null) {
+ reportButtonView = (TextView) actionsView.findViewById(R.id.report_action);
+ reportButtonView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (onReportButtonClickListener != null) {
+ onReportButtonClickListener.onReportButtonClick(number);
+ }
+ }
+ });
+ }
+
+ bindActionButtons(actionListener, phoneNumberUtilsWrapper, callLogViewsHelper);
+ }
+
+ /**
+ * Binds text titles, click handlers and intents to the voicemail, details and callback action
+ * buttons.
+ */
+ private void bindActionButtons(
+ View.OnClickListener actionListener,
+ PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
+ CallLogListItemHelper callLogViewsHelper) {
+ boolean canPlaceCallToNumber =
+ PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation);
+
+ // Set return call intent, otherwise null.
+ if (canPlaceCallToNumber) {
+ boolean isVoicemailNumber =
+ phoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
+ if (isVoicemailNumber) {
+ // Make a general call to voicemail to ensure that if there are multiple accounts
+ // it does not call the voicemail number of a specific phone account.
+ callBackButtonView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider());
+ } else {
+ // Sets the primary action to call the number.
+ callBackButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number));
+ }
+ callBackButtonView.setVisibility(View.VISIBLE);
+ callBackButtonView.setOnClickListener(actionListener);
+
+ final int titleId;
+ if (callType == Calls.VOICEMAIL_TYPE || callType == Calls.OUTGOING_TYPE) {
+ titleId = R.string.call_log_action_redial;
+ } else {
+ titleId = R.string.call_log_action_call_back;
+ }
+ callBackButtonView.setText(mContext.getString(titleId));
+ } else {
+ // Number is not callable, so hide button.
+ callBackButtonView.setTag(null);
+ callBackButtonView.setVisibility(View.GONE);
+ }
+
+ // If one of the calls had video capabilities, show the video call button.
+ if (CallUtil.isVideoEnabled(mContext) && canPlaceCallToNumber &&
+ phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
+ videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number));
+ videoCallButtonView.setVisibility(View.VISIBLE);
+ videoCallButtonView.setOnClickListener(actionListener);
+ } else {
+ videoCallButtonView.setTag(null);
+ videoCallButtonView.setVisibility(View.GONE);
+ }
+
+ // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise.
+ if (callType == Calls.VOICEMAIL_TYPE) {
+ voicemailButtonView.setOnClickListener(actionListener);
+ voicemailButtonView.setTag(
+ IntentProvider.getPlayVoicemailIntentProvider(rowId, voicemailUri));
+ voicemailButtonView.setVisibility(View.VISIBLE);
+
+ detailsButtonView.setVisibility(View.GONE);
+ } else {
+ voicemailButtonView.setTag(null);
+ voicemailButtonView.setVisibility(View.GONE);
+
+ detailsButtonView.setOnClickListener(actionListener);
+ detailsButtonView.setTag(
+ IntentProvider.getCallDetailIntentProvider(rowId, callIds, null));
+
+ if (canBeReportedAsInvalid && !reported) {
+ reportButtonView.setVisibility(View.VISIBLE);
+ } else {
+ reportButtonView.setVisibility(View.GONE);
+ }
+ }
+
+ callLogViewsHelper.setActionContentDescriptions(this);
+ }
+
+ public static CallLogListItemViews fromView(Context context, View view) {
return new CallLogListItemViews(
+ context,
(QuickContactBadge) view.findViewById(R.id.quick_contact_photo),
view.findViewById(R.id.primary_action_view),
PhoneCallDetailsViews.fromView(view),
@@ -135,6 +279,7 @@
@NeededForTesting
public static CallLogListItemViews createForTest(Context context) {
CallLogListItemViews views = new CallLogListItemViews(
+ context,
new QuickContactBadge(context),
new View(context),
PhoneCallDetailsViews.createForTest(context),