Update sample IME code to support showing autofill inline suggestion
Test: manual Bug: 146587788 Change-Id: I0e5fa3d811b8951fe471f76ce14a5bdbddd81581
This commit is contained in:
@@ -17,15 +17,33 @@
|
||||
package com.example.android.autofillkeyboard;
|
||||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.GuardedBy;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inline.InlinePresentationSpec;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InlineSuggestion;
|
||||
import android.view.inputmethod.InlineSuggestionsRequest;
|
||||
import android.view.inputmethod.InlineSuggestionsResponse;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/** The {@link InputMethodService} implementation for Autofill keyboard. */
|
||||
public class AutofillImeService extends InputMethodService {
|
||||
|
||||
private InputView mInputView;
|
||||
private Decoder mDecoder;
|
||||
private LinearLayout mSuggestionStrip;
|
||||
|
||||
@Override
|
||||
public View onCreateInputView() {
|
||||
@@ -45,6 +63,7 @@ public class AutofillImeService extends InputMethodService {
|
||||
mInputView.removeAllViews();
|
||||
Keyboard keyboard = Keyboard.qwerty(this);
|
||||
mInputView.addView(keyboard.inflateKeyboardView(LayoutInflater.from(this), mInputView));
|
||||
mSuggestionStrip = mInputView.findViewById(R.id.suggestion_view);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,7 +75,108 @@ public class AutofillImeService extends InputMethodService {
|
||||
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT;
|
||||
}
|
||||
|
||||
/***************** Inline Suggestions Demo Code *****************/
|
||||
|
||||
private static final String TAG = "AutofillImeService";
|
||||
|
||||
private Handler mMainHandler = new Handler();
|
||||
|
||||
@GuardedBy("this")
|
||||
private List<View> mSuggestionViews = new ArrayList<>();
|
||||
@GuardedBy("this")
|
||||
private List<Size> mSuggestionViewSizes = new ArrayList<>();
|
||||
@GuardedBy("this")
|
||||
private boolean mSuggestionViewVisible = false;
|
||||
|
||||
@Override
|
||||
public InlineSuggestionsRequest onCreateInlineSuggestionsRequest() {
|
||||
Log.d(TAG, "onCreateInlineSuggestionsRequest() called");
|
||||
final ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
|
||||
presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
|
||||
new Size(400, 100)).build());
|
||||
presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
|
||||
new Size(400, 100)).build());
|
||||
|
||||
return new InlineSuggestionsRequest.Builder(presentationSpecs)
|
||||
.setMaxSuggestionCount(2)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInlineSuggestionsResponse(InlineSuggestionsResponse response) {
|
||||
Log.d(TAG, "onInlineSuggestionsResponse() called");
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
onInlineSuggestionsResponseInternal(response);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private synchronized void updateInlineSuggestionVisibility(boolean visible, boolean force) {
|
||||
Log.d(TAG, "updateInlineSuggestionVisibility() called, visible=" + visible + ", force="
|
||||
+ force);
|
||||
mMainHandler.post(() -> {
|
||||
Log.d(TAG, "updateInlineSuggestionVisibility() running");
|
||||
if (visible == mSuggestionViewVisible && !force) {
|
||||
return;
|
||||
} else if (visible) {
|
||||
mSuggestionStrip.removeAllViews();
|
||||
final int size = mSuggestionViews.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
|
||||
mSuggestionViewSizes.get(i).getWidth(),
|
||||
mSuggestionViewSizes.get(i).getHeight());
|
||||
mSuggestionStrip.addView(mSuggestionViews.get(i), layoutParams);
|
||||
}
|
||||
mSuggestionViewVisible = true;
|
||||
} else {
|
||||
mSuggestionStrip.removeAllViews();
|
||||
mSuggestionViewVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized void updateSuggestionViews(View[] suggestionViews, Size[] sizes) {
|
||||
Log.d(TAG, "updateSuggestionViews() called");
|
||||
mSuggestionViews = Arrays.asList(suggestionViews);
|
||||
mSuggestionViewSizes = Arrays.asList(sizes);
|
||||
updateInlineSuggestionVisibility(true, true);
|
||||
}
|
||||
|
||||
private void onInlineSuggestionsResponseInternal(InlineSuggestionsResponse response) {
|
||||
Log.d(TAG, "onInlineSuggestionsResponseInternal() called. Suggestion="
|
||||
+ response.getInlineSuggestions().size());
|
||||
|
||||
final List<InlineSuggestion> inlineSuggestions = response.getInlineSuggestions();
|
||||
final int totalSuggestionsCount = inlineSuggestions.size();
|
||||
final AtomicInteger suggestionsCount = new AtomicInteger(totalSuggestionsCount);
|
||||
final View[] suggestionViews = new View[totalSuggestionsCount];
|
||||
final Size[] sizes = new Size[totalSuggestionsCount];
|
||||
|
||||
for (int i=0; i<totalSuggestionsCount; i++) {
|
||||
final int index = i;
|
||||
InlineSuggestion inlineSuggestion = inlineSuggestions.get(index);
|
||||
Size size = inlineSuggestion.getInfo().getPresentationSpec().getMaxSize();
|
||||
inlineSuggestion.inflate(this, size,
|
||||
AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
suggestionView -> {
|
||||
Log.d(TAG, "new inline suggestion view ready");
|
||||
suggestionViews[index] = suggestionView;
|
||||
sizes[index] = size;
|
||||
suggestionView.setOnTouchListener((v, event) -> {
|
||||
Toast.makeText(AutofillImeService.this, "hello",
|
||||
Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
});
|
||||
if (suggestionsCount.decrementAndGet() == 0) {
|
||||
updateSuggestionViews(suggestionViews, sizes);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void handle(String data) {
|
||||
Log.d(TAG, "handle() called: [" + data + "]");
|
||||
mDecoder.decode(data);
|
||||
updateInlineSuggestionVisibility(mDecoder.isEmpty(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,12 @@ final class Decoder {
|
||||
mInputConnection.commitText(data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
if (mInputConnection.getTextBeforeCursor(1, 0).length() == 0
|
||||
&& mInputConnection.getTextAfterCursor(1, 0).length() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user