diff --git a/app/build.gradle b/app/build.gradle index 58f5b82d7..a8a8e7dc7 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,6 +81,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1" // why not working with 1.6.0? 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:3.12.4' diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java index e80f6af68..30d8eeb92 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java @@ -16,7 +16,9 @@ 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.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; @@ -72,6 +78,7 @@ 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; @@ -93,6 +100,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; @@ -1336,6 +1344,43 @@ public void updateFullscreenMode() { 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 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 diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java index 1f8c16619..f1b1e50c5 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java @@ -279,6 +279,15 @@ public void setSuggestions(final SuggestedWords suggestedWords, final boolean is 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); } @@ -293,6 +302,11 @@ public void clear() { for (final TextView word : mWordViews) { word.setOnTouchListener(null); } + + if (mToolbarKey.getVisibility() != VISIBLE || mPinnedKeys.getVisibility() != VISIBLE){ + mToolbarKey.setVisibility(VISIBLE); + mPinnedKeys.setVisibility(VISIBLE); + } } private void removeAllDebugInfoViews() { diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/InlineAutofillUtils.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/InlineAutofillUtils.java new file mode 100644 index 000000000..4155e595c --- /dev/null +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/InlineAutofillUtils.java @@ -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 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 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; + } +} diff --git a/app/src/main/res/xml/method.xml b/app/src/main/res/xml/method.xml index 7cdfa197d..f620ec2b9 100644 --- a/app/src/main/res/xml/method.xml +++ b/app/src/main/res/xml/method.xml @@ -108,9 +108,12 @@ + android:supportsSwitchingToNextInputMethod="true" + android:supportsInlineSuggestions="true" + tools:targetApi="r"> + android:supportsSwitchingToNextInputMethod="true" + android:supportsInlineSuggestions="true" + tools:targetApi="r">