diff options
author | linyuh <linyuh@google.com> | 2018-05-23 16:41:50 -0700 |
---|---|---|
committer | Eric Erfanian <erfanian@google.com> | 2018-05-30 14:03:01 +0000 |
commit | 19a7c0eda9730798100994e0b5a6e99197f04f3d (patch) | |
tree | 728f98a3d2b71fc7bd662a38a0f7f22b4e0009e4 | |
parent | 2ad3c08bc26edee0c721505e21c9764c10e3e5f7 (diff) |
Better a11y for new call log entries.
Bug: 70989658
Test: CallLogDatesTest, CallLogEntryDescriptionsTest, NewCallLogViewHolderTest
PiperOrigin-RevId: 197811739
Change-Id: I0f9d1e79d8e687efffbb1dac01aaf6fa26a45f6a
8 files changed, 378 insertions, 68 deletions
diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java index 4def69cf9..3b21a60de 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java @@ -26,12 +26,16 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.view.View; +import android.view.View.AccessibilityDelegate; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.widget.ImageView; import android.widget.TextView; import com.android.dialer.calllog.database.Coalescer; import com.android.dialer.calllog.model.CoalescedRow; import com.android.dialer.calllog.ui.NewCallLogAdapter.PopCounts; import com.android.dialer.calllog.ui.menu.NewCallLogMenu; +import com.android.dialer.calllogutils.CallLogEntryDescriptions; import com.android.dialer.calllogutils.CallLogEntryText; import com.android.dialer.calllogutils.CallLogRowActions; import com.android.dialer.calllogutils.PhoneAccountUtils; @@ -62,6 +66,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { private final ImageView assistedDialIcon; private final TextView phoneAccountView; private final ImageView menuButton; + private final View callLogEntryRootView; private final Clock clock; private final RealtimeRowProcessor realtimeRowProcessor; @@ -78,6 +83,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { PopCounts popCounts) { super(view); this.activity = activity; + callLogEntryRootView = view; contactPhotoView = view.findViewById(R.id.contact_photo_view); primaryTextView = view.findViewById(R.id.primary_text); callCountTextView = view.findViewById(R.id.call_count); @@ -107,6 +113,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { // what information we have, rather than an empty card. For example, if CP2 information needs to // be queried on the fly, we can still show the phone number until the contact name loads. displayRow(row); + configA11yForRow(row); // Note: This leaks the view holder via the callback (which is an inner class), but this is OK // because we only create ~10 of them (and they'll be collected assuming all jobs finish). @@ -142,6 +149,28 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { setOnClickListenerForMenuButon(row); } + private void configA11yForRow(CoalescedRow row) { + callLogEntryRootView.setContentDescription( + CallLogEntryDescriptions.buildDescriptionForEntry(activity, clock, row)); + + // Inform a11y users that double tapping an entry now makes a call. + // This will instruct TalkBack to say "double tap to call" instead of + // "double tap to activate". + callLogEntryRootView.setAccessibilityDelegate( + new AccessibilityDelegate() { + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.addAction( + new AccessibilityAction( + AccessibilityNodeInfo.ACTION_CLICK, + activity + .getResources() + .getString(R.string.a11y_new_call_log_entry_tap_action))); + } + }); + } + private void setNumberCalls(CoalescedRow row) { int numberCalls = row.getCoalescedIds().getCoalescedIdCount(); if (numberCalls > 1) { @@ -274,6 +303,12 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { private void setOnClickListenerForMenuButon(CoalescedRow row) { menuButton.setOnClickListener(NewCallLogMenu.createOnClickListener(activity, row)); + menuButton.setContentDescription( + activity + .getResources() + .getString( + R.string.a11y_new_call_log_entry_expand_menu, + CallLogEntryText.buildPrimaryText(activity, row))); } private class RealtimeRowFutureCallback implements FutureCallback<CoalescedRow> { 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 0acd8155f..726c53bc1 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 @@ -30,13 +30,19 @@ android:layout_marginEnd="8dp" android:layout_centerVertical="true"/> + <!-- + A vertical linear layout of three rows: primary info, secondary info, and phone account info. + It is marked as not important for a11y as we will set a more user-friendly content description + for the entire entry view in Java code. + --> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toEndOf="@+id/contact_photo_view" android:layout_toStartOf="@+id/menu_button" - android:orientation="vertical"> + android:orientation="vertical" + android:importantForAccessibility="noHideDescendants"> <!-- 1st row: primary info --> <LinearLayout @@ -134,6 +140,10 @@ </LinearLayout> + <!-- + The button to expand the bottom sheet for an entry. + Its content description is set in Java code. + --> <ImageView android:id="@+id/menu_button" android:layout_width="56dp" @@ -141,8 +151,8 @@ android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:background="?android:attr/selectableItemBackgroundBorderless" - android:contentDescription="@string/a11y_new_call_log_expand_menu_for_entry" android:scaleType="center" android:src="@drawable/quantum_ic_more_vert_vd_theme_24" - android:tint="?colorIcon"/> + android:tint="?colorIcon" + tools:ignore="ContentDescription"/> </RelativeLayout> diff --git a/java/com/android/dialer/calllog/ui/res/values/strings.xml b/java/com/android/dialer/calllog/ui/res/values/strings.xml index 3f6462c7b..112044f6e 100644 --- a/java/com/android/dialer/calllog/ui/res/values/strings.xml +++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml @@ -16,12 +16,21 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- + A string informing a11y users that activating a call log entry will place a call. + Note: the word "call" here is a verb. + [CHAR LIMIT=NONE] + --> + <string name="a11y_new_call_log_entry_tap_action">call</string> + <!-- - A string to describe available action for accessibility user. - It will be read as "expand menu for this call log entry". + A string describing the menu button of a call log entry for a11y users. + An example will be read as "expand call log menu for Jane Smith". + [CHAR LIMIT=NONE] --> - <string name="a11y_new_call_log_expand_menu_for_entry"> - Expand menu for this call log entry + <string name="a11y_new_call_log_entry_expand_menu"> + Expand call log menu for <xliff:g example="Jane Smith" id="primaryTextForEntry">%1$s</xliff:g> </string> <!-- Header in call log to group calls from the current day. [CHAR LIMIT=30] --> 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"). * </pre> + * + * <p>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. * - * <p>For example, returns a string like "Wed" or "Chor". + * <p>For example, returns a string like "Jan 15" or "Jan 15, 2018". * * <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 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. * - * <p>For example, returns a string like "Jan 15" or "Jan 15, 2018". + * <p>For example, returns a string like "Wed" or "Chor". * * <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 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. + * + * <p>The description is of format<br> + * {primary description}, {secondary description}, {phone account description}. + * + * <ul> + * <li>The primary description depends on the number of calls in the entry. For example:<br> + * "1 answered call from Jane Smith", or<br> + * "2 calls, the latest is an answered call from Jane Smith". + * <li>The secondary description is the same as the secondary text for the call log entry, + * except that date/time is not abbreviated. For example:<br> + * "mobile, 11 minutes ago". + * <li>The phone account description is of format "on {phone_account_label}, via {number}". For + * example:<br> + * "on SIM 1, via 6502531234".<br> + * Note that the phone account description will be empty if the device has only one SIM. + * </ul> + * + * <p>An example of the full description can be:<br> + * "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<CharSequence> 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. + * + * <p>This method first obtains a list of strings to be shown in order and then concatenates them + * with " • ". + * + * <p>Examples: + * + * <ul> + * <li>Mobile, Duo video • 10 min ago + * <li>Spam • Mobile • Now + * <li>Blocked • Spam • Mobile • Now + * </ul> + * + * @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. * * <p>Rules: * * <ul> - * <li>An emergency number: Date + * <li>An emergency number: [{Date}] * <li>Number - not blocked, call - not spam: - * <p>$Label(, Duo video|Carrier video)?|$Location • Date + * <p>[{$Label(, Duo video|Carrier video)?|$Location}, {Date}] * <li>Number - blocked, call - not spam: - * <p>Blocked • $Label(, Duo video|Carrier video)?|$Location • Date + * <p>["Blocked", {$Label(, Duo video|Carrier video)?|$Location}, {Date}] * <li>Number - not blocked, call - spam: - * <p>Spam • $Label(, Duo video|Carrier video)? • Date + * <p>["Spam", {$Label(, Duo video|Carrier video)?}, {Date}] * <li>Number - blocked, call - spam: - * <p>Blocked • Spam • $Label(, Duo video|Carrier video)? • Date + * <p>["Blocked, Spam", {$Label(, Duo video|Carrier video)?}, {Date}] * </ul> * * <p>Examples: * * <ul> - * <li>Mobile, Duo video • Now - * <li>Duo video • 10 min ago - * <li>Mobile • 11:45 PM - * <li>Mobile • Sun - * <li>Blocked • Mobile, Duo video • Now - * <li>Blocked • Brooklyn, NJ • 10 min ago - * <li>Spam • Mobile • Now - * <li>Spam • Now - * <li>Blocked • Spam • Mobile • Now - * <li>Brooklyn, NJ • Jan 15 + * <li>["Mobile, Duo video", "Now"] + * <li>["Duo video", "10 min ago"] + * <li>["Mobile", "11:45 PM"] + * <li>["Mobile", "Sun"] + * <li>["Blocked", "Mobile, Duo video", "Now"] + * <li>["Blocked", "Brooklyn, NJ", "10 min ago"] + * <li>["Spam", "Mobile", "Now"] + * <li>["Spam", "Now"] + * <li>["Blocked", "Spam", "Mobile", "Now"] + * <li>["Brooklyn, NJ", "Jan 15"] * </ul> * - * <p>See {@link CallLogDates#newCallLogTimestampLabel(Context, long, long)} for date rules. + * <p>See {@link CallLogDates#newCallLogTimestampLabel(Context, long, long, boolean)} for date + * rules. */ - public static CharSequence buildSecondaryTextForEntries( - Context context, Clock clock, CoalescedRow row) { + static List<CharSequence> 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<CharSequence> 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 @@ <!-- String used to display calls from spam numbers in the call log. [CHAR LIMIT=30] --> <string name="new_call_log_secondary_spam">Spam</string> + + <!-- + String introducing to a11y users a call log entry in which the latest call is a missed call. + [CHAR LIMIT=NONE] + --> + <plurals name="a11y_new_call_log_entry_missed_call"> + <item quantity="one"><xliff:g example="1" id="count">%1$d</xliff:g> missed call from <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + <item quantity="other"><xliff:g example="2" id="count">%1$d</xliff:g> calls, the latest is a missed call from <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + </plurals> + + <!-- + String introducing to a11y users a call log entry in which the latest call is an answered call. + [CHAR LIMIT=NONE] + --> + <plurals name="a11y_new_call_log_entry_answered_call"> + <item quantity="one"><xliff:g example="1" id="count">%1$d</xliff:g> answered call from <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + <item quantity="other"><xliff:g example="2" id="count">%1$d</xliff:g> calls, the latest is an answered call from <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + </plurals> + + <!-- + String introducing to a11y users a call log entry in which the latest call is an outgoing call. + [CHAR LIMIT=NONE] + --> + <plurals name="a11y_new_call_log_entry_outgoing_call"> + <item quantity="one"><xliff:g example="1" id="count">%1$d</xliff:g> outgoing call to <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + <item quantity="other"><xliff:g example="2" id="count">%1$d</xliff:g> calls, the latest is an outgoing call to <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + </plurals> + + <!-- + String introducing to a11y users a call log entry in which the latest call is a blocked call. + [CHAR LIMIT=NONE] + --> + <plurals name="a11y_new_call_log_entry_blocked_call"> + <item quantity="one"><xliff:g example="1" id="count">%1$d</xliff:g> blocked call from <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + <item quantity="other"><xliff:g example="2" id="count">%1$d</xliff:g> calls, the latest is a blocked call from <xliff:g example="Jane Smith" id="primaryInfoForEntry">%2$s</xliff:g></item> + </plurals> + + + <!-- + String describing to a11y users the phone account used to make/receive the latest call in a call + log entry. + [CHAR LIMIT=NONE] + --> + <string name="a11y_new_call_log_entry_phone_account"> + on <xliff:g example="SIM 1" id="phoneAccount">%1$s</xliff:g>, + via <xliff:g example="(555) 555-5555" id="number">%2$s</xliff:g> + </string> + + <!-- + String template describing to a11y users a call log entry without phone account info. + [CHAR LIMIT=NONE] + --> + <string name="a11y_new_call_log_entry_full_description_without_phone_account_info"> + <xliff:g example="A missed call from Jane Smith" id="primaryDescriptionForEntry">%1$s</xliff:g>, <xliff:g example="mobile, 30 minutes ago" id="secondaryDescriptionForEntry">%2$s</xliff:g>. + </string> + + <!-- + String template describing to a11y users a call log entry with phone account info. + [CHAR LIMIT=NONE] + --> + <string name="a11y_new_call_log_entry_full_description_with_phone_account_info"> + <xliff:g example="A missed call from Jane Smith" id="primaryDescriptionForEntry">%1$s</xliff:g>, <xliff:g example="mobile, 30 minutes ago" id="secondaryDescriptionForEntry">%2$s</xliff:g>, <xliff:g example="on SIM 1, via (555) 555-5555">%3$s</xliff:g>. + </string> </resources> diff --git a/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java b/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java index 973f9b1a8..dd53dffc5 100644 --- a/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java +++ b/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java @@ -80,7 +80,10 @@ public class VoicemailEntryText { } secondaryText.append( CallLogDates.newCallLogTimestampLabel( - context, clock.currentTimeMillis(), voicemailEntry.getTimestamp())); + context, + clock.currentTimeMillis(), + voicemailEntry.getTimestamp(), + /* abbreviateDateTime = */ true)); long duration = voicemailEntry.getDuration(); if (duration >= 0) { |