diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 5c820c3756a20..b952e968886ec 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1400,7 +1400,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/system FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/RestorationChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java -FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/ActivityLifecycleListener.java @@ -1425,7 +1424,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/FlutterT FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ImeSyncDeferringInsetsCallback.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ListenableEditingState.java -FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/SpellCheckPlugin.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextEditingDelta.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 8a1968c81ab25..ef22df4bae286 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -842,14 +842,6 @@ class PlatformDispatcher { _onTextScaleFactorChangedZone = Zone.current; } - /// Whether the spell check service is supported on the current platform. - /// - /// This option is used by [EditableTextState] to define its - /// [SpellCheckConfiguration] when a default spell check service - /// is requested. - bool get nativeSpellCheckServiceDefined => _nativeSpellCheckServiceDefined; - bool _nativeSpellCheckServiceDefined = false; - /// Whether briefly displaying the characters as you type in obscured text /// fields is enabled in system settings. /// @@ -911,12 +903,6 @@ class PlatformDispatcher { final double textScaleFactor = (data['textScaleFactor']! as num).toDouble(); final bool alwaysUse24HourFormat = data['alwaysUse24HourFormat']! as bool; - final bool? nativeSpellCheckServiceDefined = data['nativeSpellCheckServiceDefined'] as bool?; - if (nativeSpellCheckServiceDefined != null) { - _nativeSpellCheckServiceDefined = nativeSpellCheckServiceDefined; - } else { - _nativeSpellCheckServiceDefined = false; - } // This field is optional. final bool? brieflyShowPassword = data['brieflyShowPassword'] as bool?; if (brieflyShowPassword != null) { diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 48716f55c0292..0d9249144e092 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -425,15 +425,6 @@ class SingletonFlutterWindow extends FlutterWindow { /// observe when this value changes. double get textScaleFactor => platformDispatcher.textScaleFactor; - /// Whether the spell check service is supported on the current platform. - /// - /// {@macro dart.ui.window.accessorForwardWarning} - /// - /// This option is used by [EditableTextState] to define its - /// [SpellCheckConfiguration] when spell check is enabled, but no spell check - /// service is specified. - bool get nativeSpellCheckServiceDefined => platformDispatcher.nativeSpellCheckServiceDefined; - /// Whether briefly displaying the characters as you type in obscured text /// fields is enabled in system settings. /// diff --git a/lib/web_ui/lib/platform_dispatcher.dart b/lib/web_ui/lib/platform_dispatcher.dart index 5cc6175738e3e..7e72bee0c440f 100644 --- a/lib/web_ui/lib/platform_dispatcher.dart +++ b/lib/web_ui/lib/platform_dispatcher.dart @@ -82,8 +82,6 @@ abstract class PlatformDispatcher { double get textScaleFactor => configuration.textScaleFactor; - bool get nativeSpellCheckServiceDefined => false; - bool get brieflyShowPassword => true; VoidCallback? get onTextScaleFactorChanged; diff --git a/lib/web_ui/lib/window.dart b/lib/web_ui/lib/window.dart index 43711551cd9a6..fa2206778b870 100644 --- a/lib/web_ui/lib/window.dart +++ b/lib/web_ui/lib/window.dart @@ -48,8 +48,6 @@ abstract class SingletonFlutterWindow extends FlutterWindow { double get textScaleFactor => platformDispatcher.textScaleFactor; - bool get nativeSpellCheckServiceDefined => platformDispatcher.nativeSpellCheckServiceDefined; - bool get brieflyShowPassword => platformDispatcher.brieflyShowPassword; bool get alwaysUse24HourFormat => platformDispatcher.alwaysUse24HourFormat; diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index a12c8dfee3896..204a5b3355e09 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -236,7 +236,6 @@ android_java_sources = [ "io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java", "io/flutter/embedding/engine/systemchannels/RestorationChannel.java", "io/flutter/embedding/engine/systemchannels/SettingsChannel.java", - "io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java", "io/flutter/embedding/engine/systemchannels/SystemChannel.java", "io/flutter/embedding/engine/systemchannels/TextInputChannel.java", "io/flutter/plugin/common/ActivityLifecycleListener.java", @@ -261,7 +260,6 @@ android_java_sources = [ "io/flutter/plugin/editing/ImeSyncDeferringInsetsCallback.java", "io/flutter/plugin/editing/InputConnectionAdaptor.java", "io/flutter/plugin/editing/ListenableEditingState.java", - "io/flutter/plugin/editing/SpellCheckPlugin.java", "io/flutter/plugin/editing/TextEditingDelta.java", "io/flutter/plugin/editing/TextInputPlugin.java", "io/flutter/plugin/localization/LocalizationPlugin.java", diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 538249703216b..d58cdba70a7f2 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -35,8 +35,6 @@ import android.view.autofill.AutofillValue; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; -import android.view.textservice.SpellCheckerInfo; -import android.view.textservice.TextServicesManager; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -60,7 +58,6 @@ import io.flutter.embedding.engine.renderer.RenderSurface; import io.flutter.embedding.engine.systemchannels.SettingsChannel; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.editing.SpellCheckPlugin; import io.flutter.plugin.editing.TextInputPlugin; import io.flutter.plugin.localization.LocalizationPlugin; import io.flutter.plugin.mouse.MouseCursorPlugin; @@ -129,12 +126,10 @@ public class FlutterView extends FrameLayout // existing, stateless system channels, e.g., MouseCursorChannel, TextInputChannel, etc. @Nullable private MouseCursorPlugin mouseCursorPlugin; @Nullable private TextInputPlugin textInputPlugin; - @Nullable private SpellCheckPlugin spellCheckPlugin; @Nullable private LocalizationPlugin localizationPlugin; @Nullable private KeyboardManager keyboardManager; @Nullable private AndroidTouchProcessor androidTouchProcessor; @Nullable private AccessibilityBridge accessibilityBridge; - @Nullable private TextServicesManager textServicesManager; // Provides access to foldable/hinge information @Nullable private WindowInfoRepositoryCallbackAdapterWrapper windowInfoRepo; @@ -1146,17 +1141,6 @@ public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) { this, this.flutterEngine.getTextInputChannel(), this.flutterEngine.getPlatformViewsController()); - - try { - textServicesManager = - (TextServicesManager) - getContext().getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); - spellCheckPlugin = - new SpellCheckPlugin(textServicesManager, this.flutterEngine.getSpellCheckChannel()); - } catch (Exception e) { - Log.e(TAG, "TextServicesManager not supported by device, spell check disabled."); - } - localizationPlugin = this.flutterEngine.getLocalizationPlugin(); keyboardManager = new KeyboardManager(this); @@ -1254,9 +1238,6 @@ public void detachFromFlutterEngine() { textInputPlugin.getInputMethodManager().restartInput(this); textInputPlugin.destroy(); keyboardManager.destroy(); - if (spellCheckPlugin != null) { - spellCheckPlugin.destroy(); - } if (mouseCursorPlugin != null) { mouseCursorPlugin.destroy(); @@ -1441,34 +1422,10 @@ public void removeFlutterEngineAttachmentListener( ? SettingsChannel.PlatformBrightness.dark : SettingsChannel.PlatformBrightness.light; - boolean isNativeSpellCheckServiceDefined = false; - - if (textServicesManager != null) { - if (Build.VERSION.SDK_INT >= 31) { - List enabledSpellCheckerInfos = - textServicesManager.getEnabledSpellCheckerInfos(); - boolean gboardSpellCheckerEnabled = - enabledSpellCheckerInfos.stream() - .anyMatch( - spellCheckerInfo -> - spellCheckerInfo - .getPackageName() - .equals("com.google.android.inputmethod.latin")); - - // Checks if enabled spell checker is the one that is suppported by Gboard, which is - // the one Flutter supports by default. - isNativeSpellCheckServiceDefined = - textServicesManager.isSpellCheckerEnabled() && gboardSpellCheckerEnabled; - } else { - isNativeSpellCheckServiceDefined = true; - } - } - flutterEngine .getSettingsChannel() .startMessage() .setTextScaleFactor(getResources().getConfiguration().fontScale) - .setNativeSpellCheckServiceDefined(isNativeSpellCheckServiceDefined) .setBrieflyShowPassword( Settings.System.getInt( getContext().getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 518e18c733d26..e172a87e55448 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -32,7 +32,6 @@ import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.embedding.engine.systemchannels.RestorationChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel; -import io.flutter.embedding.engine.systemchannels.SpellCheckChannel; import io.flutter.embedding.engine.systemchannels.SystemChannel; import io.flutter.embedding.engine.systemchannels.TextInputChannel; import io.flutter.plugin.localization.LocalizationPlugin; @@ -94,7 +93,6 @@ public class FlutterEngine { @NonNull private final RestorationChannel restorationChannel; @NonNull private final PlatformChannel platformChannel; @NonNull private final SettingsChannel settingsChannel; - @NonNull private final SpellCheckChannel spellCheckChannel; @NonNull private final SystemChannel systemChannel; @NonNull private final TextInputChannel textInputChannel; @@ -308,7 +306,6 @@ public FlutterEngine( platformChannel = new PlatformChannel(dartExecutor); restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData); settingsChannel = new SettingsChannel(dartExecutor); - spellCheckChannel = new SpellCheckChannel(dartExecutor); systemChannel = new SystemChannel(dartExecutor); textInputChannel = new TextInputChannel(dartExecutor); @@ -553,12 +550,6 @@ public TextInputChannel getTextInputChannel() { return textInputChannel; } - /** System channel that sends and receives spell check requests and results. */ - @NonNull - public SpellCheckChannel getSpellCheckChannel() { - return spellCheckChannel; - } - /** * Plugin registry, which registers plugins that want to be applied to this {@code FlutterEngine}. */ diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java index 46bf51190c147..1be798c384cc6 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java @@ -13,7 +13,6 @@ public class SettingsChannel { public static final String CHANNEL_NAME = "flutter/settings"; private static final String TEXT_SCALE_FACTOR = "textScaleFactor"; - private static final String NATIVE_SPELL_CHECK_SERVICE_DEFINED = "nativeSpellCheckServiceDefined"; private static final String BRIEFLY_SHOW_PASSWORD = "brieflyShowPassword"; private static final String ALWAYS_USE_24_HOUR_FORMAT = "alwaysUse24HourFormat"; private static final String PLATFORM_BRIGHTNESS = "platformBrightness"; @@ -43,13 +42,6 @@ public MessageBuilder setTextScaleFactor(float textScaleFactor) { return this; } - @NonNull - public MessageBuilder setNativeSpellCheckServiceDefined( - boolean nativeSpellCheckServiceDefined) { - message.put(NATIVE_SPELL_CHECK_SERVICE_DEFINED, nativeSpellCheckServiceDefined); - return this; - } - @NonNull public MessageBuilder setBrieflyShowPassword(@NonNull boolean brieflyShowPassword) { message.put(BRIEFLY_SHOW_PASSWORD, brieflyShowPassword); diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java deleted file mode 100644 index 4c8fbec04b475..0000000000000 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.embedding.engine.systemchannels; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.flutter.Log; -import io.flutter.embedding.engine.dart.DartExecutor; -import io.flutter.plugin.common.JSONMethodCodec; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import org.json.JSONArray; -import org.json.JSONException; - -/** - * {@link SpellCheckChannel} is a platform channel that is used by the framework to initiate spell - * check in the embedding and for the embedding to send back the results. - * - *

When there is new text to be spell checked, the framework will send to the embedding the - * message {@code SpellCheck.initiateSpellCheck} with the {@code String} locale to spell check with - * and the {@code String} of text to spell check as arguments. In response, the {@link - * io.flutter.plugin.editing.SpellCheckPlugin} will make a call to Android's spell check service to - * fetch spell check results for the specified text. - * - *

Once the spell check results are received by the {@link - * io.flutter.plugin.editing.SpellCheckPlugin}, it will send to the framework the message {@code - * SpellCheck.updateSpellCheckResults} with the {@code ArrayList} of encoded spell check - * results (see {@link - * io.flutter.plugin.editing.SpellCheckPlugin#onGetSentenceSuggestions(SentenceSuggestionsInfo[])} - * for details) with the text that these results correspond to appeneded to the front as an - * argument. For example, the argument may look like: {@code {"Hello, wrold!", - * "7.11.world\nword\nold"}}. - * - *

{@link io.flutter.plugin.editing.SpellCheckPlugin} implements {@link SpellCheckMethodHandler} - * to initiate spell check. Implement {@link SpellCheckMethodHandler} to respond to spell check - * requests. - */ -public class SpellCheckChannel { - private static final String TAG = "SpellCheckChannel"; - - public final MethodChannel channel; - private SpellCheckMethodHandler spellCheckMethodHandler; - - @NonNull - public final MethodChannel.MethodCallHandler parsingMethodHandler = - new MethodChannel.MethodCallHandler() { - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - if (spellCheckMethodHandler == null) { - Log.v( - TAG, - "No SpellCheckeMethodHandler registered, call not forwarded to spell check API."); - return; - } - String method = call.method; - Object args = call.arguments; - Log.v(TAG, "Received '" + method + "' message."); - switch (method) { - case "SpellCheck.initiateSpellCheck": - try { - final JSONArray argumentList = (JSONArray) args; - String locale = argumentList.getString(0); - String text = argumentList.getString(1); - spellCheckMethodHandler.initiateSpellCheck(locale, text, result); - } catch (JSONException exception) { - result.error("error", exception.getMessage(), null); - } - break; - default: - result.notImplemented(); - break; - } - } - }; - - public SpellCheckChannel(@NonNull DartExecutor dartExecutor) { - channel = new MethodChannel(dartExecutor, "flutter/spellcheck", JSONMethodCodec.INSTANCE); - channel.setMethodCallHandler(parsingMethodHandler); - } - - /** - * Sets the {@link SpellCheckMethodHandler} which receives all requests to spell check the - * specified text sent through this channel. - */ - public void setSpellCheckMethodHandler( - @Nullable SpellCheckMethodHandler spellCheckMethodHandler) { - this.spellCheckMethodHandler = spellCheckMethodHandler; - } - - public interface SpellCheckMethodHandler { - /** - * Requests that spell check is initiated for the specified text, which will respond to the - * {@code result} with either success if spell check results are received or error if the - * request is skipped. - */ - void initiateSpellCheck( - @NonNull String locale, @NonNull String text, @NonNull MethodChannel.Result result); - } -} diff --git a/shell/platform/android/io/flutter/plugin/editing/SpellCheckPlugin.java b/shell/platform/android/io/flutter/plugin/editing/SpellCheckPlugin.java deleted file mode 100644 index af024801748c6..0000000000000 --- a/shell/platform/android/io/flutter/plugin/editing/SpellCheckPlugin.java +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugin.editing; - -import android.view.textservice.SentenceSuggestionsInfo; -import android.view.textservice.SpellCheckerSession; -import android.view.textservice.SuggestionsInfo; -import android.view.textservice.TextInfo; -import android.view.textservice.TextServicesManager; -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; -import io.flutter.embedding.engine.systemchannels.SpellCheckChannel; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.localization.LocalizationPlugin; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -/** - * {@link SpellCheckPlugin} is the implementation of all functionality needed for spell check for - * text input. - * - *

The plugin handles requests for spell check sent by the {@link - * io.flutter.embedding.engine.systemchannels.SpellCheckChannel} via sending requests to the Android - * spell checker. It also receives the spell check results from the service and sends them back to - * the framework through the {@link io.flutter.embedding.engine.systemchannels.SpellCheckChannel}. - */ -public class SpellCheckPlugin - implements SpellCheckChannel.SpellCheckMethodHandler, - SpellCheckerSession.SpellCheckerSessionListener { - - private final SpellCheckChannel mSpellCheckChannel; - private final TextServicesManager mTextServicesManager; - private SpellCheckerSession mSpellCheckerSession; - - @VisibleForTesting MethodChannel.Result pendingResult; - @VisibleForTesting String pendingResultText; - - // The maximum number of suggestions that the Android spell check service is allowed to provide - // per word. Same number that is used by default for Android's TextViews. - private static final int MAX_SPELL_CHECK_SUGGESTIONS = 5; - - public SpellCheckPlugin( - @NonNull TextServicesManager textServicesManager, - @NonNull SpellCheckChannel spellCheckChannel) { - mTextServicesManager = textServicesManager; - mSpellCheckChannel = spellCheckChannel; - - mSpellCheckChannel.setSpellCheckMethodHandler(this); - } - - /** - * Unregisters this {@code SpellCheckPlugin} as the {@code - * SpellCheckChannel.SpellCheckMethodHandler}, for the {@link - * io.flutter.embedding.engine.systemchannels.SpellCheckChannel}, and closes the most recently - * opened {@code SpellCheckerSession}. - * - *

Do not invoke any methods on a {@code SpellCheckPlugin} after invoking this method. - */ - public void destroy() { - mSpellCheckChannel.setSpellCheckMethodHandler(null); - - if (mSpellCheckerSession != null) { - mSpellCheckerSession.close(); - } - } - - /** - * Initiates call to native spell checker to spell check specified text if there is no result - * awaiting a response. - */ - @Override - public void initiateSpellCheck( - @NonNull String locale, @NonNull String text, @NonNull MethodChannel.Result result) { - if (pendingResult != null) { - result.error("error", "Previous spell check request still pending.", null); - return; - } - - pendingResult = result; - pendingResultText = text; - - performSpellCheck(locale, text); - } - - /** Calls on the Android spell check API to spell check specified text. */ - public void performSpellCheck(@NonNull String locale, @NonNull String text) { - String[] localeCodes = locale.split("-"); - Locale localeFromString = LocalizationPlugin.localeFromString(locale); - - if (mSpellCheckerSession == null) { - mSpellCheckerSession = - mTextServicesManager.newSpellCheckerSession( - null, - localeFromString, - this, - /** referToSpellCheckerLanguageSettings= */ - true); - } - - TextInfo[] textInfos = new TextInfo[] {new TextInfo(text)}; - mSpellCheckerSession.getSentenceSuggestions(textInfos, MAX_SPELL_CHECK_SUGGESTIONS); - } - - /** - * Callback for Android spell check API that decomposes results and send results through the - * {@link SpellCheckChannel}. - * - *

Spell check results will be encoded as a string representing the span of that result, with - * the format "start_index.end_index.suggestion_1/nsuggestion_2/nsuggestion_3", where there may be - * up to 5 suggestions. - */ - @Override - public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) { - if (results.length == 0) { - pendingResult.success(new ArrayList<>(Arrays.asList(pendingResultText, ""))); - pendingResult = null; - return; - } - - ArrayList spellCheckerSuggestionSpans = new ArrayList(); - SentenceSuggestionsInfo spellCheckResults = results[0]; - - for (int i = 0; i < spellCheckResults.getSuggestionsCount(); i++) { - SuggestionsInfo suggestionsInfo = spellCheckResults.getSuggestionsInfoAt(i); - int suggestionsCount = suggestionsInfo.getSuggestionsCount(); - - if (suggestionsCount <= 0) { - continue; - } - - String spellCheckerSuggestionSpan = ""; - int start = spellCheckResults.getOffsetAt(i); - int end = start + spellCheckResults.getLengthAt(i) - 1; - - spellCheckerSuggestionSpan += String.valueOf(start) + "."; - spellCheckerSuggestionSpan += String.valueOf(end) + "."; - - for (int j = 0; j < suggestionsCount; j++) { - spellCheckerSuggestionSpan += suggestionsInfo.getSuggestionAt(j) + "\n"; - } - - spellCheckerSuggestionSpans.add( - spellCheckerSuggestionSpan.substring(0, spellCheckerSuggestionSpan.length() - 1)); - } - - spellCheckerSuggestionSpans.add(0, pendingResultText); - pendingResult.success(spellCheckerSuggestionSpans); - pendingResult = null; - } - - @Override - public void onGetSuggestions(SuggestionsInfo[] results) { - // Deprecated callback for Android spell check API; will not use. - } -} diff --git a/shell/platform/android/test/io/flutter/CustomShadowContextImpl.java b/shell/platform/android/test/io/flutter/CustomShadowContextImpl.java deleted file mode 100644 index feab3607987be..0000000000000 --- a/shell/platform/android/test/io/flutter/CustomShadowContextImpl.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.flutter; - -import android.content.Context; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowContextImpl; - -@Implements(className = ShadowContextImpl.CLASS_NAME) -public class CustomShadowContextImpl extends ShadowContextImpl { - public static final String CLASS_NAME = "android.app.ContextImpl"; - - @Implementation - @Override - public final Object getSystemService(String name) { - if (name == Context.TEXT_SERVICES_MANAGER_SERVICE) { - return null; - } - return super.getSystemService(name); - } -} diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 5c3d50224db33..9cb08f8324d4f 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -1100,8 +1100,6 @@ private FlutterEngine mockFlutterEngine() { when(fakeMessageBuilder.setPlatformBrightness(any(SettingsChannel.PlatformBrightness.class))) .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setTextScaleFactor(any(Float.class))).thenReturn(fakeMessageBuilder); - when(fakeMessageBuilder.setNativeSpellCheckServiceDefined(any(Boolean.class))) - .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setBrieflyShowPassword(any(Boolean.class))) .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setUse24HourFormat(any(Boolean.class))).thenReturn(fakeMessageBuilder); diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index 91b9244e4d800..52d02eaa3096f 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -206,8 +206,6 @@ public void itSendsLightPlatformBrightnessToFlutter() { SettingsChannel fakeSettingsChannel = mock(SettingsChannel.class); SettingsChannel.MessageBuilder fakeMessageBuilder = mock(SettingsChannel.MessageBuilder.class); when(fakeMessageBuilder.setTextScaleFactor(any(Float.class))).thenReturn(fakeMessageBuilder); - when(fakeMessageBuilder.setNativeSpellCheckServiceDefined(any(Boolean.class))) - .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setBrieflyShowPassword(any(Boolean.class))) .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setUse24HourFormat(any(Boolean.class))).thenReturn(fakeMessageBuilder); @@ -258,8 +256,6 @@ public void itSendsDarkPlatformBrightnessToFlutter() { SettingsChannel fakeSettingsChannel = mock(SettingsChannel.class); SettingsChannel.MessageBuilder fakeMessageBuilder = mock(SettingsChannel.MessageBuilder.class); when(fakeMessageBuilder.setTextScaleFactor(any(Float.class))).thenReturn(fakeMessageBuilder); - when(fakeMessageBuilder.setNativeSpellCheckServiceDefined(any(Boolean.class))) - .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setBrieflyShowPassword(any(Boolean.class))) .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setUse24HourFormat(any(Boolean.class))).thenReturn(fakeMessageBuilder); @@ -298,8 +294,6 @@ public void itSendsTextShowPasswordToFrameworkOnAttach() { SettingsChannel fakeSettingsChannel = mock(SettingsChannel.class); SettingsChannel.MessageBuilder fakeMessageBuilder = mock(SettingsChannel.MessageBuilder.class); when(fakeMessageBuilder.setTextScaleFactor(any(Float.class))).thenReturn(fakeMessageBuilder); - when(fakeMessageBuilder.setNativeSpellCheckServiceDefined(any(Boolean.class))) - .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setPlatformBrightness(any(SettingsChannel.PlatformBrightness.class))) .thenReturn(fakeMessageBuilder); when(fakeMessageBuilder.setUse24HourFormat(any(Boolean.class))).thenReturn(fakeMessageBuilder); diff --git a/shell/platform/android/test/io/flutter/plugin/editing/SpellCheckPluginTest.java b/shell/platform/android/test/io/flutter/plugin/editing/SpellCheckPluginTest.java deleted file mode 100644 index 42a8f97d1874a..0000000000000 --- a/shell/platform/android/test/io/flutter/plugin/editing/SpellCheckPluginTest.java +++ /dev/null @@ -1,217 +0,0 @@ -package io.flutter.plugin.editing; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.view.textservice.SentenceSuggestionsInfo; -import android.view.textservice.SpellCheckerSession; -import android.view.textservice.SuggestionsInfo; -import android.view.textservice.TextInfo; -import android.view.textservice.TextServicesManager; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import io.flutter.embedding.engine.dart.DartExecutor; -import io.flutter.embedding.engine.systemchannels.SpellCheckChannel; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.JSONMethodCodec; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -@RunWith(AndroidJUnit4.class) -public class SpellCheckPluginTest { - - private static void sendToBinaryMessageHandler( - BinaryMessenger.BinaryMessageHandler binaryMessageHandler, String method, Object args) { - MethodCall methodCall = new MethodCall(method, args); - ByteBuffer encodedMethodCall = JSONMethodCodec.INSTANCE.encodeMethodCall(methodCall); - binaryMessageHandler.onMessage( - (ByteBuffer) encodedMethodCall.flip(), mock(BinaryMessenger.BinaryReply.class)); - } - - @Test - public void respondsToSpellCheckChannelMessage() { - ArgumentCaptor binaryMessageHandlerCaptor = - ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class); - DartExecutor mockBinaryMessenger = mock(DartExecutor.class); - SpellCheckChannel.SpellCheckMethodHandler mockHandler = - mock(SpellCheckChannel.SpellCheckMethodHandler.class); - SpellCheckChannel spellCheckChannel = new SpellCheckChannel(mockBinaryMessenger); - - spellCheckChannel.setSpellCheckMethodHandler(mockHandler); - - verify(mockBinaryMessenger, times(1)) - .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture()); - - BinaryMessenger.BinaryMessageHandler binaryMessageHandler = - binaryMessageHandlerCaptor.getValue(); - - sendToBinaryMessageHandler( - binaryMessageHandler, - "SpellCheck.initiateSpellCheck", - Arrays.asList("en-US", "Hello, wrold!")); - - verify(mockHandler) - .initiateSpellCheck(eq("en-US"), eq("Hello, wrold!"), any(MethodChannel.Result.class)); - } - - @Test - public void initiateSpellCheckPerformsSpellCheckWhenNoResultPending() { - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - MethodChannel.Result mockResult = mock(MethodChannel.Result.class); - SpellCheckerSession fakeSpellCheckerSession = mock(SpellCheckerSession.class); - - when(fakeTextServicesManager.newSpellCheckerSession( - null, new Locale("en", "US"), spellCheckPlugin, true)) - .thenReturn(fakeSpellCheckerSession); - - spellCheckPlugin.initiateSpellCheck("en-US", "Hello, wrold!", mockResult); - - verify(spellCheckPlugin).performSpellCheck("en-US", "Hello, wrold!"); - } - - @Test - public void initiateSpellCheckThrowsErrorWhenResultPending() { - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - MethodChannel.Result mockPendingResult = mock(MethodChannel.Result.class); - MethodChannel.Result mockResult = mock(MethodChannel.Result.class); - spellCheckPlugin.pendingResult = mockPendingResult; - - spellCheckPlugin.initiateSpellCheck("en-US", "Hello, wrold!", mockResult); - - verify(mockResult).error("error", "Previous spell check request still pending.", null); - verify(spellCheckPlugin, never()).performSpellCheck("en-US", "Hello, wrold!"); - } - - @Test - public void destroyClosesSpellCheckerSessionAndClearsSpellCheckMethodHandler() { - Context fakeContext = mock(Context.class); - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - when(fakeContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE)) - .thenReturn(fakeTextServicesManager); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - SpellCheckerSession fakeSpellCheckerSession = mock(SpellCheckerSession.class); - - when(fakeTextServicesManager.newSpellCheckerSession( - null, new Locale("en", "US"), spellCheckPlugin, true)) - .thenReturn(fakeSpellCheckerSession); - - spellCheckPlugin.performSpellCheck("en-US", "Hello, wrold!"); - spellCheckPlugin.destroy(); - - verify(fakeSpellCheckChannel).setSpellCheckMethodHandler(isNull()); - verify(fakeSpellCheckerSession).close(); - } - - @Test - public void performSpellCheckSendsRequestToAndroidSpellCheckService() { - Context fakeContext = mock(Context.class); - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - when(fakeContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE)) - .thenReturn(fakeTextServicesManager); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - SpellCheckerSession fakeSpellCheckerSession = mock(SpellCheckerSession.class); - Locale english_US = new Locale("en", "US"); - - when(fakeTextServicesManager.newSpellCheckerSession(null, english_US, spellCheckPlugin, true)) - .thenReturn(fakeSpellCheckerSession); - - int maxSuggestions = 5; - ArgumentCaptor textInfosCaptor = ArgumentCaptor.forClass(TextInfo[].class); - ArgumentCaptor maxSuggestionsCaptor = ArgumentCaptor.forClass(Integer.class); - - spellCheckPlugin.performSpellCheck("en-US", "Hello, wrold!"); - - verify(fakeSpellCheckerSession) - .getSentenceSuggestions(textInfosCaptor.capture(), maxSuggestionsCaptor.capture()); - assertEquals("Hello, wrold!", textInfosCaptor.getValue()[0].getText()); - assertEquals(Integer.valueOf(maxSuggestions), maxSuggestionsCaptor.getValue()); - } - - @Test - public void performSpellCheckCreatesNewSpellCheckerSession() { - Context fakeContext = mock(Context.class); - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - when(fakeContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE)) - .thenReturn(fakeTextServicesManager); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - SpellCheckerSession fakeSpellCheckerSession = mock(SpellCheckerSession.class); - Locale english_US = new Locale("en", "US"); - - when(fakeTextServicesManager.newSpellCheckerSession(null, english_US, spellCheckPlugin, true)) - .thenReturn(fakeSpellCheckerSession); - - spellCheckPlugin.performSpellCheck("en-US", "Hello, worl!"); - spellCheckPlugin.performSpellCheck("en-US", "Hello, world!"); - - verify(fakeTextServicesManager, times(1)) - .newSpellCheckerSession(null, english_US, spellCheckPlugin, true); - } - - @Test - public void onGetSentenceSuggestionsResultsWithSuccessAndNoResultsProperly() { - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - MethodChannel.Result mockResult = mock(MethodChannel.Result.class); - spellCheckPlugin.pendingResult = mockResult; - spellCheckPlugin.pendingResultText = "Hello, world!"; - - spellCheckPlugin.onGetSentenceSuggestions(new SentenceSuggestionsInfo[] {}); - - verify(mockResult).success(new ArrayList(Arrays.asList("Hello, world!", ""))); - } - - @Test - public void onGetSentenceSuggestionsResultsWithSuccessAndResultsProperly() { - TextServicesManager fakeTextServicesManager = mock(TextServicesManager.class); - SpellCheckChannel fakeSpellCheckChannel = mock(SpellCheckChannel.class); - SpellCheckPlugin spellCheckPlugin = - spy(new SpellCheckPlugin(fakeTextServicesManager, fakeSpellCheckChannel)); - MethodChannel.Result mockResult = mock(MethodChannel.Result.class); - spellCheckPlugin.pendingResult = mockResult; - spellCheckPlugin.pendingResultText = "Hello, wrold!"; - - spellCheckPlugin.onGetSentenceSuggestions( - new SentenceSuggestionsInfo[] { - new SentenceSuggestionsInfo( - (new SuggestionsInfo[] { - new SuggestionsInfo( - SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO, - new String[] {"world", "word", "old"}) - }), - new int[] {7}, - new int[] {5}) - }); - - verify(mockResult) - .success(new ArrayList(Arrays.asList("Hello, wrold!", "7.11.world\nword\nold"))); - } -} diff --git a/shell/platform/android/test_runner/src/main/resources/robolectric.properties b/shell/platform/android/test_runner/src/main/resources/robolectric.properties index ba72a7e57eb78..ffcbe2dd23944 100644 --- a/shell/platform/android/test_runner/src/main/resources/robolectric.properties +++ b/shell/platform/android/test_runner/src/main/resources/robolectric.properties @@ -1,2 +1 @@ sdk=31 -shadows=io.flutter.CustomShadowContextImpl