Loading apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -21,8 +21,11 @@ import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.TOOL_TYPE_FINGER; import static android.view.MotionEvent.TOOL_TYPE_STYLUS; import static android.view.inputmethod.Flags.initiationWithoutInputConnection; import static org.junit.Assume.assumeFalse; import android.app.Instrumentation; import android.content.Context; import android.perftests.utils.BenchmarkState; Loading Loading @@ -186,6 +189,7 @@ public class HandwritingInitiatorPerfTest { @Test public void onInputConnectionCreated() { assumeFalse(initiationWithoutInputConnection()); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final View view = new View(mContext); final EditorInfo editorInfo = new EditorInfo(); Loading @@ -199,6 +203,7 @@ public class HandwritingInitiatorPerfTest { @Test public void onInputConnectionClosed() { assumeFalse(initiationWithoutInputConnection()); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final View view = new View(mContext); while (state.keepRunning()) { Loading core/java/android/view/HandwritingInitiator.java +112 −21 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.view.inputmethod.Flags; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.Editor; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -80,6 +82,16 @@ public class HandwritingInitiator { * connections and only set mConnectedView to null when mConnectionCount is zero. */ private int mConnectionCount = 0; /** * The reference to the View that currently has focus. * This replaces mConnecteView when {@code Flags#intitiationWithoutInputConnection()} is * enabled. */ @Nullable @VisibleForTesting public WeakReference<View> mFocusedView = null; private final InputMethodManager mImm; private final int[] mTempLocation = new int[2]; Loading Loading @@ -112,9 +124,15 @@ public class HandwritingInitiator { * * If the stylus is hovering on an unconnected editor that supports handwriting, we always show * the hover icon. * TODO(b/308827131): Rename to FocusedView after Flag is flipped. */ private boolean mShowHoverIconForConnectedView = true; /** When flag is enabled, touched editors don't wait for InputConnection for initiation. * However, delegation still waits for InputConnection. */ private final boolean mInitiateWithoutConnection = Flags.initiationWithoutInputConnection(); @VisibleForTesting public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration, @NonNull InputMethodManager inputMethodManager) { Loading Loading @@ -201,8 +219,8 @@ public class HandwritingInitiator { View candidateView = findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY, /* isHover */ false); if (candidateView != null) { if (candidateView == getConnectedView()) { if (!candidateView.hasFocus()) { if (candidateView == getConnectedOrFocusedView()) { if (!mInitiateWithoutConnection && !candidateView.hasFocus()) { requestFocusWithoutReveal(candidateView); } startHandwriting(candidateView); Loading @@ -217,9 +235,18 @@ public class HandwritingInitiator { candidateView.getHandwritingDelegatorCallback().run(); mState.mHasPreparedHandwritingDelegation = true; } else { if (!mInitiateWithoutConnection) { mState.mPendingConnectedView = new WeakReference<>(candidateView); } if (!candidateView.hasFocus()) { requestFocusWithoutReveal(candidateView); } if (mInitiateWithoutConnection && updateFocusedView(candidateView, /* fromTouchEvent */ true)) { startHandwriting(candidateView); } } } } return mState.mHasInitiatedHandwriting || mState.mHasPreparedHandwritingDelegation; Loading @@ -244,11 +271,7 @@ public class HandwritingInitiator { */ public void onDelegateViewFocused(@NonNull View view) { if (view == getConnectedView()) { if (tryAcceptStylusHandwritingDelegation(view)) { // A handwriting delegate view is accepted and handwriting starts; hide the // hover icon. mShowHoverIconForConnectedView = false; } tryAcceptStylusHandwritingDelegation(view); } } Loading @@ -260,6 +283,10 @@ public class HandwritingInitiator { * @see #onInputConnectionClosed(View) */ public void onInputConnectionCreated(@NonNull View view) { if (mInitiateWithoutConnection && !view.isHandwritingDelegate()) { // When flag is enabled, only delegation continues to wait for InputConnection. return; } if (!view.isAutoHandwritingEnabled()) { clearConnectedView(); return; Loading @@ -274,12 +301,15 @@ public class HandwritingInitiator { // A new view just gain focus. By default, we should show hover icon for it. mShowHoverIconForConnectedView = true; if (view.isHandwritingDelegate() && tryAcceptStylusHandwritingDelegation(view)) { // A handwriting delegate view is accepted and handwriting starts; hide the // hover icon. // tryAcceptStylusHandwritingDelegation should set boolean below, however, we // cannot mock IMM to return true for acceptStylusDelegation(). // TODO(b/324670412): we should move any dependent tests to integration and remove // the assignment below. mShowHoverIconForConnectedView = false; return; } if (mState != null && mState.mPendingConnectedView != null if (!mInitiateWithoutConnection && mState != null && mState.mPendingConnectedView != null && mState.mPendingConnectedView.get() == view) { startHandwriting(view); } Loading @@ -293,6 +323,9 @@ public class HandwritingInitiator { * @param view the view that closed the InputConnection. */ public void onInputConnectionClosed(@NonNull View view) { if (mInitiateWithoutConnection && !view.isHandwritingDelegate()) { return; } final View connectedView = getConnectedView(); if (connectedView == null) return; if (connectedView == view) { Loading @@ -306,6 +339,48 @@ public class HandwritingInitiator { } } @Nullable private View getFocusedView() { if (mFocusedView == null) return null; return mFocusedView.get(); } /** * Clear the tracked focused view tracked for handwriting initiation. * @param view the focused view. */ public void clearFocusedView(View view) { if (view == null || mFocusedView == null) { return; } if (mFocusedView.get() == view) { mFocusedView = null; } } /** * Called when new {@link Editor} is focused. * @return {@code true} if handwriting can initiate for given view. */ @VisibleForTesting public boolean updateFocusedView(@NonNull View view, boolean fromTouchEvent) { if (!view.shouldInitiateHandwriting()) { mFocusedView = null; return false; } final View focusedView = getFocusedView(); if (focusedView != view) { mFocusedView = new WeakReference<>(view); // A new view just gain focus. By default, we should show hover icon for it. mShowHoverIconForConnectedView = true; } if (!fromTouchEvent) { tryAcceptStylusHandwritingDelegation(view); } return true; } /** Starts a stylus handwriting session for the view. */ @VisibleForTesting public void startHandwriting(@NonNull View view) { Loading @@ -324,6 +399,9 @@ public class HandwritingInitiator { */ @VisibleForTesting public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) { if (!view.isHandwritingDelegate() || (mState != null && mState.mHasInitiatedHandwriting)) { return false; } String delegatorPackageName = view.getAllowedHandwritingDelegatorPackageName(); if (delegatorPackageName == null) { Loading @@ -337,6 +415,9 @@ public class HandwritingInitiator { if (view instanceof TextView) { ((TextView) view).hideHint(); } // A handwriting delegate view is accepted and handwriting starts; hide the // hover icon. mShowHoverIconForConnectedView = false; return true; } return false; Loading Loading @@ -377,16 +458,25 @@ public class HandwritingInitiator { return PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING); } if (hoverView != getConnectedView()) { if (hoverView != getConnectedOrFocusedView()) { // The stylus is hovering on another view that supports handwriting. We should show // hover icon. Also reset the mShowHoverIconForConnectedView so that hover // icon is displayed again next time when the stylus hovers on connected view. // hover icon. Also reset the mShowHoverIconForFocusedView so that hover // icon is displayed again next time when the stylus hovers on focused view. mShowHoverIconForConnectedView = true; return PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING); } return null; } // TODO(b/308827131): Remove once Flag is flipped. private View getConnectedOrFocusedView() { if (mInitiateWithoutConnection) { return mFocusedView == null ? null : mFocusedView.get(); } else { return mConnectedView == null ? null : mConnectedView.get(); } } private View getCachedHoverTarget() { if (mCachedHoverTarget == null) { return null; Loading Loading @@ -458,20 +548,21 @@ public class HandwritingInitiator { */ @Nullable private View findBestCandidateView(float x, float y, boolean isHover) { // TODO(b/308827131): Rename to FocusedView after Flag is flipped. // If the connectedView is not null and do not set any handwriting area, it will check // whether the connectedView's boundary contains the initial stylus position. If true, // directly return the connectedView. final View connectedView = getConnectedView(); if (connectedView != null) { final View connectedOrFocusedView = getConnectedOrFocusedView(); if (connectedOrFocusedView != null) { Rect handwritingArea = mTempRect; if (getViewHandwritingArea(connectedView, handwritingArea) && isInHandwritingArea(handwritingArea, x, y, connectedView, isHover) && shouldTriggerStylusHandwritingForView(connectedView)) { if (getViewHandwritingArea(connectedOrFocusedView, handwritingArea) && isInHandwritingArea(handwritingArea, x, y, connectedOrFocusedView, isHover) && shouldTriggerStylusHandwritingForView(connectedOrFocusedView)) { if (!isHover && mState != null) { mState.mStylusDownWithinEditorBounds = contains(handwritingArea, x, y, 0f, 0f, 0f, 0f); } return connectedView; return connectedOrFocusedView; } } Loading core/java/android/view/inputmethod/InputMethodManager.java +14 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.view.inputmethod; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; import static android.view.inputmethod.Flags.initiationWithoutInputConnection; import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_IMMEDIATE; import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_MONITOR; import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID; Loading Loading @@ -1950,6 +1951,10 @@ public final class InputMethodManager { if (mServedView != null) { clearedView = mServedView; mServedView = null; if (initiationWithoutInputConnection() && clearedView.getViewRootImpl() != null) { clearedView.getViewRootImpl().getHandwritingInitiator() .clearFocusedView(clearedView); } } if (clearedView != null) { if (DEBUG) { Loading Loading @@ -2932,6 +2937,10 @@ public final class InputMethodManager { switch (res.result) { case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW: mRestartOnNextWindowFocus = true; if (initiationWithoutInputConnection()) { mServedView.getViewRootImpl().getHandwritingInitiator().clearFocusedView( mServedView); } mServedView = null; break; } Loading Loading @@ -3094,6 +3103,11 @@ public final class InputMethodManager { return false; } mServedView = mNextServedView; if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor() && mServedView.isHandwritingDelegate()) { mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused( mServedView); } if (mServedInputConnection != null) { mServedInputConnection.finishComposingTextFromImm(); } Loading core/java/android/view/inputmethod/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -62,3 +62,11 @@ flag { bug: "311791923" is_fixed_read_only: true } flag { name: "initiation_without_input_connection" namespace: "input_method" description: "Feature flag for initiating handwriting without InputConnection" bug: "308827131" is_fixed_read_only: true } core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java +91 −29 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
apct-tests/perftests/core/src/android/view/HandwritingInitiatorPerfTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -21,8 +21,11 @@ import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.TOOL_TYPE_FINGER; import static android.view.MotionEvent.TOOL_TYPE_STYLUS; import static android.view.inputmethod.Flags.initiationWithoutInputConnection; import static org.junit.Assume.assumeFalse; import android.app.Instrumentation; import android.content.Context; import android.perftests.utils.BenchmarkState; Loading Loading @@ -186,6 +189,7 @@ public class HandwritingInitiatorPerfTest { @Test public void onInputConnectionCreated() { assumeFalse(initiationWithoutInputConnection()); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final View view = new View(mContext); final EditorInfo editorInfo = new EditorInfo(); Loading @@ -199,6 +203,7 @@ public class HandwritingInitiatorPerfTest { @Test public void onInputConnectionClosed() { assumeFalse(initiationWithoutInputConnection()); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final View view = new View(mContext); while (state.keepRunning()) { Loading
core/java/android/view/HandwritingInitiator.java +112 −21 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.view.inputmethod.Flags; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.Editor; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -80,6 +82,16 @@ public class HandwritingInitiator { * connections and only set mConnectedView to null when mConnectionCount is zero. */ private int mConnectionCount = 0; /** * The reference to the View that currently has focus. * This replaces mConnecteView when {@code Flags#intitiationWithoutInputConnection()} is * enabled. */ @Nullable @VisibleForTesting public WeakReference<View> mFocusedView = null; private final InputMethodManager mImm; private final int[] mTempLocation = new int[2]; Loading Loading @@ -112,9 +124,15 @@ public class HandwritingInitiator { * * If the stylus is hovering on an unconnected editor that supports handwriting, we always show * the hover icon. * TODO(b/308827131): Rename to FocusedView after Flag is flipped. */ private boolean mShowHoverIconForConnectedView = true; /** When flag is enabled, touched editors don't wait for InputConnection for initiation. * However, delegation still waits for InputConnection. */ private final boolean mInitiateWithoutConnection = Flags.initiationWithoutInputConnection(); @VisibleForTesting public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration, @NonNull InputMethodManager inputMethodManager) { Loading Loading @@ -201,8 +219,8 @@ public class HandwritingInitiator { View candidateView = findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY, /* isHover */ false); if (candidateView != null) { if (candidateView == getConnectedView()) { if (!candidateView.hasFocus()) { if (candidateView == getConnectedOrFocusedView()) { if (!mInitiateWithoutConnection && !candidateView.hasFocus()) { requestFocusWithoutReveal(candidateView); } startHandwriting(candidateView); Loading @@ -217,9 +235,18 @@ public class HandwritingInitiator { candidateView.getHandwritingDelegatorCallback().run(); mState.mHasPreparedHandwritingDelegation = true; } else { if (!mInitiateWithoutConnection) { mState.mPendingConnectedView = new WeakReference<>(candidateView); } if (!candidateView.hasFocus()) { requestFocusWithoutReveal(candidateView); } if (mInitiateWithoutConnection && updateFocusedView(candidateView, /* fromTouchEvent */ true)) { startHandwriting(candidateView); } } } } return mState.mHasInitiatedHandwriting || mState.mHasPreparedHandwritingDelegation; Loading @@ -244,11 +271,7 @@ public class HandwritingInitiator { */ public void onDelegateViewFocused(@NonNull View view) { if (view == getConnectedView()) { if (tryAcceptStylusHandwritingDelegation(view)) { // A handwriting delegate view is accepted and handwriting starts; hide the // hover icon. mShowHoverIconForConnectedView = false; } tryAcceptStylusHandwritingDelegation(view); } } Loading @@ -260,6 +283,10 @@ public class HandwritingInitiator { * @see #onInputConnectionClosed(View) */ public void onInputConnectionCreated(@NonNull View view) { if (mInitiateWithoutConnection && !view.isHandwritingDelegate()) { // When flag is enabled, only delegation continues to wait for InputConnection. return; } if (!view.isAutoHandwritingEnabled()) { clearConnectedView(); return; Loading @@ -274,12 +301,15 @@ public class HandwritingInitiator { // A new view just gain focus. By default, we should show hover icon for it. mShowHoverIconForConnectedView = true; if (view.isHandwritingDelegate() && tryAcceptStylusHandwritingDelegation(view)) { // A handwriting delegate view is accepted and handwriting starts; hide the // hover icon. // tryAcceptStylusHandwritingDelegation should set boolean below, however, we // cannot mock IMM to return true for acceptStylusDelegation(). // TODO(b/324670412): we should move any dependent tests to integration and remove // the assignment below. mShowHoverIconForConnectedView = false; return; } if (mState != null && mState.mPendingConnectedView != null if (!mInitiateWithoutConnection && mState != null && mState.mPendingConnectedView != null && mState.mPendingConnectedView.get() == view) { startHandwriting(view); } Loading @@ -293,6 +323,9 @@ public class HandwritingInitiator { * @param view the view that closed the InputConnection. */ public void onInputConnectionClosed(@NonNull View view) { if (mInitiateWithoutConnection && !view.isHandwritingDelegate()) { return; } final View connectedView = getConnectedView(); if (connectedView == null) return; if (connectedView == view) { Loading @@ -306,6 +339,48 @@ public class HandwritingInitiator { } } @Nullable private View getFocusedView() { if (mFocusedView == null) return null; return mFocusedView.get(); } /** * Clear the tracked focused view tracked for handwriting initiation. * @param view the focused view. */ public void clearFocusedView(View view) { if (view == null || mFocusedView == null) { return; } if (mFocusedView.get() == view) { mFocusedView = null; } } /** * Called when new {@link Editor} is focused. * @return {@code true} if handwriting can initiate for given view. */ @VisibleForTesting public boolean updateFocusedView(@NonNull View view, boolean fromTouchEvent) { if (!view.shouldInitiateHandwriting()) { mFocusedView = null; return false; } final View focusedView = getFocusedView(); if (focusedView != view) { mFocusedView = new WeakReference<>(view); // A new view just gain focus. By default, we should show hover icon for it. mShowHoverIconForConnectedView = true; } if (!fromTouchEvent) { tryAcceptStylusHandwritingDelegation(view); } return true; } /** Starts a stylus handwriting session for the view. */ @VisibleForTesting public void startHandwriting(@NonNull View view) { Loading @@ -324,6 +399,9 @@ public class HandwritingInitiator { */ @VisibleForTesting public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) { if (!view.isHandwritingDelegate() || (mState != null && mState.mHasInitiatedHandwriting)) { return false; } String delegatorPackageName = view.getAllowedHandwritingDelegatorPackageName(); if (delegatorPackageName == null) { Loading @@ -337,6 +415,9 @@ public class HandwritingInitiator { if (view instanceof TextView) { ((TextView) view).hideHint(); } // A handwriting delegate view is accepted and handwriting starts; hide the // hover icon. mShowHoverIconForConnectedView = false; return true; } return false; Loading Loading @@ -377,16 +458,25 @@ public class HandwritingInitiator { return PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING); } if (hoverView != getConnectedView()) { if (hoverView != getConnectedOrFocusedView()) { // The stylus is hovering on another view that supports handwriting. We should show // hover icon. Also reset the mShowHoverIconForConnectedView so that hover // icon is displayed again next time when the stylus hovers on connected view. // hover icon. Also reset the mShowHoverIconForFocusedView so that hover // icon is displayed again next time when the stylus hovers on focused view. mShowHoverIconForConnectedView = true; return PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING); } return null; } // TODO(b/308827131): Remove once Flag is flipped. private View getConnectedOrFocusedView() { if (mInitiateWithoutConnection) { return mFocusedView == null ? null : mFocusedView.get(); } else { return mConnectedView == null ? null : mConnectedView.get(); } } private View getCachedHoverTarget() { if (mCachedHoverTarget == null) { return null; Loading Loading @@ -458,20 +548,21 @@ public class HandwritingInitiator { */ @Nullable private View findBestCandidateView(float x, float y, boolean isHover) { // TODO(b/308827131): Rename to FocusedView after Flag is flipped. // If the connectedView is not null and do not set any handwriting area, it will check // whether the connectedView's boundary contains the initial stylus position. If true, // directly return the connectedView. final View connectedView = getConnectedView(); if (connectedView != null) { final View connectedOrFocusedView = getConnectedOrFocusedView(); if (connectedOrFocusedView != null) { Rect handwritingArea = mTempRect; if (getViewHandwritingArea(connectedView, handwritingArea) && isInHandwritingArea(handwritingArea, x, y, connectedView, isHover) && shouldTriggerStylusHandwritingForView(connectedView)) { if (getViewHandwritingArea(connectedOrFocusedView, handwritingArea) && isInHandwritingArea(handwritingArea, x, y, connectedOrFocusedView, isHover) && shouldTriggerStylusHandwritingForView(connectedOrFocusedView)) { if (!isHover && mState != null) { mState.mStylusDownWithinEditorBounds = contains(handwritingArea, x, y, 0f, 0f, 0f, 0f); } return connectedView; return connectedOrFocusedView; } } Loading
core/java/android/view/inputmethod/InputMethodManager.java +14 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.view.inputmethod; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; import static android.view.inputmethod.Flags.initiationWithoutInputConnection; import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_IMMEDIATE; import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_MONITOR; import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID; Loading Loading @@ -1950,6 +1951,10 @@ public final class InputMethodManager { if (mServedView != null) { clearedView = mServedView; mServedView = null; if (initiationWithoutInputConnection() && clearedView.getViewRootImpl() != null) { clearedView.getViewRootImpl().getHandwritingInitiator() .clearFocusedView(clearedView); } } if (clearedView != null) { if (DEBUG) { Loading Loading @@ -2932,6 +2937,10 @@ public final class InputMethodManager { switch (res.result) { case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW: mRestartOnNextWindowFocus = true; if (initiationWithoutInputConnection()) { mServedView.getViewRootImpl().getHandwritingInitiator().clearFocusedView( mServedView); } mServedView = null; break; } Loading Loading @@ -3094,6 +3103,11 @@ public final class InputMethodManager { return false; } mServedView = mNextServedView; if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor() && mServedView.isHandwritingDelegate()) { mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused( mServedView); } if (mServedInputConnection != null) { mServedInputConnection.finishComposingTextFromImm(); } Loading
core/java/android/view/inputmethod/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -62,3 +62,11 @@ flag { bug: "311791923" is_fixed_read_only: true } flag { name: "initiation_without_input_connection" namespace: "input_method" description: "Feature flag for initiating handwriting without InputConnection" bug: "308827131" is_fixed_read_only: true }
core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java +91 −29 File changed.Preview size limit exceeded, changes collapsed. Show changes