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

Commit ac92087a authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #6499411: Characters not displayed (but suggestion bar is working)

The problem was that when dismissing the lock screen, the window manager
would briefly turn off force hiding when it started animating the transition
and then turn it back on until the transition was done.

This would cause it to briefly switch focus to the app behind and then
take focus off it.  The app would find out it got focus, and re-start
input on itself, asking the input method service to do so.  At this
point the input method service would ask the window manager if the
caller really had focus, and it may or may not be told no depending
on the timing.  If it is told no, then it doesn't allow the focus
switch to happen at that point, ignoring the new input connection,
and ultimately when focus does really switch the IME is left talking
with an old dead input connection.

I added some code to the input connection to make sure when we are
no longer using one that we mark it inactive and can't use it.  This
bug was especially difficult to track down because it would only
visibly break when a GC happened during this time, causing the weak
reference on the input connection to become null.  With this change
it will now always break (though in the scenario here only if you
hit the race condition correctly).

Change-Id: I81a6164dc140c548da1a9736e42cd253e8238a80
parent 37f29abe
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ public final class InputMethodManager {
     * The InputConnection that was last retrieved from the served view.
     */
    InputConnection mServedInputConnection;
    ControlledInputConnectionWrapper mServedInputConnectionWrapper;
    /**
     * The completions that were last provided by the served view.
     */
@@ -418,16 +419,22 @@ public final class InputMethodManager {
    
    private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
        private final InputMethodManager mParentInputMethodManager;
        private boolean mActive;

        public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
                final InputMethodManager inputMethodManager) {
            super(mainLooper, conn);
            mParentInputMethodManager = inputMethodManager;
            mActive = true;
        }

        @Override
        public boolean isActive() {
            return mParentInputMethodManager.mActive;
            return mParentInputMethodManager.mActive && mActive;
        }

        void deactivate() {
            mActive = false;
        }
    }
    
@@ -666,6 +673,10 @@ public final class InputMethodManager {
    void clearConnectionLocked() {
        mCurrentTextBoxAttribute = null;
        mServedInputConnection = null;
        if (mServedInputConnectionWrapper != null) {
            mServedInputConnectionWrapper.deactivate();
            mServedInputConnectionWrapper = null;
        }
    }
    
    /**
@@ -1060,7 +1071,7 @@ public final class InputMethodManager {
            // Notify the served view that its previous input connection is finished
            notifyInputConnectionFinished();
            mServedInputConnection = ic;
            IInputContext servedContext;
            ControlledInputConnectionWrapper servedContext;
            if (ic != null) {
                mCursorSelStart = tba.initialSelStart;
                mCursorSelEnd = tba.initialSelEnd;
@@ -1071,6 +1082,10 @@ public final class InputMethodManager {
            } else {
                servedContext = null;
            }
            if (mServedInputConnectionWrapper != null) {
                mServedInputConnectionWrapper.deactivate();
            }
            mServedInputConnectionWrapper = servedContext;
            
            try {
                if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
@@ -1286,6 +1301,7 @@ public final class InputMethodManager {
        // we'll just do a window focus gain and call it a day.
        synchronized (mH) {
            try {
                if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
                mService.windowGainedFocus(mClient, rootView.getWindowToken(),
                        controlFlags, softInputMode, windowFlags, null, null);
            } catch (RemoteException e) {
+2 −1
Original line number Diff line number Diff line
@@ -1667,7 +1667,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                }

                if (mCurFocusedWindow == windowToken) {
                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
                            + " attribute=" + attribute);
                    if (attribute != null) {
                        return startInputUncheckedLocked(cs, inputContext, attribute,
                                controlFlags);
+11 −1
Original line number Diff line number Diff line
@@ -269,9 +269,19 @@ public class WindowAnimator {
                                mPendingLayoutChanges);
                        }
                        mService.mFocusMayChange = true;
                    } else if (win.isReadyForDisplay()) {
                    }
                    if (win.isReadyForDisplay()) {
                        mForceHiding = true;
                    }
                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                            "Force hide " + mForceHiding
                            + " hasSurface=" + win.mHasSurface
                            + " policyVis=" + win.mPolicyVisibility
                            + " destroying=" + win.mDestroying
                            + " attHidden=" + win.mAttachedHidden
                            + " vis=" + win.mViewVisibility
                            + " hidden=" + win.mRootToken.hidden
                            + " anim=" + win.mWinAnimator.mAnimation);
                } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
                    final boolean changed;
                    if (mForceHiding) {
+17 −10
Original line number Diff line number Diff line
@@ -1177,7 +1177,9 @@ public class WindowManagerService extends IWindowManager.Stub
                if (!w.isVisibleOrAdding()) {
                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface
                            + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility
                            + " policyVis=" + w.mPolicyVisibility + " attachHid=" + w.mAttachedHidden
                            + " policyVis=" + w.mPolicyVisibility
                            + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
                            + " attachHid=" + w.mAttachedHidden
                            + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
                    if (w.mAppToken != null) {
                        Slog.i(TAG, "  mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
@@ -7234,9 +7236,11 @@ public class WindowManagerService extends IWindowManager.Stub
            WindowState imFocus;
            if (idx > 0) {
                imFocus = mWindows.get(idx-1);
                //Log.i(TAG, "Desired input method target: " + imFocus);
                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
                //Log.i(TAG, "Last focus: " + this.mLastFocus);
                if (DEBUG_INPUT_METHOD) {
                    Slog.i(TAG, "Desired input method target: " + imFocus);
                    Slog.i(TAG, "Current focus: " + this.mCurrentFocus);
                    Slog.i(TAG, "Last focus: " + this.mLastFocus);
                }
                if (imFocus != null) {
                    // This may be a starting window, in which case we still want
                    // to count it as okay.
@@ -7247,17 +7251,20 @@ public class WindowManagerService extends IWindowManager.Stub
                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
                            WindowState w = imFocus.mAppToken.windows.get(i);
                            if (w != imFocus) {
                                //Log.i(TAG, "Switching to real app window: " + w);
                                Log.i(TAG, "Switching to real app window: " + w);
                                imFocus = w;
                                break;
                            }
                        }
                    }
                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
                    //if (imFocus.mSession.mClient != null) {
                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
                    //}
                    if (DEBUG_INPUT_METHOD) {
                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
                        if (imFocus.mSession.mClient != null) {
                            Slog.i(TAG, "IM target client binder: "
                                    + imFocus.mSession.mClient.asBinder());
                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
                        }
                    }
                    if (imFocus.mSession.mClient != null &&
                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
                        return true;