Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8fd00a0 authored by Aurimas Liutikas's avatar Aurimas Liutikas
Browse files

Increase SearchView touch targets to meet GAR3.

- Allow SearchView to expand to 48dp height if possible.
- Make the search clear button have 48dp height if possible.
- Expand the search TextView touch target height to 48dp is possible.

Framework version of patch ag/912646

Bug: 19479861
Change-Id: Ibaaef2afa20b8c05eaac8f028df4f616f2f96eb1
parent 82a0ccac
Loading
Loading
Loading
Loading
+151 −1
Original line number Diff line number Diff line
@@ -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
+3 −6
Original line number Diff line number Diff line
@@ -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"
+2 −1
Original line number Diff line number Diff line
@@ -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>
+1 −0
Original line number Diff line number Diff line
@@ -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" />