summaryrefslogtreecommitdiff
path: root/core/java/android/inputmethodservice
diff options
context:
space:
mode:
authorYohei Yukawa <yukawa@google.com>2021-03-31 02:28:22 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-03-31 02:28:22 +0000
commit12e4fde7935ef83760a45478f58eb80c49620cd9 (patch)
tree49f315a569f627c9d8cc5fa10b6c9eeb8033bfb2 /core/java/android/inputmethodservice
parent7d058d62e5bfc2893e297ece9094665d628127c2 (diff)
parent71ab752fc59e3db45e12d6ed9c922eb1ffca84a7 (diff)
Merge "Avoid IME restart for configChanges" into sc-dev
Diffstat (limited to 'core/java/android/inputmethodservice')
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java7
-rw-r--r--core/java/android/inputmethodservice/ImsConfigurationTracker.java102
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java12
3 files changed, 115 insertions, 6 deletions
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 5cfcd667632b..9198eb74d1f8 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -171,7 +171,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
SomeArgs args = (SomeArgs) msg.obj;
try {
inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
- (IInputMethodPrivilegedOperations) args.arg2);
+ (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
} finally {
args.recycle();
}
@@ -280,9 +280,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
@BinderThread
@Override
public void initializeInternal(IBinder token, int displayId,
- IInputMethodPrivilegedOperations privOps) {
+ IInputMethodPrivilegedOperations privOps, int configChanges) {
mCaller.executeOrSendMessage(
- mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
+ mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
+ configChanges));
}
@BinderThread
diff --git a/core/java/android/inputmethodservice/ImsConfigurationTracker.java b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
new file mode 100644
index 000000000000..3c788884371b
--- /dev/null
+++ b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 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.inputmethodservice;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Helper class that takes care of Configuration change behavior of {@link InputMethodService}.
+ * Note: this class is public for testing only. Never call any of it's methods for development
+ * of IMEs.
+ * @hide
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class ImsConfigurationTracker {
+
+ /**
+ * A constant value that represents {@link Configuration} has changed from the last time
+ * {@link InputMethodService#onConfigurationChanged(Configuration)} was called.
+ */
+ private static final int CONFIG_CHANGED = -1;
+
+ @Nullable
+ private Configuration mLastKnownConfig = null;
+ private int mHandledConfigChanges = 0;
+ private boolean mInitialized = false;
+
+ /**
+ * Called from {@link InputMethodService.InputMethodImpl
+ * #initializeInternal(IBinder, int, IInputMethodPrivilegedOperations, int)} ()}
+ * @param handledConfigChanges Configuration changes declared handled by IME
+ * {@link android.R.styleable#InputMethod_configChanges}.
+ */
+ @MainThread
+ public void onInitialize(int handledConfigChanges) {
+ Preconditions.checkState(!mInitialized, "onInitialize can be called only once.");
+ mInitialized = true;
+ mHandledConfigChanges = handledConfigChanges;
+ }
+
+ /**
+ * Called from {@link InputMethodService.InputMethodImpl#onBindInput()}
+ */
+ @MainThread
+ public void onBindInput(@Nullable Resources resources) {
+ Preconditions.checkState(mInitialized,
+ "onBindInput can be called only after onInitialize().");
+ if (mLastKnownConfig == null && resources != null) {
+ mLastKnownConfig = new Configuration(resources.getConfiguration());
+ }
+ }
+
+ /**
+ * Dynamically set handled configChanges.
+ * Note: this method is public for testing only.
+ */
+ public void setHandledConfigChanges(int configChanges) {
+ mHandledConfigChanges = configChanges;
+ }
+
+ /**
+ * Called from {@link InputMethodService.InputMethodImpl#onConfigurationChanged(Configuration)}}
+ */
+ @MainThread
+ public void onConfigurationChanged(@NonNull Configuration newConfig,
+ @NonNull Runnable resetStateForNewConfigurationRunner) {
+ if (!mInitialized) {
+ return;
+ }
+ final int diff = mLastKnownConfig != null
+ ? mLastKnownConfig.diffPublicOnly(newConfig) : CONFIG_CHANGED;
+ // If the new config is the same as the config this Service is already running with,
+ // then don't bother calling resetStateForNewConfiguration.
+ final int unhandledDiff = (diff & ~mHandledConfigChanges);
+ if (unhandledDiff != 0) {
+ resetStateForNewConfigurationRunner.run();
+ }
+ if (diff != 0) {
+ mLastKnownConfig = new Configuration(newConfig);
+ }
+ }
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7e2be01feb01..bf016124da31 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -513,6 +513,7 @@ public class InputMethodService extends AbstractInputMethodService {
private boolean mIsAutomotive;
private Handler mHandler;
private boolean mImeSurfaceScheduledForRemoval;
+ private ImsConfigurationTracker mConfigTracker = new ImsConfigurationTracker();
/**
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -588,12 +589,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");
+ mConfigTracker.onInitialize(configChanges);
mPrivOps.set(privilegedOperations);
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
updateInputMethodDisplay(displayId);
@@ -663,6 +665,7 @@ public class InputMethodService extends AbstractInputMethodService {
reportFullscreenMode();
initialize();
onBindInput();
+ mConfigTracker.onBindInput(getResources());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -1428,10 +1431,13 @@ 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();
+ mConfigTracker.onConfigurationChanged(newConfig, this::resetStateForNewConfiguration);
}
private void resetStateForNewConfiguration() {
@@ -3181,7 +3187,7 @@ public class InputMethodService extends AbstractInputMethodService {
requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
}
}
-
+
void startExtractingText(boolean inputChanged) {
final ExtractEditText eet = mExtractEditText;
if (eet != null && getCurrentInputStarted()