Loading core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3961,6 +3961,7 @@ package android.view.inputmethod { method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int); method public boolean hasActiveInputConnection(@Nullable android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void hideSoftInputFromServerForTest(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown(); method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle); Loading core/java/android/inputmethodservice/IInputMethodWrapper.java +2 −2 Original line number Diff line number Diff line Loading @@ -453,7 +453,7 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken, public void showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken, @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER); mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT, Loading @@ -462,7 +462,7 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override public void hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken, public void hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken, int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER); mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT, Loading core/java/android/inputmethodservice/InputMethodService.java +131 −31 Original line number Diff line number Diff line Loading @@ -701,7 +701,13 @@ public class InputMethodService extends AbstractInputMethodService { */ private IBinder mCurHideInputToken; /** The token tracking the current IME request or {@code null} otherwise. */ /** * The token tracking the current IME request. * * <p> This exists as a workaround to changing the signatures of public methods. It will get * set to a {@code non-null} value before every call that uses it, stored locally inside the * callee, and immediately after reset to {@code null} from the callee. */ @Nullable private ImeTracker.Token mCurStatsToken; Loading Loading @@ -907,14 +913,13 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver, IBinder hideInputToken, @Nullable ImeTracker.Token statsToken) { IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) { mSystemCallingHideSoftInput = true; mCurHideInputToken = hideInputToken; mCurStatsToken = statsToken; try { hideSoftInput(flags, resultReceiver); } finally { mCurStatsToken = null; mCurHideInputToken = null; mSystemCallingHideSoftInput = false; } Loading @@ -926,23 +931,33 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public void hideSoftInput(int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress( mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT); if (DEBUG) Log.v(TAG, "hideSoftInput()"); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(false /* show */, SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods. if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R && !mSystemCallingHideSoftInput) { Log.e(TAG, "IME shouldn't call hideSoftInput on itself." + " Use requestHideSelf(int) itself"); ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT); return; } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput"); ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#hideSoftInput", mDumper, null /* icProto */); final boolean wasVisible = isInputViewShown(); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput"); mShowInputFlags = 0; mShowInputRequested = false; mCurStatsToken = statsToken; hideWindow(); final boolean isVisible = isInputViewShown(); final boolean visibilityChanged = isVisible != wasVisible; Loading @@ -963,14 +978,13 @@ public class InputMethodService extends AbstractInputMethodService { @Override public void showSoftInputWithToken(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver, IBinder showInputToken, @Nullable ImeTracker.Token statsToken) { @NonNull ImeTracker.Token statsToken) { mSystemCallingShowSoftInput = true; mCurShowInputToken = showInputToken; mCurStatsToken = statsToken; try { showSoftInput(flags, resultReceiver); } finally { mCurStatsToken = null; mCurShowInputToken = null; mSystemCallingShowSoftInput = false; } Loading @@ -982,16 +996,23 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public void showSoftInput(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress( mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT); if (DEBUG) Log.v(TAG, "showSoftInput()"); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(true /* show */, SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods. if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R && !mSystemCallingShowSoftInput) { Log.e(TAG, "IME shouldn't call showSoftInput on itself." + " Use requestShowSelf(int) itself"); ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT); return; } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput"); ImeTracing.getInstance().triggerServiceDump( Loading @@ -999,11 +1020,12 @@ public class InputMethodService extends AbstractInputMethodService { null /* icProto */); final boolean wasVisible = isInputViewShown(); if (dispatchOnShowInputRequested(flags, false)) { ImeTracker.forLogging().onProgress(mCurStatsToken, ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE); showWindow(true); mCurStatsToken = statsToken; showWindow(true /* showInput */); } else { ImeTracker.forLogging().onFailed(mCurStatsToken, ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE); } setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition); Loading Loading @@ -1895,21 +1917,23 @@ public class InputMethodService extends AbstractInputMethodService { if (showingInput) { // If we were last showing the soft keyboard, try to do so again. if (dispatchOnShowInputRequested(showFlags, true)) { showWindow(true); showWindowWithToken(true /* showInput */, SoftInputShowHideReason.RESET_NEW_CONFIGURATION); if (completions != null) { mCurCompletions = completions; onDisplayCompletions(completions); } } else { hideWindow(); hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION); } } else if (mCandidatesVisibility == View.VISIBLE) { // If the candidates are currently visible, make sure the // window is shown for them. showWindow(false); showWindowWithToken(false /* showInput */, SoftInputShowHideReason.RESET_NEW_CONFIGURATION); } else { // Otherwise hide the window. hideWindow(); hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION); } // If user uses hard keyboard, IME button should always be shown. boolean showing = onEvaluateInputViewShown(); Loading Loading @@ -2368,9 +2392,11 @@ public class InputMethodService extends AbstractInputMethodService { // has not asked for the input view to be shown, then we need // to update whether the window is shown. if (shown) { showWindow(false); showWindowWithToken(false /* showInput */, SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY); } else { hideWindow(); hideWindowWithToken( SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY); } } } Loading Loading @@ -3009,6 +3035,19 @@ public class InputMethodService extends AbstractInputMethodService { return result; } /** * Utility function that creates an IME request tracking token before * calling {@link #showWindow}. * * @param showInput whether the input window should be shown. * @param reason the reason why the IME request was created. */ private void showWindowWithToken(boolean showInput, @SoftInputShowHideReason int reason) { mCurStatsToken = createStatsToken(true /* show */, reason, ImeTracker.isFromUser(mRootView)); showWindow(showInput); } public void showWindow(boolean showInput) { if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput + " mShowInputRequested=" + mShowInputRequested Loading @@ -3018,11 +3057,20 @@ public class InputMethodService extends AbstractInputMethodService { + " mInputStarted=" + mInputStarted + " mShowInputFlags=" + mShowInputFlags); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(true /* show */, SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; if (mInShowWindow) { Log.w(TAG, "Re-entrance in to showWindow"); ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW); return; } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW); ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper, null /* icProto */); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow"); Loading @@ -3046,7 +3094,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "showWindow: draw decorView!"); mWindow.show(); mDecorViewWasVisible = true; applyVisibilityInInsetsConsumerIfNecessary(true); applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken); cancelImeSurfaceRemoval(); mInShowWindow = false; Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Loading Loading @@ -3137,13 +3185,15 @@ public class InputMethodService extends AbstractInputMethodService { * Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}. * * @param setVisible {@code true} to make it visible, false to hide it. * @param statsToken the token tracking the current IME request. */ private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) { private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible, @NonNull ImeTracker.Token statsToken) { ImeTracing.getInstance().triggerServiceDump( "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper, null /* icProto */); mPrivOps.applyImeVisibilityAsync(setVisible ? mCurShowInputToken : mCurHideInputToken, setVisible, mCurStatsToken); ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken); } private void finishViews(boolean finishingInput) { Loading @@ -3159,12 +3209,35 @@ public class InputMethodService extends AbstractInputMethodService { mCandidatesViewStarted = false; } /** * Utility function that creates an IME request tracking token before * calling {@link #hideWindow}. * * @param reason the reason why the IME request was created. */ private void hideWindowWithToken(@SoftInputShowHideReason int reason) { // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it // to work with onClickListeners final boolean isFromUser = ImeTracker.isFromUser(mRootView) || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY; mCurStatsToken = createStatsToken(false /* show */, reason, isFromUser); hideWindow(); } public void hideWindow() { if (DEBUG) Log.v(TAG, "CALL: hideWindow"); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(false /* show */, SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW); ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper, null /* icProto */); setImeWindowStatus(0, mBackDisposition); applyVisibilityInInsetsConsumerIfNecessary(false); applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken); mWindowVisible = false; finishViews(false /* finishingInput */); if (mDecorViewVisible) { Loading Loading @@ -3440,9 +3513,14 @@ public class InputMethodService extends AbstractInputMethodService { private void requestHideSelf(@InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) { // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it // to work with onClickListeners final boolean isFromUser = ImeTracker.isFromUser(mRootView) || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY; final var statsToken = createStatsToken(false /* show */, reason, isFromUser); ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper, null /* icProto */); mPrivOps.hideMySoftInput(flags, reason); mPrivOps.hideMySoftInput(statsToken, flags, reason); } /** Loading @@ -3450,9 +3528,16 @@ public class InputMethodService extends AbstractInputMethodService { * interact with it. */ public final void requestShowSelf(@InputMethodManager.ShowFlags int flags) { requestShowSelf(flags, SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME); } private void requestShowSelf(@InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) { final var statsToken = createStatsToken(true /* show */, reason, ImeTracker.isFromUser(mRootView)); ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper, null /* icProto */); mPrivOps.showMySoftInput(flags); mPrivOps.showMySoftInput(statsToken, flags, reason); } private boolean handleBack(boolean doIt) { Loading @@ -3472,7 +3557,7 @@ public class InputMethodService extends AbstractInputMethodService { // If we have the window visible for some other reason -- // most likely to show candidates -- then just get rid // of it. This really shouldn't happen, but just in case... if (doIt) hideWindow(); if (doIt) hideWindowWithToken(SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY); } return true; } Loading Loading @@ -3627,10 +3712,11 @@ public class InputMethodService extends AbstractInputMethodService { @InputMethodManager.HideFlags int hideFlags) { if (DEBUG) Log.v(TAG, "toggleSoftInput()"); if (isInputViewShown()) { requestHideSelf( hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT); requestHideSelf(hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT); } else { requestShowSelf(showFlags); requestShowSelf(showFlags, SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT); } } Loading Loading @@ -4271,6 +4357,20 @@ public class InputMethodService extends AbstractInputMethodService { | (isInputViewShown() ? IME_VISIBLE : 0); } /** * Creates an IME request tracking token. * * @param show whether this is a show or a hide request. * @param reason the reason why the IME request was created. * @param isFromUser whether this request was created directly from user interaction. */ @NonNull private ImeTracker.Token createStatsToken(boolean show, @SoftInputShowHideReason int reason, boolean isFromUser) { return ImeTracker.forLogging().onStart(show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_IME, reason, isFromUser); } /** * Performs a dump of the InputMethodService's internal state. Override * to add your own information to the dump. Loading core/java/android/view/IWindow.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ oneway interface IWindow { * * @param types internal insets types (WindowInsets.Type.InsetsType) to show * @param fromIme true if this request originated from IME (InputMethodService). * @param statsToken the token tracking the current IME show request or {@code null} otherwise. * @param statsToken the token tracking the current IME request or {@code null} otherwise. */ void showInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken); Loading @@ -82,7 +82,7 @@ oneway interface IWindow { * * @param types internal insets types (WindowInsets.Type.InsetsType) to hide * @param fromIme true if this request originated from IME (InputMethodService). * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. * @param statsToken the token tracking the current IME request or {@code null} otherwise. */ void hideInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken); Loading core/java/android/view/ImeInsetsSourceConsumer.java +17 −17 Original line number Diff line number Diff line Loading @@ -21,9 +21,9 @@ import static android.view.ImeInsetsSourceConsumerProto.HAS_PENDING_REQUEST; import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER; import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; Loading Loading @@ -70,7 +70,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { if (!isShowRequested()) { mIsRequestedVisibleAwaitingControl = false; if (!running && !mHasPendingRequest) { notifyHidden(null /* statsToken */); final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED, mController.getHost().isHandlingPointerEvent() /* fromUser */); notifyHidden(statsToken); removeSurface(); } } Loading Loading @@ -144,9 +148,17 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { void requestHide(boolean fromIme, @Nullable ImeTracker.Token statsToken) { if (!fromIme) { // Create a new token to track the hide request when we have control, // as we use the passed in token for the insets animation already. final var notifyStatsToken = getControl() != null ? ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL, mController.getHost().isHandlingPointerEvent() /* fromUser */) : statsToken; // The insets might be controlled by a remote target. Let the server know we are // requested to hide. notifyHidden(statsToken); notifyHidden(notifyStatsToken); } if (mAnimationState == ANIMATION_STATE_SHOW) { mHasPendingRequest = true; Loading @@ -157,21 +169,9 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { * Notify {@link com.android.server.inputmethod.InputMethodManagerService} that * IME insets are hidden. * * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. * @param statsToken the token tracking the current IME request or {@code null} otherwise. */ private void notifyHidden(@Nullable ImeTracker.Token statsToken) { // Create a new stats token to track the hide request when: // - we do not already have one, or // - we do already have one, but we have control and use the passed in token // for the insets animation already. if (statsToken == null || getControl() != null) { statsToken = ImeTracker.forLogging().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, mController.getHost().isHandlingPointerEvent() /* fromUser */); } private void notifyHidden(@NonNull ImeTracker.Token statsToken) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN); Loading Loading
core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3961,6 +3961,7 @@ package android.view.inputmethod { method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int); method public boolean hasActiveInputConnection(@Nullable android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void hideSoftInputFromServerForTest(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown(); method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle); Loading
core/java/android/inputmethodservice/IInputMethodWrapper.java +2 −2 Original line number Diff line number Diff line Loading @@ -453,7 +453,7 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken, public void showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken, @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER); mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT, Loading @@ -462,7 +462,7 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override public void hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken, public void hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken, int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER); mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT, Loading
core/java/android/inputmethodservice/InputMethodService.java +131 −31 Original line number Diff line number Diff line Loading @@ -701,7 +701,13 @@ public class InputMethodService extends AbstractInputMethodService { */ private IBinder mCurHideInputToken; /** The token tracking the current IME request or {@code null} otherwise. */ /** * The token tracking the current IME request. * * <p> This exists as a workaround to changing the signatures of public methods. It will get * set to a {@code non-null} value before every call that uses it, stored locally inside the * callee, and immediately after reset to {@code null} from the callee. */ @Nullable private ImeTracker.Token mCurStatsToken; Loading Loading @@ -907,14 +913,13 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver, IBinder hideInputToken, @Nullable ImeTracker.Token statsToken) { IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) { mSystemCallingHideSoftInput = true; mCurHideInputToken = hideInputToken; mCurStatsToken = statsToken; try { hideSoftInput(flags, resultReceiver); } finally { mCurStatsToken = null; mCurHideInputToken = null; mSystemCallingHideSoftInput = false; } Loading @@ -926,23 +931,33 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public void hideSoftInput(int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress( mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT); if (DEBUG) Log.v(TAG, "hideSoftInput()"); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(false /* show */, SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods. if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R && !mSystemCallingHideSoftInput) { Log.e(TAG, "IME shouldn't call hideSoftInput on itself." + " Use requestHideSelf(int) itself"); ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT); return; } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput"); ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#hideSoftInput", mDumper, null /* icProto */); final boolean wasVisible = isInputViewShown(); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput"); mShowInputFlags = 0; mShowInputRequested = false; mCurStatsToken = statsToken; hideWindow(); final boolean isVisible = isInputViewShown(); final boolean visibilityChanged = isVisible != wasVisible; Loading @@ -963,14 +978,13 @@ public class InputMethodService extends AbstractInputMethodService { @Override public void showSoftInputWithToken(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver, IBinder showInputToken, @Nullable ImeTracker.Token statsToken) { @NonNull ImeTracker.Token statsToken) { mSystemCallingShowSoftInput = true; mCurShowInputToken = showInputToken; mCurStatsToken = statsToken; try { showSoftInput(flags, resultReceiver); } finally { mCurStatsToken = null; mCurShowInputToken = null; mSystemCallingShowSoftInput = false; } Loading @@ -982,16 +996,23 @@ public class InputMethodService extends AbstractInputMethodService { @MainThread @Override public void showSoftInput(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) { ImeTracker.forLogging().onProgress( mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT); if (DEBUG) Log.v(TAG, "showSoftInput()"); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(true /* show */, SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods. if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R && !mSystemCallingShowSoftInput) { Log.e(TAG, "IME shouldn't call showSoftInput on itself." + " Use requestShowSelf(int) itself"); ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT); return; } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput"); ImeTracing.getInstance().triggerServiceDump( Loading @@ -999,11 +1020,12 @@ public class InputMethodService extends AbstractInputMethodService { null /* icProto */); final boolean wasVisible = isInputViewShown(); if (dispatchOnShowInputRequested(flags, false)) { ImeTracker.forLogging().onProgress(mCurStatsToken, ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE); showWindow(true); mCurStatsToken = statsToken; showWindow(true /* showInput */); } else { ImeTracker.forLogging().onFailed(mCurStatsToken, ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE); } setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition); Loading Loading @@ -1895,21 +1917,23 @@ public class InputMethodService extends AbstractInputMethodService { if (showingInput) { // If we were last showing the soft keyboard, try to do so again. if (dispatchOnShowInputRequested(showFlags, true)) { showWindow(true); showWindowWithToken(true /* showInput */, SoftInputShowHideReason.RESET_NEW_CONFIGURATION); if (completions != null) { mCurCompletions = completions; onDisplayCompletions(completions); } } else { hideWindow(); hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION); } } else if (mCandidatesVisibility == View.VISIBLE) { // If the candidates are currently visible, make sure the // window is shown for them. showWindow(false); showWindowWithToken(false /* showInput */, SoftInputShowHideReason.RESET_NEW_CONFIGURATION); } else { // Otherwise hide the window. hideWindow(); hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION); } // If user uses hard keyboard, IME button should always be shown. boolean showing = onEvaluateInputViewShown(); Loading Loading @@ -2368,9 +2392,11 @@ public class InputMethodService extends AbstractInputMethodService { // has not asked for the input view to be shown, then we need // to update whether the window is shown. if (shown) { showWindow(false); showWindowWithToken(false /* showInput */, SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY); } else { hideWindow(); hideWindowWithToken( SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY); } } } Loading Loading @@ -3009,6 +3035,19 @@ public class InputMethodService extends AbstractInputMethodService { return result; } /** * Utility function that creates an IME request tracking token before * calling {@link #showWindow}. * * @param showInput whether the input window should be shown. * @param reason the reason why the IME request was created. */ private void showWindowWithToken(boolean showInput, @SoftInputShowHideReason int reason) { mCurStatsToken = createStatsToken(true /* show */, reason, ImeTracker.isFromUser(mRootView)); showWindow(showInput); } public void showWindow(boolean showInput) { if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput + " mShowInputRequested=" + mShowInputRequested Loading @@ -3018,11 +3057,20 @@ public class InputMethodService extends AbstractInputMethodService { + " mInputStarted=" + mInputStarted + " mShowInputFlags=" + mShowInputFlags); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(true /* show */, SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; if (mInShowWindow) { Log.w(TAG, "Re-entrance in to showWindow"); ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW); return; } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW); ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper, null /* icProto */); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow"); Loading @@ -3046,7 +3094,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "showWindow: draw decorView!"); mWindow.show(); mDecorViewWasVisible = true; applyVisibilityInInsetsConsumerIfNecessary(true); applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken); cancelImeSurfaceRemoval(); mInShowWindow = false; Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Loading Loading @@ -3137,13 +3185,15 @@ public class InputMethodService extends AbstractInputMethodService { * Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}. * * @param setVisible {@code true} to make it visible, false to hide it. * @param statsToken the token tracking the current IME request. */ private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) { private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible, @NonNull ImeTracker.Token statsToken) { ImeTracing.getInstance().triggerServiceDump( "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper, null /* icProto */); mPrivOps.applyImeVisibilityAsync(setVisible ? mCurShowInputToken : mCurHideInputToken, setVisible, mCurStatsToken); ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken); } private void finishViews(boolean finishingInput) { Loading @@ -3159,12 +3209,35 @@ public class InputMethodService extends AbstractInputMethodService { mCandidatesViewStarted = false; } /** * Utility function that creates an IME request tracking token before * calling {@link #hideWindow}. * * @param reason the reason why the IME request was created. */ private void hideWindowWithToken(@SoftInputShowHideReason int reason) { // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it // to work with onClickListeners final boolean isFromUser = ImeTracker.isFromUser(mRootView) || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY; mCurStatsToken = createStatsToken(false /* show */, reason, isFromUser); hideWindow(); } public void hideWindow() { if (DEBUG) Log.v(TAG, "CALL: hideWindow"); final var statsToken = mCurStatsToken != null ? mCurStatsToken : createStatsToken(false /* show */, SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT, ImeTracker.isFromUser(mRootView)); mCurStatsToken = null; ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW); ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper, null /* icProto */); setImeWindowStatus(0, mBackDisposition); applyVisibilityInInsetsConsumerIfNecessary(false); applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken); mWindowVisible = false; finishViews(false /* finishingInput */); if (mDecorViewVisible) { Loading Loading @@ -3440,9 +3513,14 @@ public class InputMethodService extends AbstractInputMethodService { private void requestHideSelf(@InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) { // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it // to work with onClickListeners final boolean isFromUser = ImeTracker.isFromUser(mRootView) || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY; final var statsToken = createStatsToken(false /* show */, reason, isFromUser); ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper, null /* icProto */); mPrivOps.hideMySoftInput(flags, reason); mPrivOps.hideMySoftInput(statsToken, flags, reason); } /** Loading @@ -3450,9 +3528,16 @@ public class InputMethodService extends AbstractInputMethodService { * interact with it. */ public final void requestShowSelf(@InputMethodManager.ShowFlags int flags) { requestShowSelf(flags, SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME); } private void requestShowSelf(@InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) { final var statsToken = createStatsToken(true /* show */, reason, ImeTracker.isFromUser(mRootView)); ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper, null /* icProto */); mPrivOps.showMySoftInput(flags); mPrivOps.showMySoftInput(statsToken, flags, reason); } private boolean handleBack(boolean doIt) { Loading @@ -3472,7 +3557,7 @@ public class InputMethodService extends AbstractInputMethodService { // If we have the window visible for some other reason -- // most likely to show candidates -- then just get rid // of it. This really shouldn't happen, but just in case... if (doIt) hideWindow(); if (doIt) hideWindowWithToken(SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY); } return true; } Loading Loading @@ -3627,10 +3712,11 @@ public class InputMethodService extends AbstractInputMethodService { @InputMethodManager.HideFlags int hideFlags) { if (DEBUG) Log.v(TAG, "toggleSoftInput()"); if (isInputViewShown()) { requestHideSelf( hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT); requestHideSelf(hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT); } else { requestShowSelf(showFlags); requestShowSelf(showFlags, SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT); } } Loading Loading @@ -4271,6 +4357,20 @@ public class InputMethodService extends AbstractInputMethodService { | (isInputViewShown() ? IME_VISIBLE : 0); } /** * Creates an IME request tracking token. * * @param show whether this is a show or a hide request. * @param reason the reason why the IME request was created. * @param isFromUser whether this request was created directly from user interaction. */ @NonNull private ImeTracker.Token createStatsToken(boolean show, @SoftInputShowHideReason int reason, boolean isFromUser) { return ImeTracker.forLogging().onStart(show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_IME, reason, isFromUser); } /** * Performs a dump of the InputMethodService's internal state. Override * to add your own information to the dump. Loading
core/java/android/view/IWindow.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ oneway interface IWindow { * * @param types internal insets types (WindowInsets.Type.InsetsType) to show * @param fromIme true if this request originated from IME (InputMethodService). * @param statsToken the token tracking the current IME show request or {@code null} otherwise. * @param statsToken the token tracking the current IME request or {@code null} otherwise. */ void showInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken); Loading @@ -82,7 +82,7 @@ oneway interface IWindow { * * @param types internal insets types (WindowInsets.Type.InsetsType) to hide * @param fromIme true if this request originated from IME (InputMethodService). * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. * @param statsToken the token tracking the current IME request or {@code null} otherwise. */ void hideInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken); Loading
core/java/android/view/ImeInsetsSourceConsumer.java +17 −17 Original line number Diff line number Diff line Loading @@ -21,9 +21,9 @@ import static android.view.ImeInsetsSourceConsumerProto.HAS_PENDING_REQUEST; import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER; import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; Loading Loading @@ -70,7 +70,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { if (!isShowRequested()) { mIsRequestedVisibleAwaitingControl = false; if (!running && !mHasPendingRequest) { notifyHidden(null /* statsToken */); final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED, mController.getHost().isHandlingPointerEvent() /* fromUser */); notifyHidden(statsToken); removeSurface(); } } Loading Loading @@ -144,9 +148,17 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { void requestHide(boolean fromIme, @Nullable ImeTracker.Token statsToken) { if (!fromIme) { // Create a new token to track the hide request when we have control, // as we use the passed in token for the insets animation already. final var notifyStatsToken = getControl() != null ? ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL, mController.getHost().isHandlingPointerEvent() /* fromUser */) : statsToken; // The insets might be controlled by a remote target. Let the server know we are // requested to hide. notifyHidden(statsToken); notifyHidden(notifyStatsToken); } if (mAnimationState == ANIMATION_STATE_SHOW) { mHasPendingRequest = true; Loading @@ -157,21 +169,9 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { * Notify {@link com.android.server.inputmethod.InputMethodManagerService} that * IME insets are hidden. * * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. * @param statsToken the token tracking the current IME request or {@code null} otherwise. */ private void notifyHidden(@Nullable ImeTracker.Token statsToken) { // Create a new stats token to track the hide request when: // - we do not already have one, or // - we do already have one, but we have control and use the passed in token // for the insets animation already. if (statsToken == null || getControl() != null) { statsToken = ImeTracker.forLogging().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, mController.getHost().isHandlingPointerEvent() /* fromUser */); } private void notifyHidden(@NonNull ImeTracker.Token statsToken) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN); Loading