summaryrefslogtreecommitdiff
path: root/src/com/android
diff options
context:
space:
mode:
authorTyler Gunn <tgunn@google.com>2014-05-06 17:04:56 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-05-06 17:04:56 +0000
commit3d3ff68ffb5f0f30e03d4456892cf3e1912e39d4 (patch)
tree9ddccf18a740b4e4189de825d6eaf1df17310715 /src/com/android
parenteed2e4fbcbc614aad8f62b9a4ba78f161a2fd06a (diff)
parent146a4cdf57f0d4d0cd85e808f1df2bdea639b24c (diff)
Merge "Adding support for expandable call log entries."
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/dialer/PhoneCallDetailsHelper.java76
-rw-r--r--src/com/android/dialer/PhoneCallDetailsViews.java15
-rw-r--r--src/com/android/dialer/calllog/CallLogAdapter.java317
-rw-r--r--src/com/android/dialer/calllog/CallLogFragment.java2
-rw-r--r--src/com/android/dialer/calllog/CallLogListItemHelper.java113
-rw-r--r--src/com/android/dialer/calllog/CallLogListItemViews.java64
-rw-r--r--src/com/android/dialer/list/ListsFragment.java2
-rw-r--r--src/com/android/dialerbind/ObjectFactory.java8
8 files changed, 430 insertions, 167 deletions
diff --git a/src/com/android/dialer/PhoneCallDetailsHelper.java b/src/com/android/dialer/PhoneCallDetailsHelper.java
index 4424fcb0b..edd083117 100644
--- a/src/com/android/dialer/PhoneCallDetailsHelper.java
+++ b/src/com/android/dialer/PhoneCallDetailsHelper.java
@@ -18,9 +18,7 @@ package com.android.dialer;
import android.content.res.Resources;
import android.graphics.Typeface;
-import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.telephony.PhoneNumberUtils;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
@@ -36,6 +34,10 @@ import com.android.dialer.calllog.CallTypeHelper;
import com.android.dialer.calllog.ContactInfo;
import com.android.dialer.calllog.PhoneNumberDisplayHelper;
import com.android.dialer.calllog.PhoneNumberUtilsWrapper;
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Helper class to fill in the views in {@link PhoneCallDetailsViews}.
@@ -53,6 +55,11 @@ public class PhoneCallDetailsHelper {
private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper;
/**
+ * List of items to be concatenated together for accessibility descriptions
+ */
+ private ArrayList<CharSequence> mDescriptionItems = Lists.newArrayList();
+
+ /**
* Creates a new instance of the helper.
* <p>
* Generally you should have a single instance of this helper in any context.
@@ -90,42 +97,54 @@ public class PhoneCallDetailsHelper {
Integer highlightColor =
isHighlighted ? mCallTypeHelper.getHighlightedColor(details.callTypes[0]) : null;
- // The date of this call, relative to the current time.
- CharSequence dateText = getCallDate(details);
-
- // Set the call count and date.
- setCallCountAndDate(views, callCount, dateText, highlightColor);
+ CharSequence callLocationAndDate = getCallLocationAndDate(details);
- // Get type of call (ie mobile, home, etc) if known, or the caller's
- CharSequence numberFormattedLabel = getCallTypeOrLocation(details);
+ // Set the call count, location and date.
+ setCallCountAndDate(views, callCount, callLocationAndDate, highlightColor);
final CharSequence nameText;
- final CharSequence numberText;
- final CharSequence labelText;
final CharSequence displayNumber =
mPhoneNumberHelper.getDisplayNumber(details.number,
details.numberPresentation, details.formattedNumber);
if (TextUtils.isEmpty(details.name)) {
nameText = displayNumber;
- if (TextUtils.isEmpty(details.geocode)
- || mPhoneNumberUtilsWrapper.isVoicemailNumber(details.number)) {
- numberText = mResources.getString(R.string.call_log_empty_geocode);
- } else {
- numberText = details.geocode;
- }
- labelText = numberText;
// We have a real phone number as "nameView" so make it always LTR
views.nameView.setTextDirection(View.TEXT_DIRECTION_LTR);
} else {
nameText = details.name;
- numberText = displayNumber;
- labelText = TextUtils.isEmpty(numberFormattedLabel) ? numberText :
- numberFormattedLabel;
}
views.nameView.setText(nameText);
- views.labelView.setText(labelText);
- views.labelView.setVisibility(TextUtils.isEmpty(labelText) ? View.GONE : View.VISIBLE);
+
+ // TODO: At the current time the voicemail transcription is not supported. This view
+ // is kept for future expansion when we may wish to show a transcription of voicemail.
+ views.voicemailTranscriptionView.setText("");
+ views.voicemailTranscriptionView.setVisibility(View.GONE);
+ }
+
+ /**
+ * Builds a string containing the call location and date.
+ *
+ * @param details The call details.
+ * @return The call location and date string.
+ */
+ private CharSequence getCallLocationAndDate(PhoneCallDetails details) {
+ mDescriptionItems.clear();
+
+ // Get type of call (ie mobile, home, etc) if known, or the caller's location.
+ CharSequence callTypeOrLocation = getCallTypeOrLocation(details);
+
+ // Only add the call type or location if its not empty. It will be empty for unknown
+ // callers.
+ if (!TextUtils.isEmpty(callTypeOrLocation)) {
+ mDescriptionItems.add(callTypeOrLocation);
+ }
+ // The date of this call, relative to the current time.
+ mDescriptionItems.add(getCallDate(details));
+
+ // Create a comma separated list from the call type or location, and call date.
+ // TextUtils.join ensures a locale appropriate list separator is used.
+ return TextUtils.join((List<CharSequence>)mDescriptionItems);
}
/**
@@ -139,7 +158,9 @@ public class PhoneCallDetailsHelper {
CharSequence numberFormattedLabel = null;
// Only show a label if the number is shown and it is not a SIP address.
if (!TextUtils.isEmpty(details.number)
- && !PhoneNumberHelper.isUriNumber(details.number.toString())) {
+ && !PhoneNumberHelper.isUriNumber(details.number.toString())
+ && !mPhoneNumberUtilsWrapper.isVoicemailNumber(details.number)) {
+
if (details.numberLabel == ContactInfo.GEOCODE_AS_LABEL) {
numberFormattedLabel = details.geocode;
} else {
@@ -147,6 +168,11 @@ public class PhoneCallDetailsHelper {
details.numberLabel);
}
}
+
+ if (!TextUtils.isEmpty(details.name) && TextUtils.isEmpty(numberFormattedLabel)) {
+ numberFormattedLabel = mPhoneNumberHelper.getDisplayNumber(details.number,
+ details.numberPresentation, details.formattedNumber);
+ }
return numberFormattedLabel;
}
@@ -216,7 +242,7 @@ public class PhoneCallDetailsHelper {
formattedText = text;
}
- views.callTypeAndDate.setText(formattedText);
+ views.callLocationAndDate.setText(formattedText);
}
/** Creates a SpannableString for the given text which is bold and in the given color. */
diff --git a/src/com/android/dialer/PhoneCallDetailsViews.java b/src/com/android/dialer/PhoneCallDetailsViews.java
index 4e482109b..30023ea11 100644
--- a/src/com/android/dialer/PhoneCallDetailsViews.java
+++ b/src/com/android/dialer/PhoneCallDetailsViews.java
@@ -29,16 +29,17 @@ public final class PhoneCallDetailsViews {
public final TextView nameView;
public final View callTypeView;
public final CallTypeIconsView callTypeIcons;
- public final TextView callTypeAndDate;
- public final TextView labelView;
+ public final TextView callLocationAndDate;
+ public final TextView voicemailTranscriptionView;
private PhoneCallDetailsViews(TextView nameView, View callTypeView,
- CallTypeIconsView callTypeIcons, TextView callTypeAndDate, TextView labelView) {
+ CallTypeIconsView callTypeIcons, TextView callLocationAndDate,
+ TextView voicemailTranscriptionView) {
this.nameView = nameView;
this.callTypeView = callTypeView;
this.callTypeIcons = callTypeIcons;
- this.callTypeAndDate = callTypeAndDate;
- this.labelView = labelView;
+ this.callLocationAndDate = callLocationAndDate;
+ this.voicemailTranscriptionView = voicemailTranscriptionView;
}
/**
@@ -52,8 +53,8 @@ public final class PhoneCallDetailsViews {
return new PhoneCallDetailsViews((TextView) view.findViewById(R.id.name),
view.findViewById(R.id.call_type),
(CallTypeIconsView) view.findViewById(R.id.call_type_icons),
- (TextView) view.findViewById(R.id.call_count_and_date),
- (TextView) view.findViewById(R.id.label));
+ (TextView) view.findViewById(R.id.call_location_and_date),
+ (TextView) view.findViewById(R.id.voicemail_transcription));
}
public static PhoneCallDetailsViews createForTest(Context context) {
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 266be34ba..a8cd72a39 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.CallLog.Calls;
@@ -35,20 +36,26 @@ import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.common.widget.GroupingListAdapter;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.util.UriUtils;
+import com.android.dialer.CallDetailActivity;
import com.android.dialer.PhoneCallDetails;
import com.android.dialer.PhoneCallDetailsHelper;
import com.android.dialer.R;
+import com.android.dialer.util.AsyncTaskExecutor;
+import com.android.dialer.util.AsyncTaskExecutors;
import com.android.dialer.util.ExpirableCache;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
+import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Map;
/**
* Adapter class to fill in data for the Call Log.
@@ -56,6 +63,12 @@ import java.util.LinkedList;
public class CallLogAdapter extends GroupingListAdapter
implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator {
+
+ /** The enumeration of {@link android.os.AsyncTask} objects used in this class. */
+ public enum Tasks {
+ REMOVE_CALL_LOG_ENTRIES,
+ }
+
/** Interface used to initiate a refresh of the content. */
public interface CallFetcher {
public void fetchCalls();
@@ -103,6 +116,9 @@ public class CallLogAdapter extends GroupingListAdapter
private final CallFetcher mCallFetcher;
private ViewTreeObserver mViewTreeObserver = null;
+ /** Aynchronous task executor, lazy instantiated as needed. */
+ private AsyncTaskExecutor mAsyncTaskExecutor;
+
/**
* A cache of the contact details for the phone numbers in the call log.
* <p>
@@ -113,6 +129,9 @@ public class CallLogAdapter extends GroupingListAdapter
*/
private ExpirableCache<NumberWithCountryIso, ContactInfo> mContactInfoCache;
+ /** Hashmap, keyed by call Id, used to track which call log entries have been expanded or not */
+ private HashMap<Long,Boolean> mIsExpanded = new HashMap<Long,Boolean>();
+
/**
* A request for contact details for the given number.
*/
@@ -186,12 +205,6 @@ public class CallLogAdapter extends GroupingListAdapter
/** Can be set to true by tests to disable processing of requests. */
private volatile boolean mRequestProcessingDisabled = false;
- /**
- * Whether to show the secondary action button used to play voicemail or show call details.
- * True if created from a CallLogFragment.
- * False if created from the PhoneFavoriteFragment. */
- private boolean mShowSecondaryActionButton = true;
-
private boolean mIsCallLog = true;
private int mNumMissedCalls = 0;
private int mNumMissedCallsShown = 0;
@@ -211,6 +224,35 @@ public class CallLogAdapter extends GroupingListAdapter
}
};
+ /**
+ * Click listener for the delete from call log button. Removes the current call log
+ * entry and its associated calls from the call log.
+ */
+ private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Retrieve the views from the call log view.
+ final CallLogListItemViews views =
+ (CallLogListItemViews)
+ ((View)v.getParent().getParent().getParent().getParent()).getTag();
+
+ deleteCalls(views.callIds);
+ notifyDataSetChanged();
+ }
+ };
+
+ /**
+ * The onClickListener used to expand or collapse the action buttons section for a call log
+ * entry.
+ */
+ private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ expandOrCollapseActions((View) v.getParent().getParent());
+ notifyDataSetChanged();
+ }
+ };
+
private void startActivityForAction(View view) {
final IntentProvider intentProvider = (IntentProvider) view.getTag();
if (intentProvider != null) {
@@ -251,14 +293,13 @@ public class CallLogAdapter extends GroupingListAdapter
};
public CallLogAdapter(Context context, CallFetcher callFetcher,
- ContactInfoHelper contactInfoHelper, boolean showSecondaryActionButton,
+ ContactInfoHelper contactInfoHelper,
boolean isCallLog) {
super(context);
mContext = context;
mCallFetcher = callFetcher;
mContactInfoHelper = contactInfoHelper;
- mShowSecondaryActionButton = showSecondaryActionButton;
mIsCallLog = isCallLog;
mContactInfoCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
@@ -512,8 +553,6 @@ public class CallLogAdapter extends GroupingListAdapter
private void findAndCacheViews(View view) {
// Get the views to bind to.
CallLogListItemViews views = CallLogListItemViews.fromView(view);
- views.primaryActionView.setOnClickListener(mActionListener);
- views.secondaryActionButtonView.setOnClickListener(mActionListener);
view.setTag(views);
}
@@ -537,36 +576,55 @@ public class CallLogAdapter extends GroupingListAdapter
final long duration = c.getLong(CallLogQuery.DURATION);
final int callType = c.getInt(CallLogQuery.CALL_TYPE);
final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
+ final long rowId = c.getLong(CallLogQuery.ID);
+ views.rowId = rowId;
+
+ // Store some values used when the actions ViewStub is inflated on expansion of the actions
+ // section.
+ views.number = number;
+ views.numberPresentation = numberPresentation;
+ views.callType = callType;
+ views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
+ // Stash away the Ids of the calls so that we can support deleting a row in the call log.
+ views.callIds = getCallIds(c, rowId, count);
final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c);
final boolean isVoicemailNumber =
PhoneNumberUtilsWrapper.INSTANCE.isVoicemailNumber(number);
- // Primary action is always to call, if possible.
- if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)) {
- // Sets the primary action to call the number.
- views.primaryActionView.setTag(IntentProvider.getReturnCallIntentProvider(number));
- } else {
- views.primaryActionView.setTag(null);
- }
+ // Where binding and not in the call log, use default behaviour of invoking a call when
+ // tapping the primary view.
+ if (!mIsCallLog) {
+ views.primaryActionView.setOnClickListener(this.mActionListener);
- if ( mShowSecondaryActionButton ) {
- // Store away the voicemail information so we can play it directly.
- if (callType == Calls.VOICEMAIL_TYPE) {
- String voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
- final long rowId = c.getLong(CallLogQuery.ID);
- views.secondaryActionButtonView.setTag(
- IntentProvider.getPlayVoicemailIntentProvider(rowId, voicemailUri));
+ // Set return call intent, otherwise null.
+ if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)) {
+ // Sets the primary action to call the number.
+ views.primaryActionView.setTag(IntentProvider.getReturnCallIntentProvider(number));
} else {
- // Store the call details information.
- views.secondaryActionButtonView.setTag(
- IntentProvider.getCallDetailIntentProvider(
- getCursor(), c.getPosition(), c.getLong(CallLogQuery.ID), count));
+ // Number is not callable, so hide button.
+ views.primaryActionView.setTag(null);
}
} else {
- // No action enabled.
- views.secondaryActionButtonView.setTag(null);
+ // In the call log, expand/collapse an actions section for the call log entry when
+ // the primary view is tapped.
+
+ // TODO: This needs to be changed to do the proper QP open/close animation.
+ views.primaryActionView.setOnClickListener(this.mExpandCollapseListener);
+
+ // Note: Binding of the action buttons is done as required in configureActionViews
+ // when the user expands the actions ViewStub.
+ }
+
+ // Restore expansion state of the row on rebind. Inflate the actions ViewStub if required,
+ // and set its visibility state accordingly.
+ if (isExpanded(rowId)) {
+ // Inflate the view stub if necessary, and wire up the event handlers.
+ inflateActionViewStub(view);
+ views.actionsView.setVisibility(View.VISIBLE);
+ } else if (views.actionsView != null) {
+ views.actionsView.setVisibility(View.GONE);
}
// Lookup contacts with this number
@@ -631,8 +689,7 @@ public class CallLogAdapter extends GroupingListAdapter
final boolean isNew = c.getInt(CallLogQuery.IS_READ) == 0;
// New items also use the highlighted version of the text.
final boolean isHighlighted = isNew;
- mCallLogViewsHelper.setPhoneCallDetails(views, details, isHighlighted,
- mShowSecondaryActionButton);
+ mCallLogViewsHelper.setPhoneCallDetails(views, details, isHighlighted);
int contactType = ContactPhotoManager.TYPE_DEFAULT;
@@ -668,6 +725,130 @@ public class CallLogAdapter extends GroupingListAdapter
bindBadge(view, info, details, callType);
}
+ /**
+ * Determines if a call log row with the given Id is expanded to show the action buttons or
+ * not. If the row Id is not yet tracked, add a new entry assuming the row is collapsed.
+ * @param rowId
+ * @return
+ */
+ private boolean isExpanded(long rowId) {
+ if (!mIsExpanded.containsKey(rowId)) {
+ mIsExpanded.put(rowId, false);
+ }
+
+ return mIsExpanded.get(rowId);
+ }
+
+ /**
+ * Toggles the expansion state tracked for the call log row identified by rowId and returns
+ * the new expansion state.
+ *
+ * @param rowId The row Id associated with the call log row to expand/collapse.
+ * @return True where the row is now expanded, false otherwise.
+ */
+ private boolean toggleExpansion(long rowId) {
+ boolean isExpanded = isExpanded(rowId);
+
+ mIsExpanded.put(rowId, !isExpanded);
+ return !isExpanded;
+ }
+
+ /**
+ * Expands or collapses the view containing the CALLBACK, VOICEMAIL and DELETE action buttons.
+ *
+ * @param callLogItem The call log entry parent view.
+ */
+ private void expandOrCollapseActions(View callLogItem) {
+ final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
+
+ // Hide or show the actions view.
+ boolean expanded = toggleExpansion(views.rowId);
+
+ // Inflate the view stub if necessary, and wire up the event handlers.
+ inflateActionViewStub(callLogItem);
+
+ if (expanded) {
+ views.actionsView.setVisibility(View.VISIBLE);
+
+ // Attempt to give accessibility focus to one of the action buttons.
+ // This ensures that a user realizes the expansion occurred.
+ // NOTE(tgunn): requestAccessibilityFocus returns true if the requested
+ // focus was successful. The first successful focus will satisfy the OR
+ // block and block further attempts to set focus.
+ boolean focused = views.callBackButtonView.requestAccessibilityFocus() ||
+ views.voicemailButtonView.requestAccessibilityFocus() ||
+ views.deleteButtonView.requestAccessibilityFocus();
+ } else {
+ views.actionsView.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * 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(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 = stub.inflate();
+ }
+
+ if (views.callBackButtonView == null) {
+ views.callBackButtonView = (TextView)views.actionsView.findViewById(R.id.call_back_action);
+ }
+
+ if (views.voicemailButtonView == null) {
+ views.voicemailButtonView = (TextView)views.actionsView.findViewById(R.id.voicemail_action);
+ }
+
+ if ( views.deleteButtonView == null) {
+ views.deleteButtonView = (TextView)views.actionsView.findViewById(R.id.delete_action);
+ }
+
+ bindActionButtons(views);
+ }
+
+ /***
+ * Binds click handlers and intents to the voicemail, delete and callback action buttons.
+ *
+ * @param views The call log item views.
+ */
+ private void bindActionButtons(CallLogListItemViews views) {
+ // Set return call intent, otherwise null.
+ if (PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation)) {
+ // Sets the primary action to call the number.
+ views.callBackButtonView.setTag(
+ IntentProvider.getReturnCallIntentProvider(views.number));
+ views.callBackButtonView.setVisibility(View.VISIBLE);
+ views.callBackButtonView.setOnClickListener(mActionListener);
+ } else {
+ // Number is not callable, so hide button.
+ views.callBackButtonView.setTag(null);
+ views.callBackButtonView.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);
+ } else {
+ views.voicemailButtonView.setTag(null);
+ views.voicemailButtonView.setVisibility(View.GONE);
+ }
+
+ views.deleteButtonView.setOnClickListener(this.mDeleteListener);
+
+ mCallLogViewsHelper.setActionContentDescriptions(views);
+ }
+
protected void bindBadge(View view, ContactInfo info, PhoneCallDetails details, int callType) {
// Do not show badge in call log.
@@ -960,4 +1141,76 @@ public class CallLogAdapter extends GroupingListAdapter
}
return number;
}
+
+ /**
+ * Retrieves the call Ids represented by the current call log row.
+ *
+ * @param cursor Call log cursor to retrieve call Ids from.
+ * @param id Id of the first call of the grouping.
+ * @param groupSize Number of calls associated with the current call log row.
+ * @return Array of call Ids.
+ */
+ private long[] getCallIds(final Cursor cursor, final long id, final int groupSize) {
+ // We want to restore the position in the cursor at the end.
+ int startingPosition = cursor.getPosition();
+ long[] ids = new long[groupSize];
+ // Copy the ids of the rows in the group.
+ for (int index = 0; index < groupSize; ++index) {
+ ids[index] = cursor.getLong(CallLogQuery.ID);
+ cursor.moveToNext();
+ }
+ cursor.moveToPosition(startingPosition);
+ return ids;
+ }
+
+ /**
+ * Retrieves an instance of the asynchronous task executor, creating one if required.
+ * @return The {@link com.android.dialer.util.AsyncTaskExecutor}
+ */
+ private AsyncTaskExecutor getTaskExecutor() {
+ if (mAsyncTaskExecutor == null) {
+ mAsyncTaskExecutor = AsyncTaskExecutors.createAsyncTaskExecutor();
+ }
+ return mAsyncTaskExecutor;
+ }
+
+ /**
+ * Deletes the calls specified in the callIds array, asynchronously.
+ *
+ * @param callIds Ids of calls to be deleted.
+ */
+ private void deleteCalls(long[] callIds) {
+ if (callIds == null) {
+ return;
+ }
+
+ // Build comma separated list of ids to delete.
+ final StringBuilder callIdString = new StringBuilder();
+ for (long callId : callIds) {
+ if (callIdString.length() != 0) {
+ callIdString.append(",");
+ }
+ callIdString.append(callId);
+ }
+
+ // Perform removal of call log entries asynchronously.
+ getTaskExecutor().submit(Tasks.REMOVE_CALL_LOG_ENTRIES,
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... params) {
+ // Issue delete.
+ mContext.getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+ Calls._ID + " IN (" + callIdString + ")", null);
+ return null;
+ }
+
+ @Override
+ public void onPostExecute(Void result) {
+ // Somewhere went wrong: we're going to bail out and show error to users.
+ Toast.makeText(mContext, R.string.toast_entry_removed,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ );
+ }
}
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index 2ab613646..094815182 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -154,7 +154,7 @@ public class CallLogFragment extends ListFragment
String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
mAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this, new ContactInfoHelper(
- getActivity(), currentCountryIso), true, true);
+ getActivity(), currentCountryIso), true);
setListAdapter(mAdapter);
mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
this, mLogLimit);
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index a85cd019e..81d1a2711 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -25,6 +25,7 @@ import android.view.View;
import com.android.dialer.PhoneCallDetails;
import com.android.dialer.PhoneCallDetailsHelper;
import com.android.dialer.R;
+import com.android.internal.util.CharSequences;
/**
* Helper class to fill in the views of a call log entry.
@@ -56,13 +57,11 @@ import com.android.dialer.R;
* @param views the views to populate
* @param details the details of a phone call needed to fill in the data
* @param isHighlighted whether to use the highlight text for the call
- * @param showSecondaryActionButton whether to show the secondary action button or not
*/
public void setPhoneCallDetails(CallLogListItemViews views, PhoneCallDetails details,
- boolean isHighlighted, boolean showSecondaryActionButton) {
+ boolean isHighlighted) {
mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details,
isHighlighted);
- boolean canPlay = details.callTypes[0] == Calls.VOICEMAIL_TYPE;
// Set the accessibility text for the contact badge
views.quickContactView.setContentDescription(getContactBadgeDescription(details));
@@ -70,35 +69,25 @@ import com.android.dialer.R;
// Set the primary action accessibility description
views.primaryActionView.setContentDescription(getCallDescription(details));
- // If secondary action is visible, either show voicemail playback icon, or
- // show the "clock" icon corresponding to the call details screen.
- if (showSecondaryActionButton) {
- if (canPlay) {
- // Playback action takes preference.
- configurePlaySecondaryAction(views, isHighlighted);
- } else {
- // Call details is the secondary action.
- configureCallDetailsSecondaryAction(views, details);
- }
- } else {
- // No secondary action is to be shown (ie this is likely a PhoneFavoriteFragment)
- views.secondaryActionView.setVisibility(View.GONE);
- }
+ // Cache name or number of caller. Used when setting the content descriptions of buttons
+ // when the actions ViewStub is inflated.
+ views.nameOrNumber = this.getNameOrNumber(details);
}
/**
- * Sets the secondary action to invoke call details.
+ * Sets the accessibility descriptions for the action buttons in the action button ViewStub.
*
- * @param views the views to populate
- * @param details the details of a phone call needed to fill in the call details data
+ * @param views The views associated with the current call log entry.
*/
- private void configureCallDetailsSecondaryAction(CallLogListItemViews views,
- PhoneCallDetails details) {
- views.secondaryActionView.setVisibility(View.VISIBLE);
- // Use the small dark grey clock icon.
- views.secondaryActionButtonView.setImageResource(R.drawable.ic_menu_history_dk);
- views.secondaryActionButtonView.setContentDescription(
- mResources.getString(R.string.description_call_details));
+ public void setActionContentDescriptions(CallLogListItemViews views) {
+ views.callBackButtonView.setContentDescription(
+ mResources.getString(R.string.description_call_back_action, views.nameOrNumber));
+
+ views.voicemailButtonView.setContentDescription(
+ mResources.getString(R.string.description_voicemail_action, views.nameOrNumber));
+
+ views.deleteButtonView.setContentDescription(
+ mResources.getString(R.string.description_delete_action, views.nameOrNumber));
}
/**
@@ -123,16 +112,11 @@ import com.android.dialer.R;
*
* The {Caller Information} references the most recent call associated with the caller.
* For incoming calls:
- * If missed call: Return missed call from {Name/Number} {Call Type} {Call Time}.
- * If answered call: Return answered call from {Name/Number} {Call Type} {Call Time}.
- *
- * For unknown callers, drop the "Return" part, since the call can't be returned:
- * If answered unknown: Answered call from {Name/Number} {Call Time}.
- * If missed unknown: Missed call from {Name/Number} {Call Time}.
+ * If missed call: Missed call from {Name/Number} {Call Type} {Call Time}.
+ * If answered call: Answered call from {Name/Number} {Call Type} {Call Time}.
*
* For outgoing calls:
- * If outgoing: Call {Name/Number] {Call Type}. {Last} called {Call Time}.
- * Where {Last} is dropped if the number of calls for the caller is 1.
+ * If outgoing: Call to {Name/Number] {Call Type} {Call Time}.
*
* Where:
* {Name/Number} is the name or number of the caller (as shown in call log).
@@ -140,8 +124,8 @@ import com.android.dialer.R;
* {Call Time} is the time since the last call for the contact occurred.
*
* Examples:
- * 3 calls. New Voicemail. Return missed call from Joe Smith mobile 2 hours ago.
- * 2 calls. Call John Doe mobile. Last called 1 hour ago.
+ * 3 calls. New Voicemail. Missed call from Joe Smith mobile 2 hours ago.
+ * 2 calls. Answered call from John Doe mobile. Last called 1 hour ago.
* @param details Details of call.
* @return Return call action description.
*/
@@ -191,43 +175,17 @@ import com.android.dialer.R;
*/
public int getCallDescriptionStringID(PhoneCallDetails details) {
int lastCallType = getLastCallType(details.callTypes);
- boolean isNumberCallable = PhoneNumberUtilsWrapper.canPlaceCallsTo(details.number,
- details.numberPresentation);
-
- // Default string to use is "call XYZ..." just in case we manage to fall through.
- int stringID = R.string.description_call_last_multiple;
-
- if (!isNumberCallable) {
- // Number isn't callable; this is an incoming call from an unknown caller.
- // An uncallable outgoing call wouldn't be in the call log.
-
- // Voicemail and missed calls are both considered missed.
- if (lastCallType == Calls.VOICEMAIL_TYPE ||
- lastCallType == Calls.MISSED_TYPE) {
- stringID = R.string.description_unknown_missed_call;
- } else if (lastCallType == Calls.INCOMING_TYPE) {
- stringID = R.string.description_unknown_answered_call;
- }
+ int stringID;
+
+ if (lastCallType == Calls.VOICEMAIL_TYPE || lastCallType == Calls.MISSED_TYPE) {
+ //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>.
+ stringID = R.string.description_incoming_missed_call;
+ } else if (lastCallType == Calls.INCOMING_TYPE) {
+ //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>.
+ stringID = R.string.description_incoming_answered_call;
} else {
- // Known caller, so callable.
-
- // Missed call (ie voicemail or missed)
- if (lastCallType == Calls.VOICEMAIL_TYPE ||
- lastCallType == Calls.MISSED_TYPE) {
- stringID = R.string.description_return_missed_call;
- } else if (lastCallType == Calls.INCOMING_TYPE) {
- // Incoming answered.
- stringID = R.string.description_return_answered_call;
- } else {
- // Outgoing call.
-
- // If we have a history of multiple calls
- if (details.callTypes.length > 1) {
- stringID = R.string.description_call_last_multiple;
- } else {
- stringID = R.string.description_call_last;
- }
- }
+ //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>.
+ stringID = R.string.description_outgoing_call;
}
return stringID;
}
@@ -260,13 +218,4 @@ import com.android.dialer.R;
}
return recipient;
}
-
- /** Sets the secondary action to correspond to the play button. */
- private void configurePlaySecondaryAction(CallLogListItemViews views, boolean isHighlighted) {
- views.secondaryActionView.setVisibility(View.VISIBLE);
- views.secondaryActionButtonView.setImageResource(
- isHighlighted ? R.drawable.ic_play_active_holo_dark : R.drawable.ic_play_holo_light);
- views.secondaryActionButtonView.setContentDescription(
- mResources.getString(R.string.description_call_log_play_button));
- }
}
diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViews.java
index a3789569e..879647f15 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViews.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViews.java
@@ -34,25 +34,67 @@ public final class CallLogListItemViews {
public final QuickContactBadge quickContactView;
/** The primary action view of the entry. */
public final View primaryActionView;
- /** The secondary action view, which includes both the vertical divider line and
- * the action button itself. Used so that the button and divider line can be
- * made visible/hidden as a whole. */
- public final View secondaryActionView;
- /** The secondary action button on the entry. */
- public final ImageView secondaryActionButtonView;
/** The details of the phone call. */
public final PhoneCallDetailsViews phoneCallDetailsViews;
/** The text of the header of a section. */
public final TextView listHeaderTextView;
+ /** 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 "delete" action button - assigned only when the action section is expanded. */
+ public TextView deleteButtonView;
+ /** The "voicemail" action button - assigned only when the action section is expanded. */
+ public TextView voicemailButtonView;
+
+ /**
+ * The row Id for the first call associated with the call log entry. Used as a key for the
+ * map used to track which call log entries have the action button section expanded.
+ */
+ public long rowId;
+
+ /**
+ * The call Ids for the calls represented by the current call log entry. Used when the user
+ * deletes a call log entry.
+ */
+ public long[] callIds;
+
+ /**
+ * The callable phone number for the current call log entry. Cached here as the call back
+ * intent is set only when the actions ViewStub is inflated.
+ */
+ public String number;
+
+ /**
+ * The phone number presentation for the current call log entry. Cached here as the call back
+ * intent is set only when the actions ViewStub is inflated.
+ */
+ public int numberPresentation;
+
+ /**
+ * The type of call for the current call log entry. Cached here as the call back
+ * intent is set only when the actions ViewStub is inflated.
+ */
+ public int callType;
+
+ /**
+ * If the call has an associated voicemail message, the URI of the voicemail message for
+ * playback. Cached here as the voicemail intent is only set when the actions ViewStub is
+ * inflated.
+ */
+ public String voicemailUri;
+
+ /**
+ * The name or number associated with the call. Cached here for use when setting content
+ * descriptions on buttons in the actions ViewStub when it is inflated.
+ */
+ public CharSequence nameOrNumber;
private CallLogListItemViews(QuickContactBadge quickContactView, View primaryActionView,
- View secondaryActionView, ImageView secondaryActionButtonView,
PhoneCallDetailsViews phoneCallDetailsViews,
TextView listHeaderTextView) {
this.quickContactView = quickContactView;
this.primaryActionView = primaryActionView;
- this.secondaryActionView = secondaryActionView;
- this.secondaryActionButtonView = secondaryActionButtonView;
this.phoneCallDetailsViews = phoneCallDetailsViews;
this.listHeaderTextView = listHeaderTextView;
}
@@ -61,8 +103,6 @@ public final class CallLogListItemViews {
return new CallLogListItemViews(
(QuickContactBadge) view.findViewById(R.id.quick_contact_photo),
view.findViewById(R.id.primary_action_view),
- view.findViewById(R.id.secondary_action_view),
- (ImageView) view.findViewById(R.id.secondary_action_icon),
PhoneCallDetailsViews.fromView(view),
(TextView) view.findViewById(R.id.call_log_header));
}
@@ -72,8 +112,6 @@ public final class CallLogListItemViews {
return new CallLogListItemViews(
new QuickContactBadge(context),
new View(context),
- new View(context),
- new ImageView(context),
PhoneCallDetailsViews.createForTest(context),
new TextView(context));
}
diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java
index 49d6b3af3..88e5ce0e9 100644
--- a/src/com/android/dialer/list/ListsFragment.java
+++ b/src/com/android/dialer/list/ListsFragment.java
@@ -177,7 +177,7 @@ public class ListsFragment extends Fragment implements CallLogQueryHandler.Liste
this, 1);
final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
- new ContactInfoHelper(getActivity(), currentCountryIso), false, false);
+ new ContactInfoHelper(getActivity(), currentCountryIso), false);
mMergedAdapter = new ShortcutCardsAdapter(getActivity(), this, mCallLogAdapter);
}
diff --git a/src/com/android/dialerbind/ObjectFactory.java b/src/com/android/dialerbind/ObjectFactory.java
index be91e3310..e7ca8d9e3 100644
--- a/src/com/android/dialerbind/ObjectFactory.java
+++ b/src/com/android/dialerbind/ObjectFactory.java
@@ -39,15 +39,11 @@ public class ObjectFactory {
* @param context The context to use.
* @param callFetcher Instance of call fetcher to use.
* @param contactInfoHelper Instance of contact info helper class to use.
- * @param hideSecondaryAction If true, secondary action will be hidden (ie call details
- * or play voicemail).
* @param isCallLog Is this call log adapter being used on the call log?
* @return Instance of CallLogAdapter.
*/
public static CallLogAdapter newCallLogAdapter(Context context, CallFetcher callFetcher,
- ContactInfoHelper contactInfoHelper, boolean hideSecondaryAction,
- boolean isCallLog) {
- return new CallLogAdapter(context, callFetcher, contactInfoHelper, hideSecondaryAction,
- isCallLog);
+ ContactInfoHelper contactInfoHelper, boolean isCallLog) {
+ return new CallLogAdapter(context, callFetcher, contactInfoHelper, isCallLog);
}
}