未验证 提交 b3e7732c 编写于 作者: T Tong Mu 提交者: GitHub

System mouse cursor: Android (#18569)

Adds system mouse cursor to the Android engine.
上级 5a085ac3
...@@ -727,6 +727,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/system ...@@ -727,6 +727,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/system
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/MouseCursorChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/NavigationChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/NavigationChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java
...@@ -754,6 +755,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StringCod ...@@ -754,6 +755,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/StringCod
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/FlutterTextUtils.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/FlutterTextUtils.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/mouse/MouseCursorPlugin.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/AccessibilityEventsDelegate.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/AccessibilityEventsDelegate.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformView.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformView.java
......
...@@ -177,6 +177,7 @@ android_java_sources = [ ...@@ -177,6 +177,7 @@ android_java_sources = [
"io/flutter/embedding/engine/systemchannels/KeyEventChannel.java", "io/flutter/embedding/engine/systemchannels/KeyEventChannel.java",
"io/flutter/embedding/engine/systemchannels/LifecycleChannel.java", "io/flutter/embedding/engine/systemchannels/LifecycleChannel.java",
"io/flutter/embedding/engine/systemchannels/LocalizationChannel.java", "io/flutter/embedding/engine/systemchannels/LocalizationChannel.java",
"io/flutter/embedding/engine/systemchannels/MouseCursorChannel.java",
"io/flutter/embedding/engine/systemchannels/NavigationChannel.java", "io/flutter/embedding/engine/systemchannels/NavigationChannel.java",
"io/flutter/embedding/engine/systemchannels/PlatformChannel.java", "io/flutter/embedding/engine/systemchannels/PlatformChannel.java",
"io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java", "io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java",
...@@ -204,6 +205,7 @@ android_java_sources = [ ...@@ -204,6 +205,7 @@ android_java_sources = [
"io/flutter/plugin/editing/FlutterTextUtils.java", "io/flutter/plugin/editing/FlutterTextUtils.java",
"io/flutter/plugin/editing/InputConnectionAdaptor.java", "io/flutter/plugin/editing/InputConnectionAdaptor.java",
"io/flutter/plugin/editing/TextInputPlugin.java", "io/flutter/plugin/editing/TextInputPlugin.java",
"io/flutter/plugin/mouse/MouseCursorPlugin.java",
"io/flutter/plugin/platform/AccessibilityEventsDelegate.java", "io/flutter/plugin/platform/AccessibilityEventsDelegate.java",
"io/flutter/plugin/platform/PlatformPlugin.java", "io/flutter/plugin/platform/PlatformPlugin.java",
"io/flutter/plugin/platform/PlatformView.java", "io/flutter/plugin/platform/PlatformView.java",
...@@ -442,6 +444,7 @@ action("robolectric_tests") { ...@@ -442,6 +444,7 @@ action("robolectric_tests") {
"test/io/flutter/plugin/common/StandardMethodCodecTest.java", "test/io/flutter/plugin/common/StandardMethodCodecTest.java",
"test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java", "test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java",
"test/io/flutter/plugin/editing/TextInputPluginTest.java", "test/io/flutter/plugin/editing/TextInputPluginTest.java",
"test/io/flutter/plugin/mouse/MouseCursorPluginTest.java",
"test/io/flutter/plugin/platform/PlatformPluginTest.java", "test/io/flutter/plugin/platform/PlatformPluginTest.java",
"test/io/flutter/plugin/platform/SingleViewPresentationTest.java", "test/io/flutter/plugin/platform/SingleViewPresentationTest.java",
"test/io/flutter/plugins/GeneratedPluginRegistrant.java", "test/io/flutter/plugins/GeneratedPluginRegistrant.java",
......
...@@ -17,6 +17,7 @@ import android.util.AttributeSet; ...@@ -17,6 +17,7 @@ import android.util.AttributeSet;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface; import android.view.Surface;
import android.view.View; import android.view.View;
import android.view.ViewStructure; import android.view.ViewStructure;
...@@ -39,6 +40,7 @@ import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener; ...@@ -39,6 +40,7 @@ import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
import io.flutter.embedding.engine.renderer.RenderSurface; import io.flutter.embedding.engine.renderer.RenderSurface;
import io.flutter.embedding.engine.systemchannels.SettingsChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel;
import io.flutter.plugin.editing.TextInputPlugin; import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.plugin.mouse.MouseCursorPlugin;
import io.flutter.plugin.platform.PlatformViewsController; import io.flutter.plugin.platform.PlatformViewsController;
import io.flutter.view.AccessibilityBridge; import io.flutter.view.AccessibilityBridge;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -75,7 +77,7 @@ import java.util.Set; ...@@ -75,7 +77,7 @@ import java.util.Set;
* See <a>https://source.android.com/devices/graphics/arch-tv#surface_or_texture</a> for more * See <a>https://source.android.com/devices/graphics/arch-tv#surface_or_texture</a> for more
* information comparing {@link android.view.SurfaceView} and {@link android.view.TextureView}. * information comparing {@link android.view.SurfaceView} and {@link android.view.TextureView}.
*/ */
public class FlutterView extends FrameLayout { public class FlutterView extends FrameLayout implements MouseCursorPlugin.MouseCursorViewDelegate {
private static final String TAG = "FlutterView"; private static final String TAG = "FlutterView";
// Internal view hierarchy references. // Internal view hierarchy references.
...@@ -97,6 +99,7 @@ public class FlutterView extends FrameLayout { ...@@ -97,6 +99,7 @@ public class FlutterView extends FrameLayout {
// //
// These components essentially add some additional behavioral logic on top of // These components essentially add some additional behavioral logic on top of
// existing, stateless system channels, e.g., KeyEventChannel, TextInputChannel, etc. // existing, stateless system channels, e.g., KeyEventChannel, TextInputChannel, etc.
@Nullable private MouseCursorPlugin mouseCursorPlugin;
@Nullable private TextInputPlugin textInputPlugin; @Nullable private TextInputPlugin textInputPlugin;
@Nullable private AndroidKeyProcessor androidKeyProcessor; @Nullable private AndroidKeyProcessor androidKeyProcessor;
@Nullable private AndroidTouchProcessor androidTouchProcessor; @Nullable private AndroidTouchProcessor androidTouchProcessor;
...@@ -756,6 +759,16 @@ public class FlutterView extends FrameLayout { ...@@ -756,6 +759,16 @@ public class FlutterView extends FrameLayout {
} }
// -------- End: Accessibility --------- // -------- End: Accessibility ---------
// -------- Start: Mouse -------
@Override
@TargetApi(Build.VERSION_CODES.N)
@RequiresApi(Build.VERSION_CODES.N)
@NonNull
public PointerIcon getSystemPointerIcon(int type) {
return PointerIcon.getSystemIcon(getContext(), type);
}
// -------- End: Mouse ---------
/** /**
* Connects this {@code FlutterView} to the given {@link FlutterEngine}. * Connects this {@code FlutterView} to the given {@link FlutterEngine}.
* *
...@@ -794,6 +807,9 @@ public class FlutterView extends FrameLayout { ...@@ -794,6 +807,9 @@ public class FlutterView extends FrameLayout {
// Initialize various components that know how to process Android View I/O // Initialize various components that know how to process Android View I/O
// in a way that Flutter understands. // in a way that Flutter understands.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mouseCursorPlugin = new MouseCursorPlugin(this, this.flutterEngine.getMouseCursorChannel());
}
textInputPlugin = textInputPlugin =
new TextInputPlugin( new TextInputPlugin(
this, this,
......
...@@ -21,6 +21,7 @@ import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; ...@@ -21,6 +21,7 @@ import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
import io.flutter.embedding.engine.systemchannels.KeyEventChannel; import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
import io.flutter.embedding.engine.systemchannels.LifecycleChannel; import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
import io.flutter.embedding.engine.systemchannels.LocalizationChannel; import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
import io.flutter.embedding.engine.systemchannels.NavigationChannel; import io.flutter.embedding.engine.systemchannels.NavigationChannel;
import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.embedding.engine.systemchannels.SettingsChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel;
...@@ -77,6 +78,7 @@ public class FlutterEngine { ...@@ -77,6 +78,7 @@ public class FlutterEngine {
@NonNull private final KeyEventChannel keyEventChannel; @NonNull private final KeyEventChannel keyEventChannel;
@NonNull private final LifecycleChannel lifecycleChannel; @NonNull private final LifecycleChannel lifecycleChannel;
@NonNull private final LocalizationChannel localizationChannel; @NonNull private final LocalizationChannel localizationChannel;
@NonNull private final MouseCursorChannel mouseCursorChannel;
@NonNull private final NavigationChannel navigationChannel; @NonNull private final NavigationChannel navigationChannel;
@NonNull private final PlatformChannel platformChannel; @NonNull private final PlatformChannel platformChannel;
@NonNull private final SettingsChannel settingsChannel; @NonNull private final SettingsChannel settingsChannel;
...@@ -218,6 +220,7 @@ public class FlutterEngine { ...@@ -218,6 +220,7 @@ public class FlutterEngine {
keyEventChannel = new KeyEventChannel(dartExecutor); keyEventChannel = new KeyEventChannel(dartExecutor);
lifecycleChannel = new LifecycleChannel(dartExecutor); lifecycleChannel = new LifecycleChannel(dartExecutor);
localizationChannel = new LocalizationChannel(dartExecutor); localizationChannel = new LocalizationChannel(dartExecutor);
mouseCursorChannel = new MouseCursorChannel(dartExecutor);
navigationChannel = new NavigationChannel(dartExecutor); navigationChannel = new NavigationChannel(dartExecutor);
platformChannel = new PlatformChannel(dartExecutor); platformChannel = new PlatformChannel(dartExecutor);
settingsChannel = new SettingsChannel(dartExecutor); settingsChannel = new SettingsChannel(dartExecutor);
...@@ -391,6 +394,12 @@ public class FlutterEngine { ...@@ -391,6 +394,12 @@ public class FlutterEngine {
return systemChannel; return systemChannel;
} }
/** System channel that sends and receives text input requests and state. */
@NonNull
public MouseCursorChannel getMouseCursorChannel() {
return mouseCursorChannel;
}
/** System channel that sends and receives text input requests and state. */ /** System channel that sends and receives text input requests and state. */
@NonNull @NonNull
public TextInputChannel getTextInputChannel() { public TextInputChannel getTextInputChannel() {
......
// 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 android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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;
import java.util.HashMap;
/** System channel that receives requests for mouse cursor behavior, e.g., set as system cursors. */
public class MouseCursorChannel {
private static final String TAG = "MouseCursorChannel";
@NonNull public final MethodChannel channel;
@Nullable private MouseCursorMethodHandler mouseCursorMethodHandler;
public MouseCursorChannel(@NonNull DartExecutor dartExecutor) {
channel = new MethodChannel(dartExecutor, "flutter/mousecursor", StandardMethodCodec.INSTANCE);
channel.setMethodCallHandler(parsingMethodCallHandler);
}
/**
* Sets the {@link MouseCursorMethodHandler} which receives all events and requests that are
* parsed from the underlying platform channel.
*/
public void setMethodHandler(@Nullable MouseCursorMethodHandler mouseCursorMethodHandler) {
this.mouseCursorMethodHandler = mouseCursorMethodHandler;
}
@NonNull
private final MethodChannel.MethodCallHandler parsingMethodCallHandler =
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (mouseCursorMethodHandler == null) {
// If no explicit mouseCursorMethodHandler has been registered then we don't
// need to forward this call to an API. Return.
return;
}
final String method = call.method;
Log.v(TAG, "Received '" + method + "' message.");
try {
// More methods are expected to be added here, hence the switch.
switch (method) {
case "activateSystemCursor":
@SuppressWarnings("unchecked")
final HashMap<String, Object> data = (HashMap<String, Object>) call.arguments;
final String kind = (String) data.get("kind");
try {
mouseCursorMethodHandler.activateSystemCursor(kind);
} catch (Exception e) {
result.error("error", "Error when setting cursors: " + e.getMessage(), null);
break;
}
result.success(true);
break;
default:
}
} catch (Exception e) {
result.error("error", "Unhandled error: " + e.getMessage(), null);
}
}
};
@VisibleForTesting
public void synthesizeMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
parsingMethodCallHandler.onMethodCall(call, result);
}
public interface MouseCursorMethodHandler {
// Called when the pointer should start displaying a system mouse cursor
// specified by {@code shapeCode}.
public void activateSystemCursor(@NonNull String kind);
}
}
// 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.mouse;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.PointerIcon;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
import java.util.HashMap;
/** A mandatory plugin that handles mouse cursor requests. */
@TargetApi(Build.VERSION_CODES.N)
@RequiresApi(Build.VERSION_CODES.N)
public class MouseCursorPlugin {
@NonNull private final MouseCursorViewDelegate mView;
@NonNull private final MouseCursorChannel mouseCursorChannel;
public MouseCursorPlugin(
@NonNull MouseCursorViewDelegate view, @NonNull MouseCursorChannel mouseCursorChannel) {
mView = view;
this.mouseCursorChannel = mouseCursorChannel;
mouseCursorChannel.setMethodHandler(
new MouseCursorChannel.MouseCursorMethodHandler() {
@Override
public void activateSystemCursor(@NonNull String kind) {
mView.setPointerIcon(resolveSystemCursor(kind));
}
});
}
/**
* Return a pointer icon object for a system cursor.
*
* <p>This method guarantees to return a non-null object.
*/
private PointerIcon resolveSystemCursor(@NonNull String kind) {
if (MouseCursorPlugin.systemCursorConstants == null) {
// Initialize the map when first used, because the map can grow big in the future (~70)
// and most mobile devices will not use them.
MouseCursorPlugin.systemCursorConstants =
new HashMap<String, Integer>() {
private static final long serialVersionUID = 1L;
{
put("none", Integer.valueOf(PointerIcon.TYPE_NULL));
// "basic": default
put("click", Integer.valueOf(PointerIcon.TYPE_HAND));
put("text", Integer.valueOf(PointerIcon.TYPE_TEXT));
// "forbidden": default
put("grab", Integer.valueOf(PointerIcon.TYPE_GRAB));
put("grabbing", Integer.valueOf(PointerIcon.TYPE_GRABBING));
}
};
}
final int cursorConstant =
MouseCursorPlugin.systemCursorConstants.getOrDefault(kind, PointerIcon.TYPE_ARROW);
return mView.getSystemPointerIcon(cursorConstant);
}
/**
* Detaches the text input plugin from the platform views controller.
*
* <p>The MouseCursorPlugin instance should not be used after calling this.
*/
public void destroy() {
mouseCursorChannel.setMethodHandler(null);
}
/**
* A map from Flutter's system cursor {@code kind} to Android's pointer icon constants.
*
* <p>It is null until the first time a system cursor is requested, at which time it is filled
* with the entire mapping.
*/
@NonNull private static HashMap<String, Integer> systemCursorConstants;
/**
* Delegate interface for requesting the system to display a pointer icon object.
*
* <p>Typically implemented by an {@link android.view.View}, such as a {@code FlutterView}.
*/
public interface MouseCursorViewDelegate {
/**
* Gets a system pointer icon object for the given {@code type}.
*
* <p>If typeis not recognized, returns the default pointer icon.
*
* <p>This is typically implemented by calling {@link android.view.PointerIcon.getSystemIcon}
* with the context associated with this view.
*/
public PointerIcon getSystemPointerIcon(int type);
/**
* Request the pointer to display the specified icon object.
*
* <p>If the delegate is implemented by a {@link android.view.View}, then this method is
* automatically implemented by View.
*/
public void setPointerIcon(@NonNull PointerIcon icon);
}
}
...@@ -24,6 +24,7 @@ import android.util.Log; ...@@ -24,6 +24,7 @@ import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface; import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
...@@ -49,6 +50,7 @@ import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; ...@@ -49,6 +50,7 @@ import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
import io.flutter.embedding.engine.systemchannels.KeyEventChannel; import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
import io.flutter.embedding.engine.systemchannels.LifecycleChannel; import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
import io.flutter.embedding.engine.systemchannels.LocalizationChannel; import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
import io.flutter.embedding.engine.systemchannels.NavigationChannel; import io.flutter.embedding.engine.systemchannels.NavigationChannel;
import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.embedding.engine.systemchannels.SettingsChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel;
...@@ -57,6 +59,7 @@ import io.flutter.embedding.engine.systemchannels.TextInputChannel; ...@@ -57,6 +59,7 @@ import io.flutter.embedding.engine.systemchannels.TextInputChannel;
import io.flutter.plugin.common.ActivityLifecycleListener; import io.flutter.plugin.common.ActivityLifecycleListener;
import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.editing.TextInputPlugin; import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.plugin.mouse.MouseCursorPlugin;
import io.flutter.plugin.platform.PlatformPlugin; import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.plugin.platform.PlatformViewsController; import io.flutter.plugin.platform.PlatformViewsController;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
...@@ -72,7 +75,8 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -72,7 +75,8 @@ import java.util.concurrent.atomic.AtomicLong;
* <p>Deprecation: {@link io.flutter.embedding.android.FlutterView} is the new API that now replaces * <p>Deprecation: {@link io.flutter.embedding.android.FlutterView} is the new API that now replaces
* this class. See https://flutter.dev/go/android-project-migration for more migration details. * this class. See https://flutter.dev/go/android-project-migration for more migration details.
*/ */
public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry { public class FlutterView extends SurfaceView
implements BinaryMessenger, TextureRegistry, MouseCursorPlugin.MouseCursorViewDelegate {
/** /**
* Interface for those objects that maintain and expose a reference to a {@code FlutterView} (such * Interface for those objects that maintain and expose a reference to a {@code FlutterView} (such
* as a full-screen Flutter activity). * as a full-screen Flutter activity).
...@@ -120,6 +124,7 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture ...@@ -120,6 +124,7 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
private final SystemChannel systemChannel; private final SystemChannel systemChannel;
private final InputMethodManager mImm; private final InputMethodManager mImm;
private final TextInputPlugin mTextInputPlugin; private final TextInputPlugin mTextInputPlugin;
private final MouseCursorPlugin mMouseCursorPlugin;
private final AndroidKeyProcessor androidKeyProcessor; private final AndroidKeyProcessor androidKeyProcessor;
private final AndroidTouchProcessor androidTouchProcessor; private final AndroidTouchProcessor androidTouchProcessor;
private AccessibilityBridge mAccessibilityNodeProvider; private AccessibilityBridge mAccessibilityNodeProvider;
...@@ -221,6 +226,11 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture ...@@ -221,6 +226,11 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
mNativeView.getPluginRegistry().getPlatformViewsController(); mNativeView.getPluginRegistry().getPlatformViewsController();
mTextInputPlugin = mTextInputPlugin =
new TextInputPlugin(this, new TextInputChannel(dartExecutor), platformViewsController); new TextInputPlugin(this, new TextInputChannel(dartExecutor), platformViewsController);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMouseCursorPlugin = new MouseCursorPlugin(this, new MouseCursorChannel(dartExecutor));
} else {
mMouseCursorPlugin = null;
}
androidKeyProcessor = new AndroidKeyProcessor(keyEventChannel, mTextInputPlugin); androidKeyProcessor = new AndroidKeyProcessor(keyEventChannel, mTextInputPlugin);
androidTouchProcessor = new AndroidTouchProcessor(flutterRenderer); androidTouchProcessor = new AndroidTouchProcessor(flutterRenderer);
mNativeView mNativeView
...@@ -793,6 +803,14 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture ...@@ -793,6 +803,14 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
} }
} }
@Override
@TargetApi(Build.VERSION_CODES.N)
@RequiresApi(Build.VERSION_CODES.N)
@NonNull
public PointerIcon getSystemPointerIcon(int type) {
return PointerIcon.getSystemIcon(getContext(), type);
}
@Override @Override
@UiThread @UiThread
public void send(String channel, ByteBuffer message) { public void send(String channel, ByteBuffer message) {
......
...@@ -20,6 +20,7 @@ import io.flutter.plugin.common.StandardMessageCodecTest; ...@@ -20,6 +20,7 @@ import io.flutter.plugin.common.StandardMessageCodecTest;
import io.flutter.plugin.common.StandardMethodCodecTest; import io.flutter.plugin.common.StandardMethodCodecTest;
import io.flutter.plugin.editing.InputConnectionAdaptorTest; import io.flutter.plugin.editing.InputConnectionAdaptorTest;
import io.flutter.plugin.editing.TextInputPluginTest; import io.flutter.plugin.editing.TextInputPluginTest;
import io.flutter.plugin.mouse.MouseCursorPluginTest;
import io.flutter.plugin.platform.PlatformPluginTest; import io.flutter.plugin.platform.PlatformPluginTest;
import io.flutter.plugin.platform.SingleViewPresentationTest; import io.flutter.plugin.platform.SingleViewPresentationTest;
import io.flutter.util.PreconditionsTest; import io.flutter.util.PreconditionsTest;
...@@ -58,6 +59,7 @@ import test.io.flutter.embedding.engine.dart.DartExecutorTest; ...@@ -58,6 +59,7 @@ import test.io.flutter.embedding.engine.dart.DartExecutorTest;
SingleViewPresentationTest.class, SingleViewPresentationTest.class,
SmokeTest.class, SmokeTest.class,
TextInputPluginTest.class, TextInputPluginTest.class,
MouseCursorPluginTest.class,
AccessibilityBridgeTest.class, AccessibilityBridgeTest.class,
}) })
/** Runs all of the unit tests listed in the {@code @SuiteClasses} annotation. */ /** Runs all of the unit tests listed in the {@code @SuiteClasses} annotation. */
......
...@@ -27,6 +27,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer; ...@@ -27,6 +27,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
import io.flutter.embedding.engine.systemchannels.LifecycleChannel; import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
import io.flutter.embedding.engine.systemchannels.LocalizationChannel; import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
import io.flutter.embedding.engine.systemchannels.NavigationChannel; import io.flutter.embedding.engine.systemchannels.NavigationChannel;
import io.flutter.embedding.engine.systemchannels.SettingsChannel; import io.flutter.embedding.engine.systemchannels.SettingsChannel;
import io.flutter.embedding.engine.systemchannels.SystemChannel; import io.flutter.embedding.engine.systemchannels.SystemChannel;
...@@ -615,6 +616,7 @@ public class FlutterActivityAndFragmentDelegateTest { ...@@ -615,6 +616,7 @@ public class FlutterActivityAndFragmentDelegateTest {
when(engine.getNavigationChannel()).thenReturn(mock(NavigationChannel.class)); when(engine.getNavigationChannel()).thenReturn(mock(NavigationChannel.class));
when(engine.getSystemChannel()).thenReturn(mock(SystemChannel.class)); when(engine.getSystemChannel()).thenReturn(mock(SystemChannel.class));
when(engine.getTextInputChannel()).thenReturn(mock(TextInputChannel.class)); when(engine.getTextInputChannel()).thenReturn(mock(TextInputChannel.class));
when(engine.getMouseCursorChannel()).thenReturn(mock(MouseCursorChannel.class));
when(engine.getActivityControlSurface()).thenReturn(mock(ActivityControlSurface.class)); when(engine.getActivityControlSurface()).thenReturn(mock(ActivityControlSurface.class));
return engine; return engine;
......
package io.flutter.plugin.mouse;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.annotation.TargetApi;
import android.view.PointerIcon;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import java.util.HashMap;
import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@Config(
manifest = Config.NONE,
shadows = {})
@RunWith(RobolectricTestRunner.class)
@TargetApi(24)
public class MouseCursorPluginTest {
@Test
public void mouseCursorPlugin_SetsSystemCursorOnRequest() throws JSONException {
// Initialize a general MouseCursorPlugin.
FlutterView testView = spy(new FlutterView(RuntimeEnvironment.application));
MouseCursorChannel mouseCursorChannel = new MouseCursorChannel(mock(DartExecutor.class));
MouseCursorPlugin mouseCursorPlugin = new MouseCursorPlugin(testView, mouseCursorChannel);
final StoredResult methodResult = new StoredResult();
mouseCursorChannel.synthesizeMethodCall(
new MethodCall(
"activateSystemCursor",
new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put("device", 1);
put("kind", "text");
}
}),
methodResult);
verify(testView, times(1)).getSystemPointerIcon(PointerIcon.TYPE_TEXT);
verify(testView, times(1)).setPointerIcon(any(PointerIcon.class));
assertEquals(methodResult.result, Boolean.TRUE);
}
}
class StoredResult implements MethodChannel.Result {
Object result;
@Override
public void success(Object result) {
this.result = result;
}
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {}
@Override
public void notImplemented() {}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册