summaryrefslogtreecommitdiff
path: root/java/com/android/dialer
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer')
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java10
-rw-r--r--java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java4
-rw-r--r--java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java13
-rw-r--r--java/com/android/dialer/calllog/database/annotated_call_log.proto14
-rw-r--r--java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java105
-rw-r--r--java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java4
-rw-r--r--java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java69
-rw-r--r--java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java127
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogAdapter.java6
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogFragment.java6
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java18
-rw-r--r--java/com/android/dialer/calllog/ui/res/layout/new_call_log_entry.xml4
-rw-r--r--java/com/android/dialer/calllogutils/CallLogDates.java165
-rw-r--r--java/com/android/dialer/calllogutils/CallLogDurations.java (renamed from java/com/android/dialer/calllogutils/CallEntryFormatter.java)55
-rw-r--r--java/com/android/dialer/calllogutils/res/values/strings.xml3
15 files changed, 518 insertions, 85 deletions
diff --git a/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
index 9c592fc5f..084bd667c 100644
--- a/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
+++ b/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
@@ -28,7 +28,8 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry;
-import com.android.dialer.calllogutils.CallEntryFormatter;
+import com.android.dialer.calllogutils.CallLogDates;
+import com.android.dialer.calllogutils.CallLogDurations;
import com.android.dialer.calllogutils.CallTypeHelper;
import com.android.dialer.calllogutils.CallTypeIconsView;
import com.android.dialer.common.LogUtil;
@@ -103,16 +104,17 @@ public class CallDetailsEntryViewHolder extends ViewHolder {
callTypeText.setText(
callTypeHelper.getCallTypeText(callType, isVideoCall, isPulledCall, isLightbringerCall));
- callTime.setText(CallEntryFormatter.formatDate(context, entry.getDate()));
+ callTime.setText(CallLogDates.formatDate(context, entry.getDate()));
+
if (CallTypeHelper.isMissedCallType(callType)) {
callDuration.setVisibility(View.GONE);
} else {
callDuration.setVisibility(View.VISIBLE);
callDuration.setText(
- CallEntryFormatter.formatDurationAndDataUsage(
+ CallLogDurations.formatDurationAndDataUsage(
context, entry.getDuration(), entry.getDataUsage()));
callDuration.setContentDescription(
- CallEntryFormatter.formatDurationAndDataUsageA11y(
+ CallLogDurations.formatDurationAndDataUsageA11y(
context, entry.getDuration(), entry.getDataUsage()));
}
setMultimediaDetails(number, entry, showMultimediaDivider);
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
index 30aa2bff5..9a3d2e20f 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
@@ -112,7 +112,9 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
}
return cursor;
case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
- Assert.checkArgument(projection == null, "projection not supported for coalesced call log");
+ Assert.checkArgument(
+ projection == CoalescedAnnotatedCallLog.ALL_COLUMNS,
+ "only ALL_COLUMNS projection supported for coalesced call log");
Assert.checkArgument(selection == null, "selection not supported for coalesced call log");
Assert.checkArgument(
selectionArgs == null, "selection args not supported for coalesced call log");
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
index 5f48d7b1f..ebfd3c79b 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
@@ -35,9 +35,20 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper {
private static final String CREATE_TABLE_SQL =
new StringBuilder()
.append("create table if not exists " + AnnotatedCallLog.TABLE + " (")
+ // Common columns.
.append(AnnotatedCallLog._ID + " integer primary key, ")
.append(AnnotatedCallLog.TIMESTAMP + " integer, ")
- .append(AnnotatedCallLog.CONTACT_NAME + " string, ")
+ .append(AnnotatedCallLog.PRIMARY_TEXT + " string, ")
+ .append(AnnotatedCallLog.CONTACT_PHOTO_URI + " string, ")
+ .append(AnnotatedCallLog.NUMBER_TYPE_LABEL + " string, ")
+ .append(AnnotatedCallLog.IS_READ + " integer, ")
+ .append(AnnotatedCallLog.GEOCODED_LOCATION + " string, ")
+ .append(AnnotatedCallLog.PHONE_ACCOUNT_LABEL + " string, ")
+ .append(AnnotatedCallLog.PHONE_ACCOUNT_COLOR + " integer, ")
+ .append(AnnotatedCallLog.FEATURES + " integer, ")
+ .append(AnnotatedCallLog.IS_BUSINESS + " integer, ")
+ .append(AnnotatedCallLog.IS_VOICEMAIL + " integer, ")
+ // Columns only in AnnotatedCallLog
.append(AnnotatedCallLog.NUMBER + " blob")
.append(");")
.toString();
diff --git a/java/com/android/dialer/calllog/database/annotated_call_log.proto b/java/com/android/dialer/calllog/database/annotated_call_log.proto
new file mode 100644
index 000000000..eb0ee52ce
--- /dev/null
+++ b/java/com/android/dialer/calllog/database/annotated_call_log.proto
@@ -0,0 +1,14 @@
+syntax = "proto2";
+
+option java_package = "com.android.dialer";
+option java_multiple_files = true;
+option optimize_for = LITE_RUNTIME;
+
+// DIALER_SCRUB.UNCOMMENT_IN_OPEN_SOURCE option optimize_for = LITE_RUNTIME;
+
+package com.android.dialer;
+
+// A list of android.provider.CallLog.Calls.TYPE values.
+message CallTypes {
+ repeated int32 type = 1;
+}
diff --git a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
index 7f314e37c..172006878 100644
--- a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
+++ b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
@@ -42,13 +42,103 @@ public class AnnotatedCallLogContract {
String TIMESTAMP = "timestamp";
/**
- * Name to display for the entry.
+ * Primary text to display for the entry. This could be a name from a local contact or caller ID
+ * data source, or it could just be a phone number, for example.
+ *
+ * <p>This is exactly how it should appear to the user. If the user's locale or name display
+ * preferences change, this column should be rewritten.
*
* <p>Type: TEXT
*/
- String CONTACT_NAME = "contact_name";
+ String PRIMARY_TEXT = "primary_text";
+
+ /**
+ * Local photo URI for the contact associated with the phone number, if it exists.
+ *
+ * <p>Photos currently only come from local contacts database and not caller ID sources. If
+ * there is no photo for a contact then an appropriate letter tile should be drawn.
+ *
+ * <p>TYPE: TEXT
+ */
+ String CONTACT_PHOTO_URI = "contact_photo_uri";
+
+ // TODO(zachh): If we need to support photos other than local contacts', add a (blob?) column.
+
+ /**
+ * The number type as a string to be displayed to the user, for example "Home" or "Mobile".
+ *
+ * <p>This column should be updated for the appropriate language when the locale changes.
+ *
+ * <p>TYPE: TEXT
+ */
+ String NUMBER_TYPE_LABEL = "number_type_label";
+
+ /**
+ * See CallLog.Calls.IS_READ.
+ *
+ * <p>TYPE: INTEGER (boolean)
+ */
+ String IS_READ = "is_read";
- String[] ALL_COMMON_COLUMNS = new String[] {_ID, TIMESTAMP, CONTACT_NAME};
+ /**
+ * See CallLog.Calls.GEOCODED_LOCATION.
+ *
+ * <p>TYPE: TEXT
+ */
+ String GEOCODED_LOCATION = "geocoded_location";
+
+ /**
+ * String suitable for display which indicates the phone account used to make the call.
+ *
+ * <p>TYPE: TEXT
+ */
+ String PHONE_ACCOUNT_LABEL = "phone_account_label";
+
+ /**
+ * The color int for the phone account.
+ *
+ * <p>TYPE: INTEGER (int)
+ */
+ String PHONE_ACCOUNT_COLOR = "phone_account_color";
+
+ /**
+ * See CallLog.Calls.FEATURES.
+ *
+ * <p>TYPE: INTEGER (int)
+ */
+ String FEATURES = "features";
+
+ /**
+ * True if a caller ID data source informed us that this is a business number. This is used to
+ * determine if a generic business avatar should be shown vs. a generic person avatar.
+ *
+ * <p>TYPE: INTEGER (boolean)
+ */
+ String IS_BUSINESS = "is_business";
+
+ /**
+ * True if this was a call to voicemail. This is used to determine if the voicemail avatar
+ * should be displayed.
+ *
+ * <p>TYPE: INTEGER (boolean)
+ */
+ String IS_VOICEMAIL = "is_voicemail";
+
+ String[] ALL_COMMON_COLUMNS =
+ new String[] {
+ _ID,
+ TIMESTAMP,
+ PRIMARY_TEXT,
+ CONTACT_PHOTO_URI,
+ NUMBER_TYPE_LABEL,
+ IS_READ,
+ GEOCODED_LOCATION,
+ PHONE_ACCOUNT_LABEL,
+ PHONE_ACCOUNT_COLOR,
+ FEATURES,
+ IS_BUSINESS,
+ IS_VOICEMAIL
+ };
}
/**
@@ -116,11 +206,18 @@ public class AnnotatedCallLogContract {
public static final String FORMATTED_NUMBER = "formatted_number";
/**
+ * The call types of the most recent 3 calls, encoded as a CallTypes proto.
+ *
+ * <p>TYPE: BLOB
+ */
+ public static final String CALL_TYPES = "call_types";
+
+ /**
* Columns that are only in the {@link CoalescedAnnotatedCallLog} but not the {@link
* AnnotatedCallLog}.
*/
private static final String[] COLUMNS_ONLY_IN_COALESCED_CALL_LOG =
- new String[] {NUMBER_CALLS, FORMATTED_NUMBER};
+ new String[] {NUMBER_CALLS, FORMATTED_NUMBER, CALL_TYPES};
/** All columns in the {@link CoalescedAnnotatedCallLog}. */
public static final String[] ALL_COLUMNS =
diff --git a/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java b/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java
index db7421515..ad824274e 100644
--- a/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java
@@ -51,7 +51,7 @@ public final class ContactsDataSource implements CallLogDataSource {
Assert.isWorkerThread();
// TODO(zachh): Implementation.
for (ContentValues contentValues : mutations.getInserts().values()) {
- contentValues.put(AnnotatedCallLog.CONTACT_NAME, "Placeholder name");
+ contentValues.put(AnnotatedCallLog.PRIMARY_TEXT, "Placeholder name");
}
}
@@ -64,7 +64,7 @@ public final class ContactsDataSource implements CallLogDataSource {
public ContentValues coalesce(List<ContentValues> individualRowsSortedByTimestampDesc) {
// TODO(zachh): Implementation.
return new RowCombiner(individualRowsSortedByTimestampDesc)
- .useSingleValueString(AnnotatedCallLog.CONTACT_NAME)
+ .useSingleValueString(AnnotatedCallLog.PRIMARY_TEXT)
.combine();
}
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
index 86145a95b..94b908f8f 100644
--- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
@@ -28,10 +28,13 @@ import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.dialer.DialerPhoneNumber;
@@ -40,10 +43,12 @@ import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.Coa
import com.android.dialer.calllog.datasources.CallLogDataSource;
import com.android.dialer.calllog.datasources.CallLogMutations;
import com.android.dialer.calllog.datasources.util.RowCombiner;
+import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
+import com.android.dialer.theme.R;
import com.android.dialer.util.PermissionsUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -189,7 +194,18 @@ public class SystemCallLogDataSource implements CallLogDataSource {
.query(
Calls.CONTENT_URI, // Excludes voicemail
new String[] {
- Calls._ID, Calls.DATE, Calls.LAST_MODIFIED, Calls.NUMBER, Calls.COUNTRY_ISO
+ Calls._ID,
+ Calls.DATE,
+ Calls.LAST_MODIFIED,
+ Calls.NUMBER,
+ Calls.COUNTRY_ISO,
+ Calls.CACHED_NUMBER_TYPE,
+ Calls.CACHED_NUMBER_LABEL,
+ Calls.IS_READ,
+ Calls.GEOCODED_LOCATION,
+ Calls.PHONE_ACCOUNT_COMPONENT_NAME,
+ Calls.PHONE_ACCOUNT_ID,
+ Calls.FEATURES
},
Calls.LAST_MODIFIED + " > ?",
new String[] {String.valueOf(previousTimestampProcessed)},
@@ -211,6 +227,14 @@ public class SystemCallLogDataSource implements CallLogDataSource {
int lastModifiedColumn = cursor.getColumnIndexOrThrow(Calls.LAST_MODIFIED);
int numberColumn = cursor.getColumnIndexOrThrow(Calls.NUMBER);
int countryIsoColumn = cursor.getColumnIndexOrThrow(Calls.COUNTRY_ISO);
+ int cachedNumberTypeColumn = cursor.getColumnIndexOrThrow(Calls.CACHED_NUMBER_TYPE);
+ int cachedNumberLabelColumn = cursor.getColumnIndexOrThrow(Calls.CACHED_NUMBER_LABEL);
+ int isReadColumn = cursor.getColumnIndexOrThrow(Calls.IS_READ);
+ int geocodedLocationColumn = cursor.getColumnIndexOrThrow(Calls.GEOCODED_LOCATION);
+ int phoneAccountComponentColumn =
+ cursor.getColumnIndexOrThrow(Calls.PHONE_ACCOUNT_COMPONENT_NAME);
+ int phoneAccountIdColumn = cursor.getColumnIndexOrThrow(Calls.PHONE_ACCOUNT_ID);
+ int featuresColumn = cursor.getColumnIndexOrThrow(Calls.FEATURES);
// The cursor orders by LAST_MODIFIED DESC, so the first result is the most recent timestamp
// processed.
@@ -220,14 +244,34 @@ public class SystemCallLogDataSource implements CallLogDataSource {
long date = cursor.getLong(dateColumn);
String numberAsStr = cursor.getString(numberColumn);
String countryIso = cursor.getString(countryIsoColumn);
+ // TODO(zachh): Decide if should use "cached" columns from call log or recompute.
+ int cachedNumberType = cursor.getInt(cachedNumberTypeColumn);
+ String cachedNumberLabel = cursor.getString(cachedNumberLabelColumn);
+ int isRead = cursor.getInt(isReadColumn);
+ String geocodedLocation = cursor.getString(geocodedLocationColumn);
+ String phoneAccountComponentName = cursor.getString(phoneAccountComponentColumn);
+ String phoneAccountId = cursor.getString(phoneAccountIdColumn);
+ int features = cursor.getInt(featuresColumn);
byte[] numberAsProtoBytes =
dialerPhoneNumberUtil.parse(numberAsStr, countryIso).toByteArray();
ContentValues contentValues = new ContentValues();
contentValues.put(AnnotatedCallLog.TIMESTAMP, date);
+ // TODO(zachh): Need to handle post-dial digits; different on N and M.
contentValues.put(AnnotatedCallLog.NUMBER, numberAsProtoBytes);
+ // TODO(zachh): Test this for locales.
+ contentValues.put(
+ AnnotatedCallLog.NUMBER_TYPE_LABEL,
+ Phone.getTypeLabel(appContext.getResources(), cachedNumberType, cachedNumberLabel)
+ .toString());
+ contentValues.put(AnnotatedCallLog.IS_READ, isRead);
+ contentValues.put(AnnotatedCallLog.GEOCODED_LOCATION, geocodedLocation);
+ populatePhoneAccountLabelAndColor(
+ appContext, contentValues, phoneAccountComponentName, phoneAccountId);
+ contentValues.put(AnnotatedCallLog.FEATURES, features);
+
if (existingAnnotatedCallLogIds.contains(id)) {
mutations.update(id, contentValues);
} else {
@@ -238,6 +282,29 @@ public class SystemCallLogDataSource implements CallLogDataSource {
}
}
+ private void populatePhoneAccountLabelAndColor(
+ Context appContext,
+ ContentValues contentValues,
+ String phoneAccountComponentName,
+ String phoneAccountId) {
+ PhoneAccountHandle phoneAccountHandle =
+ PhoneAccountUtils.getAccount(phoneAccountComponentName, phoneAccountId);
+ if (phoneAccountHandle == null) {
+ return;
+ }
+ String label = PhoneAccountUtils.getAccountLabel(appContext, phoneAccountHandle);
+ if (TextUtils.isEmpty(label)) {
+ return;
+ }
+ contentValues.put(AnnotatedCallLog.PHONE_ACCOUNT_LABEL, label);
+
+ int color = PhoneAccountUtils.getAccountColor(appContext, phoneAccountHandle);
+ if (color == PhoneAccount.NO_HIGHLIGHT_COLOR) {
+ color = R.color.dialer_secondary_text_color;
+ }
+ contentValues.put(AnnotatedCallLog.PHONE_ACCOUNT_COLOR, color);
+ }
+
private static void handleDeletes(
Context appContext, Set<Long> existingAnnotatedCallLogIds, CallLogMutations mutations) {
Set<Long> systemCallLogIds =
diff --git a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java
new file mode 100644
index 000000000..e993816bf
--- /dev/null
+++ b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllog.ui;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import com.android.dialer.CallTypes;
+import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+/** CursorLoader for the coalesced annotated call log. */
+final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader {
+
+ /** Indexes for CoalescedAnnotatedCallLog.ALL_COLUMNS */
+ private static final int ID = 0;
+
+ private static final int TIMESTAMP = 1;
+ private static final int PRIMARY_TEXT = 2;
+ private static final int CONTACT_PHOTO_URI = 3;
+ private static final int NUMBER_TYPE_LABEL = 4;
+ private static final int IS_READ = 5;
+ private static final int GEOCODED_LOCATION = 6;
+ private static final int PHONE_ACCOUNT_LABEL = 7;
+ private static final int PHONE_ACCOUNT_COLOR = 8;
+ private static final int FEATURES = 9;
+ private static final int IS_BUSINESS = 10;
+ private static final int IS_VOICEMAIL = 11;
+ private static final int NUMBER_CALLS = 12;
+ private static final int FORMATTED_NUMBER = 13;
+ private static final int CALL_TYPES = 14;
+
+ /** Convenience class for accessing values using an abbreviated syntax. */
+ static final class Row {
+ private final Cursor cursor;
+
+ Row(Cursor cursor) {
+ this.cursor = cursor;
+ }
+
+ long id() {
+ return cursor.getInt(ID);
+ }
+
+ long timestamp() {
+ return cursor.getLong(TIMESTAMP);
+ }
+
+ String primaryText() {
+ return cursor.getString(PRIMARY_TEXT);
+ }
+
+ String contactPhotoUri() {
+ return cursor.getString(CONTACT_PHOTO_URI);
+ }
+
+ String numberTypeLabel() {
+ return cursor.getString(NUMBER_TYPE_LABEL);
+ }
+
+ boolean isRead() {
+ return cursor.getInt(IS_READ) == 1;
+ }
+
+ String geocodedLocation() {
+ return cursor.getString(GEOCODED_LOCATION);
+ }
+
+ String phoneAccountLabel() {
+ return cursor.getString(PHONE_ACCOUNT_LABEL);
+ }
+
+ int phoneAccountColor() {
+ return cursor.getInt(PHONE_ACCOUNT_COLOR);
+ }
+
+ int features() {
+ return cursor.getInt(FEATURES);
+ }
+
+ boolean isBusiness() {
+ return cursor.getInt(IS_BUSINESS) == 1;
+ }
+
+ boolean isVoicemail() {
+ return cursor.getInt(IS_VOICEMAIL) == 1;
+ }
+
+ int numberCalls() {
+ return cursor.getInt(NUMBER_CALLS);
+ }
+
+ String formattedNumber() {
+ return cursor.getString(FORMATTED_NUMBER);
+ }
+
+ CallTypes callTypes() throws InvalidProtocolBufferException {
+ return CallTypes.parseFrom(cursor.getBlob(CALL_TYPES));
+ }
+ }
+
+ CoalescedAnnotatedCallLogCursorLoader(Context context) {
+ // CoalescedAnnotatedCallLog requires that PROJECTION be ALL_COLUMNS and the following params be
+ // null.
+ super(
+ context,
+ CoalescedAnnotatedCallLog.CONTENT_URI,
+ CoalescedAnnotatedCallLog.ALL_COLUMNS,
+ null,
+ null,
+ null);
+ }
+}
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java
index f9ab21cb3..4655b0982 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java
@@ -19,17 +19,14 @@ import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
-import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
/** {@link RecyclerView.Adapter} for the new call log fragment. */
final class NewCallLogAdapter extends RecyclerView.Adapter<NewCallLogViewHolder> {
private final Cursor cursor;
- private final int timestampIndex;
NewCallLogAdapter(Cursor cursor) {
this.cursor = cursor;
- timestampIndex = cursor.getColumnIndexOrThrow(CoalescedAnnotatedCallLog.TIMESTAMP);
}
@Override
@@ -42,8 +39,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<NewCallLogViewHolder>
@Override
public void onBindViewHolder(NewCallLogViewHolder viewHolder, int position) {
cursor.moveToPosition(position);
- long timestamp = cursor.getLong(timestampIndex);
- viewHolder.bind(timestamp);
+ viewHolder.bind(cursor);
}
@Override
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
index 17fcf1939..c4bcb766b 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
@@ -17,7 +17,6 @@ package com.android.dialer.calllog.ui;
import android.app.Fragment;
import android.app.LoaderManager.LoaderCallbacks;
-import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
@@ -29,7 +28,6 @@ import android.view.ViewGroup;
import com.android.dialer.calllog.CallLogComponent;
import com.android.dialer.calllog.CallLogFramework;
import com.android.dialer.calllog.CallLogFramework.CallLogUi;
-import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
@@ -133,9 +131,7 @@ public final class NewCallLogFragment extends Fragment
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
LogUtil.enterBlock("NewCallLogFragment.onCreateLoader");
- // CoalescedAnnotatedCallLog requires that all params be null.
- return new CursorLoader(
- getContext(), CoalescedAnnotatedCallLog.CONTENT_URI, null, null, null, null);
+ return new CoalescedAnnotatedCallLogCursorLoader(getContext());
}
@Override
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java
index 9521a032c..72ea17b03 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java
@@ -15,6 +15,7 @@
*/
package com.android.dialer.calllog.ui;
+import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
@@ -27,17 +28,20 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
// TODO(zachh): Format correctly using current locale.
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
- private final TextView contactNameView;
- private final TextView timestampView;
+ private final TextView primaryTextView;
+ private final TextView secondaryTextView;
NewCallLogViewHolder(View view) {
super(view);
- contactNameView = view.findViewById(R.id.contact_name);
- timestampView = view.findViewById(R.id.timestamp);
+ primaryTextView = view.findViewById(R.id.primary_text);
+ secondaryTextView = view.findViewById(R.id.secondary_text);
}
- void bind(long timestamp) {
- contactNameView.setText("Contact Name Placeholder");
- timestampView.setText(dateFormat.format(timestamp));
+ /** @param cursor a cursor from {@link CoalescedAnnotatedCallLogCursorLoader}. */
+ void bind(Cursor cursor) {
+ CoalescedAnnotatedCallLogCursorLoader.Row row =
+ new CoalescedAnnotatedCallLogCursorLoader.Row(cursor);
+ primaryTextView.setText(row.primaryText());
+ secondaryTextView.setText(dateFormat.format(row.timestamp()));
}
}
diff --git a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_entry.xml b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_entry.xml
index 99797fab4..38e07becf 100644
--- a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_entry.xml
+++ b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_entry.xml
@@ -23,13 +23,13 @@
android:orientation="vertical">
<TextView
- android:id="@+id/contact_name"
+ android:id="@+id/primary_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/PrimaryText"/>
<TextView
- android:id="@+id/timestamp"
+ android:id="@+id/secondary_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SecondaryText"/>
diff --git a/java/com/android/dialer/calllogutils/CallLogDates.java b/java/com/android/dialer/calllogutils/CallLogDates.java
new file mode 100644
index 000000000..2d4bd8bf5
--- /dev/null
+++ b/java/com/android/dialer/calllogutils/CallLogDates.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.calllogutils;
+
+import android.content.Context;
+import android.icu.lang.UCharacter;
+import android.icu.text.BreakIterator;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.text.format.DateUtils;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+/** Static methods for formatting dates in the call log. */
+public final class CallLogDates {
+
+ /**
+ * Uses the new date formatting rules to format dates in the new call log.
+ *
+ * <p>Rules:
+ *
+ * <pre>
+ * if < 1 minute ago: "Now";
+ * else if today: "12:15 PM"
+ * else if < 3 days ago: "Wednesday";
+ * else: "Jan 15"
+ * </pre>
+ */
+ public static CharSequence newCallLogTimestampLabel(
+ Context context, long nowMillis, long timestampMillis) {
+ if (nowMillis - timestampMillis < TimeUnit.MINUTES.toMillis(1)) {
+ return context.getString(R.string.now);
+ }
+ if (isSameDay(nowMillis, timestampMillis)) {
+ return DateUtils.formatDateTime(
+ context, timestampMillis, DateUtils.FORMAT_SHOW_TIME); // e.g. 12:15 PM
+ }
+ if (isWithin3Days(nowMillis, timestampMillis)) {
+ return formatDayOfWeek(context, timestampMillis); // e.g. "Wednesday"
+ }
+ return formatAbbreviatedMonthAndDay(context, timestampMillis); // e.g. "Jan 15"
+ }
+
+ /**
+ * Formats the provided date into a value suitable for display in the current locale.
+ *
+ * <p>For example, returns a string like "Wednesday, May 25, 2016, 8:02PM" or "Chorshanba, 2016
+ * may 25,20:02".
+ *
+ * <p>For pre-N devices, the returned value may not start with a capital if the local convention
+ * is to not capitalize day names. On N+ devices, the returned value is always capitalized.
+ */
+ public static CharSequence formatDate(Context context, long callDateMillis) {
+ return toTitleCase(
+ DateUtils.formatDateTime(
+ context,
+ callDateMillis,
+ DateUtils.FORMAT_SHOW_TIME
+ | DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_YEAR));
+ }
+
+ /**
+ * Formats the provided date into the day of week.
+ *
+ * <p>For example, returns a string like "Wednesday" or "Chorshanba".
+ *
+ * <p>For pre-N devices, the returned value may not start with a capital if the local convention
+ * is to not capitalize day names. On N+ devices, the returned value is always capitalized.
+ */
+ private static CharSequence formatDayOfWeek(Context context, long callDateMillis) {
+ return toTitleCase(
+ DateUtils.formatDateTime(context, callDateMillis, DateUtils.FORMAT_SHOW_WEEKDAY));
+ }
+
+ /**
+ * Formats the provided date into the month abbreviation and day.
+ *
+ * <p>For example, returns a string like "Jan 15".
+ *
+ * <p>For pre-N devices, the returned value may not start with a capital if the local convention
+ * is to not capitalize day names. On N+ devices, the returned value is always capitalized.
+ */
+ private static CharSequence formatAbbreviatedMonthAndDay(Context context, long callDateMillis) {
+ return toTitleCase(
+ DateUtils.formatDateTime(
+ context, callDateMillis, DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_NO_YEAR));
+ }
+
+ private static CharSequence toTitleCase(CharSequence value) {
+ // We want the beginning of the date string to be capitalized, even if the word at the beginning
+ // of the string is not usually capitalized. For example, "Wednesdsay" in Uzbek is "chorshanba”
+ // (not capitalized). To handle this issue we apply title casing to the start of the sentence so
+ // that "chorshanba, 2016 may 25,20:02" becomes "Chorshanba, 2016 may 25,20:02".
+ //
+ // The ICU library was not available in Android until N, so we can only do this in N+ devices.
+ // Pre-N devices will still see incorrect capitalization in some languages.
+ if (VERSION.SDK_INT < VERSION_CODES.N) {
+ return value;
+ }
+
+ // Using the ICU library is safer than just applying toUpperCase() on the first letter of the
+ // word because in some languages, there can be multiple starting characters which should be
+ // upper-cased together. For example in Dutch "ij" is a digraph in which both letters should be
+ // capitalized together.
+
+ // TITLECASE_NO_LOWERCASE is necessary so that things that are already capitalized are not
+ // lower-cased as part of the conversion.
+ return UCharacter.toTitleCase(
+ Locale.getDefault(),
+ value.toString(),
+ BreakIterator.getSentenceInstance(),
+ UCharacter.TITLECASE_NO_LOWERCASE);
+ }
+
+ private static boolean isWithin3Days(long nowMillis, long timestampMillis) {
+ Calendar threeDaysAgoStartOfDay = Calendar.getInstance();
+ threeDaysAgoStartOfDay.setTimeInMillis(nowMillis);
+
+ // This is attempting to find the start of the current day, but it's not quite right due to
+ // daylight savings. Unfortunately there doesn't seem to be a way to get the correct start of
+ // the day without using Joda or Java8, both of which are disallowed. This means that the wrong
+ // formatting may be applied on days with time changes (though the displayed values will be
+ // correct).
+ threeDaysAgoStartOfDay.add(
+ Calendar.HOUR_OF_DAY, -threeDaysAgoStartOfDay.get(Calendar.HOUR_OF_DAY));
+ threeDaysAgoStartOfDay.add(Calendar.MINUTE, -threeDaysAgoStartOfDay.get(Calendar.MINUTE));
+ threeDaysAgoStartOfDay.add(Calendar.SECOND, -threeDaysAgoStartOfDay.get(Calendar.SECOND));
+
+ threeDaysAgoStartOfDay.add(Calendar.DATE, -2);
+
+ Calendar then = Calendar.getInstance();
+ then.setTimeInMillis(timestampMillis);
+
+ return then.equals(threeDaysAgoStartOfDay) || then.after(threeDaysAgoStartOfDay);
+ }
+
+ private static boolean isSameDay(long firstMillis, long secondMillis) {
+ Calendar first = Calendar.getInstance();
+ first.setTimeInMillis(firstMillis);
+
+ Calendar second = Calendar.getInstance();
+ second.setTimeInMillis(secondMillis);
+
+ return first.get(Calendar.YEAR) == second.get(Calendar.YEAR)
+ && first.get(Calendar.MONTH) == second.get(Calendar.MONTH)
+ && first.get(Calendar.DAY_OF_MONTH) == second.get(Calendar.DAY_OF_MONTH);
+ }
+}
diff --git a/java/com/android/dialer/calllogutils/CallEntryFormatter.java b/java/com/android/dialer/calllogutils/CallLogDurations.java
index c5ec15748..20998deb4 100644
--- a/java/com/android/dialer/calllogutils/CallEntryFormatter.java
+++ b/java/com/android/dialer/calllogutils/CallLogDurations.java
@@ -18,67 +18,16 @@ package com.android.dialer.calllogutils;
import android.content.Context;
import android.content.res.Resources;
-import android.icu.lang.UCharacter;
-import android.icu.text.BreakIterator;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.text.format.DateUtils;
import android.text.format.Formatter;
import com.android.dialer.util.DialerUtils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import java.util.Locale;
import java.util.concurrent.TimeUnit;
-/** Utility class for formatting data and data usage in call log entries. */
-public class CallEntryFormatter {
-
- /**
- * Formats the provided date into a value suitable for display in the current locale.
- *
- * <p>For example, returns a string like "Wednesday, May 25, 2016, 8:02PM" or "Chorshanba, 2016
- * may 25,20:02".
- *
- * <p>For pre-N devices, the returned value may not start with a capital if the local convention
- * is to not capitalize day names. On N+ devices, the returned value is always capitalized.
- */
- public static CharSequence formatDate(Context context, long callDateMillis) {
- CharSequence dateValue =
- DateUtils.formatDateRange(
- context,
- callDateMillis /* startDate */,
- callDateMillis /* endDate */,
- DateUtils.FORMAT_SHOW_TIME
- | DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_WEEKDAY
- | DateUtils.FORMAT_SHOW_YEAR);
-
- // We want the beginning of the date string to be capitalized, even if the word at the beginning
- // of the string is not usually capitalized. For example, "Wednesdsay" in Uzbek is "chorshanba”
- // (not capitalized). To handle this issue we apply title casing to the start of the sentence so
- // that "chorshanba, 2016 may 25,20:02" becomes "Chorshanba, 2016 may 25,20:02".
- //
- // The ICU library was not available in Android until N, so we can only do this in N+ devices.
- // Pre-N devices will still see incorrect capitalization in some languages.
- if (VERSION.SDK_INT < VERSION_CODES.N) {
- return dateValue;
- }
-
- // Using the ICU library is safer than just applying toUpperCase() on the first letter of the
- // word because in some languages, there can be multiple starting characters which should be
- // upper-cased together. For example in Dutch "ij" is a digraph in which both letters should be
- // capitalized together.
-
- // TITLECASE_NO_LOWERCASE is necessary so that things that are already capitalized like the
- // month ("May") are not lower-cased as part of the conversion.
- return UCharacter.toTitleCase(
- Locale.getDefault(),
- dateValue.toString(),
- BreakIterator.getSentenceInstance(),
- UCharacter.TITLECASE_NO_LOWERCASE);
- }
+/** Utility class for formatting duration and data usage in call log entries. */
+public class CallLogDurations {
private static CharSequence formatDuration(Context context, long elapsedSeconds) {
Resources res = context.getResources();
diff --git a/java/com/android/dialer/calllogutils/res/values/strings.xml b/java/com/android/dialer/calllogutils/res/values/strings.xml
index 255990399..56cd94a9e 100644
--- a/java/com/android/dialer/calllogutils/res/values/strings.xml
+++ b/java/com/android/dialer/calllogutils/res/values/strings.xml
@@ -127,4 +127,7 @@
<!-- String used for displaying calls to the voicemail number in the call log -->
<string name="voicemail_string">Voicemail</string>
+
+ <!-- String to be displayed to indicate in the call log that a call just now occurred. -->
+ <string name="now">Now</string>
</resources> \ No newline at end of file