Inline autofill support (#336)

Theming support is still missing
This commit is contained in:
arcarum 2023-12-29 12:51:46 +04:00 committed by GitHub
parent c19441310d
commit ab183c53d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 195 additions and 2 deletions

View file

@ -81,6 +81,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1"
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0'
implementation 'androidx.autofill:autofill:1.1.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:5.7.0'

View file

@ -16,7 +16,9 @@ import android.graphics.Color;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
@ -33,8 +35,12 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.HorizontalScrollView;
import org.dslul.openboard.inputmethod.accessibility.AccessibilityUtils;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
@ -73,6 +79,7 @@ import org.dslul.openboard.inputmethod.latin.suggestions.SuggestionStripViewAcce
import org.dslul.openboard.inputmethod.latin.touchinputconsumer.GestureConsumer;
import org.dslul.openboard.inputmethod.latin.utils.ApplicationUtils;
import org.dslul.openboard.inputmethod.latin.utils.ColorUtilKt;
import org.dslul.openboard.inputmethod.latin.utils.InlineAutofillUtils;
import org.dslul.openboard.inputmethod.latin.utils.InputMethodPickerKt;
import org.dslul.openboard.inputmethod.latin.utils.JniUtils;
import org.dslul.openboard.inputmethod.latin.utils.LeakGuardHandlerWrapper;
@ -94,6 +101,7 @@ import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.N
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
@ -1342,6 +1350,43 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
updateSoftInputWindowLayoutParameters();
}
@Override
@RequiresApi(api = Build.VERSION_CODES.R)
public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull Bundle uiExtras) {
Log.d(TAG,"onCreateInlineSuggestionsRequest called");
// Revert to default behaviour if show_suggestions is disabled
// (Maybe there is a better way to do this)
if(!mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()){
return null;
}
return InlineAutofillUtils.createInlineSuggestionRequest(mDisplayContext);
}
@Override
@RequiresApi(api = Build.VERSION_CODES.R)
public boolean onInlineSuggestionsResponse(InlineSuggestionsResponse response) {
Log.d(TAG,"onInlineSuggestionsResponse called");
final List<InlineSuggestion> inlineSuggestions = response.getInlineSuggestions();
if (inlineSuggestions.isEmpty()) {
return false;
}
HorizontalScrollView view = InlineAutofillUtils.createView(inlineSuggestions, mDisplayContext);
// Delay required to show properly
new Handler().postDelayed(() -> {
mSuggestionStripView.clear();
mSuggestionStripView.hideKeys();
mSuggestionStripView.addSuggestionView(view);
}, 200);
return true;
}
private void updateSoftInputWindowLayoutParameters() {
// Override layout parameters to expand {@link SoftInputWindow} to the entire screen.
// See {@link InputMethodService#setinputView(View)} and

View file

@ -264,6 +264,15 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
getContext(), mSuggestedWords, mSuggestionsStrip, this);
}
public void addSuggestionView(final View view) {
mSuggestionsStrip.addView(view);
}
public void hideKeys() {
mToolbarKey.setVisibility(GONE);
mPinnedKeys.setVisibility(GONE);
}
public void setMoreSuggestionsHeight(final int remainingHeight) {
mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
}
@ -278,6 +287,11 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
for (final TextView word : mWordViews) {
word.setOnTouchListener(null);
}
if (mToolbarKey.getVisibility() != VISIBLE || mPinnedKeys.getVisibility() != VISIBLE){
mToolbarKey.setVisibility(VISIBLE);
mPinnedKeys.setVisibility(VISIBLE);
}
}
private void removeAllDebugInfoViews() {

View file

@ -0,0 +1,127 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0
*/
package org.dslul.openboard.inputmethod.latin.utils;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.util.Size;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.inline.InlinePresentationSpec;
import androidx.annotation.RequiresApi;
import androidx.autofill.inline.UiVersions;
import androidx.autofill.inline.common.ImageViewStyle;
import androidx.autofill.inline.common.TextViewStyle;
import androidx.autofill.inline.common.ViewStyle;
import androidx.autofill.inline.v1.InlineSuggestionUi;
import org.dslul.openboard.inputmethod.latin.R;
import java.util.ArrayList;
import java.util.List;
// Modified code from https://android.googlesource.com/platform/development/+/master/samples/AutofillKeyboard/
@RequiresApi(api = Build.VERSION_CODES.R)
public class InlineAutofillUtils {
private static int toPixel(int dp, Context context) {
return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dp,
context.getResources().getDisplayMetrics());
}
private static int getHeight(Context context) {
return context.getResources().getDimensionPixelSize(R.dimen.config_suggestions_strip_height);
}
public static InlineSuggestionsRequest createInlineSuggestionRequest(Context context) {
UiVersions.StylesBuilder stylesBuilder = UiVersions.newStylesBuilder();
@SuppressLint("RestrictedApi") InlineSuggestionUi.Style style = InlineSuggestionUi.newStyleBuilder()
.setSingleIconChipStyle(
new ViewStyle.Builder()
.setBackground(
Icon.createWithResource(context,
androidx.autofill.R.drawable.autofill_inline_suggestion_chip_background))
.setPadding(0, 0, 0, 0)
.build())
.setChipStyle(
new ViewStyle.Builder()
.setBackground(
Icon.createWithResource(context,
androidx.autofill.R.drawable.autofill_inline_suggestion_chip_background))
.build())
.setStartIconStyle(new ImageViewStyle.Builder().setLayoutMargin(0, 0, 0, 0).build())
.setTitleStyle(
new TextViewStyle.Builder()
.setLayoutMargin(toPixel(4, context), 0, toPixel(4, context), 0)
.setTextColor(Color.parseColor("#FF202124"))
.setTextSize(12)
.build())
.setSubtitleStyle(
new TextViewStyle.Builder()
.setLayoutMargin(0, 0, toPixel(4, context), 0)
.setTextColor(Color.parseColor("#99202124"))
.setTextSize(10)
.build())
.setEndIconStyle(new ImageViewStyle.Builder().setLayoutMargin(0, 0, 0, 0).build())
.build();
stylesBuilder.addStyle(style);
Bundle stylesBundle = stylesBuilder.build();
Size min = new Size(100, getHeight(context));
Size max = new Size(740, getHeight(context));
final ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
presentationSpecs.add(new InlinePresentationSpec.Builder(min, max).setStyle(stylesBundle).build());
presentationSpecs.add(new InlinePresentationSpec.Builder(min, max).setStyle(stylesBundle).build());
presentationSpecs.add(new InlinePresentationSpec.Builder(min, max).setStyle(stylesBundle).build());
return new InlineSuggestionsRequest.Builder(presentationSpecs)
.setMaxSuggestionCount(6)
.build();
}
public static HorizontalScrollView createView(List<InlineSuggestion> inlineSuggestions, Context context) {
final int totalSuggestionsCount = inlineSuggestions.size();
// A container to hold all views
LinearLayout container = new LinearLayout(context);
for (int i = 0; i < totalSuggestionsCount; i++) {
final InlineSuggestion inlineSuggestion = inlineSuggestions.get(i);
inlineSuggestion.inflate(context, new Size(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT), context.getMainExecutor(), (view) -> {
if (view != null)
container.addView(view);
});
}
HorizontalScrollView view = new HorizontalScrollView(context);
view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
view.setHorizontalScrollBarEnabled(false);
view.addView(container);
return view;
}
}

View file

@ -108,9 +108,12 @@
<!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
subtype.-->
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:settingsActivity="org.dslul.openboard.inputmethod.latin.settings.SettingsActivity"
android:isDefault="@bool/im_is_default"
android:supportsSwitchingToNextInputMethod="true">
android:supportsSwitchingToNextInputMethod="true"
android:supportsInlineSuggestions="true"
tools:targetApi="r">
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic"
android:subtypeId="0xc9194f97"

View file

@ -15,9 +15,12 @@ We don't want the subtypes managed by the system because it doesn't allow for ni
the system picker crashes on some devices for unknown reasons.
-->
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:settingsActivity="org.dslul.openboard.inputmethod.latin.settings.SettingsActivity"
android:isDefault="@bool/im_is_default"
android:supportsSwitchingToNextInputMethod="true">
android:supportsSwitchingToNextInputMethod="true"
android:supportsInlineSuggestions="true"
tools:targetApi="r">
<subtype android:icon="@drawable/ic_ime_switcher"
android:imeSubtypeExtraValue="dummy"
android:imeSubtypeMode="keyboard"