diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java index b359465c4738d..9db41c41c31cb 100644 --- a/core/java/android/inputmethodservice/AbstractInputMethodService.java +++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java @@ -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; @@ -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. @@ -238,9 +225,36 @@ 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); + } + }; + } + /** * Implement this to handle trackball events on your input method. * @@ -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. - * - *

Default implementation does nothing.

- * - * @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 diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 99e439ae0fb1b..90990b45e5525 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -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 mTarget; + final WeakReference mTarget; final Context mContext; @UnsupportedAppUsage final HandlerCaller mCaller; @@ -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 @@ -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; } @@ -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=" diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index e0b001f5ed192..dadea6792ac16 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -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; @@ -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"); @@ -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)) { @@ -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; @@ -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(); @@ -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 */); @@ -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) { @@ -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; @@ -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); } @@ -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); } @@ -3281,67 +3280,91 @@ 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 - public final void exposeContent(@NonNull InputContentInfo inputContentInfo, - @NonNull InputConnection inputConnection) { - if (inputConnection == null) { - return; - } - if (getCurrentInputConnection() != inputConnection) { - return; - } - exposeContentInternal(inputContentInfo, getCurrentInputEditorInfo()); - } - - /** - * {@inheritDoc} - * @hide - */ - @AnyThread - @Override - public final void notifyUserActionIfNecessary() { - synchronized (mLock) { - if (mNotifyUserActionSent) { - return; + final InputMethodServiceInternal createInputMethodServiceInternal() { + return new InputMethodServiceInternal() { + /** + * {@inheritDoc} + */ + @NonNull + @Override + public Context getContext() { + return InputMethodService.this; } - mPrivOps.notifyUserActionAsync(); - mNotifyUserActionSent = true; - } - } - /** - * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access - * permission to the content. - * - *

See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo, - * InputConnection)} for details.

- * - * @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, - @NonNull EditorInfo editorInfo) { - final Uri contentUri = inputContentInfo.getContentUri(); - final IInputContentUriToken uriToken = - mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName); - if (uriToken == null) { - Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString() - + " packageName=" + editorInfo.packageName); - return; - } - inputContentInfo.setUriToken(uriToken); + /** + * {@inheritDoc} + */ + @Override + public void exposeContent(@NonNull InputContentInfo inputContentInfo, + @NonNull InputConnection inputConnection) { + if (inputConnection == null) { + return; + } + if (getCurrentInputConnection() != inputConnection) { + return; + } + exposeContentInternal(inputContentInfo, getCurrentInputEditorInfo()); + } + + /** + * {@inheritDoc} + */ + @Override + public void notifyUserActionIfNecessary() { + synchronized (mLock) { + if (mNotifyUserActionSent) { + return; + } + mPrivOps.notifyUserActionAsync(); + mNotifyUserActionSent = true; + } + } + + /** + * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access + * permission to the content. + * + *

See {@link #exposeContent(InputContentInfo, InputConnection)} for details.

+ * + * @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, + @NonNull EditorInfo editorInfo) { + final Uri contentUri = inputContentInfo.getContentUri(); + final IInputContentUriToken uriToken = + mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName); + if (uriToken == null) { + 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() { @@ -3411,42 +3434,44 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mSettingsObserver=" + mSettingsObserver); } - /** - * @hide - */ - @Override - public final void dumpProtoInternal(ProtoOutputStream proto, byte[] icProto) { - final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE); - mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW); - proto.write(VIEWS_CREATED, mViewsCreated); - proto.write(DECOR_VIEW_VISIBLE, mDecorViewVisible); - proto.write(DECOR_VIEW_WAS_VISIBLE, mDecorViewWasVisible); - proto.write(WINDOW_VISIBLE, mWindowVisible); - proto.write(IN_SHOW_WINDOW, mInShowWindow); - proto.write(CONFIGURATION, getResources().getConfiguration().toString()); - proto.write(TOKEN, Objects.toString(mToken)); - proto.write(INPUT_BINDING, Objects.toString(mInputBinding)); - proto.write(INPUT_STARTED, mInputStarted); - proto.write(INPUT_VIEW_STARTED, mInputViewStarted); - proto.write(CANDIDATES_VIEW_STARTED, mCandidatesViewStarted); - if (mInputEditorInfo != null) { - mInputEditorInfo.dumpDebug(proto, INPUT_EDITOR_INFO); + private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() { + /** + * {@inheritDoc} + */ + @Override + 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); + proto.write(DECOR_VIEW_VISIBLE, mDecorViewVisible); + proto.write(DECOR_VIEW_WAS_VISIBLE, mDecorViewWasVisible); + proto.write(WINDOW_VISIBLE, mWindowVisible); + proto.write(IN_SHOW_WINDOW, mInShowWindow); + proto.write(CONFIGURATION, getResources().getConfiguration().toString()); + proto.write(TOKEN, Objects.toString(mToken)); + proto.write(INPUT_BINDING, Objects.toString(mInputBinding)); + proto.write(INPUT_STARTED, mInputStarted); + proto.write(INPUT_VIEW_STARTED, mInputViewStarted); + proto.write(CANDIDATES_VIEW_STARTED, mCandidatesViewStarted); + if (mInputEditorInfo != null) { + mInputEditorInfo.dumpDebug(proto, INPUT_EDITOR_INFO); + } + proto.write(SHOW_INPUT_REQUESTED, mShowInputRequested); + proto.write(LAST_SHOW_INPUT_REQUESTED, mLastShowInputRequested); + proto.write(SHOW_INPUT_FLAGS, mShowInputFlags); + proto.write(CANDIDATES_VISIBILITY, mCandidatesVisibility); + proto.write(FULLSCREEN_APPLIED, mFullscreenApplied); + proto.write(IS_FULLSCREEN, mIsFullscreen); + proto.write(EXTRACT_VIEW_HIDDEN, mExtractViewHidden); + proto.write(EXTRACTED_TOKEN, mExtractedToken); + proto.write(IS_INPUT_VIEW_SHOWN, mIsInputViewShown); + proto.write(STATUS_ICON, mStatusIcon); + mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS); + proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver)); + if (icProto != null) { + proto.write(INPUT_CONNECTION_CALL, icProto); + } + proto.end(token); } - proto.write(SHOW_INPUT_REQUESTED, mShowInputRequested); - proto.write(LAST_SHOW_INPUT_REQUESTED, mLastShowInputRequested); - proto.write(SHOW_INPUT_FLAGS, mShowInputFlags); - proto.write(CANDIDATES_VISIBILITY, mCandidatesVisibility); - proto.write(FULLSCREEN_APPLIED, mFullscreenApplied); - proto.write(IS_FULLSCREEN, mIsFullscreen); - proto.write(EXTRACT_VIEW_HIDDEN, mExtractViewHidden); - proto.write(EXTRACTED_TOKEN, mExtractedToken); - proto.write(IS_INPUT_VIEW_SHOWN, mIsInputViewShown); - proto.write(STATUS_ICON, mStatusIcon); - mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS); - proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver)); - if (icProto != null) { - proto.write(INPUT_CONNECTION_CALL, icProto); - } - proto.end(token); - } + }; } diff --git a/core/java/android/inputmethodservice/InputMethodServiceInternal.java b/core/java/android/inputmethodservice/InputMethodServiceInternal.java new file mode 100644 index 0000000000000..7cd4ff61b2c80 --- /dev/null +++ b/core/java/android/inputmethodservice/InputMethodServiceInternal.java @@ -0,0 +1,86 @@ +/* + * 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. + * + *

CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.

+ */ +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. + * + *

The caller is responsible for checking {@link android.Manifest.permission.DUMP}.

+ * + * @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) { + } +} diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java index 98a49ccb27d80..4fa98be75b46c 100644 --- a/core/java/android/inputmethodservice/RemoteInputConnection.java +++ b/core/java/android/inputmethodservice/RemoteInputConnection.java @@ -52,7 +52,7 @@ final class RemoteInputConnection implements InputConnection { private final IInputContextInvoker mInvoker; @NonNull - private final WeakReference mInputMethodService; + private final WeakReference mInputMethodService; @MissingMethodFlags private final int mMissingMethods; @@ -67,7 +67,7 @@ final class RemoteInputConnection implements InputConnection { private final CancellationGroup mCancellationGroup; RemoteInputConnection( - @NonNull WeakReference inputMethodService, + @NonNull WeakReference inputMethodService, IInputContext inputContext, @MissingMethodFlags int missingMethods, @NonNull CancellationGroup cancellationGroup) { mInputMethodService = inputMethodService; @@ -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; @@ -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; @@ -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; @@ -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; @@ -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; @@ -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; @@ -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; @@ -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; diff --git a/core/java/com/android/internal/inputmethod/ImeTracing.java b/core/java/com/android/internal/inputmethod/ImeTracing.java index a95f7560c7c87..71a1957970486 100644 --- a/core/java/com/android/internal/inputmethod/ImeTracing.java +++ b/core/java/com/android/internal/inputmethod/ImeTracing.java @@ -19,7 +19,6 @@ package com.android.internal.inputmethod; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; -import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; @@ -106,14 +105,30 @@ public abstract class ImeTracing { public abstract void triggerClientDump(String where, InputMethodManager immInstance, @Nullable byte[] icProto); + /** + * A delegate for {@link #triggerServiceDump(String, ServiceDumper, byte[])}. + */ + @FunctionalInterface + public interface ServiceDumper { + /** + * Dumps internal data into {@link ProtoOutputStream}. + * + * @param proto {@link ProtoOutputStream} to be dumped into. + * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto + * format. + */ + void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto); + } + /** * Starts a proto dump of the currently connected InputMethodService information. * * @param where Place where the trace was triggered. - * @param service The {@link android.inputmethodservice.InputMethodService} to be dumped. + * @param dumper {@link ServiceDumper} to be used to dump + * {@link android.inputmethodservice.InputMethodService}. * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format. */ - public abstract void triggerServiceDump(String where, AbstractInputMethodService service, + public abstract void triggerServiceDump(String where, ServiceDumper dumper, @Nullable byte[] icProto); /** diff --git a/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java index 91ce5e762ec1a..31d278b5ca543 100644 --- a/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java +++ b/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java @@ -18,7 +18,6 @@ package com.android.internal.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; -import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; import android.util.Log; @@ -65,7 +64,7 @@ class ImeTracingClientImpl extends ImeTracing { } @Override - public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service, + public void triggerServiceDump(String where, @NonNull ServiceDumper dumper, @Nullable byte[] icProto) { if (!isEnabled() || !isAvailable()) { return; @@ -80,7 +79,7 @@ class ImeTracingClientImpl extends ImeTracing { try { ProtoOutputStream proto = new ProtoOutputStream(); - service.dumpProtoInternal(proto, icProto); + dumper.dumpToProto(proto, icProto); sendToService(proto.getBytes(), IME_TRACING_FROM_IMS, where); } catch (RemoteException e) { Log.e(TAG, "Exception while sending ime-related service dump to server", e); diff --git a/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java index b5aa91adaea94..d452e60eb1dd8 100644 --- a/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java +++ b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java @@ -19,7 +19,6 @@ package com.android.internal.inputmethod; import static android.os.Build.IS_USER; import android.annotation.Nullable; -import android.inputmethodservice.AbstractInputMethodService; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; import android.util.Log; @@ -112,8 +111,7 @@ class ImeTracingServerImpl extends ImeTracing { } @Override - public void triggerServiceDump(String where, AbstractInputMethodService service, - @Nullable byte[] icProto) { + public void triggerServiceDump(String where, ServiceDumper dumper, @Nullable byte[] icProto) { // Intentionally left empty, this is implemented in ImeTracingClientImpl }