Skip to content

Commit c6539f2

Browse files
committed
[MaterialDatePicker][a11y] Announce current year and day
PiperOrigin-RevId: 479303709
1 parent 9897bc2 commit c6539f2

File tree

5 files changed

+86
-11
lines changed

5 files changed

+86
-11
lines changed

lib/java/com/google/android/material/datepicker/DateStrings.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package com.google.android.material.datepicker;
1717

18+
import com.google.android.material.R;
19+
20+
import android.content.Context;
1821
import android.icu.text.DateFormat;
1922
import android.os.Build.VERSION;
2023
import android.os.Build.VERSION_CODES;
@@ -198,4 +201,37 @@ static Pair<String, String> getDateRangeString(
198201
return Pair.create(
199202
getYearMonthDay(start, Locale.getDefault()), getYearMonthDay(end, Locale.getDefault()));
200203
}
204+
205+
/**
206+
* Returns the day content description.
207+
*
208+
* @param context the {@link Context}
209+
* @param dayInMillis UTC milliseconds representing the first moment of the day in local timezone
210+
* @param isToday boolean representing if the day is today
211+
* @return Day content description string
212+
*/
213+
static String getDayContentDescription(Context context, long dayInMillis, boolean isToday) {
214+
String dayContentDescription = getOptionalYearMonthDayOfWeekDay(dayInMillis);
215+
if (isToday) {
216+
return String.format(
217+
context.getString(R.string.mtrl_picker_today_description), dayContentDescription);
218+
}
219+
return dayContentDescription;
220+
}
221+
222+
/**
223+
* Returns the year content description.
224+
*
225+
* @param context the {@link Context}
226+
* @param year the year, example: 2020
227+
* @return Year content description string
228+
*/
229+
static String getYearContentDescription(Context context, int year) {
230+
if (UtcDates.getTodayCalendar().get(Calendar.YEAR) == year) {
231+
return String.format(
232+
context.getString(R.string.mtrl_picker_navigate_to_current_year_description), year);
233+
}
234+
return String.format(
235+
context.getString(R.string.mtrl_picker_navigate_to_year_description), year);
236+
}
201237
}

lib/java/com/google/android/material/datepicker/MonthAdapter.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ public TextView getView(int position, @Nullable View convertView, @NonNull ViewG
138138
Locale locale = dayTextView.getResources().getConfiguration().locale;
139139
dayTextView.setText(String.format(locale, "%d", dayNumber));
140140
long dayInMillis = month.getDay(dayNumber);
141-
dayTextView.setContentDescription(DateStrings.getOptionalYearMonthDayOfWeekDay(dayInMillis));
141+
dayTextView.setContentDescription(
142+
DateStrings.getDayContentDescription(
143+
dayTextView.getContext(), dayInMillis, isToday(dayInMillis)));
142144
dayTextView.setVisibility(View.VISIBLE);
143145
dayTextView.setEnabled(true);
144146
}
@@ -187,13 +189,14 @@ private void updateSelectedState(@Nullable TextView dayTextView, long date, int
187189
final CalendarItemStyle style;
188190
boolean valid = calendarConstraints.getDateValidator().isValid(date);
189191
boolean selected = false;
192+
boolean isToday = isToday(date);
190193
if (valid) {
191194
dayTextView.setEnabled(true);
192195
selected = isSelected(date);
193196
dayTextView.setSelected(selected);
194197
if (selected) {
195198
style = calendarStyle.selectedDay;
196-
} else if (UtcDates.getTodayCalendar().getTimeInMillis() == date) {
199+
} else if (isToday) {
197200
style = calendarStyle.todayDay;
198201
} else {
199202
style = calendarStyle.day;
@@ -234,13 +237,17 @@ private void updateSelectedState(@Nullable TextView dayTextView, long date, int
234237
dayNumber,
235238
valid,
236239
selected,
237-
DateStrings.getOptionalYearMonthDayOfWeekDay(dayInMillis));
240+
DateStrings.getDayContentDescription(context, dayInMillis, isToday));
238241
dayTextView.setContentDescription(decoratorContentDescription);
239242
} else {
240243
style.styleItem(dayTextView);
241244
}
242245
}
243246

247+
private boolean isToday(long date) {
248+
return UtcDates.getTodayCalendar().getTimeInMillis() == date;
249+
}
250+
244251
private boolean isSelected(long date) {
245252
for (long selectedDay : dateSelector.getSelectedDays()) {
246253
if (UtcDates.canonicalYearMonthDay(date) == UtcDates.canonicalYearMonthDay(selectedDay)) {

lib/java/com/google/android/material/datepicker/YearGridAdapter.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,9 @@ public YearGridAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGrou
5959
@Override
6060
public void onBindViewHolder(@NonNull YearGridAdapter.ViewHolder viewHolder, int position) {
6161
int year = getYearForPosition(position);
62-
String navigateYear =
63-
viewHolder
64-
.textView
65-
.getContext()
66-
.getString(R.string.mtrl_picker_navigate_to_year_description);
6762
viewHolder.textView.setText(String.format(Locale.getDefault(), "%d", year));
68-
viewHolder.textView.setContentDescription(String.format(navigateYear, year));
63+
viewHolder.textView.setContentDescription(
64+
DateStrings.getYearContentDescription(viewHolder.textView.getContext(), year));
6965
CalendarStyle styles = materialCalendar.getCalendarStyle();
7066
Calendar calendar = UtcDates.getTodayCalendar();
7167
CalendarItemStyle style = calendar.get(Calendar.YEAR) == year ? styles.todayYear : styles.year;

lib/java/com/google/android/material/datepicker/res/values/strings.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
<string name="mtrl_picker_toggle_to_day_selection" description="a11y string to indicate this button switches the user to choosing a day [CHAR_LIMIT=NONE]">Tap to switch to Calendar view</string>
4949
<string name="mtrl_picker_day_of_week_column_header" description="a11y string to indicate this is a header for a column of days for one day of the week (e.g., Monday) [CHAR_LIMIT=NONE]">Column of days: %1$s</string>
5050
<string name="mtrl_picker_announce_current_selection" description="a11y string read on selection change to indicate the new selection [CHAR_LIMIT=NONE]">Current selection: %1$s</string>
51-
<string name="mtrl_picker_navigate_to_year_description" description="a11y string that informs the user that tapping this button will switch the year [CHAR_LIMIT=NONE]">Navigate to year %1$s</string>
51+
<string name="mtrl_picker_navigate_to_year_description" description="a11y string that informs the user that tapping this button will switch the year [CHAR_LIMIT=NONE]">Navigate to year %1$d</string>
52+
<string name="mtrl_picker_navigate_to_current_year_description" description="a11y string that informs the user that tapping this button will switch the current year [CHAR_LIMIT=NONE]">Navigate to current year %1$d</string>
53+
<string name="mtrl_picker_today_description" description="a11y string that informs the user that the focused day is today [CHAR_LIMIT=NONE]">Today %1$s</string>
5254

5355
</resources>

lib/javatests/com/google/android/material/datepicker/DateStringsTest.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
*/
1616
package com.google.android.material.datepicker;
1717

18+
import static org.hamcrest.MatcherAssert.assertThat;
1819
import static org.hamcrest.core.Is.is;
19-
import static org.junit.Assert.assertThat;
2020

2121
import android.os.Build.VERSION_CODES;
2222
import androidx.core.util.Pair;
23+
import androidx.test.core.app.ApplicationProvider;
2324
import java.text.SimpleDateFormat;
2425
import java.util.Calendar;
2526
import java.util.Locale;
@@ -297,4 +298,37 @@ public void getDateRangeStringMultipleYearsWithUserDefinedDateFormat() {
297298
assertThat(dateRangeString.first, is("May 30"));
298299
assertThat(dateRangeString.second, is("Dec 05"));
299300
}
301+
302+
@Test
303+
public void getDayContentDescription_notToday() {
304+
startDate = setupLocalizedCalendar(Locale.US, 2020, 10, 30);
305+
String contentDescription =
306+
DateStrings.getDayContentDescription(
307+
ApplicationProvider.getApplicationContext(), startDate.getTimeInMillis(), false);
308+
assertThat(contentDescription, is("Mon, Nov 30, 2020"));
309+
}
310+
311+
@Test
312+
public void getDayContentDescription_today() {
313+
startDate = setupLocalizedCalendar(Locale.US, 2020, 10, 30);
314+
String contentDescription =
315+
DateStrings.getDayContentDescription(
316+
ApplicationProvider.getApplicationContext(), startDate.getTimeInMillis(), true);
317+
assertThat(contentDescription, is("Today Mon, Nov 30, 2020"));
318+
}
319+
320+
@Test
321+
public void getYearContentDescription_notCurrent() {
322+
String contentDescription =
323+
DateStrings.getYearContentDescription(ApplicationProvider.getApplicationContext(), 2020);
324+
assertThat(contentDescription, is("Navigate to year 2020"));
325+
}
326+
327+
@Test
328+
public void getYearContentDescription_current() {
329+
String contentDescription =
330+
DateStrings.getYearContentDescription(
331+
ApplicationProvider.getApplicationContext(), CURRENT_YEAR);
332+
assertThat(contentDescription, is("Navigate to current year " + CURRENT_YEAR));
333+
}
300334
}

0 commit comments

Comments
 (0)