Commit cb3f2522 authored by Sam Blitzstein's avatar Sam Blitzstein
Browse files

Polishing accessibility for date picker.

Bug: 8531032
Change-Id: Idff339300a8edcd353b4d8e37e8b218b7b99460b
parent 9884d4cd
......@@ -22,4 +22,5 @@
android:gravity="center"
android:includeFontPadding="false"
android:textColor="@color/white"
android:textSize="@dimen/date_picker_header_text_size" />
android:textSize="@dimen/date_picker_header_text_size"
android:importantForAccessibility="no" />
......@@ -24,7 +24,7 @@
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
<com.android.datetimepicker.AccessibleLinearLayout
android:id="@+id/date_picker_month_and_day"
android:layout_width="match_parent"
android:layout_height="wrap_content"
......@@ -55,9 +55,9 @@
android:includeFontPadding="false"
android:textColor="@color/date_picker_selector"
android:textSize="@dimen/selected_date_day_size" />
</LinearLayout>
</com.android.datetimepicker.AccessibleLinearLayout>
<TextView
<com.android.datetimepicker.AccessibleTextView
android:id="@+id/date_picker_year"
android:layout_width="match_parent"
android:layout_height="wrap_content"
......
......@@ -13,7 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
<com.android.datetimepicker.date.AccessibleDateAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/animator"
android:layout_width="@dimen/date_picker_component_width"
android:layout_height="@dimen/date_picker_view_animator_height"
......
......@@ -46,7 +46,7 @@
android:layout_marginLeft="@dimen/extra_time_label_margin"
android:layout_marginRight="@dimen/extra_time_label_margin"
android:layout_centerVertical="true" >
<com.android.datetimepicker.FakeButton
<com.android.datetimepicker.AccessibleTextView
android:id="@+id/hours"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -87,7 +87,7 @@
android:layout_marginLeft="@dimen/extra_time_label_margin"
android:layout_marginRight="@dimen/extra_time_label_margin"
android:layout_centerVertical="true" >
<com.android.datetimepicker.FakeButton
<com.android.datetimepicker.AccessibleTextView
android:id="@+id/minutes"
style="@style/time_label"
android:layout_width="wrap_content"
......@@ -96,8 +96,7 @@
android:text="@string/time_placeholder"
android:layout_gravity="center" />
</FrameLayout>
<com.android.datetimepicker.FakeButton
<com.android.datetimepicker.AccessibleTextView
android:id="@+id/ampm_hitspace"
android:layout_width="@dimen/ampm_label_size"
android:layout_height="wrap_content"
......
/*
* Copyright (C) 2013 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.datetimepicker;
import android.content.Context;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.LinearLayout;
/**
* Fake Button class, used so TextViews can announce themselves as Buttons, for accessibility.
*/
public class AccessibleLinearLayout extends LinearLayout {
public AccessibleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(Button.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Button.class.getName());
}
}
......@@ -26,9 +26,9 @@ import android.widget.TextView;
/**
* Fake Button class, used so TextViews can announce themselves as Buttons, for accessibility.
*/
public class FakeButton extends TextView {
public class AccessibleTextView extends TextView {
public FakeButton(Context context, AttributeSet attrs) {
public AccessibleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
......
......@@ -19,6 +19,7 @@ package com.android.datetimepicker;
import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
import android.os.Build;
import android.text.format.Time;
import android.view.View;
......@@ -39,6 +40,17 @@ public class Utils {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
/**
* Try to speak the specified text, for accessibility. Only available on JB or later.
* @param text Text to announce.
*/
@SuppressLint("NewApi")
public static void tryAccessibilityAnnounce(View view, CharSequence text) {
if (isJellybeanOrLater() && view != null && text != null) {
view.announceForAccessibility(text);
}
}
public static int getDaysInMonth(int month, int year) {
switch (month) {
case Calendar.JANUARY:
......
/*
* Copyright (C) 2013 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.datetimepicker.date;
import android.content.Context;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ViewAnimator;
public class AccessibleDateAnimator extends ViewAnimator {
private long mDateMillis;
public AccessibleDateAnimator(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setDateMillis(long dateMillis) {
mDateMillis = dateMillis;
}
/**
* Announce the currently-selected date when launched.
*/
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
// Clear the event's current text so that only the current date will be spoken.
event.getText().clear();
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_WEEKDAY;
String dateString = DateUtils.formatDateTime(getContext(), mDateMillis, flags);
event.getText().add(dateString);
return true;
}
return super.dispatchPopulateAccessibilityEvent(event);
}
}
\ No newline at end of file
......@@ -20,9 +20,14 @@ import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.DialogFragment;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.Vibrator;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
......@@ -30,6 +35,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
......@@ -82,7 +88,7 @@ public class DatePickerDialog extends DialogFragment implements
private OnDateSetListener mCallBack;
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
private ViewAnimator mAnimator;
private AccessibleDateAnimator mAnimator;
private TextView mDayOfWeekView;
private LinearLayout mMonthAndDayView;
......@@ -104,6 +110,12 @@ public class DatePickerDialog extends DialogFragment implements
private boolean mDelayAnimation = true;
// Accessibility strings.
private String mDayPickerDescription;
private String mSelectDay;
private String mYearPickerDescription;
private String mSelectYear;
/**
* The callback used to indicate the user is done filling in the date.
*/
......@@ -219,9 +231,16 @@ public class DatePickerDialog extends DialogFragment implements
mDayPickerView = new DayPickerView(activity, this);
mYearPickerView = new YearPickerView(activity, this);
mAnimator = (ViewAnimator) view.findViewById(R.id.animator);
Resources res = getResources();
mDayPickerDescription = res.getString(R.string.day_picker_description);
mSelectDay = res.getString(R.string.select_day);
mYearPickerDescription = res.getString(R.string.year_picker_description);
mSelectYear = res.getString(R.string.select_year);
mAnimator = (AccessibleDateAnimator) view.findViewById(R.id.animator);
mAnimator.addView(mDayPickerView);
mAnimator.addView(mYearPickerView);
mAnimator.setDateMillis(mCalendar.getTimeInMillis());
// TODO: Replace with animation decided upon by the design team.
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(ANIMATION_DURATION);
......@@ -245,7 +264,7 @@ public class DatePickerDialog extends DialogFragment implements
}
});
updateDisplay();
updateDisplay(false);
setCurrentView(currentView);
if (listPosition != -1) {
......@@ -259,6 +278,8 @@ public class DatePickerDialog extends DialogFragment implements
}
private void setCurrentView(final int viewIndex) {
long millis = mCalendar.getTimeInMillis();
switch (viewIndex) {
case MONTH_AND_DAY_VIEW:
ObjectAnimator pulseAnimator = Utils.getPulseAnimator(mMonthAndDayView, 0.9f,
......@@ -275,6 +296,11 @@ public class DatePickerDialog extends DialogFragment implements
mCurrentView = viewIndex;
}
pulseAnimator.start();
int flags = DateUtils.FORMAT_SHOW_DATE;
String dayString = DateUtils.formatDateTime(getActivity(), millis, flags);
mAnimator.setContentDescription(mDayPickerDescription+": "+dayString);
Utils.tryAccessibilityAnnounce(mAnimator, mSelectDay);
break;
case YEAR_VIEW:
pulseAnimator = Utils.getPulseAnimator(mYearView, 0.85f, 1.1f);
......@@ -290,19 +316,37 @@ public class DatePickerDialog extends DialogFragment implements
mCurrentView = viewIndex;
}
pulseAnimator.start();
CharSequence yearString = YEAR_FORMAT.format(millis);
mAnimator.setContentDescription(mYearPickerDescription+": "+yearString);
Utils.tryAccessibilityAnnounce(mAnimator, mSelectYear);
break;
}
}
private void updateDisplay() {
private void updateDisplay(boolean announce) {
if (mDayOfWeekView != null) {
mDayOfWeekView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,
Locale.getDefault()).toUpperCase(Locale.getDefault()));
}
mSelectedMonthTextView.setText(mCalendar.getDisplayName(Calendar.MONTH, Calendar.SHORT,
Locale.getDefault()).toUpperCase(Locale.getDefault()));
mSelectedDayTextView.setText(DAY_FORMAT.format(mCalendar.getTime()));
mYearView.setText(YEAR_FORMAT.format(mCalendar.getTime()));
// Accessibility.
long millis = mCalendar.getTimeInMillis();
mAnimator.setDateMillis(millis);
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR;
String monthAndDayText = DateUtils.formatDateTime(getActivity(), millis, flags);
mMonthAndDayView.setContentDescription(monthAndDayText);
if (announce) {
flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
String fullDateText = DateUtils.formatDateTime(getActivity(), millis, flags);
Utils.tryAccessibilityAnnounce(mAnimator, fullDateText);
}
}
public void setFirstDayOfWeek(int startOfWeek) {
......@@ -359,7 +403,7 @@ public class DatePickerDialog extends DialogFragment implements
mCalendar.set(Calendar.YEAR, year);
updatePickers();
setCurrentView(MONTH_AND_DAY_VIEW);
updateDisplay();
updateDisplay(true);
}
@Override
......@@ -368,7 +412,7 @@ public class DatePickerDialog extends DialogFragment implements
mCalendar.set(Calendar.MONTH, month);
mCalendar.set(Calendar.DAY_OF_MONTH, day);
updatePickers();
updateDisplay();
updateDisplay(true);
}
private void updatePickers() {
......
......@@ -16,18 +16,27 @@
package com.android.datetimepicker.date;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import com.android.datetimepicker.Utils;
import com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener;
import com.android.datetimepicker.date.SimpleMonthAdapter.CalendarDay;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
/**
* This displays a list of months in a calendar format with selectable days.
*/
......@@ -50,6 +59,7 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
protected int mNumWeeks = 6;
protected boolean mShowWeekNumber = false;
protected int mDaysPerWeek = 7;
private static SimpleDateFormat YEAR_FORMAT = new SimpleDateFormat("yyyy", Locale.getDefault());
// These affect the scroll speed and feel
protected float mFriction = 1.0f;
......@@ -78,6 +88,7 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
protected int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE;
private final DatePickerController mController;
private boolean mPerformingScroll;
public DayPickerView(Context context, DatePickerController controller) {
super(context);
......@@ -162,7 +173,6 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
mTempDay.set(day);
final int position = (day.year - mController.getMinYear())
* SimpleMonthAdapter.MONTHS_IN_YEAR + day.month;
Log.d(TAG, "Year: " + day.year);
View child;
int i = 0;
......@@ -400,6 +410,84 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
protected void layoutChildren() {
final CalendarDay focusedDay = findAccessibilityFocus();
super.layoutChildren();
restoreAccessibilityFocus(focusedDay);
if (mPerformingScroll) {
mPerformingScroll = false;
} else {
restoreAccessibilityFocus(focusedDay);
}
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setItemCount(-1);
}
private String getMonthAndYearString(CalendarDay day) {
Calendar cal = Calendar.getInstance();
cal.set(day.year, day.month, day.day);
StringBuffer sbuf = new StringBuffer();
sbuf.append(cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
sbuf.append(" ");
sbuf.append(YEAR_FORMAT.format(cal.getTime()));
return sbuf.toString();
}
/**
* Necessary for accessibility, to ensure we support "scrolling" forward and backward
* in the month list.
*/
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
/**
* When scroll forward/backward events are received, announce the newly scrolled-to month.
*/
@SuppressLint("NewApi")
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (action != AccessibilityNodeInfo.ACTION_SCROLL_FORWARD &&
action != AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
return super.performAccessibilityAction(action, arguments);
}
// Figure out what month is showing.
int firstVisiblePosition = getFirstVisiblePosition();
int month = firstVisiblePosition % 12;
int year = firstVisiblePosition / 12 + mController.getMinYear();
CalendarDay day = new CalendarDay(year, month, 1);
// Scroll either forward or backward one month.
if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) {
day.month++;
if (day.month == 12) {
day.month = 0;
day.year++;
}
} else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
View firstVisibleView = getChildAt(0);
// If the view is fully visible, jump one month back. Otherwise, we'll just jump
// to the first day of first visible month.
if (firstVisibleView != null && firstVisibleView.getTop() >= -1) {
// There's an off-by-one somewhere, so the top of the first visible item will
// actually be -1 when it's at the exact top.
day.month--;
if (day.month == -1) {
day.month = 11;
day.year--;
}
}
}
// Go to that month.
Utils.tryAccessibilityAnnounce(this, getMonthAndYearString(day));
goTo(day, true, false, true);
mPerformingScroll = true;
return true;
}
}
......@@ -16,6 +16,7 @@
package com.android.datetimepicker.date;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import android.view.View;
......@@ -24,6 +25,7 @@ import android.widget.AbsListView.LayoutParams;
import android.widget.BaseAdapter;
import com.android.datetimepicker.date.SimpleMonthView.OnDayClickListener;
import com.android.datetimepicker.R;
import java.util.Calendar;
import java.util.HashMap;
......@@ -104,7 +106,7 @@ public class SimpleMonthAdapter extends BaseAdapter implements OnDayClickListene
/**
* Updates the selected day and related parameters.
*
* @param selectedTime The time to highlight
* @param day The day to highlight
*/
public void setSelectedDay(CalendarDay day) {
mSelectedDay = day;
......@@ -137,6 +139,7 @@ public class SimpleMonthAdapter extends BaseAdapter implements OnDayClickListene
return position;
}
@SuppressLint("NewApi")
@SuppressWarnings("unchecked")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
......@@ -186,6 +189,7 @@ public class SimpleMonthAdapter extends BaseAdapter implements OnDayClickListene
return mSelectedDay.year == year && mSelectedDay.month == month;
}
@Override
public void onDayClick(SimpleMonthView view, CalendarDay day) {
if (day != null) {
......
......@@ -27,6 +27,7 @@ import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.SparseArray;
......@@ -52,6 +53,7 @@ import java.util.Locale;
* within the specified month.
*/
public class SimpleMonthView extends View {
private static final String TAG = "SimpleMonthView";
/**
* These params can be passed into the view to control how it appears.
......@@ -404,17 +406,19 @@ public class SimpleMonthView extends View {
mNodeProvider.invalidateParent();
}
private void drawMonthTitle(Canvas canvas) {
int x = (mWidth + 2 * mPadding) / 2;
int y = (MONTH_HEADER_SIZE - MONTH_DAY_LABEL_TEXT_SIZE) / 2 + (MONTH_LABEL_TEXT_SIZE / 3);
private String getMonthAndYearString() {
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
| DateUtils.FORMAT_NO_MONTH_DAY;
mStringBuilder.setLength(0);
long millis = mCalendar.getTimeInMillis();
String title = DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags,
return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags,
Time.getCurrentTimezone()).toString();
canvas.drawText(title, x, y, mMonthTitlePaint);
}
private void drawMonthTitle(Canvas canvas) {
int x = (mWidth + 2 * mPadding) / 2;
int y = (MONTH_HEADER_SIZE - MONTH_DAY_LABEL_TEXT_SIZE) / 2 + (MONTH_LABEL_TEXT_SIZE / 3);
canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
}
private void drawMonthDayLabels(Canvas canvas) {
......@@ -455,7 +459,6 @@ public class SimpleMonthView extends View {
mMonthNumPaint.setColor(mDayTextColor);
}
canvas.drawText(String.format("%d", dayNumber), x, y, mMonthNumPaint);
j++;
if (j == mNumDays) {
j = 0;
......@@ -550,6 +553,8 @@ public class SimpleMonthView extends View {
private final SparseArray<CalendarDay> mCachedItems = new SparseArray<CalendarDay>();
private final Rect mTempRect = new Rect();
Calendar recycle;
public MonthViewNodeProvider(Context context, View parent) {
super(context, parent);
}
......@@ -659,19 +664,17 @@ public class SimpleMonthView extends View {
* @return A description of the time object
*/
private CharSequence getItemDescription(CalendarDay item) {
final StringBuffer sbuf = new StringBuffer();
sbuf.append(String.format("%d", item.day));
sbuf.append(" ");
sbuf.append(mCalendar.getDisplayName(Calendar.MONTH, Calendar.LONG,
Locale.getDefault()));
sbuf.append(" ");
sbuf.append(String.format("%d", mYear));
if (recycle == null) {
recycle = Calendar.getInstance();
}
recycle.set(item.year, item.month, item.day);
CharSequence date = DateFormat.format("dd MMMM yyyy", recycle.getTimeInMillis());
if (item.day == mSelectedDay) {
return getContext().getString(R.string.item_is_selected, sbuf);
return getContext().getString(R.string.item_is_selected, date);
}
return sbuf;
return date;
}
}
......
......@@ -22,7 +22,9 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
import com.android.datetimepicker.R;
......@@ -38,6 +40,8 @@ public class TextViewWithCircularIndicator extends TextView {
private final int mRadius;
private final int mCircleColor;
private final String mItemIsSelectedText;
private boolean mDrawCircle;
public TextViewWithCircularIndicator(Context context, AttributeSet attrs) {
......@@ -45,6 +49,8 @@ public class TextViewWithCircularIndicator extends TextView {
Resources res = context.getResources();
mCircleColor = res.getColor(R.color.blue);
mRadius = res.getDimensionPixelOffset(R.dimen.month_select_circle_radius);
mItemIsSelectedText = context.getResources().getString(R.string.item_is_selected);
init();
}
......@@ -71,4 +77,14 @@ public class TextViewWithCircularIndicator extends TextView {
canvas.drawCircle(width / 2, height / 2, radius, mCirclePaint);
}
}
@Override
public CharSequence getContentDescription() {
CharSequence itemText = getText();
if (mDrawCircle) {
return String.format(mItemIsSelectedText, itemText);
} else {
return itemText;
}
}
}
......@@ -19,8 +19,10 @@ package com.android.datetimepicker.date;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.StateListDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
......@@ -28,6 +30,7 @@ import android.widget.ListView;
import android.widget.TextView;
import com.android.datetimepicker.R;
import com.android.datetimepicker.Utils;
import com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener;
import java.util.ArrayList;
......@@ -37,6 +40,7 @@ import java.util.List;
* Displays a selectable list of years.
*/
public class YearPickerView extends ListView implements OnItemClickListener, OnDateChangedListener {
private static final String TAG = "YearPickerView";
private final DatePickerController mController;
private YearAdapter mAdapter;
......@@ -147,4 +151,13 @@ public class YearPickerView extends ListView implements OnItemClickListener, OnD
mAdapter.notifyDataSetChanged();
postSetSelectionCentered(mController.getSelectedDay().year - mController.getMinYear());
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
event.setFromIndex(0);
event.setToIndex(0);
}
}
}
......@@ -17,7 +17,6 @@
package com.android.datetimepicker.time;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.ActionBar.LayoutParams;
import android.app.DialogFragment;
import android.content.Context;
......@@ -293,11 +292,11 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL
private void updateAmPmDisplay(int amOrPm) {
if (amOrPm == AM) {
mAmPmTextView.setText(mAmText);
tryAccessibilityAnnounce(mAmText);
Utils.tryAccessibilityAnnounce(mTimePicker, mAmText);
mAmPmHitspace.setContentDescription(mAmText);
} else if (amOrPm == PM){
mAmPmTextView.setText(mPmText);
tryAccessibilityAnnounce(mPmText);
Utils.tryAccessibilityAnnounce(mTimePicker, mPmText);
mAmPmHitspace.setContentDescription(mPmText);
} else {
mAmPmTextView.setText(mDoublePlaceholderText);
......@@ -330,7 +329,7 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL
setCurrentItemShowing(MINUTE_INDEX, true, true, false);
announcement += ". " + mSelectMinutes;
}
tryAccessibilityAnnounce(announcement);
Utils.tryAccessibilityAnnounce(mTimePicker, announcement);
} else if (pickerIndex == MINUTE_INDEX){
setMinute(newValue);
} else if (pickerIndex == AMPM_INDEX) {
......@@ -359,7 +358,7 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL
mHourView.setText(text);
mHourSpaceView.setText(text);
if (announce) {
tryAccessibilityAnnounce(text);
Utils.tryAccessibilityAnnounce(mTimePicker, text);
}
}
......@@ -368,7 +367,7 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL
value = 0;
}
CharSequence text = String.format(Locale.getDefault(), "%02d", value);
tryAccessibilityAnnounce(text);
Utils.tryAccessibilityAnnounce(mTimePicker, text);
mMinuteView.setText(text);
mMinuteSpaceView.setText(text);
}
......@@ -386,14 +385,14 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL
}
mTimePicker.setContentDescription(mHourPickerDescription+": "+hours);
if (announce) {
tryAccessibilityAnnounce(mSelectHours);
Utils.tryAccessibilityAnnounce(mTimePicker, mSelectHours);
}
labelToAnimate = mHourView;
} else {
int minutes = mTimePicker.getMinutes();
mTimePicker.setContentDescription(mMinutePickerDescription+": "+minutes);
if (announce) {
tryAccessibilityAnnounce(mSelectMinutes);
Utils.tryAccessibilityAnnounce(mTimePicker, mSelectMinutes);
}
labelToAnimate = mMinuteView;
}
......@@ -410,17 +409,6 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL
pulseAnimator.start();
}
/**
* Try to speak the specified text, for accessibility. Only available on JB or later.
* @param text
*/
@SuppressLint("NewApi")
private void tryAccessibilityAnnounce(CharSequence text) {
if (Utils.isJellybeanOrLater() && mTimePicker != null && text != null) {
mTimePicker.announceForAccessibility(text);
}
}
/**
* For keyboard mode, processes key events.
* @param keyCode the pressed key.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment