diff --git a/build.gradle.kts b/build.gradle.kts index d357ed238..a5ecfaf47 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,7 @@ plugins { dependencies { implementation("androidx.window:window-java:1.3.0") implementation("androidx.core:core:1.16.0") + implementation("androidx.autofill:autofill:1.3.0") testImplementation("junit:junit:4.13.2") } diff --git a/res/layout/keyboard.xml b/res/layout/keyboard.xml index 8af048da5..629ead336 100644 --- a/res/layout/keyboard.xml +++ b/res/layout/keyboard.xml @@ -1,2 +1,16 @@ - + + + + + + diff --git a/res/xml/method.xml b/res/xml/method.xml index 26441cb50..5dac6da4f 100644 --- a/res/xml/method.xml +++ b/res/xml/method.xml @@ -1,5 +1,5 @@ - + diff --git a/srcs/juloo.keyboard2/InlineAutofill.java b/srcs/juloo.keyboard2/InlineAutofill.java new file mode 100644 index 000000000..e77b0f923 --- /dev/null +++ b/srcs/juloo.keyboard2/InlineAutofill.java @@ -0,0 +1,89 @@ +package juloo.keyboard2; + +import static juloo.keyboard2.Logs.TAG; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.autofill.inline.UiVersions; +import androidx.autofill.inline.v1.InlineSuggestionUi; + +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.util.Size; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InlineSuggestion; +import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.widget.inline.InlinePresentationSpec; + +import java.util.Collections; +import java.util.List; + +@RequiresApi(api = Build.VERSION_CODES.R) +public class InlineAutofill { + private HorizontalScrollView _autofillContainer; + private LinearLayout _autofillSuggestions; + + public void onInflate(View keyboardViewParent) + { + _autofillContainer = keyboardViewParent.findViewById(R.id.autofill_container); + _autofillSuggestions = keyboardViewParent.findViewById(R.id.autofill_suggestions); + } + + @Nullable + public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull Bundle uiExtras) + { + Size smallestSize = new Size(0, 0); + Size biggestSize = new Size(Integer.MAX_VALUE, Integer.MAX_VALUE); + + UiVersions.StylesBuilder stylesBuilder = UiVersions.newStylesBuilder(); + + InlineSuggestionUi.Style style = InlineSuggestionUi.newStyleBuilder().build(); + stylesBuilder.addStyle(style); + + Bundle stylesBundle = stylesBuilder.build(); + InlinePresentationSpec spec = + new InlinePresentationSpec.Builder(smallestSize, biggestSize) + .setStyle(stylesBundle) + .build(); + + return new InlineSuggestionsRequest.Builder(Collections.singletonList(spec)).build(); + } + + public boolean onInlineSuggestionsResponse(Context context, @NonNull InlineSuggestionsResponse response) + { + List inlineSuggestions = response.getInlineSuggestions(); + + float height = + TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, 40, context.getResources().getDisplayMetrics()); + Size autofillSize = new Size(ViewGroup.LayoutParams.WRAP_CONTENT, ((int) height)); + + _autofillSuggestions.removeAllViews(); + _autofillContainer.setVisibility(inlineSuggestions.isEmpty() ? View.GONE : View.VISIBLE); + + for (InlineSuggestion inlineSuggestion : inlineSuggestions) + { + try + { + inlineSuggestion.inflate( + context, + autofillSize, + context.getMainExecutor(), + _autofillSuggestions::addView); + } + catch (Exception e) + { + Log.e(TAG, "onInlineSuggestionsResponse - inlineSuggestion.infLate - " + e); + } + } + return true; + } +} \ No newline at end of file diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index f0408e048..0dacf3615 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -1,36 +1,39 @@ package juloo.keyboard2; import android.annotation.TargetApi; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.inputmethodservice.InputMethodService; +import android.os.Build; import android.os.Build.VERSION; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.text.InputType; -import android.util.Log; -import android.util.LogPrinter; import android.view.*; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import android.widget.FrameLayout; import android.widget.LinearLayout; -import java.util.AbstractMap.SimpleEntry; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; import juloo.keyboard2.prefs.LayoutsPreference; public class Keyboard2 extends InputMethodService implements SharedPreferences.OnSharedPreferenceChangeListener { + private View _keyboardViewParent = null; private Keyboard2View _keyboardView; + private InlineAutofill _inlineAutofill; private KeyEventHandler _keyeventhandler; /** If not 'null', the layout to use instead of [_config.current_layout]. */ private KeyboardData _currentSpecialLayout; @@ -116,13 +119,21 @@ public void onCreate() Config.initGlobalConfig(prefs, getResources(), _keyeventhandler, _foldStateTracker.isUnfolded()); prefs.registerOnSharedPreferenceChangeListener(this); _config = Config.globalConfig(); - _keyboardView = (Keyboard2View)inflate_view(R.layout.keyboard); + _inlineAutofill = new InlineAutofill(); + inflate_keyboardView(); _keyboardView.reset(); Logs.set_debug_logs(getResources().getBoolean(R.bool.debug_logs)); ClipboardHistoryService.on_startup(this, _keyeventhandler); _foldStateTracker.setChangedCallback(() -> { refresh_config(); }); } + private void inflate_keyboardView() { + _keyboardViewParent = inflate_view(R.layout.keyboard); + _inlineAutofill.onInflate(_keyboardViewParent); + _keyboardView = _keyboardViewParent.findViewById(R.id.keyboard_view); + _keyboardViewParent.getBackground().setAlpha(_config.keyboardOpacity); + } + @Override public void onDestroy() { super.onDestroy(); @@ -211,10 +222,10 @@ private void refresh_config() // Refreshing the theme config requires re-creating the views if (prev_theme != _config.theme) { - _keyboardView = (Keyboard2View)inflate_view(R.layout.keyboard); + inflate_keyboardView(); _emojiPane = null; _clipboard_pane = null; - setInputView(_keyboardView); + setInputView(_keyboardViewParent); } _keyboardView.reset(); } @@ -240,7 +251,7 @@ public void onStartInputView(EditorInfo info, boolean restarting) _currentSpecialLayout = refresh_special_layout(); _keyboardView.setKeyboard(current_layout()); _keyeventhandler.started(_config); - setInputView(_keyboardView); + setInputView(_keyboardViewParent); Logs.debug_startup_input_view(info, _config); } @@ -393,7 +404,7 @@ public void handle_event_key(KeyValue.Event ev) case SWITCH_BACK_EMOJI: case SWITCH_BACK_CLIPBOARD: - setInputView(_keyboardView); + setInputView(_keyboardViewParent); break; case CHANGE_METHOD_PICKER: @@ -477,4 +488,19 @@ private View inflate_view(int layout) { return View.inflate(new ContextThemeWrapper(this, _config.theme), layout, null); } + + @RequiresApi(api = Build.VERSION_CODES.R) + @Nullable + @Override + public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull Bundle uiExtras) + { + return _inlineAutofill.onCreateInlineSuggestionsRequest(uiExtras); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + @Override + public boolean onInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) + { + return _inlineAutofill.onInlineSuggestionsResponse(this, response); + } } diff --git a/srcs/juloo.keyboard2/Keyboard2View.java b/srcs/juloo.keyboard2/Keyboard2View.java index 1532970ad..e2b1468d2 100644 --- a/srcs/juloo.keyboard2/Keyboard2View.java +++ b/srcs/juloo.keyboard2/Keyboard2View.java @@ -342,7 +342,6 @@ public WindowInsets onApplyWindowInsets(WindowInsets wi) protected void onDraw(Canvas canvas) { // Set keyboard background opacity - getBackground().setAlpha(_config.keyboardOpacity); float y = _tc.margin_top; for (KeyboardData.Row row : _keyboard.rows) {