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:
Feng Cao
2020-06-01 00:30:03 -07:00
parent 7cbc5035b9
commit 0500ea20fa
2 changed files with 50 additions and 12 deletions

View File

@@ -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;
}

View File

@@ -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));