From c5c42189eeab0389a94717de9a66c6d00068e8bf Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Tue, 22 May 2018 15:30:39 -0700 Subject: Began implementation of Dialer dark theme. - README on how to properly theme Dialer going forward. - Migrated all widgets to use global colors. - Removed all activity and application themes where it wasn't necessary. - Added themeing test rule for Espresso tests. Bug: 79883035 Test: tap PiperOrigin-RevId: 197634256 Change-Id: I4b7d94d45aeeb59d484b0069fdd1e200a654910b --- java/com/android/dialer/calllogutils/CallTypeIconsView.java | 8 ++++---- java/com/android/dialer/calllogutils/res/values/colors.xml | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'java/com/android/dialer/calllogutils') diff --git a/java/com/android/dialer/calllogutils/CallTypeIconsView.java b/java/com/android/dialer/calllogutils/CallTypeIconsView.java index 30d9b6178..1df615f9c 100644 --- a/java/com/android/dialer/calllogutils/CallTypeIconsView.java +++ b/java/com/android/dialer/calllogutils/CallTypeIconsView.java @@ -27,7 +27,7 @@ import android.support.annotation.VisibleForTesting; import android.util.AttributeSet; import android.view.View; import com.android.dialer.compat.AppCompatConstants; -import com.android.dialer.theme.ThemeUtil; +import com.android.dialer.theme.base.ThemeUtil; import java.util.ArrayList; import java.util.List; @@ -289,20 +289,20 @@ public class CallTypeIconsView extends View { int iconId = R.drawable.quantum_ic_call_received_white_24; Drawable drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); incoming = drawable.mutate(); - incoming.setColorFilter(r.getColor(R.color.answered_call), PorterDuff.Mode.MULTIPLY); + incoming.setColorFilter(r.getColor(R.color.dialer_call_green), PorterDuff.Mode.MULTIPLY); // Create a rotated instance of the call arrow for outgoing calls. iconId = R.drawable.quantum_ic_call_made_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); outgoing = drawable.mutate(); - outgoing.setColorFilter(r.getColor(R.color.answered_call), PorterDuff.Mode.MULTIPLY); + outgoing.setColorFilter(r.getColor(R.color.dialer_call_green), PorterDuff.Mode.MULTIPLY); // Need to make a copy of the arrow drawable, otherwise the same instance colored // above will be recolored here. iconId = R.drawable.quantum_ic_call_missed_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); missed = drawable.mutate(); - missed.setColorFilter(r.getColor(R.color.missed_call), PorterDuff.Mode.MULTIPLY); + missed.setColorFilter(r.getColor(R.color.dialer_red), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_voicemail_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); diff --git a/java/com/android/dialer/calllogutils/res/values/colors.xml b/java/com/android/dialer/calllogutils/res/values/colors.xml index 8662163c1..3a9e3ae8a 100644 --- a/java/com/android/dialer/calllogutils/res/values/colors.xml +++ b/java/com/android/dialer/calllogutils/res/values/colors.xml @@ -15,8 +15,4 @@ ~ limitations under the License --> - - #C53929 - - #00c853 \ No newline at end of file -- cgit v1.2.3 From ffd525d8eb9dbe1bc4d87909b01371743c296a16 Mon Sep 17 00:00:00 2001 From: linyuh Date: Tue, 22 May 2018 23:54:53 -0700 Subject: Delete AppCompatConstants Test: Existing tests PiperOrigin-RevId: 197681266 Change-Id: I27fdda1d5c252993795b6eb860663c8cab0d363c --- .../dialer/calllogutils/CallTypeHelper.java | 24 +++++++++++----------- .../dialer/calllogutils/CallTypeIconsView.java | 14 ++++++------- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'java/com/android/dialer/calllogutils') diff --git a/java/com/android/dialer/calllogutils/CallTypeHelper.java b/java/com/android/dialer/calllogutils/CallTypeHelper.java index 6feaeb998..1bcaa317b 100644 --- a/java/com/android/dialer/calllogutils/CallTypeHelper.java +++ b/java/com/android/dialer/calllogutils/CallTypeHelper.java @@ -17,7 +17,7 @@ package com.android.dialer.calllogutils; import android.content.res.Resources; -import com.android.dialer.compat.AppCompatConstants; +import android.provider.CallLog.Calls; import com.android.dialer.duo.Duo; /** Helper class to perform operations related to call types. */ @@ -87,17 +87,17 @@ public class CallTypeHelper { } public static boolean isMissedCallType(int callType) { - return (callType != AppCompatConstants.CALLS_INCOMING_TYPE - && callType != AppCompatConstants.CALLS_OUTGOING_TYPE - && callType != AppCompatConstants.CALLS_VOICEMAIL_TYPE - && callType != AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE); + return (callType != Calls.INCOMING_TYPE + && callType != Calls.OUTGOING_TYPE + && callType != Calls.VOICEMAIL_TYPE + && callType != Calls.ANSWERED_EXTERNALLY_TYPE); } /** Returns the text used to represent the given call type. */ public CharSequence getCallTypeText( int callType, boolean isVideoCall, boolean isPulledCall, boolean isDuoCall) { switch (callType) { - case AppCompatConstants.CALLS_INCOMING_TYPE: + case Calls.INCOMING_TYPE: if (isVideoCall) { if (isPulledCall) { return incomingVideoPulledName; @@ -115,7 +115,7 @@ public class CallTypeHelper { } } - case AppCompatConstants.CALLS_OUTGOING_TYPE: + case Calls.OUTGOING_TYPE: if (isVideoCall) { if (isPulledCall) { return outgoingVideoPulledName; @@ -133,23 +133,23 @@ public class CallTypeHelper { } } - case AppCompatConstants.CALLS_MISSED_TYPE: + case Calls.MISSED_TYPE: if (isVideoCall) { return missedVideoName; } else { return missedName; } - case AppCompatConstants.CALLS_VOICEMAIL_TYPE: + case Calls.VOICEMAIL_TYPE: return voicemailName; - case AppCompatConstants.CALLS_REJECTED_TYPE: + case Calls.REJECTED_TYPE: return rejectedName; - case AppCompatConstants.CALLS_BLOCKED_TYPE: + case Calls.BLOCKED_TYPE: return blockedName; - case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE: + case Calls.ANSWERED_EXTERNALLY_TYPE: return answeredElsewhereName; default: diff --git a/java/com/android/dialer/calllogutils/CallTypeIconsView.java b/java/com/android/dialer/calllogutils/CallTypeIconsView.java index 1df615f9c..990fa7314 100644 --- a/java/com/android/dialer/calllogutils/CallTypeIconsView.java +++ b/java/com/android/dialer/calllogutils/CallTypeIconsView.java @@ -23,10 +23,10 @@ import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.provider.CallLog.Calls; import android.support.annotation.VisibleForTesting; import android.util.AttributeSet; import android.view.View; -import com.android.dialer.compat.AppCompatConstants; import com.android.dialer.theme.base.ThemeUtil; import java.util.ArrayList; import java.util.List; @@ -167,16 +167,16 @@ public class CallTypeIconsView extends View { private Drawable getCallTypeDrawable(int callType) { Resources resources = useLargeIcons ? largeResouces : CallTypeIconsView.resources; switch (callType) { - case AppCompatConstants.CALLS_INCOMING_TYPE: - case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE: + case Calls.INCOMING_TYPE: + case Calls.ANSWERED_EXTERNALLY_TYPE: return resources.incoming; - case AppCompatConstants.CALLS_OUTGOING_TYPE: + case Calls.OUTGOING_TYPE: return resources.outgoing; - case AppCompatConstants.CALLS_MISSED_TYPE: + case Calls.MISSED_TYPE: return resources.missed; - case AppCompatConstants.CALLS_VOICEMAIL_TYPE: + case Calls.VOICEMAIL_TYPE: return resources.voicemail; - case AppCompatConstants.CALLS_BLOCKED_TYPE: + case Calls.BLOCKED_TYPE: return resources.blocked; default: // It is possible for users to end up with calls with unknown call types in their -- cgit v1.2.3 From a93df43762f1539593da5f90bec16be2be01d281 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Wed, 23 May 2018 12:59:03 -0700 Subject: Converted ThemeUtil into a DaggerModule. This enables us to have Google-Sans font in GoogleDialer and Roboto in AOSP. Bug: 79883035 Test: tap PiperOrigin-RevId: 197774497 Change-Id: I1d490ab196a444c62e439444627d659fc42973ea --- .../android/dialer/calllogutils/CallTypeIconsView.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'java/com/android/dialer/calllogutils') diff --git a/java/com/android/dialer/calllogutils/CallTypeIconsView.java b/java/com/android/dialer/calllogutils/CallTypeIconsView.java index 990fa7314..19c30c575 100644 --- a/java/com/android/dialer/calllogutils/CallTypeIconsView.java +++ b/java/com/android/dialer/calllogutils/CallTypeIconsView.java @@ -27,7 +27,8 @@ import android.provider.CallLog.Calls; import android.support.annotation.VisibleForTesting; import android.util.AttributeSet; import android.view.View; -import com.android.dialer.theme.base.ThemeUtil; +import com.android.dialer.theme.base.Theme; +import com.android.dialer.theme.base.ThemeComponent; import java.util.ArrayList; import java.util.List; @@ -304,40 +305,41 @@ public class CallTypeIconsView extends View { missed = drawable.mutate(); missed.setColorFilter(r.getColor(R.color.dialer_red), PorterDuff.Mode.MULTIPLY); + Theme theme = ThemeComponent.get(context).theme(); iconId = R.drawable.quantum_ic_voicemail_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); voicemail = drawable.mutate(); - voicemail.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + voicemail.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_block_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); blocked = drawable.mutate(); - blocked.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + blocked.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_videocam_vd_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); videoCall = drawable.mutate(); - videoCall.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + videoCall.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_hd_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); hdCall = drawable.mutate(); - hdCall.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + hdCall.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_signal_wifi_4_bar_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); wifiCall = drawable.mutate(); - wifiCall.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + wifiCall.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_language_white_24; drawable = largeIcons ? r.getDrawable(iconId) : getScaledBitmap(context, iconId); assistedDialedCall = drawable.mutate(); - assistedDialedCall.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + assistedDialedCall.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconId = R.drawable.quantum_ic_rtt_vd_theme_24; drawable = largeIcons ? r.getDrawable(iconId, null) : getScaledBitmap(context, iconId); rttCall = drawable.mutate(); - rttCall.setColorFilter(ThemeUtil.getColorIcon(), PorterDuff.Mode.MULTIPLY); + rttCall.setColorFilter(theme.getColorIcon(), PorterDuff.Mode.MULTIPLY); iconMargin = largeIcons ? 0 : r.getDimensionPixelSize(R.dimen.call_log_icon_margin); } -- cgit v1.2.3 From 19a7c0eda9730798100994e0b5a6e99197f04f3d Mon Sep 17 00:00:00 2001 From: linyuh Date: Wed, 23 May 2018 16:41:50 -0700 Subject: Better a11y for new call log entries. Bug: 70989658 Test: CallLogDatesTest, CallLogEntryDescriptionsTest, NewCallLogViewHolderTest PiperOrigin-RevId: 197811739 Change-Id: I0f9d1e79d8e687efffbb1dac01aaf6fa26a45f6a --- .../android/dialer/calllogutils/CallLogDates.java | 85 +++++++----- .../calllogutils/CallLogEntryDescriptions.java | 154 +++++++++++++++++++++ .../dialer/calllogutils/CallLogEntryText.java | 71 +++++++--- .../dialer/calllogutils/res/values/strings.xml | 63 +++++++++ 4 files changed, 313 insertions(+), 60 deletions(-) create mode 100644 java/com/android/dialer/calllogutils/CallLogEntryDescriptions.java (limited to 'java/com/android/dialer/calllogutils') diff --git a/java/com/android/dialer/calllogutils/CallLogDates.java b/java/com/android/dialer/calllogutils/CallLogDates.java index 2c332901c..9c04c05f7 100644 --- a/java/com/android/dialer/calllogutils/CallLogDates.java +++ b/java/com/android/dialer/calllogutils/CallLogDates.java @@ -36,13 +36,16 @@ public final class CallLogDates { * if < 1 minute ago: "Just now"; * else if < 1 hour ago: time relative to now (e.g., "8 min ago"); * else if today: time (e.g., "12:15 PM"); - * else if < 7 days: abbreviated day of week (e.g., "Wed"); - * else if < 1 year: date with abbreviated month, day, but no year (e.g., "Jan 15"); - * else: date with abbreviated month, day, and year (e.g., "Jan 15, 2018"). + * else if < 7 days: day of week (e.g., "Wed"); + * else if < 1 year: date with month, day, but no year (e.g., "Jan 15"); + * else: date with month, day, and year (e.g., "Jan 15, 2018"). * + * + *

Callers can decide whether to abbreviate date/time by specifying flag {@code + * abbreviateDateTime}. */ public static CharSequence newCallLogTimestampLabel( - Context context, long nowMillis, long timestampMillis) { + Context context, long nowMillis, long timestampMillis, boolean abbreviateDateTime) { // For calls logged less than 1 minute ago, display "Just now". if (nowMillis - timestampMillis < TimeUnit.MINUTES.toMillis(1)) { return context.getString(R.string.just_now); @@ -50,16 +53,19 @@ public final class CallLogDates { // For calls logged less than 1 hour ago, display time relative to now (e.g., "8 min ago"). if (nowMillis - timestampMillis < TimeUnit.HOURS.toMillis(1)) { - return DateUtils.getRelativeTimeSpanString( - timestampMillis, - nowMillis, - DateUtils.MINUTE_IN_MILLIS, - DateUtils.FORMAT_ABBREV_RELATIVE) - .toString() - // The platform method DateUtils#getRelativeTimeSpanString adds a dot ('.') after the - // abbreviated time unit for some languages (e.g., "8 min. ago") but we prefer not to have - // the dot. - .replace(".", ""); + return abbreviateDateTime + ? DateUtils.getRelativeTimeSpanString( + timestampMillis, + nowMillis, + DateUtils.MINUTE_IN_MILLIS, + DateUtils.FORMAT_ABBREV_RELATIVE) + .toString() + // The platform method DateUtils#getRelativeTimeSpanString adds a dot ('.') after the + // abbreviated time unit for some languages (e.g., "8 min. ago") but we prefer not to + // have the dot. + .replace(".", "") + : DateUtils.getRelativeTimeSpanString( + timestampMillis, nowMillis, DateUtils.MINUTE_IN_MILLIS); } int dayDifference = getDayDifference(nowMillis, timestampMillis); @@ -69,19 +75,19 @@ public final class CallLogDates { return DateUtils.formatDateTime(context, timestampMillis, DateUtils.FORMAT_SHOW_TIME); } - // For calls logged within a week, display the abbreviated day of week (e.g., "Wed"). + // For calls logged within a week, display the day of week (e.g., "Wed"). if (dayDifference < 7) { - return formatDayOfWeek(context, timestampMillis); + return formatDayOfWeek(context, timestampMillis, abbreviateDateTime); } - // For calls logged within a year, display abbreviated month, day, but no year (e.g., "Jan 15"). + // For calls logged within a year, display month, day, but no year (e.g., "Jan 15"). if (isWithinOneYear(nowMillis, timestampMillis)) { - return formatAbbreviatedDate(context, timestampMillis, /* showYear = */ false); + return formatDate(context, timestampMillis, /* showYear = */ false, abbreviateDateTime); } - // For calls logged no less than one year ago, display abbreviated month, day, and year + // For calls logged no less than one year ago, display month, day, and year // (e.g., "Jan 15, 2018"). - return formatAbbreviatedDate(context, timestampMillis, /* showYear = */ true); + return formatDate(context, timestampMillis, /* showYear = */ true, abbreviateDateTime); } /** @@ -106,36 +112,41 @@ public final class CallLogDates { } /** - * Formats the provided timestamp (in milliseconds) into abbreviated day of week. + * Formats the provided timestamp (in milliseconds) into the month, day, and optionally, year. * - *

For example, returns a string like "Wed" or "Chor". + *

For example, returns a string like "Jan 15" or "Jan 15, 2018". * *

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 timestamp) { - return toTitleCase( - DateUtils.formatDateTime( - context, timestamp, DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY)); + private static CharSequence formatDate( + Context context, long timestamp, boolean showYear, boolean abbreviateDateTime) { + int formatFlags = 0; + if (abbreviateDateTime) { + formatFlags |= DateUtils.FORMAT_ABBREV_MONTH; + } + if (!showYear) { + formatFlags |= DateUtils.FORMAT_NO_YEAR; + } + + return toTitleCase(DateUtils.formatDateTime(context, timestamp, formatFlags)); } /** - * Formats the provided timestamp (in milliseconds) into the month abbreviation, day, and - * optionally, year. + * Formats the provided timestamp (in milliseconds) into day of week. * - *

For example, returns a string like "Jan 15" or "Jan 15, 2018". + *

For example, returns a string like "Wed" or "Chor". * *

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 formatAbbreviatedDate( - Context context, long timestamp, boolean showYear) { - int flags = DateUtils.FORMAT_ABBREV_MONTH; - if (!showYear) { - flags |= DateUtils.FORMAT_NO_YEAR; - } - - return toTitleCase(DateUtils.formatDateTime(context, timestamp, flags)); + private static CharSequence formatDayOfWeek( + Context context, long timestamp, boolean abbreviateDateTime) { + int formatFlags = + abbreviateDateTime + ? (DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY) + : DateUtils.FORMAT_SHOW_WEEKDAY; + return toTitleCase(DateUtils.formatDateTime(context, timestamp, formatFlags)); } private static CharSequence toTitleCase(CharSequence value) { diff --git a/java/com/android/dialer/calllogutils/CallLogEntryDescriptions.java b/java/com/android/dialer/calllogutils/CallLogEntryDescriptions.java new file mode 100644 index 000000000..244087989 --- /dev/null +++ b/java/com/android/dialer/calllogutils/CallLogEntryDescriptions.java @@ -0,0 +1,154 @@ +/* + * 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.provider.CallLog.Calls; +import android.support.annotation.PluralsRes; +import android.telecom.PhoneAccountHandle; +import android.text.TextUtils; +import com.android.dialer.calllog.model.CoalescedRow; +import com.android.dialer.telecom.TelecomUtil; +import com.android.dialer.time.Clock; +import com.google.common.collect.Collections2; +import java.util.List; + +/** Builds descriptions of call log entries for accessibility users. */ +public final class CallLogEntryDescriptions { + + private CallLogEntryDescriptions() {} + + /** + * Builds the content description for a call log entry. + * + *

The description is of format
+ * {primary description}, {secondary description}, {phone account description}. + * + *

    + *
  • The primary description depends on the number of calls in the entry. For example:
    + * "1 answered call from Jane Smith", or
    + * "2 calls, the latest is an answered call from Jane Smith". + *
  • The secondary description is the same as the secondary text for the call log entry, + * except that date/time is not abbreviated. For example:
    + * "mobile, 11 minutes ago". + *
  • The phone account description is of format "on {phone_account_label}, via {number}". For + * example:
    + * "on SIM 1, via 6502531234".
    + * Note that the phone account description will be empty if the device has only one SIM. + *
+ * + *

An example of the full description can be:
+ * "2 calls, the latest is an answered call from Jane Smith, mobile, 11 minutes ago, on SIM 1, via + * 6502531234". + */ + public static CharSequence buildDescriptionForEntry( + Context context, Clock clock, CoalescedRow row) { + + // Build the primary description. + // Examples: + // (1) For an entry containing only 1 call: + // "1 missed call from James Smith". + // (2) For entries containing multiple calls: + // "2 calls, the latest is a missed call from Jame Smith". + CharSequence primaryDescription = + context + .getResources() + .getQuantityString( + getPrimaryDescriptionResIdForCallType(row), + row.getCoalescedIds().getCoalescedIdCount(), + row.getCoalescedIds().getCoalescedIdCount(), + CallLogEntryText.buildPrimaryText(context, row)); + + // Build the secondary description. + // An example: "mobile, 11 minutes ago". + CharSequence secondaryDescription = + joinSecondaryTextComponents( + CallLogEntryText.buildSecondaryTextListForEntries( + context, clock, row, /* abbreviateDateTime = */ false)); + + // Build the phone account description. + // Note that this description can be an empty string. + CharSequence phoneAccountDescription = buildPhoneAccountDescription(context, row); + + return TextUtils.isEmpty(phoneAccountDescription) + ? context + .getResources() + .getString( + R.string.a11y_new_call_log_entry_full_description_without_phone_account_info, + primaryDescription, + secondaryDescription) + : context + .getResources() + .getString( + R.string.a11y_new_call_log_entry_full_description_with_phone_account_info, + primaryDescription, + secondaryDescription, + phoneAccountDescription); + } + + private static @PluralsRes int getPrimaryDescriptionResIdForCallType(CoalescedRow row) { + switch (row.getCallType()) { + case Calls.INCOMING_TYPE: + case Calls.ANSWERED_EXTERNALLY_TYPE: + return R.plurals.a11y_new_call_log_entry_answered_call; + case Calls.OUTGOING_TYPE: + return R.plurals.a11y_new_call_log_entry_outgoing_call; + case Calls.MISSED_TYPE: + return R.plurals.a11y_new_call_log_entry_missed_call; + case Calls.VOICEMAIL_TYPE: + throw new IllegalStateException("Voicemails not expected in call log"); + case Calls.BLOCKED_TYPE: + return R.plurals.a11y_new_call_log_entry_blocked_call; + default: + // It is possible for users to end up with calls with unknown call types in their + // call history, possibly due to 3rd party call log implementations (e.g. to + // distinguish between rejected and missed calls). Instead of crashing, just + // assume that all unknown call types are missed calls. + return R.plurals.a11y_new_call_log_entry_missed_call; + } + } + + private static CharSequence buildPhoneAccountDescription(Context context, CoalescedRow row) { + PhoneAccountHandle phoneAccountHandle = + TelecomUtil.composePhoneAccountHandle( + row.getPhoneAccountComponentName(), row.getPhoneAccountId()); + if (phoneAccountHandle == null) { + return ""; + } + + String phoneAccountLabel = PhoneAccountUtils.getAccountLabel(context, phoneAccountHandle); + if (TextUtils.isEmpty(phoneAccountLabel)) { + return ""; + } + + if (TextUtils.isEmpty(row.getNumber().getNormalizedNumber())) { + return ""; + } + + return context + .getResources() + .getString( + R.string.a11y_new_call_log_entry_phone_account, + phoneAccountLabel, + row.getNumber().getNormalizedNumber()); + } + + private static CharSequence joinSecondaryTextComponents(List components) { + return TextUtils.join( + ", ", Collections2.filter(components, (text) -> !TextUtils.isEmpty(text))); + } +} diff --git a/java/com/android/dialer/calllogutils/CallLogEntryText.java b/java/com/android/dialer/calllogutils/CallLogEntryText.java index acf8ef932..895497f0f 100644 --- a/java/com/android/dialer/calllogutils/CallLogEntryText.java +++ b/java/com/android/dialer/calllogutils/CallLogEntryText.java @@ -26,6 +26,7 @@ import com.android.dialer.time.Clock; import com.google.common.base.Optional; import com.google.common.collect.Collections2; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -76,45 +77,69 @@ public final class CallLogEntryText { } /** - * The secondary text to show in the main call log entry list. + * The secondary text to be shown in the main call log entry list. + * + *

This method first obtains a list of strings to be shown in order and then concatenates them + * with " • ". + * + *

Examples: + * + *

    + *
  • Mobile, Duo video • 10 min ago + *
  • Spam • Mobile • Now + *
  • Blocked • Spam • Mobile • Now + *
+ * + * @see #buildSecondaryTextListForEntries(Context, Clock, CoalescedRow, boolean) for details. + */ + public static CharSequence buildSecondaryTextForEntries( + Context context, Clock clock, CoalescedRow row) { + return joinSecondaryTextComponents( + buildSecondaryTextListForEntries(context, clock, row, /* abbreviateDateTime = */ true)); + } + + /** + * Returns a list of strings to be shown in order as the main call log entry's secondary text. * *

Rules: * *

    - *
  • An emergency number: Date + *
  • An emergency number: [{Date}] *
  • Number - not blocked, call - not spam: - *

    $Label(, Duo video|Carrier video)?|$Location • Date + *

    [{$Label(, Duo video|Carrier video)?|$Location}, {Date}] *

  • Number - blocked, call - not spam: - *

    Blocked • $Label(, Duo video|Carrier video)?|$Location • Date + *

    ["Blocked", {$Label(, Duo video|Carrier video)?|$Location}, {Date}] *

  • Number - not blocked, call - spam: - *

    Spam • $Label(, Duo video|Carrier video)? • Date + *

    ["Spam", {$Label(, Duo video|Carrier video)?}, {Date}] *

  • Number - blocked, call - spam: - *

    Blocked • Spam • $Label(, Duo video|Carrier video)? • Date + *

    ["Blocked, Spam", {$Label(, Duo video|Carrier video)?}, {Date}] *

* *

Examples: * *

    - *
  • Mobile, Duo video • Now - *
  • Duo video • 10 min ago - *
  • Mobile • 11:45 PM - *
  • Mobile • Sun - *
  • Blocked • Mobile, Duo video • Now - *
  • Blocked • Brooklyn, NJ • 10 min ago - *
  • Spam • Mobile • Now - *
  • Spam • Now - *
  • Blocked • Spam • Mobile • Now - *
  • Brooklyn, NJ • Jan 15 + *
  • ["Mobile, Duo video", "Now"] + *
  • ["Duo video", "10 min ago"] + *
  • ["Mobile", "11:45 PM"] + *
  • ["Mobile", "Sun"] + *
  • ["Blocked", "Mobile, Duo video", "Now"] + *
  • ["Blocked", "Brooklyn, NJ", "10 min ago"] + *
  • ["Spam", "Mobile", "Now"] + *
  • ["Spam", "Now"] + *
  • ["Blocked", "Spam", "Mobile", "Now"] + *
  • ["Brooklyn, NJ", "Jan 15"] *
* - *

See {@link CallLogDates#newCallLogTimestampLabel(Context, long, long)} for date rules. + *

See {@link CallLogDates#newCallLogTimestampLabel(Context, long, long, boolean)} for date + * rules. */ - public static CharSequence buildSecondaryTextForEntries( - Context context, Clock clock, CoalescedRow row) { + static List buildSecondaryTextListForEntries( + Context context, Clock clock, CoalescedRow row, boolean abbreviateDateTime) { // For emergency numbers, the secondary text should contain only the timestamp. if (row.getNumberAttributes().getIsEmergencyNumber()) { - return CallLogDates.newCallLogTimestampLabel( - context, clock.currentTimeMillis(), row.getTimestamp()); + return Collections.singletonList( + CallLogDates.newCallLogTimestampLabel( + context, clock.currentTimeMillis(), row.getTimestamp(), abbreviateDateTime)); } List components = new ArrayList<>(); @@ -130,8 +155,8 @@ public final class CallLogEntryText { components.add( CallLogDates.newCallLogTimestampLabel( - context, clock.currentTimeMillis(), row.getTimestamp())); - return joinSecondaryTextComponents(components); + context, clock.currentTimeMillis(), row.getTimestamp(), abbreviateDateTime)); + return components; } /** diff --git a/java/com/android/dialer/calllogutils/res/values/strings.xml b/java/com/android/dialer/calllogutils/res/values/strings.xml index e476bdd6c..52b6d3408 100644 --- a/java/com/android/dialer/calllogutils/res/values/strings.xml +++ b/java/com/android/dialer/calllogutils/res/values/strings.xml @@ -145,4 +145,67 @@ Spam + + + + %1$d missed call from %2$s + %1$d calls, the latest is a missed call from %2$s + + + + + %1$d answered call from %2$s + %1$d calls, the latest is an answered call from %2$s + + + + + %1$d outgoing call to %2$s + %1$d calls, the latest is an outgoing call to %2$s + + + + + %1$d blocked call from %2$s + %1$d calls, the latest is a blocked call from %2$s + + + + + + on %1$s, + via %2$s + + + + + %1$s, %2$s. + + + + + %1$s, %2$s, %3$s. + -- cgit v1.2.3 From 3a44f18827dd8adacf7776162140f4969c9f2807 Mon Sep 17 00:00:00 2001 From: linyuh Date: Thu, 24 May 2018 10:56:02 -0700 Subject: Better a11y for contact badge in the new call log. Bug: 70989658 Test: GlidePhotoManagerImplTest PiperOrigin-RevId: 197918533 Change-Id: I61d04e270ddf4237e8ed9c10e62e8d95f86d1eca --- java/com/android/dialer/calllogutils/PhotoInfoBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'java/com/android/dialer/calllogutils') diff --git a/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java b/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java index 0677c9114..2e2e4abcb 100644 --- a/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java +++ b/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java @@ -16,6 +16,7 @@ package com.android.dialer.calllogutils; +import android.content.Context; import android.provider.CallLog.Calls; import android.support.v4.os.BuildCompat; import com.android.dialer.NumberAttributes; @@ -28,8 +29,9 @@ import com.android.dialer.voicemail.model.VoicemailEntry; public final class PhotoInfoBuilder { /** Returns a {@link PhotoInfo.Builder} with info from {@link CoalescedRow}. */ - public static PhotoInfo.Builder fromCoalescedRow(CoalescedRow coalescedRow) { + public static PhotoInfo.Builder fromCoalescedRow(Context context, CoalescedRow coalescedRow) { return fromNumberAttributes(coalescedRow.getNumberAttributes()) + .setName(CallLogEntryText.buildPrimaryText(context, coalescedRow).toString()) .setFormattedNumber(coalescedRow.getFormattedNumber()) .setIsVoicemail(coalescedRow.getIsVoicemailCall()) .setIsSpam( -- cgit v1.2.3