diff options
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/datetimepicker/AccessibleLinearLayout.java | 46 | ||||
-rw-r--r-- | src/com/android/datetimepicker/AccessibleTextView.java (renamed from src/com/android/datetimepicker/FakeButton.java) | 4 | ||||
-rw-r--r-- | src/com/android/datetimepicker/Utils.java | 12 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/AccessibleDateAnimator.java | 53 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/DatePickerDialog.java | 56 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/DayPickerView.java | 92 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/SimpleMonthAdapter.java | 6 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/SimpleMonthView.java | 35 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/TextViewWithCircularIndicator.java | 16 | ||||
-rw-r--r-- | src/com/android/datetimepicker/date/YearPickerView.java | 13 | ||||
-rw-r--r-- | src/com/android/datetimepicker/time/TimePickerDialog.java | 26 |
11 files changed, 313 insertions, 46 deletions
diff --git a/src/com/android/datetimepicker/AccessibleLinearLayout.java b/src/com/android/datetimepicker/AccessibleLinearLayout.java new file mode 100644 index 0000000..629f856 --- /dev/null +++ b/src/com/android/datetimepicker/AccessibleLinearLayout.java @@ -0,0 +1,46 @@ +/* + * 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()); + } +} diff --git a/src/com/android/datetimepicker/FakeButton.java b/src/com/android/datetimepicker/AccessibleTextView.java index 6ab1b61..98fa744 100644 --- a/src/com/android/datetimepicker/FakeButton.java +++ b/src/com/android/datetimepicker/AccessibleTextView.java @@ -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); } diff --git a/src/com/android/datetimepicker/Utils.java b/src/com/android/datetimepicker/Utils.java index 83590bf..ac603bc 100644 --- a/src/com/android/datetimepicker/Utils.java +++ b/src/com/android/datetimepicker/Utils.java @@ -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: diff --git a/src/com/android/datetimepicker/date/AccessibleDateAnimator.java b/src/com/android/datetimepicker/date/AccessibleDateAnimator.java new file mode 100644 index 0000000..fc022cd --- /dev/null +++ b/src/com/android/datetimepicker/date/AccessibleDateAnimator.java @@ -0,0 +1,53 @@ +/* + * 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 diff --git a/src/com/android/datetimepicker/date/DatePickerDialog.java b/src/com/android/datetimepicker/date/DatePickerDialog.java index 8954c35..84ef2f3 100644 --- a/src/com/android/datetimepicker/date/DatePickerDialog.java +++ b/src/com/android/datetimepicker/date/DatePickerDialog.java @@ -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() { diff --git a/src/com/android/datetimepicker/date/DayPickerView.java b/src/com/android/datetimepicker/date/DayPickerView.java index fcd1d8c..5a49e42 100644 --- a/src/com/android/datetimepicker/date/DayPickerView.java +++ b/src/com/android/datetimepicker/date/DayPickerView.java @@ -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; } } diff --git a/src/com/android/datetimepicker/date/SimpleMonthAdapter.java b/src/com/android/datetimepicker/date/SimpleMonthAdapter.java index 84be210..10a815a 100644 --- a/src/com/android/datetimepicker/date/SimpleMonthAdapter.java +++ b/src/com/android/datetimepicker/date/SimpleMonthAdapter.java @@ -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) { diff --git a/src/com/android/datetimepicker/date/SimpleMonthView.java b/src/com/android/datetimepicker/date/SimpleMonthView.java index bcb592f..832bdfb 100644 --- a/src/com/android/datetimepicker/date/SimpleMonthView.java +++ b/src/com/android/datetimepicker/date/SimpleMonthView.java @@ -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; } } diff --git a/src/com/android/datetimepicker/date/TextViewWithCircularIndicator.java b/src/com/android/datetimepicker/date/TextViewWithCircularIndicator.java index 66140f5..09a0a4b 100644 --- a/src/com/android/datetimepicker/date/TextViewWithCircularIndicator.java +++ b/src/com/android/datetimepicker/date/TextViewWithCircularIndicator.java @@ -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; + } + } } diff --git a/src/com/android/datetimepicker/date/YearPickerView.java b/src/com/android/datetimepicker/date/YearPickerView.java index 411c574..70d2522 100644 --- a/src/com/android/datetimepicker/date/YearPickerView.java +++ b/src/com/android/datetimepicker/date/YearPickerView.java @@ -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); + } + } } diff --git a/src/com/android/datetimepicker/time/TimePickerDialog.java b/src/com/android/datetimepicker/time/TimePickerDialog.java index 27742a2..2a385f7 100644 --- a/src/com/android/datetimepicker/time/TimePickerDialog.java +++ b/src/com/android/datetimepicker/time/TimePickerDialog.java @@ -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; } @@ -411,17 +410,6 @@ public class TimePickerDialog extends DialogFragment implements OnValueSelectedL } /** - * 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. * @return true if the key was successfully processed, false otherwise. |