diff options
10 files changed, 150 insertions, 538 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index f7ef26bf09df..a7f69374ff00 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -50381,6 +50381,12 @@ package android.view { field public static final int VERTICAL_GRAVITY_MASK = 112; // 0x70 } + public class HandwritingDelegateConfiguration { + ctor public HandwritingDelegateConfiguration(@IdRes int, @NonNull Runnable); + method public int getDelegatorViewId(); + method @NonNull public Runnable getInitiationCallback(); + } + public class HapticFeedbackConstants { field public static final int CLOCK_TICK = 4; // 0x4 field public static final int CONFIRM = 16; // 0x10 @@ -51978,8 +51984,6 @@ package android.view { method @Nullable public CharSequence getAccessibilityPaneTitle(); method @IdRes public int getAccessibilityTraversalAfter(); method @IdRes public int getAccessibilityTraversalBefore(); - method @NonNull public String getAllowedHandwritingDelegatePackageName(); - method @NonNull public String getAllowedHandwritingDelegatorPackageName(); method public float getAlpha(); method public android.view.animation.Animation getAnimation(); method @Nullable public android.graphics.Matrix getAnimationMatrix(); @@ -52035,7 +52039,7 @@ package android.view { method public float getHandwritingBoundsOffsetLeft(); method public float getHandwritingBoundsOffsetRight(); method public float getHandwritingBoundsOffsetTop(); - method @Nullable public Runnable getHandwritingDelegatorCallback(); + method @Nullable public android.view.HandwritingDelegateConfiguration getHandwritingDelegateConfiguration(); method public final boolean getHasOverlappingRendering(); method public final int getHeight(); method public void getHitRect(android.graphics.Rect); @@ -52191,7 +52195,6 @@ package android.view { method public boolean isFocused(); method public final boolean isFocusedByDefault(); method public boolean isForceDarkAllowed(); - method public boolean isHandwritingDelegate(); method public boolean isHapticFeedbackEnabled(); method public boolean isHardwareAccelerated(); method public boolean isHorizontalFadingEdgeEnabled(); @@ -52362,8 +52365,6 @@ package android.view { method public void setAccessibilityTraversalBefore(@IdRes int); method public void setActivated(boolean); method public void setAllowClickWhenDisabled(boolean); - method public void setAllowedHandwritingDelegatePackage(@NonNull String); - method public void setAllowedHandwritingDelegatorPackage(@NonNull String); method public void setAlpha(@FloatRange(from=0.0, to=1.0) float); method public void setAnimation(android.view.animation.Animation); method public void setAnimationMatrix(@Nullable android.graphics.Matrix); @@ -52406,7 +52407,7 @@ package android.view { method public void setForegroundTintList(@Nullable android.content.res.ColorStateList); method public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode); method public void setHandwritingBoundsOffsets(float, float, float, float); - method public void setHandwritingDelegatorCallback(@Nullable Runnable); + method public void setHandwritingDelegateConfiguration(@Nullable android.view.HandwritingDelegateConfiguration); method public void setHapticFeedbackEnabled(boolean); method public void setHasTransientState(boolean); method public void setHorizontalFadingEdgeEnabled(boolean); @@ -52419,7 +52420,6 @@ package android.view { method public void setImportantForAutofill(int); method public void setImportantForContentCapture(int); method public void setIsCredential(boolean); - method public void setIsHandwritingDelegate(boolean); method public void setKeepScreenOn(boolean); method public void setKeyboardNavigationCluster(boolean); method public void setLabelFor(@IdRes int); @@ -55618,8 +55618,6 @@ package android.view.inputmethod { } public final class InputMethodManager { - method public boolean acceptStylusHandwritingDelegation(@NonNull android.view.View); - method public boolean acceptStylusHandwritingDelegation(@NonNull android.view.View, @NonNull String); method public void dispatchKeyEventFromInputMethod(@Nullable android.view.View, @NonNull android.view.KeyEvent); method public void displayCompletions(android.view.View, android.view.inputmethod.CompletionInfo[]); method @Nullable public android.view.inputmethod.InputMethodInfo getCurrentInputMethodInfo(); @@ -55641,8 +55639,6 @@ package android.view.inputmethod { method public boolean isInputMethodSuppressingSpellChecker(); method public boolean isStylusHandwritingAvailable(); method @Deprecated public boolean isWatchingCursor(android.view.View); - method public void prepareStylusHandwritingDelegation(@NonNull android.view.View); - method public void prepareStylusHandwritingDelegation(@NonNull android.view.View, @NonNull String); method public void restartInput(android.view.View); method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle); method @Deprecated public void setAdditionalInputMethodSubtypes(@NonNull String, @NonNull android.view.inputmethod.InputMethodSubtype[]); diff --git a/core/java/android/view/HandwritingDelegateConfiguration.java b/core/java/android/view/HandwritingDelegateConfiguration.java new file mode 100644 index 000000000000..719c614f42f0 --- /dev/null +++ b/core/java/android/view/HandwritingDelegateConfiguration.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.annotation.IdRes; +import android.annotation.NonNull; + +/** + * Configuration for a view to act as a handwriting initiation delegate. This allows handwriting + * mode for a delegator editor view to be initiated by stylus movement on the delegate view. + * + * <p>If a stylus {@link MotionEvent} occurs within the delegate view's bounds, the callback + * returned by {@link #getInitiationCallback()} will be called. The callback implementation is + * expected to show and focus the delegator editor view. If a view with identifier matching {@link + * #getDelegatorViewId()} creates an input connection while the same stylus {@link MotionEvent} + * sequence is ongoing, handwriting mode will be initiated for that view. + * + * <p>A common use case is a custom view which looks like a text editor but does not actually + * support text editing itself, and clicking on the custom view causes an EditText to be shown. To + * support handwriting initiation in this case, {@link View#setHandwritingDelegateConfiguration} can + * be called on the custom view to configure it as a delegate, and set the EditText as the delegator + * by passing the EditText's identifier as the {@code delegatorViewId}. The {@code + * initiationCallback} implementation is typically the same as the click listener implementation + * which shows the EditText. + */ +public class HandwritingDelegateConfiguration { + @IdRes private final int mDelegatorViewId; + @NonNull private final Runnable mInitiationCallback; + + /** + * Constructs a HandwritingDelegateConfiguration instance. + * + * @param delegatorViewId identifier of the delegator editor view for which handwriting mode + * should be initiated + * @param initiationCallback callback called when a stylus {@link MotionEvent} occurs within + * this view's bounds. This will be called from the UI thread. + */ + public HandwritingDelegateConfiguration( + @IdRes int delegatorViewId, @NonNull Runnable initiationCallback) { + mDelegatorViewId = delegatorViewId; + mInitiationCallback = initiationCallback; + } + + /** + * Returns the identifier of the delegator editor view for which handwriting mode should be + * initiated. + */ + public int getDelegatorViewId() { + return mDelegatorViewId; + } + + /** + * Returns the callback which should be called when a stylus {@link MotionEvent} occurs within + * the delegate view's bounds. The callback should only be called from the UI thread. + */ + @NonNull + public Runnable getInitiationCallback() { + return mInitiationCallback; + } +} diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index 98f61a366381..8d221ab0b70a 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.IdRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -171,11 +172,15 @@ public class HandwritingInitiator { if (candidateView != null) { if (candidateView == getConnectedView()) { startHandwriting(candidateView); - } else if (candidateView.getHandwritingDelegatorCallback() != null) { - mImm.prepareStylusHandwritingDelegation( - candidateView, - candidateView.getAllowedHandwritingDelegatePackageName()); - candidateView.getHandwritingDelegatorCallback().run(); + } else if (candidateView.getHandwritingDelegateConfiguration() != null) { + mState.mDelegatorViewId = + candidateView + .getHandwritingDelegateConfiguration() + .getDelegatorViewId(); + candidateView + .getHandwritingDelegateConfiguration() + .getInitiationCallback() + .run(); } else { if (candidateView.getRevealOnFocusHint()) { candidateView.setRevealOnFocusHint(false); @@ -222,9 +227,6 @@ public class HandwritingInitiator { } else { mConnectedView = new WeakReference<>(view); mConnectionCount = 1; - if (view.isHandwritingDelegate() && tryAcceptStylusHandwritingDelegation(view)) { - return; - } if (mState != null && mState.mShouldInitHandwriting) { tryStartHandwriting(); } @@ -277,15 +279,17 @@ public class HandwritingInitiator { } final Rect handwritingArea = getViewHandwritingArea(connectedView); - if (isInHandwritingArea( - handwritingArea, mState.mStylusDownX, mState.mStylusDownY, connectedView)) { + if ((mState.mDelegatorViewId != View.NO_ID + && mState.mDelegatorViewId == connectedView.getId()) + || isInHandwritingArea( + handwritingArea, mState.mStylusDownX, mState.mStylusDownY, connectedView)) { startHandwriting(connectedView); } else { mState.mShouldInitHandwriting = false; } } - /** Starts a stylus handwriting session for the view. */ + /** For test only. */ @VisibleForTesting public void startHandwriting(@NonNull View view) { mImm.startStylusHandwriting(view); @@ -294,23 +298,6 @@ public class HandwritingInitiator { } /** - * Starts a stylus handwriting session for the delegate view, if {@link - * InputMethodManager#prepareStylusHandwritingDelegation} was previously called. - */ - @VisibleForTesting - public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) { - if (mImm.acceptStylusHandwritingDelegation( - view, view.getAllowedHandwritingDelegatorPackageName())) { - if (mState != null) { - mState.mHasInitiatedHandwriting = true; - mState.mShouldInitHandwriting = false; - } - return true; - } - return false; - } - - /** * Notify that the handwriting area for the given view might be updated. * @param view the view whose handwriting area might be updated. */ @@ -555,6 +542,13 @@ public class HandwritingInitiator { * built InputConnection. */ private boolean mExceedHandwritingSlop; + /** + * If the current ongoing stylus MotionEvent sequence started over a handwriting initiation + * delegate view, then this is the view identifier of the corresponding delegator view. If + * the delegator view creates an input connection while the MotionEvent sequence is still + * ongoing, then handwriting mode will be initiated for the delegator view. + */ + @IdRes private int mDelegatorViewId = View.NO_ID; /** The pointer id of the stylus pointer that is being tracked. */ private final int mStylusPointerId; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index fee20517a499..7d18bf082bcb 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5101,13 +5101,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private boolean mHoveringTouchDelegate = false; - // These two fields are set if the view is a handwriting delegator. - private Runnable mHandwritingDelegatorCallback; - private String mAllowedHandwritingDelegatePackageName; - - // These two fields are set if the view is a handwriting delegate. - private boolean mIsHandwritingDelegate; - private String mAllowedHandwritingDelegatorPackageName; + /** + * Configuration for this view to act as a handwriting initiation delegate. This allows + * handwriting mode for a delegator editor view to be initiated by stylus movement on this + * delegate view. + */ + private HandwritingDelegateConfiguration mHandwritingDelegateConfiguration; /** * Solid color to use as a background when creating the drawing cache. Enables @@ -12411,168 +12410,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this - * view's bounds. The callback will be called from the UI thread. - * - * <p>Setting a callback allows this view to act as a handwriting delegator, so that handwriting - * mode for a delegate editor view can be initiated by stylus movement on this delegator view. - * The callback implementation is expected to show and focus the delegate editor view. If a view - * which returns {@code true} for {@link #isHandwritingDelegate()} creates an input connection - * while the same stylus {@link MotionEvent} sequence is ongoing, handwriting mode will be - * initiated for that view. - * - * <p>A common use case is a custom view which looks like a text editor but does not actually - * support text editing itself, and clicking on the custom view causes an EditText to be shown. - * To support handwriting initiation in this case, this method can be called on the custom view - * to configure it as a delegator. The EditText should call {@link #setIsHandwritingDelegate} to - * set it as a delegate. The {@code callback} implementation is typically the same as the click - * listener implementation which shows the EditText. + * Configures this view to act as a handwriting initiation delegate. This allows handwriting + * mode for a delegator editor view to be initiated by stylus movement on this delegate view. * * <p>If {@code null} is passed, this view will no longer act as a handwriting initiation - * delegator. - * - * @param callback a callback which should be called when a stylus {@link MotionEvent} occurs - * within this view's bounds + * delegate. */ - public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { - mHandwritingDelegatorCallback = callback; - if (callback != null) { - // By default, the delegate must be from the same package as the delegator view. - mAllowedHandwritingDelegatePackageName = mContext.getOpPackageName(); + public void setHandwritingDelegateConfiguration( + @Nullable HandwritingDelegateConfiguration configuration) { + mHandwritingDelegateConfiguration = configuration; + if (configuration != null) { setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); - } else { - mAllowedHandwritingDelegatePackageName = null; } } /** - * Returns the callback set by {@link #setHandwritingDelegatorCallback} which should be called - * when a stylus {@link MotionEvent} occurs within this view's bounds. The callback should only - * be called from the UI thread. + * If this view has been configured as a handwriting initiation delegate, returns the delegate + * configuration. */ @Nullable - public Runnable getHandwritingDelegatorCallback() { - return mHandwritingDelegatorCallback; - } - - /** - * Specifies that this view may act as a handwriting initiation delegator for a delegate editor - * view from the specified package. If this method is not called, delegators may only be used to - * initiate handwriting mode for a delegate editor view from the same package as the delegator - * view. This method allows specifying a different trusted package which may contain a delegate - * editor view linked to this delegator view. This should be called after {@link - * #setHandwritingDelegatorCallback}. - * - * <p>If this method is called on the delegator view, then {@link - * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view. - * - * <p>For example, to configure a delegator view in package 1: - * - * <pre> - * delegatorView.setHandwritingDelegatorCallback(callback); - * delegatorView.setAllowedHandwritingDelegatePackage(package2);</pre> - * - * Then to configure the corresponding delegate editor view in package 2: - * - * <pre> - * delegateEditorView.setIsHandwritingDelegate(true); - * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);</pre> - * - * @param allowedPackageName the package name of a delegate editor view linked to this delegator - * view - * @throws IllegalStateException If the view has not been configured as a handwriting delegator - * using {@link #setHandwritingDelegatorCallback}. - */ - public void setAllowedHandwritingDelegatePackage(@NonNull String allowedPackageName) { - if (mHandwritingDelegatorCallback == null) { - throw new IllegalStateException("This view is not a handwriting delegator."); - } - mAllowedHandwritingDelegatePackageName = allowedPackageName; - } - - /** - * Returns the allowed package for delegate editor views for which this view may act as a - * handwriting delegator. If {@link #setAllowedHandwritingDelegatePackage} has not been called, - * this will return this view's package name, since by default delegators may only be used to - * initiate handwriting mode for a delegate editor view from the same package as the delegator - * view. This will return a different allowed package if set by {@link - * #setAllowedHandwritingDelegatePackage}. - * - * @throws IllegalStateException If the view has not been configured as a handwriting delegator - * using {@link #setHandwritingDelegatorCallback}. - */ - @NonNull - public String getAllowedHandwritingDelegatePackageName() { - if (mHandwritingDelegatorCallback == null) { - throw new IllegalStateException("This view is not a handwriting delegator."); - } - return mAllowedHandwritingDelegatePackageName; - } - - /** - * Sets this view to be a handwriting delegate. If a delegate view creates an input connection - * while a stylus {@link MotionEvent} sequence from a delegator view is ongoing, handwriting - * mode will be initiated for the delegate view. - * - * @param isHandwritingDelegate whether this view is a handwriting initiation delegate - * @see #setHandwritingDelegatorCallback(Runnable) - */ - public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { - mIsHandwritingDelegate = isHandwritingDelegate; - if (mIsHandwritingDelegate) { - // By default, the delegator must be from the same package as the delegate view. - mAllowedHandwritingDelegatorPackageName = mContext.getOpPackageName(); - } else { - mAllowedHandwritingDelegatePackageName = null; - } - } - - /** - * Returns whether this view has been set as a handwriting delegate by {@link - * #setIsHandwritingDelegate}. - */ - public boolean isHandwritingDelegate() { - return mIsHandwritingDelegate; - } - - /** - * Specifies that a view from the specified package may act as a handwriting delegator for this - * delegate editor view. If this method is not called, only views from the same package as the - * delegate editor view may act as a handwriting delegator. This method allows specifying a - * different trusted package which may contain a delegator view linked to this delegate editor - * view. This should be called after {@link #setIsHandwritingDelegate}. - * - * <p>If this method is called on the delegate editor view, then {@link - * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view. - * - * @param allowedPackageName the package name of a delegator view linked to this delegate editor - * view - * @throws IllegalStateException If the view has not been configured as a handwriting delegate - * using {@link #setIsHandwritingDelegate}. - */ - public void setAllowedHandwritingDelegatorPackage(@NonNull String allowedPackageName) { - if (!mIsHandwritingDelegate) { - throw new IllegalStateException("This view is not a handwriting delegate."); - } - mAllowedHandwritingDelegatorPackageName = allowedPackageName; - } - - /** - * Returns the allowed package for views which may act as a handwriting delegator for this - * delegate editor view. If {@link #setAllowedHandwritingDelegatorPackage} has not been called, - * this will return this view's package name, since by default only views from the same package - * as the delegator editor view may act as a handwriting delegator. This will return a different - * allowed package if set by {@link #setAllowedHandwritingDelegatorPackage}. - * - * @throws IllegalStateException If the view has not been configured as a handwriting delegate - * using {@link #setIsHandwritingDelegate}. - */ - @NonNull - public String getAllowedHandwritingDelegatorPackageName() { - if (!mIsHandwritingDelegate) { - throw new IllegalStateException("This view is not a handwriting delegate."); - } - return mAllowedHandwritingDelegatorPackageName; + public HandwritingDelegateConfiguration getHandwritingDelegateConfiguration() { + return mHandwritingDelegateConfiguration; } /** @@ -24616,7 +24474,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } rebuildOutline(); - if (onCheckIsTextEditor() || mHandwritingDelegatorCallback != null) { + if (onCheckIsTextEditor() || mHandwritingDelegateConfiguration != null) { setHandwritingArea(new Rect(0, 0, newWidth, newHeight)); } } diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java index db17a533c303..966026198a21 100644 --- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java +++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java @@ -505,40 +505,6 @@ final class IInputMethodManagerGlobalInvoker { } @AnyThread - static void prepareStylusHandwritingDelegation( - @NonNull IInputMethodClient client, - @NonNull String delegatePackageName, - @NonNull String delegatorPackageName) { - final IInputMethodManager service = getService(); - if (service == null) { - return; - } - try { - service.prepareStylusHandwritingDelegation( - client, delegatePackageName, delegatorPackageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - @AnyThread - static boolean acceptStylusHandwritingDelegation( - @NonNull IInputMethodClient client, - @NonNull String delegatePackageName, - @NonNull String delegatorPackageName) { - final IInputMethodManager service = getService(); - if (service == null) { - return false; - } - try { - return service.acceptStylusHandwritingDelegation( - client, delegatePackageName, delegatorPackageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - @AnyThread @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) static boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) { final IInputMethodManager service = getService(); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 36d2b8a89779..642182b5ddfd 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -99,7 +99,6 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; -import android.widget.Editor; import android.window.ImeOnBackInvokedDispatcher; import android.window.WindowOnBackInvokedDispatcher; @@ -1553,7 +1552,11 @@ public final class InputMethodManager { if (fallbackContext == null) { return false; } - if (!isStylusHandwritingEnabled(fallbackContext)) { + if (Settings.Global.getInt(fallbackContext.getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 0) { + if (DEBUG) { + Log.d(TAG, "Stylus handwriting is not enabled in settings."); + } return false; } return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(userId); @@ -2230,173 +2233,35 @@ public final class InputMethodManager { * @see #isStylusHandwritingAvailable() */ public void startStylusHandwriting(@NonNull View view) { - startStylusHandwritingInternal(view, null /* delegatorPackageName */); - } - - private boolean startStylusHandwritingInternal( - @NonNull View view, @Nullable String delegatorPackageName) { - Objects.requireNonNull(view); - // Re-dispatch if there is a context mismatch. final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); if (fallbackImm != null) { - fallbackImm.startStylusHandwritingInternal(view, delegatorPackageName); + fallbackImm.startStylusHandwriting(view); } + Objects.requireNonNull(view); - boolean useDelegation = !TextUtils.isEmpty(delegatorPackageName); - if (!isStylusHandwritingEnabled(view.getContext())) { - Log.w(TAG, "Stylus handwriting pref is disabled. " - + "Ignoring calls to start stylus handwriting."); - return false; + if (Settings.Global.getInt(view.getContext().getContentResolver(), + Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 0) { + Log.d(TAG, "Ignoring startStylusHandwriting(view) as stylus handwriting is disabled"); + return; } checkFocus(); synchronized (mH) { if (!hasServedByInputMethodLocked(view)) { Log.w(TAG, - "Ignoring startStylusHandwriting as view=" + view + " is not served."); - return false; + "Ignoring startStylusHandwriting() as view=" + view + " is not served."); + return; } if (view.getViewRootImpl() != mCurRootView) { - Log.w(TAG, - "Ignoring startStylusHandwriting: View's window does not have focus."); - return false; - } - if (useDelegation) { - return IInputMethodManagerGlobalInvoker.acceptStylusHandwritingDelegation( - mClient, view.getContext().getOpPackageName(), delegatorPackageName); - } else { - IInputMethodManagerGlobalInvoker.startStylusHandwriting(mClient); + Log.w(TAG, "Ignoring startStylusHandwriting: View's window does not have focus."); + return; } - return false; - } - } - private boolean isStylusHandwritingEnabled(@NonNull Context context) { - if (Settings.Global.getInt(context.getContentResolver(), - Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 0) { - Log.d(TAG, "Stylus handwriting pref is disabled."); - return false; + IInputMethodManagerGlobalInvoker.startStylusHandwriting(mClient); + // TODO(b/210039666): do we need any extra work for supporting non-native + // UI toolkits? } - return true; - } - - /** - * Prepares delegation of starting stylus handwriting session to a different editor in same - * or different window than the view on which initial handwriting stroke was detected. - * - * Delegation can be used to start stylus handwriting session before the {@link Editor} view or - * its {@link InputConnection} is started. Calling this method starts buffering of stylus - * motion events until {@link #acceptStylusHandwritingDelegation(View)} is called, at which - * point the handwriting session can be started and the buffered stylus motion events will be - * delivered to the IME. - * e.g. Delegation can be used when initial handwriting stroke is - * on a pseudo {@link Editor} like widget (with no {@link InputConnection}) but actual - * {@link Editor} is on a different window. - * - * <p> Note: If an actual {@link Editor} capable of {@link InputConnection} is being scribbled - * upon using stylus, use {@link #startStylusHandwriting(View)} instead.</p> - * - * @param delegatorView the view that receives initial stylus stroke and delegates it to the - * actual editor. Its window must {@link View#hasWindowFocus have focus}. - * @see #prepareStylusHandwritingDelegation(View, String) - * @see #acceptStylusHandwritingDelegation(View) - * @see #startStylusHandwriting(View) - */ - public void prepareStylusHandwritingDelegation(@NonNull View delegatorView) { - prepareStylusHandwritingDelegation( - delegatorView, delegatorView.getContext().getOpPackageName()); - } - - /** - * Prepares delegation of starting stylus handwriting session to a different editor in same or a - * different window in a different package than the view on which initial handwriting stroke - * was detected. - * - * Delegation can be used to start stylus handwriting session before the {@link Editor} view or - * its {@link InputConnection} is started. Calling this method starts buffering of stylus - * motion events until {@link #acceptStylusHandwritingDelegation(View, String)} is called, at - * which point the handwriting session can be started and the buffered stylus motion events will - * be delivered to the IME. - * e.g. Delegation can be used when initial handwriting stroke is - * on a pseudo {@link Editor} like widget (with no {@link InputConnection}) but actual - * {@link Editor} is on a different window in the given package. - * - * <p>Note: If delegator and delegate are in same package use - * {@link #prepareStylusHandwritingDelegation(View)} instead.</p> - * - * @param delegatorView the view that receives initial stylus stroke and delegates it to the - * actual editor. Its window must {@link View#hasWindowFocus have focus}. - * @param delegatePackageName package name that contains actual {@link Editor} which should - * start stylus handwriting session by calling {@link #acceptStylusHandwritingDelegation}. - * @see #prepareStylusHandwritingDelegation(View) - * @see #acceptStylusHandwritingDelegation(View, String) - */ - public void prepareStylusHandwritingDelegation( - @NonNull View delegatorView, @NonNull String delegatePackageName) { - Objects.requireNonNull(delegatorView); - Objects.requireNonNull(delegatePackageName); - - // Re-dispatch if there is a context mismatch. - final InputMethodManager fallbackImm = - getFallbackInputMethodManagerIfNecessary(delegatorView); - if (fallbackImm != null) { - fallbackImm.prepareStylusHandwritingDelegation(delegatorView, delegatePackageName); - } - - if (!isStylusHandwritingEnabled(delegatorView.getContext())) { - Log.w(TAG, "Stylus handwriting pref is disabled. " - + "Ignoring prepareStylusHandwritingDelegation()."); - return; - } - IInputMethodManagerGlobalInvoker.prepareStylusHandwritingDelegation( - mClient, - delegatePackageName, - delegatorView.getContext().getOpPackageName()); - } - - /** - * Accepts and starts a stylus handwriting session on the delegate view, if handwriting - * initiation delegation was previously requested using - * {@link #prepareStylusHandwritingDelegation(View)} from the delegator. - * - * <p>Note: If delegator and delegate are in different application packages, use - * {@link #acceptStylusHandwritingDelegation(View, String)} instead.</p> - * - * @param delegateView delegate view capable of receiving input via {@link InputConnection} - * on which {@link #startStylusHandwriting(View)} will be called. - * @return {@code true} if view belongs to same application package as used in - * {@link #prepareStylusHandwritingDelegation(View)} and handwriting session can start. - * @see #acceptStylusHandwritingDelegation(View, String) - * @see #prepareStylusHandwritingDelegation(View) - */ - public boolean acceptStylusHandwritingDelegation(@NonNull View delegateView) { - return startStylusHandwritingInternal( - delegateView, delegateView.getContext().getOpPackageName()); - } - - /** - * Accepts and starts a stylus handwriting session on the delegate view, if handwriting - * initiation delegation was previously requested using - * {@link #prepareStylusHandwritingDelegation(View, String)} from te delegator and the view - * belongs to a specified delegate package. - * - * <p>Note: If delegator and delegate are in same application package use - * {@link #acceptStylusHandwritingDelegation(View)} instead.</p> - * - * @param delegateView delegate view capable of receiving input via {@link InputConnection} - * on which {@link #startStylusHandwriting(View)} will be called. - * @param delegatorPackageName package name of the delegator that handled initial stylus stroke. - * @return {@code true} if view belongs to allowed delegate package declared in - * {@link #prepareStylusHandwritingDelegation(View, String)} and handwriting session can start. - * @see #prepareStylusHandwritingDelegation(View, String) - * @see #acceptStylusHandwritingDelegation(View) - */ - public boolean acceptStylusHandwritingDelegation( - @NonNull View delegateView, @NonNull String delegatorPackageName) { - Objects.requireNonNull(delegatorPackageName); - - return startStylusHandwritingInternal(delegateView, delegatorPackageName); } /** diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 5805d0e050d1..9116cb3ec9fa 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -148,15 +148,6 @@ interface IInputMethodManager { /** Start Stylus handwriting session **/ void startStylusHandwriting(in IInputMethodClient client); - /** Prepares delegation of starting stylus handwriting session to a different editor **/ - void prepareStylusHandwritingDelegation(in IInputMethodClient client, - in String delegatePackageName, - in String delegatorPackageName); - - /** Accepts and starts a stylus handwriting session for the delegate view **/ - boolean acceptStylusHandwritingDelegation(in IInputMethodClient client, - in String delegatePackageName, in String delegatorPackageName); - /** Returns {@code true} if currently selected IME supports Stylus handwriting. */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)") diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java index 76f5277cfe0b..95aa5d0de119 100644 --- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java +++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java @@ -32,6 +32,7 @@ import android.app.Instrumentation; import android.content.Context; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.view.HandwritingDelegateConfiguration; import android.view.HandwritingInitiator; import android.view.InputDevice; import android.view.MotionEvent; @@ -209,11 +210,14 @@ public class HandwritingInitiatorTest { @Test public void onTouchEvent_startHandwriting_delegate() { - View delegateView = new View(mContext); - delegateView.setIsHandwritingDelegate(true); + int delegatorViewId = 234; + View delegatorView = new View(mContext); + delegatorView.setId(delegatorViewId); - mTestView.setHandwritingDelegatorCallback( - () -> mHandwritingInitiator.onInputConnectionCreated(delegateView)); + mTestView.setHandwritingDelegateConfiguration( + new HandwritingDelegateConfiguration( + delegatorViewId, + () -> mHandwritingInitiator.onInputConnectionCreated(delegatorView))); final int x1 = (sHwArea.left + sHwArea.right) / 2; final int y1 = (sHwArea.top + sHwArea.bottom) / 2; @@ -225,7 +229,7 @@ public class HandwritingInitiatorTest { MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0); mHandwritingInitiator.onTouchEvent(stylusEvent2); - verify(mHandwritingInitiator, times(1)).tryAcceptStylusHandwritingDelegation(delegateView); + verify(mHandwritingInitiator, times(1)).startHandwriting(delegatorView); } @Test diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java index eb4dba63dea9..1c7294f8a9d5 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java @@ -20,14 +20,12 @@ import static android.view.InputDevice.SOURCE_STYLUS; import android.Manifest; import android.annotation.AnyThread; -import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UiThread; import android.hardware.input.InputManager; import android.os.IBinder; import android.os.Looper; -import android.text.TextUtils; import android.util.Slog; import android.view.BatchedInputEventReceiver; import android.view.Choreographer; @@ -37,8 +35,6 @@ import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.MotionEvent; import android.view.SurfaceControl; -import android.view.View; -import android.view.inputmethod.InputMethodManager; import com.android.server.LocalServices; import com.android.server.input.InputManagerInternal; @@ -56,9 +52,6 @@ final class HandwritingModeController { // TODO(b/210039666): flip the flag. static final boolean DEBUG = true; private static final int EVENT_BUFFER_SIZE = 100; - // A longer event buffer used for handwriting delegation - // TODO(b/210039666): make this device touch sampling rate dependent. - private static final int LONG_EVENT_BUFFER = EVENT_BUFFER_SIZE * 20; // This must be the looper for the UiThread. private final Looper mLooper; @@ -70,9 +63,6 @@ final class HandwritingModeController { private Runnable mInkWindowInitRunnable; private boolean mRecordingGesture; private int mCurrentDisplayId; - // when set, package names are used for handwriting delegation. - private @Nullable String mDelegatePackageName; - private @Nullable String mDelegatorPackageName; private HandwritingEventReceiverSurface mHandwritingSurface; @@ -147,41 +137,6 @@ final class HandwritingModeController { return mRecordingGesture; } - boolean hasOngoingStylusHandwritingSession() { - return mHandwritingSurface != null && mHandwritingSurface.isIntercepting(); - } - - /** - * Prepare delegation of stylus handwriting to a different editor - * @see InputMethodManager#prepareStylusHandwritingDelegation(View, String) - */ - void prepareStylusHandwritingDelegation( - @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { - mDelegatePackageName = delegatePackageName; - mDelegatorPackageName = delegatorPackageName; - ((ArrayList) mHandwritingBuffer).ensureCapacity(LONG_EVENT_BUFFER); - // TODO(b/210039666): cancel delegation after a timeout or next input method client binding. - } - - @Nullable String getDelegatePackageName() { - return mDelegatePackageName; - } - - @Nullable String getDelegatorPackageName() { - return mDelegatorPackageName; - } - - /** - * Clear any pending handwriting delegation info. - */ - void clearPendingHandwritingDelegation() { - if (DEBUG) { - Slog.d(TAG, "clearPendingHandwritingDelegation"); - } - mDelegatorPackageName = null; - mDelegatePackageName = null; - } - /** * Starts a {@link HandwritingSession} to transfer to the IME. * @@ -268,7 +223,6 @@ final class HandwritingModeController { } } - clearPendingHandwritingDelegation(); mRecordingGesture = false; } @@ -305,10 +259,7 @@ final class HandwritingModeController { mInkWindowInitRunnable = null; } - // If handwriting delegation is ongoing, don't clear the buffer so that multiple strokes - // can be buffered across windows. - if (TextUtils.isEmpty(mDelegatePackageName) - && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) { + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { mRecordingGesture = false; mHandwritingBuffer.clear(); return; diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 8ef4e4afae9b..f5875abe17e6 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -236,8 +236,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub private static final int MSG_FINISH_HANDWRITING = 1110; private static final int MSG_REMOVE_HANDWRITING_WINDOW = 1120; - private static final int MSG_PREPARE_HANDWRITING_DELEGATION = 1130; - private static final int MSG_SET_INTERACTIVE = 3030; private static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000; @@ -2691,14 +2689,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @AnyThread - void schedulePrepareStylusHandwritingDelegation( - @NonNull String delegatePackageName, @NonNull String delegatorPackageName) { - mHandler.obtainMessage( - MSG_PREPARE_HANDWRITING_DELEGATION, - new Pair<>(delegatePackageName, delegatorPackageName)).sendToTarget(); - } - - @AnyThread void scheduleRemoveStylusHandwritingWindow() { mHandler.obtainMessage(MSG_REMOVE_HANDWRITING_WINDOW).sendToTarget(); } @@ -3314,7 +3304,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub "InputMethodManagerService#startStylusHandwriting"); int uid = Binder.getCallingUid(); synchronized (ImfLock.class) { - mHwController.clearPendingHandwritingDelegation(); if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting", null /* statsToken */)) { return; @@ -3342,13 +3331,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub "There is no ongoing stylus gesture to start stylus handwriting."); return; } - if (mHwController.hasOngoingStylusHandwritingSession()) { - // prevent duplicate calls to startStylusHandwriting(). - Slog.e(TAG, - "Stylus handwriting session is already ongoing." - + " Ignoring startStylusHandwriting()."); - return; - } if (DEBUG) Slog.v(TAG, "Client requesting Stylus Handwriting to be started"); final IInputMethodInvoker curMethod = getCurMethodLocked(); if (curMethod != null) { @@ -3363,68 +3345,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } - @Override - public void prepareStylusHandwritingDelegation( - @NonNull IInputMethodClient client, - @NonNull String delegatePackageName, - @NonNull String delegatorPackageName) { - if (!verifyClientAndPackageMatch(client, delegatorPackageName)) { - Slog.w(TAG, "prepareStylusHandwritingDelegation() fail"); - throw new IllegalArgumentException("Delegator doesn't match Uid"); - } - schedulePrepareStylusHandwritingDelegation(delegatePackageName, delegatorPackageName); - } - - @Override - public boolean acceptStylusHandwritingDelegation( - @NonNull IInputMethodClient client, - @NonNull String delegatePackageName, - @NonNull String delegatorPackageName) { - if (!verifyDelegator(client, delegatePackageName, delegatorPackageName)) { - return false; - } - - startStylusHandwriting(client); - return true; - } - - private boolean verifyClientAndPackageMatch( - @NonNull IInputMethodClient client, @NonNull String packageName) { - ClientState cs; - synchronized (ImfLock.class) { - cs = mClients.get(client.asBinder()); - } - if (cs == null) { - throw new IllegalArgumentException("unknown client " + client.asBinder()); - } - return InputMethodUtils.checkIfPackageBelongsToUid( - mPackageManagerInternal, cs.mUid, packageName); - } - - private boolean verifyDelegator( - @NonNull IInputMethodClient client, - @NonNull String delegatePackageName, - @NonNull String delegatorPackageName) { - if (!verifyClientAndPackageMatch(client, delegatePackageName)) { - Slog.w(TAG, "Delegate package does not belong to the same user. Ignoring" - + " startStylusHandwriting"); - return false; - } - synchronized (ImfLock.class) { - if (!delegatorPackageName.equals(mHwController.getDelegatorPackageName())) { - Slog.w(TAG, - "Delegator package does not match. Ignoring startStylusHandwriting"); - return false; - } - if (!delegatePackageName.equals(mHwController.getDelegatePackageName())) { - Slog.w(TAG, - "Delegate package does not match. Ignoring startStylusHandwriting"); - return false; - } - } - return true; - } - @BinderThread @Override public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) { @@ -4932,13 +4852,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } return true; } - case MSG_PREPARE_HANDWRITING_DELEGATION: - synchronized (ImfLock.class) { - String delegate = (String) ((Pair) msg.obj).first; - String delegator = (String) ((Pair) msg.obj).second; - mHwController.prepareStylusHandwritingDelegation(delegate, delegator); - } - return true; case MSG_START_HANDWRITING: synchronized (ImfLock.class) { IInputMethodInvoker curMethod = getCurMethodLocked(); |