summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yohei Yukawa <yukawa@google.com> 2023-08-24 13:11:43 -0700
committer Yohei Yukawa <yukawa@google.com> 2023-08-24 13:11:43 -0700
commit2a757ef4aea5cf9674be508e87378f66874ef163 (patch)
treee61e6a26537e997c77da9678bfd3e06e513fda60
parent4d4fc565241c2d6297d3248b9120b2c5360d59c3 (diff)
Add @hide IMM#hideSoftInputFromView as an optimization
It seems that it is relatively a common pattern used in the Framework code when trying to hide a software keyboard. var imm = view.getSystemService(InputMethodManager.class); if (imm != null && imm.isActive(view)) { imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } The above code can be easily optimized by introducing a counterpart of InputMethodManager#showSoftInput(View view, int flags); so that the hide request can be issued when and only when the specified view has already established a connection to the IME. The optimized code would look like as follows. var imm = view.getSystemService(InputMethodManager.class); if (imm != null) { imm.hideSoftInputFromView(view, 0); } Major advantages of such an approach are: * IMM#checkFocus() can never be called. * IMM needs to take a lock only once. With above, this CL introduces IMM#hideSoftInputFromView() as @hide method so that we can start making sure that such an approach works well. Fix: 296466613 Test: atest CtsInputMethodTestCases:EditTextImeSupportTest Change-Id: I01e5a29c0f82d068751774a2c58a1bd7b7b7f91a
-rw-r--r--core/java/android/view/inputmethod/ImeTracker.java1
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java34
-rw-r--r--core/java/android/widget/DatePickerSpinnerDelegate.java12
-rw-r--r--core/java/android/widget/NumberPicker.java4
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java12
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodDebug.java2
-rw-r--r--core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java7
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java4
9 files changed, 65 insertions, 23 deletions
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 03d1cd8f89e3..f9d8b083ee9c 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -782,6 +782,7 @@ public interface ImeTracker {
private boolean shouldMonitorLatency(@SoftInputShowHideReason int reason) {
return reason == SoftInputShowHideReason.SHOW_SOFT_INPUT
|| reason == SoftInputShowHideReason.HIDE_SOFT_INPUT
+ || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW
|| reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API
|| reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API
|| reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0d713f4af705..5bb1e9318175 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2280,6 +2280,40 @@ public final class InputMethodManager {
}
/**
+ * Synonym for {@link #hideSoftInputFromWindow(IBinder, int)} but takes a {@link View} as a
+ * parameter to be a counterpart of {@link #showSoftInput(View, int)}.
+ *
+ * @param view {@link View} to be used to conditionally issue hide request when and only when
+ * this {@link View} is serving as an IME target.
+ * @hide
+ */
+ public boolean hideSoftInputFromView(@NonNull View view, @HideFlags int flags) {
+ final var reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW;
+ final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
+ null /* component */, Process.myUid(),
+ ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
+ ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+ reason, ActivityThread::currentApplication);
+ ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromView",
+ this, null /* icProto */);
+ synchronized (mH) {
+ if (!hasServedByInputMethodLocked(view)) {
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+ ImeTracker.forLatency().onShowFailed(
+ statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
+ ActivityThread::currentApplication);
+ Log.w(TAG, "Ignoring hideSoftInputFromView() as view=" + view + " is not served.");
+ return false;
+ }
+
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+
+ return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, view.getWindowToken(),
+ statsToken, flags, null, reason);
+ }
+ }
+
+ /**
* Start stylus handwriting session.
*
* If supported by the current input method, a stylus handwriting session is started on the
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index c6d456d8cb01..788b4afce017 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -640,15 +640,15 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
// value and having the IME up makes no sense.
InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
if (inputMethodManager != null) {
- if (inputMethodManager.isActive(mYearSpinnerInput)) {
+ if (mYearSpinnerInput.hasFocus()) {
+ inputMethodManager.hideSoftInputFromView(mYearSpinnerInput, 0);
mYearSpinnerInput.clearFocus();
- inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
- } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
+ } else if (mMonthSpinnerInput.hasFocus()) {
+ inputMethodManager.hideSoftInputFromView(mMonthSpinnerInput, 0);
mMonthSpinnerInput.clearFocus();
- inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
- } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
+ } else if (mDaySpinnerInput.hasFocus()) {
+ inputMethodManager.hideSoftInputFromView(mDaySpinnerInput, 0);
mDaySpinnerInput.clearFocus();
- inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
}
}
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 4f1c40a8d1c2..e600b4f0fe45 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1328,8 +1328,8 @@ public class NumberPicker extends LinearLayout {
private void hideSoftInput() {
InputMethodManager inputMethodManager =
getContext().getSystemService(InputMethodManager.class);
- if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
- inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+ if (inputMethodManager != null) {
+ inputMethodManager.hideSoftInputFromView(mInputText, 0);
}
if (mHasSelectorWheel) {
mInputText.setVisibility(View.INVISIBLE);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8899f5cd91d4..c9548bd9115d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2436,8 +2436,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!enabled) {
// Hide the soft input if the currently active TextView is disabled
InputMethodManager imm = getInputMethodManager();
- if (imm != null && imm.isActive(this)) {
- imm.hideSoftInputFromWindow(getWindowToken(), 0);
+ if (imm != null) {
+ imm.hideSoftInputFromView(this, 0);
}
}
@@ -8008,8 +8008,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} else if (actionCode == EditorInfo.IME_ACTION_DONE) {
InputMethodManager imm = getInputMethodManager();
- if (imm != null && imm.isActive(this)) {
- imm.hideSoftInputFromWindow(getWindowToken(), 0);
+ if (imm != null) {
+ imm.hideSoftInputFromView(this, 0);
}
return;
}
@@ -9672,8 +9672,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// No target for next focus, but make sure the IME
// if this came from it.
InputMethodManager imm = getInputMethodManager();
- if (imm != null && imm.isActive(this)) {
- imm.hideSoftInputFromWindow(getWindowToken(), 0);
+ if (imm != null) {
+ imm.hideSoftInputFromView(this, 0);
}
}
}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index bd2fa5965bc9..1a660be64c99 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -471,15 +471,15 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
// value and having the IME up makes no sense.
InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
if (inputMethodManager != null) {
- if (inputMethodManager.isActive(mHourSpinnerInput)) {
+ if (mHourSpinnerInput.hasFocus()) {
+ inputMethodManager.hideSoftInputFromView(mHourSpinnerInput, 0);
mHourSpinnerInput.clearFocus();
- inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
- } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
+ } else if (mMinuteSpinnerInput.hasFocus()) {
+ inputMethodManager.hideSoftInputFromView(mMinuteSpinnerInput, 0);
mMinuteSpinnerInput.clearFocus();
- inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
- } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
+ } else if (mAmPmSpinnerInput.hasFocus()) {
+ inputMethodManager.hideSoftInputFromView(mAmPmSpinnerInput, 0);
mAmPmSpinnerInput.clearFocus();
- inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
}
}
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 023fbf449889..9b7fa2f4f9e9 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -263,6 +263,8 @@ public final class InputMethodDebug {
return "HIDE_WHEN_INPUT_TARGET_INVISIBLE";
case SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION:
return "HIDE_SOFT_INPUT_CLOSE_CURRENT_SESSION";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW:
+ return "HIDE_SOFT_INPUT_FROM_VIEW";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index a32cd818e6e1..861b8a75f730 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -20,6 +20,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.os.IBinder;
+import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
@@ -70,6 +71,7 @@ import java.lang.annotation.Retention;
SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS,
SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE,
SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW,
})
public @interface SoftInputShowHideReason {
/** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
@@ -284,4 +286,9 @@ public @interface SoftInputShowHideReason {
* Hide soft input when {@link InputMethodManager#closeCurrentInput()} gets called.
*/
int HIDE_CLOSE_CURRENT_SESSION = ImeProtoEnums.REASON_HIDE_CLOSE_CURRENT_SESSION;
+
+ /**
+ * Hide soft input when {@link InputMethodManager#hideSoftInputFromView(View, int)} gets called.
+ */
+ int HIDE_SOFT_INPUT_FROM_VIEW = ImeProtoEnums.REASON_HIDE_SOFT_INPUT_FROM_VIEW;
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index b0aa8f19f24b..6ecffa4752cf 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -383,9 +383,7 @@ public final class PrintContentView extends ViewGroup implements View.OnClickLis
if (focused != null && focused.isFocused()) {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(
Context.INPUT_METHOD_SERVICE);
- if (imm.isActive(focused)) {
- imm.hideSoftInputFromWindow(getWindowToken(), 0);
- }
+ imm.hideSoftInputFromView(focused, 0);
focused.clearFocus();
}
}