summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/quantum/res/drawable/quantum_ic_more_vert_vd_theme_24.xml10
-rw-r--r--java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java4
-rw-r--r--java/com/android/dialer/calllog/database/Coalescer.java12
-rw-r--r--java/com/android/dialer/calllog/database/annotated_call_log.proto3
-rw-r--r--java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java29
-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/datasources/util/RowCombiner.java13
-rw-r--r--java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java29
-rw-r--r--java/com/android/dialer/calllog/ui/HeaderViewHolder.java36
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogAdapter.java126
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogFragment.java4
-rw-r--r--java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java100
-rw-r--r--java/com/android/dialer/calllog/ui/res/layout/new_call_log_entry.xml65
-rw-r--r--java/com/android/dialer/calllog/ui/res/layout/new_call_log_header.xml29
-rw-r--r--java/com/android/dialer/calllog/ui/res/values/dimens.xml28
-rw-r--r--java/com/android/dialer/calllog/ui/res/values/strings.xml32
-rw-r--r--java/com/android/dialer/calllog/ui/res/values/styles.xml28
-rw-r--r--java/com/android/dialer/calllogutils/CallLogDates.java3
-rw-r--r--java/com/android/dialer/function/Supplier.java23
-rw-r--r--java/com/android/dialer/strictmode/DialerStrictMode.java14
-rw-r--r--java/com/android/dialer/time/Clock.java23
22 files changed, 602 insertions, 82 deletions
diff --git a/assets/quantum/res/drawable/quantum_ic_more_vert_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_more_vert_vd_theme_24.xml
new file mode 100644
index 000000000..1a3a684f4
--- /dev/null
+++ b/assets/quantum/res/drawable/quantum_ic_more_vert_vd_theme_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
index ebfd3c79b..507a51af6 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
@@ -38,7 +38,9 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper {
// Common columns.
.append(AnnotatedCallLog._ID + " integer primary key, ")
.append(AnnotatedCallLog.TIMESTAMP + " integer, ")
- .append(AnnotatedCallLog.PRIMARY_TEXT + " string, ")
+ .append(AnnotatedCallLog.NAME + " string, ")
+ .append(AnnotatedCallLog.NEW + " integer, ")
+ .append(AnnotatedCallLog.TYPE + " integer, ")
.append(AnnotatedCallLog.CONTACT_PHOTO_URI + " string, ")
.append(AnnotatedCallLog.NUMBER_TYPE_LABEL + " string, ")
.append(AnnotatedCallLog.IS_READ + " integer, ")
diff --git a/java/com/android/dialer/calllog/database/Coalescer.java b/java/com/android/dialer/calllog/database/Coalescer.java
index 23ddc9c21..55bed3e8c 100644
--- a/java/com/android/dialer/calllog/database/Coalescer.java
+++ b/java/com/android/dialer/calllog/database/Coalescer.java
@@ -133,8 +133,16 @@ public class Coalescer {
DialerPhoneNumber number1;
DialerPhoneNumber number2;
try {
- number1 = DialerPhoneNumber.parseFrom(row1.getAsByteArray(AnnotatedCallLog.NUMBER));
- number2 = DialerPhoneNumber.parseFrom(row2.getAsByteArray(AnnotatedCallLog.NUMBER));
+ byte[] number1Bytes = row1.getAsByteArray(AnnotatedCallLog.NUMBER);
+ byte[] number2Bytes = row2.getAsByteArray(AnnotatedCallLog.NUMBER);
+
+ if (number1Bytes == null || number2Bytes == null) {
+ // Empty numbers should not be combined.
+ return false;
+ }
+
+ number1 = DialerPhoneNumber.parseFrom(number1Bytes);
+ number2 = DialerPhoneNumber.parseFrom(number2Bytes);
} catch (InvalidProtocolBufferException e) {
throw Assert.createAssertionFailException("error parsing DialerPhoneNumber proto", e);
}
diff --git a/java/com/android/dialer/calllog/database/annotated_call_log.proto b/java/com/android/dialer/calllog/database/annotated_call_log.proto
index eb0ee52ce..de2bc5f14 100644
--- a/java/com/android/dialer/calllog/database/annotated_call_log.proto
+++ b/java/com/android/dialer/calllog/database/annotated_call_log.proto
@@ -8,7 +8,8 @@ option optimize_for = LITE_RUNTIME;
package com.android.dialer;
-// A list of android.provider.CallLog.Calls.TYPE values.
+// A list of android.provider.CallLog.Calls.TYPE values ordered from newest to
+// oldest.
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 172006878..c669bdae5 100644
--- a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
+++ b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
@@ -42,15 +42,15 @@ public class AnnotatedCallLogContract {
String TIMESTAMP = "timestamp";
/**
- * 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.
+ * Name of the caller if available. This could be a name from a local contact or caller ID data
+ * source, 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 PRIMARY_TEXT = "primary_text";
+ String NAME = "name";
/**
* Local photo URI for the contact associated with the phone number, if it exists.
@@ -74,14 +74,21 @@ public class AnnotatedCallLogContract {
String NUMBER_TYPE_LABEL = "number_type_label";
/**
- * See CallLog.Calls.IS_READ.
+ * See {@link android.provider.CallLog.Calls#IS_READ}.
*
* <p>TYPE: INTEGER (boolean)
*/
String IS_READ = "is_read";
/**
- * See CallLog.Calls.GEOCODED_LOCATION.
+ * See {@link android.provider.CallLog.Calls#NEW}.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ String NEW = "new";
+
+ /**
+ * See {@link android.provider.CallLog.Calls#GEOCODED_LOCATION}.
*
* <p>TYPE: TEXT
*/
@@ -102,7 +109,7 @@ public class AnnotatedCallLogContract {
String PHONE_ACCOUNT_COLOR = "phone_account_color";
/**
- * See CallLog.Calls.FEATURES.
+ * See {@link android.provider.CallLog.Calls#FEATURES}.
*
* <p>TYPE: INTEGER (int)
*/
@@ -128,10 +135,11 @@ public class AnnotatedCallLogContract {
new String[] {
_ID,
TIMESTAMP,
- PRIMARY_TEXT,
+ NAME,
CONTACT_PHOTO_URI,
NUMBER_TYPE_LABEL,
IS_READ,
+ NEW,
GEOCODED_LOCATION,
PHONE_ACCOUNT_LABEL,
PHONE_ACCOUNT_COLOR,
@@ -168,6 +176,13 @@ public class AnnotatedCallLogContract {
* <p>Type: BLOB
*/
public static final String NUMBER = "number";
+
+ /**
+ * Copied from {@link android.provider.CallLog.Calls#TYPE}.
+ *
+ * <p>Type: INTEGER (int)
+ */
+ public static final String TYPE = "type";
}
/**
diff --git a/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java b/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java
index ad824274e..8090cbc62 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.PRIMARY_TEXT, "Placeholder name");
+ contentValues.put(AnnotatedCallLog.NAME, "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.PRIMARY_TEXT)
+ .useSingleValueString(AnnotatedCallLog.NAME)
.combine();
}
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
index 94b908f8f..7bf2972c5 100644
--- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
@@ -37,6 +37,7 @@ import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.ArraySet;
+import com.android.dialer.CallTypes;
import com.android.dialer.DialerPhoneNumber;
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog;
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
@@ -84,6 +85,7 @@ public class SystemCallLogDataSource implements CallLogDataSource {
LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no call log permissions");
return;
}
+ // TODO(zachh): Need to somehow register observers if user enables permission after launch?
appContext
.getContentResolver()
@@ -104,8 +106,11 @@ public class SystemCallLogDataSource implements CallLogDataSource {
* column is unused). This means that we can't detect deletes without scanning the entire table,
* which would be too slow. So, we just rely on content observers to trigger rebuilds when any
* change is made to the system call log.
+ *
+ * Just return false unless the table has never been written to.
*/
- return false;
+ return !PreferenceManager.getDefaultSharedPreferences(appContext)
+ .contains(PREF_LAST_TIMESTAMP_PROCESSED);
}
@WorkerThread
@@ -152,23 +157,41 @@ public class SystemCallLogDataSource implements CallLogDataSource {
ContentValues coalescedValues =
new RowCombiner(individualRowsSortedByTimestampDesc)
.useMostRecentLong(AnnotatedCallLog.TIMESTAMP)
+ .useMostRecentLong(AnnotatedCallLog.NEW)
+ .useMostRecentString(AnnotatedCallLog.NUMBER_TYPE_LABEL)
+ .useMostRecentString(AnnotatedCallLog.GEOCODED_LOCATION)
.combine();
// All phone numbers in the provided group should be equivalent (but could be formatted
// differently). Arbitrarily show the raw phone number of the most recent call.
DialerPhoneNumber mostRecentPhoneNumber =
getMostRecentPhoneNumber(individualRowsSortedByTimestampDesc);
- coalescedValues.put(
- CoalescedAnnotatedCallLog.FORMATTED_NUMBER,
- mostRecentPhoneNumber.getRawInput().getNumber());
+ if (mostRecentPhoneNumber != null) {
+ coalescedValues.put(
+ CoalescedAnnotatedCallLog.FORMATTED_NUMBER,
+ mostRecentPhoneNumber.getRawInput().getNumber());
+ }
+
+ CallTypes.Builder callTypes = CallTypes.newBuilder();
+ // Store a maximum of 3 call types since that's all we show to users via icons.
+ for (int i = 0; i < 3 && i < individualRowsSortedByTimestampDesc.size(); i++) {
+ callTypes.addType(
+ individualRowsSortedByTimestampDesc.get(i).getAsInteger(AnnotatedCallLog.TYPE));
+ }
+ coalescedValues.put(CoalescedAnnotatedCallLog.CALL_TYPES, callTypes.build().toByteArray());
+
return coalescedValues;
}
+ @Nullable
private static DialerPhoneNumber getMostRecentPhoneNumber(
List<ContentValues> individualRowsSortedByTimestampDesc) {
- DialerPhoneNumber dialerPhoneNumber;
byte[] protoBytes =
individualRowsSortedByTimestampDesc.get(0).getAsByteArray(AnnotatedCallLog.NUMBER);
+ if (protoBytes == null) {
+ return null;
+ }
+ DialerPhoneNumber dialerPhoneNumber;
try {
dialerPhoneNumber = DialerPhoneNumber.parseFrom(protoBytes);
} catch (InvalidProtocolBufferException e) {
@@ -198,10 +221,12 @@ public class SystemCallLogDataSource implements CallLogDataSource {
Calls.DATE,
Calls.LAST_MODIFIED,
Calls.NUMBER,
+ Calls.TYPE,
Calls.COUNTRY_ISO,
Calls.CACHED_NUMBER_TYPE,
Calls.CACHED_NUMBER_LABEL,
Calls.IS_READ,
+ Calls.NEW,
Calls.GEOCODED_LOCATION,
Calls.PHONE_ACCOUNT_COMPONENT_NAME,
Calls.PHONE_ACCOUNT_ID,
@@ -226,10 +251,12 @@ public class SystemCallLogDataSource implements CallLogDataSource {
int dateColumn = cursor.getColumnIndexOrThrow(Calls.DATE);
int lastModifiedColumn = cursor.getColumnIndexOrThrow(Calls.LAST_MODIFIED);
int numberColumn = cursor.getColumnIndexOrThrow(Calls.NUMBER);
+ int typeColumn = cursor.getColumnIndexOrThrow(Calls.TYPE);
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 newColumn = cursor.getColumnIndexOrThrow(Calls.NEW);
int geocodedLocationColumn = cursor.getColumnIndexOrThrow(Calls.GEOCODED_LOCATION);
int phoneAccountComponentColumn =
cursor.getColumnIndexOrThrow(Calls.PHONE_ACCOUNT_COMPONENT_NAME);
@@ -243,30 +270,40 @@ public class SystemCallLogDataSource implements CallLogDataSource {
long id = cursor.getLong(idColumn);
long date = cursor.getLong(dateColumn);
String numberAsStr = cursor.getString(numberColumn);
+ long type = cursor.getType(typeColumn);
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);
+ int isNew = cursor.getInt(newColumn);
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());
+
+ if (!TextUtils.isEmpty(numberAsStr)) {
+ byte[] numberAsProtoBytes =
+ dialerPhoneNumberUtil.parse(numberAsStr, countryIso).toByteArray();
+ // TODO(zachh): Need to handle post-dial digits; different on N and M.
+ contentValues.put(AnnotatedCallLog.NUMBER, numberAsProtoBytes);
+ }
+
+ contentValues.put(AnnotatedCallLog.TYPE, type);
+
+ // Phone.getTypeLabel returns "Custom" if given (0, null) which is not of any use. Just
+ // omit setting the label if there's no information for it.
+ if (cachedNumberType != 0 || cachedNumberLabel != null) {
+ contentValues.put(
+ AnnotatedCallLog.NUMBER_TYPE_LABEL,
+ Phone.getTypeLabel(appContext.getResources(), cachedNumberType, cachedNumberLabel)
+ .toString());
+ }
contentValues.put(AnnotatedCallLog.IS_READ, isRead);
+ contentValues.put(AnnotatedCallLog.NEW, isNew);
contentValues.put(AnnotatedCallLog.GEOCODED_LOCATION, geocodedLocation);
populatePhoneAccountLabelAndColor(
appContext, contentValues, phoneAccountComponentName, phoneAccountId);
diff --git a/java/com/android/dialer/calllog/datasources/util/RowCombiner.java b/java/com/android/dialer/calllog/datasources/util/RowCombiner.java
index 0c7be1e27..3595a055d 100644
--- a/java/com/android/dialer/calllog/datasources/util/RowCombiner.java
+++ b/java/com/android/dialer/calllog/datasources/util/RowCombiner.java
@@ -36,12 +36,23 @@ public class RowCombiner {
return this;
}
+ /** Use the most recent value for the specified column. */
+ public RowCombiner useMostRecentString(String columnName) {
+ combinedRow.put(columnName, individualRowsSortedByTimestampDesc.get(0).getAsString(columnName));
+ return this;
+ }
+
/** Asserts that all column values for the given column name are the same, and uses it. */
public RowCombiner useSingleValueString(String columnName) {
Iterator<ContentValues> iterator = individualRowsSortedByTimestampDesc.iterator();
String singleValue = iterator.next().getAsString(columnName);
while (iterator.hasNext()) {
- Assert.checkState(iterator.next().getAsString(columnName).equals(singleValue));
+ String current = iterator.next().getAsString(columnName);
+ if (current == null) {
+ Assert.checkState(singleValue == null);
+ } else {
+ Assert.checkState(current.equals(singleValue));
+ }
}
combinedRow.put(columnName, singleValue);
return this;
diff --git a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java
index e993816bf..654591688 100644
--- a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java
+++ b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java
@@ -30,19 +30,20 @@ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader {
private static final int ID = 0;
private static final int TIMESTAMP = 1;
- private static final int PRIMARY_TEXT = 2;
+ private static final int NAME = 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;
+ private static final int NEW = 6;
+ private static final int GEOCODED_LOCATION = 7;
+ private static final int PHONE_ACCOUNT_LABEL = 8;
+ private static final int PHONE_ACCOUNT_COLOR = 9;
+ private static final int FEATURES = 10;
+ private static final int IS_BUSINESS = 11;
+ private static final int IS_VOICEMAIL = 12;
+ private static final int NUMBER_CALLS = 13;
+ private static final int FORMATTED_NUMBER = 14;
+ private static final int CALL_TYPES = 15;
/** Convenience class for accessing values using an abbreviated syntax. */
static final class Row {
@@ -60,8 +61,8 @@ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader {
return cursor.getLong(TIMESTAMP);
}
- String primaryText() {
- return cursor.getString(PRIMARY_TEXT);
+ String name() {
+ return cursor.getString(NAME);
}
String contactPhotoUri() {
@@ -76,6 +77,10 @@ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader {
return cursor.getInt(IS_READ) == 1;
}
+ boolean isNew() {
+ return cursor.getInt(NEW) == 1;
+ }
+
String geocodedLocation() {
return cursor.getString(GEOCODED_LOCATION);
}
diff --git a/java/com/android/dialer/calllog/ui/HeaderViewHolder.java b/java/com/android/dialer/calllog/ui/HeaderViewHolder.java
new file mode 100644
index 000000000..e4fe029fa
--- /dev/null
+++ b/java/com/android/dialer/calllog/ui/HeaderViewHolder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.support.annotation.StringRes;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.View;
+import android.widget.TextView;
+
+/** ViewHolder for {@link NewCallLogAdapter} to display "Today" or "Older" divider row. */
+final class HeaderViewHolder extends ViewHolder {
+
+ private TextView headerTextView;
+
+ HeaderViewHolder(View view) {
+ super(view);
+ headerTextView = view.findViewById(R.id.new_call_log_header_text);
+ }
+
+ void setHeader(@StringRes int header) {
+ headerTextView.setText(header);
+ }
+}
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java
index 4655b0982..b922a6e3b 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java
@@ -16,34 +16,140 @@
package com.android.dialer.calllog.ui;
import android.database.Cursor;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.ViewGroup;
+import com.android.dialer.calllogutils.CallLogDates;
+import com.android.dialer.common.Assert;
+import com.android.dialer.time.Clock;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/** {@link RecyclerView.Adapter} for the new call log fragment. */
-final class NewCallLogAdapter extends RecyclerView.Adapter<NewCallLogViewHolder> {
+final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
+
+ /** IntDef for the different types of rows that can be shown in the call log. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RowType.HEADER_TODAY, RowType.HEADER_OLDER, RowType.CALL_LOG_ENTRY})
+ @interface RowType {
+ /** Header that displays "Today". */
+ int HEADER_TODAY = 1;
+ /** Header that displays "Older". */
+ int HEADER_OLDER = 2;
+ /** A row representing a call log entry (which could represent one or more calls). */
+ int CALL_LOG_ENTRY = 3;
+ }
private final Cursor cursor;
+ private final Clock clock;
- NewCallLogAdapter(Cursor cursor) {
+ /** Null when the "Today" header should not be displayed. */
+ @Nullable private final Integer todayHeaderPosition;
+ /** Null when the "Older" header should not be displayed. */
+ @Nullable private final Integer olderHeaderPosition;
+
+ NewCallLogAdapter(Cursor cursor, Clock clock) {
this.cursor = cursor;
+ this.clock = clock;
+
+ // Calculate header adapter positions by reading cursor.
+ long currentTimeMillis = clock.currentTimeMillis();
+ if (cursor.moveToNext()) {
+ CoalescedAnnotatedCallLogCursorLoader.Row firstRow =
+ new CoalescedAnnotatedCallLogCursorLoader.Row(cursor);
+ if (CallLogDates.isSameDay(currentTimeMillis, firstRow.timestamp())) {
+ this.todayHeaderPosition = 0;
+ int adapterPosition = 2; // Accounted for "Today" header and first row.
+ while (cursor.moveToNext()) {
+ CoalescedAnnotatedCallLogCursorLoader.Row row =
+ new CoalescedAnnotatedCallLogCursorLoader.Row(cursor);
+ if (CallLogDates.isSameDay(currentTimeMillis, row.timestamp())) {
+ adapterPosition++;
+ } else {
+ this.olderHeaderPosition = adapterPosition;
+ return;
+ }
+ }
+ this.olderHeaderPosition = null; // Didn't find any "Older" rows.
+ } else {
+ this.todayHeaderPosition = null; // Didn't find any "Today" rows.
+ this.olderHeaderPosition = 0;
+ }
+ } else { // There are no rows, just need to set these because they are final.
+ this.todayHeaderPosition = null;
+ this.olderHeaderPosition = null;
+ }
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType) {
+ switch (viewType) {
+ case RowType.HEADER_TODAY:
+ case RowType.HEADER_OLDER:
+ return new HeaderViewHolder(
+ LayoutInflater.from(viewGroup.getContext())
+ .inflate(R.layout.new_call_log_header, viewGroup, false));
+ case RowType.CALL_LOG_ENTRY:
+ return new NewCallLogViewHolder(
+ LayoutInflater.from(viewGroup.getContext())
+ .inflate(R.layout.new_call_log_entry, viewGroup, false),
+ clock);
+ default:
+ throw Assert.createUnsupportedOperationFailException("Unsupported view type: " + viewType);
+ }
}
@Override
- public NewCallLogViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
- return new NewCallLogViewHolder(
- LayoutInflater.from(viewGroup.getContext())
- .inflate(R.layout.new_call_log_entry, viewGroup, false));
+ public void onBindViewHolder(ViewHolder viewHolder, int position) {
+ if (viewHolder instanceof HeaderViewHolder) {
+ HeaderViewHolder headerViewHolder = (HeaderViewHolder) viewHolder;
+ @RowType int viewType = getItemViewType(position);
+ if (viewType == RowType.HEADER_OLDER) {
+ headerViewHolder.setHeader(R.string.new_call_log_header_older);
+ } else if (viewType == RowType.HEADER_TODAY) {
+ headerViewHolder.setHeader(R.string.new_call_log_header_today);
+ } else {
+ throw Assert.createIllegalStateFailException(
+ "Unexpected view type " + viewType + " at position: " + position);
+ }
+ return;
+ }
+ NewCallLogViewHolder newCallLogViewHolder = (NewCallLogViewHolder) viewHolder;
+ int previousHeaders = 0;
+ if (todayHeaderPosition != null && position > todayHeaderPosition) {
+ previousHeaders++;
+ }
+ if (olderHeaderPosition != null && position > olderHeaderPosition) {
+ previousHeaders++;
+ }
+ cursor.moveToPosition(position - previousHeaders);
+ newCallLogViewHolder.bind(cursor);
}
@Override
- public void onBindViewHolder(NewCallLogViewHolder viewHolder, int position) {
- cursor.moveToPosition(position);
- viewHolder.bind(cursor);
+ @RowType
+ public int getItemViewType(int position) {
+ if (todayHeaderPosition != null && position == todayHeaderPosition) {
+ return RowType.HEADER_TODAY;
+ }
+ if (olderHeaderPosition != null && position == olderHeaderPosition) {
+ return RowType.HEADER_OLDER;
+ }
+ return RowType.CALL_LOG_ENTRY;
}
@Override
public int getItemCount() {
- return cursor.getCount();
+ int numberOfHeaders = 0;
+ if (todayHeaderPosition != null) {
+ numberOfHeaders++;
+ }
+ if (olderHeaderPosition != null) {
+ numberOfHeaders++;
+ }
+ return cursor.getCount() + numberOfHeaders;
}
}
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
index c4bcb766b..92276786e 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java
@@ -68,7 +68,7 @@ public final class NewCallLogFragment extends Fragment
refreshAnnotatedCallLogTask =
dialerExecutorFactory
.createUiTaskBuilder(
- getFragmentManager(),
+ getActivity().getFragmentManager(),
"NewCallLogFragment.refreshAnnotatedCallLog",
component.getRefreshAnnotatedCallLogWorker())
.build();
@@ -140,7 +140,7 @@ public final class NewCallLogFragment extends Fragment
// TODO(zachh): Handle empty cursor by showing empty view.
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- recyclerView.setAdapter(new NewCallLogAdapter(newCursor));
+ recyclerView.setAdapter(new NewCallLogAdapter(newCursor, System::currentTimeMillis));
}
@Override
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java
index 72ea17b03..b6b658fe6 100644
--- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java
+++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java
@@ -15,33 +15,119 @@
*/
package com.android.dialer.calllog.ui;
+import android.content.Context;
import android.database.Cursor;
+import android.provider.CallLog.Calls;
import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
import android.view.View;
+import android.widget.QuickContactBadge;
import android.widget.TextView;
-import java.text.SimpleDateFormat;
+import com.android.dialer.calllogutils.CallLogDates;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.time.Clock;
import java.util.Locale;
/** {@link RecyclerView.ViewHolder} for the new call log. */
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 Context context;
private final TextView primaryTextView;
private final TextView secondaryTextView;
+ private final QuickContactBadge quickContactBadge;
+ private final Clock clock;
- NewCallLogViewHolder(View view) {
+ NewCallLogViewHolder(View view, Clock clock) {
super(view);
+ this.context = view.getContext();
primaryTextView = view.findViewById(R.id.primary_text);
secondaryTextView = view.findViewById(R.id.secondary_text);
+ quickContactBadge = view.findViewById(R.id.quick_contact_photo);
+ this.clock = clock;
}
/** @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()));
+
+ // TODO(zachh): Add HD icon and Wifi icon after primary text.
+ // TODO(zachh): Call type icons for last 3 calls.
+ // TODO(zachh): Use name for primary text if available.
+ // TODO(zachh): Handle CallLog.Calls.PRESENTATION_*, including Verizon restricted numbers.
+ // TODO(zachh): Handle RTL properly.
+ primaryTextView.setText(buildPrimaryText(row));
+ secondaryTextView.setText(buildSecondaryText(row));
+
+ if (row.isNew()) {
+ // TODO(zachh): Figure out correct styling for new/missed/unread calls.
+ primaryTextView.setTextAppearance(R.style.primary_textview_new_call);
+ // TODO(zachh): Styling for call type icons when the call is new.
+ secondaryTextView.setTextAppearance(R.style.secondary_textview_new_call);
+ }
+
+ setPhoto();
+ }
+
+ private String buildPrimaryText(CoalescedAnnotatedCallLogCursorLoader.Row row) {
+ StringBuilder primaryText =
+ new StringBuilder(
+ TextUtils.isEmpty(row.formattedNumber())
+ ? context.getText(R.string.new_call_log_unknown)
+ : row.formattedNumber());
+ if (row.numberCalls() > 1) {
+ primaryText.append(String.format(Locale.getDefault(), " (%d)", row.numberCalls()));
+ }
+ return primaryText.toString();
+ }
+
+ private String buildSecondaryText(CoalescedAnnotatedCallLogCursorLoader.Row row) {
+ /*
+ * Rules: (Duo video, )?$Label|$Location • Date
+ *
+ * Examples:
+ * Duo Video, Mobile • Now
+ * Duo Video • 11:45pm
+ * Mobile • 11:45pm
+ * Mobile • Sunday
+ * Brooklyn, NJ • Jan 15
+ *
+ * Date rules:
+ * if < 1 minute ago: "Now"; else if today: HH:MM(am|pm); else if < 3 days: day; else: MON D
+ */
+ StringBuilder secondaryText = new StringBuilder();
+ if ((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) {
+ // TODO(zachh): Add "Duo" prefix?
+ secondaryText.append(context.getText(R.string.new_call_log_video));
+ }
+ String numberTypeLabel = row.numberTypeLabel();
+ if (!TextUtils.isEmpty(numberTypeLabel)) {
+ if (secondaryText.length() > 0) {
+ secondaryText.append(", ");
+ }
+ secondaryText.append(numberTypeLabel);
+ } else { // If there's a number type label, don't show the location.
+ String location = row.geocodedLocation();
+ if (!TextUtils.isEmpty(location)) {
+ if (secondaryText.length() > 0) {
+ secondaryText.append(", ");
+ }
+ secondaryText.append(location);
+ }
+ }
+ if (secondaryText.length() > 0) {
+ secondaryText.append(" • ");
+ }
+ secondaryText.append(
+ CallLogDates.newCallLogTimestampLabel(context, clock.currentTimeMillis(), row.timestamp()));
+ return secondaryText.toString();
+ }
+
+ private void setPhoto() {
+ // TODO(zachh): Set photo/icon appropriately. (This just uses the anonymous avatar.)
+ ContactPhotoManager.getInstance(context)
+ .loadDialerThumbnailOrPhoto(
+ quickContactBadge, null, 0, null, null, LetterTileDrawable.TYPE_DEFAULT);
}
}
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 38e07becf..568b3512e 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
@@ -15,23 +15,64 @@
~ limitations under the License
-->
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="8dp"
- android:orientation="vertical">
+ android:layout_marginTop="@dimen/call_log_entry_top_margin"
+ android:paddingTop="@dimen/call_log_entry_padding_top_start"
+ android:paddingBottom="@dimen/call_log_entry_padding_bottom_end"
+ android:paddingStart="@dimen/call_log_entry_padding_top_start"
+ android:paddingEnd="@dimen/call_log_entry_padding_bottom_end"
+ android:gravity="center_vertical">
- <TextView
- android:id="@+id/primary_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/PrimaryText"/>
+ <QuickContactBadge
+ android:id="@+id/quick_contact_photo"
+ android:layout_width="@dimen/call_log_entry_photo_size"
+ android:layout_height="@dimen/call_log_entry_photo_size"
+ android:layout_centerVertical="true"
+ android:padding="@dimen/call_log_entry_photo_padding"
+ android:focusable="true"/>
- <TextView
- android:id="@+id/secondary_text"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@style/SecondaryText"/>
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@+id/quick_contact_photo"
+ android:layout_toStartOf="@+id/menu_button"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/primary_text"
+ style="@style/PrimaryText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/call_log_entry_photo_text_margin"/>
+
+ <TextView
+ android:id="@+id/secondary_text"
+ style="@style/SecondaryText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/call_log_entry_photo_text_margin"/>
+
+ <TextView
+ android:id="@+id/phone_account"
+ style="@style/SecondaryText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/call_log_entry_photo_text_margin"
+ android:visibility="gone"/>
+ </LinearLayout>
-</LinearLayout> \ No newline at end of file
+ <ImageView
+ android:id="@+id/menu_button"
+ android:layout_width="@dimen/call_log_entry_menu_button_size"
+ android:layout_height="@dimen/call_log_entry_menu_button_size"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:scaleType="center"
+ android:src="@drawable/quantum_ic_more_vert_vd_theme_24"
+ android:tint="@color/dialer_secondary_text_color"/>
+</RelativeLayout>
diff --git a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_header.xml b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_header.xml
new file mode 100644
index 000000000..13575db55
--- /dev/null
+++ b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_header.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:height="48dp">
+ <TextView
+ android:id="@+id/new_call_log_header_text"
+ style="@style/SecondaryText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/call_log_action_icon_margin_start"
+ android:layout_centerVertical="true"/>
+</RelativeLayout>
diff --git a/java/com/android/dialer/calllog/ui/res/values/dimens.xml b/java/com/android/dialer/calllog/ui/res/values/dimens.xml
new file mode 100644
index 000000000..bfb4c99d7
--- /dev/null
+++ b/java/com/android/dialer/calllog/ui/res/values/dimens.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<resources>
+
+ <!-- call log entries -->
+ <dimen name="call_log_entry_top_margin">6dp</dimen>
+ <dimen name="call_log_entry_padding_bottom_end">16dp</dimen>
+ <dimen name="call_log_entry_padding_top_start">12dp</dimen>
+ <dimen name="call_log_entry_photo_size">48dp</dimen>
+ <dimen name="call_log_entry_photo_padding">4dp</dimen>
+ <dimen name="call_log_entry_photo_text_margin">8dp</dimen>
+ <dimen name="call_log_entry_menu_button_size">48dp</dimen>
+
+</resources>
diff --git a/java/com/android/dialer/calllog/ui/res/values/strings.xml b/java/com/android/dialer/calllog/ui/res/values/strings.xml
new file mode 100644
index 000000000..9b044ca08
--- /dev/null
+++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<resources>
+
+ <!-- Text to show in call log for a video call. [CHAR LIMIT=16] -->
+ <string name="new_call_log_video">Video</string>
+
+ <!-- String used to display calls from unknown numbers in the call log. [CHAR LIMIT=30] -->
+ <string name="new_call_log_unknown">Unknown</string>
+
+ <!-- Header in call log to group calls from the current day. [CHAR LIMIT=30] -->
+ <string name="new_call_log_header_today">Today</string>
+
+ <!-- Header in call log to group calls from before the current day. [CHAR LIMIT=30] -->
+ <string name="new_call_log_header_older">Older</string>
+
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/calllog/ui/res/values/styles.xml b/java/com/android/dialer/calllog/ui/res/values/styles.xml
new file mode 100644
index 000000000..23cb93e1a
--- /dev/null
+++ b/java/com/android/dialer/calllog/ui/res/values/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<resources>
+
+ <style name="primary_textview_new_call">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ </style>
+
+ <style name="secondary_textview_new_call">
+ <item name="android:textColor">@color/missed_call</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/calllogutils/CallLogDates.java b/java/com/android/dialer/calllogutils/CallLogDates.java
index 2d4bd8bf5..82e8e404e 100644
--- a/java/com/android/dialer/calllogutils/CallLogDates.java
+++ b/java/com/android/dialer/calllogutils/CallLogDates.java
@@ -151,7 +151,8 @@ public final class CallLogDates {
return then.equals(threeDaysAgoStartOfDay) || then.after(threeDaysAgoStartOfDay);
}
- private static boolean isSameDay(long firstMillis, long secondMillis) {
+ /** Returns true if the provided timestamps are from the same day in the default time zone. */
+ public static boolean isSameDay(long firstMillis, long secondMillis) {
Calendar first = Calendar.getInstance();
first.setTimeInMillis(firstMillis);
diff --git a/java/com/android/dialer/function/Supplier.java b/java/com/android/dialer/function/Supplier.java
new file mode 100644
index 000000000..1a16183f2
--- /dev/null
+++ b/java/com/android/dialer/function/Supplier.java
@@ -0,0 +1,23 @@
+/*
+ * 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.function;
+
+/** Functional interface for supplying generic values. */
+public interface Supplier<T> {
+
+ /** Supplies a value. */
+ T get();
+}
diff --git a/java/com/android/dialer/strictmode/DialerStrictMode.java b/java/com/android/dialer/strictmode/DialerStrictMode.java
index 4a0336e53..c7d0b3f57 100644
--- a/java/com/android/dialer/strictmode/DialerStrictMode.java
+++ b/java/com/android/dialer/strictmode/DialerStrictMode.java
@@ -28,6 +28,7 @@ import android.support.annotation.AnyThread;
import android.support.annotation.MainThread;
import android.support.v4.os.UserManagerCompat;
import com.android.dialer.buildtype.BuildType;
+import com.android.dialer.function.Supplier;
import com.android.dialer.util.DialerUtils;
/** Enables strict mode for the application, and provides means of temporarily disabling it. */
@@ -94,11 +95,6 @@ public final class DialerStrictMode {
return Looper.getMainLooper().equals(Looper.myLooper());
}
- /** Functional interface intended to be used with {@link #bypass(Provider)}. */
- public interface Provider<T> {
- T get();
- }
-
/**
* Convenience method for disabling and enabling the thread policy death penalty using lambdas.
*
@@ -111,17 +107,17 @@ public final class DialerStrictMode {
* <p>The thread policy is only mutated if this is called from the main thread.
*/
@AnyThread
- public static <T> T bypass(Provider<T> provider) {
+ public static <T> T bypass(Supplier<T> supplier) {
if (isStrictModeAllowed() && onMainThread()) {
ThreadPolicy originalPolicy = StrictMode.getThreadPolicy();
StrictModeUtils.setRecommendedMainThreadPolicy(THREAD_LOG_PENALTY);
try {
- return provider.get();
+ return supplier.get();
} finally {
StrictMode.setThreadPolicy(originalPolicy);
}
}
- return provider.get();
+ return supplier.get();
}
/**
@@ -149,3 +145,5 @@ public final class DialerStrictMode {
runnable.run();
}
}
+
+
diff --git a/java/com/android/dialer/time/Clock.java b/java/com/android/dialer/time/Clock.java
new file mode 100644
index 000000000..4b7edc662
--- /dev/null
+++ b/java/com/android/dialer/time/Clock.java
@@ -0,0 +1,23 @@
+/*
+ * 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.time;
+
+/** Functional interface for providing time since epoch. */
+public interface Clock {
+ /** Returns milliseconds since epoch. */
+ long currentTimeMillis();
+}