-
Notifications
You must be signed in to change notification settings - Fork 6k
Add Spell Check Support for Android Engine #30858
Changes from 1 commit
dc93719
cd234ad
f463846
3dfae0a
546692b
5f43ff5
ee73219
624f68b
846b195
b27704c
64f0ac7
0cc3776
33f2f40
eb3c731
1877242
5372aaa
d9adbdc
34809db
10d154d
00c228e
e08171f
5ccc144
87ab60f
f4083d7
ce45427
6972b0b
3eba4de
963d9ae
6ea2ede
32c7702
e9ebd5b
8298436
993b6c8
4179f42
f999488
ade72bc
c20b62c
49583d4
49939aa
0cf00f3
48a4354
510f83a
d8e333b
61908d3
29b095f
ee28058
4f0a074
6c4d437
d73b915
66c24ed
04a2ce1
15d17f5
e6414b2
2882e3b
dfe4689
cdc6b9c
65b8850
036b15b
188c2ad
8198d4e
a2b6c90
2aac372
894f4e9
2a4ea66
c2a6550
6125e74
74d1477
cc8bf5e
5a175ec
1c02784
3e74d61
975673c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package io.flutter.embedding.engine.systemchannels; | ||
|
|
||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.Nullable; | ||
| import androidx.annotation.VisibleForTesting; | ||
| 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 java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import org.json.JSONArray; | ||
| import org.json.JSONException; | ||
|
|
||
| public class SpellCheckChannel { | ||
| private static final String TAG = "SpellCheckChannel"; | ||
|
|
||
| @NonNull public final MethodChannel channel; | ||
| @Nullable private SpellCheckMethodHandler spellCheckMethodHandler; | ||
|
||
|
|
||
| @NonNull @VisibleForTesting | ||
|
||
| final MethodChannel.MethodCallHandler parsingMethodHandler = | ||
| new MethodChannel.MethodCallHandler() { | ||
| @Override | ||
| public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { | ||
| if (spellCheckMethodHandler == null) { | ||
| // If no explicit SpellCheckMethodHandler has been registered then we don't | ||
| // need to forward this call to an API. Return. | ||
camsim99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
camsim99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return; | ||
| } | ||
| String method = call.method; | ||
| Object args = call.arguments; | ||
| Log.v(TAG, "Received '" + method + "' message."); | ||
| switch (method) { | ||
| case "SpellCheck.initiateSpellChecking": | ||
| System.out.println("-----------FETCH RECEIVED IN ENGINE------------------"); | ||
| try { | ||
| final JSONArray argumentList = (JSONArray) args; | ||
| String locale = argumentList.getString(0); | ||
| String text = argumentList.getString(1); | ||
| spellCheckMethodHandler.initiateSpellChecking(locale, text); | ||
| result.success(null); | ||
| } catch (JSONException exception) { | ||
| result.error("error", exception.getMessage(), null); | ||
| } | ||
| break; | ||
| default: | ||
| System.out.println( | ||
| "-----------WRONG METHOD BEING CALLED IN ENGINE------------------"); | ||
| result.notImplemented(); | ||
| break; | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| public SpellCheckChannel(@NonNull DartExecutor dartExecutor) { | ||
| // TODO(camillesimon): Use JSON? | ||
| this.channel = new MethodChannel(dartExecutor, "flutter/spellcheck", JSONMethodCodec.INSTANCE); | ||
|
||
| channel.setMethodCallHandler(parsingMethodHandler); | ||
| } | ||
|
|
||
| /** Responsible for sending spell checker results across to the framework. */ | ||
| public void updateSpellCheckerResults( | ||
| ArrayList<String> spellCheckerResults, String spellCheckedText) { | ||
| channel.invokeMethod( | ||
| "TextInputClient.updateSpellCheckerResults", | ||
| Arrays.asList(spellCheckerResults, spellCheckedText)); | ||
| } | ||
|
|
||
| public void setSpellCheckMethodHandler( | ||
| @Nullable SpellCheckMethodHandler spellCheckMethodHandler) { | ||
| System.out.println("-------------------SPELL CHECK HANDLER SET-------------------"); | ||
| this.spellCheckMethodHandler = spellCheckMethodHandler; | ||
| } | ||
|
|
||
| public interface SpellCheckMethodHandler { | ||
| /** | ||
| * Requests that spell checking is initiated for the inputted text recognized by the framework, | ||
| * which will automatically result in spell checking resutls being sent back to the framework. | ||
| */ | ||
| void initiateSpellChecking(String locale, String text); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| // 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.content.Context; | ||
| import android.view.View; | ||
| import android.view.textservice.SentenceSuggestionsInfo; | ||
| import android.view.textservice.SpellCheckerInfo; | ||
| 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 io.flutter.embedding.engine.systemchannels.SpellCheckChannel; | ||
| import java.util.ArrayList; | ||
| import java.util.Locale; | ||
|
|
||
| public class SpellCheckPlugin implements SpellCheckerSession.SpellCheckerSessionListener { | ||
|
|
||
| @NonNull private final View mView; | ||
| @NonNull private final SpellCheckChannel mSpellCheckChannel; | ||
| @NonNull private final TextServicesManager tsm; | ||
|
||
| private SpellCheckerSession mSpellCheckerSession; | ||
|
|
||
| // String of spell checked text for testing | ||
| private String currentSpellCheckedText; | ||
|
|
||
| public SpellCheckPlugin(@NonNull View view, @NonNull SpellCheckChannel spellCheckChannel) { | ||
| System.out.println("----------------SpellCheckPlugin INITIATED-------------"); | ||
| mView = view; | ||
| mSpellCheckChannel = spellCheckChannel; | ||
| tsm = | ||
| (TextServicesManager) | ||
| view.getContext().getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); | ||
|
|
||
| mSpellCheckChannel.setSpellCheckMethodHandler( | ||
| new SpellCheckChannel.SpellCheckMethodHandler() { | ||
|
||
| @Override | ||
| public void initiateSpellChecking(String locale, String text) { | ||
| currentSpellCheckedText = text; | ||
| performSpellCheck(locale, text); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| // Responsible for calling the Android spell checker API to retrieve spell | ||
| // checking results. | ||
| public void performSpellCheck(String locale, String text) { | ||
camsim99 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| String[] localeCodes = locale.split("-"); | ||
| Locale localeToUse; | ||
|
|
||
| if (localeCodes.length == 3) { | ||
|
||
| localeToUse = new Locale(localeCodes[0], localeCodes[1], localeCodes[2]); | ||
| } else if (localeCodes.length == 2) { | ||
| localeToUse = new Locale(localeCodes[0], localeCodes[1]); | ||
| } else { | ||
| localeToUse = new Locale(localeCodes[0]); | ||
| } | ||
|
|
||
| // Open a new spell checker session when a new text input client is set. | ||
| // Closes spell checker session if one previously in use. | ||
| // TODO(camillesimon): Figure out proper session management. | ||
| if (mSpellCheckerSession != null) { | ||
| mSpellCheckerSession.close(); | ||
|
||
| mSpellCheckerSession = tsm.newSpellCheckerSession(null, Locale.ENGLISH, this, true); | ||
| } else { | ||
| mSpellCheckerSession = tsm.newSpellCheckerSession(null, Locale.ENGLISH, this, true); | ||
| } | ||
| SpellCheckerInfo infoChecker = mSpellCheckerSession.getSpellChecker(); | ||
|
|
||
| // Define TextInfo[] object (textInfos) based on the current input to be | ||
| // spell checked. | ||
| TextInfo[] textInfos = new TextInfo[] {new TextInfo(text)}; | ||
|
|
||
| // Make API call. Maximum suggestions requested set to 3 for now. | ||
| System.out.println("----------------SpellCheckPlugin FETCH INITIATED-------------"); | ||
| mSpellCheckerSession.getSentenceSuggestions(textInfos, 3); | ||
|
||
| } | ||
|
|
||
| // Responsible for decomposing spell checker results into an object that can | ||
| // then be sent to the framework. | ||
| @Override | ||
| public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) { | ||
| ArrayList<String> spellCheckerSuggestionSpans = new ArrayList<String>(); | ||
|
|
||
| for (int i = 0; i < results[0].getSuggestionsCount(); i++) { | ||
|
||
| SuggestionsInfo suggestionsInfo = results[0].getSuggestionsInfoAt(i); | ||
|
||
| int suggestionsCount = suggestionsInfo.getSuggestionsCount(); | ||
|
|
||
camsim99 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (suggestionsCount > 0) { | ||
| String spellCheckerSuggestionSpan = ""; | ||
| int start = results[0].getOffsetAt(i); | ||
| int length = results[0].getLengthAt(i); | ||
|
|
||
| spellCheckerSuggestionSpan += (String.valueOf(start) + "."); | ||
| spellCheckerSuggestionSpan += (String.valueOf(start + (length - 1)) + "."); | ||
|
||
|
|
||
| for (int j = 0; j < suggestionsCount; j++) { | ||
| String key = "suggestion_" + String.valueOf(j); | ||
| spellCheckerSuggestionSpan += (suggestionsInfo.getSuggestionAt(j) + ","); | ||
| } | ||
|
|
||
| spellCheckerSuggestionSpans.add( | ||
| spellCheckerSuggestionSpan.substring(0, spellCheckerSuggestionSpan.length() - 1)); | ||
| } | ||
| } | ||
|
|
||
| // Make call to update the spell checker results in the framework. | ||
| // Current text being passed for testing purposes. | ||
| // TODO(camillesimon): Don't pass text back to framework. | ||
| mSpellCheckChannel.updateSpellCheckerResults( | ||
| spellCheckerSuggestionSpans, currentSpellCheckedText); | ||
| } | ||
|
|
||
| @Override | ||
| public void onGetSuggestions(SuggestionsInfo[] results) { | ||
camsim99 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Callback for a deprecated method, so will not use. | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.