summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Gunn <tgunn@google.com>2014-05-15 20:56:35 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-05-15 20:56:35 +0000
commit437858ccdf5257760310d90004030a597e514f3e (patch)
treef1cdff4effa20fc2c926d9b9a3e40aa7ce5aed72
parentc4643f77f287725f955f7f5cdd6686877e6b9923 (diff)
parent4dfd7129ab04853504fe0c050e982db7b178b643 (diff)
Merge "Adding day group headings in the call log which group call log entries under 4 headings, "Today", "Yesterday", "Last week", "Other"."
-rw-r--r--res/layout/call_log_fragment.xml6
-rw-r--r--res/layout/call_log_list_item.xml33
-rw-r--r--res/values/dimens.xml2
-rw-r--r--res/values/strings.xml11
-rw-r--r--src/com/android/dialer/calllog/CallLogAdapter.java117
-rw-r--r--src/com/android/dialer/calllog/CallLogGroupBuilder.java98
-rw-r--r--src/com/android/dialer/calllog/CallLogListItemViews.java17
7 files changed, 250 insertions, 34 deletions
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index b4714a333..5cddbe749 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -61,13 +61,17 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <!-- clipChildren=true is required to ensure shadows on elevated call log entries are not
+ clipped.-->
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
android:scrollbarStyle="outsideOverlay"
android:divider="@null"
- android:nestedScrollingEnabled="true" />
+ android:nestedScrollingEnabled="true"
+ android:clipChildren="false"
+ />
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 6068bd817..b36101e55 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -22,20 +22,23 @@
android:id="@+id/call_log_list_item"
android:orientation="vertical"
>
- <!--
- This layout may represent either a call log item or one of the
- headers in the call log.
-
- The former will make the @id/call_log_item visible and the
- @id/call_log_header gone.
-
- The latter will make the @id/call_log_header visible and the
- @id/call_log_item gone
- -->
-
+ <!-- Day group heading. Used to show a "today", "yesterday", "last week" or "other" heading
+ above a group of call log entries. -->
+ <TextView
+ android:id="@+id/call_log_day_group_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/call_log_outer_margin"
+ android:layout_marginEnd="@dimen/call_log_outer_margin"
+ android:textColor="?attr/call_log_secondary_text_color"
+ android:textSize="@dimen/call_log_secondary_text_size"
+ android:paddingTop="@dimen/call_log_day_group_padding"
+ android:paddingBottom="0dp"
+ />
<!-- Linear layout to separate the primary area containing the contact badge and caller
information and the secondary action (call details / play voicemail). -->
<LinearLayout
+ android:id="@+id/call_log_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
@@ -127,14 +130,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
- <TextView
- android:id="@+id/call_log_header"
- style="@style/ContactListSeparatorTextViewStyle"
- android:layout_marginStart="@dimen/call_log_outer_margin"
- android:layout_marginEnd="@dimen/call_log_outer_margin"
- android:paddingTop="@dimen/call_log_inner_margin"
- android:paddingBottom="@dimen/call_log_inner_margin" />
-
<!-- Displays the extra link section -->
<ViewStub android:id="@+id/link_stub"
android:layout="@layout/call_log_list_item_extra"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 89bd5927b..ae653303c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -130,4 +130,6 @@
<dimen name="call_log_action_height">48dp</dimen>
<!-- Elevation of expanded call log items. -->
<dimen name="call_log_expanded_elevation">4dp</dimen>
+ <!-- Padding above call log day group headers. -->
+ <dimen name="call_log_day_group_padding">16dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d6d4766fe..4215f5367 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -718,6 +718,15 @@
[CHAR LIMIT=NONE] -->
<string name="description_delete_action">Delete call log entry for <xliff:g id="nameOrNumber" example="John Smith">%1$s</xliff:g></string>
- <!-- Toast message which appears when a call log entry is deleted. -->
+ <!-- Toast message which appears when a call log entry is deleted.
+ [CHAR LIMIT=NONE] -->
<string name="toast_entry_removed">Call log entry deleted.</string>
+
+ <!-- String used as a header in the call log above calls which occurred last week.
+ [CHAR LIMIT=65] -->
+ <string name="call_log_header_last_week">Last week</string>
+
+ <!-- String used as a header in the call log above calls which ocurred more than a week ago.
+ [CHAR LIMIT=65] -->
+ <string name="call_log_header_other">Other</string>
</resources>
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 0aca9136b..c4389ad49 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -40,6 +40,7 @@ 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.DateUtils;
import com.android.contacts.common.util.UriUtils;
import com.android.dialer.PhoneCallDetails;
import com.android.dialer.PhoneCallDetailsHelper;
@@ -60,7 +61,6 @@ 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,
@@ -117,6 +117,12 @@ public class CallLogAdapter extends GroupingListAdapter
/** The size of the cache of contact info. */
private static final int CONTACT_INFO_CACHE_SIZE = 100;
+ /** Localized string representing the word "Today". */
+ private static final CharSequence TODAY_LABEL = DateUtils.getTodayString();
+
+ /** Localized string representing the word "Yesterday". */
+ private static final CharSequence YESTERDAY_LABEL = DateUtils.getYesterdayString();
+
protected final Context mContext;
private final ContactInfoHelper mContactInfoHelper;
private final CallFetcher mCallFetcher;
@@ -139,6 +145,20 @@ public class CallLogAdapter extends GroupingListAdapter
private HashMap<Long,Boolean> mIsExpanded = new HashMap<Long,Boolean>();
/**
+ * Hashmap, keyed by call Id, used to track the day group for a call. As call log entries are
+ * put into the primary call groups in {@link com.android.dialer.calllog.CallLogGroupBuilder},
+ * they are also assigned a secondary "day group". This hashmap tracks the day group assigned
+ * to all calls in the call log. This information is used to trigger the display of a day
+ * group header above the call log entry at the start of a day group.
+ * Note: Multiple calls are grouped into a single primary "call group" in the call log, and
+ * the cursor used to bind rows includes all of these calls. When determining if a day group
+ * change has occurred it is necessary to look at the last entry in the call log to determine
+ * its day group. This hashmap provides a means of determining the previous day group without
+ * having to reverse the cursor to the start of the previous day call log entry.
+ */
+ private HashMap<Long,Integer> mDayGroups = new HashMap<Long, Integer>();
+
+ /**
* A request for contact details for the given number.
*/
private static final class ContactInfoRequest {
@@ -589,7 +609,6 @@ public class CallLogAdapter extends GroupingListAdapter
// Default case: an item in the call log.
views.primaryActionView.setVisibility(View.VISIBLE);
- views.listHeaderTextView.setVisibility(View.GONE);
final String number = c.getString(CallLogQuery.NUMBER);
final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
@@ -600,6 +619,21 @@ public class CallLogAdapter extends GroupingListAdapter
final long rowId = c.getLong(CallLogQuery.ID);
views.rowId = rowId;
+ // For entries in the call log, check if the day group has changed and display a header
+ // if necessary.
+ if (mIsCallLog) {
+ int currentGroup = getDayGroupForCall(rowId);
+ int previousGroup = getPreviousDayGroup(c);
+ if (currentGroup != previousGroup) {
+ views.dayGroupHeader.setVisibility(View.VISIBLE);
+ views.dayGroupHeader.setText(getGroupDescription(currentGroup));
+ } else {
+ views.dayGroupHeader.setVisibility(View.GONE);
+ }
+ } else {
+ views.dayGroupHeader.setVisibility(View.GONE);
+ }
+
// Store some values used when the actions ViewStub is inflated on expansion of the actions
// section.
views.number = number;
@@ -738,6 +772,38 @@ public class CallLogAdapter extends GroupingListAdapter
}
/**
+ * Retrieves the day group of the previous call in the call log. Used to determine if the day
+ * group has changed and to trigger display of the day group text.
+ *
+ * @param cursor The call log cursor.
+ * @return The previous day group, or DAY_GROUP_NONE if this is the first call.
+ */
+ private int getPreviousDayGroup(Cursor cursor) {
+ // We want to restore the position in the cursor at the end.
+ int startingPosition = cursor.getPosition();
+ int dayGroup = CallLogGroupBuilder.DAY_GROUP_NONE;
+ if (cursor.moveToPrevious()) {
+ long previousRowId = cursor.getLong(CallLogQuery.ID);
+ dayGroup = getDayGroupForCall(previousRowId);
+ }
+ cursor.moveToPosition(startingPosition);
+ return dayGroup;
+ }
+
+ /**
+ * Given a call Id, look up the day group that the call belongs to. The day group data is
+ * populated in {@link com.android.dialer.calllog.CallLogGroupBuilder}.
+ *
+ * @param callId The call to retrieve the day group for.
+ * @return The day group for the call.
+ */
+ private int getDayGroupForCall(long callId) {
+ if (mDayGroups.containsKey(callId)) {
+ return mDayGroups.get(callId);
+ }
+ return CallLogGroupBuilder.DAY_GROUP_NONE;
+ }
+ /**
* 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
@@ -779,9 +845,9 @@ public class CallLogAdapter extends GroupingListAdapter
inflateActionViewStub(callLogItem);
views.actionsView.setVisibility(View.VISIBLE);
- callLogItem.setBackgroundColor(
+ views.callLogEntryView.setBackgroundColor(
callLogItem.getResources().getColor(R.color.background_dialer_light));
- callLogItem.setElevation(
+ views.callLogEntryView.setElevation(
callLogItem.getResources().getDimension(R.dimen.call_log_expanded_elevation));
// Attempt to give accessibility focus to one of the action buttons.
@@ -799,9 +865,9 @@ public class CallLogAdapter extends GroupingListAdapter
views.actionsView.setVisibility(View.GONE);
}
- callLogItem.setBackgroundColor(
+ views.callLogEntryView.setBackgroundColor(
callLogItem.getResources().getColor(R.color.background_dialer_list_items));
- callLogItem.setElevation(0);
+ views.callLogEntryView.setElevation(0);
}
}
@@ -1138,6 +1204,27 @@ public class CallLogAdapter extends GroupingListAdapter
super.addGroup(cursorPosition, size, expanded);
}
+ /**
+ * Stores the day group associated with a call in the call log.
+ *
+ * @param rowId The row Id of the current call.
+ * @param dayGroup The day group the call belongs in.
+ */
+ @Override
+ public void setDayGroup(long rowId, int dayGroup) {
+ if (!mDayGroups.containsKey(rowId)) {
+ mDayGroups.put(rowId, dayGroup);
+ }
+ }
+
+ /**
+ * Clears the day group associations on re-bind of the call log.
+ */
+ @Override
+ public void clearDayGroups() {
+ mDayGroups.clear();
+ }
+
/*
* Get the number from the Contacts, if available, since sometimes
* the number provided by caller id may not be formatted properly
@@ -1199,6 +1286,24 @@ public class CallLogAdapter extends GroupingListAdapter
}
/**
+ * Determines the description for a day group.
+ *
+ * @param group The day group to retrieve the description for.
+ * @return The day group description.
+ */
+ private CharSequence getGroupDescription(int group) {
+ if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) {
+ return TODAY_LABEL;
+ } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) {
+ return YESTERDAY_LABEL;
+ } else if (group == CallLogGroupBuilder.DAY_GROUP_LAST_WEEK) {
+ return mContext.getResources().getString(R.string.call_log_header_last_week);
+ } else {
+ return mContext.getResources().getString(R.string.call_log_header_other);
+ }
+ }
+
+ /**
* Retrieves an instance of the asynchronous task executor, creating one if required.
* @return The {@link com.android.dialer.util.AsyncTaskExecutor}
*/
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index 0b2edf0bb..50cf054a2 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -19,22 +19,74 @@ package com.android.dialer.calllog;
import android.database.Cursor;
import android.provider.CallLog.Calls;
import android.telephony.PhoneNumberUtils;
+import android.text.format.Time;
import com.android.common.widget.GroupingListAdapter;
+import com.android.contacts.common.util.DateUtils;
import com.android.contacts.common.util.PhoneNumberHelper;
import com.google.common.annotations.VisibleForTesting;
/**
- * Groups together calls in the call log.
+ * Groups together calls in the call log. The primary grouping attempts to group together calls
+ * to and from the same number into a single row on the call log.
+ * A secondary grouping assigns calls, grouped via the primary grouping, to "day groups". The day
+ * groups provide a means of identifying the calls which occurred "Today", "Yesterday", "Last week",
+ * or "Other".
* <p>
* This class is meant to be used in conjunction with {@link GroupingListAdapter}.
*/
public class CallLogGroupBuilder {
public interface GroupCreator {
+
+ /**
+ * Defines the interface for adding a group to the call log.
+ * The primary group for a call log groups the calls together based on the number which was
+ * dialed.
+ * @param cursorPosition The starting position of the group in the cursor.
+ * @param size The size of the group.
+ * @param expanded Whether the group is expanded; always false for the call log.
+ */
public void addGroup(int cursorPosition, int size, boolean expanded);
+
+ /**
+ * Defines the interface for tracking the day group each call belongs to. Calls in a call
+ * group are assigned the same day group as the first call in the group. The day group
+ * assigns calls to the buckets: Today, Yesterday, Last week, and Other
+ *
+ * @param rowId The row Id of the current call.
+ * @param dayGroup The day group the call belongs in.
+ */
+ public void setDayGroup(long rowId, int dayGroup);
+
+ /**
+ * Defines the interface for clearing the day groupings information on rebind/regroup.
+ */
+ public void clearDayGroups();
}
+ /**
+ * Day grouping for call log entries used to represent no associated day group. Used primarily
+ * when retrieving the previous day group, but there is no previous day group (i.e. we are at
+ * the start of the list).
+ */
+ public static final int DAY_GROUP_NONE = -1;
+
+ /** Day grouping for calls which occurred today. */
+ public static final int DAY_GROUP_TODAY = 0;
+
+ /** Day grouping for calls which occurred yesterday. */
+ public static final int DAY_GROUP_YESTERDAY = 1;
+
+ /** Day grouping for calls which occurred last week. */
+ public static final int DAY_GROUP_LAST_WEEK = 2;
+
+ /** Day grouping for calls which occurred before last week. */
+ public static final int DAY_GROUP_OTHER = 3;
+
+ /** Instance of the time object used for time calculations. */
+ private static final Time TIME = new Time();
+
/** The object on which the groups are created. */
private final GroupCreator mGroupCreator;
@@ -59,18 +111,33 @@ public class CallLogGroupBuilder {
return;
}
+ // Clear any previous day grouping information.
+ mGroupCreator.clearDayGroups();
+
+ // Get current system time, used for calculating which day group calls belong to.
+ long currentTime = System.currentTimeMillis();
+
int currentGroupSize = 1;
cursor.moveToFirst();
// The number of the first entry in the group.
String firstNumber = cursor.getString(CallLogQuery.NUMBER);
// This is the type of the first call in the group.
int firstCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
+
+ // Determine the day group for the first call in the cursor.
+ final long firstDate = cursor.getLong(CallLogQuery.DATE);
+ final long firstRowId = cursor.getLong(CallLogQuery.ID);
+ int currentGroupDayGroup = getDayGroup(firstDate, currentTime);
+ mGroupCreator.setDayGroup(firstRowId, currentGroupDayGroup);
+
while (cursor.moveToNext()) {
// The number of the current row in the cursor.
final String currentNumber = cursor.getString(CallLogQuery.NUMBER);
final int callType = cursor.getInt(CallLogQuery.CALL_TYPE);
final boolean sameNumber = equalNumbers(firstNumber, currentNumber);
final boolean shouldGroup;
+ final long currentCallId = cursor.getLong(CallLogQuery.ID);
+ final long date = cursor.getLong(CallLogQuery.DATE);
if (!sameNumber) {
// Should only group with calls from the same number.
@@ -88,6 +155,11 @@ public class CallLogGroupBuilder {
// the group until we find a call that does not match.
currentGroupSize++;
} else {
+ // The call group has changed, so determine the day group for the new call group.
+ // This ensures all calls grouped together in the call log are assigned the same
+ // day group.
+ currentGroupDayGroup = getDayGroup(date, currentTime);
+
// Create a group for the previous set of calls, excluding the current one, but do
// not create a group for a single call.
if (currentGroupSize > 1) {
@@ -99,6 +171,9 @@ public class CallLogGroupBuilder {
firstNumber = currentNumber;
firstCallType = callType;
}
+
+ // Save the day group associated with the current call.
+ mGroupCreator.setDayGroup(currentCallId, currentGroupDayGroup);
}
// If the last set of calls at the end of the call log was itself a group, create it now.
if (currentGroupSize > 1) {
@@ -154,4 +229,25 @@ public class CallLogGroupBuilder {
return userinfo1.equals(userinfo2) && rest1.equalsIgnoreCase(rest2);
}
+
+ /**
+ * Given a call date and the current date, determine which date group the call belongs in.
+ *
+ * @param date The call date.
+ * @param now The current date.
+ * @return The date group the call belongs in.
+ */
+ private int getDayGroup(long date, long now) {
+ int days = DateUtils.getDayDifference(TIME, date, now);
+
+ if (days == 0) {
+ return DAY_GROUP_TODAY;
+ } else if (days == 1) {
+ return DAY_GROUP_YESTERDAY;
+ } else if (days > 1 && days <=7) {
+ return DAY_GROUP_LAST_WEEK;
+ } else {
+ return DAY_GROUP_OTHER;
+ }
+ }
}
diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViews.java
index 333769d7e..648362e09 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViews.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViews.java
@@ -36,8 +36,10 @@ public final class CallLogListItemViews {
public final View primaryActionView;
/** The details of the phone call. */
public final PhoneCallDetailsViews phoneCallDetailsViews;
- /** The text of the header of a section. */
- public final TextView listHeaderTextView;
+ /** The text of the header for a day grouping. */
+ public final TextView dayGroupHeader;
+ /** The view containing the details for the call log row, including the action buttons. */
+ public final View callLogEntryView;
/** 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. */
@@ -91,12 +93,13 @@ public final class CallLogListItemViews {
public CharSequence nameOrNumber;
private CallLogListItemViews(QuickContactBadge quickContactView, View primaryActionView,
- PhoneCallDetailsViews phoneCallDetailsViews,
- TextView listHeaderTextView) {
+ PhoneCallDetailsViews phoneCallDetailsViews, View callLogEntryView,
+ TextView dayGroupHeader) {
this.quickContactView = quickContactView;
this.primaryActionView = primaryActionView;
this.phoneCallDetailsViews = phoneCallDetailsViews;
- this.listHeaderTextView = listHeaderTextView;
+ this.callLogEntryView = callLogEntryView;
+ this.dayGroupHeader = dayGroupHeader;
}
public static CallLogListItemViews fromView(View view) {
@@ -104,7 +107,8 @@ public final class CallLogListItemViews {
(QuickContactBadge) view.findViewById(R.id.quick_contact_photo),
view.findViewById(R.id.primary_action_view),
PhoneCallDetailsViews.fromView(view),
- (TextView) view.findViewById(R.id.call_log_header));
+ view.findViewById(R.id.call_log_row),
+ (TextView) view.findViewById(R.id.call_log_day_group_label));
}
@NeededForTesting
@@ -113,6 +117,7 @@ public final class CallLogListItemViews {
new QuickContactBadge(context),
new View(context),
PhoneCallDetailsViews.createForTest(context),
+ new View(context),
new TextView(context));
views.callBackButtonView = new TextView(context);
views.deleteButtonView = new TextView(context);