Merge "Increase SearchView touch targets to meet GAR3." into nyc-dev

This commit is contained in:
Aurimas Liutikas
2016-04-15 22:47:09 +00:00
committed by Android (Google) Code Review
4 changed files with 157 additions and 8 deletions

View File

@@ -53,7 +53,10 @@ import android.util.TypedValue;
import android.view.CollapsibleActionView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView.OnItemClickListener;
@@ -111,6 +114,12 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
private final ImageView mVoiceButton;
private final View mDropDownAnchor;
private UpdatableTouchDelegate mTouchDelegate;
private Rect mSearchSrcTextViewBounds = new Rect();
private Rect mSearchSrtTextViewBoundsExpanded = new Rect();
private int[] mTemp = new int[2];
private int[] mTemp2 = new int[2];
/** Icon optionally displayed when the SearchView is collapsed. */
private final ImageView mCollapsedIcon;
@@ -801,7 +810,48 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
break;
}
widthMode = MeasureSpec.EXACTLY;
super.onMeasure(MeasureSpec.makeMeasureSpec(width, widthMode), heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
switch (heightMode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
height = Math.min(getPreferredHeight(), height);
break;
}
heightMode = MeasureSpec.EXACTLY;
super.onMeasure(MeasureSpec.makeMeasureSpec(width, widthMode),
MeasureSpec.makeMeasureSpec(height, heightMode));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
// Expand mSearchSrcTextView touch target to be the height of the parent in order to
// allow it to be up to 48dp.
getChildBoundsWithinSearchView(mSearchSrcTextView, mSearchSrcTextViewBounds);
mSearchSrtTextViewBoundsExpanded.set(
mSearchSrcTextViewBounds.left, 0, mSearchSrcTextViewBounds.right, bottom - top);
if (mTouchDelegate == null) {
mTouchDelegate = new UpdatableTouchDelegate(mSearchSrtTextViewBoundsExpanded,
mSearchSrcTextViewBounds, mSearchSrcTextView);
setTouchDelegate(mTouchDelegate);
} else {
mTouchDelegate.setBounds(mSearchSrtTextViewBoundsExpanded, mSearchSrcTextViewBounds);
}
}
}
private void getChildBoundsWithinSearchView(View view, Rect rect) {
view.getLocationInWindow(mTemp);
getLocationInWindow(mTemp2);
final int top = mTemp[1] - mTemp2[1];
final int left = mTemp[0] - mTemp2[0];
rect.set(left , top, left + view.getWidth(), top + view.getHeight());
}
private int getPreferredWidth() {
@@ -809,6 +859,11 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
.getDimensionPixelSize(R.dimen.search_view_preferred_width);
}
private int getPreferredHeight() {
return getContext().getResources()
.getDimensionPixelSize(R.dimen.search_view_preferred_height);
}
private void updateViewsVisibility(final boolean collapsed) {
mIconified = collapsed;
// Visibility of views that are visible when collapsed
@@ -1749,6 +1804,101 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
}
};
private static class UpdatableTouchDelegate extends TouchDelegate {
/**
* View that should receive forwarded touch events
*/
private final View mDelegateView;
/**
* Bounds in local coordinates of the containing view that should be mapped to the delegate
* view. This rect is used for initial hit testing.
*/
private final Rect mTargetBounds;
/**
* Bounds in local coordinates of the containing view that are actual bounds of the delegate
* view. This rect is used for event coordinate mapping.
*/
private final Rect mActualBounds;
/**
* mTargetBounds inflated to include some slop. This rect is to track whether the motion events
* should be considered to be be within the delegate view.
*/
private final Rect mSlopBounds;
private final int mSlop;
/**
* True if the delegate had been targeted on a down event (intersected mTargetBounds).
*/
private boolean mDelegateTargeted;
public UpdatableTouchDelegate(Rect targetBounds, Rect actualBounds, View delegateView) {
super(targetBounds, delegateView);
mSlop = ViewConfiguration.get(delegateView.getContext()).getScaledTouchSlop();
mTargetBounds = new Rect();
mSlopBounds = new Rect();
mActualBounds = new Rect();
setBounds(targetBounds, actualBounds);
mDelegateView = delegateView;
}
public void setBounds(Rect desiredBounds, Rect actualBounds) {
mTargetBounds.set(desiredBounds);
mSlopBounds.set(desiredBounds);
mSlopBounds.inset(-mSlop, -mSlop);
mActualBounds.set(actualBounds);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
boolean sendToDelegate = false;
boolean hit = true;
boolean handled = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mTargetBounds.contains(x, y)) {
mDelegateTargeted = true;
sendToDelegate = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
sendToDelegate = mDelegateTargeted;
if (sendToDelegate) {
if (!mSlopBounds.contains(x, y)) {
hit = false;
}
}
break;
case MotionEvent.ACTION_CANCEL:
sendToDelegate = mDelegateTargeted;
mDelegateTargeted = false;
break;
}
if (sendToDelegate) {
if (hit && !mActualBounds.contains(x, y)) {
// Offset event coordinates to be in the center of the target view since we
// are within the targetBounds, but not inside the actual bounds of
// mDelegateView
event.setLocation(mDelegateView.getWidth() / 2,
mDelegateView.getHeight() / 2);
} else {
// Offset event coordinates to the target view coordinates.
event.setLocation(x - mActualBounds.left, y - mActualBounds.top);
}
handled = mDelegateView.dispatchTouchEvent(event);
}
return handled;
}
}
/**
* Local subclass for AutoCompleteTextView.
* @hide

View File

@@ -48,11 +48,8 @@
<LinearLayout
android:id="@+id/search_edit_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip"
android:layout_marginStart="8dip"
android:layout_marginEnd="8dip"
android:orientation="horizontal"
@@ -71,7 +68,7 @@
<LinearLayout
android:id="@+id/search_plate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
@@ -81,7 +78,7 @@
android:layout_height="36dip"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="bottom"
android:layout_gravity="center_vertical"
android:paddingStart="@dimen/dropdownitem_text_padding_left"
android:paddingEnd="@dimen/dropdownitem_text_padding_right"
android:singleLine="true"

View File

@@ -184,8 +184,9 @@
<!-- The spacing between messages in Notification.MessagingStyle -->
<dimen name="notification_messaging_spacing">6dp</dimen>
<!-- Preferred width of the search view. -->
<!-- Preferred width and height of the search view. -->
<dimen name="search_view_preferred_width">320dip</dimen>
<dimen name="search_view_preferred_height">48dip</dimen>
<!-- Dialog padding for round display -->
<dimen name="alert_dialog_round_padding">27dip</dimen>

View File

@@ -423,6 +423,7 @@
<java-symbol type="dimen" name="dropdownitem_text_padding_left" />
<java-symbol type="dimen" name="password_keyboard_spacebar_vertical_correction" />
<java-symbol type="dimen" name="search_view_preferred_width" />
<java-symbol type="dimen" name="search_view_preferred_height" />
<java-symbol type="dimen" name="textview_error_popup_default_width" />
<java-symbol type="dimen" name="toast_y_offset" />
<java-symbol type="dimen" name="action_bar_stacked_max_height" />