Loading core/java/android/widget/DatePickerCalendarDelegate.java +16 −2 Original line number Diff line number Diff line Loading @@ -171,7 +171,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { // Set up year picker view. mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker); mYearPickerView.setRange(mMinDate, mMaxDate); mYearPickerView.setDate(mCurrentDate.getTimeInMillis()); mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR)); mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener); // Set up content descriptions. Loading Loading @@ -267,6 +267,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { // Automatically switch to day picker. setCurrentView(VIEW_MONTH_DAY); // Switch focus back to the year text. mHeaderYear.requestFocus(); } }; Loading Loading @@ -344,7 +347,18 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { mAnimator.announceForAccessibility(mSelectDay); break; case VIEW_YEAR: mYearPickerView.setDate(mCurrentDate.getTimeInMillis()); final int year = mCurrentDate.get(Calendar.YEAR); mYearPickerView.setYear(year); mYearPickerView.post(new Runnable() { @Override public void run() { mYearPickerView.requestFocus(); final View selected = mYearPickerView.getSelectedView(); if (selected != null) { selected.requestFocus(); } } }); if (mCurrentView != viewIndex) { mHeaderMonthDay.setActivated(false); Loading core/java/android/widget/DayPickerPagerAdapter.java +8 −0 Original line number Diff line number Diff line Loading @@ -287,6 +287,14 @@ class DayPickerPagerAdapter extends PagerAdapter { return null; } SimpleMonthView getView(Object object) { if (object == null) { return null; } final ViewHolder holder = (ViewHolder) object; return holder.calendar; } private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { @Override public void onDayClick(SimpleMonthView view, Calendar day) { Loading core/java/android/widget/DayPickerViewPager.java +41 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package android.widget; import com.android.internal.widget.ViewPager; import android.annotation.Nullable; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import com.android.internal.util.Predicate; import com.android.internal.widget.PagerAdapter; import com.android.internal.widget.ViewPager; import java.util.ArrayList; Loading Loading @@ -134,4 +140,37 @@ class DayPickerViewPager extends ViewPager { mMatchParentChildren.clear(); } @Override protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { if (predicate.apply(this)) { return this; } // Always try the selected view first. final DayPickerPagerAdapter adapter = (DayPickerPagerAdapter) getAdapter(); final SimpleMonthView current = adapter.getView(getCurrent()); if (current != childToSkip && current != null) { final View v = current.findViewByPredicate(predicate); if (v != null) { return v; } } final int len = getChildCount(); for (int i = 0; i < len; i++) { final View child = getChildAt(i); if (child != childToSkip && child != current) { final View v = child.findViewByPredicate(predicate); if (v != null) { return v; } } } return null; } } core/java/android/widget/SimpleMonthView.java +247 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.widget; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; Loading @@ -34,8 +35,10 @@ import android.util.AttributeSet; import android.util.IntArray; import android.util.MathUtils; import android.util.StateSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; Loading @@ -61,11 +64,14 @@ class SimpleMonthView extends View { private static final String DEFAULT_TITLE_FORMAT = "MMMMy"; private static final String DAY_OF_WEEK_FORMAT = "EEEEE"; private static final int SELECTED_HIGHLIGHT_ALPHA = 0xB0; private final TextPaint mMonthPaint = new TextPaint(); private final TextPaint mDayOfWeekPaint = new TextPaint(); private final TextPaint mDayPaint = new TextPaint(); private final Paint mDaySelectorPaint = new Paint(); private final Paint mDayHighlightPaint = new Paint(); private final Paint mDayHighlightSelectorPaint = new Paint(); private final Calendar mCalendar = Calendar.getInstance(); private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance(); Loading Loading @@ -130,7 +136,9 @@ class SimpleMonthView extends View { private ColorStateList mDayTextColor; private int mTouchedItem = -1; private int mHighlightedDay = -1; private int mPreviouslyHighlightedDay = -1; private boolean mIsTouchHighlighted = false; public SimpleMonthView(Context context) { this(context, null); Loading Loading @@ -268,6 +276,9 @@ class SimpleMonthView extends View { mDayHighlightPaint.setAntiAlias(true); mDayHighlightPaint.setStyle(Style.FILL); mDayHighlightSelectorPaint.setAntiAlias(true); mDayHighlightSelectorPaint.setStyle(Style.FILL); mDayPaint.setAntiAlias(true); mDayPaint.setTextSize(dayTextSize); mDayPaint.setTypeface(Typeface.create(dayTypeface, 0)); Loading Loading @@ -296,6 +307,8 @@ class SimpleMonthView extends View { final int activatedColor = dayBackgroundColor.getColorForState( StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); mDaySelectorPaint.setColor(activatedColor); mDayHighlightSelectorPaint.setColor(activatedColor); mDayHighlightSelectorPaint.setAlpha(SELECTED_HIGHLIGHT_ALPHA); invalidate(); } Loading Loading @@ -326,8 +339,10 @@ class SimpleMonthView extends View { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: final int touchedItem = getDayAtLocation(x, y); if (mTouchedItem != touchedItem) { mTouchedItem = touchedItem; mIsTouchHighlighted = true; if (mHighlightedDay != touchedItem) { mHighlightedDay = touchedItem; mPreviouslyHighlightedDay = touchedItem; invalidate(); } if (action == MotionEvent.ACTION_DOWN && touchedItem < 0) { Loading @@ -342,13 +357,236 @@ class SimpleMonthView extends View { // Fall through. case MotionEvent.ACTION_CANCEL: // Reset touched day on stream end. mTouchedItem = -1; mHighlightedDay = -1; mIsTouchHighlighted = false; invalidate(); break; } return true; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // We need to handle focus change within the SimpleMonthView because we are simulating // multiple Views. The arrow keys will move between days until there is no space (no // day to the left, top, right, or bottom). Focus forward and back jumps out of the // SimpleMonthView, skipping over other SimpleMonthViews in the parent ViewPager // to the next focusable View in the hierarchy. boolean focusChanged = false; switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (event.hasNoModifiers()) { focusChanged = moveOneDay(isLayoutRtl()); } break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (event.hasNoModifiers()) { focusChanged = moveOneDay(!isLayoutRtl()); } break; case KeyEvent.KEYCODE_DPAD_UP: if (event.hasNoModifiers()) { ensureFocusedDay(); if (mHighlightedDay > 7) { mHighlightedDay -= 7; focusChanged = true; } } break; case KeyEvent.KEYCODE_DPAD_DOWN: if (event.hasNoModifiers()) { ensureFocusedDay(); if (mHighlightedDay <= mDaysInMonth - 7) { mHighlightedDay += 7; focusChanged = true; } } break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: if (mHighlightedDay != -1) { onDayClicked(mHighlightedDay); return true; } break; case KeyEvent.KEYCODE_TAB: { int focusChangeDirection = 0; if (event.hasNoModifiers()) { focusChangeDirection = View.FOCUS_FORWARD; } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { focusChangeDirection = View.FOCUS_BACKWARD; } if (focusChangeDirection != 0) { final ViewParent parent = getParent(); // move out of the ViewPager next/previous View nextFocus = this; do { nextFocus = nextFocus.focusSearch(focusChangeDirection); } while (nextFocus != null && nextFocus != this && nextFocus.getParent() == parent); if (nextFocus != null) { nextFocus.requestFocus(); return true; } } break; } } if (focusChanged) { invalidate(); return true; } else { return super.onKeyDown(keyCode, event); } } private boolean moveOneDay(boolean positive) { ensureFocusedDay(); boolean focusChanged = false; if (positive) { if (!isLastDayOfWeek(mHighlightedDay) && mHighlightedDay < mDaysInMonth) { mHighlightedDay++; focusChanged = true; } } else { if (!isFirstDayOfWeek(mHighlightedDay) && mHighlightedDay > 1) { mHighlightedDay--; focusChanged = true; } } return focusChanged; } @Override protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, @Nullable Rect previouslyFocusedRect) { if (gainFocus) { // If we've gained focus through arrow keys, we should find the day closest // to the focus rect. If we've gained focus through forward/back, we should // focus on the selected day if there is one. final int offset = findDayOffset(); switch(direction) { case View.FOCUS_RIGHT: { int row = findClosestRow(previouslyFocusedRect); mHighlightedDay = row == 0 ? 1 : (row * DAYS_IN_WEEK) - offset + 1; break; } case View.FOCUS_LEFT: { int row = findClosestRow(previouslyFocusedRect) + 1; mHighlightedDay = Math.min(mDaysInMonth, (row * DAYS_IN_WEEK) - offset); break; } case View.FOCUS_DOWN: { final int col = findClosestColumn(previouslyFocusedRect); final int day = col - offset + 1; mHighlightedDay = day < 1 ? day + DAYS_IN_WEEK : day; break; } case View.FOCUS_UP: { final int col = findClosestColumn(previouslyFocusedRect); final int maxWeeks = (offset + mDaysInMonth) / DAYS_IN_WEEK; final int day = col - offset + (DAYS_IN_WEEK * maxWeeks) + 1; mHighlightedDay = day > mDaysInMonth ? day - DAYS_IN_WEEK : day; break; } } ensureFocusedDay(); invalidate(); } super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); } /** * Returns the row (0 indexed) closest to previouslyFocusedRect or center if null. */ private int findClosestRow(@Nullable Rect previouslyFocusedRect) { if (previouslyFocusedRect == null) { return 3; } else { int centerY = previouslyFocusedRect.centerY(); final TextPaint p = mDayPaint; final int headerHeight = mMonthHeight + mDayOfWeekHeight; final int rowHeight = mDayHeight; // Text is vertically centered within the row height. final float halfLineHeight = (p.ascent() + p.descent()) / 2f; final int rowCenter = headerHeight + rowHeight / 2; centerY -= rowCenter - halfLineHeight; int row = Math.round(centerY / (float) rowHeight); final int maxDay = findDayOffset() + mDaysInMonth; final int maxRows = (maxDay / DAYS_IN_WEEK) - ((maxDay % DAYS_IN_WEEK == 0) ? 1 : 0); row = MathUtils.constrain(row, 0, maxRows); return row; } } /** * Returns the column (0 indexed) closest to the previouslyFocusedRect or center if null. * The 0 index is related to the first day of the week. */ private int findClosestColumn(@Nullable Rect previouslyFocusedRect) { if (previouslyFocusedRect == null) { return DAYS_IN_WEEK / 2; } else { int centerX = previouslyFocusedRect.centerX() - mPaddingLeft; final int columnFromLeft = MathUtils.constrain(centerX / mCellWidth, 0, DAYS_IN_WEEK - 1); return isLayoutRtl() ? DAYS_IN_WEEK - columnFromLeft - 1: columnFromLeft; } } @Override public void getFocusedRect(Rect r) { if (mHighlightedDay > 0) { getBoundsForDay(mHighlightedDay, r); } else { super.getFocusedRect(r); } } @Override protected void onFocusLost() { if (!mIsTouchHighlighted) { // Unhighlight a day. mPreviouslyHighlightedDay = mHighlightedDay; mHighlightedDay = -1; invalidate(); } super.onFocusLost(); } /** * Ensure some day is highlighted. If a day isn't highlighted, it chooses the selected day, * if possible, or the first day of the month if not. */ private void ensureFocusedDay() { if (mHighlightedDay != -1) { return; } if (mPreviouslyHighlightedDay != -1) { mHighlightedDay = mPreviouslyHighlightedDay; return; } if (mActivatedDay != -1) { mHighlightedDay = mActivatedDay; return; } mHighlightedDay = 1; } private boolean isFirstDayOfWeek(int day) { final int offset = findDayOffset(); return (offset + day - 1) % DAYS_IN_WEEK == 0; } private boolean isLastDayOfWeek(int day) { final int offset = findDayOffset(); return (offset + day) % DAYS_IN_WEEK == 0; } @Override protected void onDraw(Canvas canvas) { final int paddingLeft = getPaddingLeft(); Loading Loading @@ -432,12 +670,15 @@ class SimpleMonthView extends View { } final boolean isDayActivated = mActivatedDay == day; final boolean isDayHighlighted = mHighlightedDay == day; if (isDayActivated) { stateMask |= StateSet.VIEW_STATE_ACTIVATED; // Adjust the circle to be centered on the row. canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDaySelectorPaint); } else if (mTouchedItem == day) { final Paint paint = isDayHighlighted ? mDayHighlightSelectorPaint : mDaySelectorPaint; canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, paint); } else if (isDayHighlighted) { stateMask |= StateSet.VIEW_STATE_PRESSED; if (isDayEnabled) { Loading core/java/android/widget/YearPickerView.java +0 −6 Original line number Diff line number Diff line Loading @@ -38,8 +38,6 @@ class YearPickerView extends ListView { private OnYearSelectedListener mOnYearSelectedListener; private long mCurrentTimeMillis; public YearPickerView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.listViewStyle); } Loading Loading @@ -79,10 +77,6 @@ class YearPickerView extends ListView { mOnYearSelectedListener = listener; } public void setDate(long currentTimeMillis) { mCurrentTimeMillis = currentTimeMillis; } /** * Sets the currently selected year. Jumps immediately to the new year. * Loading Loading
core/java/android/widget/DatePickerCalendarDelegate.java +16 −2 Original line number Diff line number Diff line Loading @@ -171,7 +171,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { // Set up year picker view. mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker); mYearPickerView.setRange(mMinDate, mMaxDate); mYearPickerView.setDate(mCurrentDate.getTimeInMillis()); mYearPickerView.setYear(mCurrentDate.get(Calendar.YEAR)); mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener); // Set up content descriptions. Loading Loading @@ -267,6 +267,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { // Automatically switch to day picker. setCurrentView(VIEW_MONTH_DAY); // Switch focus back to the year text. mHeaderYear.requestFocus(); } }; Loading Loading @@ -344,7 +347,18 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { mAnimator.announceForAccessibility(mSelectDay); break; case VIEW_YEAR: mYearPickerView.setDate(mCurrentDate.getTimeInMillis()); final int year = mCurrentDate.get(Calendar.YEAR); mYearPickerView.setYear(year); mYearPickerView.post(new Runnable() { @Override public void run() { mYearPickerView.requestFocus(); final View selected = mYearPickerView.getSelectedView(); if (selected != null) { selected.requestFocus(); } } }); if (mCurrentView != viewIndex) { mHeaderMonthDay.setActivated(false); Loading
core/java/android/widget/DayPickerPagerAdapter.java +8 −0 Original line number Diff line number Diff line Loading @@ -287,6 +287,14 @@ class DayPickerPagerAdapter extends PagerAdapter { return null; } SimpleMonthView getView(Object object) { if (object == null) { return null; } final ViewHolder holder = (ViewHolder) object; return holder.calendar; } private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { @Override public void onDayClick(SimpleMonthView view, Calendar day) { Loading
core/java/android/widget/DayPickerViewPager.java +41 −2 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package android.widget; import com.android.internal.widget.ViewPager; import android.annotation.Nullable; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import com.android.internal.util.Predicate; import com.android.internal.widget.PagerAdapter; import com.android.internal.widget.ViewPager; import java.util.ArrayList; Loading Loading @@ -134,4 +140,37 @@ class DayPickerViewPager extends ViewPager { mMatchParentChildren.clear(); } @Override protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { if (predicate.apply(this)) { return this; } // Always try the selected view first. final DayPickerPagerAdapter adapter = (DayPickerPagerAdapter) getAdapter(); final SimpleMonthView current = adapter.getView(getCurrent()); if (current != childToSkip && current != null) { final View v = current.findViewByPredicate(predicate); if (v != null) { return v; } } final int len = getChildCount(); for (int i = 0; i < len; i++) { final View child = getChildAt(i); if (child != childToSkip && child != current) { final View v = child.findViewByPredicate(predicate); if (v != null) { return v; } } } return null; } }
core/java/android/widget/SimpleMonthView.java +247 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.widget; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; Loading @@ -34,8 +35,10 @@ import android.util.AttributeSet; import android.util.IntArray; import android.util.MathUtils; import android.util.StateSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; Loading @@ -61,11 +64,14 @@ class SimpleMonthView extends View { private static final String DEFAULT_TITLE_FORMAT = "MMMMy"; private static final String DAY_OF_WEEK_FORMAT = "EEEEE"; private static final int SELECTED_HIGHLIGHT_ALPHA = 0xB0; private final TextPaint mMonthPaint = new TextPaint(); private final TextPaint mDayOfWeekPaint = new TextPaint(); private final TextPaint mDayPaint = new TextPaint(); private final Paint mDaySelectorPaint = new Paint(); private final Paint mDayHighlightPaint = new Paint(); private final Paint mDayHighlightSelectorPaint = new Paint(); private final Calendar mCalendar = Calendar.getInstance(); private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance(); Loading Loading @@ -130,7 +136,9 @@ class SimpleMonthView extends View { private ColorStateList mDayTextColor; private int mTouchedItem = -1; private int mHighlightedDay = -1; private int mPreviouslyHighlightedDay = -1; private boolean mIsTouchHighlighted = false; public SimpleMonthView(Context context) { this(context, null); Loading Loading @@ -268,6 +276,9 @@ class SimpleMonthView extends View { mDayHighlightPaint.setAntiAlias(true); mDayHighlightPaint.setStyle(Style.FILL); mDayHighlightSelectorPaint.setAntiAlias(true); mDayHighlightSelectorPaint.setStyle(Style.FILL); mDayPaint.setAntiAlias(true); mDayPaint.setTextSize(dayTextSize); mDayPaint.setTypeface(Typeface.create(dayTypeface, 0)); Loading Loading @@ -296,6 +307,8 @@ class SimpleMonthView extends View { final int activatedColor = dayBackgroundColor.getColorForState( StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); mDaySelectorPaint.setColor(activatedColor); mDayHighlightSelectorPaint.setColor(activatedColor); mDayHighlightSelectorPaint.setAlpha(SELECTED_HIGHLIGHT_ALPHA); invalidate(); } Loading Loading @@ -326,8 +339,10 @@ class SimpleMonthView extends View { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: final int touchedItem = getDayAtLocation(x, y); if (mTouchedItem != touchedItem) { mTouchedItem = touchedItem; mIsTouchHighlighted = true; if (mHighlightedDay != touchedItem) { mHighlightedDay = touchedItem; mPreviouslyHighlightedDay = touchedItem; invalidate(); } if (action == MotionEvent.ACTION_DOWN && touchedItem < 0) { Loading @@ -342,13 +357,236 @@ class SimpleMonthView extends View { // Fall through. case MotionEvent.ACTION_CANCEL: // Reset touched day on stream end. mTouchedItem = -1; mHighlightedDay = -1; mIsTouchHighlighted = false; invalidate(); break; } return true; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // We need to handle focus change within the SimpleMonthView because we are simulating // multiple Views. The arrow keys will move between days until there is no space (no // day to the left, top, right, or bottom). Focus forward and back jumps out of the // SimpleMonthView, skipping over other SimpleMonthViews in the parent ViewPager // to the next focusable View in the hierarchy. boolean focusChanged = false; switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (event.hasNoModifiers()) { focusChanged = moveOneDay(isLayoutRtl()); } break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (event.hasNoModifiers()) { focusChanged = moveOneDay(!isLayoutRtl()); } break; case KeyEvent.KEYCODE_DPAD_UP: if (event.hasNoModifiers()) { ensureFocusedDay(); if (mHighlightedDay > 7) { mHighlightedDay -= 7; focusChanged = true; } } break; case KeyEvent.KEYCODE_DPAD_DOWN: if (event.hasNoModifiers()) { ensureFocusedDay(); if (mHighlightedDay <= mDaysInMonth - 7) { mHighlightedDay += 7; focusChanged = true; } } break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: if (mHighlightedDay != -1) { onDayClicked(mHighlightedDay); return true; } break; case KeyEvent.KEYCODE_TAB: { int focusChangeDirection = 0; if (event.hasNoModifiers()) { focusChangeDirection = View.FOCUS_FORWARD; } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { focusChangeDirection = View.FOCUS_BACKWARD; } if (focusChangeDirection != 0) { final ViewParent parent = getParent(); // move out of the ViewPager next/previous View nextFocus = this; do { nextFocus = nextFocus.focusSearch(focusChangeDirection); } while (nextFocus != null && nextFocus != this && nextFocus.getParent() == parent); if (nextFocus != null) { nextFocus.requestFocus(); return true; } } break; } } if (focusChanged) { invalidate(); return true; } else { return super.onKeyDown(keyCode, event); } } private boolean moveOneDay(boolean positive) { ensureFocusedDay(); boolean focusChanged = false; if (positive) { if (!isLastDayOfWeek(mHighlightedDay) && mHighlightedDay < mDaysInMonth) { mHighlightedDay++; focusChanged = true; } } else { if (!isFirstDayOfWeek(mHighlightedDay) && mHighlightedDay > 1) { mHighlightedDay--; focusChanged = true; } } return focusChanged; } @Override protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, @Nullable Rect previouslyFocusedRect) { if (gainFocus) { // If we've gained focus through arrow keys, we should find the day closest // to the focus rect. If we've gained focus through forward/back, we should // focus on the selected day if there is one. final int offset = findDayOffset(); switch(direction) { case View.FOCUS_RIGHT: { int row = findClosestRow(previouslyFocusedRect); mHighlightedDay = row == 0 ? 1 : (row * DAYS_IN_WEEK) - offset + 1; break; } case View.FOCUS_LEFT: { int row = findClosestRow(previouslyFocusedRect) + 1; mHighlightedDay = Math.min(mDaysInMonth, (row * DAYS_IN_WEEK) - offset); break; } case View.FOCUS_DOWN: { final int col = findClosestColumn(previouslyFocusedRect); final int day = col - offset + 1; mHighlightedDay = day < 1 ? day + DAYS_IN_WEEK : day; break; } case View.FOCUS_UP: { final int col = findClosestColumn(previouslyFocusedRect); final int maxWeeks = (offset + mDaysInMonth) / DAYS_IN_WEEK; final int day = col - offset + (DAYS_IN_WEEK * maxWeeks) + 1; mHighlightedDay = day > mDaysInMonth ? day - DAYS_IN_WEEK : day; break; } } ensureFocusedDay(); invalidate(); } super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); } /** * Returns the row (0 indexed) closest to previouslyFocusedRect or center if null. */ private int findClosestRow(@Nullable Rect previouslyFocusedRect) { if (previouslyFocusedRect == null) { return 3; } else { int centerY = previouslyFocusedRect.centerY(); final TextPaint p = mDayPaint; final int headerHeight = mMonthHeight + mDayOfWeekHeight; final int rowHeight = mDayHeight; // Text is vertically centered within the row height. final float halfLineHeight = (p.ascent() + p.descent()) / 2f; final int rowCenter = headerHeight + rowHeight / 2; centerY -= rowCenter - halfLineHeight; int row = Math.round(centerY / (float) rowHeight); final int maxDay = findDayOffset() + mDaysInMonth; final int maxRows = (maxDay / DAYS_IN_WEEK) - ((maxDay % DAYS_IN_WEEK == 0) ? 1 : 0); row = MathUtils.constrain(row, 0, maxRows); return row; } } /** * Returns the column (0 indexed) closest to the previouslyFocusedRect or center if null. * The 0 index is related to the first day of the week. */ private int findClosestColumn(@Nullable Rect previouslyFocusedRect) { if (previouslyFocusedRect == null) { return DAYS_IN_WEEK / 2; } else { int centerX = previouslyFocusedRect.centerX() - mPaddingLeft; final int columnFromLeft = MathUtils.constrain(centerX / mCellWidth, 0, DAYS_IN_WEEK - 1); return isLayoutRtl() ? DAYS_IN_WEEK - columnFromLeft - 1: columnFromLeft; } } @Override public void getFocusedRect(Rect r) { if (mHighlightedDay > 0) { getBoundsForDay(mHighlightedDay, r); } else { super.getFocusedRect(r); } } @Override protected void onFocusLost() { if (!mIsTouchHighlighted) { // Unhighlight a day. mPreviouslyHighlightedDay = mHighlightedDay; mHighlightedDay = -1; invalidate(); } super.onFocusLost(); } /** * Ensure some day is highlighted. If a day isn't highlighted, it chooses the selected day, * if possible, or the first day of the month if not. */ private void ensureFocusedDay() { if (mHighlightedDay != -1) { return; } if (mPreviouslyHighlightedDay != -1) { mHighlightedDay = mPreviouslyHighlightedDay; return; } if (mActivatedDay != -1) { mHighlightedDay = mActivatedDay; return; } mHighlightedDay = 1; } private boolean isFirstDayOfWeek(int day) { final int offset = findDayOffset(); return (offset + day - 1) % DAYS_IN_WEEK == 0; } private boolean isLastDayOfWeek(int day) { final int offset = findDayOffset(); return (offset + day) % DAYS_IN_WEEK == 0; } @Override protected void onDraw(Canvas canvas) { final int paddingLeft = getPaddingLeft(); Loading Loading @@ -432,12 +670,15 @@ class SimpleMonthView extends View { } final boolean isDayActivated = mActivatedDay == day; final boolean isDayHighlighted = mHighlightedDay == day; if (isDayActivated) { stateMask |= StateSet.VIEW_STATE_ACTIVATED; // Adjust the circle to be centered on the row. canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDaySelectorPaint); } else if (mTouchedItem == day) { final Paint paint = isDayHighlighted ? mDayHighlightSelectorPaint : mDaySelectorPaint; canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, paint); } else if (isDayHighlighted) { stateMask |= StateSet.VIEW_STATE_PRESSED; if (isDayEnabled) { Loading
core/java/android/widget/YearPickerView.java +0 −6 Original line number Diff line number Diff line Loading @@ -38,8 +38,6 @@ class YearPickerView extends ListView { private OnYearSelectedListener mOnYearSelectedListener; private long mCurrentTimeMillis; public YearPickerView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.listViewStyle); } Loading Loading @@ -79,10 +77,6 @@ class YearPickerView extends ListView { mOnYearSelectedListener = listener; } public void setDate(long currentTimeMillis) { mCurrentTimeMillis = currentTimeMillis; } /** * Sets the currently selected year. Jumps immediately to the new year. * Loading