From f6af093e2dfd156768a3937e94d405c04c541fea Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Tue, 21 Mar 2017 12:38:44 -0700 Subject: [PATCH] Deprecate IMM#showSoftInputUnchecked() part 2 This is the 2nd attempt to have CryptKeeper stop depending on InputMethodManager#showSoftInputUnchecked() do avoid non-deterministic behaviors. Note that the original one [1] was reverted [2] due to ClassCastException as crypt_keeper_pin_field.xml was not updated to use ImeAwareEditText. We have been receiving more and more strange bug reports regarding the initial IME visibility on CryptKeeper (Bug 31915865, Bug 35198715, and Bug 36148078). Most likely we have introduced more bugs before fixing previous bugs. As the first step to disentangle multiple problems, this CL addresses a long standing issue that CryptKeeper relies on @hide internal API InputMethodManager#showSoftInputUnchecked(). As explained in Bug 36015425, IMM#showSoftInputUnchecked() is considered harmful in terms of bypassing standard IME focus handling flows, which prevents us from taking advantage of historical debugging mechanism that we have added recently in Bug 35079353. [1]: I3cffeec286d9372ff05e85a49b82287cb1add8a2 4ae46cd1ad0725c8049c3954de19874df8483983 [2]: I776ad2e6ba0eabacb3d6be6de23ba37fe5ce7bc7 cf026ead8009578e91cc2daf3ff69aed4c4c9261 Test: Manually verified that Bug 31915865 is still broken but this CL does not make it worse. 1. Flash an image into a non direct-boot device. 2. Set up a device boot password. 3. adb reboot After the step 3, the software keyboard shows up automatically then suddenly disappears (Bug 35198715). Do the same test for device boot PIN instead of password. Bug: 36015425 Change-Id: I182b05d3ff59fb3b4732d60d0d5a464f0e0e0235 --- res/layout/crypt_keeper_password_field.xml | 3 +- res/layout/crypt_keeper_pin_field.xml | 3 +- src/com/android/settings/CryptKeeper.java | 21 ++--- .../android/settings/widget/ImeAwareEditText.java | 92 ++++++++++++++++++++++ 4 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 src/com/android/settings/widget/ImeAwareEditText.java diff --git a/res/layout/crypt_keeper_password_field.xml b/res/layout/crypt_keeper_password_field.xml index 8102658e44..bf286c0770 100644 --- a/res/layout/crypt_keeper_password_field.xml +++ b/res/layout/crypt_keeper_password_field.xml @@ -21,7 +21,8 @@ switcher, if necessary. Assumed to be in a horizontal LinearLayout. --> - + - + showSoftInputIfNecessary(); + + public ImeAwareEditText(Context context) { + super(context, null); + } + + public ImeAwareEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ImeAwareEditText(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public ImeAwareEditText(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + /** + * This method is called back by the system when the system is about to establish a connection + * to the current input method. + * + *

This is a good and reliable signal to schedule a pending task to call + * {@link InputMethodManager#showSoftInput(View, int)}.

+ * + * @param editorInfo context about the text input field. + * @return {@link InputConnection} to be passed to the input method. + */ + @Override + public InputConnection onCreateInputConnection(EditorInfo editorInfo) { + final InputConnection ic = super.onCreateInputConnection(editorInfo); + if (mHasPendingShowSoftInputRequest) { + removeCallbacks(mRunShowSoftInputIfNecessary); + post(mRunShowSoftInputIfNecessary); + } + return ic; + } + + private void showSoftInputIfNecessary() { + if (mHasPendingShowSoftInputRequest) { + final InputMethodManager imm = + getContext().getSystemService(InputMethodManager.class); + imm.showSoftInput(this, 0); + mHasPendingShowSoftInputRequest = false; + } + } + + public void scheduleShowSoftInput() { + final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); + if (imm.isActive(this)) { + // This means that ImeAwareEditText is already connected to the IME. + // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check. + mHasPendingShowSoftInputRequest = false; + removeCallbacks(mRunShowSoftInputIfNecessary); + imm.showSoftInput(this, 0); + return; + } + + // Otherwise, InputMethodManager#showSoftInput() should be deferred after + // onCreateInputConnection(). + mHasPendingShowSoftInputRequest = true; + } +} -- 2.11.0