diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a11a605e97e2f..5ffaf4910922a 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -556,6 +556,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/system FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.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 FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SettingsChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/SystemChannel.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 570da3c5d75f3..e91963c3d7107 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -160,6 +160,7 @@ action("flutter_shell_java") { "io/flutter/embedding/engine/systemchannels/LocalizationChannel.java", "io/flutter/embedding/engine/systemchannels/NavigationChannel.java", "io/flutter/embedding/engine/systemchannels/PlatformChannel.java", + "io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java", "io/flutter/embedding/engine/systemchannels/SettingsChannel.java", "io/flutter/embedding/engine/systemchannels/SystemChannel.java", "io/flutter/embedding/engine/systemchannels/TextInputChannel.java", diff --git a/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java b/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java index 072e8ccf8a163..d146db360f965 100644 --- a/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java +++ b/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java @@ -80,7 +80,7 @@ public Registrar registrarFor(String pluginKey) { public void attach(FlutterView flutterView, Activity activity) { mFlutterView = flutterView; mActivity = activity; - mPlatformViewsController.attach(activity, flutterView, flutterView); + mPlatformViewsController.attach(activity, flutterView, flutterView.getDartExecutor()); } public void detach() { diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java new file mode 100644 index 0000000000000..bccb2fcf9d1df --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java @@ -0,0 +1,437 @@ +// 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 java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; + +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; + +/** + * System channel that sends 2-way communication between Flutter and Android to + * facilitate embedding of Android Views within a Flutter application. + * + * Register a {@link PlatformViewsHandler} to implement the Android side of this channel. + */ +public class PlatformViewsChannel { + private final MethodChannel channel; + private PlatformViewsHandler handler; + + private final MethodChannel.MethodCallHandler parsingHandler = new MethodChannel.MethodCallHandler() { + @Override + public void onMethodCall(MethodCall call, MethodChannel.Result result) { + // If there is no handler to respond to this message then we don't need to + // parse it. Return. + if (handler == null) { + return; + } + + switch (call.method) { + case "create": + create(call, result); + break; + case "dispose": + dispose(call, result); + break; + case "resize": + resize(call, result); + break; + case "touch": + touch(call, result); + break; + case "setDirection": + setDirection(call, result); + break; + } + result.notImplemented(); + } + + private void create(MethodCall call, MethodChannel.Result result) { + Map createArgs = call.arguments(); + PlatformViewCreationRequest request = new PlatformViewCreationRequest( + (int) createArgs.get("id"), + (String) createArgs.get("viewType"), + (double) createArgs.get("width"), + (double) createArgs.get("height"), + (int) createArgs.get("direction"), + createArgs.containsKey("params") + ? ByteBuffer.wrap((byte[]) createArgs.get("params")) + : null + ); + + try { + long textureId = handler.createPlatformView(request); + result.success(textureId); + } catch (IllegalStateException exception) { + result.error( + "error", + exception.getMessage(), + null + ); + } + } + + private void dispose(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + int viewId = call.arguments(); + try { + handler.disposePlatformView(viewId); + result.success(null); + } catch (IllegalStateException exception) { + result.error( + "error", + exception.getMessage(), + null + ); + } + } + + private void resize(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + Map resizeArgs = call.arguments(); + PlatformViewResizeRequest resizeRequest = new PlatformViewResizeRequest( + (int) resizeArgs.get("id"), + (double) resizeArgs.get("width"), + (double) resizeArgs.get("height") + ); + try { + handler.resizePlatformView( + resizeRequest, + new Runnable() { + @Override + public void run() { + result.success(null); + } + } + ); + } catch (IllegalStateException exception) { + result.error( + "error", + exception.getMessage(), + null + ); + } + } + + private void touch(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + List args = call.arguments(); + PlatformViewTouch touch = new PlatformViewTouch( + (int) args.get(0), + (Number) args.get(1), + (Number) args.get(2), + (int) args.get(3), + (int) args.get(4), + args.get(5), + args.get(6), + (int) args.get(7), + (int) args.get(8), + (float) (double) args.get(9), + (float) (double) args.get(10), + (int) args.get(11), + (int) args.get(12), + (int) args.get(13), + (int) args.get(14) + ); + + try { + handler.onTouch(touch); + result.success(null); + } catch (IllegalStateException exception) { + result.error( + "error", + exception.getMessage(), + null + ); + } + } + + private void setDirection(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + Map setDirectionArgs = call.arguments(); + int newDirectionViewId = (int) setDirectionArgs.get("id"); + int direction = (int) setDirectionArgs.get("direction"); + + try { + handler.setDirection( + newDirectionViewId, + direction + ); + result.success(null); + } catch (IllegalStateException exception) { + result.error( + "error", + exception.getMessage(), + null + ); + } + } + }; + + /** + * Constructs a {@code PlatformViewsChannel} that connects Android to the Dart code + * running in {@code dartExecutor}. + * + * The given {@code dartExecutor} is permitted to be idle or executing code. + * + * See {@link DartExecutor}. + */ + public PlatformViewsChannel(@NonNull DartExecutor dartExecutor) { + channel = new MethodChannel(dartExecutor, "flutter/platform_views", StandardMethodCodec.INSTANCE); + channel.setMethodCallHandler(parsingHandler); + } + + /** + * Sets the {@link PlatformViewsHandler} which receives all events and requests + * that are parsed from the underlying platform views channel. + */ + public void setPlatformViewsHandler(@Nullable PlatformViewsHandler handler) { + this.handler = handler; + } + + /** + * Handler that receives platform view messages sent from Flutter to Android + * through a given {@link PlatformViewsChannel}. + * + * To register a {@code PlatformViewsHandler} with a {@link PlatformViewsChannel}, + * see {@link PlatformViewsChannel#setPlatformViewsHandler(PlatformViewsHandler)}. + */ + public interface PlatformViewsHandler { + /** + * The Flutter application would like to display a new Android {@code View}, i.e., + * platform view. + * + * The handler should instantiate the desired Android {@code View}, create a new + * {@link io.flutter.view.FlutterView.SurfaceTextureRegistryEntry} within the + * given Flutter execution context, and then return the new texture's ID. + */ + // TODO(mattcarroll): Introduce an annotation for @TextureId + long createPlatformView(@NonNull PlatformViewCreationRequest request); + + /** + * The Flutter application could like dispose of an existing Android {@code View}, + * i.e., platform view. + */ + void disposePlatformView(int viewId); + + /** + * The Flutter application would like to resize an existing Android {@code View}, + * i.e., platform view. + */ + void resizePlatformView( + @NonNull PlatformViewResizeRequest request, + @NonNull Runnable onComplete); + + /** + * The user touched a platform view within Flutter. + * + * Touch data is reported in {@code touch}. + */ + void onTouch(@NonNull PlatformViewTouch touch); + + /** + * The Flutter application would like to change the layout direction of + * an existing Android {@code View}, i.e., platform view. + */ + // TODO(mattcarroll): Introduce an annotation for @TextureId + void setDirection(int viewId, int direction); + } + + /** + * Request sent from Flutter to create a new platform view. + */ + public static class PlatformViewCreationRequest { + /** + * The ID of the platform view as seen by the Flutter side. + */ + public final int viewId; + + /** + * The type of Android {@code View} to create for this platform view. + */ + @NonNull + public final String viewType; + + /** + * The density independent width to display the platform view. + */ + public final double logicalWidth; + + /** + * The density independent height to display the platform view. + */ + public final double logicalHeight; + + /** + * The layout direction of the new platform view. + * + * See {@link android.view.View.LAYOUT_DIRECTION_LTR} and + * {@link android.view.View.LAYOUT_DIRECTION_RTL} + */ + public final int direction; + + /** + * Custom parameters that are unique to the desired platform view. + */ + @Nullable + public final ByteBuffer params; + + public PlatformViewCreationRequest( + int viewId, + @NonNull String viewType, + double logicalWidth, + double logicalHeight, + int direction, + @Nullable ByteBuffer params + ) { + this.viewId = viewId; + this.viewType = viewType; + this.logicalWidth = logicalWidth; + this.logicalHeight = logicalHeight; + this.direction = direction; + this.params = params; + } + } + + /** + * Request sent from Flutter to resize a platform view. + */ + public static class PlatformViewResizeRequest { + /** + * The ID of the platform view as seen by the Flutter side. + */ + public final int viewId; + + /** + * The new density independent width to display the platform view. + */ + public final double newLogicalWidth; + + /** + * The new density independent height to display the platform view. + */ + public final double newLogicalHeight; + + public PlatformViewResizeRequest( + int viewId, + double newLogicalWidth, + double newLogicalHeight + ) { + this.viewId = viewId; + this.newLogicalWidth = newLogicalWidth; + this.newLogicalHeight = newLogicalHeight; + } + } + + /** + * The state of a touch event in Flutter within a platform view. + */ + public static class PlatformViewTouch { + /** + * The ID of the platform view as seen by the Flutter side. + */ + public final int viewId; + + /** + * The amount of time that the touch has been pressed. + */ + @NonNull + public final Number downTime; + /** + * TODO(mattcarroll): javadoc + */ + @NonNull + public final Number eventTime; + public final int action; + /** + * The number of pointers (e.g, fingers) involved in the touch event. + */ + public final int pointerCount; + /** + * Properties for each pointer, encoded in a raw format. + */ + @NonNull + public final Object rawPointerPropertiesList; + /** + * Coordinates for each pointer, encoded in a raw format. + */ + @NonNull + public final Object rawPointerCoords; + /** + * TODO(mattcarroll): javadoc + */ + public final int metaState; + /** + * TODO(mattcarroll): javadoc + */ + public final int buttonState; + /** + * Coordinate precision along the x-axis. + */ + public final float xPrecision; + /** + * Coordinate precision along the y-axis. + */ + public final float yPrecision; + /** + * TODO(mattcarroll): javadoc + */ + public final int deviceId; + /** + * TODO(mattcarroll): javadoc + */ + public final int edgeFlags; + /** + * TODO(mattcarroll): javadoc + */ + public final int source; + /** + * TODO(mattcarroll): javadoc + */ + public final int flags; + + PlatformViewTouch( + int viewId, + @NonNull Number downTime, + @NonNull Number eventTime, + int action, + int pointerCount, + @NonNull Object rawPointerPropertiesList, + @NonNull Object rawPointerCoords, + int metaState, + int buttonState, + float xPrecision, + float yPrecision, + int deviceId, + int edgeFlags, + int source, + int flags + ) { + this.viewId = viewId; + this.downTime = downTime; + this.eventTime = eventTime; + this.action = action; + this.pointerCount = pointerCount; + this.rawPointerPropertiesList = rawPointerPropertiesList; + this.rawPointerCoords = rawPointerCoords; + this.metaState = metaState; + this.buttonState = buttonState; + this.xPrecision = xPrecision; + this.yPrecision = yPrecision; + this.deviceId = deviceId; + this.edgeFlags = edgeFlags; + this.source = source; + this.flags = flags; + } + } + + /** + * The provided platform view ID does not correspond to any existing platform view. + */ + public static class NoSuchPlatformViewException extends IllegalStateException {} +} diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java index 9c3da20e905a3..2e2b621c7bf88 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java @@ -12,20 +12,24 @@ import android.os.Build; import android.support.annotation.UiThread; import android.util.DisplayMetrics; +import android.support.annotation.NonNull; import android.util.Log; import android.view.MotionEvent; import android.view.View; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.StandardMethodCodec; import io.flutter.view.AccessibilityBridge; import io.flutter.view.TextureRegistry; + import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; /** * Manages platform views. @@ -33,11 +37,9 @@ * Each {@link io.flutter.app.FlutterPluginRegistry} has a single platform views controller. * A platform views controller can be attached to at most one Flutter view. */ -public class PlatformViewsController implements MethodChannel.MethodCallHandler, PlatformViewsAccessibilityDelegate { +public class PlatformViewsController implements PlatformViewsAccessibilityDelegate { private static final String TAG = "PlatformViewsController"; - private static final String CHANNEL_NAME = "flutter/platform_views"; - // API level 20 is required for VirtualDisplay#setSurface which we use when resizing a platform view. private static final int MINIMAL_SDK = Build.VERSION_CODES.KITKAT_WATCH; @@ -49,14 +51,172 @@ public class PlatformViewsController implements MethodChannel.MethodCallHandler, // The texture registry maintaining the textures into which the embedded views will be rendered. private TextureRegistry textureRegistry; - // The messenger used to communicate with the framework over the platform views channel. - private BinaryMessenger messenger; + // The system channel used to communicate with the framework about platform views. + private PlatformViewsChannel platformViewsChannel; // The accessibility bridge to which accessibility events form the platform views will be dispatched. private final AccessibilityEventsDelegate accessibilityEventsDelegate; private final HashMap vdControllers; + private final PlatformViewsChannel.PlatformViewsHandler channelHandler = new PlatformViewsChannel.PlatformViewsHandler() { + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + @Override + public long createPlatformView(@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) { + ensureValidAndroidVersion(); + + if (!validateDirection(request.direction)) { + throw new IllegalStateException("Trying to create a view with unknown direction value: " + + request.direction + "(view id: " + request.viewId + ")"); + } + + if (vdControllers.containsKey(request.viewId)) { + throw new IllegalStateException("Trying to create an already created platform view, view id: " + + request.viewId); + } + + PlatformViewFactory viewFactory = registry.getFactory(request.viewType); + if (viewFactory == null) { + throw new IllegalStateException("Trying to create a platform view of unregistered type: " + + request.viewType); + } + + Object createParams = null; + if (request.params != null) { + createParams = viewFactory.getCreateArgsCodec().decodeMessage(request.params); + } + + int physicalWidth = toPhysicalPixels(request.logicalWidth); + int physicalHeight = toPhysicalPixels(request.logicalHeight); + validateVirtualDisplayDimensions(physicalWidth, physicalHeight); + + TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture(); + VirtualDisplayController vdController = VirtualDisplayController.create( + context, + accessibilityEventsDelegate, + viewFactory, + textureEntry, + toPhysicalPixels(request.logicalWidth), + toPhysicalPixels(request.logicalHeight), + request.viewId, + createParams + ); + + if (vdController == null) { + throw new IllegalStateException("Failed creating virtual display for a " + + request.viewType + " with id: " + request.viewId); + } + + vdControllers.put(request.viewId, vdController); + vdController.getView().setLayoutDirection(request.direction); + + // TODO(amirh): copy accessibility nodes to the FlutterView's accessibility tree. + + return textureEntry.id(); + } + + @Override + public void disposePlatformView(int viewId) { + ensureValidAndroidVersion(); + + VirtualDisplayController vdController = vdControllers.get(viewId); + if (vdController == null) { + throw new IllegalStateException("Trying to dispose a platform view with unknown id: " + + viewId); + } + + vdController.dispose(); + vdControllers.remove(viewId); + } + + @Override + public void resizePlatformView(@NonNull PlatformViewsChannel.PlatformViewResizeRequest request, @NonNull Runnable onComplete) { + ensureValidAndroidVersion(); + + VirtualDisplayController vdController = vdControllers.get(request.viewId); + if (vdController == null) { + throw new IllegalStateException("Trying to resize a platform view with unknown id: " + + request.viewId); + } + + int physicalWidth = toPhysicalPixels(request.newLogicalWidth); + int physicalHeight = toPhysicalPixels(request.newLogicalHeight); + validateVirtualDisplayDimensions(physicalWidth, physicalHeight); + + vdController.resize( + physicalWidth, + physicalHeight, + onComplete + ); + } + + @Override + public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) { + ensureValidAndroidVersion(); + + float density = context.getResources().getDisplayMetrics().density; + PointerProperties[] pointerProperties = + parsePointerPropertiesList(touch.rawPointerPropertiesList) + .toArray(new PointerProperties[touch.pointerCount]); + PointerCoords[] pointerCoords = + parsePointerCoordsList(touch.rawPointerCoords, density) + .toArray(new PointerCoords[touch.pointerCount]); + + View view = vdControllers.get(touch.viewId).getView(); + if (view == null) { + throw new IllegalStateException("Sending touch to an unknown view with id: " + + touch.viewId); + } + + MotionEvent event = MotionEvent.obtain( + touch.downTime.longValue(), + touch.eventTime.longValue(), + touch.action, + touch.pointerCount, + pointerProperties, + pointerCoords, + touch.metaState, + touch.buttonState, + touch.xPrecision, + touch.yPrecision, + touch.deviceId, + touch.edgeFlags, + touch.source, + touch.flags + ); + + view.dispatchTouchEvent(event); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + @Override + public void setDirection(int viewId, int direction) { + ensureValidAndroidVersion(); + + if (!validateDirection(direction)) { + throw new IllegalStateException("Trying to set unknown direction value: " + direction + + "(view id: " + viewId + ")"); + } + + View view = vdControllers.get(viewId).getView(); + if (view == null) { + throw new IllegalStateException("Sending touch to an unknown view with id: " + + direction); + } + + view.setLayoutDirection(direction); + } + + private void ensureValidAndroidVersion() { + if (Build.VERSION.SDK_INT < MINIMAL_SDK) { + Log.e(TAG, "Trying to use platform views with API " + Build.VERSION.SDK_INT + + ", required API level is: " + MINIMAL_SDK); + throw new IllegalStateException("An attempt was made to use platform views on a" + + " version of Android that platform views does not support."); + } + } + }; + public PlatformViewsController() { registry = new PlatformViewRegistryImpl(); vdControllers = new HashMap<>(); @@ -70,9 +230,9 @@ public PlatformViewsController() { * This should be the context of the Activity hosting the Flutter application. * @param textureRegistry The texture registry which provides the output textures into which the embedded views * will be rendered. - * @param messenger The Flutter application on the other side of this messenger drives this platform views controller. + * @param dartExecutor The dart execution context, which is used to setup a system channel. */ - public void attach(Context context, TextureRegistry textureRegistry, BinaryMessenger messenger) { + public void attach(Context context, TextureRegistry textureRegistry, @NonNull DartExecutor dartExecutor) { if (this.context != null) { throw new AssertionError( "A PlatformViewsController can only be attached to a single output target.\n" + @@ -81,9 +241,8 @@ public void attach(Context context, TextureRegistry textureRegistry, BinaryMesse } this.context = context; this.textureRegistry = textureRegistry; - this.messenger = messenger; - MethodChannel channel = new MethodChannel(messenger, CHANNEL_NAME, StandardMethodCodec.INSTANCE); - channel.setMethodCallHandler(this); + platformViewsChannel = new PlatformViewsChannel(dartExecutor); + platformViewsChannel.setPlatformViewsHandler(channelHandler); } /** @@ -95,8 +254,8 @@ public void attach(Context context, TextureRegistry textureRegistry, BinaryMesse */ @UiThread public void detach() { - messenger.setMessageHandler(CHANNEL_NAME, null); - messenger = null; + platformViewsChannel.setPlatformViewsHandler(null); + platformViewsChannel = null; context = null; textureRegistry = null; } @@ -132,242 +291,6 @@ public View getPlatformViewById(Integer id) { return controller.getView(); } - @Override - public void onMethodCall(final MethodCall call, final MethodChannel.Result result) { - if (Build.VERSION.SDK_INT < MINIMAL_SDK) { - Log.e(TAG, "Trying to use platform views with API " + Build.VERSION.SDK_INT - + ", required API level is: " + MINIMAL_SDK); - return; - } - switch (call.method) { - case "create": - createPlatformView(call, result); - return; - case "dispose": - disposePlatformView(call, result); - return; - case "resize": - resizePlatformView(call, result); - return; - case "touch": - onTouch(call, result); - return; - case "setDirection": - setDirection(call, result); - return; - } - result.notImplemented(); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - private void createPlatformView(MethodCall call, MethodChannel.Result result) { - Map args = call.arguments(); - int id = (int) args.get("id"); - String viewType = (String) args.get("viewType"); - double logicalWidth = (double) args.get("width"); - double logicalHeight = (double) args.get("height"); - int direction = (int) args.get("direction"); - - if (!validateDirection(direction)) { - result.error( - "error", - "Trying to create a view with unknown direction value: " + direction + "(view id: " + id + ")", - null - ); - return; - } - - if (vdControllers.containsKey(id)) { - result.error( - "error", - "Trying to create an already created platform view, view id: " + id, - null - ); - return; - } - - PlatformViewFactory viewFactory = registry.getFactory(viewType); - if (viewFactory == null) { - result.error( - "error", - "Trying to create a platform view of unregistered type: " + viewType, - null - ); - return; - } - - Object createParams = null; - if (args.containsKey("params")) { - createParams = viewFactory.getCreateArgsCodec().decodeMessage(ByteBuffer.wrap((byte[]) args.get("params"))); - } - - int physicalWidth = toPhysicalPixels(logicalWidth); - int physicalHeight = toPhysicalPixels(logicalHeight); - validateVirtualDisplayDimensions(physicalWidth, physicalHeight); - - TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture(); - VirtualDisplayController vdController = VirtualDisplayController.create( - context, - accessibilityEventsDelegate, - viewFactory, - textureEntry, - physicalWidth, - physicalHeight, - id, - createParams - ); - - if (vdController == null) { - result.error( - "error", - "Failed creating virtual display for a " + viewType + " with id: " + id, - null - ); - return; - } - - vdControllers.put(id, vdController); - vdController.getView().setLayoutDirection(direction); - - // TODO(amirh): copy accessibility nodes to the FlutterView's accessibility tree. - - result.success(textureEntry.id()); - } - - private void disposePlatformView(MethodCall call, MethodChannel.Result result) { - int id = call.arguments(); - - VirtualDisplayController vdController = vdControllers.get(id); - if (vdController == null) { - result.error( - "error", - "Trying to dispose a platform view with unknown id: " + id, - null - ); - return; - } - - vdController.dispose(); - vdControllers.remove(id); - result.success(null); - } - - private void resizePlatformView(MethodCall call, final MethodChannel.Result result) { - Map args = call.arguments(); - int id = (int) args.get("id"); - double width = (double) args.get("width"); - double height = (double) args.get("height"); - - VirtualDisplayController vdController = vdControllers.get(id); - if (vdController == null) { - result.error( - "error", - "Trying to resize a platform view with unknown id: " + id, - null - ); - return; - } - - int physicalWidth = toPhysicalPixels(width); - int physicalHeight = toPhysicalPixels(height); - validateVirtualDisplayDimensions(physicalWidth, physicalHeight); - - vdController.resize( - physicalWidth, - physicalHeight, - new Runnable() { - @Override - public void run() { - result.success(null); - } - } - ); - } - - private void onTouch(MethodCall call, MethodChannel.Result result) { - List args = call.arguments(); - - float density = context.getResources().getDisplayMetrics().density; - - int id = (int) args.get(0); - Number downTime = (Number) args.get(1); - Number eventTime = (Number) args.get(2); - int action = (int) args.get(3); - int pointerCount = (int) args.get(4); - PointerProperties[] pointerProperties = - parsePointerPropertiesList(args.get(5)).toArray(new PointerProperties[pointerCount]); - PointerCoords[] pointerCoords = - parsePointerCoordsList(args.get(6), density).toArray(new PointerCoords[pointerCount]); - - int metaState = (int) args.get(7); - int buttonState = (int) args.get(8); - float xPrecision = (float) (double) args.get(9); - float yPrecision = (float) (double) args.get(10); - int deviceId = (int) args.get(11); - int edgeFlags = (int) args.get(12); - int source = (int) args.get(13); - int flags = (int) args.get(14); - - View view = vdControllers.get(id).getView(); - if (view == null) { - result.error( - "error", - "Sending touch to an unknown view with id: " + id, - null - ); - return; - } - - MotionEvent event = MotionEvent.obtain( - downTime.longValue(), - eventTime.longValue(), - action, - pointerCount, - pointerProperties, - pointerCoords, - metaState, - buttonState, - xPrecision, - yPrecision, - deviceId, - edgeFlags, - source, - flags - ); - - view.dispatchTouchEvent(event); - result.success(null); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - private void setDirection(MethodCall call, MethodChannel.Result result) { - Map args = call.arguments(); - int id = (int) args.get("id"); - int direction = (int) args.get("direction"); - - if (!validateDirection(direction)) { - result.error( - "error", - "Trying to set unknown direction value: " + direction + "(view id: " + id + ")", - null - ); - return; - } - - View view = vdControllers.get(id).getView(); - if (view == null) { - result.error( - "error", - "Sending touch to an unknown view with id: " + id, - null - ); - return; - } - - view.setLayoutDirection(direction); - result.success(null); - } - private static boolean validateDirection(int direction) { return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL; } diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 5603695cb281b..1893a22e717e7 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -15,6 +15,8 @@ import android.graphics.SurfaceTexture; import android.os.Build; import android.os.Handler; +import android.provider.Settings; +import android.support.annotation.NonNull; import android.os.LocaleList; import android.support.annotation.RequiresApi; import android.support.annotation.UiThread; @@ -197,7 +199,7 @@ public void surfaceDestroyed(SurfaceHolder holder) { sendLocalesToDart(getResources().getConfiguration()); sendUserPlatformSettingsToDart(); } - + private static Activity getActivity(Context context) { if (context == null) { return null; @@ -212,6 +214,11 @@ private static Activity getActivity(Context context) { return null; } + @NonNull + public DartExecutor getDartExecutor() { + return dartExecutor; + } + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (!isAttached()) {