Skip to content

Commit

Permalink
[Slider] Keyboard navigation fix
Browse files Browse the repository at this point in the history
Resolves #1364

GIT_ORIGIN_REV_ID=8a0fb870fafba516db529ffee13ea448964b0a9b
PiperOrigin-RevId: 315302829
  • Loading branch information
consp1racy authored and ymarian committed Jun 8, 2020
1 parent c66c69d commit 3e3bc41
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 28 deletions.
87 changes: 66 additions & 21 deletions lib/java/com/google/android/material/slider/BaseSlider.java
Original file line number Diff line number Diff line change
Expand Up @@ -1825,13 +1825,11 @@ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_TAB:
if (event.hasNoModifiers()) {
moveFocus(1);
return true;
return moveFocus(1);
} else if (event.isShiftPressed()) {
moveFocus(-1);
return true;
return moveFocus(-1);
}
return false;
// fall through
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_MINUS:
moveFocus(-1);
Expand All @@ -1850,7 +1848,7 @@ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
}
} else {
isLongPress |= event.isLongPress();
Float increment = calculateIncrementForKey(event, keyCode);
Float increment = calculateIncrementForKey(keyCode);
if (increment != null) {
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
increment = -increment;
Expand All @@ -1863,6 +1861,25 @@ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
}
return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_TAB:
if (event.hasNoModifiers()) {
return moveFocus(1);
} else if (event.isShiftPressed()) {
return moveFocus(-1);
}
// fall through
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
activeThumbIdx = -1;
for (TooltipDrawable label : labels) {
ViewUtils.getContentViewOverlay(this).remove(label);
}
postInvalidate();
return true;
default:
// Nothing to do in this case.
}
}
}

Expand All @@ -1875,31 +1892,36 @@ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
return super.onKeyUp(keyCode, event);
}

private void moveFocus(int direction) {
/**
* Attempts to move focus to next or previous thumb and returns whether the focused thumb changed.
* If focused thumb didn't change, we're at the view boundary for specified {@code direction} and
* focus should be moved to next or previous view instead.
*/
private boolean moveFocus(int direction) {
int oldFocusedThumbIdx = focusedThumbIdx;
focusedThumbIdx += direction;
focusedThumbIdx = MathUtils.clamp(focusedThumbIdx, 0, values.size() - 1);
if (activeThumbIdx != -1) {
activeThumbIdx = focusedThumbIdx;
if (focusedThumbIdx == oldFocusedThumbIdx) {
// Move focus to next or previous view.
return false;
} else {
if (activeThumbIdx != -1) {
activeThumbIdx = focusedThumbIdx;
}
updateHaloHotspot();
postInvalidate();
return true;
}
updateHaloHotspot();
postInvalidate();
}

private Float calculateIncrementForKey(KeyEvent event, int keyCode) {
private Float calculateIncrementForKey(int keyCode) {
// If this is a long press, increase the increment so it will only take around 20 steps.
// Otherwise choose the smallest valid increment.
float increment = isLongPress ? calculateStepIncrement(20) : calculateStepIncrement();
switch (keyCode) {
case KeyEvent.KEYCODE_TAB:
if (event.isShiftPressed()) {
return -increment;
} else {
return increment;
}
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_MINUS:
increment = -increment;
// fallthrough
return -increment;
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_PLUS:
case KeyEvent.KEYCODE_EQUALS:
Expand Down Expand Up @@ -1937,12 +1959,35 @@ protected void onFocusChanged(
for (TooltipDrawable label : labels) {
ViewUtils.getContentViewOverlay(this).remove(label);
}
accessibilityHelper.requestKeyboardFocusForVirtualView(ExploreByTouchHelper.INVALID_ID);
accessibilityHelper.clearKeyboardFocusForVirtualView(focusedThumbIdx);
} else {
focusThumbOnFocusGained(direction);
accessibilityHelper.requestKeyboardFocusForVirtualView(focusedThumbIdx);
}
}

private void focusThumbOnFocusGained(int direction) {
switch (direction) {
case FOCUS_BACKWARD:
case FOCUS_LEFT:
moveFocus(Integer.MAX_VALUE);
break;
case FOCUS_FORWARD:
case FOCUS_RIGHT:
moveFocus(Integer.MIN_VALUE);
break;
case FOCUS_UP:
case FOCUS_DOWN:
default:
// Don't make assumptions about where exactly focus came from. Use previously focused thumb.
}
}

@VisibleForTesting
final int getAccessibilityFocusedVirtualViewId() {
return accessibilityHelper.getAccessibilityFocusedVirtualViewId();
}

@NonNull
@Override
public CharSequence getAccessibilityClassName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ static float calculateXPositionFromValue(Slider s, float value) {
return s.getTrackSidePadding() + x;
}

static void activateFocusedThumb(Slider s) {
static void clickDpadCenter(Slider s) {
new KeyEventBuilder(KeyEvent.KEYCODE_DPAD_CENTER).dispatchEvent(s);
}

Expand Down

0 comments on commit 3e3bc41

Please sign in to comment.