diff options
| author | 2019-12-29 20:20:41 +0800 | |
|---|---|---|
| committer | 2020-02-24 07:55:29 +0000 | |
| commit | d85e158db8bf763e46b9f877e9ed70214debccb0 (patch) | |
| tree | aed91fc49ddc582d3442c1a33305b92c99a1843b | |
| parent | 5bbfd65359b8e552a7b14c787b8fa02de6e5afc5 (diff) | |
Introduce SoftInputShowHideHistory
Add SoftInputShowHideHistory class to monitor showSoftInput / hideSoftInput
histories, each entry data contains:
- ClientState: IME focused client process pid / uid who
shows / hides soft input
- Current focused window
- Target display ID
- Reason: describes why show / hide input
- Request show or hide input
- Timestamp
Bug: 141738570
Test: manual by calling "adb shell dumpsys input_method"
Change-Id: I21ad1708d68eae59dcd3d414248193fb130dadc2
Merged-In: 10ecd64cddb22e44dfbae10464e24e261d9fdff2
(cherry picked from commit 10ecd64cddb22e44dfbae10464e24e261d9fdff2)
8 files changed, 362 insertions, 35 deletions
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index 382a254b67a6..3876976575ae 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -16,6 +16,8 @@ package com.android.internal.inputmethod; +import android.annotation.AnyThread; +import android.annotation.NonNull; import android.view.WindowManager; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; @@ -25,6 +27,7 @@ import java.util.StringJoiner; * Provides useful methods for debugging. */ public final class InputMethodDebug { + /** * Not intended to be instantiated. */ @@ -174,4 +177,71 @@ public final class InputMethodDebug { return joiner.setEmptyValue("(none)").toString(); } + + + /** + * Converts {@link SoftInputShowHideReason} to {@link String} for history dump. + */ + public static String softInputDisplayReasonToString(@SoftInputShowHideReason int reason) { + switch (reason) { + case SoftInputShowHideReason.SHOW_SOFT_INPUT: + return "SHOW_SOFT_INPUT"; + case SoftInputShowHideReason.ATTACH_NEW_INPUT: + return "ATTACH_NEW_INPUT"; + case SoftInputShowHideReason.SHOW_MY_SOFT_INPUT: + return "SHOW_MY_SOFT_INPUT"; + case SoftInputShowHideReason.HIDE_SOFT_INPUT: + return "HIDE_SOFT_INPUT"; + case SoftInputShowHideReason.HIDE_MY_SOFT_INPUT: + return "HIDE_MY_SOFT_INPUT"; + case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV: + return "SHOW_AUTO_EDITOR_FORWARD_NAV"; + case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV: + return "SHOW_STATE_VISIBLE_FORWARD_NAV"; + case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE: + return "SHOW_STATE_ALWAYS_VISIBLE"; + case SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE: + return "SHOW_SETTINGS_ON_CHANGE"; + case SoftInputShowHideReason.HIDE_SWITCH_USER: + return "HIDE_SWITCH_USER"; + case SoftInputShowHideReason.HIDE_INVALID_USER: + return "HIDE_INVALID_USER"; + case SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW: + return "HIDE_UNSPECIFIED_WINDOW"; + case SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV: + return "HIDE_STATE_HIDDEN_FORWARD_NAV"; + case SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE: + return "HIDE_ALWAYS_HIDDEN_STATE"; + case SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND: + return "HIDE_RESET_SHELL_COMMAND"; + case SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE: + return "HIDE_SETTINGS_ON_CHANGE"; + case SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME: + return "HIDE_POWER_BUTTON_GO_HOME"; + case SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED: + return "HIDE_DOCKED_STACK_ATTACHED"; + case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION: + return "HIDE_RECENTS_ANIMATION"; + default: + return "Unknown=" + reason; + } + } + + /** + * Return a fixed size string of the object. + * TODO(b/141738570): Take & return with StringBuilder to make more memory efficient. + */ + @NonNull + @AnyThread + public static String objToString(Object obj) { + if (obj == null) { + return "null"; + } + StringBuilder sb = new StringBuilder(64); + sb.setLength(0); + sb.append(obj.getClass().getName()); + sb.append("@"); + sb.append(Integer.toHexString(obj.hashCode())); + return sb.toString(); + } } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java new file mode 100644 index 000000000000..79397b81ace7 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -0,0 +1,143 @@ +/* + * 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 com.android.internal.inputmethod; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.view.WindowManager.LayoutParams; + +import java.lang.annotation.Retention; + +/** + * Describes the reason why Soft input window visible / hidden. + */ +@Retention(SOURCE) +@IntDef(value = { + SoftInputShowHideReason.SHOW_SOFT_INPUT, + SoftInputShowHideReason.ATTACH_NEW_INPUT, + SoftInputShowHideReason.SHOW_MY_SOFT_INPUT, + SoftInputShowHideReason.HIDE_SOFT_INPUT, + SoftInputShowHideReason.HIDE_MY_SOFT_INPUT, + SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV, + SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV, + SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE, + SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, + SoftInputShowHideReason.HIDE_SWITCH_USER, + SoftInputShowHideReason.HIDE_INVALID_USER, + SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW, + SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV, + SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE, + SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND, + SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE, + SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME, + SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED, + SoftInputShowHideReason.HIDE_RECENTS_ANIMATION}) +public @interface SoftInputShowHideReason { + /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ + int SHOW_SOFT_INPUT = 0; + + /** Show soft input when {@code InputMethodManagerService#attachNewInputLocked} called. */ + int ATTACH_NEW_INPUT = 1; + + /** Show soft input by {@code InputMethodManagerService#showMySoftInput}. */ + int SHOW_MY_SOFT_INPUT = 2; + + /** + * Hide soft input by + * {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow}. + */ + int HIDE_SOFT_INPUT = 3; + + /** Hide soft input by {@code InputMethodManagerService#hideMySoftInput}. */ + int HIDE_MY_SOFT_INPUT = 4; + + /** + * Show soft input when navigated forward to the window (with + * {@link LayoutParams#SOFT_INPUT_IS_FORWARD_NAVIGATION}} which the focused view is text + * editor and system will auto-show the IME when the window can resize or running on a large + * screen. + */ + int SHOW_AUTO_EDITOR_FORWARD_NAV = 5; + + /** + * Show soft input when navigated forward to the window with + * {@link LayoutParams#SOFT_INPUT_IS_FORWARD_NAVIGATION} and + * {@link LayoutParams#SOFT_INPUT_STATE_VISIBLE}. + */ + int SHOW_STATE_VISIBLE_FORWARD_NAV = 6; + + /** + * Show soft input when the window with {@link LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE}. + */ + int SHOW_STATE_ALWAYS_VISIBLE = 7; + + /** + * Show soft input during {@code InputMethodManagerService} receive changes from + * {@code SettingsProvider}. + */ + int SHOW_SETTINGS_ON_CHANGE = 8; + + /** Hide soft input during switching user. */ + int HIDE_SWITCH_USER = 9; + + /** Hide soft input when the user is invalid. */ + int HIDE_INVALID_USER = 10; + + /** + * Hide soft input when the window with {@link LayoutParams#SOFT_INPUT_STATE_UNSPECIFIED} which + * the focused view is not text editor. + */ + int HIDE_UNSPECIFIED_WINDOW = 11; + + /** + * Hide soft input when navigated forward to the window with + * {@link LayoutParams#SOFT_INPUT_IS_FORWARD_NAVIGATION} and + * {@link LayoutParams#SOFT_INPUT_STATE_HIDDEN}. + */ + int HIDE_STATE_HIDDEN_FORWARD_NAV = 12; + + /** + * Hide soft input when the window with {@link LayoutParams#SOFT_INPUT_STATE_ALWAYS_HIDDEN}. + */ + int HIDE_ALWAYS_HIDDEN_STATE = 13; + + /** Hide soft input when "adb shell ime <command>" called. */ + int HIDE_RESET_SHELL_COMMAND = 14; + + /** + * Hide soft input during {@code InputMethodManagerService} receive changes from + * {@code SettingsProvider}. + */ + int HIDE_SETTINGS_ON_CHANGE = 15; + + /** + * Hide soft input from {@link com.android.server.policy.PhoneWindowManager} when setting + * {@link com.android.internal.R.integer#config_shortPressOnPowerBehavior} in config.xml as + * dismiss IME. + */ + int HIDE_POWER_BUTTON_GO_HOME = 16; + + /** Hide soft input when attaching docked stack. */ + int HIDE_DOCKED_STACK_ATTACHED = 17; + + /** + * Hide soft input when {@link com.android.server.wm.RecentsAnimationController} starts + * intercept touch from app window. + */ + int HIDE_RECENTS_ANIMATION = 18; +} diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index eac2d24c3dab..f24699a6ae64 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -21,6 +21,7 @@ import android.annotation.UserIdInt; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputMethodInfo; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.server.LocalServices; @@ -51,7 +52,7 @@ public abstract class InputMethodManagerInternal { /** * Hides the current input method, if visible. */ - public abstract void hideCurrentInputMethod(); + public abstract void hideCurrentInputMethod(@SoftInputShowHideReason int reason); /** * Returns the list of installed input methods for the specified user. @@ -106,7 +107,7 @@ public abstract class InputMethodManagerInternal { } @Override - public void hideCurrentInputMethod() { + public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { } @Override diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 87262a844b18..d161c410be01 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -131,6 +131,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodDebug; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import com.android.internal.inputmethod.UnbindReason; @@ -767,6 +768,75 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("mMethodMap") private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>(); + private static final class SoftInputShowHideHistory { + private Entry[] mEntries = new Entry[16]; + private int mNextIndex = 0; + private static final AtomicInteger sSequenceNumber = new AtomicInteger(0); + + // TODO(b/141738570): add requestWindowToken to track who request show / hide softInput. + private static final class Entry { + ClientState mClientState; + String mFocusedWindowString; + @SoftInputModeFlags + int mFocusedWindowSoftInputMode; + @SoftInputShowHideReason + int mReason; + boolean mRequestShowKeyboard; + // The timing of handling MSG_SHOW_SOFT_INPUT or MSG_HIDE_SOFT_INPUT. + long mTimestamp; + long mWallTime; + int mTargetDisplayId; + + Entry(ClientState client, String focusedWindow, @SoftInputModeFlags int softInputMode, + @SoftInputShowHideReason int reason, boolean show) { + mClientState = client; + mFocusedWindowString = focusedWindow; + mFocusedWindowSoftInputMode = softInputMode; + mReason = reason; + mRequestShowKeyboard = show; + mTimestamp = SystemClock.uptimeMillis(); + mWallTime = System.currentTimeMillis(); + } + } + + void addEntry(@NonNull Entry entry) { + final int index = mNextIndex; + mEntries[index] = entry; + mNextIndex = (mNextIndex + 1) % mEntries.length; + } + + void dump(@NonNull PrintWriter pw, @NonNull String prefix) { + final SimpleDateFormat dataFormat = + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US); + + for (int i = 0; i < mEntries.length; ++i) { + final Entry entry = mEntries[(i + mNextIndex) % mEntries.length]; + if (entry == null) { + continue; + } + pw.print(prefix); + pw.println("SoftInputShowHideHistory #" + sSequenceNumber.getAndIncrement() + ":"); + + pw.print(prefix); + pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime)) + + " (timestamp=" + entry.mTimestamp + ")"); + + pw.print(prefix); + pw.print(" requestShowKeyboard=" + entry.mRequestShowKeyboard); + pw.print(" targetDisplayId=" + entry.mTargetDisplayId); + pw.println(" reason=" + entry.mReason); + + pw.print(prefix); + pw.print(" requestClient=" + entry.mClientState); + pw.println(" focusedWindow=" + entry.mFocusedWindowString); + + pw.print(prefix); + pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString( + entry.mFocusedWindowSoftInputMode)); + } + } + } + /** * Map of generated token to windowToken that is requesting * {@link InputMethodManager#showSoftInput(View, int)}. @@ -933,6 +1003,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @NonNull private final StartInputHistory mStartInputHistory = new StartInputHistory(); + @GuardedBy("mMethodMap") + @NonNull + private final SoftInputShowHideHistory mSoftInputShowHideHistory = + new SoftInputShowHideHistory(); + class SettingsObserver extends ContentObserver { int mUserId; boolean mRegistered = false; @@ -989,11 +1064,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub == AccessibilityService.SHOW_MODE_HIDDEN; if (mAccessibilityRequestingNoSoftKeyboard) { final boolean showRequested = mShowRequested; - hideCurrentInputLocked(0, null); + hideCurrentInputLocked(0, null, + SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE); mShowRequested = showRequested; } else if (mShowRequested) { - showCurrentInputLocked( - mCurFocusedWindow, InputMethodManager.SHOW_IMPLICIT, null); + showCurrentInputLocked(mCurFocusedWindow, + InputMethodManager.SHOW_IMPLICIT, null, + SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE); } } else { boolean enabledChanged = false; @@ -1618,7 +1695,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // TODO: Is it really possible that switchUserLocked() happens before system ready? if (mSystemReady) { - hideCurrentInputLocked(0, null); + hideCurrentInputLocked(0, null, SoftInputShowHideReason.HIDE_SWITCH_USER); resetCurrentMethodAndClient(UnbindReason.SWITCH_USER); buildInputMethodListLocked(initialUserSwitch); if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) { @@ -2154,7 +2231,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub startInputToken, session, mCurInputContext, mCurAttribute)); if (mShowRequested) { if (DEBUG) Slog.v(TAG, "Attach new input asks to show input"); - showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null); + showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null, + SoftInputShowHideReason.ATTACH_NEW_INPUT); } return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION, session.session, (session.channel != null ? session.channel.dup() : null), @@ -2893,7 +2971,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } if (DEBUG) Slog.v(TAG, "Client requesting input be shown"); - return showCurrentInputLocked(windowToken, flags, resultReceiver); + return showCurrentInputLocked(windowToken, flags, resultReceiver, + SoftInputShowHideReason.SHOW_SOFT_INPUT); } finally { Binder.restoreCallingIdentity(ident); } @@ -2901,7 +2980,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver) { + boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason) { mShowRequested = true; if (mAccessibilityRequestingNoSoftKeyboard) { return false; @@ -2924,9 +3004,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // create a dummy token for IMS so that IMS cannot inject windows into client app. Binder showInputToken = new Binder(); mShowRequestWindowMap.put(showInputToken, windowToken); - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO( - MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod, - resultReceiver, showInputToken)); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO( + MSG_SHOW_SOFT_INPUT, getImeShowFlags(), reason, mCurMethod, resultReceiver, + showInputToken)); mInputShown = true; if (mHaveConnection && !mVisibleBound) { bindCurrentInputMethodServiceLocked( @@ -2984,14 +3064,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (DEBUG) Slog.v(TAG, "Client requesting input be hidden"); - return hideCurrentInputLocked(flags, resultReceiver); + return hideCurrentInputLocked(flags, resultReceiver, + SoftInputShowHideReason.HIDE_SOFT_INPUT); } finally { Binder.restoreCallingIdentity(ident); } } } - boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) { + boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason) { if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0 && (mShowExplicitlyRequested || mShowForced)) { if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide"); @@ -3018,8 +3100,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // delivered to the IME process as an IPC. Hence the inconsistency between // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in // the final state. - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver)); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(MSG_HIDE_SOFT_INPUT, + reason, mCurMethod, resultReceiver)); res = true; } else { res = false; @@ -3156,7 +3238,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "If you need to impersonate a foreground user/profile from" + " a background user, use EditorInfo.targetInputMethodUser with" + " INTERACT_ACROSS_USERS_FULL permission."); - hideCurrentInputLocked(0, null); + hideCurrentInputLocked(0, null, SoftInputShowHideReason.HIDE_INVALID_USER); return InputBindResult.INVALID_USER; } @@ -3219,7 +3301,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // be behind any soft input window, so hide the // soft input window if it is shown. if (DEBUG) Slog.v(TAG, "Unspecified window will hide input"); - hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null); + hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null, + SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW); // If focused display changed, we should unbind current method // to make app window in previous display relayout after Ime @@ -3245,7 +3328,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub attribute, startInputFlags, startInputReason); didStart = true; } - showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null); + showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, + SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV); } break; case LayoutParams.SOFT_INPUT_STATE_UNCHANGED: @@ -3254,12 +3338,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case LayoutParams.SOFT_INPUT_STATE_HIDDEN: if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward"); - hideCurrentInputLocked(0, null); + hideCurrentInputLocked(0, null, + SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV); } break; case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: if (DEBUG) Slog.v(TAG, "Window asks to hide input"); - hideCurrentInputLocked(0, null); + hideCurrentInputLocked(0, null, + SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE); break; case LayoutParams.SOFT_INPUT_STATE_VISIBLE: if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { @@ -3271,7 +3357,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub attribute, startInputFlags, startInputReason); didStart = true; } - showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null); + showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, + SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV); } else { Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because" + " there is no focused view that also returns true from" @@ -3288,7 +3375,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub attribute, startInputFlags, startInputReason); didStart = true; } - showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null); + showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null, + SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE); } else { Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because" + " there is no focused view that also returns true from" @@ -3780,7 +3868,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } long ident = Binder.clearCallingIdentity(); try { - hideCurrentInputLocked(flags, null); + hideCurrentInputLocked(flags, null, SoftInputShowHideReason.HIDE_MY_SOFT_INPUT); } finally { Binder.restoreCallingIdentity(ident); } @@ -3795,7 +3883,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } long ident = Binder.clearCallingIdentity(); try { - showCurrentInputLocked(mLastImeTargetWindow, flags, null); + showCurrentInputLocked(mLastImeTargetWindow, flags, null, + SoftInputShowHideReason.SHOW_MY_SOFT_INPUT); } finally { Binder.restoreCallingIdentity(ident); } @@ -3878,10 +3967,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case MSG_SHOW_SOFT_INPUT: args = (SomeArgs)msg.obj; try { + final @SoftInputShowHideReason int reason = msg.arg2; if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput(" - + msg.arg1 + ", " + args.arg2 + ")"); + + msg.arg1 + ", " + args.arg2 + ") for reason: " + + InputMethodDebug.softInputDisplayReasonToString(reason)); ((IInputMethod) args.arg1).showSoftInput( (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2); + mSoftInputShowHideHistory.addEntry( + new SoftInputShowHideHistory.Entry(mCurClient, + InputMethodDebug.objToString(mCurFocusedWindow), + mCurFocusedWindowSoftInputMode, reason, true /* show */)); } catch (RemoteException e) { } args.recycle(); @@ -3889,16 +3984,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case MSG_HIDE_SOFT_INPUT: args = (SomeArgs)msg.obj; try { + final @SoftInputShowHideReason int reason = msg.arg1; if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, " - + args.arg2 + ")"); + + args.arg2 + ") for reason: " + + InputMethodDebug.softInputDisplayReasonToString(reason)); ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2); + mSoftInputShowHideHistory.addEntry( + new SoftInputShowHideHistory.Entry(mCurClient, + InputMethodDebug.objToString(mCurFocusedWindow), + mCurFocusedWindowSoftInputMode, reason, false /* show */)); } catch (RemoteException e) { } args.recycle(); return true; case MSG_HIDE_CURRENT_INPUT_METHOD: synchronized (mMethodMap) { - hideCurrentInputLocked(0, null); + final @SoftInputShowHideReason int reason = (int) msg.obj; + hideCurrentInputLocked(0, null, reason); } return true; case MSG_INITIALIZE_IME: @@ -4682,9 +4784,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void hideCurrentInputMethod() { + public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD); - mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD); + mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget(); } @Override @@ -4841,6 +4943,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" mStartInputHistory:"); mStartInputHistory.dump(pw, " "); + + p.println(" mSoftInputShowHideHistory:"); + mSoftInputShowHideHistory.dump(pw, " "); } p.println(" "); @@ -5300,7 +5405,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final String nextIme; final List<InputMethodInfo> nextEnabledImes; if (userId == mSettings.getCurrentUserId()) { - hideCurrentInputLocked(0, null); + hideCurrentInputLocked(0, null, + SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND); unbindCurrentMethodLocked(); // Reset the current IME resetSelectedInputMethodAndSubtypeLocked(null); diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 4904061ec1af..1aff23b09c0f 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -73,6 +73,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.IMultiClientInputMethod; import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations; import com.android.internal.inputmethod.IMultiClientInputMethodSession; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import com.android.internal.inputmethod.UnbindReason; @@ -174,7 +175,7 @@ public final class MultiClientInputMethodManagerService { } @Override - public void hideCurrentInputMethod() { + public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { reportNotSupported(); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 19e6062401c0..1ec44d3bc9c7 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -186,6 +186,7 @@ import android.view.autofill.AutofillManagerInternal; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.os.RoSystemProperties; @@ -1105,7 +1106,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { LocalServices.getService(InputMethodManagerInternal.class); } if (mInputMethodManagerInternal != null) { - mInputMethodManagerInternal.hideCurrentInputMethod(); + mInputMethodManagerInternal.hideCurrentInputMethod( + SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME); } } else { shortPressPowerGoHome(); diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 6431e117c4e6..958c8ae94e47 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -53,6 +53,7 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DockedDividerUtils; import com.android.server.LocalServices; @@ -517,7 +518,8 @@ public class DockedStackDividerController { // Hide the current IME to avoid problems with animations from IME adjustment when // attaching the docked stack. - inputMethodManagerInternal.hideCurrentInputMethod(); + inputMethodManagerInternal.hideCurrentInputMethod( + SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED); mImeHideRequested = true; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 6b6b94681879..c3a8335e1c9d 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -55,6 +55,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; @@ -301,7 +302,8 @@ public class RecentsAnimationController implements DeathRecipient { final InputMethodManagerInternal inputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); if (inputMethodManagerInternal != null) { - inputMethodManagerInternal.hideCurrentInputMethod(); + inputMethodManagerInternal.hideCurrentInputMethod( + SoftInputShowHideReason.HIDE_RECENTS_ANIMATION); } } finally { Binder.restoreCallingIdentity(token); |