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

Commit 982a94c5 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Fix a race to detemine IME switcher visibilityde

When the current user is switching to a user who requires password to
unlock, there is a chance that InputMethodManagerService has not
completed InputMethodManagerService#onSwitchUser() when the keyguard is
calling InputMethodManager#getEnabledInputMethodList() to detemine
whether the IME switcher icon should be shown or not.  If this occurs,
and if the previous user enables only one IME but the new user enables
multiple IMEs, it's possible that the IME switcher icon is not shown
when it should be.  Although the user is still able to work around this
by switch back to the previous user then the current user again until
the icon shows up, or can rely on a way to switch to next
IME (e.g. globe key) if it's available, the lack of the IME switcher
is still concerning since it can prevent the user from unlocking the
device.

As a quick workaround for this situation, this CL introduces a delayed
task to re-evaluate if we need to show the IME switcher icon on the
keyguard or not (currently the delay is set to 500msec) until this race
condition is fundamentally fixed.

Bug: 30640917
Change-Id: I93ea71d73540c31fbbe1cc4bd6747871f957dcc6
parent 0b26adbb
Loading
Loading
Loading
Loading
+47 −25
Original line number Original line Diff line number Diff line
@@ -42,16 +42,21 @@ import java.util.List;
 * Displays an alphanumeric (latin-1) key entry for the user to enter
 * Displays an alphanumeric (latin-1) key entry for the user to enter
 * an unlock password
 * an unlock password
 */
 */

public class KeyguardPasswordView extends KeyguardAbsKeyInputView
public class KeyguardPasswordView extends KeyguardAbsKeyInputView
        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {


    private final boolean mShowImeAtScreenOn;
    private final boolean mShowImeAtScreenOn;
    private final int mDisappearYTranslation;
    private final int mDisappearYTranslation;


    // A delay constant to be used in a workaround for the situation where InputMethodManagerService
    // is not switched to the new user yet.
    // TODO: Remove this by ensuring such a race condition never happens.
    private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500;  // 500ms

    InputMethodManager mImm;
    InputMethodManager mImm;
    private TextView mPasswordEntry;
    private TextView mPasswordEntry;
    private TextViewInputDisabler mPasswordEntryDisabler;
    private TextViewInputDisabler mPasswordEntryDisabler;
    private View mSwitchImeButton;


    private Interpolator mLinearOutSlowInInterpolator;
    private Interpolator mLinearOutSlowInInterpolator;
    private Interpolator mFastOutLinearInInterpolator;
    private Interpolator mFastOutLinearInInterpolator;
@@ -141,12 +146,31 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
        mPasswordEntry.requestFocus();
        mPasswordEntry.requestFocus();
    }
    }


    private void updateSwitchImeButton() {
        // If there's more than one IME, enable the IME switcher button
        final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE;
        final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes(mImm, false);
        if (wasVisible != shouldBeVisible) {
            mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
        }

        // TODO: Check if we still need this hack.
        // If no icon is visible, reset the start margin on the password field so the text is
        // still centered.
        if (mSwitchImeButton.getVisibility() != View.VISIBLE) {
            android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
            if (params instanceof MarginLayoutParams) {
                final MarginLayoutParams mlp = (MarginLayoutParams) params;
                mlp.setMarginStart(0);
                mPasswordEntry.setLayoutParams(params);
            }
        }
    }

    @Override
    @Override
    protected void onFinishInflate() {
    protected void onFinishInflate() {
        super.onFinishInflate();
        super.onFinishInflate();


        boolean imeOrDeleteButtonVisible = false;

        mImm = (InputMethodManager) getContext().getSystemService(
        mImm = (InputMethodManager) getContext().getSystemService(
                Context.INPUT_METHOD_SERVICE);
                Context.INPUT_METHOD_SERVICE);


@@ -171,12 +195,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView


        mPasswordEntry.requestFocus();
        mPasswordEntry.requestFocus();


        // If there's more than one IME, enable the IME switcher button
        mSwitchImeButton = findViewById(R.id.switch_ime_button);
        View switchImeButton = findViewById(R.id.switch_ime_button);
        mSwitchImeButton.setOnClickListener(new OnClickListener() {
        if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(mImm, false)) {
            switchImeButton.setVisibility(View.VISIBLE);
            imeOrDeleteButtonVisible = true;
            switchImeButton.setOnClickListener(new OnClickListener() {
            @Override
            @Override
            public void onClick(View v) {
            public void onClick(View v) {
                mCallback.userActivity(); // Leave the screen on a bit longer
                mCallback.userActivity(); // Leave the screen on a bit longer
@@ -184,18 +204,20 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
                mImm.showInputMethodPicker(false /* showAuxiliarySubtypes */);
                mImm.showInputMethodPicker(false /* showAuxiliarySubtypes */);
            }
            }
        });
        });
        }


        // If no icon is visible, reset the start margin on the password field so the text is
        // If there's more than one IME, enable the IME switcher button
        // still centered.
        updateSwitchImeButton();
        if (!imeOrDeleteButtonVisible) {

            android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
        // When we the current user is switching, InputMethodManagerService sometimes has not
            if (params instanceof MarginLayoutParams) {
        // switched internal state yet here. As a quick workaround, we check the keyboard state
                final MarginLayoutParams mlp = (MarginLayoutParams) params;
        // again.
                mlp.setMarginStart(0);
        // TODO: Remove this workaround by ensuring such a race condition never happens.
                mPasswordEntry.setLayoutParams(params);
        postDelayed(new Runnable() {
            }
            @Override
            public void run() {
                updateSwitchImeButton();
            }
            }
        }, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON);
    }
    }


    @Override
    @Override