Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
38f1ee1
Proof of concept that can call startStylusHandwriting
justinmc May 20, 2024
f5c45e2
Fix the notification 'this app does not support handwriting input'
justinmc May 21, 2024
2c70875
Correctly report success/error
justinmc May 21, 2024
2da6b2e
Show icon on hover
justinmc May 21, 2024
815e6cd
Trying the other gestures, but not getting called...
justinmc May 21, 2024
da21044
Use isStylusHandwritingAvailable, as recommended in the doc
justinmc May 22, 2024
cdf7366
TODO for upgraded androidx
justinmc May 23, 2024
a298ad0
Merge branch 'main' into scribe
justinmc May 28, 2024
39249a5
AndroidX has been upgraded, though the PR seems to be getting reverte…
justinmc May 28, 2024
14ff786
Overriding preview as well, and checking if we ever get a call (no)
justinmc May 28, 2024
8217442
Declare that we support all the handwriting gestures!
justinmc May 28, 2024
d5e0301
Well that's why that wasn't getting called
justinmc May 29, 2024
39a4c8e
Version gate
justinmc May 29, 2024
27ca8db
Send selection gesture to framework
justinmc May 29, 2024
521fb22
TODO for granularity
justinmc May 30, 2024
2a27c55
Merge branch 'main' into scribe
justinmc Sep 30, 2024
5046264
Auto formatting
justinmc Sep 30, 2024
f9856a2
Pointer functionality is being moved to a separate PR
justinmc Sep 30, 2024
989eb2a
WIP Generic handwriting gesture call
justinmc Oct 1, 2024
47bd6b7
WIP previewHandwritingGesture
justinmc Oct 1, 2024
948d387
Scribe gestures will be handled in a separate PR
justinmc Oct 1, 2024
c2f1425
isStylusHandwritingAvailable method
justinmc Oct 1, 2024
5d385c5
Don't need to call isStylusHandwritingAvailable, that's on the caller
justinmc Oct 1, 2024
0a54134
Remove support for gestures, now shows dialog when gesture performed
justinmc Oct 1, 2024
aa95c06
Let's keep it a separate channel for now and check in review
justinmc Oct 1, 2024
0962507
ScribePluginTest
justinmc Oct 1, 2024
885f4bb
Get tests working, and add basic tests for ScribePlugin
justinmc Oct 1, 2024
8ef8f49
License check fix
justinmc Oct 1, 2024
49fa99b
Test for ScribePlugin
justinmc Oct 2, 2024
585ac33
Enforce api levels
justinmc Oct 2, 2024
250adbc
Separate Plugin and Channel tests
justinmc Oct 2, 2024
e96d8bc
Only start scribe when api available
justinmc Oct 2, 2024
8056d17
Test for TextInputPlugin change
justinmc Oct 2, 2024
016223e
Add missing api_level guards
justinmc Oct 3, 2024
cc69690
Move method channel handlers to their own private methods
justinmc Oct 3, 2024
6f1a6d8
Misc Reid's review comments
justinmc Oct 3, 2024
1ae66f1
Test unsupported api levels in scribeplugintest. Allow it to be creat…
justinmc Oct 4, 2024
f019841
Some work on testing api versions in ScribeChannel
justinmc Oct 4, 2024
d802eb2
Works without deprecated method
justinmc Oct 4, 2024
3685c9d
Test ScribeChannel when old api level
justinmc Oct 4, 2024
0ceab93
Make view public so it could be updated if the view changes
justinmc Oct 4, 2024
bc4dafd
TestInputPlugin unsupported test
justinmc Oct 4, 2024
00621e2
Private but settable view
justinmc Oct 7, 2024
53212fc
Use jsonmethodcodec
justinmc Oct 7, 2024
02c8f43
Test reply value now that we're using jsonmethodcodec
justinmc Oct 7, 2024
6d86717
Fix test missing mocked scribechannel
justinmc Oct 7, 2024
44c22d5
Fix platformviewscontrollertest due to missing scribechannel again.
justinmc Oct 7, 2024
06edcdb
Fix mixed up api version in test
justinmc Oct 7, 2024
df68cb8
isFeatureAvailable convenience method
justinmc Oct 18, 2024
37cab6c
Merge branch 'main' into scribe
justinmc Oct 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -44102,6 +44102,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/syst
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/ProcessTextChannel.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/RestorationChannel.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/ScribeChannel.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/common/ActivityLifecycleListener.java + ../../../flutter/LICENSE
Expand All @@ -44125,6 +44126,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/Flutte
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ImeSyncDeferringInsetsCallback.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ListenableEditingState.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/ScribePlugin.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/SpellCheckPlugin.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextEditingDelta.java + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java + ../../../flutter/LICENSE
Expand Down Expand Up @@ -46978,6 +46980,7 @@ 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/ProcessTextChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/RestorationChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/ScribeChannel.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
Expand All @@ -47004,6 +47007,7 @@ 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/ScribePlugin.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
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ android_java_sources = [
"io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java",
"io/flutter/embedding/engine/systemchannels/ProcessTextChannel.java",
"io/flutter/embedding/engine/systemchannels/RestorationChannel.java",
"io/flutter/embedding/engine/systemchannels/ScribeChannel.java",
"io/flutter/embedding/engine/systemchannels/SettingsChannel.java",
"io/flutter/embedding/engine/systemchannels/SpellCheckChannel.java",
"io/flutter/embedding/engine/systemchannels/SystemChannel.java",
Expand All @@ -320,6 +321,7 @@ 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/ScribePlugin.java",
"io/flutter/plugin/editing/SpellCheckPlugin.java",
"io/flutter/plugin/editing/TextEditingDelta.java",
"io/flutter/plugin/editing/TextInputPlugin.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
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.ScribePlugin;
import io.flutter.plugin.editing.SpellCheckPlugin;
import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.plugin.localization.LocalizationPlugin;
Expand Down Expand Up @@ -133,6 +134,7 @@ public class FlutterView extends FrameLayout
@Nullable private MouseCursorPlugin mouseCursorPlugin;
@Nullable private TextInputPlugin textInputPlugin;
@Nullable private SpellCheckPlugin spellCheckPlugin;
@Nullable private ScribePlugin scribePlugin;
@Nullable private LocalizationPlugin localizationPlugin;
@Nullable private KeyboardManager keyboardManager;
@Nullable private AndroidTouchProcessor androidTouchProcessor;
Expand Down Expand Up @@ -1120,10 +1122,12 @@ public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
if (Build.VERSION.SDK_INT >= API_LEVELS.API_24) {
mouseCursorPlugin = new MouseCursorPlugin(this, this.flutterEngine.getMouseCursorChannel());
}

textInputPlugin =
new TextInputPlugin(
this,
this.flutterEngine.getTextInputChannel(),
this.flutterEngine.getScribeChannel(),
this.flutterEngine.getPlatformViewsController());

try {
Expand All @@ -1136,6 +1140,10 @@ public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
Log.e(TAG, "TextServicesManager not supported by device, spell check disabled.");
}

scribePlugin =
new ScribePlugin(
this, textInputPlugin.getInputMethodManager(), this.flutterEngine.getScribeChannel());

localizationPlugin = this.flutterEngine.getLocalizationPlugin();

keyboardManager = new KeyboardManager(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.embedding.engine.systemchannels.ProcessTextChannel;
import io.flutter.embedding.engine.systemchannels.RestorationChannel;
import io.flutter.embedding.engine.systemchannels.ScribeChannel;
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
import io.flutter.embedding.engine.systemchannels.SpellCheckChannel;
import io.flutter.embedding.engine.systemchannels.SystemChannel;
Expand Down Expand Up @@ -100,6 +101,7 @@ public class FlutterEngine implements ViewUtils.DisplayUpdater {
@NonNull private final RestorationChannel restorationChannel;
@NonNull private final PlatformChannel platformChannel;
@NonNull private final ProcessTextChannel processTextChannel;
@NonNull private final ScribeChannel scribeChannel;
@NonNull private final SettingsChannel settingsChannel;
@NonNull private final SpellCheckChannel spellCheckChannel;
@NonNull private final SystemChannel systemChannel;
Expand Down Expand Up @@ -337,6 +339,7 @@ public FlutterEngine(
platformChannel = new PlatformChannel(dartExecutor);
processTextChannel = new ProcessTextChannel(dartExecutor, context.getPackageManager());
restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData);
scribeChannel = new ScribeChannel(dartExecutor);
settingsChannel = new SettingsChannel(dartExecutor);
spellCheckChannel = new SpellCheckChannel(dartExecutor);
systemChannel = new SystemChannel(dartExecutor);
Expand Down Expand Up @@ -610,6 +613,12 @@ public TextInputChannel getTextInputChannel() {
return textInputChannel;
}

/** System channel that sends and receives Scribe requests and results. */
@NonNull
public ScribeChannel getScribeChannel() {
return scribeChannel;
}

/** System channel that sends and receives spell check requests and results. */
@NonNull
public SpellCheckChannel getSpellCheckChannel() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// 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 static io.flutter.Build.API_LEVELS;

import android.annotation.TargetApi;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import io.flutter.Log;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.StandardMethodCodec;

/**
* {@link ScribeChannel} is a platform channel that is used by the framework to facilitate the
* Scribe handwriting text input feature.
*/
public class ScribeChannel {
private static final String TAG = "ScribeChannel";

@VisibleForTesting
public static final String METHOD_IS_STYLUS_HANDWRITING_AVAILABLE =
"Scribe.isStylusHandwritingAvailable";

@VisibleForTesting
public static final String METHOD_START_STYLUS_HANDWRITING = "Scribe.startStylusHandwriting";

public final MethodChannel channel;
private ScribeMethodHandler scribeMethodHandler;

@NonNull
public final MethodChannel.MethodCallHandler parsingMethodHandler =
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (scribeMethodHandler == null) {
Log.v(TAG, "No ScribeMethodHandler registered. Scribe call not handled.");
return;
}
String method = call.method;
Object args = call.arguments;
Log.v(TAG, "Received '" + method + "' message.");
switch (method) {
case METHOD_IS_STYLUS_HANDWRITING_AVAILABLE:
isStylusHandwritingAvailable(call, result);
break;
case METHOD_START_STYLUS_HANDWRITING:
startStylusHandwriting(call, result);
break;
default:
result.notImplemented();
break;
}
}
};

private void isStylusHandwritingAvailable(
@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (Build.VERSION.SDK_INT < API_LEVELS.API_34) {
result.error("error", "Requires API level 34 or higher.", null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that the dart side of the plugin needs to check if it is running on android and check the api level?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess in practice this probably means that you want to call this wrapped in a try/catch in Dart. My thought process is that this method channel method is just a proxy for InputMethodManager.isStylusHandwritingAvailable. If I'm not even able to call that, I should error, rather than succeed with false, which the app developer might interpret to mean that InputMethodManager.isStylusHandwritingAvailable returned false.

If that sounds reasonable then I'll at least make sure this is clearly documented in the framework.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update here: #52943 (comment)

return;
}

try {
final boolean isAvailable = scribeMethodHandler.isStylusHandwritingAvailable();
result.success(isAvailable);
} catch (IllegalStateException exception) {
result.error("error", exception.getMessage(), null);
}
}

private void startStylusHandwriting(
@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (Build.VERSION.SDK_INT < API_LEVELS.API_33) {
result.error("error", "Requires API level 33 or higher.", null);
return;
}

try {
scribeMethodHandler.startStylusHandwriting();
result.success(null);
} catch (IllegalStateException exception) {
result.error("error", exception.getMessage(), null);
}
}

public ScribeChannel(@NonNull DartExecutor dartExecutor) {
channel = new MethodChannel(dartExecutor, "flutter/scribe", StandardMethodCodec.INSTANCE);
channel.setMethodCallHandler(parsingMethodHandler);
}

/**
* Sets the {@link ScribeMethodHandler} which receives all requests for scribe sent through this
* channel.
*/
public void setScribeMethodHandler(@Nullable ScribeMethodHandler scribeMethodHandler) {
this.scribeMethodHandler = scribeMethodHandler;
}

public interface ScribeMethodHandler {
/**
* Responds to the {@code result} with success and a boolean indicating whether or not stylus
* hadnwriting is available.
*/
@TargetApi(API_LEVELS.API_34)
@RequiresApi(API_LEVELS.API_34)
boolean isStylusHandwritingAvailable();

/**
* Requests to start Scribe stylus handwriting, which will respond to the {@code result} with
* either success if handwriting input has started or error otherwise.
*/
@TargetApi(API_LEVELS.API_33)
@RequiresApi(API_LEVELS.API_33)
void startStylusHandwriting();
}

// TODO(justinmc): Scribe stylus gestures should be supported here.
// https://github.com/flutter/flutter/issues/156018
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import androidx.core.view.inputmethod.InputConnectionCompat;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.systemchannels.ScribeChannel;
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
Expand All @@ -51,6 +52,7 @@ public interface KeyboardDelegate {

private final View mFlutterView;
private final int mClient;
private final ScribeChannel scribeChannel;
private final TextInputChannel textInputChannel;
private final ListenableEditingState mEditable;
private final EditorInfo mEditorInfo;
Expand All @@ -69,6 +71,7 @@ public InputConnectionAdaptor(
View view,
int client,
TextInputChannel textInputChannel,
ScribeChannel scribeChannel,
KeyboardDelegate keyboardDelegate,
ListenableEditingState editable,
EditorInfo editorInfo,
Expand All @@ -77,6 +80,7 @@ public InputConnectionAdaptor(
mFlutterView = view;
mClient = client;
this.textInputChannel = textInputChannel;
this.scribeChannel = scribeChannel;
mEditable = editable;
mEditable.addEditingStateListener(this);
mEditorInfo = editorInfo;
Expand All @@ -100,10 +104,19 @@ public InputConnectionAdaptor(
View view,
int client,
TextInputChannel textInputChannel,
ScribeChannel scribeChannel,
KeyboardDelegate keyboardDelegate,
ListenableEditingState editable,
EditorInfo editorInfo) {
this(view, client, textInputChannel, keyboardDelegate, editable, editorInfo, new FlutterJNI());
this(
view,
client,
textInputChannel,
scribeChannel,
keyboardDelegate,
editable,
editorInfo,
new FlutterJNI());
}

private ExtractedText getExtractedText(ExtractedTextRequest request) {
Expand Down Expand Up @@ -262,6 +275,10 @@ public boolean setSelection(int start, int end) {
return result;
}

// TODO(justinmc): Scribe stylus gestures should be supported here via
// performHandwritingGesture.
// https://github.com/flutter/flutter/issues/156018

// Sanitizes the index to ensure the index is within the range of the
// contents of editable.
private static int clampIndexToEditable(int index, Editable editable) {
Expand Down
79 changes: 79 additions & 0 deletions shell/platform/android/io/flutter/plugin/editing/ScribePlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 static io.flutter.Build.API_LEVELS;

import android.annotation.TargetApi;
import android.os.Build;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import io.flutter.embedding.engine.systemchannels.ScribeChannel;

/**
* {@link ScribePlugin} is the implementation of all functionality needed for handwriting stylus
* text input.
*
* <p>The plugin handles requests for scribe sent by the {@link
* io.flutter.embedding.engine.systemchannels.ScribeChannel}.
*
* <p>On API versions below 33, the plugin does nothing.
*/
public class ScribePlugin implements ScribeChannel.ScribeMethodHandler {

@NonNull private final ScribeChannel mScribeChannel;
@NonNull private final InputMethodManager mInputMethodManager;
@NonNull public View mView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want this to be private or at least public and @VisibleForTesting not public.
Then add a setter for the view. My gut is that over time if the view changes then you want to be informed and be able to setup new callbacks or other events.


public ScribePlugin(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the view that is passed in here. Views in andoid IIRC do not have a long lifespan and this view is final. What happens when the app is backgrounded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the FlutterView from when ScribePlugin is created in FlutterView.java:

      scribePlugin =
          new ScribePlugin(
              this, textInputPlugin.getInputMethodManager(), this.flutterEngine.getScribeChannel());

I need it in order to call InputMethodManager.startStylusHandwriting. Is there a better way to get ahold of the View at that time that's called maybe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not so confident as to block the pr but I suspect that you can't make that variable final. That there is not a 1 to 1 relationship between flutter view and plugin instantiation.

I am specifically thinking of add to app and cached engine scenarios.
https://docs.flutter.dev/add-to-app/android/add-flutter-screen#step-3-optional-use-a-cached-flutterengine

None of our existing tests would catch this because they would not execute this code path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(From another thread) I've made a view setter so it can be updated if needed.

@NonNull View view, @NonNull InputMethodManager imm, @NonNull ScribeChannel scribeChannel) {
if (Build.VERSION.SDK_INT >= API_LEVELS.API_33) {
view.setAutoHandwritingEnabled(false);
}

mView = view;
mInputMethodManager = imm;
mScribeChannel = scribeChannel;

mScribeChannel.setScribeMethodHandler(this);
}

/**
* Unregisters this {@code ScribePlugin} as the {@code ScribeChannel.ScribeMethodHandler}, for the
* {@link io.flutter.embedding.engine.systemchannels.ScribeChannel}.
*
* <p>Do not invoke any methods on a {@code ScribePlugin} after invoking this method.
*/
public void destroy() {
mScribeChannel.setScribeMethodHandler(null);
}

/**
* Returns true if the InputMethodManager supports Scribe stylus handwriting input.
*
* <p>Call this before calling startStylusHandwriting to make sure it's available.
*/
@TargetApi(API_LEVELS.API_34)
@RequiresApi(API_LEVELS.API_34)
@Override
public boolean isStylusHandwritingAvailable() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public interface for ScribeMethodHandler does not annotate these methods as requiring api 34 so there is no expectation for callers that work on a ScribeMethodHandler that they should need to check api level. Either provide a branch inside the method that returns a default or modify the interface to have these annotations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I'll add the annotations to ScribeMethodHandler's methods.

return mInputMethodManager.isStylusHandwritingAvailable();
}

/**
* Starts stylus handwriting input.
*
* <p>Typically isStylusHandwritingAvailable should be called first to determine whether this is
* supported by the IME.
*/
@TargetApi(API_LEVELS.API_33)
@RequiresApi(API_LEVELS.API_33)
@Override
public void startStylusHandwriting() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here with interface vs implementation annotations.

mInputMethodManager.startStylusHandwriting(mView);
}
}
Loading