Postpone hover state resolution in DropDownListView
Prevents a HOVER_EXIT => TOUCH_DOWN transition from triggering two Drawable.setState() calls in the same frame. Bug: 25849904 Change-Id: Ib10f127fd68e433992b6b11e62ac2263d790ef52
This commit is contained in:
@@ -74,6 +74,12 @@ public class DropDownListView extends ListView {
|
||||
/** Helper for drag-to-open auto scrolling. */
|
||||
private AbsListViewAutoScroller mScrollHelper;
|
||||
|
||||
/**
|
||||
* Runnable posted when we are awaiting hover event resolution. When set,
|
||||
* drawable state changes are postponed.
|
||||
*/
|
||||
private ResolveHoverRunnable mResolveHoverRunnable;
|
||||
|
||||
/**
|
||||
* Creates a new list view wrapper.
|
||||
*
|
||||
@@ -100,19 +106,37 @@ public class DropDownListView extends ListView {
|
||||
return isHovered() || super.shouldShowSelector();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (mResolveHoverRunnable != null) {
|
||||
// Resolved hover event as hover => touch transition.
|
||||
mResolveHoverRunnable.cancel();
|
||||
}
|
||||
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHoverEvent(@NonNull MotionEvent ev) {
|
||||
final int action = ev.getActionMasked();
|
||||
if (action == MotionEvent.ACTION_HOVER_EXIT && mResolveHoverRunnable == null) {
|
||||
// This may be transitioning to TOUCH_DOWN. Postpone drawable state
|
||||
// updates until either the next frame or the next touch event.
|
||||
mResolveHoverRunnable = new ResolveHoverRunnable();
|
||||
mResolveHoverRunnable.post();
|
||||
}
|
||||
|
||||
// Allow the super class to handle hover state management first.
|
||||
final boolean handled = super.onHoverEvent(ev);
|
||||
|
||||
final int action = ev.getActionMasked();
|
||||
if (action == MotionEvent.ACTION_HOVER_ENTER
|
||||
|| action == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
|
||||
if (position != INVALID_POSITION && position != mSelectedPosition) {
|
||||
final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
|
||||
if (hoveredItem.isEnabled()) {
|
||||
// Force a focus so that the proper selector state gets used when we update.
|
||||
// Force a focus so that the proper selector state gets
|
||||
// used when we update.
|
||||
requestFocus();
|
||||
|
||||
positionSelector(position, hoveredItem);
|
||||
@@ -122,7 +146,8 @@ public class DropDownListView extends ListView {
|
||||
updateSelectorState();
|
||||
}
|
||||
} else {
|
||||
// Do not cancel the selected position if the selection is visible by other reasons.
|
||||
// Do not cancel the selected position if the selection is visible
|
||||
// by other means.
|
||||
if (!super.shouldShowSelector()) {
|
||||
setSelectedPositionInt(INVALID_POSITION);
|
||||
setNextSelectedPositionInt(INVALID_POSITION);
|
||||
@@ -132,6 +157,13 @@ public class DropDownListView extends ListView {
|
||||
return handled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
if (mResolveHoverRunnable == null) {
|
||||
super.drawableStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles forwarded events.
|
||||
*
|
||||
@@ -196,12 +228,14 @@ public class DropDownListView extends ListView {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the list selection is hidden, as part of a workaround for a touch mode issue
|
||||
* (see the declaration for mListSelectionHidden).
|
||||
* @param listSelectionHidden
|
||||
* Sets whether the list selection is hidden, as part of a workaround for a
|
||||
* touch mode issue (see the declaration for mListSelectionHidden).
|
||||
*
|
||||
* @param hideListSelection {@code true} to hide list selection,
|
||||
* {@code false} to show
|
||||
*/
|
||||
public void setListSelectionHidden(boolean listSelectionHidden) {
|
||||
this.mListSelectionHidden = listSelectionHidden;
|
||||
public void setListSelectionHidden(boolean hideListSelection) {
|
||||
mListSelectionHidden = hideListSelection;
|
||||
}
|
||||
|
||||
private void clearPressedItem() {
|
||||
@@ -312,4 +346,25 @@ public class DropDownListView extends ListView {
|
||||
public boolean hasFocus() {
|
||||
return mHijackFocus || super.hasFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable that forces hover event resolution and updates drawable state.
|
||||
*/
|
||||
private class ResolveHoverRunnable implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
// Resolved hover event as standard hover exit.
|
||||
mResolveHoverRunnable = null;
|
||||
drawableStateChanged();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
mResolveHoverRunnable = null;
|
||||
removeCallbacks(this);
|
||||
}
|
||||
|
||||
public void post() {
|
||||
DropDownListView.this.post(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user