Conversation
mklim
left a comment
There was a problem hiding this comment.
I gave this PR a high-level review and didn't closely vet for readability/style nits since this is still a WIP.
One thing I noticed is that in the engine there's a v1 and a v2 embedding. These changes need to be added to both places, because we're currently supporting both.
Depending on whether context needs to be tied to an activity, and assuming it doesn't, I think it makes more sense for the channel to be initialized and live in FlutterEngine in v2 of the embedding instead of FlutterView. If it really needs a context then it should probably be in the v2 FlutterView, shell/platform/android/io/flutter/embedding/android/FlutterView.java.
Currently this PR is just adding it to the v1 "FlutterView," shell/platform/android/io/flutter/view/FlutterView.java, which I think does make sense as the right place for the v1 embedding.
You can look up LifecycleChannel for an example of how something is used in both places.
Other than that the basic approach doesn't seem to have any issues to me.
/cc @matthew-carroll, I think it would be good for him to verify this too.
| private MouseCursorMethodHandler mouseCursorMethodHandler; | ||
|
|
||
| public MouseCursorChannel(@NonNull DartExecutor dartExecutor) { | ||
| channel = new MethodChannel(dartExecutor, CHANNEL_NAME, JSONMethodCodec.INSTANCE); |
There was a problem hiding this comment.
Any reason why JSON instead of the Standard method codec here?
Edit: I looked at the other channels and they seem to vary. I'm not sure which is preferred but plugins always uses Standard. /cc @matthew-carroll in case he knows.
There was a problem hiding this comment.
Unfortunately, I don't know. I added structure around the channels, but didn't change any of them.
| // Argument list is [device, cursor]. Since Android only supports one pointer device, | ||
| // we can ignore argument 0. | ||
| cursor = argumentList.getInt(1); | ||
| } catch (Exception e) { |
There was a problem hiding this comment.
readability nit: It's generally not great to catch Exception as a top level type. This ends up potentially masking completely unrelated issues to actually parsing the message. I would change this into the specific parsing exceptions that are a concern.
| } | ||
|
|
||
| @NonNull | ||
| @VisibleForTesting |
There was a problem hiding this comment.
readability nit: I wouldn't make this @VisibleForTesting protected unless you really need to expose this for a test and just for a test for some reason. In the state this PR is now it would be better to make this private.
| * The given {@code dartExecutor} is used to construct the method channel with which the | ||
| * platform communicates with the framework. | ||
| * | ||
| * The given {@code context} is used to create system cursor object. Usually it's the current |
There was a problem hiding this comment.
Usually it's the current activity.
Does it need to be linked to an activity, or is it okay to be just a system context? I'm asking because with the v2 add-to-app embedding changes, it's possible for engine code like this to be executing even when there is no visible UI or activity to speak of.
| @NonNull | ||
| private View view; | ||
|
|
||
| // The target application context. |
There was a problem hiding this comment.
"application context" would mean that this is never an activity, so this is a little confusing. (Android is confusing in general about this. See the #getApplicationContext docs.)
|
|
||
| /* Displays no cursor at the pointer. | ||
| */ | ||
| public final static int none = 0x334c4a4c; |
There was a problem hiding this comment.
This is hard to read and understand. Would Strings make sense here? What's the significance of these specific int values?
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| package io.flutter.plugin.mouse; |
There was a problem hiding this comment.
Is this expected to be used in plugins? I think this would maybe make more sense in io.flutter.embedding.engine.systemchannels.
| private MouseCursorMethodHandler mouseCursorMethodHandler; | ||
|
|
||
| public MouseCursorChannel(@NonNull DartExecutor dartExecutor) { | ||
| channel = new MethodChannel(dartExecutor, CHANNEL_NAME, JSONMethodCodec.INSTANCE); |
There was a problem hiding this comment.
Unfortunately, I don't know. I added structure around the channels, but didn't change any of them.
| import io.flutter.plugin.mouse.MouseCursors; | ||
|
|
||
| /** | ||
| * Manages mouse cursor of the mouse device. |
There was a problem hiding this comment.
Please include <p> tags in all javadoc comments, as shown in other files.
| mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); | ||
| PlatformViewsController platformViewsController = mNativeView.getPluginRegistry().getPlatformViewsController(); | ||
| mTextInputPlugin = new TextInputPlugin(this, dartExecutor, platformViewsController); | ||
| mMouseCursorController = new MouseCursorController(this, dartExecutor, context); |
There was a problem hiding this comment.
Are changes needed in the new FlutterView, too?
| ) { | ||
| channel = new MouseCursorChannel(dartExecutor); | ||
| channel.setMethodHandler(channelHandler); | ||
| this.view = view; |
There was a problem hiding this comment.
Rather than manipulate a View within this class, I would recommend defining a delegate interface and then implement that interface within the old and new FlutterViews. That way, there is no magic or mystery when reading FlutterView as to what it's doing. When we move control of something like a View to other classes, sooner or later we get surprised by conflicts or unexpected behaviors.
|
Close it in favor of separate PRs for each platform. Also I have some major changes in progress. |
Description
This is a WIP about adding mouse cursor control.
The engine section of the mouse cursor system is basically a bridge between the framework section, which it talks to via a method channel, and the system calls. Although all platforms use the same channel, each platform has their own interfaces depending on how features are provided by the platform. That being said, all platform interfaces are designed with the following principles:
Map<String, dynamic>.For example, macOS requires
hideandunhidecalls to be balanced. This is counted and enforced by the framework, while the engine blindly follows commands.Exception: When we implement custom cursors in the future, the cursor objects have to be cached and maintained by the engine.
For example, Flutter has
MouseCursorSystemShapewhich are platform-independent constants that represent system cursors. The mapping between them to Android/GLFW platform constants are done by the framework, so that the engine can directly use the platform constants it receives.Exception: On macOS the system mouse cursors are not represented by integer constants but by objects, therefore we have to define our own system constants.
Related Issues