Merge "Vibrate when the gear gets up to speed"
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index c2c247e..d563f51 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -17,6 +17,9 @@
package android.view;
import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import java.util.ArrayList;
import java.util.Collections;
@@ -173,6 +176,7 @@
// Note: This sort is stable.
mSequentialFocusComparator.setRoot(root);
mSequentialFocusComparator.setIsLayoutRtl(root.isLayoutRtl());
+ mSequentialFocusComparator.setFocusables(focusables);
Collections.sort(focusables, mSequentialFocusComparator);
} finally {
mSequentialFocusComparator.recycle();
@@ -598,8 +602,16 @@
+ "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
}
+ private static final boolean isValidId(final int id) {
+ return id != 0 && id != View.NO_ID;
+ }
+
/**
* Sorts views according to their visual layout and geometry for default tab order.
+ * If views are part of a focus chain (nextFocusForwardId), then they are all grouped
+ * together. The head of the chain is used to determine the order of the chain and is
+ * first in the order and the tail of the chain is the last in the order. The views
+ * in the middle of the chain can be arbitrary order.
* This is used for sequential focus traversal.
*/
private static final class SequentialFocusComparator implements Comparator<View> {
@@ -607,9 +619,15 @@
private final Rect mSecondRect = new Rect();
private ViewGroup mRoot;
private boolean mIsLayoutRtl;
+ private final SparseArray<View> mFocusables = new SparseArray<View>();
+ private final SparseBooleanArray mIsConnectedTo = new SparseBooleanArray();
+ private final ArrayMap<View, View> mHeadsOfChains = new ArrayMap<View, View>();
public void recycle() {
mRoot = null;
+ mFocusables.clear();
+ mHeadsOfChains.clear();
+ mIsConnectedTo.clear();
}
public void setRoot(ViewGroup root) {
@@ -620,11 +638,72 @@
mIsLayoutRtl = b;
}
+ public void setFocusables(ArrayList<View> focusables) {
+ for (int i = focusables.size() - 1; i >= 0; i--) {
+ final View view = focusables.get(i);
+ final int id = view.getId();
+ if (isValidId(id)) {
+ mFocusables.put(id, view);
+ }
+ final int nextId = view.getNextFocusForwardId();
+ if (isValidId(nextId)) {
+ mIsConnectedTo.put(nextId, true);
+ }
+ }
+
+ for (int i = focusables.size() - 1; i >= 0; i--) {
+ final View view = focusables.get(i);
+ final int nextId = view.getNextFocusForwardId();
+ if (isValidId(nextId) && !mIsConnectedTo.get(view.getId())) {
+ setHeadOfChain(view);
+ }
+ }
+ }
+
+ private void setHeadOfChain(View head) {
+ for (View view = head; view != null;
+ view = mFocusables.get(view.getNextFocusForwardId())) {
+ final View otherHead = mHeadsOfChains.get(view);
+ if (otherHead != null) {
+ if (otherHead == head) {
+ return; // This view has already had its head set properly
+ }
+ // A hydra -- multi-headed focus chain (e.g. A->C and B->C)
+ // Use the one we've already chosen instead and reset this chain.
+ view = head;
+ head = otherHead;
+ }
+ mHeadsOfChains.put(view, head);
+ }
+ }
+
public int compare(View first, View second) {
if (first == second) {
return 0;
}
+ // Order between views within a chain is immaterial -- next/previous is
+ // within a chain is handled elsewhere.
+ View firstHead = mHeadsOfChains.get(first);
+ View secondHead = mHeadsOfChains.get(second);
+ if (firstHead == secondHead && firstHead != null) {
+ if (first == firstHead) {
+ return -1; // first is the head, it should be first
+ } else if (second == firstHead) {
+ return 1; // second is the head, it should be first
+ } else if (isValidId(first.getNextFocusForwardId())) {
+ return -1; // first is not the end of the chain
+ } else {
+ return 1; // first is end of chain
+ }
+ }
+ if (firstHead != null) {
+ first = firstHead;
+ }
+ if (secondHead != null) {
+ second = secondHead;
+ }
+ // First see if they belong to the same focus chain.
getRect(first, mFirstRect);
getRect(second, mSecondRect);
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 7e542c9..cbb6109 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -171,7 +171,7 @@
// 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.
@@ -267,6 +267,9 @@
// Automatically switch to day picker.
setCurrentView(VIEW_MONTH_DAY);
+
+ // Switch focus back to the year text.
+ mHeaderYear.requestFocus();
}
};
@@ -344,7 +347,18 @@
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);
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 8fe8252..f5840dc 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -287,6 +287,14 @@
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) {
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index bb6e3a4..5f0ae29 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -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;
@@ -134,4 +140,37 @@
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;
+ }
+
}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index e9325ef..6edce91 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -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;
@@ -34,8 +35,10 @@
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;
@@ -61,11 +64,14 @@
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();
@@ -130,7 +136,9 @@
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);
@@ -268,6 +276,9 @@
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));
@@ -296,6 +307,8 @@
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();
}
@@ -326,8 +339,10 @@
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) {
@@ -342,7 +357,8 @@
// Fall through.
case MotionEvent.ACTION_CANCEL:
// Reset touched day on stream end.
- mTouchedItem = -1;
+ mHighlightedDay = -1;
+ mIsTouchHighlighted = false;
invalidate();
break;
}
@@ -350,6 +366,228 @@
}
@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();
final int paddingTop = getPaddingTop();
@@ -432,12 +670,15 @@
}
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) {
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index 89e59f9..96624d2 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -38,8 +38,6 @@
private OnYearSelectedListener mOnYearSelectedListener;
- private long mCurrentTimeMillis;
-
public YearPickerView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.listViewStyle);
}
@@ -79,10 +77,6 @@
mOnYearSelectedListener = listener;
}
- public void setDate(long currentTimeMillis) {
- mCurrentTimeMillis = currentTimeMillis;
- }
-
/**
* Sets the currently selected year. Jumps immediately to the new year.
*
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 6217d6e..948a6bb 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -1095,7 +1095,16 @@
View child = getChildAt(i);
ii = infoForChild(child);
if (ii != null && ii.position == mCurItem) {
- if (child.requestFocus(focusDirection)) {
+ final Rect focusRect;
+ if (currentFocused == null) {
+ focusRect = null;
+ } else {
+ focusRect = mTempRect;
+ currentFocused.getFocusedRect(mTempRect);
+ offsetDescendantRectToMyCoords(currentFocused, mTempRect);
+ offsetRectIntoDescendantCoords(child, mTempRect);
+ }
+ if (child.requestFocus(focusDirection, focusRect)) {
break;
}
}
@@ -1321,6 +1330,11 @@
}
}
+ public Object getCurrent() {
+ final ItemInfo itemInfo = infoForPosition(getCurrentItem());
+ return itemInfo == null ? null : itemInfo.object;
+ }
+
@Override
public void removeView(View view) {
if (mInLayout) {
diff --git a/core/res/res/layout/date_picker_header_material.xml b/core/res/res/layout/date_picker_header_material.xml
index a4388f6..821b588 100644
--- a/core/res/res/layout/date_picker_header_material.xml
+++ b/core/res/res/layout/date_picker_header_material.xml
@@ -19,19 +19,27 @@
android:id="@+id/date_picker_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="18dp"
android:paddingStart="?attr/dialogPreferredPadding"
android:paddingEnd="?attr/dialogPreferredPadding"
- android:orientation="vertical">
+ android:paddingTop="16dp"
+ android:paddingBottom="18dp"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
- <!-- Top padding should stay on this view so that
- the touch target is a bit larger. -->
<TextView
android:id="@+id/date_picker_header_year"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="16dp"
- android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel" />
+ android:focusable="true"
+ android:layout_marginStart="-8dp"
+ android:layout_marginEnd="-8dp"
+ android:layout_marginTop="-8dp"
+ android:layout_marginBottom="-8dp"
+ android:padding="8dp"
+ android:background="?attr/selectableItemBackground"
+ android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel"
+ android:nextFocusForward="@+id/prev" />
<TextView
android:id="@+id/date_picker_header_date"
diff --git a/core/res/res/layout/date_picker_month_item_material.xml b/core/res/res/layout/date_picker_month_item_material.xml
index cb79cee..52f7b8e 100644
--- a/core/res/res/layout/date_picker_month_item_material.xml
+++ b/core/res/res/layout/date_picker_month_item_material.xml
@@ -21,4 +21,5 @@
android:layout_height="wrap_content"
android:paddingStart="@dimen/day_picker_padding_horizontal"
android:paddingEnd="@dimen/day_picker_padding_horizontal"
- android:paddingTop="@dimen/day_picker_padding_top" />
+ android:paddingTop="@dimen/day_picker_padding_top"
+ android:focusable="true"/>
diff --git a/core/res/res/layout/day_picker_content_material.xml b/core/res/res/layout/day_picker_content_material.xml
index b582d74..d77e8dc 100644
--- a/core/res/res/layout/day_picker_content_material.xml
+++ b/core/res/res/layout/day_picker_content_material.xml
@@ -33,7 +33,9 @@
android:src="@drawable/ic_chevron_start"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/date_picker_prev_month_button"
- android:visibility="invisible" />
+ android:visibility="invisible"
+ android:nextFocusForward="@+id/next"
+ android:nextFocusDown="@+id/month_view" />
<ImageButton
android:id="@+id/next"
@@ -44,6 +46,8 @@
android:src="@drawable/ic_chevron_end"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/date_picker_next_month_button"
- android:visibility="invisible" />
+ android:visibility="invisible"
+ android:nextFocusForward="@+id/month_view"
+ android:nextFocusDown="@+id/month_view"/>
</FrameLayout>