diff options
author | Andrew Lee <anwlee@google.com> | 2015-04-15 17:23:27 -0700 |
---|---|---|
committer | Andrew Lee <anwlee@google.com> | 2015-04-16 09:39:49 -0700 |
commit | c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264 (patch) | |
tree | 7e3747d673f53e9c201442a503f6cff0a6e3bfe6 /src | |
parent | 1582ac15d1f30a651000aa5d5098d73be3aa4810 (diff) |
Move call log actions into expandable view.
This isn't the prettiest thing ever, but with this the "framework" of
all of the changes for the new visual style of the call logs is in
place. From here on out, the remainder of tasks should be unblocked
and relatively independent.
+ Rename ...ItemViews to ...ItemViewHolder. This probably wasn't
completely necessary, but is more proper given the new architecture.
+ ViewHolder is now officially where most of the independent UI logic
for a single call log list item should live. This changelist moves
further in that direction by storing references and helpers in it, to
lessen what must be passed in from the adapter.
+ Split out the call action from the rest of the actions, since it
has a special treatment on the card.
+ Convert text action buttons into a vertical stack.
+ Consolidate action stylings into a single style, for simplicity.
+ Miscellaneous style and string changes to put things in a better
state. This included tweaking some of the (ripple) backgrounds.
+ Update tests, according to changes.
Bug: 19372817
Change-Id: Ic923c0bcbbc1c153952131d0c772df9e9589fb03
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/dialer/calllog/CallLogAdapter.java | 49 | ||||
-rw-r--r-- | src/com/android/dialer/calllog/CallLogListItemHelper.java | 8 | ||||
-rw-r--r-- | src/com/android/dialer/calllog/CallLogListItemViewHolder.java (renamed from src/com/android/dialer/calllog/CallLogListItemViews.java) | 202 |
3 files changed, 142 insertions, 117 deletions
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java index 07cd215e9..cc1a4a632 100644 --- a/src/com/android/dialer/calllog/CallLogAdapter.java +++ b/src/com/android/dialer/calllog/CallLogAdapter.java @@ -153,8 +153,7 @@ public class CallLogAdapter extends GroupingListAdapter private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() { @Override public void onClick(View v) { - final View callLogItem = (View) v.getParent().getParent(); - handleRowExpanded(callLogItem, false /* forceExpand */); + handleRowExpanded(v, false /* forceExpand */); } }; @@ -266,15 +265,15 @@ public class CallLogAdapter extends GroupingListAdapter LayoutInflater inflater = LayoutInflater.from(mContext); 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(mContext, view); - view.setTag(views); - - // Set text height to false on the TextViews so they don't have extra padding. - views.phoneCallDetailsViews.nameView.setElegantTextHeight(false); - views.phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false); + CallLogListItemViewHolder viewHolder = CallLogListItemViewHolder.create( + view, + mContext, + mActionListener, + mPhoneNumberUtilsWrapper, + mCallLogViewsHelper); + viewHolder.primaryActionView.setTag(viewHolder); - return (CallLogListItemViews) view.getTag(); + return viewHolder; } /** @@ -292,7 +291,7 @@ public class CallLogAdapter extends GroupingListAdapter } int count = getGroupSize(position); - CallLogListItemViews views = (CallLogListItemViews) viewHolder; + CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder; views.rootView.setAccessibilityDelegate(mAccessibilityDelegate); // Default case: an item in the call log. @@ -378,12 +377,7 @@ public class CallLogAdapter extends GroupingListAdapter // Restore expansion state of the row on rebind. Inflate the actions ViewStub if required, // and set its visibility state accordingly. - views.expandOrCollapseActions( - isExpanded(rowId), - mOnReportButtonClickListener, - mActionListener, - mPhoneNumberUtilsWrapper, - mCallLogViewsHelper); + views.showActions(isExpanded(rowId), mOnReportButtonClickListener); if (TextUtils.isEmpty(name)) { details = new PhoneCallDetails(number, numberPresentation, formattedNumber, countryIso, @@ -409,6 +403,8 @@ public class CallLogAdapter extends GroupingListAdapter mContactInfoHelper.isBusiness(info.sourceType)); views.quickContactView.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE); + views.updateCallButton(); + // Listen for the first draw if (mViewTreeObserver == null) { mViewTreeObserver = views.rootView.getViewTreeObserver(); @@ -603,28 +599,13 @@ public class CallLogAdapter extends GroupingListAdapter * of its previous state */ private void handleRowExpanded(View view, boolean forceExpand) { - final CallLogListItemViews views = (CallLogListItemViews) view.getTag(); + final CallLogListItemViewHolder views = (CallLogListItemViewHolder) view.getTag(); if (forceExpand && isExpanded(views.rowId)) { return; } - // Hide or show the actions view. boolean expanded = toggleExpansion(views.rowId); - expandItem(views, expanded); - } - - /** - * @param views The view holder for the item to expand or collapse. - * @param expand {@code true} to expand the item, {@code false} otherwise. - */ - public void expandItem(CallLogListItemViews views, boolean expand) { - // Trigger loading of the viewstub and visual expand or collapse. - views.expandOrCollapseActions( - expand, - mOnReportButtonClickListener, - mActionListener, - mPhoneNumberUtilsWrapper, - mCallLogViewsHelper); + views.showActions(expanded, mOnReportButtonClickListener); } } diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java index 77ad333d9..0e94ef402 100644 --- a/src/com/android/dialer/calllog/CallLogListItemHelper.java +++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java @@ -62,7 +62,7 @@ import com.android.dialer.R; * @param details the details of a phone call needed to fill in the data */ public void setPhoneCallDetails( - Context context, CallLogListItemViews views, PhoneCallDetails details) { + Context context, CallLogListItemViewHolder views, PhoneCallDetails details) { mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details); // Set the accessibility text for the contact badge @@ -81,7 +81,7 @@ import com.android.dialer.R; * * @param views The views associated with the current call log entry. */ - public void setActionContentDescriptions(CallLogListItemViews views) { + public void setActionContentDescriptions(CallLogListItemViewHolder views) { if (views.nameOrNumber == null) { Log.e(TAG, "setActionContentDescriptions; name or number is null."); } @@ -90,10 +90,6 @@ import com.android.dialer.R; // Although we don't expect a null name or number, it is best to protect against it. CharSequence nameOrNumber = views.nameOrNumber == null ? "" : views.nameOrNumber; - views.callBackButtonView.setContentDescription( - TextUtils.expandTemplate( - mResources.getString(R.string.description_call_back_action), nameOrNumber)); - views.videoCallButtonView.setContentDescription( TextUtils.expandTemplate( mResources.getString(R.string.description_video_call_action), diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java index 4d4343692..4b208f14a 100644 --- a/src/com/android/dialer/calllog/CallLogListItemViews.java +++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java @@ -18,6 +18,7 @@ package com.android.dialer.calllog; import android.content.Context; import android.content.res.Resources; +import android.content.Intent; import android.net.Uri; import android.provider.CallLog.Calls; import android.support.v7.widget.CardView; @@ -27,6 +28,7 @@ import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; +import android.view.ViewTreeObserver; import android.widget.QuickContactBadge; import android.widget.TextView; @@ -34,19 +36,18 @@ import com.android.contacts.common.CallUtil; import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; import com.android.contacts.common.testing.NeededForTesting; +import com.android.dialer.PhoneCallDetailsHelper; import com.android.dialer.PhoneCallDetailsViews; import com.android.dialer.R; /** - * 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 is an object containing references to views contained by the call log list item. This + * improves 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. + * This object also contains UI logic pertaining to the view, to isolate it from the CallLogAdapter. */ -public final class CallLogListItemViews extends RecyclerView.ViewHolder { +public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder { + /** The root view of the call log list item */ public final View rootView; /** The quick contact badge for the contact. */ @@ -59,10 +60,10 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { public final TextView dayGroupHeader; /** The view containing the details for the call log row, including the action buttons. */ public final CardView callLogEntryView; + /** The actionable view which places a call to the number corresponding to the call log row. */ + public final View callActionView; /** The view containing call log item actions. Null until the ViewStub is inflated. */ public View actionsView; - /** The "call back" action button - assigned only when the action section is expanded. */ - public TextView callBackButtonView; /** The "video call" action button - assigned only when the action section is expanded. */ public TextView videoCallButtonView; /** The "voicemail" action button - assigned only when the action section is expanded. */ @@ -134,20 +135,31 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { private static final int VOICEMAIL_TRANSCRIPTION_MAX_LINES = 10; - private Context mContext; - private int mPhotoSize; + private final Context mContext; + private final View.OnClickListener mActionListener; + private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper; + private final CallLogListItemHelper mCallLogListItemHelper; + private final int mPhotoSize; - private CallLogListItemViews( + private CallLogListItemViewHolder( Context context, + View.OnClickListener actionListener, + PhoneNumberUtilsWrapper phoneNumberUtilsWrapper, + CallLogListItemHelper callLogListItemHelper, View rootView, QuickContactBadge quickContactView, View primaryActionView, PhoneCallDetailsViews phoneCallDetailsViews, CardView callLogEntryView, - TextView dayGroupHeader) { + TextView dayGroupHeader, + View callActionView) { super(rootView); + mContext = context; + mActionListener = actionListener; + mPhoneNumberUtilsWrapper = phoneNumberUtilsWrapper; + mCallLogListItemHelper = callLogListItemHelper; this.rootView = rootView; this.quickContactView = quickContactView; @@ -155,20 +167,39 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { this.phoneCallDetailsViews = phoneCallDetailsViews; this.callLogEntryView = callLogEntryView; this.dayGroupHeader = dayGroupHeader; + this.callActionView = callActionView; Resources resources = mContext.getResources(); mPhotoSize = mContext.getResources().getDimensionPixelSize(R.dimen.contact_photo_size); + + // Set text height to false on the TextViews so they don't have extra padding. + phoneCallDetailsViews.nameView.setElegantTextHeight(false); + phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false); + + if (callActionView != null) { + callActionView.setOnClickListener(mActionListener); + } } - public static CallLogListItemViews fromView(Context context, View view) { - return new CallLogListItemViews( + public static CallLogListItemViewHolder create( + View view, + Context context, + View.OnClickListener actionListener, + PhoneNumberUtilsWrapper phoneNumberUtilsWrapper, + CallLogListItemHelper callLogListItemHelper) { + + return new CallLogListItemViewHolder( context, + actionListener, + phoneNumberUtilsWrapper, + callLogListItemHelper, view, (QuickContactBadge) view.findViewById(R.id.quick_contact_photo), view.findViewById(R.id.primary_action_view), PhoneCallDetailsViews.fromView(view), (CardView) view.findViewById(R.id.call_log_row), - (TextView) view.findViewById(R.id.call_log_day_group_label)); + (TextView) view.findViewById(R.id.call_log_day_group_label), + view.findViewById(R.id.call_icon)); } /** @@ -179,19 +210,12 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { * @param callLogItem The call log list item view. */ public void inflateActionViewStub( - final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener, - View.OnClickListener actionListener, - PhoneNumberUtilsWrapper phoneNumberUtilsWrapper, - CallLogListItemHelper callLogViewsHelper) { + final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener) { ViewStub stub = (ViewStub) rootView.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); } @@ -216,54 +240,54 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { }); } - bindActionButtons(actionListener, phoneNumberUtilsWrapper, callLogViewsHelper); + bindActionButtons(); } - /** - * 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) { + public void updateCallButton() { boolean canPlaceCallToNumber = PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation); - // Set return call intent, otherwise null. if (canPlaceCallToNumber) { boolean isVoicemailNumber = - phoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number); + mPhoneNumberUtilsWrapper.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()); + callActionView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider()); } else { - // Sets the primary action to call the number. - callBackButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number)); + callActionView.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; + if (nameOrNumber != null) { + callActionView.setContentDescription(TextUtils.expandTemplate( + mContext.getString(R.string.description_call_action), + nameOrNumber)); } else { - titleId = R.string.call_log_action_call_back; + callActionView.setContentDescription( + mContext.getString(R.string.description_call_log_call_action)); } - callBackButtonView.setText(mContext.getString(titleId)); + + callActionView.setVisibility(View.VISIBLE); } else { - // Number is not callable, so hide button. - callBackButtonView.setTag(null); - callBackButtonView.setVisibility(View.GONE); + callActionView.setTag(null); + callActionView.setVisibility(View.GONE); } + } + + /** + * Binds text titles, click handlers and intents to the voicemail, details and callback action + * buttons. + */ + private void bindActionButtons() { + boolean canPlaceCallToNumber = + PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation); // 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); + videoCallButtonView.setOnClickListener(mActionListener); } else { videoCallButtonView.setTag(null); videoCallButtonView.setVisibility(View.GONE); @@ -271,7 +295,7 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise. if (callType == Calls.VOICEMAIL_TYPE) { - voicemailButtonView.setOnClickListener(actionListener); + voicemailButtonView.setOnClickListener(mActionListener); voicemailButtonView.setTag( IntentProvider.getPlayVoicemailIntentProvider(rowId, voicemailUri)); voicemailButtonView.setVisibility(View.VISIBLE); @@ -281,7 +305,7 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { voicemailButtonView.setTag(null); voicemailButtonView.setVisibility(View.GONE); - detailsButtonView.setOnClickListener(actionListener); + detailsButtonView.setOnClickListener(mActionListener); detailsButtonView.setTag( IntentProvider.getCallDetailIntentProvider(rowId, callIds, null)); @@ -292,30 +316,21 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { } } - callLogViewsHelper.setActionContentDescriptions(this); + mCallLogListItemHelper.setActionContentDescriptions(this); } /** - * Expands or collapses the view containing the CALLBACK/REDIAL, VOICEMAIL and DETAILS action - * buttons. + * Show or hide the action views, such as voicemail, details, and add contact. * - * TODO: Reduce number of classes which need to be passed in to inflate the action view stub. - * 1) Instantiate them in this class, and store local references. - * 2) Set them on the CallLogListItemHelper and use it for inflation. - * 3) Implement a parent view for a call log list item, and store references in that class. + * If the action views have never been shown yet for this view, inflate the view stub. */ - public void expandOrCollapseActions( - boolean isExpanded, - final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener, - View.OnClickListener actionListener, - PhoneNumberUtilsWrapper phoneNumberUtilsWrapper, - CallLogListItemHelper callLogViewsHelper) { - expandVoicemailTranscriptionView(isExpanded); + public void showActions(boolean show, + final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener) { + expandVoicemailTranscriptionView(show); - if (isExpanded) { + if (show) { // Inflate the view stub if necessary, and wire up the event handlers. - inflateActionViewStub(onReportButtonClickListener, actionListener, - phoneNumberUtilsWrapper, callLogViewsHelper); + inflateActionViewStub(onReportButtonClickListener); actionsView.setVisibility(View.VISIBLE); actionsView.setAlpha(1.0f); @@ -326,6 +341,27 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { actionsView.setVisibility(View.GONE); } } + + if (actionsView != null) { + final ViewTreeObserver observer = callLogEntryView.getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + if (observer.isAlive()) { + observer.removeOnPreDrawListener(this); + } + + // TODO: Animate, instead of immediately resizing. + int currentHeight = primaryActionView.getHeight(); + int actionsHeight = actionsView.getVisibility() == View.VISIBLE + ? actionsView.getHeight() : 0; + callLogEntryView.getLayoutParams().height = currentHeight + actionsHeight; + callLogEntryView.requestLayout(); + + return false; + } + }); + } } public void expandVoicemailTranscriptionView(boolean isExpanded) { @@ -371,20 +407,32 @@ public final class CallLogListItemViews extends RecyclerView.ViewHolder { } @NeededForTesting - public static CallLogListItemViews createForTest(Context context) { - CallLogListItemViews views = new CallLogListItemViews( + public static CallLogListItemViewHolder createForTest(Context context) { + Resources resources = context.getResources(); + PhoneNumberDisplayHelper phoneNumberHelper = + new PhoneNumberDisplayHelper(context, resources); + PhoneNumberUtilsWrapper phoneNumberUtilsWrapper = new PhoneNumberUtilsWrapper(context); + PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper( + context, resources, phoneNumberUtilsWrapper); + + CallLogListItemViewHolder viewHolder = new CallLogListItemViewHolder( context, + null /* actionListener */, + phoneNumberUtilsWrapper, + new CallLogListItemHelper( + phoneCallDetailsHelper, phoneNumberHelper, resources), new View(context), new QuickContactBadge(context), new View(context), PhoneCallDetailsViews.createForTest(context), new CardView(context), - new TextView(context)); - views.callBackButtonView = new TextView(context); - views.voicemailButtonView = new TextView(context); - views.detailsButtonView = new TextView(context); - views.reportButtonView = new TextView(context); - views.actionsView = new View(context); - return views; + new TextView(context), + new View(context)); + viewHolder.voicemailButtonView = new TextView(context); + viewHolder.detailsButtonView = new TextView(context); + viewHolder.reportButtonView = new TextView(context); + viewHolder.actionsView = new View(context); + + return viewHolder; } } |