Loading core/java/android/inputmethodservice/AbstractInputMethodService.java +29 −44 Original line number Diff line number Diff line Loading @@ -25,13 +25,10 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.proto.ProtoOutputStream; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodSession; import android.window.WindowProviderService; Loading Loading @@ -215,16 +212,6 @@ public abstract class AbstractInputMethodService extends WindowProviderService */ public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); /** * Dumps the internal state of IME to a protocol buffer output stream. * * @param proto ProtoOutputStream to dump data to. * @param icProto {@link InputConnection} call data in proto format. * @hide */ @SuppressWarnings("HiddenAbstractMethod") public abstract void dumpProtoInternal(ProtoOutputStream proto, @Nullable byte[] icProto); /** * Implement this to handle {@link android.os.Binder#dump Binder.dump()} * calls on your input method. Loading @@ -238,7 +225,34 @@ public abstract class AbstractInputMethodService extends WindowProviderService if (mInputMethod == null) { mInputMethod = onCreateInputMethodInterface(); } return new IInputMethodWrapper(this, mInputMethod); return new IInputMethodWrapper(createInputMethodServiceInternal(), mInputMethod); } /** * Used to inject custom {@link InputMethodServiceInternal}. * * @return the {@link InputMethodServiceInternal} to be used. */ @NonNull InputMethodServiceInternal createInputMethodServiceInternal() { return new InputMethodServiceInternal() { /** * {@inheritDoc} */ @NonNull @Override public Context getContext() { return AbstractInputMethodService.this; } /** * {@inheritDoc} */ @Override public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { AbstractInputMethodService.this.dump(fd, fout, args); } }; } /** Loading @@ -263,35 +277,6 @@ public abstract class AbstractInputMethodService extends WindowProviderService return false; } /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * * <p>Default implementation does nothing.</p> * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be * called. * @return {@code false} if we cannot allow a temporary access permission. * @hide */ public void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { return; } /** * Called when the user took some actions that should be taken into consideration to update the * MRU list for input method rotation. * * @hide */ public void notifyUserActionIfNecessary() { } // TODO(b/149463653): remove it in T. We missed the API deadline in S. /** @hide */ @Override Loading core/java/android/inputmethodservice/IInputMethodWrapper.java +8 −8 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ class IInputMethodWrapper extends IInputMethod.Stub private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80; private static final int DO_CREATE_INLINE_SUGGESTIONS_REQUEST = 90; final WeakReference<AbstractInputMethodService> mTarget; final WeakReference<InputMethodServiceInternal> mTarget; final Context mContext; @UnsupportedAppUsage final HandlerCaller mCaller; Loading Loading @@ -129,12 +129,12 @@ class IInputMethodWrapper extends IInputMethod.Stub } } public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) { mTarget = new WeakReference<>(context); mContext = context.getApplicationContext(); IInputMethodWrapper(InputMethodServiceInternal imsInternal, InputMethod inputMethod) { mTarget = new WeakReference<>(imsInternal); mContext = imsInternal.getContext().getApplicationContext(); mCaller = new HandlerCaller(mContext, null, this, true /*asyncHandler*/); mInputMethod = new WeakReference<>(inputMethod); mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mTargetSdkVersion = imsInternal.getContext().getApplicationInfo().targetSdkVersion; } @MainThread Loading @@ -149,7 +149,7 @@ class IInputMethodWrapper extends IInputMethod.Stub switch (msg.what) { case DO_DUMP: { AbstractInputMethodService target = mTarget.get(); InputMethodServiceInternal target = mTarget.get(); if (target == null) { return; } Loading Loading @@ -251,11 +251,11 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { AbstractInputMethodService target = mTarget.get(); InputMethodServiceInternal target = mTarget.get(); if (target == null) { return; } if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) if (target.getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { fout.println("Permission Denial: can't dump InputMethodManager from from pid=" Loading core/java/android/inputmethodservice/InputMethodService.java +128 −103 Original line number Diff line number Diff line Loading @@ -55,7 +55,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.AnyThread; import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IntDef; Loading Loading @@ -740,7 +739,7 @@ public class InputMethodService extends AbstractInputMethodService { return; } ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this, "InputMethodService.InputMethodImpl#hideSoftInput", mDumper, null /* icProto */); final boolean wasVisible = isInputViewShown(); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput"); Loading Loading @@ -797,7 +796,7 @@ public class InputMethodService extends AbstractInputMethodService { } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput"); ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this, "InputMethodService.InputMethodImpl#showSoftInput", mDumper, null /* icProto */); final boolean wasVisible = isInputViewShown(); if (dispatchOnShowInputRequested(flags, false)) { Loading Loading @@ -2222,7 +2221,7 @@ public class InputMethodService extends AbstractInputMethodService { return; } ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper, null /* icProto */); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow"); mDecorViewWasVisible = mDecorViewVisible; Loading Loading @@ -2301,7 +2300,7 @@ public class InputMethodService extends AbstractInputMethodService { */ private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) { ImeTracing.getInstance().triggerServiceDump( "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this, "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper, null /* icProto */); if (setVisible) { cancelImeSurfaceRemoval(); Loading Loading @@ -2330,7 +2329,7 @@ public class InputMethodService extends AbstractInputMethodService { public void hideWindow() { if (DEBUG) Log.v(TAG, "CALL: hideWindow"); ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper, null /* icProto */); mWindowVisible = false; finishViews(false /* finishingInput */); Loading Loading @@ -2403,7 +2402,7 @@ public class InputMethodService extends AbstractInputMethodService { void doFinishInput() { if (DEBUG) Log.v(TAG, "CALL: doFinishInput"); ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", mDumper, null /* icProto */); finishViews(true /* finishingInput */); if (mInputStarted) { Loading @@ -2420,7 +2419,7 @@ public class InputMethodService extends AbstractInputMethodService { if (!restarting && mInputStarted) { doFinishInput(); } ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", mDumper, null /* icProto */); mInputStarted = true; mStartedInputConnection = ic; Loading Loading @@ -2580,7 +2579,7 @@ public class InputMethodService extends AbstractInputMethodService { * @param flags Provides additional operating flags. */ public void requestHideSelf(int flags) { ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper, null /* icProto */); mPrivOps.hideMySoftInput(flags); } Loading @@ -2594,7 +2593,7 @@ public class InputMethodService extends AbstractInputMethodService { * @param flags Provides additional operating flags. */ public final void requestShowSelf(int flags) { ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper, null /* icProto */); mPrivOps.showMySoftInput(flags); } Loading Loading @@ -3281,18 +3280,28 @@ public class InputMethodService extends AbstractInputMethodService { } /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * Used to inject custom {@link InputMethodServiceInternal}. * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called. * @hide * @return the {@link InputMethodServiceInternal} to be used. */ @NonNull @Override final InputMethodServiceInternal createInputMethodServiceInternal() { return new InputMethodServiceInternal() { /** * {@inheritDoc} */ @NonNull @Override public Context getContext() { return InputMethodService.this; } /** * {@inheritDoc} */ @Override public final void exposeContent(@NonNull InputContentInfo inputContentInfo, public void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { if (inputConnection == null) { return; Loading @@ -3305,11 +3314,9 @@ public class InputMethodService extends AbstractInputMethodService { /** * {@inheritDoc} * @hide */ @AnyThread @Override public final void notifyUserActionIfNecessary() { public void notifyUserActionIfNecessary() { synchronized (mLock) { if (mNotifyUserActionSent) { return; Loading @@ -3323,12 +3330,10 @@ public class InputMethodService extends AbstractInputMethodService { * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo, * InputConnection)} for details.</p> * <p>See {@link #exposeContent(InputContentInfo, InputConnection)} for details.</p> * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputContentInfo Content to be temporarily exposed from the input method to * the application. This cannot be {@code null}. * @param editorInfo The editor that receives {@link InputContentInfo}. */ private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo, Loading @@ -3337,13 +3342,31 @@ public class InputMethodService extends AbstractInputMethodService { final IInputContentUriToken uriToken = mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName); if (uriToken == null) { Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString() + " packageName=" + editorInfo.packageName); Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString() + " packageName=" + editorInfo.packageName); return; } inputContentInfo.setUriToken(uriToken); } /** * {@inheritDoc} */ @Override public void dump(FileDescriptor fd, PrintWriter fout, String[]args) { InputMethodService.this.dump(fd, fout, args); } /** * {@inheritDoc} */ @Override public void triggerServiceDump(String where, @Nullable byte[] icProto) { ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto); } }; } private int mapToImeWindowStatus() { return IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0); Loading Loading @@ -3411,11 +3434,12 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mSettingsObserver=" + mSettingsObserver); } private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() { /** * @hide * {@inheritDoc} */ @Override public final void dumpProtoInternal(ProtoOutputStream proto, byte[] icProto) { public void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto) { final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE); mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW); proto.write(VIEWS_CREATED, mViewsCreated); Loading Loading @@ -3449,4 +3473,5 @@ public class InputMethodService extends AbstractInputMethodService { } proto.end(token); } }; } core/java/android/inputmethodservice/InputMethodServiceInternal.java 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.inputmethodservice; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import java.io.FileDescriptor; import java.io.PrintWriter; /** * A set of internal methods exposed by {@link InputMethodService} to be called only from other * framework classes for internal use. * * <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p> */ interface InputMethodServiceInternal { /** * @return {@link Context} associated with the service. */ @NonNull Context getContext(); /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} * will be called. */ default void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { } /** * Called when the user took some actions that should be taken into consideration to update the * MRU list for input method rotation. */ default void notifyUserActionIfNecessary() { } /** * Called when the system is asking the IME to dump its information for debugging. * * <p>The caller is responsible for checking {@link android.Manifest.permission.DUMP}.</p> * * @param fd The raw file descriptor that the dump is being sent to. * @param fout The file to which you should dump your state. This will be * closed for you after you return. * @param args additional arguments to the dump request. */ default void dump(FileDescriptor fd, PrintWriter fout, String[] args) { } /** * Called with {@link com.android.internal.inputmethod.ImeTracing#triggerServiceDump(String, * com.android.internal.inputmethod.ImeTracing.ServiceDumper, byte[])} needs to be triggered * with the given parameters. * * @param where {@code where} parameter to be passed. * @param icProto {@code icProto} parameter to be passed. */ default void triggerServiceDump(String where, @Nullable byte[] icProto) { } } core/java/android/inputmethodservice/RemoteInputConnection.java +16 −22 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ final class RemoteInputConnection implements InputConnection { private final IInputContextInvoker mInvoker; @NonNull private final WeakReference<AbstractInputMethodService> mInputMethodService; private final WeakReference<InputMethodServiceInternal> mInputMethodService; @MissingMethodFlags private final int mMissingMethods; Loading @@ -67,7 +67,7 @@ final class RemoteInputConnection implements InputConnection { private final CancellationGroup mCancellationGroup; RemoteInputConnection( @NonNull WeakReference<AbstractInputMethodService> inputMethodService, @NonNull WeakReference<InputMethodServiceInternal> inputMethodService, IInputContext inputContext, @MissingMethodFlags int missingMethods, @NonNull CancellationGroup cancellationGroup) { mInputMethodService = inputMethodService; Loading @@ -90,12 +90,11 @@ final class RemoteInputConnection implements InputConnection { final CharSequence result = Completable.getResultOrNull( value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(length, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getTextAfterCursor", icProto); } return result; Loading @@ -115,12 +114,11 @@ final class RemoteInputConnection implements InputConnection { final CharSequence result = Completable.getResultOrNull( value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(length, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getTextBeforeCursor", icProto); } return result; Loading @@ -140,12 +138,11 @@ final class RemoteInputConnection implements InputConnection { final CharSequence result = Completable.getResultOrNull( value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getSelectedText", icProto); } return result; Loading Loading @@ -179,12 +176,11 @@ final class RemoteInputConnection implements InputConnection { final SurroundingText result = Completable.getResultOrNull( value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto( beforeLength, afterLength, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getSurroundingText", icProto); } return result; Loading @@ -200,12 +196,11 @@ final class RemoteInputConnection implements InputConnection { final int result = Completable.getResultOrZero( value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto( reqModes, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getCursorCapsMode", icProto); } return result; Loading @@ -221,12 +216,11 @@ final class RemoteInputConnection implements InputConnection { final ExtractedText result = Completable.getResultOrNull( value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto( request, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getExtractedText", icProto); } return result; Loading @@ -243,7 +237,7 @@ final class RemoteInputConnection implements InputConnection { @AnyThread private void notifyUserActionIfNecessary() { final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService == null) { // This basically should not happen, because it's the the caller of this method. return; Loading Loading @@ -395,7 +389,7 @@ final class RemoteInputConnection implements InputConnection { } if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService == null) { // This basically should not happen, because it's the caller of this method. return false; Loading Loading
core/java/android/inputmethodservice/AbstractInputMethodService.java +29 −44 Original line number Diff line number Diff line Loading @@ -25,13 +25,10 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.proto.ProtoOutputStream; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodSession; import android.window.WindowProviderService; Loading Loading @@ -215,16 +212,6 @@ public abstract class AbstractInputMethodService extends WindowProviderService */ public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); /** * Dumps the internal state of IME to a protocol buffer output stream. * * @param proto ProtoOutputStream to dump data to. * @param icProto {@link InputConnection} call data in proto format. * @hide */ @SuppressWarnings("HiddenAbstractMethod") public abstract void dumpProtoInternal(ProtoOutputStream proto, @Nullable byte[] icProto); /** * Implement this to handle {@link android.os.Binder#dump Binder.dump()} * calls on your input method. Loading @@ -238,7 +225,34 @@ public abstract class AbstractInputMethodService extends WindowProviderService if (mInputMethod == null) { mInputMethod = onCreateInputMethodInterface(); } return new IInputMethodWrapper(this, mInputMethod); return new IInputMethodWrapper(createInputMethodServiceInternal(), mInputMethod); } /** * Used to inject custom {@link InputMethodServiceInternal}. * * @return the {@link InputMethodServiceInternal} to be used. */ @NonNull InputMethodServiceInternal createInputMethodServiceInternal() { return new InputMethodServiceInternal() { /** * {@inheritDoc} */ @NonNull @Override public Context getContext() { return AbstractInputMethodService.this; } /** * {@inheritDoc} */ @Override public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { AbstractInputMethodService.this.dump(fd, fout, args); } }; } /** Loading @@ -263,35 +277,6 @@ public abstract class AbstractInputMethodService extends WindowProviderService return false; } /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * * <p>Default implementation does nothing.</p> * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be * called. * @return {@code false} if we cannot allow a temporary access permission. * @hide */ public void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { return; } /** * Called when the user took some actions that should be taken into consideration to update the * MRU list for input method rotation. * * @hide */ public void notifyUserActionIfNecessary() { } // TODO(b/149463653): remove it in T. We missed the API deadline in S. /** @hide */ @Override Loading
core/java/android/inputmethodservice/IInputMethodWrapper.java +8 −8 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ class IInputMethodWrapper extends IInputMethod.Stub private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80; private static final int DO_CREATE_INLINE_SUGGESTIONS_REQUEST = 90; final WeakReference<AbstractInputMethodService> mTarget; final WeakReference<InputMethodServiceInternal> mTarget; final Context mContext; @UnsupportedAppUsage final HandlerCaller mCaller; Loading Loading @@ -129,12 +129,12 @@ class IInputMethodWrapper extends IInputMethod.Stub } } public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) { mTarget = new WeakReference<>(context); mContext = context.getApplicationContext(); IInputMethodWrapper(InputMethodServiceInternal imsInternal, InputMethod inputMethod) { mTarget = new WeakReference<>(imsInternal); mContext = imsInternal.getContext().getApplicationContext(); mCaller = new HandlerCaller(mContext, null, this, true /*asyncHandler*/); mInputMethod = new WeakReference<>(inputMethod); mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mTargetSdkVersion = imsInternal.getContext().getApplicationInfo().targetSdkVersion; } @MainThread Loading @@ -149,7 +149,7 @@ class IInputMethodWrapper extends IInputMethod.Stub switch (msg.what) { case DO_DUMP: { AbstractInputMethodService target = mTarget.get(); InputMethodServiceInternal target = mTarget.get(); if (target == null) { return; } Loading Loading @@ -251,11 +251,11 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { AbstractInputMethodService target = mTarget.get(); InputMethodServiceInternal target = mTarget.get(); if (target == null) { return; } if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) if (target.getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { fout.println("Permission Denial: can't dump InputMethodManager from from pid=" Loading
core/java/android/inputmethodservice/InputMethodService.java +128 −103 Original line number Diff line number Diff line Loading @@ -55,7 +55,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.AnyThread; import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IntDef; Loading Loading @@ -740,7 +739,7 @@ public class InputMethodService extends AbstractInputMethodService { return; } ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this, "InputMethodService.InputMethodImpl#hideSoftInput", mDumper, null /* icProto */); final boolean wasVisible = isInputViewShown(); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput"); Loading Loading @@ -797,7 +796,7 @@ public class InputMethodService extends AbstractInputMethodService { } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput"); ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this, "InputMethodService.InputMethodImpl#showSoftInput", mDumper, null /* icProto */); final boolean wasVisible = isInputViewShown(); if (dispatchOnShowInputRequested(flags, false)) { Loading Loading @@ -2222,7 +2221,7 @@ public class InputMethodService extends AbstractInputMethodService { return; } ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper, null /* icProto */); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow"); mDecorViewWasVisible = mDecorViewVisible; Loading Loading @@ -2301,7 +2300,7 @@ public class InputMethodService extends AbstractInputMethodService { */ private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) { ImeTracing.getInstance().triggerServiceDump( "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this, "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper, null /* icProto */); if (setVisible) { cancelImeSurfaceRemoval(); Loading Loading @@ -2330,7 +2329,7 @@ public class InputMethodService extends AbstractInputMethodService { public void hideWindow() { if (DEBUG) Log.v(TAG, "CALL: hideWindow"); ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper, null /* icProto */); mWindowVisible = false; finishViews(false /* finishingInput */); Loading Loading @@ -2403,7 +2402,7 @@ public class InputMethodService extends AbstractInputMethodService { void doFinishInput() { if (DEBUG) Log.v(TAG, "CALL: doFinishInput"); ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", mDumper, null /* icProto */); finishViews(true /* finishingInput */); if (mInputStarted) { Loading @@ -2420,7 +2419,7 @@ public class InputMethodService extends AbstractInputMethodService { if (!restarting && mInputStarted) { doFinishInput(); } ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", mDumper, null /* icProto */); mInputStarted = true; mStartedInputConnection = ic; Loading Loading @@ -2580,7 +2579,7 @@ public class InputMethodService extends AbstractInputMethodService { * @param flags Provides additional operating flags. */ public void requestHideSelf(int flags) { ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper, null /* icProto */); mPrivOps.hideMySoftInput(flags); } Loading @@ -2594,7 +2593,7 @@ public class InputMethodService extends AbstractInputMethodService { * @param flags Provides additional operating flags. */ public final void requestShowSelf(int flags) { ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this, ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper, null /* icProto */); mPrivOps.showMySoftInput(flags); } Loading Loading @@ -3281,18 +3280,28 @@ public class InputMethodService extends AbstractInputMethodService { } /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * Used to inject custom {@link InputMethodServiceInternal}. * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called. * @hide * @return the {@link InputMethodServiceInternal} to be used. */ @NonNull @Override final InputMethodServiceInternal createInputMethodServiceInternal() { return new InputMethodServiceInternal() { /** * {@inheritDoc} */ @NonNull @Override public Context getContext() { return InputMethodService.this; } /** * {@inheritDoc} */ @Override public final void exposeContent(@NonNull InputContentInfo inputContentInfo, public void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { if (inputConnection == null) { return; Loading @@ -3305,11 +3314,9 @@ public class InputMethodService extends AbstractInputMethodService { /** * {@inheritDoc} * @hide */ @AnyThread @Override public final void notifyUserActionIfNecessary() { public void notifyUserActionIfNecessary() { synchronized (mLock) { if (mNotifyUserActionSent) { return; Loading @@ -3323,12 +3330,10 @@ public class InputMethodService extends AbstractInputMethodService { * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo, * InputConnection)} for details.</p> * <p>See {@link #exposeContent(InputContentInfo, InputConnection)} for details.</p> * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. * This cannot be {@code null}. * @param inputContentInfo Content to be temporarily exposed from the input method to * the application. This cannot be {@code null}. * @param editorInfo The editor that receives {@link InputContentInfo}. */ private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo, Loading @@ -3337,13 +3342,31 @@ public class InputMethodService extends AbstractInputMethodService { final IInputContentUriToken uriToken = mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName); if (uriToken == null) { Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString() + " packageName=" + editorInfo.packageName); Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString() + " packageName=" + editorInfo.packageName); return; } inputContentInfo.setUriToken(uriToken); } /** * {@inheritDoc} */ @Override public void dump(FileDescriptor fd, PrintWriter fout, String[]args) { InputMethodService.this.dump(fd, fout, args); } /** * {@inheritDoc} */ @Override public void triggerServiceDump(String where, @Nullable byte[] icProto) { ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto); } }; } private int mapToImeWindowStatus() { return IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0); Loading Loading @@ -3411,11 +3434,12 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mSettingsObserver=" + mSettingsObserver); } private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() { /** * @hide * {@inheritDoc} */ @Override public final void dumpProtoInternal(ProtoOutputStream proto, byte[] icProto) { public void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto) { final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE); mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW); proto.write(VIEWS_CREATED, mViewsCreated); Loading Loading @@ -3449,4 +3473,5 @@ public class InputMethodService extends AbstractInputMethodService { } proto.end(token); } }; }
core/java/android/inputmethodservice/InputMethodServiceInternal.java 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.inputmethodservice; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import java.io.FileDescriptor; import java.io.PrintWriter; /** * A set of internal methods exposed by {@link InputMethodService} to be called only from other * framework classes for internal use. * * <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p> */ interface InputMethodServiceInternal { /** * @return {@link Context} associated with the service. */ @NonNull Context getContext(); /** * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access * permission to the content. * * @param inputContentInfo Content to be temporarily exposed from the input method to the * application. This cannot be {@code null}. * @param inputConnection {@link InputConnection} with which * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} * will be called. */ default void exposeContent(@NonNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection) { } /** * Called when the user took some actions that should be taken into consideration to update the * MRU list for input method rotation. */ default void notifyUserActionIfNecessary() { } /** * Called when the system is asking the IME to dump its information for debugging. * * <p>The caller is responsible for checking {@link android.Manifest.permission.DUMP}.</p> * * @param fd The raw file descriptor that the dump is being sent to. * @param fout The file to which you should dump your state. This will be * closed for you after you return. * @param args additional arguments to the dump request. */ default void dump(FileDescriptor fd, PrintWriter fout, String[] args) { } /** * Called with {@link com.android.internal.inputmethod.ImeTracing#triggerServiceDump(String, * com.android.internal.inputmethod.ImeTracing.ServiceDumper, byte[])} needs to be triggered * with the given parameters. * * @param where {@code where} parameter to be passed. * @param icProto {@code icProto} parameter to be passed. */ default void triggerServiceDump(String where, @Nullable byte[] icProto) { } }
core/java/android/inputmethodservice/RemoteInputConnection.java +16 −22 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ final class RemoteInputConnection implements InputConnection { private final IInputContextInvoker mInvoker; @NonNull private final WeakReference<AbstractInputMethodService> mInputMethodService; private final WeakReference<InputMethodServiceInternal> mInputMethodService; @MissingMethodFlags private final int mMissingMethods; Loading @@ -67,7 +67,7 @@ final class RemoteInputConnection implements InputConnection { private final CancellationGroup mCancellationGroup; RemoteInputConnection( @NonNull WeakReference<AbstractInputMethodService> inputMethodService, @NonNull WeakReference<InputMethodServiceInternal> inputMethodService, IInputContext inputContext, @MissingMethodFlags int missingMethods, @NonNull CancellationGroup cancellationGroup) { mInputMethodService = inputMethodService; Loading @@ -90,12 +90,11 @@ final class RemoteInputConnection implements InputConnection { final CharSequence result = Completable.getResultOrNull( value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(length, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getTextAfterCursor", icProto); } return result; Loading @@ -115,12 +114,11 @@ final class RemoteInputConnection implements InputConnection { final CharSequence result = Completable.getResultOrNull( value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(length, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getTextBeforeCursor", icProto); } return result; Loading @@ -140,12 +138,11 @@ final class RemoteInputConnection implements InputConnection { final CharSequence result = Completable.getResultOrNull( value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getSelectedText", icProto); } return result; Loading Loading @@ -179,12 +176,11 @@ final class RemoteInputConnection implements InputConnection { final SurroundingText result = Completable.getResultOrNull( value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto( beforeLength, afterLength, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getSurroundingText", icProto); } return result; Loading @@ -200,12 +196,11 @@ final class RemoteInputConnection implements InputConnection { final int result = Completable.getResultOrZero( value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto( reqModes, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getCursorCapsMode", icProto); } return result; Loading @@ -221,12 +216,11 @@ final class RemoteInputConnection implements InputConnection { final ExtractedText result = Completable.getResultOrNull( value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS); final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) { final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto( request, flags, result); ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText", inputMethodService, icProto); inputMethodService.triggerServiceDump(TAG + "#getExtractedText", icProto); } return result; Loading @@ -243,7 +237,7 @@ final class RemoteInputConnection implements InputConnection { @AnyThread private void notifyUserActionIfNecessary() { final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService == null) { // This basically should not happen, because it's the the caller of this method. return; Loading Loading @@ -395,7 +389,7 @@ final class RemoteInputConnection implements InputConnection { } if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { final AbstractInputMethodService inputMethodService = mInputMethodService.get(); final InputMethodServiceInternal inputMethodService = mInputMethodService.get(); if (inputMethodService == null) { // This basically should not happen, because it's the caller of this method. return false; Loading