Update the sample IME to solve some flickers
* This, together with the change on the framework side ag/11685298, gets rid of the flicker on the notification pull down/up case, as well as switching from username to password. * The idea is to not clear the suggestions onInputFinish. Instead, we schedule a delayed deletion of the suggestions on InputStart, which will get canceled if there is new suggestions coming to the IME within the timeout. This gets rid of the flicker on the two cases mentioned in previous bullet. Test: manual test Bug: 157515522 Change-Id: I60d9181de3230d468224e2df08fee59b741d6828
This commit is contained in:
@@ -23,6 +23,7 @@ import android.graphics.drawable.Icon;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.util.TypedValue;
|
||||
@@ -66,6 +67,7 @@ public class AutofillImeService extends InputMethodService {
|
||||
private static final long MOVE_SUGGESTIONS_DOWN_TIMEOUT = 10000;
|
||||
|
||||
private InputView mInputView;
|
||||
private Keyboard mKeyboard;
|
||||
private Decoder mDecoder;
|
||||
|
||||
private ViewGroup mSuggestionStrip;
|
||||
@@ -74,6 +76,8 @@ public class AutofillImeService extends InputMethodService {
|
||||
private InlineContentClipView mScrollableSuggestionsClip;
|
||||
private ViewGroup mScrollableSuggestions;
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
private final Runnable mMoveScrollableSuggestionsToBg = () -> {
|
||||
mScrollableSuggestionsClip.setZOrderedOnTop(false);
|
||||
Toast.makeText(AutofillImeService.this, "Chips moved to bg - not clickable",
|
||||
@@ -101,6 +105,13 @@ public class AutofillImeService extends InputMethodService {
|
||||
@Override
|
||||
public View onCreateInputView() {
|
||||
mInputView = (InputView) LayoutInflater.from(this).inflate(R.layout.input_view, null);
|
||||
mKeyboard = Keyboard.qwerty(this);
|
||||
mInputView.addView(mKeyboard.inflateKeyboardView(LayoutInflater.from(this), mInputView));
|
||||
mSuggestionStrip = mInputView.findViewById(R.id.suggestion_strip);
|
||||
mPinnedSuggestionsStart = mInputView.findViewById(R.id.pinned_suggestions_start);
|
||||
mPinnedSuggestionsEnd = mInputView.findViewById(R.id.pinned_suggestions_end);
|
||||
mScrollableSuggestionsClip = mInputView.findViewById(R.id.scrollable_suggestions_clip);
|
||||
mScrollableSuggestions = mInputView.findViewById(R.id.scrollable_suggestions);
|
||||
return mInputView;
|
||||
}
|
||||
|
||||
@@ -108,23 +119,42 @@ public class AutofillImeService extends InputMethodService {
|
||||
public void onStartInput(EditorInfo attribute, boolean restarting) {
|
||||
super.onStartInput(attribute, restarting);
|
||||
mDecoder = new Decoder(getCurrentInputConnection());
|
||||
if(mKeyboard != null) {
|
||||
mKeyboard.reset();
|
||||
}
|
||||
if (mInputView != null) {
|
||||
// We delay the deletion of the suggestions from previous input connection, to avoid
|
||||
// the flicker caused by deleting them and immediately showing new suggestions for
|
||||
// the current input connection.
|
||||
Log.d(TAG, "onStartInput scheduling a delayed deletion of inline suggestions");
|
||||
mDelayedDeletion = () -> {
|
||||
Log.d(TAG, "onStartInput deleting inline suggestions");
|
||||
mDelayedDeletion = null;
|
||||
updateInlineSuggestionStrip(Collections.emptyList());
|
||||
};
|
||||
mHandler.postDelayed(mDelayedDeletion, 200);
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mDelayedDeletion;
|
||||
|
||||
@Override
|
||||
public void onStartInputView(EditorInfo info, boolean restarting) {
|
||||
super.onStartInputView(info, restarting);
|
||||
}
|
||||
|
||||
mInputView.removeAllViews();
|
||||
Keyboard keyboard = Keyboard.qwerty(this);
|
||||
mInputView.addView(keyboard.inflateKeyboardView(LayoutInflater.from(this), mInputView));
|
||||
|
||||
mSuggestionStrip = mInputView.findViewById(R.id.suggestion_strip);
|
||||
mPinnedSuggestionsStart = mInputView.findViewById(R.id.pinned_suggestions_start);
|
||||
mPinnedSuggestionsEnd = mInputView.findViewById(R.id.pinned_suggestions_end);
|
||||
mScrollableSuggestionsClip = mInputView.findViewById(R.id.scrollable_suggestions_clip);
|
||||
mScrollableSuggestions = mInputView.findViewById(R.id.scrollable_suggestions);
|
||||
|
||||
updateInlineSuggestionStrip(Collections.emptyList());
|
||||
@Override
|
||||
public void onFinishInputView(boolean finishingInput) {
|
||||
super.onFinishInputView(finishingInput);
|
||||
if (!finishingInput) {
|
||||
// This runs when the IME is hide (but not finished). We need to clear the suggestions.
|
||||
// Otherwise, they will stay on the screen for a bit after the IME window disappears.
|
||||
// TODO: right now the framework resends the suggestions when onStartInputView is
|
||||
// called. If the framework is changed to not resend, then we need to cache the
|
||||
// inline suggestion views locally and re-attach them when the IME is shown again by
|
||||
// onStartInputView.
|
||||
updateInlineSuggestionStrip(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,6 +228,10 @@ public class AutofillImeService extends InputMethodService {
|
||||
@Override
|
||||
public boolean onInlineSuggestionsResponse(InlineSuggestionsResponse response) {
|
||||
Log.d(TAG, "onInlineSuggestionsResponse() called");
|
||||
if(mDelayedDeletion != null) {
|
||||
Log.d(TAG, "onInlineSuggestionsResponse unscheduling delayed deletion");
|
||||
mHandler.removeCallbacks(mDelayedDeletion);
|
||||
}
|
||||
onInlineSuggestionsResponseInternal(response);
|
||||
return true;
|
||||
}
|
||||
@@ -209,7 +243,6 @@ public class AutofillImeService extends InputMethodService {
|
||||
|
||||
final int size = suggestionItems.size();
|
||||
if (size <= 0) {
|
||||
mSuggestionStrip.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,11 @@ final class Keyboard {
|
||||
return mKeyboardView;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mState = 0;
|
||||
mapKeys();
|
||||
}
|
||||
|
||||
private void mapKeys() {
|
||||
for (int i = 0; i < mKeyMapping.size(); i++) {
|
||||
TextView softkey = mKeyboardView.findViewById(mKeyMapping.keyAt(i));
|
||||
|
||||
Reference in New Issue
Block a user