Introduce InputMethodServiceInternal for better abstraction
This is a mechanical refactoring CL that has no behavior change. This CL removes the direct dependency on AbstractInputMethodService from whenever possible. As a result, the following classes no longer directly depend on AbstractInputMethodService. * android.inputmethodservice.IInputMethodWrapper * android.inputmethodservice.RemoteInputConnection * com.android.internal.inputmethod.ImeTracing * com.android.internal.inputmethod.ImeTracingClientImpl * com.android.internal.inputmethod.ImeTracingServerImpl This is still a purely mechanical refactoring. There should be no observable behavior change. Bug: 192412909 Test: atest CtsInputMethodTestCases Test: Manually verified that IME tracing still works Change-Id: I2aeeeacd27195ce10059d6590e098a4a969e774d
This commit is contained in:
@@ -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.
|
||||
*
|
||||
* <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
|
||||
|
||||
@@ -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;
|
||||
@@ -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="
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>See {@link android.inputmethodservice.InputMethodService#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 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.
|
||||
*
|
||||
* <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 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <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) {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user