Merge "Add InputConnection app and service dump"

This commit is contained in:
TreeHugger Robot
2020-12-02 17:30:06 +00:00
committed by Android (Google) Code Review
15 changed files with 484 additions and 43 deletions

View File

@@ -199,10 +199,11 @@ public abstract class AbstractInputMethodService extends Service
* 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);
public abstract void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto);
/**
* Implement this to handle {@link android.os.Binder#dump Binder.dump()}

View File

@@ -25,6 +25,7 @@ import static android.inputmethodservice.InputMethodServiceProto.EXTRACTED_TOKEN
import static android.inputmethodservice.InputMethodServiceProto.EXTRACT_VIEW_HIDDEN;
import static android.inputmethodservice.InputMethodServiceProto.FULLSCREEN_APPLIED;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_BINDING;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_CONNECTION_CALL;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_EDITOR_INFO;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_STARTED;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_VIEW_STARTED;
@@ -742,7 +743,8 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this);
"InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this,
null /* icProto */);
final boolean wasVisible = isInputViewShown();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
@@ -798,7 +800,8 @@ public class InputMethodService extends AbstractInputMethodService {
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this);
"InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this,
null /* icProto */);
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
@@ -2182,7 +2185,8 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this,
null /* icProto */);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
@@ -2260,7 +2264,8 @@ public class InputMethodService extends AbstractInputMethodService {
*/
private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this);
"InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this,
null /* icProto */);
mPrivOps.applyImeVisibility(setVisible
? mCurShowInputToken : mCurHideInputToken, setVisible);
}
@@ -2285,7 +2290,8 @@ 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", this,
null /* icProto */);
mWindowVisible = false;
finishViews(false /* finishingInput */);
if (mDecorViewVisible) {
@@ -2356,7 +2362,8 @@ 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", this,
null /* icProto */);
finishViews(true /* finishingInput */);
if (mInputStarted) {
mInlineSuggestionSessionController.notifyOnFinishInput();
@@ -2372,7 +2379,8 @@ public class InputMethodService extends AbstractInputMethodService {
if (!restarting && mInputStarted) {
doFinishInput();
}
ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this,
null /* icProto */);
mInputStarted = true;
mStartedInputConnection = ic;
mInputEditorInfo = attribute;
@@ -2531,7 +2539,8 @@ 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", this,
null /* icProto */);
mPrivOps.hideMySoftInput(flags);
}
@@ -2544,7 +2553,8 @@ 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", this,
null /* icProto */);
mPrivOps.showMySoftInput(flags);
}
@@ -3364,7 +3374,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @hide
*/
@Override
public final void dumpProtoInternal(ProtoOutputStream proto) {
public final void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto) {
final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE);
mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
proto.write(VIEWS_CREATED, mViewsCreated);
@@ -3393,6 +3403,9 @@ public class InputMethodService extends AbstractInputMethodService {
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.getBytes());
}
proto.end(token);
}
}

View File

@@ -110,15 +110,20 @@ public abstract class ImeTracing {
*
* @param where Place where the trace was triggered.
* @param immInstance The {@link InputMethodManager} instance to dump.
* @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
public abstract void triggerClientDump(String where, InputMethodManager immInstance);
public abstract void triggerClientDump(String where, InputMethodManager immInstance,
ProtoOutputStream 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 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, AbstractInputMethodService service,
ProtoOutputStream icProto);
/**
* Starts a proto dump of the InputMethodManagerService information.

View File

@@ -45,7 +45,8 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
public void triggerClientDump(String where, @NonNull InputMethodManager immInstance) {
public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -59,7 +60,7 @@ class ImeTracingClientImpl extends ImeTracing {
try {
ProtoOutputStream proto = new ProtoOutputStream();
immInstance.dumpDebug(proto);
immInstance.dumpDebug(proto, icProto);
sendToService(proto.getBytes(), IME_TRACING_FROM_CLIENT, where);
} catch (RemoteException e) {
Log.e(TAG, "Exception while sending ime-related client dump to server", e);
@@ -69,7 +70,8 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service) {
public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service,
ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -83,7 +85,7 @@ class ImeTracingClientImpl extends ImeTracing {
try {
ProtoOutputStream proto = new ProtoOutputStream();
service.dumpProtoInternal(proto);
service.dumpProtoInternal(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);

View File

@@ -133,12 +133,14 @@ class ImeTracingServerImpl extends ImeTracing {
}
@Override
public void triggerClientDump(String where, InputMethodManager immInstance) {
public void triggerClientDump(String where, InputMethodManager immInstance,
ProtoOutputStream icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
@Override
public void triggerServiceDump(String where, AbstractInputMethodService service) {
public void triggerServiceDump(String where, AbstractInputMethodService service,
ProtoOutputStream icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright (C) 2020 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.util.imetracing;
import static android.view.inputmethod.InputConnectionCallProto.GET_CURSOR_CAPS_MODE;
import static android.view.inputmethod.InputConnectionCallProto.GET_EXTRACTED_TEXT;
import static android.view.inputmethod.InputConnectionCallProto.GET_SELECTED_TEXT;
import static android.view.inputmethod.InputConnectionCallProto.GET_SURROUNDING_TEXT;
import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_AFTER_CURSOR;
import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_BEFORE_CURSOR;
import static android.view.inputmethod.InputConnectionCallProto.GetExtractedText.REQUEST;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnectionCallProto.GetCursorCapsMode;
import android.view.inputmethod.InputConnectionCallProto.GetExtractedText;
import android.view.inputmethod.InputConnectionCallProto.GetSelectedText;
import android.view.inputmethod.InputConnectionCallProto.GetSurroundingText;
import android.view.inputmethod.InputConnectionCallProto.GetTextAfterCursor;
import android.view.inputmethod.InputConnectionCallProto.GetTextBeforeCursor;
import android.view.inputmethod.SurroundingText;
/**
* Helper class for constructing {@link android.view.inputmethod.InputConnection} dumps, which are
* integrated into {@link ImeTracing}.
* @hide
*/
public class InputConnectionHelper {
static final String TAG = "InputConnectionHelper";
public static final boolean DUMP_TEXT = false;
private InputConnectionHelper() {}
/**
* Builder for InputConnectionCallProto to hold
* {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)} data.
*
* @param length The expected length of the text. This must be non-negative.
* @param flags Supplies additional options controlling how the text is
* returned. May be either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
* @param result The text after the cursor position; the length of the
* returned text might be less than <var>length</var>.
* @return ProtoOutputStream holding the InputConnectionCallProto data.
*/
public static ProtoOutputStream buildGetTextAfterCursorProto(@IntRange(from = 0) int length,
int flags, @Nullable CharSequence result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_TEXT_AFTER_CURSOR);
proto.write(GetTextAfterCursor.LENGTH, length);
proto.write(GetTextAfterCursor.FLAGS, flags);
if (result == null) {
proto.write(GetTextAfterCursor.RESULT, "null result");
} else if (DUMP_TEXT) {
proto.write(GetTextAfterCursor.RESULT, result.toString());
}
proto.end(token);
return proto;
}
/**
* Builder for InputConnectionCallProto to hold
* {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)} data.
*
* @param length The expected length of the text. This must be non-negative.
* @param flags Supplies additional options controlling how the text is
* returned. May be either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
* @param result The text before the cursor position; the length of the
* returned text might be less than <var>length</var>.
* @return ProtoOutputStream holding the InputConnectionCallProto data.
*/
public static ProtoOutputStream buildGetTextBeforeCursorProto(@IntRange(from = 0) int length,
int flags, @Nullable CharSequence result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_TEXT_BEFORE_CURSOR);
proto.write(GetTextBeforeCursor.LENGTH, length);
proto.write(GetTextBeforeCursor.FLAGS, flags);
if (result == null) {
proto.write(GetTextBeforeCursor.RESULT, "null result");
} else if (DUMP_TEXT) {
proto.write(GetTextBeforeCursor.RESULT, result.toString());
}
proto.end(token);
return proto;
}
/**
* Builder for InputConnectionCallProto to hold
* {@link android.view.inputmethod.InputConnection#getSelectedText(int)} data.
*
* @param flags Supplies additional options controlling how the text is
* returned. May be either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
* @param result the text that is currently selected, if any, or null if
* no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
* later, returns false when the target application does not implement
* this method.
* @return ProtoOutputStream holding the InputConnectionCallProto data.
*/
public static ProtoOutputStream buildGetSelectedTextProto(int flags,
@Nullable CharSequence result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_SELECTED_TEXT);
proto.write(GetSelectedText.FLAGS, flags);
if (result == null) {
proto.write(GetSelectedText.RESULT, "null result");
} else if (DUMP_TEXT) {
proto.write(GetSelectedText.RESULT, result.toString());
}
proto.end(token);
return proto;
}
/**
* Builder for InputConnectionCallProto to hold
* {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)} data.
*
* @param beforeLength The expected length of the text before the cursor.
* @param afterLength The expected length of the text after the cursor.
* @param flags Supplies additional options controlling how the text is
* returned. May be either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
* @param result an {@link android.view.inputmethod.SurroundingText} object describing the
* surrounding text and state of selection, or null if the input connection is no longer valid,
* or the editor can't comply with the request for some reason, or the application does not
* implement this method. The length of the returned text might be less than the sum of
* <var>beforeLength</var> and <var>afterLength</var> .
* @return ProtoOutputStream holding the InputConnectionCallProto data.
*/
public static ProtoOutputStream buildGetSurroundingTextProto(@IntRange(from = 0)
int beforeLength, @IntRange(from = 0) int afterLength, int flags,
@Nullable SurroundingText result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_SURROUNDING_TEXT);
proto.write(GetSurroundingText.BEFORE_LENGTH, beforeLength);
proto.write(GetSurroundingText.AFTER_LENGTH, afterLength);
proto.write(GetSurroundingText.FLAGS, flags);
if (result == null) {
final long token_result = proto.start(GetSurroundingText.RESULT);
proto.write(GetSurroundingText.SurroundingText.TEXT, "null result");
proto.end(token_result);
} else if (DUMP_TEXT) {
final long token_result = proto.start(GetSurroundingText.RESULT);
proto.write(GetSurroundingText.SurroundingText.TEXT, result.getText().toString());
proto.write(GetSurroundingText.SurroundingText.SELECTION_START,
result.getSelectionStart());
proto.write(GetSurroundingText.SurroundingText.SELECTION_END,
result.getSelectionEnd());
proto.write(GetSurroundingText.SurroundingText.OFFSET, result.getOffset());
proto.end(token_result);
}
proto.end(token);
return proto;
}
/**
* Builder for InputConnectionCallProto to hold
* {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)} data.
*
* @param reqModes The desired modes to retrieve, as defined by
* {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}.
* @param result the caps mode flags that are in effect at the current
* cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
* @return ProtoOutputStream holding the InputConnectionCallProto data.
*/
public static ProtoOutputStream buildGetCursorCapsModeProto(int reqModes, int result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_CURSOR_CAPS_MODE);
proto.write(GetCursorCapsMode.REQ_MODES, reqModes);
if (DUMP_TEXT) {
proto.write(GetCursorCapsMode.RESULT, result);
}
proto.end(token);
return proto;
}
/**
* Builder for InputConnectionCallProto to hold
* {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)}
* data.
*
* @param request Description of how the text should be returned.
* {@link android.view.inputmethod.ExtractedTextRequest}
* @param flags Additional options to control the client, either {@code 0} or
* {@link android.view.inputmethod.InputConnection#GET_EXTRACTED_TEXT_MONITOR}.
* @param result an {@link android.view.inputmethod.ExtractedText}
* object describing the state of the text view and containing the
* extracted text itself, or null if the input connection is no
* longer valid of the editor can't comply with the request for
* some reason.
* @return ProtoOutputStream holding the InputConnectionCallProto data.
*/
public static ProtoOutputStream buildGetExtractedTextProto(@NonNull ExtractedTextRequest
request, int flags, @Nullable ExtractedText result) {
ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.start(GET_EXTRACTED_TEXT);
final long token_request = proto.start(REQUEST);
proto.write(GetExtractedText.ExtractedTextRequest.TOKEN, request.token);
proto.write(GetExtractedText.ExtractedTextRequest.FLAGS, request.flags);
proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_LINES, request.hintMaxLines);
proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_CHARS, request.hintMaxChars);
proto.end(token_request);
proto.write(GetExtractedText.FLAGS, flags);
if (result == null) {
proto.write(GetExtractedText.RESULT, "null result");
} else if (DUMP_TEXT) {
proto.write(GetExtractedText.RESULT, result.text.toString());
}
proto.end(token);
return proto;
}
}

View File

@@ -829,7 +829,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#show",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
} else {
@@ -886,7 +886,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
void hide(@InsetsType int types, boolean fromIme) {
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hide",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
} else {
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
@@ -928,7 +928,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (fromIme) {
ImeTracing.getInstance().triggerClientDump(
"InsetsController#controlWindowInsetsAnimation",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
}
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
@@ -1022,7 +1022,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
animationType, mHost.getTranslator());
if ((typesReady & WindowInsets.Type.ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
}
mRunningAnimations.add(new RunningAnimation(runner, animationType));
if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
@@ -1200,7 +1200,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (types.valueAt(j) == ITYPE_IME) {
ImeTracing.getInstance().triggerClientDump(
"InsetsSourceConsumer#notifyAnimationFinished",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
}
stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
@@ -1345,7 +1345,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hideDirectly",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
}
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
@@ -1361,7 +1361,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void showDirectly(@InsetsType int types, boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsController#showDirectly",
mHost.getInputMethodManager());
mHost.getInputMethodManager(), null /* icProto */);
}
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {

View File

@@ -9225,7 +9225,8 @@ public final class ViewRootImpl implements ViewParent,
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets",
viewAncestor.getInsetsController().getHost().getInputMethodManager());
viewAncestor.getInsetsController().getHost().getInputMethodManager(),
null /* icProto */);
}
if (viewAncestor != null) {
viewAncestor.showInsets(types, fromIme);
@@ -9238,7 +9239,8 @@ public final class ViewRootImpl implements ViewParent,
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets",
viewAncestor.getInsetsController().getHost().getInputMethodManager());
viewAncestor.getInsetsController().getHost().getInputMethodManager(),
null /* icProto */);
}
if (viewAncestor != null) {
viewAncestor.hideInsets(types, fromIme);

View File

@@ -23,6 +23,7 @@ import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodCl
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION_CALL;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL;
import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
@@ -579,7 +580,8 @@ public final class InputMethodManager {
int windowFlags) {
final View servedView;
ImeTracing.getInstance().triggerClientDump(
"InputMethodManager.DelegateImpl#startInput", InputMethodManager.this);
"InputMethodManager.DelegateImpl#startInput", InputMethodManager.this,
null /* icProto */);
synchronized (mH) {
mCurrentTextBoxAttribute = null;
mCompletions = null;
@@ -1016,6 +1018,11 @@ public final class InputMethodManager {
return mParentInputMethodManager.mActive && !isFinished();
}
@Override
public InputMethodManager getIMM() {
return mParentInputMethodManager;
}
void deactivate() {
if (isFinished()) {
// This is a small performance optimization. Still only the 1st call of
@@ -1713,7 +1720,8 @@ public final class InputMethodManager {
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
null /* icProto */);
// Re-dispatch if there is a context mismatch.
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
if (fallbackImm != null) {
@@ -1822,7 +1830,7 @@ public final class InputMethodManager {
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
this);
this, null /* icProto */);
checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
@@ -2228,7 +2236,8 @@ public final class InputMethodManager {
* @hide
*/
public void notifyImeHidden(IBinder windowToken) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
null /* icProto */);
synchronized (mH) {
try {
if (mCurMethod != null && mCurRootView != null
@@ -3296,7 +3305,7 @@ public final class InputMethodManager {
for (String arg : args) {
if (arg.equals(PROTO_ARG)) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
dumpDebug(proto);
dumpDebug(proto, null /* icProto */);
proto.flush();
return true;
}
@@ -3309,10 +3318,11 @@ public final class InputMethodManager {
* {@link ProtoOutputStream}.
*
* @param proto The proto stream to which the dumps are written.
* @param icProto {@link InputConnection} call data in proto format.
* @hide
*/
@GuardedBy("mH")
public void dumpDebug(ProtoOutputStream proto) {
public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
if (mCurMethod == null) {
return;
}
@@ -3337,6 +3347,9 @@ public final class InputMethodManager {
if (mServedInputConnectionWrapper != null) {
mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
}
if (icProto != null) {
proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
}
}
}
}

View File

@@ -27,6 +27,9 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.util.imetracing.ImeTracing;
import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -36,6 +39,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.SurroundingText;
import com.android.internal.annotations.GuardedBy;
@@ -124,7 +128,9 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
}
abstract protected boolean isActive();
protected abstract boolean isActive();
protected abstract InputMethodManager getIMM();
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
@@ -264,6 +270,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
void executeMessage(Message msg) {
ProtoOutputStream icProto;
switch (msg.what) {
case DO_GET_TEXT_AFTER_CURSOR: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
@@ -278,6 +285,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
msg.arg2, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextAfterCursor", getIMM(), icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -302,6 +315,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
msg.arg2, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextBeforeCursor", getIMM(), icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -326,6 +345,11 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getSelectedText(msg.arg1);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSelectedText", getIMM(), icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -354,6 +378,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getSurroundingText(beforeLength, afterLength, flags);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
afterLength, flags, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSurroundingText", getIMM(), icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -378,6 +408,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getCursorCapsMode(msg.arg1);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getCursorCapsMode", getIMM(), icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -404,6 +440,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getExtractedText(request, msg.arg1);
}
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
msg.arg1, result);
ImeTracing.getInstance().triggerClientDump(
TAG + "#getExtractedText", getIMM(), icProto);
}
try {
callback.onResult(result);
} catch (RemoteException e) {

View File

@@ -24,6 +24,9 @@ import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.imetracing.ImeTracing;
import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -87,8 +90,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
return Completable.getResultOrNull(
CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final AbstractInputMethodService inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
ProtoOutputStream icProto = InputConnectionHelper.buildGetTextAfterCursorProto(length,
flags, result);
ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor",
inputMethodService, icProto);
}
return result;
}
/**
@@ -107,8 +120,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
return Completable.getResultOrNull(
CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final AbstractInputMethodService inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
ProtoOutputStream icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(length,
flags, result);
ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor",
inputMethodService, icProto);
}
return result;
}
@AnyThread
@@ -127,8 +150,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
return Completable.getResultOrNull(
CharSequence result = Completable.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final AbstractInputMethodService inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
ProtoOutputStream icProto = InputConnectionHelper.buildGetSelectedTextProto(flags,
result);
ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText",
inputMethodService, icProto);
}
return result;
}
/**
@@ -161,8 +194,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
return Completable.getResultOrNull(
SurroundingText result = Completable.getResultOrNull(
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final AbstractInputMethodService inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
ProtoOutputStream icProto = InputConnectionHelper.buildGetSurroundingTextProto(
beforeLength, afterLength, flags, result);
ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText",
inputMethodService, icProto);
}
return result;
}
@AnyThread
@@ -177,8 +220,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return 0;
}
return Completable.getResultOrZero(
int result = Completable.getResultOrZero(
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final AbstractInputMethodService inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
ProtoOutputStream icProto = InputConnectionHelper.buildGetCursorCapsModeProto(
reqModes, result);
ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode",
inputMethodService, icProto);
}
return result;
}
@AnyThread
@@ -193,8 +246,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
return Completable.getResultOrNull(
ExtractedText result = Completable.getResultOrNull(
value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final AbstractInputMethodService inputMethodService = mInputMethodService.get();
if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
ProtoOutputStream icProto = InputConnectionHelper.buildGetExtractedTextProto(
request, flags, result);
ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText",
inputMethodService, icProto);
}
return result;
}
@AnyThread

View File

@@ -28,6 +28,7 @@ import android.text.Editable;
import android.text.Selection;
import android.text.method.KeyListener;
import android.util.Log;
import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
@@ -45,7 +46,6 @@ import android.widget.TextView;
public class EditableInputConnection extends BaseInputConnection
implements DumpableInputConnection {
private static final boolean DEBUG = false;
private static final boolean DUMP_TEXT = false;
private static final String TAG = "EditableInputConnection";
private final TextView mTextView;
@@ -243,7 +243,7 @@ public class EditableInputConnection extends BaseInputConnection
final long token = proto.start(fieldId);
CharSequence editableText = mTextView.getText();
CharSequence selectedText = getSelectedText(0 /* flags */);
if (DUMP_TEXT) {
if (InputConnectionHelper.DUMP_TEXT) {
if (editableText != null) {
proto.write(EDITABLE_TEXT, editableText.toString());
}

View File

@@ -18,6 +18,7 @@ syntax = "proto2";
import "frameworks/base/core/proto/android/inputmethodservice/softinputwindow.proto";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
import "frameworks/base/core/proto/android/view/inputmethod/inputconnection.proto";
package android.inputmethodservice;
@@ -51,6 +52,7 @@ message InputMethodServiceProto {
optional int32 status_icon = 25;
optional InsetsProto last_computed_insets = 26;
optional string settings_observer = 27;
optional .android.view.inputmethod.InputConnectionCallProto input_connection_call = 28;
message InsetsProto {
optional int32 content_top_insets = 1;

View File

@@ -31,4 +31,68 @@ message InputConnectionProto {
optional int32 selected_text_start = 3;
optional int32 selected_text_end = 4;
optional int32 cursor_caps_mode = 5;
}
/**
* Shows information about parameters and result for method calls to
* {@link android.view.inputmethod.InputConnection}.
*/
message InputConnectionCallProto {
oneof method_call {
GetTextBeforeCursor get_text_before_cursor = 1;
GetTextAfterCursor get_text_after_cursor = 2;
GetSelectedText get_selected_text = 3;
GetSurroundingText get_surrounding_text = 4;
GetCursorCapsMode get_cursor_caps_mode = 5;
GetExtractedText get_extracted_text = 6;
}
message GetTextBeforeCursor {
optional int32 length = 1;
optional int32 flags = 2;
optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
}
message GetTextAfterCursor {
optional int32 length = 1;
optional int32 flags = 2;
optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
}
message GetSelectedText {
optional int32 flags = 1;
optional string result = 2 [(.android.privacy).dest = DEST_LOCAL];
}
message GetSurroundingText {
optional int32 before_length = 1;
optional int32 after_length = 2;
optional int32 flags = 3;
optional SurroundingText result = 4;
message SurroundingText {
optional string text = 1 [(.android.privacy).dest = DEST_LOCAL];
optional int32 selection_start = 2;
optional int32 selection_end = 3;
optional int32 offset = 4;
}
}
message GetCursorCapsMode {
optional int32 req_modes = 1;
optional int32 result = 2;
}
message GetExtractedText {
optional ExtractedTextRequest request = 1;
optional int32 flags = 2;
optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
message ExtractedTextRequest {
optional int32 token = 1;
optional int32 flags = 2;
optional int32 hint_max_lines = 3;
optional int32 hint_max_chars = 4;
}
}
}

View File

@@ -72,6 +72,7 @@ message InputMethodClientsTraceProto {
optional EditorInfoProto editor_info = 6;
optional ImeFocusControllerProto ime_focus_controller = 7;
optional InputConnectionProto input_connection = 8;
optional InputConnectionCallProto input_connection_call = 9;
}
}