summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorAurimas Liutikas <aurimas@google.com>2016-04-15 22:47:09 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2016-04-15 22:47:11 +0000
commitd0612e74f27844904af55ddb133522cec4298058 (patch)
tree69707a47c0719f0df804fba2d73b6ec307919743 /core/java/android
parentf94fcc3e5da33ba3d77dd90f5d5ae32cb506dd0e (diff)
parentc8fd00a046b6228095f8bb440be5d6ce1c260f6e (diff)
Merge "Increase SearchView touch targets to meet GAR3." into nyc-dev
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/widget/SearchView.java152
1 files changed, 151 insertions, 1 deletions
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 9a4d69fd4e9a..5878cad2f9a3 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -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