Make IME handling deterministic in CryptKeeper
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. 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). Bug: 36015425 Change-Id: I3cffeec286d9372ff05e85a49b82287cb1add8a2
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
switcher, if necessary. Assumed to be in a horizontal LinearLayout. -->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<EditText android:id="@+id/passwordEntry"
|
||||
<com.android.settings.widget.ImeAwareEditText android:id="@+id/passwordEntry"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1"
|
||||
|
@@ -57,7 +57,6 @@ import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -66,6 +65,7 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockPatternView;
|
||||
import com.android.internal.widget.LockPatternView.Cell;
|
||||
import com.android.internal.widget.LockPatternView.DisplayMode;
|
||||
import com.android.settings.widget.ImeAwareEditText;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -122,7 +122,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
|
||||
private boolean mCooldown = false;
|
||||
|
||||
PowerManager.WakeLock mWakeLock;
|
||||
private EditText mPasswordEntry;
|
||||
private ImeAwareEditText mPasswordEntry;
|
||||
private LockPatternView mLockPatternView;
|
||||
/** Number of calls to {@link #notifyUser()} to ignore before notifying. */
|
||||
private int mNotificationCountdown = 0;
|
||||
@@ -277,9 +277,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
|
||||
// Reenable the password entry
|
||||
if (mPasswordEntry != null) {
|
||||
mPasswordEntry.setEnabled(true);
|
||||
final InputMethodManager imm = (InputMethodManager) getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(mPasswordEntry, 0);
|
||||
mPasswordEntry.scheduleShowSoftInput();
|
||||
setBackFunctionality(true);
|
||||
}
|
||||
}
|
||||
@@ -744,7 +742,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
|
||||
|
||||
private void passwordEntryInit() {
|
||||
// Password/pin case
|
||||
mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
|
||||
mPasswordEntry = (ImeAwareEditText) findViewById(R.id.passwordEntry);
|
||||
if (mPasswordEntry != null){
|
||||
mPasswordEntry.setOnEditorActionListener(this);
|
||||
mPasswordEntry.requestFocus();
|
||||
@@ -797,16 +795,13 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
|
||||
}
|
||||
}
|
||||
|
||||
// Asynchronously throw up the IME, since there are issues with requesting it to be shown
|
||||
// immediately.
|
||||
// Make sure that the IME is shown when everything becomes ready.
|
||||
if (mLockPatternView == null && !mCooldown) {
|
||||
getWindow().setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override public void run() {
|
||||
imm.showSoftInputUnchecked(0, null);
|
||||
}
|
||||
}, 0);
|
||||
if (mPasswordEntry != null) {
|
||||
mPasswordEntry.scheduleShowSoftInput();
|
||||
}
|
||||
}
|
||||
|
||||
updateEmergencyCallButtonState();
|
||||
|
92
src/com/android/settings/widget/ImeAwareEditText.java
Normal file
92
src/com/android/settings/widget/ImeAwareEditText.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class ImeAwareEditText extends EditText {
|
||||
private boolean mHasPendingShowSoftInputRequest;
|
||||
final Runnable mRunShowSoftInputIfNecessary = () -> 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.
|
||||
*
|
||||
* <p>This is a good and reliable signal to schedule a pending task to call
|
||||
* {@link InputMethodManager#showSoftInput(View, int)}.</p>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user