summaryrefslogtreecommitdiff
path: root/core/java/android/inputmethodservice/InputMethodService.java
diff options
context:
space:
mode:
authorTaran Singh <tarandeep@google.com>2021-03-01 19:35:51 +0000
committerTaran Singh <tarandeep@google.com>2021-03-10 08:22:42 +0000
commit9a2eed9f496f1fbca3434b672dfdeb2f59448078 (patch)
treef7512e2d3dff38f92f4e3228212444c6c53fc8c1 /core/java/android/inputmethodservice/InputMethodService.java
parentee971e56485627db54ef7a5336f710368c732726 (diff)
Avoid IME restart for configChanges
Handle onConfigurationChanged() in order to prevent restarting InputMethodService everytime. We introduce a new API attribute "configChanges" in InputMethod(attrs.xml) which when declared by IME, will be responsible for handling mentioned configuration changes. This CL re-introduces [1] with fix: Use new Configuration instance for IMS#mLastKnownConfig [1] Iff88b768c6b06cf5cf1fe9e97ee97f8f78e6f0bd Bug: 167948419 Test: atest InputMethodServiceTest Manually: 1. Patch Ie91e7a8e06b80864ef9409031e8543858552d70d to use dual display area. 2. Open applications with editors on both display areas. 3. Attach a debug point for IMS#onConfigurationChanged(). 4. Make sure IMS#resetStateForNewConfiguration() is not called when IME moves between these two identical DisplayAreas Change-Id: Ib94fddadb0dae648cf73a4c1642e51edebd19f50
Diffstat (limited to 'core/java/android/inputmethodservice/InputMethodService.java')
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java44
1 files changed, 41 insertions, 3 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7e2be01feb01..40a0fc4e8339 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,6 +70,7 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -131,6 +132,7 @@ import android.widget.TextView;
import android.window.WindowMetricsHelper;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
@@ -513,6 +515,8 @@ public class InputMethodService extends AbstractInputMethodService {
private boolean mIsAutomotive;
private Handler mHandler;
private boolean mImeSurfaceScheduledForRemoval;
+ private Configuration mLastKnownConfig;
+ private int mHandledConfigChanges;
/**
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -588,12 +592,13 @@ public class InputMethodService extends AbstractInputMethodService {
@MainThread
@Override
public final void initializeInternal(@NonNull IBinder token, int displayId,
- IInputMethodPrivilegedOperations privilegedOperations) {
+ IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
Log.w(TAG, "The token has already registered, ignore this initialization.");
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
+ mHandledConfigChanges = configChanges;
mPrivOps.set(privilegedOperations);
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
updateInputMethodDisplay(displayId);
@@ -821,6 +826,9 @@ public class InputMethodService extends AbstractInputMethodService {
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
}
final boolean isVisible = isInputViewShown();
+ if (isVisible && getResources() != null) {
+ mLastKnownConfig = new Configuration(getResources().getConfiguration());
+ }
final boolean visibilityChanged = isVisible != wasVisible;
if (resultReceiver != null) {
resultReceiver.send(visibilityChanged
@@ -1428,10 +1436,30 @@ public class InputMethodService extends AbstractInputMethodService {
* state: {@link #onStartInput} if input is active, and
* {@link #onCreateInputView} and {@link #onStartInputView} and related
* appropriate functions if the UI is displayed.
+ * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
+ * changes themselves instead of being restarted with
+ * {@link android.R.styleable#InputMethod_configChanges}.
*/
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- resetStateForNewConfiguration();
+ if (shouldImeRestartForConfig(newConfig)) {
+ resetStateForNewConfiguration();
+ }
+ }
+
+ /**
+ * @return {@code true} if {@link InputMethodService} needs to restart to handle
+ * .{@link #onConfigurationChanged(Configuration)}
+ */
+ @VisibleForTesting
+ boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
+ if (mLastKnownConfig == null) {
+ return true;
+ }
+ // If the new config is the same as the config this Service is already running with,
+ // then don't bother calling resetStateForNewConfiguration.
+ int unhandledDiff = (mLastKnownConfig.diffPublicOnly(newConfig) & ~mHandledConfigChanges);
+ return unhandledDiff != 0;
}
private void resetStateForNewConfiguration() {
@@ -3181,7 +3209,17 @@ public class InputMethodService extends AbstractInputMethodService {
requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
}
}
-
+
+ @VisibleForTesting
+ void setLastKnownConfig(@NonNull Configuration config) {
+ mLastKnownConfig = config;
+ }
+
+ @VisibleForTesting
+ void setHandledConfigChanges(int configChanges) {
+ mHandledConfigChanges = configChanges;
+ }
+
void startExtractingText(boolean inputChanged) {
final ExtractEditText eet = mExtractEditText;
if (eet != null && getCurrentInputStarted()