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

Commit 4cf7ba63 authored by Justin Ghan's avatar Justin Ghan
Browse files

Hide hint text when starting handwriting

Bug: 277153261
Test: atest android.view.stylus.HandwritingInitiatorTest
Change-Id: I64007e8ea9a52a76cff78b04bc5b307c117b77c8
parent 53c8ac6f
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;

import com.android.internal.annotations.VisibleForTesting;

@@ -305,6 +306,9 @@ public class HandwritingInitiator {
        mImm.startStylusHandwriting(view);
        mState.mHasInitiatedHandwriting = true;
        mState.mShouldInitHandwriting = false;
        if (view instanceof TextView) {
            ((TextView) view).hideHint();
        }
    }

    /**
@@ -323,6 +327,9 @@ public class HandwritingInitiator {
                mState.mHasInitiatedHandwriting = true;
                mState.mShouldInitHandwriting = false;
            }
            if (view instanceof TextView) {
                ((TextView) view).hideHint();
            }
            return true;
        }
        return false;
+22 −2
Original line number Diff line number Diff line
@@ -805,6 +805,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    private CharSequence mHint;
    @UnsupportedAppUsage
    private Layout mHintLayout;
    private boolean mHideHint;
    private MovementMethod mMovement;
@@ -7110,6 +7111,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        sendOnTextChanged(text, 0, oldlen, textLength);
        onTextChanged(text, 0, oldlen, textLength);
        mHideHint = false;
        if (a11yTextChangeType == AccessibilityUtils.TEXT) {
            notifyViewAccessibilityStateChangedIfNeeded(
                    AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
@@ -7268,6 +7271,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }
    private void setHintInternal(CharSequence hint) {
        mHideHint = false;
        mHint = TextUtils.stringOrSpannedString(hint);
        if (mLayout != null) {
@@ -7308,6 +7312,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return mHint;
    }
    /**
     * Temporarily hides the hint text until the text is modified, or the hint text is modified, or
     * the view gains or loses focus.
     *
     * @hide
     */
    public void hideHint() {
        if (isShowingHint()) {
            mHideHint = true;
            invalidate();
        }
    }
    /**
     * Returns if the text is constrained to a single horizontally scrolling line ignoring new
     * line characters instead of letting it wrap onto multiple lines.
@@ -8904,7 +8921,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        Layout layout = mLayout;
        if (mHint != null && mText.length() == 0) {
        if (mHint != null && !mHideHint && mText.length() == 0) {
            if (mHintTextColor != null) {
                color = mCurHintTextColor;
            }
@@ -11223,7 +11240,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }
    private boolean isShowingHint() {
        return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint);
        return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint) && !mHideHint;
    }
    /**
@@ -12367,6 +12384,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        sendOnTextChanged(buffer, start, before, after);
        onTextChanged(buffer, start, before, after);
        mHideHint = false;
        clearGesturePreviewHighlight();
    }
@@ -12507,6 +12525,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            return;
        }
        mHideHint = false;
        if (mEditor != null) mEditor.onFocusChanged(focused, direction);
        if (focused) {
+114 −0
Original line number Diff line number Diff line
@@ -23,14 +23,20 @@ import static android.view.stylus.HandwritingTestUtil.createView;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.HandwritingInitiator;
@@ -38,7 +44,9 @@ import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -47,6 +55,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

/**
 * Tests for {@link HandwritingInitiator}
@@ -543,6 +552,111 @@ public class HandwritingInitiatorTest {
        assertThat(mHandwritingInitiator.mConnectedView.get()).isEqualTo(mTestView1);
    }

    @Test
    public void startHandwriting_hidesHint() {
        EditText editText =
                new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
        editText.setHint("hint");
        editText.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

        verifyEditTextDrawsText(editText, "hint");

        mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
        mHandwritingInitiator.startHandwriting(editText);

        verifyEditTextDrawsText(editText, null);
    }

    @Test
    public void startHandwriting_clearFocus_restoresHint() {
        EditText editText =
                new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
        editText.setHint("hint");
        editText.setLayoutParams(new ViewGroup.LayoutParams(1024, 1024));
        editText.requestFocus();

        verifyEditTextDrawsText(editText, "hint");

        mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
        mHandwritingInitiator.startHandwriting(editText);

        verifyEditTextDrawsText(editText, null);

        editText.clearFocus();

        verifyEditTextDrawsText(editText, "hint");
    }

    @Test
    public void startHandwriting_setHint_restoresHint() {
        EditText editText =
                new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
        editText.setHint("hint");
        editText.setLayoutParams(new ViewGroup.LayoutParams(1024, 1024));

        verifyEditTextDrawsText(editText, "hint");

        mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
        mHandwritingInitiator.startHandwriting(editText);

        verifyEditTextDrawsText(editText, null);

        editText.setHint("new hint");

        verifyEditTextDrawsText(editText, "new hint");
    }

    @Test
    public void startHandwriting_setText_restoresHint() {
        EditText editText =
                new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
        editText.setHint("hint");
        editText.setLayoutParams(new ViewGroup.LayoutParams(1024, 1024));

        verifyEditTextDrawsText(editText, "hint");

        mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
        mHandwritingInitiator.startHandwriting(editText);

        verifyEditTextDrawsText(editText, null);

        editText.setText("a");
        editText.setText("");

        verifyEditTextDrawsText(editText, "hint");
    }

    private void verifyEditTextDrawsText(EditText editText, String text) {
        editText.measure(
                View.MeasureSpec.makeMeasureSpec(1024, View.MeasureSpec.AT_MOST),
                View.MeasureSpec.makeMeasureSpec(1024, View.MeasureSpec.AT_MOST));
        Canvas canvas = prepareMockCanvas(editText);
        editText.draw(canvas);
        if (text != null) {
            ArgumentCaptor<CharSequence> textCaptor = ArgumentCaptor.forClass(CharSequence.class);
            verify(canvas).drawText(
                    textCaptor.capture(), anyInt(), anyInt(), anyFloat(), anyFloat(), any());
            assertThat(textCaptor.getValue().toString()).isEqualTo(text);
        } else {
            verify(canvas, never()).drawText(
                    any(CharSequence.class), anyInt(), anyInt(), anyFloat(), anyFloat(), any());
        }
    }

    private Canvas prepareMockCanvas(View view) {
        Canvas canvas = mock(Canvas.class);
        when(canvas.getClipBounds(any())).thenAnswer(invocation -> {
            Rect outRect = invocation.getArgument(0);
            outRect.top = 0;
            outRect.left = 0;
            outRect.right = view.getMeasuredWidth();
            outRect.bottom = view.getMeasuredHeight();
            return true;
        });
        return canvas;
    }

    private MotionEvent createStylusEvent(int action, int x, int y, long eventTime) {
        MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
        properties[0].toolType = MotionEvent.TOOL_TYPE_STYLUS;