Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a2eed9f authored by Taran Singh's avatar Taran Singh
Browse files

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
parent ee971e56
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -51290,6 +51290,7 @@ package android.view.inputmethod {
    method public int describeContents();
    method public void dump(android.util.Printer, String);
    method public android.content.ComponentName getComponent();
    method public int getConfigChanges();
    method public String getId();
    method public int getIsDefaultResourceId();
    method public String getPackageName();
+4 −0
Original line number Diff line number Diff line
@@ -2663,6 +2663,10 @@ package android.view.inputmethod {
    method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
  }

  public final class InputMethodInfo implements android.os.Parcelable {
    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
  }

  public final class InputMethodManager {
    method public int getDisplayId();
    method public boolean hasActiveInputConnection(@Nullable android.view.View);
+4 −3
Original line number Diff line number Diff line
@@ -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
+41 −3
Original line number Diff line number Diff line
@@ -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,11 +1436,31 @@ 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);
        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() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.resetStateForNewConfiguration");
@@ -3182,6 +3210,16 @@ public class InputMethodService extends AbstractInputMethodService {
        }
    }

    @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()
+1 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ public interface InputMethod {
     */
    @MainThread
    default void initializeInternal(IBinder token, int displayId,
            IInputMethodPrivilegedOperations privilegedOperations) {
            IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
        updateInputMethodDisplay(displayId);
        attachToken(token);
    }
Loading