mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
System mouse cursor: Android (#18569)
Adds system mouse cursor to the Android engine.
This commit is contained in:
parent
5a085ac3c6
commit
b3e7732cf9
@ -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/LifecycleChannel.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/PlatformChannel.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
|
||||
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/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/PlatformPlugin.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformView.java
|
||||
|
||||
@ -177,6 +177,7 @@ android_java_sources = [
|
||||
"io/flutter/embedding/engine/systemchannels/KeyEventChannel.java",
|
||||
"io/flutter/embedding/engine/systemchannels/LifecycleChannel.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/PlatformChannel.java",
|
||||
"io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java",
|
||||
@ -204,6 +205,7 @@ android_java_sources = [
|
||||
"io/flutter/plugin/editing/FlutterTextUtils.java",
|
||||
"io/flutter/plugin/editing/InputConnectionAdaptor.java",
|
||||
"io/flutter/plugin/editing/TextInputPlugin.java",
|
||||
"io/flutter/plugin/mouse/MouseCursorPlugin.java",
|
||||
"io/flutter/plugin/platform/AccessibilityEventsDelegate.java",
|
||||
"io/flutter/plugin/platform/PlatformPlugin.java",
|
||||
"io/flutter/plugin/platform/PlatformView.java",
|
||||
@ -442,6 +444,7 @@ action("robolectric_tests") {
|
||||
"test/io/flutter/plugin/common/StandardMethodCodecTest.java",
|
||||
"test/io/flutter/plugin/editing/InputConnectionAdaptorTest.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/SingleViewPresentationTest.java",
|
||||
"test/io/flutter/plugins/GeneratedPluginRegistrant.java",
|
||||
|
||||
@ -17,6 +17,7 @@ import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewStructure;
|
||||
@ -39,6 +40,7 @@ import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.embedding.engine.renderer.RenderSurface;
|
||||
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
|
||||
import io.flutter.plugin.editing.TextInputPlugin;
|
||||
import io.flutter.plugin.mouse.MouseCursorPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import io.flutter.view.AccessibilityBridge;
|
||||
import java.util.ArrayList;
|
||||
@ -75,7 +77,7 @@ import java.util.Set;
|
||||
* 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}.
|
||||
*/
|
||||
public class FlutterView extends FrameLayout {
|
||||
public class FlutterView extends FrameLayout implements MouseCursorPlugin.MouseCursorViewDelegate {
|
||||
private static final String TAG = "FlutterView";
|
||||
|
||||
// Internal view hierarchy references.
|
||||
@ -97,6 +99,7 @@ public class FlutterView extends FrameLayout {
|
||||
//
|
||||
// These components essentially add some additional behavioral logic on top of
|
||||
// existing, stateless system channels, e.g., KeyEventChannel, TextInputChannel, etc.
|
||||
@Nullable private MouseCursorPlugin mouseCursorPlugin;
|
||||
@Nullable private TextInputPlugin textInputPlugin;
|
||||
@Nullable private AndroidKeyProcessor androidKeyProcessor;
|
||||
@Nullable private AndroidTouchProcessor androidTouchProcessor;
|
||||
@ -756,6 +759,16 @@ public class FlutterView extends FrameLayout {
|
||||
}
|
||||
// -------- 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}.
|
||||
*
|
||||
@ -794,6 +807,9 @@ public class FlutterView extends FrameLayout {
|
||||
|
||||
// Initialize various components that know how to process Android View I/O
|
||||
// in a way that Flutter understands.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
mouseCursorPlugin = new MouseCursorPlugin(this, this.flutterEngine.getMouseCursorChannel());
|
||||
}
|
||||
textInputPlugin =
|
||||
new TextInputPlugin(
|
||||
this,
|
||||
|
||||
@ -21,6 +21,7 @@ import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
|
||||
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.PlatformChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
|
||||
@ -77,6 +78,7 @@ public class FlutterEngine {
|
||||
@NonNull private final KeyEventChannel keyEventChannel;
|
||||
@NonNull private final LifecycleChannel lifecycleChannel;
|
||||
@NonNull private final LocalizationChannel localizationChannel;
|
||||
@NonNull private final MouseCursorChannel mouseCursorChannel;
|
||||
@NonNull private final NavigationChannel navigationChannel;
|
||||
@NonNull private final PlatformChannel platformChannel;
|
||||
@NonNull private final SettingsChannel settingsChannel;
|
||||
@ -218,6 +220,7 @@ public class FlutterEngine {
|
||||
keyEventChannel = new KeyEventChannel(dartExecutor);
|
||||
lifecycleChannel = new LifecycleChannel(dartExecutor);
|
||||
localizationChannel = new LocalizationChannel(dartExecutor);
|
||||
mouseCursorChannel = new MouseCursorChannel(dartExecutor);
|
||||
navigationChannel = new NavigationChannel(dartExecutor);
|
||||
platformChannel = new PlatformChannel(dartExecutor);
|
||||
settingsChannel = new SettingsChannel(dartExecutor);
|
||||
@ -391,6 +394,12 @@ public class FlutterEngine {
|
||||
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. */
|
||||
@NonNull
|
||||
public TextInputChannel getTextInputChannel() {
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
// 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;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
@ -49,6 +50,7 @@ import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
|
||||
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.PlatformChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
|
||||
@ -57,6 +59,7 @@ import io.flutter.embedding.engine.systemchannels.TextInputChannel;
|
||||
import io.flutter.plugin.common.ActivityLifecycleListener;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.editing.TextInputPlugin;
|
||||
import io.flutter.plugin.mouse.MouseCursorPlugin;
|
||||
import io.flutter.plugin.platform.PlatformPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -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
|
||||
* 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
|
||||
* as a full-screen Flutter activity).
|
||||
@ -120,6 +124,7 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
|
||||
private final SystemChannel systemChannel;
|
||||
private final InputMethodManager mImm;
|
||||
private final TextInputPlugin mTextInputPlugin;
|
||||
private final MouseCursorPlugin mMouseCursorPlugin;
|
||||
private final AndroidKeyProcessor androidKeyProcessor;
|
||||
private final AndroidTouchProcessor androidTouchProcessor;
|
||||
private AccessibilityBridge mAccessibilityNodeProvider;
|
||||
@ -221,6 +226,11 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
|
||||
mNativeView.getPluginRegistry().getPlatformViewsController();
|
||||
mTextInputPlugin =
|
||||
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);
|
||||
androidTouchProcessor = new AndroidTouchProcessor(flutterRenderer);
|
||||
mNativeView
|
||||
@ -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
|
||||
@UiThread
|
||||
public void send(String channel, ByteBuffer message) {
|
||||
|
||||
@ -20,6 +20,7 @@ import io.flutter.plugin.common.StandardMessageCodecTest;
|
||||
import io.flutter.plugin.common.StandardMethodCodecTest;
|
||||
import io.flutter.plugin.editing.InputConnectionAdaptorTest;
|
||||
import io.flutter.plugin.editing.TextInputPluginTest;
|
||||
import io.flutter.plugin.mouse.MouseCursorPluginTest;
|
||||
import io.flutter.plugin.platform.PlatformPluginTest;
|
||||
import io.flutter.plugin.platform.SingleViewPresentationTest;
|
||||
import io.flutter.util.PreconditionsTest;
|
||||
@ -58,6 +59,7 @@ import test.io.flutter.embedding.engine.dart.DartExecutorTest;
|
||||
SingleViewPresentationTest.class,
|
||||
SmokeTest.class,
|
||||
TextInputPluginTest.class,
|
||||
MouseCursorPluginTest.class,
|
||||
AccessibilityBridgeTest.class,
|
||||
})
|
||||
/** Runs all of the unit tests listed in the {@code @SuiteClasses} annotation. */
|
||||
|
||||
@ -27,6 +27,7 @@ import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
|
||||
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.SettingsChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.SystemChannel;
|
||||
@ -615,6 +616,7 @@ public class FlutterActivityAndFragmentDelegateTest {
|
||||
when(engine.getNavigationChannel()).thenReturn(mock(NavigationChannel.class));
|
||||
when(engine.getSystemChannel()).thenReturn(mock(SystemChannel.class));
|
||||
when(engine.getTextInputChannel()).thenReturn(mock(TextInputChannel.class));
|
||||
when(engine.getMouseCursorChannel()).thenReturn(mock(MouseCursorChannel.class));
|
||||
when(engine.getActivityControlSurface()).thenReturn(mock(ActivityControlSurface.class));
|
||||
|
||||
return engine;
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
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() {}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user