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

Commit d9eb911b authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Hide the software input based on its state.

This is a 2nd trial of I20ae2749a which is reverted due to a regression.
The goals of this CL are two:
- Split setImeWindowStatus method into two: keeping IMS status and
  updating system UI e.g. NavBar icon state.
- Hide software keyboard based on a realistic IMS status.

IMMS#mImeWindowVis has been used for two purpose, keeping IMS status and
updating the NavBar icons, e.g. keyboard icon.
However, to update NavBar icon, sometimes IMMS#mImeWindowVis value is
updated without any notification from IMS. As the result, the status
value becomes incosistent with the real IMS state.
This patch extracts NavBar update logic into separate method and keeps
IMMS#mImeWindowVis as notified status. Then, use it for hiding software
input correctly in IMMS#hideCurrentInputLocked.

This CL also removes refreshImeWindowVisibilityLocked method including
workaround for fixing Bug 11186297. That issue is no longer
reproducible with latest lock screen and almost no effect for existing
users and developers.  So simply remove them in this CL.

BUG: 21446788
BUG: 20764441
BUG: 18722991
Change-Id: I33dc6278fd892f26e56352722bf9449b8b102030
parent 29932d13
Loading
Loading
Loading
Loading
+97 −87
Original line number Diff line number Diff line
@@ -398,6 +398,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    int mCurUserActionNotificationSequenceNumber = 0;

    int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;

    /**
     * A set of status bits regarding the active IME.
     *
     * <p>This value is a combination of following two bits:</p>
     * <dl>
     * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
     * <dd>
     *   If this bit is ON, connected IME is ready to accept touch/key events.
     * </dd>
     * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
     * <dd>
     *   If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
     * </dd>
     * </dl>
     * <em>Do not update this value outside of setImeWindowStatus.</em>
     */
    int mImeWindowVis;

    private AlertDialog.Builder mDialogBuilder;
@@ -459,12 +476,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            final String action = intent.getAction();
            if (Intent.ACTION_SCREEN_ON.equals(action)) {
                mScreenOn = true;
                refreshImeWindowVisibilityLocked();
                updateSystemUi(mCurToken, mImeWindowVis, mBackDisposition);
                updateActive();
                return;
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                mScreenOn = false;
                setImeWindowVisibilityStatusHiddenLocked();
                updateSystemUi(mCurToken, 0 /* vis */, mBackDisposition);
                updateActive();
                return;
            } else if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
@@ -660,7 +677,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                            // Uh oh, current input method is no longer around!
                            // Pick another one...
                            Slog.i(TAG, "Current input method removed: " + curInputMethodId);
                            setImeWindowVisibilityStatusHiddenLocked();
                            updateSystemUiLocked(mCurToken, 0 /* vis */, mBackDisposition);
                            if (!chooseNewDefaultIMELocked()) {
                                changed = true;
                                curIm = null;
@@ -1003,7 +1020,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                mStatusBar = statusBar;
                statusBar.setIconVisibility("ime", false);
                updateImeWindowStatusLocked();
                updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
                mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                        com.android.internal.R.bool.show_ongoing_ime_switcher);
                if (mShowOngoingImeSwitcherForPhones) {
@@ -1029,33 +1046,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        }
    }

    private void setImeWindowVisibilityStatusHiddenLocked() {
        mImeWindowVis = 0;
        updateImeWindowStatusLocked();
    }

    private void refreshImeWindowVisibilityLocked() {
        final Configuration conf = mRes.getConfiguration();
        final boolean haveHardKeyboard = conf.keyboard
                != Configuration.KEYBOARD_NOKEYS;
        final boolean hardKeyShown = haveHardKeyboard
                && conf.hardKeyboardHidden
                        != Configuration.HARDKEYBOARDHIDDEN_YES;

        final boolean isScreenLocked = isKeyguardLocked();
        final boolean inputActive = !isScreenLocked && (mInputShown || hardKeyShown);
        // We assume the softkeyboard is shown when the input is active as long as the
        // hard keyboard is not shown.
        final boolean inputVisible = inputActive && !hardKeyShown;
        mImeWindowVis = (inputActive ? InputMethodService.IME_ACTIVE : 0)
                | (inputVisible ? InputMethodService.IME_VISIBLE : 0);
        updateImeWindowStatusLocked();
    }

    private void updateImeWindowStatusLocked() {
        setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition);
    }

    // ---------------------------------------------------------------------------------------
    // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
    // 1) it comes from the system process
@@ -1541,7 +1531,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    sessionState.session.finishSession();
                } catch (RemoteException e) {
                    Slog.w(TAG, "Session failed to close due to remote exception", e);
                    setImeWindowVisibilityStatusHiddenLocked();
                    updateSystemUiLocked(mCurToken, 0 /* vis */, mBackDisposition);
                }
                sessionState.session = null;
            }
@@ -1629,11 +1619,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        }
    }

    private boolean shouldShowImeSwitcherLocked() {
    private boolean shouldShowImeSwitcherLocked(int visibility) {
        if (!mShowOngoingImeSwitcherForPhones) return false;
        if (mSwitchingDialog != null) return false;
        if (isScreenLocked()) return false;
        if ((mImeWindowVis & InputMethodService.IME_ACTIVE) == 0) return false;
        if ((visibility & InputMethodService.IME_ACTIVE) == 0) return false;
        if (mWindowManagerService.isHardKeyboardAvailable()) {
            // When physical keyboard is attached, we show the ime switcher (or notification if
            // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
@@ -1641,7 +1631,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
            return true;
        }
        if ((mImeWindowVis & InputMethodService.IME_VISIBLE) == 0) return false;
        if ((visibility & InputMethodService.IME_VISIBLE) == 0) return false;

        List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
        final int N = imis.size();
@@ -1690,27 +1680,48 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
    }

    // Caution! This method is called in this class. Handle multi-user carefully
    @SuppressWarnings("deprecation")
    @Override
    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
        final long ident = Binder.clearCallingIdentity();
        try {
        if (!calledWithValidToken(token)) {
            final int uid = Binder.getCallingUid();
            Slog.e(TAG, "Ignoring setImeWindowStatus due to an invalid token. uid:" + uid
                    + " token:" + token);
            return;
        }

        synchronized (mMethodMap) {
            mImeWindowVis = vis;
            mBackDisposition = backDisposition;
            updateSystemUiLocked(token, vis, backDisposition);
        }
    }

    private void updateSystemUi(IBinder token, int vis, int backDisposition) {
        synchronized (mMethodMap) {
            updateSystemUiLocked(token, vis, backDisposition);
        }
    }

    // Caution! This method is called in this class. Handle multi-user carefully
    private void updateSystemUiLocked(IBinder token, int vis, int backDisposition) {
        if (!calledWithValidToken(token)) {
            final int uid = Binder.getCallingUid();
            Slog.e(TAG, "Ignoring updateSystemUiLocked due to an invalid token. uid:" + uid
                    + " token:" + token);
            return;
        }

        // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
        // all updateSystemUi happens on system previlege.
        final long ident = Binder.clearCallingIdentity();
        try {
            // apply policy for binder calls
            if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
                vis = 0;
            }
                mImeWindowVis = vis;
                mBackDisposition = backDisposition;
            // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
                final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked();
            final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
            if (mStatusBar != null) {
                mStatusBar.setImeWindowStatus(token, vis, backDisposition,
                        needsToShowImeSwitcher);
@@ -1747,7 +1758,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    mNotificationShown = false;
                }
            }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
@@ -1912,7 +1922,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
                if (mCurMethod != null) {
                    try {
                        refreshImeWindowVisibilityLocked();
                        updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
                        mCurMethod.changeInputMethodSubtype(newSubtype);
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Failed to call changeInputMethodSubtype");
@@ -2074,7 +2084,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            return false;
        }
        boolean res;
        if (mInputShown && mCurMethod != null) {
        if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && mCurMethod != null) {
            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
                    MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
            res = true;
@@ -3048,7 +3058,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            mSwitchingDialog.getWindow().getAttributes().privateFlags |=
                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
            mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
            updateImeWindowStatusLocked();
            updateSystemUi(mCurToken, mImeWindowVis, mBackDisposition);
            mSwitchingDialog.show();
        }
    }
@@ -3107,7 +3117,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            mSwitchingDialog = null;
        }

        updateImeWindowStatusLocked();
        updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
        mDialogBuilder = null;
        mIms = null;
    }