diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index e02a6409acf08..827e54166a9b9 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -1481,8 +1481,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platfor
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewWrapper.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
-FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java
-FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java
FILE: ../../../flutter/shell/platform/android/io/flutter/util/PathUtils.java
FILE: ../../../flutter/shell/platform/android/io/flutter/util/Preconditions.java
FILE: ../../../flutter/shell/platform/android/io/flutter/util/Predicate.java
diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn
index 84827f4610e77..7444efa71a0eb 100644
--- a/shell/platform/android/BUILD.gn
+++ b/shell/platform/android/BUILD.gn
@@ -286,8 +286,6 @@ android_java_sources = [
"io/flutter/plugin/platform/PlatformViewWrapper.java",
"io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java",
"io/flutter/plugin/platform/PlatformViewsController.java",
- "io/flutter/plugin/platform/SingleViewPresentation.java",
- "io/flutter/plugin/platform/VirtualDisplayController.java",
"io/flutter/util/PathUtils.java",
"io/flutter/util/Preconditions.java",
"io/flutter/util/Predicate.java",
diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java
index f63e899b4e8c9..1e2eac8e61db1 100644
--- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java
+++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java
@@ -873,21 +873,6 @@ public InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs) {
return textInputPlugin.createInputConnection(this, keyboardManager, outAttrs);
}
- /**
- * Allows a {@code View} that is not currently the input connection target to invoke commands on
- * the {@link android.view.inputmethod.InputMethodManager}, which is otherwise disallowed.
- *
- *
Returns true to allow non-input-connection-targets to invoke methods on {@code
- * InputMethodManager}, or false to exclusively allow the input connection target to invoke such
- * methods.
- */
- @Override
- public boolean checkInputConnectionProxy(View view) {
- return flutterEngine != null
- ? flutterEngine.getPlatformViewsController().checkInputConnectionProxy(view)
- : super.checkInputConnectionProxy(view);
- }
-
/**
* Invoked when a hardware key is pressed or released.
*
diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java
index d338b7cfcbce1..4b50d01e856d9 100644
--- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java
+++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java
@@ -147,18 +147,15 @@ private void resize(@NonNull MethodCall call, @NonNull MethodChannel.Result resu
(double) resizeArgs.get("width"),
(double) resizeArgs.get("height"));
try {
- handler.resize(
- resizeRequest,
- (PlatformViewBufferSize bufferSize) -> {
- if (bufferSize == null) {
- result.error("error", "Failed to resize the platform view", null);
- } else {
- final Map response = new HashMap<>();
- response.put("width", (double) bufferSize.width);
- response.put("height", (double) bufferSize.height);
- result.success(response);
- }
- });
+ final PlatformViewBufferSize sz = handler.resize(resizeRequest);
+ if (sz == null) {
+ result.error("error", "Failed to resize the platform view", null);
+ } else {
+ final Map response = new HashMap<>();
+ response.put("width", (double) sz.width);
+ response.put("height", (double) sz.height);
+ result.success(response);
+ }
} catch (IllegalStateException exception) {
result.error("error", detailedExceptionString(exception), null);
}
@@ -301,11 +298,9 @@ public interface PlatformViewsHandler {
* The Flutter application would like to resize an existing Android {@code View}.
*
* @param request The request to resize the platform view.
- * @param onComplete Once the resize is completed, this is the handler to notify the size of the
- * platform view buffer.
+ * @return The buffer size where the platform view pixels are written to.
*/
- void resize(
- @NonNull PlatformViewResizeRequest request, @NonNull PlatformViewBufferResized onComplete);
+ PlatformViewBufferSize resize(@NonNull PlatformViewResizeRequest request);
/**
* The Flutter application would like to change the offset of an existing Android {@code View}.
@@ -423,11 +418,6 @@ public PlatformViewBufferSize(int width, int height) {
}
}
- /** Allows to notify when a platform view buffer has been resized. */
- public interface PlatformViewBufferResized {
- void run(@Nullable PlatformViewBufferSize bufferSize);
- }
-
/** 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. */
diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java
index 094786f6d825e..a48e073dc5f60 100644
--- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java
+++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java
@@ -89,9 +89,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
try {
final JSONObject arguments = (JSONObject) args;
final int platformViewId = arguments.getInt("platformViewId");
- final boolean usesVirtualDisplay =
- arguments.optBoolean("usesVirtualDisplay", false);
- textInputMethodHandler.setPlatformViewClient(platformViewId, usesVirtualDisplay);
+ textInputMethodHandler.setPlatformViewClient(platformViewId);
result.success(null);
} catch (JSONException exception) {
result.error("error", exception.getMessage(), null);
@@ -403,10 +401,8 @@ public interface TextInputMethodHandler {
* different client is set.
*
* @param id the ID of the platform view to be set as a text input client.
- * @param usesVirtualDisplay True if the platform view uses a virtual display, false if it uses
- * hybrid composition.
*/
- void setPlatformViewClient(int id, boolean usesVirtualDisplay);
+ void setPlatformViewClient(int id);
/**
* Sets the size and the transform matrix of the current text input client.
diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java
index 7b1ca47ffa0e8..c35412eb2b9e5 100644
--- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java
+++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java
@@ -54,12 +54,6 @@ public class TextInputPlugin implements ListenableEditingState.EditingStateWatch
// Initialize the "last seen" text editing values to a non-null value.
private TextEditState mLastKnownFrameworkTextEditingState;
- // When true following calls to createInputConnection will return the cached lastInputConnection
- // if the input
- // target is a platform view. See the comments on lockPlatformViewInputConnection for more
- // details.
- private boolean isInputConnectionLocked;
-
@SuppressLint("NewApi")
public TextInputPlugin(
@NonNull View view,
@@ -105,7 +99,7 @@ public void show() {
@Override
public void hide() {
- if (inputTarget.type == InputTarget.Type.PHYSICAL_DISPLAY_PLATFORM_VIEW) {
+ if (inputTarget.type == InputTarget.Type.PLATFORM_VIEW) {
notifyViewExited();
} else {
hideTextInput(mView);
@@ -136,8 +130,8 @@ public void setClient(
}
@Override
- public void setPlatformViewClient(int platformViewId, boolean usesVirtualDisplay) {
- setPlatformViewTextInputClient(platformViewId, usesVirtualDisplay);
+ public void setPlatformViewClient(int platformViewId) {
+ setPlatformViewTextInputClient(platformViewId);
}
@Override
@@ -182,36 +176,6 @@ ImeSyncDeferringInsetsCallback getImeSyncCallback() {
return imeSyncCallback;
}
- /**
- * Use the current platform view input connection until unlockPlatformViewInputConnection is
- * called.
- *
- * The current input connection instance is cached and any following call to @{link
- * createInputConnection} returns the cached connection until unlockPlatformViewInputConnection is
- * called.
- *
- *
This is a no-op if the current input target isn't a platform view.
- *
- *
This is used to preserve an input connection when moving a platform view from one virtual
- * display to another.
- */
- public void lockPlatformViewInputConnection() {
- if (inputTarget.type == InputTarget.Type.VIRTUAL_DISPLAY_PLATFORM_VIEW) {
- isInputConnectionLocked = true;
- }
- }
-
- /**
- * Unlocks the input connection.
- *
- *
See also: @{link lockPlatformViewInputConnection}.
- */
- public void unlockPlatformViewInputConnection() {
- if (inputTarget.type == InputTarget.Type.VIRTUAL_DISPLAY_PLATFORM_VIEW) {
- isInputConnectionLocked = false;
- }
- }
-
/**
* Detaches the text input plugin from the platform views controller.
*
@@ -295,21 +259,10 @@ public InputConnection createInputConnection(
return null;
}
- if (inputTarget.type == InputTarget.Type.PHYSICAL_DISPLAY_PLATFORM_VIEW) {
+ if (inputTarget.type == InputTarget.Type.PLATFORM_VIEW) {
return null;
}
- if (inputTarget.type == InputTarget.Type.VIRTUAL_DISPLAY_PLATFORM_VIEW) {
- if (isInputConnectionLocked) {
- return lastInputConnection;
- }
- lastInputConnection =
- platformViewsController
- .getPlatformViewById(inputTarget.id)
- .onCreateInputConnection(outAttrs);
- return lastInputConnection;
- }
-
outAttrs.inputType =
inputTypeFromTextInputType(
configuration.inputType,
@@ -364,9 +317,7 @@ public InputConnection getLastInputConnection() {
* input connection.
*/
public void clearPlatformViewClient(int platformViewId) {
- if ((inputTarget.type == InputTarget.Type.VIRTUAL_DISPLAY_PLATFORM_VIEW
- || inputTarget.type == InputTarget.Type.PHYSICAL_DISPLAY_PLATFORM_VIEW)
- && inputTarget.id == platformViewId) {
+ if (inputTarget.type == InputTarget.Type.PLATFORM_VIEW && inputTarget.id == platformViewId) {
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
notifyViewExited();
mImm.hideSoftInputFromWindow(mView.getApplicationWindowToken(), 0);
@@ -427,26 +378,13 @@ void setTextInputClient(int client, TextInputChannel.Configuration configuration
// setTextInputClient will be followed by a call to setTextInputEditingState.
// Do a restartInput at that time.
mRestartInputPending = true;
- unlockPlatformViewInputConnection();
lastClientRect = null;
mEditable.addEditingStateListener(this);
}
- private void setPlatformViewTextInputClient(int platformViewId, boolean usesVirtualDisplay) {
- if (usesVirtualDisplay) {
- // We need to make sure that the Flutter view is focused so that no imm operations get short
- // circuited.
- // Not asking for focus here specifically manifested in a bug on API 28 devices where the
- // platform view's request to show a keyboard was ignored.
- mView.requestFocus();
- inputTarget = new InputTarget(InputTarget.Type.VIRTUAL_DISPLAY_PLATFORM_VIEW, platformViewId);
- mImm.restartInput(mView);
- mRestartInputPending = false;
- } else {
- inputTarget =
- new InputTarget(InputTarget.Type.PHYSICAL_DISPLAY_PLATFORM_VIEW, platformViewId);
- lastInputConnection = null;
- }
+ private void setPlatformViewTextInputClient(int platformViewId) {
+ inputTarget = new InputTarget(InputTarget.Type.PLATFORM_VIEW, platformViewId);
+ lastInputConnection = null;
}
private static boolean composingChanged(
@@ -537,29 +475,11 @@ public void inspect(double x, double y) {
@VisibleForTesting
void clearTextInputClient() {
- if (inputTarget.type == InputTarget.Type.VIRTUAL_DISPLAY_PLATFORM_VIEW) {
- // This only applies to platform views that use a virtual display.
- // Focus changes in the framework tree have no guarantees on the order focus nodes are
- // notified. A node that lost focus may be notified before or after a node that gained focus.
- // When moving the focus from a Flutter text field to an AndroidView, it is possible that the
- // Flutter text field's focus node will be notified that it lost focus after the AndroidView
- // was notified that it gained focus. When this happens the text field will send a
- // clearTextInput command which we ignore.
- // By doing this we prevent the framework from clearing a platform view input client (the only
- // way to do so is to set a new framework text client). I don't see an obvious use case for
- // "clearing" a platform view's text input client, and it may be error prone as we don't know
- // how the platform view manages the input connection and we probably shouldn't interfere.
- // If we ever want to allow the framework to clear a platform view text client we should
- // probably consider changing the focus manager such that focus nodes that lost focus are
- // notified before focus nodes that gained focus as part of the same focus event.
- return;
- }
mEditable.removeEditingStateListener(this);
notifyViewExited();
configuration = null;
updateAutofillConfigurationIfNeeded(null);
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
- unlockPlatformViewInputConnection();
lastClientRect = null;
}
@@ -569,12 +489,9 @@ enum Type {
// InputConnection is managed by the TextInputPlugin, and events are forwarded to the Flutter
// framework.
FRAMEWORK_CLIENT,
- // InputConnection is managed by a platform view that is presented on a virtual display.
- VIRTUAL_DISPLAY_PLATFORM_VIEW,
- // InputConnection is managed by a platform view that is embedded in the activity's view
- // hierarchy. This view hierarchy is displayed in a physical display within the aplication
- // display area.
- PHYSICAL_DISPLAY_PLATFORM_VIEW,
+ // InputConnection is managed by a platform view that is embeded in the Android view
+ // hierarchy.
+ PLATFORM_VIEW,
}
public InputTarget(@NonNull Type type, int id) {
diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformView.java b/shell/platform/android/io/flutter/plugin/platform/PlatformView.java
index d7b3cf52aba91..2c563ccac937b 100644
--- a/shell/platform/android/io/flutter/plugin/platform/PlatformView.java
+++ b/shell/platform/android/io/flutter/plugin/platform/PlatformView.java
@@ -66,8 +66,11 @@ default void onFlutterViewDetached() {}
*
*
This hook only exists for rare cases where the plugin relies on the state of the input
* connection. This probably doesn't need to be implemented.
+ *
+ *
This method is deprecated, and will be removed in a future release.
*/
@SuppressLint("NewApi")
+ @Deprecated
default void onInputConnectionLocked() {}
/**
@@ -75,7 +78,10 @@ default void onInputConnectionLocked() {}
*
*
This hook only exists for rare cases where the plugin relies on the state of the input
* connection. This probably doesn't need to be implemented.
+ *
+ *
This method is deprecated, and will be removed in a future release.
*/
@SuppressLint("NewApi")
+ @Deprecated
default void onInputConnectionUnlocked() {}
}
diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewFactory.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewFactory.java
index e21ee3897f555..936f9fabeca5b 100644
--- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewFactory.java
+++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewFactory.java
@@ -28,7 +28,7 @@ public PlatformViewFactory(@Nullable MessageCodec createArgsCodec) {
* null, or no arguments were sent from the Flutter app.
*/
@NonNull
- public abstract PlatformView create(Context context, int viewId, @Nullable Object args);
+ public abstract PlatformView create(@Nullable Context context, int viewId, @Nullable Object args);
/** Returns the codec to be used for decoding the args parameter of {@link #create}. */
@Nullable
diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java
index f1f91ddaa3055..968dda33f1ee8 100644
--- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java
+++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java
@@ -18,9 +18,6 @@ public interface PlatformViewsAccessibilityDelegate {
@Nullable
View getPlatformViewById(int viewId);
- /** Returns true if the platform view uses virtual displays. */
- boolean usesVirtualDisplay(int id);
-
/**
* Attaches an accessibility bridge for this platform views accessibility delegate.
*
diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
index 4f78a732d1fe1..8008da1a77b28 100644
--- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
+++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
@@ -9,11 +9,9 @@
import android.annotation.TargetApi;
import android.content.Context;
-import android.content.MutableContextWrapper;
import android.os.Build;
import android.util.SparseArray;
import android.view.MotionEvent;
-import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -32,11 +30,9 @@
import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel;
import io.flutter.plugin.editing.TextInputPlugin;
-import io.flutter.util.ViewUtils;
import io.flutter.view.AccessibilityBridge;
import io.flutter.view.TextureRegistry;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -50,19 +46,6 @@
public class PlatformViewsController implements PlatformViewsAccessibilityDelegate {
private static final String TAG = "PlatformViewsController";
- // These view types allow out-of-band drawing commands that don't notify the Android view
- // hierarchy.
- // To support these cases, Flutter hosts the embedded view in a VirtualDisplay,
- // and binds the VirtualDisplay to a GL texture that is then composed by the engine.
- // However, there are a few issues with Virtual Displays. For example, they don't fully support
- // accessibility due to https://github.com/flutter/flutter/issues/29717,
- // and keyboard interactions may have non-deterministic behavior.
- // Views that issue out-of-band drawing commands that aren't included in this array are
- // required to call `View#invalidate()` to notify Flutter about the update.
- // This isn't ideal, but given all the other limitations it's a reasonable tradeoff.
- // Related issue: https://github.com/flutter/flutter/issues/103630
- private static Class[] VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY = {SurfaceView.class};
-
private final PlatformViewRegistryImpl registry;
private AndroidTouchProcessor androidTouchProcessor;
@@ -85,17 +68,6 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
// dispatched.
private final AccessibilityEventsDelegate accessibilityEventsDelegate;
- // TODO(mattcarroll): Refactor overall platform views to facilitate testing and then make
- // this private. This is visible as a hack to facilitate testing. This was deemed the least
- // bad option at the time of writing.
- @VisibleForTesting /* package */ final HashMap vdControllers;
-
- // Maps a virtual display's context to the embedded view hosted in this virtual display.
- // Since each virtual display has it's unique context this allows associating any view with the
- // platform view that
- // it is associated with(e.g if a platform view creates other views in the same virtual display.
- @VisibleForTesting /* package */ final HashMap contextToEmbeddedView;
-
// The platform views.
private final SparseArray platformViews;
@@ -151,22 +123,21 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
new PlatformViewsChannel.PlatformViewsHandler() {
- @TargetApi(19)
+ @TargetApi(Build.VERSION_CODES.KITKAT)
@Override
// TODO(egarciad): Remove the need for this.
// https://github.com/flutter/flutter/issues/96679
public void createForPlatformViewLayer(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
// API level 19 is required for `android.graphics.ImageReader`.
- ensureValidAndroidVersion(19);
+ ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT);
- final int viewId = request.viewId;
if (!validateDirection(request.direction)) {
throw new IllegalStateException(
"Trying to create a view with unknown direction value: "
+ request.direction
+ "(view id: "
- + viewId
+ + request.viewId
+ ")");
}
@@ -181,13 +152,12 @@ public void createForPlatformViewLayer(
createParams = factory.getCreateArgsCodec().decodeMessage(request.params);
}
- final PlatformView platformView = factory.create(context, viewId, createParams);
+ final PlatformView platformView = factory.create(context, request.viewId, createParams);
platformView.getView().setLayoutDirection(request.direction);
- platformViews.put(viewId, platformView);
- Log.i(TAG, "Using hybrid composition for platform view: " + viewId);
+ platformViews.put(request.viewId, platformView);
}
- @TargetApi(20)
+ @TargetApi(Build.VERSION_CODES.M)
@Override
public long createForTextureLayer(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
@@ -224,116 +194,45 @@ public long createForTextureLayer(
createParams = viewFactory.getCreateArgsCodec().decodeMessage(request.params);
}
- // The virtual display controller will change the embedded view context.
- final Context embeddedViewContext = new MutableContextWrapper(context);
- final PlatformView platformView =
- viewFactory.create(embeddedViewContext, viewId, createParams);
+ final PlatformView platformView = viewFactory.create(context, viewId, createParams);
platformViews.put(viewId, platformView);
- final View embeddedView = platformView.getView();
- if (embeddedView == null) {
- throw new IllegalStateException(
- "PlatformView#getView() returned null, but an Android view reference was expected.");
- } else if (embeddedView.getParent() != null) {
- throw new IllegalStateException(
- "The Android view returned from PlatformView#getView() was already added to a parent view.");
- }
-
- embeddedView.setLayoutDirection(request.direction);
-
- final int physicalWidth = toPhysicalPixels(request.logicalWidth);
- final int physicalHeight = toPhysicalPixels(request.logicalHeight);
-
- // Case 1. Add the view to a virtual display if the embedded view contains any of the
- // VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY view types.
- // These views allow out-of-band graphics operations that aren't notified to the Android
- // view hierarchy via callbacks such as ViewParent#onDescendantInvalidated().
- // The virtual display is wired up to a GL texture that is composed by the Flutter engine.
- // Also, use virtual display if the API level is 20, 21 or 22 since the Case 2. requires
- // at least API level 23.
- final boolean shouldUseVirtualDisplay =
- ViewUtils.hasChildViewOfType(embeddedView, VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY)
- || Build.VERSION.SDK_INT < 23;
-
- if (!usesSoftwareRendering && shouldUseVirtualDisplay) {
- Log.i(TAG, "Hosting view in a virtual display for platform view: " + viewId);
- // API level 20 is required to use VirtualDisplay#setSurface.
- ensureValidAndroidVersion(20);
-
- final TextureRegistry.SurfaceTextureEntry textureEntry =
- textureRegistry.createSurfaceTexture();
-
- final VirtualDisplayController vdController =
- VirtualDisplayController.create(
- context,
- accessibilityEventsDelegate,
- platformView,
- textureEntry,
- physicalWidth,
- physicalHeight,
- request.viewId,
- createParams,
- (view, hasFocus) -> {
- if (hasFocus) {
- platformViewsChannel.invokeViewFocused(request.viewId);
- }
- });
-
- if (vdController == null) {
- throw new IllegalStateException(
- "Failed creating virtual display for a "
- + request.viewType
- + " with id: "
- + request.viewId);
- }
-
- // If our FlutterEngine is already attached to a Flutter UI, provide that Android
- // View to this new platform view.
- if (flutterView != null) {
- vdController.onFlutterViewAttached(flutterView);
- }
-
- vdControllers.put(request.viewId, vdController);
- contextToEmbeddedView.put(embeddedView.getContext(), embeddedView);
- return textureEntry.id();
- }
-
- // Case 2. Attach the view to the Android view hierarchy and record their drawing
- // operations, so they can be forwarded to a GL texture that is composed by the
- // Flutter engine.
-
- // API level 23 is required to use Surface#lockHardwareCanvas().
- ensureValidAndroidVersion(23);
- Log.i(TAG, "Hosting view in view hierarchy for platform view: " + viewId);
-
- PlatformViewWrapper viewWrapper;
+ PlatformViewWrapper wrapperView;
long txId;
if (usesSoftwareRendering) {
- viewWrapper = new PlatformViewWrapper(context);
+ wrapperView = new PlatformViewWrapper(context);
txId = -1;
} else {
final TextureRegistry.SurfaceTextureEntry textureEntry =
textureRegistry.createSurfaceTexture();
- viewWrapper = new PlatformViewWrapper(context, textureEntry);
+ wrapperView = new PlatformViewWrapper(context, textureEntry);
txId = textureEntry.id();
}
- viewWrapper.setTouchProcessor(androidTouchProcessor);
- viewWrapper.setBufferSize(physicalWidth, physicalHeight);
+ wrapperView.setTouchProcessor(androidTouchProcessor);
- final FrameLayout.LayoutParams viewWrapperLayoutParams =
+ final int physicalWidth = toPhysicalPixels(request.logicalWidth);
+ final int physicalHeight = toPhysicalPixels(request.logicalHeight);
+ wrapperView.setBufferSize(physicalWidth, physicalHeight);
+
+ final FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(physicalWidth, physicalHeight);
- // Size and position the view wrapper.
final int physicalTop = toPhysicalPixels(request.logicalTop);
final int physicalLeft = toPhysicalPixels(request.logicalLeft);
- viewWrapperLayoutParams.topMargin = physicalTop;
- viewWrapperLayoutParams.leftMargin = physicalLeft;
- viewWrapper.setLayoutParams(viewWrapperLayoutParams);
+ layoutParams.topMargin = physicalTop;
+ layoutParams.leftMargin = physicalLeft;
+ wrapperView.setLayoutParams(layoutParams);
- // Size the embedded view.
- // This isn't needed when the virtual display is used because the virtual display itself
- // is sized.
+ final View embeddedView = platformView.getView();
+ if (embeddedView == null) {
+ throw new IllegalStateException(
+ "PlatformView#getView() returned null, but an Android view reference was expected.");
+ } else if (embeddedView.getParent() != null) {
+ throw new IllegalStateException(
+ "The Android view returned from PlatformView#getView() was already added to a parent view.");
+ }
embeddedView.setLayoutParams(new FrameLayout.LayoutParams(physicalWidth, physicalHeight));
+ embeddedView.setLayoutDirection(request.direction);
// Accessibility in the embedded view is initially disabled because if a Flutter app
// disabled accessibility in the first frame, the embedding won't receive an update to
@@ -345,12 +244,8 @@ public long createForTextureLayer(
embeddedView.setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- // Add the embedded view to the wrapper.
- viewWrapper.addView(embeddedView);
-
- // Listen for focus changed in any subview, so the framework is notified when the platform
- // view is focused.
- viewWrapper.setOnDescendantFocusChangeListener(
+ wrapperView.addView(embeddedView);
+ wrapperView.setOnDescendantFocusChangeListener(
(v, hasFocus) -> {
if (hasFocus) {
platformViewsChannel.invokeViewFocused(viewId);
@@ -358,37 +253,19 @@ public long createForTextureLayer(
textInputPlugin.clearPlatformViewClient(viewId);
}
});
- flutterView.addView(viewWrapper);
- viewWrappers.append(viewId, viewWrapper);
+ flutterView.addView(wrapperView);
+ viewWrappers.append(viewId, wrapperView);
return txId;
}
@Override
public void dispose(int viewId) {
final PlatformView platformView = platformViews.get(viewId);
- if (platformView == null) {
- Log.e(TAG, "Disposing unknown platform view with id: " + viewId);
- return;
- }
- platformViews.remove(viewId);
-
- try {
+ if (platformView != null) {
+ platformViews.remove(viewId);
platformView.dispose();
- } catch (RuntimeException exception) {
- Log.e(TAG, "Disposing platform view threw an exception", exception);
}
-
- if (usesVirtualDisplay(viewId)) {
- final VirtualDisplayController vdController = vdControllers.get(viewId);
- final View embeddedView = vdController.getView();
- if (embeddedView != null) {
- contextToEmbeddedView.remove(embeddedView.getContext());
- }
- vdControllers.remove(viewId);
- return;
- }
- // The platform view is displayed using a TextureLayer and is inserted in the view
- // hierarchy.
+ // The platform view is displayed using a TextureLayer.
final PlatformViewWrapper viewWrapper = viewWrappers.get(viewId);
if (viewWrapper != null) {
viewWrapper.removeAllViews();
@@ -418,65 +295,33 @@ public void dispose(int viewId) {
@Override
public void offset(int viewId, double top, double left) {
- if (usesVirtualDisplay(viewId)) {
- // Virtual displays don't need an accessibility offset.
- return;
- }
- // For platform views that use TextureView and are in the view hierarchy, set
- // an offset to the wrapper view.
- // This ensures that the accessibility highlights are drawn in the expected position on
- // screen.
- // This offset doesn't affect the position of the embeded view by itself since the GL
- // texture is positioned by the Flutter engine, which knows where to position different
- // types of layers.
- final PlatformViewWrapper viewWrapper = viewWrappers.get(viewId);
- if (viewWrapper == null) {
+ final PlatformViewWrapper wrapper = viewWrappers.get(viewId);
+ if (wrapper == null) {
Log.e(TAG, "Setting offset for unknown platform view with id: " + viewId);
return;
}
final int physicalTop = toPhysicalPixels(top);
final int physicalLeft = toPhysicalPixels(left);
final FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) viewWrapper.getLayoutParams();
+ (FrameLayout.LayoutParams) wrapper.getLayoutParams();
layoutParams.topMargin = physicalTop;
layoutParams.leftMargin = physicalLeft;
- viewWrapper.setLayoutParams(layoutParams);
+ wrapper.setLayoutParams(layoutParams);
}
@Override
- public void resize(
- @NonNull PlatformViewsChannel.PlatformViewResizeRequest request,
- @NonNull PlatformViewsChannel.PlatformViewBufferResized onComplete) {
- final int physicalWidth = toPhysicalPixels(request.newLogicalWidth);
- final int physicalHeight = toPhysicalPixels(request.newLogicalHeight);
+ public PlatformViewsChannel.PlatformViewBufferSize resize(
+ @NonNull PlatformViewsChannel.PlatformViewResizeRequest request) {
final int viewId = request.viewId;
-
- if (usesVirtualDisplay(viewId)) {
- final VirtualDisplayController vdController = vdControllers.get(viewId);
- // Resizing involved moving the platform view to a new virtual display. Doing so
- // potentially results in losing an active input connection. To make sure we preserve
- // the input connection when resizing we lock it here and unlock after the resize is
- // complete.
- lockInputConnection(vdController);
- vdController.resize(
- physicalWidth,
- physicalHeight,
- () -> {
- unlockInputConnection(vdController);
- onComplete.run(
- new PlatformViewsChannel.PlatformViewBufferSize(
- toLogicalPixels(vdController.getBufferWidth()),
- toLogicalPixels(vdController.getBufferHeight())));
- });
- return;
- }
-
final PlatformView platformView = platformViews.get(viewId);
- final PlatformViewWrapper viewWrapper = viewWrappers.get(viewId);
- if (platformView == null || viewWrapper == null) {
+ final PlatformViewWrapper view = viewWrappers.get(viewId);
+ if (platformView == null || view == null) {
Log.e(TAG, "Resizing unknown platform view with id: " + viewId);
- return;
+ return null;
}
+ final int newWidth = toPhysicalPixels(request.newLogicalWidth);
+ final int newHeight = toPhysicalPixels(request.newLogicalHeight);
+
// Resize the buffer only when the current buffer size is smaller than the new size.
// This is required to prevent a situation when smooth keyboard animation
// resizes the texture too often, such that the GPU and the platform thread don't agree on
@@ -485,56 +330,46 @@ public void resize(
// Resizing the texture causes pixel stretching since the size of the GL texture used in
// the engine
// is set by the framework, but the texture buffer size is set by the platform down below.
- if (physicalWidth > viewWrapper.getBufferWidth()
- || physicalHeight > viewWrapper.getBufferHeight()) {
- viewWrapper.setBufferSize(physicalWidth, physicalHeight);
+ if (newWidth > view.getBufferWidth() || newHeight > view.getBufferHeight()) {
+ view.setBufferSize(newWidth, newHeight);
}
- final ViewGroup.LayoutParams viewWrapperLayoutParams = viewWrapper.getLayoutParams();
- viewWrapperLayoutParams.width = physicalWidth;
- viewWrapperLayoutParams.height = physicalHeight;
- viewWrapper.setLayoutParams(viewWrapperLayoutParams);
+ final ViewGroup.LayoutParams viewWrapperLayoutParams = view.getLayoutParams();
+ viewWrapperLayoutParams.width = newWidth;
+ viewWrapperLayoutParams.height = newHeight;
+ view.setLayoutParams(viewWrapperLayoutParams);
final View embeddedView = platformView.getView();
if (embeddedView != null) {
final ViewGroup.LayoutParams embeddedViewLayoutParams = embeddedView.getLayoutParams();
- embeddedViewLayoutParams.width = physicalWidth;
- embeddedViewLayoutParams.height = physicalHeight;
+ embeddedViewLayoutParams.width = newWidth;
+ embeddedViewLayoutParams.height = newHeight;
embeddedView.setLayoutParams(embeddedViewLayoutParams);
}
- onComplete.run(
- new PlatformViewsChannel.PlatformViewBufferSize(
- toLogicalPixels(viewWrapper.getBufferWidth()),
- toLogicalPixels(viewWrapper.getBufferHeight())));
+ return new PlatformViewsChannel.PlatformViewBufferSize(
+ toLogicalPixels(view.getBufferWidth()), toLogicalPixels(view.getBufferHeight()));
}
@Override
public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
final int viewId = touch.viewId;
- final float density = context.getResources().getDisplayMetrics().density;
-
- if (usesVirtualDisplay(viewId)) {
- final VirtualDisplayController vdController = vdControllers.get(viewId);
- final MotionEvent event = toMotionEvent(density, touch, true);
- vdController.dispatchTouchEvent(event);
- return;
- }
-
final PlatformView platformView = platformViews.get(viewId);
if (platformView == null) {
Log.e(TAG, "Sending touch to an unknown view with id: " + viewId);
return;
}
+ ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
+ final float density = context.getResources().getDisplayMetrics().density;
+ final MotionEvent event = toMotionEvent(density, touch);
final View view = platformView.getView();
if (view == null) {
Log.e(TAG, "Sending touch to a null view with id: " + viewId);
return;
}
- final MotionEvent event = toMotionEvent(density, touch, false);
view.dispatchTouchEvent(event);
}
- @TargetApi(17)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setDirection(int viewId, int direction) {
if (!validateDirection(direction)) {
@@ -545,47 +380,33 @@ public void setDirection(int viewId, int direction) {
+ viewId
+ ")");
}
-
- View embeddedView;
-
- if (usesVirtualDisplay(viewId)) {
- final VirtualDisplayController controller = vdControllers.get(viewId);
- embeddedView = controller.getView();
- } else {
- final PlatformView platformView = platformViews.get(viewId);
- if (platformView == null) {
- Log.e(TAG, "Setting direction to an unknown view with id: " + viewId);
- return;
- }
- embeddedView = platformView.getView();
+ final PlatformView platformView = platformViews.get(viewId);
+ if (platformView == null) {
+ Log.e(TAG, "Setting direction to an unknown view with id: " + viewId);
+ return;
}
- if (embeddedView == null) {
+ ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
+ final View view = platformView.getView();
+ if (view == null) {
Log.e(TAG, "Setting direction to a null view with id: " + viewId);
return;
}
- embeddedView.setLayoutDirection(direction);
+ view.setLayoutDirection(direction);
}
@Override
public void clearFocus(int viewId) {
- View embeddedView;
-
- if (usesVirtualDisplay(viewId)) {
- final VirtualDisplayController controller = vdControllers.get(viewId);
- embeddedView = controller.getView();
- } else {
- final PlatformView platformView = platformViews.get(viewId);
- if (platformView == null) {
- Log.e(TAG, "Clearing focus on an unknown view with id: " + viewId);
- return;
- }
- embeddedView = platformView.getView();
+ final PlatformView platformView = platformViews.get(viewId);
+ if (platformView == null) {
+ Log.e(TAG, "Clearing focus on an unknown view with id: " + viewId);
+ return;
}
- if (embeddedView == null) {
+ final View view = platformView.getView();
+ if (view == null) {
Log.e(TAG, "Clearing focus on a null view with id: " + viewId);
return;
}
- embeddedView.clearFocus();
+ view.clearFocus();
}
private void ensureValidAndroidVersion(int minSdkVersion) {
@@ -605,8 +426,7 @@ public void synchronizeToNativeViewHierarchy(boolean yes) {
};
@VisibleForTesting
- public MotionEvent toMotionEvent(
- float density, PlatformViewsChannel.PlatformViewTouch touch, boolean usingVirtualDiplay) {
+ public MotionEvent toMotionEvent(float density, PlatformViewsChannel.PlatformViewTouch touch) {
MotionEventTracker.MotionEventId motionEventId =
MotionEventTracker.MotionEventId.from(touch.motionEventId);
MotionEvent trackedEvent = motionEventTracker.pop(motionEventId);
@@ -622,7 +442,7 @@ public MotionEvent toMotionEvent(
parsePointerCoordsList(touch.rawPointerCoords, density)
.toArray(new PointerCoords[touch.pointerCount]);
- if (!usingVirtualDiplay && trackedEvent != null) {
+ if (trackedEvent != null) {
return MotionEvent.obtain(
trackedEvent.getDownTime(),
trackedEvent.getEventTime(),
@@ -661,9 +481,7 @@ public MotionEvent toMotionEvent(
public PlatformViewsController() {
registry = new PlatformViewRegistryImpl();
- vdControllers = new HashMap<>();
accessibilityEventsDelegate = new AccessibilityEventsDelegate();
- contextToEmbeddedView = new HashMap<>();
overlayLayerViews = new SparseArray<>();
currentFrameUsedOverlayLayerIds = new HashSet<>();
currentFrameUsedPlatformViewIds = new HashSet<>();
@@ -776,7 +594,6 @@ public void detachFromView() {
final FlutterMutatorView view = platformViewParent.valueAt(index);
flutterView.removeView(view);
}
-
destroyOverlaySurfaces();
removeOverlaySurfaces();
flutterView = null;
@@ -817,29 +634,6 @@ public void detachTextInputPlugin() {
textInputPlugin = null;
}
- /**
- * Returns true if Flutter should perform input connection proxying for the view.
- *
- * If the view is a platform view managed by this platform views controller returns true. Else
- * if the view was created in a platform view's VD, delegates the decision to the platform view's
- * {@link View#checkInputConnectionProxy(View)} method. Else returns false.
- */
- public boolean checkInputConnectionProxy(@Nullable View view) {
- // View can be null on some devices
- // See: https://github.com/flutter/flutter/issues/36517
- if (view == null) {
- return false;
- }
- if (!contextToEmbeddedView.containsKey(view.getContext())) {
- return false;
- }
- View platformView = contextToEmbeddedView.get(view.getContext());
- if (platformView == view) {
- return true;
- }
- return platformView.checkInputConnectionProxy(view);
- }
-
public PlatformViewRegistry getRegistry() {
return registry;
}
@@ -857,21 +651,16 @@ public void onAttachedToJNI() {
* PlatformViewsController} detaches from JNI.
*/
public void onDetachedFromJNI() {
- diposeAllViews();
+ flushAllViews();
}
public void onPreEngineRestart() {
- diposeAllViews();
+ flushAllViews();
}
@Override
@Nullable
public View getPlatformViewById(int viewId) {
- if (usesVirtualDisplay(viewId)) {
- final VirtualDisplayController controller = vdControllers.get(viewId);
- return controller.getView();
- }
-
final PlatformView platformView = platformViews.get(viewId);
if (platformView == null) {
return null;
@@ -879,27 +668,6 @@ public View getPlatformViewById(int viewId) {
return platformView.getView();
}
- @Override
- public boolean usesVirtualDisplay(int id) {
- return vdControllers.containsKey(id);
- }
-
- private void lockInputConnection(@NonNull VirtualDisplayController controller) {
- if (textInputPlugin == null) {
- return;
- }
- textInputPlugin.lockPlatformViewInputConnection();
- controller.onInputConnectionLocked();
- }
-
- private void unlockInputConnection(@NonNull VirtualDisplayController controller) {
- if (textInputPlugin == null) {
- return;
- }
- textInputPlugin.unlockPlatformViewInputConnection();
- controller.onInputConnectionUnlocked();
- }
-
private static boolean validateDirection(int direction) {
return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;
}
@@ -961,11 +729,9 @@ private int toLogicalPixels(double physicalPixels) {
return (int) Math.round(physicalPixels / getDisplayDensity());
}
- private void diposeAllViews() {
+ private void flushAllViews() {
while (platformViews.size() > 0) {
- final int viewId = platformViews.keyAt(0);
- // Dispose deletes the entry from platformViews and clears associated resources.
- channelHandler.dispose(viewId);
+ channelHandler.dispose(platformViews.keyAt(0));
}
}
diff --git a/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java b/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java
deleted file mode 100644
index 188875d89d5af..0000000000000
--- a/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java
+++ /dev/null
@@ -1,482 +0,0 @@
-// 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.platform;
-
-import static android.content.Context.WINDOW_SERVICE;
-import static android.view.View.OnFocusChangeListener;
-
-import android.annotation.TargetApi;
-import android.app.AlertDialog;
-import android.app.Presentation;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.MutableContextWrapper;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.FrameLayout;
-import androidx.annotation.Keep;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import io.flutter.Log;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-/*
- * A presentation used for hosting a single Android view in a virtual display.
- *
- * This presentation overrides the WindowManager's addView/removeView/updateViewLayout methods, such that views added
- * directly to the WindowManager are added as part of the presentation's view hierarchy (to fakeWindowViewGroup).
- *
- * The view hierarchy for the presentation is as following:
- *
- * rootView
- * / \
- * / \
- * / \
- * container state.fakeWindowViewGroup
- * |
- * EmbeddedView
- */
-@Keep
-@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-class SingleViewPresentation extends Presentation {
-
- /*
- * When an embedded view is resized in Flutterverse we move the Android view to a new virtual display
- * that has the new size. This class keeps the presentation state that moves with the view to the presentation of
- * the new virtual display.
- */
- static class PresentationState {
- // The Android view we are embedding in the Flutter app.
- private PlatformView platformView;
-
- // The InvocationHandler for a WindowManager proxy. This is essentially the custom window
- // manager for the
- // presentation.
- private WindowManagerHandler windowManagerHandler;
-
- // Contains views that were added directly to the window manager (e.g
- // android.widget.PopupWindow).
- private FakeWindowViewGroup fakeWindowViewGroup;
- }
-
- // A reference to the current accessibility bridge to which accessibility events will be
- // delegated.
- private final AccessibilityEventsDelegate accessibilityEventsDelegate;
-
- private final OnFocusChangeListener focusChangeListener;
-
- // This is the view id assigned by the Flutter framework to the embedded view, we keep it here
- // so when we create the platform view we can tell it its view id.
- private int viewId;
-
- // This is the creation parameters for the platform view, we keep it here
- // so when we create the platform view we can tell it its view id.
- private Object createParams;
-
- // The root view for the presentation, it has 2 childs: container which contains the embedded
- // view, and
- // fakeWindowViewGroup which contains views that were added directly to the presentation's window
- // manager.
- private AccessibilityDelegatingFrameLayout rootView;
-
- // Contains the embedded platform view (platformView.getView()) when it is attached to the
- // presentation.
- private FrameLayout container;
-
- private final PresentationState state;
-
- private boolean startFocused = false;
-
- // The context for the application window that hosts FlutterView.
- private final Context outerContext;
-
- /**
- * Creates a presentation that will use the view factory to create a new platform view in the
- * presentation's onCreate, and attach it.
- */
- public SingleViewPresentation(
- Context outerContext,
- Display display,
- PlatformView view,
- AccessibilityEventsDelegate accessibilityEventsDelegate,
- int viewId,
- Object createParams,
- OnFocusChangeListener focusChangeListener) {
- super(new ImmContext(outerContext), display);
- this.accessibilityEventsDelegate = accessibilityEventsDelegate;
- this.viewId = viewId;
- this.createParams = createParams;
- this.focusChangeListener = focusChangeListener;
- this.outerContext = outerContext;
- state = new PresentationState();
- state.platformView = view;
- getWindow()
- .setFlags(
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- getWindow().setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
- }
- }
-
- /**
- * Creates a presentation that will attach an already existing view as its root view.
- *
- *
The display's density must match the density of the context used when the view was created.
- */
- public SingleViewPresentation(
- Context outerContext,
- Display display,
- AccessibilityEventsDelegate accessibilityEventsDelegate,
- PresentationState state,
- OnFocusChangeListener focusChangeListener,
- boolean startFocused) {
- super(new ImmContext(outerContext), display);
- this.accessibilityEventsDelegate = accessibilityEventsDelegate;
- this.state = state;
- this.focusChangeListener = focusChangeListener;
- this.outerContext = outerContext;
- getWindow()
- .setFlags(
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
- this.startFocused = startFocused;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // This makes sure we preserve alpha for the VD's content.
- getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
- if (state.fakeWindowViewGroup == null) {
- state.fakeWindowViewGroup = new FakeWindowViewGroup(getContext());
- }
- if (state.windowManagerHandler == null) {
- WindowManager windowManagerDelegate =
- (WindowManager) getContext().getSystemService(WINDOW_SERVICE);
- state.windowManagerHandler =
- new WindowManagerHandler(windowManagerDelegate, state.fakeWindowViewGroup);
- }
-
- container = new FrameLayout(getContext());
-
- // Our base mContext has already been wrapped with an IMM cache at instantiation time, but
- // we want to wrap it again here to also return state.windowManagerHandler.
- Context baseContext =
- new PresentationContext(getContext(), state.windowManagerHandler, outerContext);
-
- View embeddedView = state.platformView.getView();
- if (embeddedView.getContext() instanceof MutableContextWrapper) {
- MutableContextWrapper currentContext = (MutableContextWrapper) embeddedView.getContext();
- currentContext.setBaseContext(baseContext);
- } else {
- throw new IllegalStateException(
- "Unexpected platform view context. "
- + "When constructing a platform view in the factory, use the context from PlatformViewFactory#create, view id: "
- + viewId);
- }
-
- container.addView(embeddedView);
- rootView =
- new AccessibilityDelegatingFrameLayout(
- getContext(), accessibilityEventsDelegate, embeddedView);
- rootView.addView(container);
- rootView.addView(state.fakeWindowViewGroup);
-
- embeddedView.setOnFocusChangeListener(focusChangeListener);
- rootView.setFocusableInTouchMode(true);
- if (startFocused) {
- embeddedView.requestFocus();
- } else {
- rootView.requestFocus();
- }
- setContentView(rootView);
- }
-
- public PresentationState detachState() {
- container.removeAllViews();
- rootView.removeAllViews();
- return state;
- }
-
- public PlatformView getView() {
- if (state.platformView == null) return null;
- return state.platformView;
- }
-
- /*
- * A view group that implements the same layout protocol that exist between the WindowManager and its direct
- * children.
- *
- * Currently only a subset of the protocol is supported (gravity, x, and y).
- */
- static class FakeWindowViewGroup extends ViewGroup {
- // Used in onLayout to keep the bounds of the current view.
- // We keep it as a member to avoid object allocations during onLayout which are discouraged.
- private final Rect viewBounds;
-
- // Used in onLayout to keep the bounds of the child views.
- // We keep it as a member to avoid object allocations during onLayout which are discouraged.
- private final Rect childRect;
-
- public FakeWindowViewGroup(Context context) {
- super(context);
- viewBounds = new Rect();
- childRect = new Rect();
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- WindowManager.LayoutParams params = (WindowManager.LayoutParams) child.getLayoutParams();
- viewBounds.set(l, t, r, b);
- Gravity.apply(
- params.gravity,
- child.getMeasuredWidth(),
- child.getMeasuredHeight(),
- viewBounds,
- params.x,
- params.y,
- childRect);
- child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- child.measure(atMost(widthMeasureSpec), atMost(heightMeasureSpec));
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- private static int atMost(int measureSpec) {
- return MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(measureSpec), MeasureSpec.AT_MOST);
- }
- }
-
- /** Answers calls for {@link InputMethodManager} with an instance cached at creation time. */
- // TODO(mklim): This caches the IMM at construction time and won't pick up any changes. In rare
- // cases where the FlutterView changes windows this will return an outdated instance. This
- // should be fixed to instead defer returning the IMM to something that know's FlutterView's
- // true Context.
- private static class ImmContext extends ContextWrapper {
- private @NonNull final InputMethodManager inputMethodManager;
-
- ImmContext(Context base) {
- this(base, /*inputMethodManager=*/ null);
- }
-
- private ImmContext(Context base, @Nullable InputMethodManager inputMethodManager) {
- super(base);
- this.inputMethodManager =
- inputMethodManager != null
- ? inputMethodManager
- : (InputMethodManager) base.getSystemService(INPUT_METHOD_SERVICE);
- }
-
- @Override
- public Object getSystemService(String name) {
- if (INPUT_METHOD_SERVICE.equals(name)) {
- return inputMethodManager;
- }
- return super.getSystemService(name);
- }
-
- @Override
- public Context createDisplayContext(Display display) {
- Context displayContext = super.createDisplayContext(display);
- return new ImmContext(displayContext, inputMethodManager);
- }
- }
-
- /** Proxies a Context replacing the WindowManager with our custom instance. */
- // TODO(mklim): This caches the IMM at construction time and won't pick up any changes. In rare
- // cases where the FlutterView changes windows this will return an outdated instance. This
- // should be fixed to instead defer returning the IMM to something that know's FlutterView's
- // true Context.
- private static class PresentationContext extends ContextWrapper {
- private @NonNull final WindowManagerHandler windowManagerHandler;
- private @Nullable WindowManager windowManager;
- private final Context flutterAppWindowContext;
-
- PresentationContext(
- Context base,
- @NonNull WindowManagerHandler windowManagerHandler,
- Context flutterAppWindowContext) {
- super(base);
- this.windowManagerHandler = windowManagerHandler;
- this.flutterAppWindowContext = flutterAppWindowContext;
- }
-
- @Override
- public Object getSystemService(String name) {
- if (WINDOW_SERVICE.equals(name)) {
- if (isCalledFromAlertDialog()) {
- // Alert dialogs are showing on top of the entire application and should not be limited to
- // the virtual
- // display. If we detect that an android.app.AlertDialog constructor is what's fetching
- // the window manager
- // we return the one for the application's window.
- //
- // Note that if we don't do this AlertDialog will throw a ClassCastException as down the
- // line it tries
- // to case this instance to a WindowManagerImpl which the object returned by
- // getWindowManager is not
- // a subclass of.
- return flutterAppWindowContext.getSystemService(name);
- }
- return getWindowManager();
- }
- return super.getSystemService(name);
- }
-
- private WindowManager getWindowManager() {
- if (windowManager == null) {
- windowManager = windowManagerHandler.getWindowManager();
- }
- return windowManager;
- }
-
- private boolean isCalledFromAlertDialog() {
- StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
- for (int i = 0; i < stackTraceElements.length && i < 11; i++) {
- if (stackTraceElements[i].getClassName().equals(AlertDialog.class.getCanonicalName())
- && stackTraceElements[i].getMethodName().equals("")) {
- return true;
- }
- }
- return false;
- }
- }
-
- /*
- * A dynamic proxy handler for a WindowManager with custom overrides.
- *
- * The presentation's window manager delegates all calls to the default window manager.
- * WindowManager#addView calls triggered by views that are attached to the virtual display are crashing
- * (see: https://github.com/flutter/flutter/issues/20714). This was triggered when selecting text in an embedded
- * WebView (as the selection handles are implemented as popup windows).
- *
- * This dynamic proxy overrides the addView, removeView, removeViewImmediate, and updateViewLayout methods
- * to prevent these crashes.
- *
- * This will be more efficient as a static proxy that's not using reflection, but as the engine is currently
- * not being built against the latest Android SDK we cannot override all relevant method.
- * Tracking issue for upgrading the engine's Android sdk: https://github.com/flutter/flutter/issues/20717
- */
- static class WindowManagerHandler implements InvocationHandler {
- private static final String TAG = "PlatformViewsController";
-
- private final WindowManager delegate;
- FakeWindowViewGroup fakeWindowRootView;
-
- WindowManagerHandler(WindowManager delegate, FakeWindowViewGroup fakeWindowViewGroup) {
- this.delegate = delegate;
- fakeWindowRootView = fakeWindowViewGroup;
- }
-
- public WindowManager getWindowManager() {
- return (WindowManager)
- Proxy.newProxyInstance(
- WindowManager.class.getClassLoader(), new Class>[] {WindowManager.class}, this);
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- switch (method.getName()) {
- case "addView":
- addView(args);
- return null;
- case "removeView":
- removeView(args);
- return null;
- case "removeViewImmediate":
- removeViewImmediate(args);
- return null;
- case "updateViewLayout":
- updateViewLayout(args);
- return null;
- }
- try {
- return method.invoke(delegate, args);
- } catch (InvocationTargetException e) {
- throw e.getCause();
- }
- }
-
- private void addView(Object[] args) {
- if (fakeWindowRootView == null) {
- Log.w(TAG, "Embedded view called addView while detached from presentation");
- return;
- }
- View view = (View) args[0];
- WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) args[1];
- fakeWindowRootView.addView(view, layoutParams);
- }
-
- private void removeView(Object[] args) {
- if (fakeWindowRootView == null) {
- Log.w(TAG, "Embedded view called removeView while detached from presentation");
- return;
- }
- View view = (View) args[0];
- fakeWindowRootView.removeView(view);
- }
-
- private void removeViewImmediate(Object[] args) {
- if (fakeWindowRootView == null) {
- Log.w(TAG, "Embedded view called removeViewImmediate while detached from presentation");
- return;
- }
- View view = (View) args[0];
- view.clearAnimation();
- fakeWindowRootView.removeView(view);
- }
-
- private void updateViewLayout(Object[] args) {
- if (fakeWindowRootView == null) {
- Log.w(TAG, "Embedded view called updateViewLayout while detached from presentation");
- return;
- }
- View view = (View) args[0];
- WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) args[1];
- fakeWindowRootView.updateViewLayout(view, layoutParams);
- }
- }
-
- private static class AccessibilityDelegatingFrameLayout extends FrameLayout {
- private final AccessibilityEventsDelegate accessibilityEventsDelegate;
- private final View embeddedView;
-
- public AccessibilityDelegatingFrameLayout(
- Context context,
- AccessibilityEventsDelegate accessibilityEventsDelegate,
- View embeddedView) {
- super(context);
- this.accessibilityEventsDelegate = accessibilityEventsDelegate;
- this.embeddedView = embeddedView;
- }
-
- @Override
- public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
- return accessibilityEventsDelegate.requestSendAccessibilityEvent(embeddedView, child, event);
- }
- }
-}
diff --git a/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java b/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java
deleted file mode 100644
index e049d5cccbd44..0000000000000
--- a/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java
+++ /dev/null
@@ -1,305 +0,0 @@
-// 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.platform;
-
-import static android.view.View.OnFocusChangeListener;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
-import android.util.DisplayMetrics;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import io.flutter.Log;
-import io.flutter.view.TextureRegistry;
-import java.util.Locale;
-
-@TargetApi(20)
-class VirtualDisplayController {
- private static String TAG = "VirtualDisplayController";
-
- public static VirtualDisplayController create(
- Context context,
- AccessibilityEventsDelegate accessibilityEventsDelegate,
- PlatformView view,
- TextureRegistry.SurfaceTextureEntry textureEntry,
- int width,
- int height,
- int viewId,
- Object createParams,
- OnFocusChangeListener focusChangeListener) {
-
- int selectedWidth = width;
- int selectedHeight = height;
-
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- if (selectedWidth == 0 || selectedHeight == 0) {
- return null;
- }
- // Prevent https://github.com/flutter/flutter/issues/2897.
- if (selectedWidth > metrics.widthPixels || selectedHeight > metrics.heightPixels) {
- float aspectRatio = (float) selectedWidth / (float) selectedHeight;
- int maybeWidth = (int) (metrics.heightPixels * aspectRatio);
- int maybeHeight = (int) (metrics.widthPixels / aspectRatio);
-
- if (maybeHeight <= metrics.heightPixels) {
- selectedWidth = metrics.widthPixels;
- selectedHeight = maybeHeight;
- } else if (maybeWidth <= metrics.widthPixels) {
- selectedHeight = metrics.heightPixels;
- selectedWidth = maybeWidth;
- } else {
- return null;
- }
-
- String message =
- String.format(
- Locale.US,
- "Resizing virtual display of size: [%d, %d] to size [%d, %d] "
- + "since it's larger than the device display size [%d, %d].",
- width,
- height,
- selectedWidth,
- selectedHeight,
- metrics.widthPixels,
- metrics.heightPixels);
- Log.w(TAG, message);
- }
-
- textureEntry.surfaceTexture().setDefaultBufferSize(selectedWidth, selectedHeight);
- Surface surface = new Surface(textureEntry.surfaceTexture());
- DisplayManager displayManager =
- (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
-
- int densityDpi = context.getResources().getDisplayMetrics().densityDpi;
- VirtualDisplay virtualDisplay =
- displayManager.createVirtualDisplay(
- "flutter-vd", selectedWidth, selectedHeight, densityDpi, surface, 0);
-
- if (virtualDisplay == null) {
- return null;
- }
- VirtualDisplayController controller =
- new VirtualDisplayController(
- context,
- accessibilityEventsDelegate,
- virtualDisplay,
- view,
- surface,
- textureEntry,
- focusChangeListener,
- viewId,
- createParams);
- controller.bufferWidth = selectedWidth;
- controller.bufferHeight = selectedHeight;
- return controller;
- }
-
- @VisibleForTesting SingleViewPresentation presentation;
-
- private final Context context;
- private final AccessibilityEventsDelegate accessibilityEventsDelegate;
- private final int densityDpi;
- private final TextureRegistry.SurfaceTextureEntry textureEntry;
- private final OnFocusChangeListener focusChangeListener;
- private final Surface surface;
-
- private VirtualDisplay virtualDisplay;
- private int bufferWidth;
- private int bufferHeight;
-
- private VirtualDisplayController(
- Context context,
- AccessibilityEventsDelegate accessibilityEventsDelegate,
- VirtualDisplay virtualDisplay,
- PlatformView view,
- Surface surface,
- TextureRegistry.SurfaceTextureEntry textureEntry,
- OnFocusChangeListener focusChangeListener,
- int viewId,
- Object createParams) {
- this.context = context;
- this.accessibilityEventsDelegate = accessibilityEventsDelegate;
- this.textureEntry = textureEntry;
- this.focusChangeListener = focusChangeListener;
- this.surface = surface;
- this.virtualDisplay = virtualDisplay;
- densityDpi = context.getResources().getDisplayMetrics().densityDpi;
- presentation =
- new SingleViewPresentation(
- context,
- this.virtualDisplay.getDisplay(),
- view,
- accessibilityEventsDelegate,
- viewId,
- createParams,
- focusChangeListener);
- presentation.show();
- }
-
- public int getBufferWidth() {
- return bufferWidth;
- }
-
- public int getBufferHeight() {
- return bufferHeight;
- }
-
- public void resize(final int width, final int height, final Runnable onNewSizeFrameAvailable) {
- boolean isFocused = getView().isFocused();
- final SingleViewPresentation.PresentationState presentationState = presentation.detachState();
- // We detach the surface to prevent it being destroyed when releasing the vd.
- //
- // setSurface is only available starting API 20. We could support API 19 by re-creating a new
- // SurfaceTexture here. This will require refactoring the TextureRegistry to allow recycling
- // texture
- // entry IDs.
- virtualDisplay.setSurface(null);
- virtualDisplay.release();
-
- bufferWidth = width;
- bufferHeight = height;
- textureEntry.surfaceTexture().setDefaultBufferSize(width, height);
- DisplayManager displayManager =
- (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
- virtualDisplay =
- displayManager.createVirtualDisplay("flutter-vd", width, height, densityDpi, surface, 0);
-
- final View embeddedView = getView();
- // There's a bug in Android version older than O where view tree observer onDrawListeners don't
- // get properly
- // merged when attaching to window, as a workaround we register the on draw listener after the
- // view is attached.
- embeddedView.addOnAttachStateChangeListener(
- new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- OneTimeOnDrawListener.schedule(
- embeddedView,
- new Runnable() {
- @Override
- public void run() {
- // We need some delay here until the frame propagates through the vd surface to
- // to the texture,
- // 128ms was picked pretty arbitrarily based on trial and error.
- // As long as we invoke the runnable after a new frame is available we avoid the
- // scaling jank
- // described in: https://github.com/flutter/flutter/issues/19572
- // We should ideally run onNewSizeFrameAvailable ASAP to make the embedded view
- // more responsive
- // following a resize.
- embeddedView.postDelayed(onNewSizeFrameAvailable, 128);
- }
- });
- embeddedView.removeOnAttachStateChangeListener(this);
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {}
- });
-
- // Create a new SingleViewPresentation and show() it before we cancel() the existing
- // presentation. Calling show() and cancel() in this order fixes
- // https://github.com/flutter/flutter/issues/26345 and maintains seamless transition
- // of the contents of the presentation.
- SingleViewPresentation newPresentation =
- new SingleViewPresentation(
- context,
- virtualDisplay.getDisplay(),
- accessibilityEventsDelegate,
- presentationState,
- focusChangeListener,
- isFocused);
- newPresentation.show();
- presentation.cancel();
- presentation = newPresentation;
- }
-
- public void dispose() {
- // Fix rare crash on HuaWei device described in: https://github.com/flutter/engine/pull/9192
- presentation.cancel();
- presentation.detachState();
- virtualDisplay.release();
- textureEntry.release();
- }
-
- /** See {@link PlatformView#onFlutterViewAttached(View)} */
- /*package*/ void onFlutterViewAttached(@NonNull View flutterView) {
- if (presentation == null || presentation.getView() == null) {
- return;
- }
- presentation.getView().onFlutterViewAttached(flutterView);
- }
-
- /** See {@link PlatformView#onFlutterViewDetached()} */
- /*package*/ void onFlutterViewDetached() {
- if (presentation == null || presentation.getView() == null) {
- return;
- }
- presentation.getView().onFlutterViewDetached();
- }
-
- /*package*/ void onInputConnectionLocked() {
- if (presentation == null || presentation.getView() == null) {
- return;
- }
- presentation.getView().onInputConnectionLocked();
- }
-
- /*package*/ void onInputConnectionUnlocked() {
- if (presentation == null || presentation.getView() == null) {
- return;
- }
- presentation.getView().onInputConnectionUnlocked();
- }
-
- public View getView() {
- if (presentation == null) return null;
- PlatformView platformView = presentation.getView();
- return platformView.getView();
- }
-
- /** Dispatches a motion event to the presentation for this controller. */
- public void dispatchTouchEvent(MotionEvent event) {
- if (presentation == null) return;
- presentation.dispatchTouchEvent(event);
- }
-
- static class OneTimeOnDrawListener implements ViewTreeObserver.OnDrawListener {
- static void schedule(View view, Runnable runnable) {
- OneTimeOnDrawListener listener = new OneTimeOnDrawListener(view, runnable);
- view.getViewTreeObserver().addOnDrawListener(listener);
- }
-
- final View mView;
- Runnable mOnDrawRunnable;
-
- OneTimeOnDrawListener(View view, Runnable onDrawRunnable) {
- this.mView = view;
- this.mOnDrawRunnable = onDrawRunnable;
- }
-
- @Override
- public void onDraw() {
- if (mOnDrawRunnable == null) {
- return;
- }
- mOnDrawRunnable.run();
- mOnDrawRunnable = null;
- mView.post(
- new Runnable() {
- @Override
- public void run() {
- mView.getViewTreeObserver().removeOnDrawListener(OneTimeOnDrawListener.this);
- }
- });
- }
- }
-}
diff --git a/shell/platform/android/io/flutter/util/ViewUtils.java b/shell/platform/android/io/flutter/util/ViewUtils.java
index 5baaca2ba549d..95ea8fa855437 100644
--- a/shell/platform/android/io/flutter/util/ViewUtils.java
+++ b/shell/platform/android/io/flutter/util/ViewUtils.java
@@ -10,7 +10,6 @@
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public final class ViewUtils {
@@ -57,58 +56,16 @@ public static int generateViewId(int fallbackId) {
* @return True if the current view or any descendant view has focus.
*/
public static boolean childHasFocus(@Nullable View root) {
- return traverseHierarchy(root, (View view) -> view.hasFocus());
- }
-
- /**
- * Returns true if the root or any child view is an instance of the given types.
- *
- * @param root The root view.
- * @param viewTypes The types of views.
- * @return true if any child view is an instance of any of the given types.
- */
- public static boolean hasChildViewOfType(@Nullable View root, Class extends View>[] viewTypes) {
- return traverseHierarchy(
- root,
- (View view) -> {
- for (int i = 0; i < viewTypes.length; i++) {
- final Class extends View> viewType = viewTypes[i];
- if (viewType.isInstance(view)) {
- return true;
- }
- }
- return false;
- });
- }
-
- /** Allows to visit a view. */
- public interface ViewVisitor {
- boolean run(@NonNull View view);
- }
-
- /**
- * Traverses the view hierarchy in pre-order and runs the visitor for each child view including
- * the root view.
- *
- * If the visitor returns true, the traversal stops, and the method returns true.
- *
- *
If the visitor returns false, the traversal continues until all views are visited.
- *
- * @param root The root view.
- * @param visitor The visitor.
- * @return true if the visitor returned true for a given view.
- */
- public static boolean traverseHierarchy(@Nullable View root, @NonNull ViewVisitor visitor) {
if (root == null) {
return false;
}
- if (visitor.run(root)) {
+ if (root.hasFocus()) {
return true;
}
if (root instanceof ViewGroup) {
final ViewGroup viewGroup = (ViewGroup) root;
for (int idx = 0; idx < viewGroup.getChildCount(); idx++) {
- if (traverseHierarchy(viewGroup.getChildAt(idx), visitor)) {
+ if (childHasFocus(viewGroup.getChildAt(idx))) {
return true;
}
}
diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java
index 28b09507214b3..48f1ab700cc8a 100644
--- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java
+++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java
@@ -573,26 +573,6 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
return null;
}
- // Generate accessibility node for platform views using a virtual display.
- //
- // In this case, register the accessibility node in the view embedder,
- // so the accessibility tree can be mirrored as a subtree of the Flutter accessibility tree.
- // This is in constrast to hybrid composition where the embedded view is in the view hiearchy,
- // so it doesn't need to be mirrored.
- //
- // See the case down below for how hybrid composition is handled.
- if (semanticsNode.platformViewId != -1) {
- if (platformViewsAccessibilityDelegate.usesVirtualDisplay(semanticsNode.platformViewId)) {
- View embeddedView =
- platformViewsAccessibilityDelegate.getPlatformViewById(semanticsNode.platformViewId);
- if (embeddedView == null) {
- return null;
- }
- Rect bounds = semanticsNode.getGlobalRect();
- return accessibilityViewEmbedder.getRootNode(embeddedView, semanticsNode.id, bounds);
- }
- }
-
AccessibilityNodeInfo result =
obtainAccessibilityNodeInfo(rootAccessibilityView, virtualViewId);
// Work around for https://github.com/flutter/flutter/issues/2101
@@ -905,19 +885,12 @@ && shouldSetCollectionInfo(semanticsNode)) {
View embeddedView =
platformViewsAccessibilityDelegate.getPlatformViewById(child.platformViewId);
- // Add the embedded view as a child of the current accessibility node if it's not
- // using a virtual display.
- //
- // In this case, the view is in the Activity's view hierarchy, so it doesn't need to be
- // mirrored.
- //
- // See the case above for how virtual displays are handled.
- if (!platformViewsAccessibilityDelegate.usesVirtualDisplay(child.platformViewId)) {
- result.addChild(embeddedView);
- continue;
- }
+ // Add the embedded view as a child of the current accessibility node if it's using
+ // hybrid composition.
+ result.addChild(embeddedView);
+ } else {
+ result.addChild(rootAccessibilityView, child.id);
}
- result.addChild(rootAccessibilityView, child.id);
}
return result;
}
@@ -1549,8 +1522,7 @@ void updateSemantics(
if (semanticsNode.hadPreviousConfig) {
updated.add(semanticsNode);
}
- if (semanticsNode.platformViewId != -1
- && !platformViewsAccessibilityDelegate.usesVirtualDisplay(semanticsNode.platformViewId)) {
+ if (semanticsNode.platformViewId != -1) {
View embeddedView =
platformViewsAccessibilityDelegate.getPlatformViewById(semanticsNode.platformViewId);
if (embeddedView != null) {
diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java
index eb498a2335e96..15245de3ef7db 100644
--- a/shell/platform/android/io/flutter/view/FlutterView.java
+++ b/shell/platform/android/io/flutter/view/FlutterView.java
@@ -26,7 +26,6 @@
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewStructure;
import android.view.WindowInsets;
@@ -422,14 +421,6 @@ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return mTextInputPlugin.createInputConnection(this, mKeyboardManager, outAttrs);
}
- @Override
- public boolean checkInputConnectionProxy(View view) {
- return mNativeView
- .getPluginRegistry()
- .getPlatformViewsController()
- .checkInputConnectionProxy(view);
- }
-
@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
super.onProvideAutofillVirtualStructure(structure, flags);
diff --git a/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java b/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java
index d3fb9a8659efe..d80e59186998b 100644
--- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java
+++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java
@@ -8,7 +8,6 @@
import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
-import android.content.MutableContextWrapper;
import android.content.res.AssetManager;
import android.graphics.SurfaceTexture;
import android.util.SparseArray;
@@ -19,7 +18,6 @@
import android.view.View;
import android.view.ViewParent;
import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.android.FlutterImageView;
@@ -59,119 +57,6 @@
@RunWith(AndroidJUnit4.class)
public class PlatformViewsControllerTest {
- @Ignore
- @Test
- public void itNotifiesVirtualDisplayControllersOfViewAttachmentAndDetachment() {
- // Setup test structure.
- FlutterView fakeFlutterView = new FlutterView(ApplicationProvider.getApplicationContext());
-
- // Create fake VirtualDisplayControllers. This requires internal knowledge of
- // PlatformViewsController. We know that all PlatformViewsController does is
- // forward view attachment/detachment calls to it's VirtualDisplayControllers.
- //
- // TODO(mattcarroll): once PlatformViewsController is refactored into testable
- // pieces, remove this test and avoid verifying private behavior.
- VirtualDisplayController fakeVdController1 = mock(VirtualDisplayController.class);
- VirtualDisplayController fakeVdController2 = mock(VirtualDisplayController.class);
-
- // Create the PlatformViewsController that is under test.
- PlatformViewsController platformViewsController = new PlatformViewsController();
-
- // Manually inject fake VirtualDisplayControllers into the PlatformViewsController.
- platformViewsController.vdControllers.put(0, fakeVdController1);
- platformViewsController.vdControllers.put(1, fakeVdController1);
-
- // Execute test & verify results.
- // Attach PlatformViewsController to the fake Flutter View.
- platformViewsController.attachToView(fakeFlutterView);
-
- // Verify that all virtual display controllers were notified of View attachment.
- verify(fakeVdController1, times(1)).onFlutterViewAttached(eq(fakeFlutterView));
- verify(fakeVdController1, never()).onFlutterViewDetached();
- verify(fakeVdController2, times(1)).onFlutterViewAttached(eq(fakeFlutterView));
- verify(fakeVdController2, never()).onFlutterViewDetached();
-
- // Detach PlatformViewsController from the fake Flutter View.
- platformViewsController.detachFromView();
-
- // Verify that all virtual display controllers were notified of the View detachment.
- verify(fakeVdController1, times(1)).onFlutterViewAttached(eq(fakeFlutterView));
- verify(fakeVdController1, times(1)).onFlutterViewDetached();
- verify(fakeVdController2, times(1)).onFlutterViewAttached(eq(fakeFlutterView));
- verify(fakeVdController2, times(1)).onFlutterViewDetached();
- }
-
- @Ignore
- @Test
- public void itCancelsOldPresentationOnResize() {
- // Setup test structure.
- // Create a fake View that represents the View that renders a Flutter UI.
- View fakeFlutterView = new View(ApplicationProvider.getApplicationContext());
-
- // Create fake VirtualDisplayControllers. This requires internal knowledge of
- // PlatformViewsController. We know that all PlatformViewsController does is
- // forward view attachment/detachment calls to it's VirtualDisplayControllers.
- //
- // TODO(mattcarroll): once PlatformViewsController is refactored into testable
- // pieces, remove this test and avoid verifying private behavior.
- VirtualDisplayController fakeVdController1 = mock(VirtualDisplayController.class);
-
- SingleViewPresentation presentation = fakeVdController1.presentation;
-
- fakeVdController1.resize(10, 10, null);
-
- assertEquals(fakeVdController1.presentation != presentation, true);
- assertEquals(presentation.isShowing(), false);
- }
-
- @Test
- public void itUsesActionEventTypeFromFrameworkEventForVirtualDisplays() {
- MotionEventTracker motionEventTracker = MotionEventTracker.getInstance();
- PlatformViewsController platformViewsController = new PlatformViewsController();
-
- MotionEvent original =
- MotionEvent.obtain(
- 100, // downTime
- 100, // eventTime
- 1, // action
- 0, // x
- 0, // y
- 0 // metaState
- );
-
- // track an event that will later get passed to us from framework
- MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(original);
-
- PlatformViewTouch frameWorkTouch =
- new PlatformViewTouch(
- 0, // viewId
- original.getDownTime(),
- original.getEventTime(),
- 2, // action
- 1, // pointerCount
- Arrays.asList(Arrays.asList(0, 0)), // pointer properties
- Arrays.asList(Arrays.asList(0., 1., 2., 3., 4., 5., 6., 7., 8.)), // pointer coords
- original.getMetaState(),
- original.getButtonState(),
- original.getXPrecision(),
- original.getYPrecision(),
- original.getDeviceId(),
- original.getEdgeFlags(),
- original.getSource(),
- original.getFlags(),
- motionEventId.getId());
-
- MotionEvent resolvedEvent =
- platformViewsController.toMotionEvent(
- 1, // density
- frameWorkTouch,
- true // usingVirtualDisplays
- );
-
- assertEquals(resolvedEvent.getAction(), frameWorkTouch.action);
- assertNotEquals(resolvedEvent.getAction(), original.getAction());
- }
-
@Ignore
@Test
public void itUsesActionEventTypeFromMotionEventForHybridPlatformViews() {
@@ -211,8 +96,7 @@ public void itUsesActionEventTypeFromMotionEventForHybridPlatformViews() {
motionEventId.getId());
MotionEvent resolvedEvent =
- platformViewsController.toMotionEvent(
- /*density=*/ 1, frameWorkTouch, /*usingVirtualDisplay=*/ false);
+ platformViewsController.toMotionEvent(/*density=*/ 1, frameWorkTouch);
assertNotEquals(resolvedEvent.getAction(), frameWorkTouch.action);
assertEquals(resolvedEvent.getAction(), original.getAction());
@@ -411,68 +295,6 @@ public void createHybridPlatformViewMessage__throwsIfViewIsNull() {
});
}
- @Test
- @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
- public void onDetachedFromJNI_clearsPlatformViewContext() {
- PlatformViewsController platformViewsController = new PlatformViewsController();
-
- int platformViewId = 0;
- assertNull(platformViewsController.getPlatformViewById(platformViewId));
-
- PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
- PlatformView platformView = mock(PlatformView.class);
-
- SurfaceView pv = mock(SurfaceView.class);
- when(pv.getContext()).thenReturn(mock(MutableContextWrapper.class));
- when(pv.getLayoutParams()).thenReturn(new LayoutParams(1, 1));
-
- when(platformView.getView()).thenReturn(pv);
- when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
- platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
-
- FlutterJNI jni = new FlutterJNI();
- attach(jni, platformViewsController);
-
- // Simulate create call from the framework.
- createPlatformView(
- jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
-
- assertFalse(platformViewsController.contextToEmbeddedView.isEmpty());
- platformViewsController.onDetachedFromJNI();
- assertTrue(platformViewsController.contextToEmbeddedView.isEmpty());
- }
-
- @Test
- @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
- public void onPreEngineRestart_clearsPlatformViewContext() {
- PlatformViewsController platformViewsController = new PlatformViewsController();
-
- int platformViewId = 0;
- assertNull(platformViewsController.getPlatformViewById(platformViewId));
-
- PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
- PlatformView platformView = mock(PlatformView.class);
-
- SurfaceView pv = mock(SurfaceView.class);
- when(pv.getContext()).thenReturn(mock(MutableContextWrapper.class));
- when(pv.getLayoutParams()).thenReturn(new LayoutParams(1, 1));
-
- when(platformView.getView()).thenReturn(pv);
- when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
- platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
-
- FlutterJNI jni = new FlutterJNI();
- attach(jni, platformViewsController);
-
- // Simulate create call from the framework.
- createPlatformView(
- jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
-
- assertFalse(platformViewsController.contextToEmbeddedView.isEmpty());
- platformViewsController.onDetachedFromJNI();
- assertTrue(platformViewsController.contextToEmbeddedView.isEmpty());
- }
-
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
public void createPlatformViewMessage__throwsIfViewHasParent() {
@@ -988,13 +810,6 @@ public void destroyOverlaySurfaces__doesNotRemoveOverlayView() {
verify(flutterView, never()).removeView(overlayImageView);
}
- @Test
- public void checkInputConnectionProxy__falseIfViewIsNull() {
- final PlatformViewsController platformViewsController = new PlatformViewsController();
- boolean shouldProxying = platformViewsController.checkInputConnectionProxy(null);
- assertFalse(shouldProxying);
- }
-
@Test
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
public void convertPlatformViewRenderSurfaceAsDefault() {
diff --git a/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java b/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java
deleted file mode 100644
index 2cc177fd86648..0000000000000
--- a/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package io.flutter.plugin.platform;
-
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-import static android.os.Build.VERSION_CODES.P;
-import static android.os.Build.VERSION_CODES.R;
-import static junit.framework.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.view.Display;
-import android.view.inputmethod.InputMethodManager;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@Config(manifest = Config.NONE)
-@RunWith(AndroidJUnit4.class)
-@TargetApi(P)
-public class SingleViewPresentationTest {
- @Test
- @Config(minSdk = JELLY_BEAN_MR1, maxSdk = R)
- public void returnsOuterContextInputMethodManager() {
- // There's a bug in Android Q caused by the IMM being instanced per display.
- // https://github.com/flutter/flutter/issues/38375. We need the context returned by
- // SingleViewPresentation to be consistent from its instantiation instead of defaulting to
- // what the system would have returned at call time.
-
- // It's not possible to set up the exact same conditions as the unit test in the bug here,
- // but we can make sure that we're wrapping the Context passed in at instantiation time and
- // returning the same InputMethodManager from it. This test passes in a Spy context instance
- // that initially returns a mock. Without the bugfix this test falls back to Robolectric's
- // system service instead of the spy's and fails.
-
- // Create an SVP under test with a Context that returns a local IMM mock.
- Context context = spy(RuntimeEnvironment.application);
- InputMethodManager expected = mock(InputMethodManager.class);
- when(context.getSystemService(Context.INPUT_METHOD_SERVICE)).thenReturn(expected);
- DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
- SingleViewPresentation svp =
- new SingleViewPresentation(context, dm.getDisplay(0), null, null, null, false);
-
- // Get the IMM from the SVP's context.
- InputMethodManager actual =
- (InputMethodManager) svp.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-
- // This should be the mocked instance from construction, not the IMM from the greater
- // Android OS (or Robolectric's shadow, in this case).
- assertEquals(expected, actual);
- }
-
- @Test
- @Config(minSdk = JELLY_BEAN_MR1, maxSdk = R)
- public void returnsOuterContextInputMethodManager_createDisplayContext() {
- // The IMM should also persist across display contexts created from the base context.
-
- // Create an SVP under test with a Context that returns a local IMM mock.
- Context context = spy(RuntimeEnvironment.application);
- InputMethodManager expected = mock(InputMethodManager.class);
- when(context.getSystemService(Context.INPUT_METHOD_SERVICE)).thenReturn(expected);
- Display display =
- ((DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE)).getDisplay(0);
- SingleViewPresentation svp =
- new SingleViewPresentation(context, display, null, null, null, false);
-
- // Get the IMM from the SVP's context.
- InputMethodManager actual =
- (InputMethodManager)
- svp.getContext()
- .createDisplayContext(display)
- .getSystemService(Context.INPUT_METHOD_SERVICE);
-
- // This should be the mocked instance from construction, not the IMM from the greater
- // Android OS (or Robolectric's shadow, in this case).
- assertEquals(expected, actual);
- }
-}
diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java
index 324331d9d1817..86c714c0f3554 100644
--- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java
+++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java
@@ -1527,7 +1527,6 @@ public void itProducesPlatformViewNodeForHybridComposition() {
View embeddedView = mock(View.class);
when(accessibilityDelegate.getPlatformViewById(1)).thenReturn(embeddedView);
- when(accessibilityDelegate.usesVirtualDisplay(1)).thenReturn(false);
AccessibilityNodeInfo nodeInfo = mock(AccessibilityNodeInfo.class);
when(embeddedView.createAccessibilityNodeInfo()).thenReturn(nodeInfo);
@@ -1565,7 +1564,6 @@ public void itMakesPlatformViewImportantForAccessibility() {
View embeddedView = mock(View.class);
when(accessibilityDelegate.getPlatformViewById(1)).thenReturn(embeddedView);
- when(accessibilityDelegate.usesVirtualDisplay(1)).thenReturn(false);
TestSemanticsUpdate testSemanticsRootUpdate = root.toUpdate();
testSemanticsRootUpdate.sendUpdateToBridge(accessibilityBridge);
@@ -1600,7 +1598,6 @@ public void itMakesPlatformViewNoImportantForAccessibility() {
View embeddedView = mock(View.class);
when(accessibilityDelegate.getPlatformViewById(1)).thenReturn(embeddedView);
- when(accessibilityDelegate.usesVirtualDisplay(1)).thenReturn(false);
TestSemanticsUpdate testSemanticsRootWithPlatformViewUpdate = rootWithPlatformView.toUpdate();
testSemanticsRootWithPlatformViewUpdate.sendUpdateToBridge(accessibilityBridge);
@@ -1615,34 +1612,6 @@ public void itMakesPlatformViewNoImportantForAccessibility() {
.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
- @Test
- public void itProducesPlatformViewNodeForVirtualDisplay() {
- PlatformViewsAccessibilityDelegate accessibilityDelegate =
- mock(PlatformViewsAccessibilityDelegate.class);
- AccessibilityViewEmbedder accessibilityViewEmbedder = mock(AccessibilityViewEmbedder.class);
- AccessibilityBridge accessibilityBridge =
- setUpBridge(
- /*rootAccessibilityView=*/ null,
- /*accessibilityChannel=*/ null,
- /*accessibilityManager=*/ null,
- /*contentResolver=*/ null,
- accessibilityViewEmbedder,
- accessibilityDelegate);
-
- TestSemanticsNode platformView = new TestSemanticsNode();
- platformView.platformViewId = 1;
-
- TestSemanticsUpdate testSemanticsUpdate = platformView.toUpdate();
- testSemanticsUpdate.sendUpdateToBridge(accessibilityBridge);
-
- View embeddedView = mock(View.class);
- when(accessibilityDelegate.getPlatformViewById(1)).thenReturn(embeddedView);
- when(accessibilityDelegate.usesVirtualDisplay(1)).thenReturn(true);
-
- accessibilityBridge.createAccessibilityNodeInfo(0);
- verify(accessibilityViewEmbedder).getRootNode(eq(embeddedView), eq(0), any(Rect.class));
- }
-
@Test
public void releaseDropsChannelMessageHandler() {
AccessibilityChannel mockChannel = mock(AccessibilityChannel.class);
diff --git a/testing/android_systrace_test.py b/testing/android_systrace_test.py
index e6c039db5ac59..2367df9ae6138 100755
--- a/testing/android_systrace_test.py
+++ b/testing/android_systrace_test.py
@@ -127,7 +127,7 @@ def main():
dest='activity_name',
action='store',
help='The activity to launch as it appears in AndroidManifest.xml, '
- 'e.g. .PlatformViewsActivity'
+ 'e.g. .TextPlatformViewActivity'
)
parser.add_argument(
'--adb-path',
diff --git a/testing/run_tests.py b/testing/run_tests.py
index c87b2f579dc3e..8afe20956aa8a 100755
--- a/testing/run_tests.py
+++ b/testing/run_tests.py
@@ -604,7 +604,7 @@ def RunAndroidTests(android_variant='android_debug_unopt', adb_path=None):
RunCmd([
systrace_test, '--adb-path', adb_path, '--apk-path', scenario_apk,
'--package-name', 'dev.flutter.scenarios', '--activity-name',
- '.PlatformViewsActivity'
+ '.TextPlatformViewActivity'
])
diff --git a/testing/scenario_app/android/BUILD.gn b/testing/scenario_app/android/BUILD.gn
index 9e3b401f61882..67e53aab8b795 100644
--- a/testing/scenario_app/android/BUILD.gn
+++ b/testing/scenario_app/android/BUILD.gn
@@ -13,19 +13,16 @@ _android_sources = [
"app/src/androidTest/java/dev/flutter/scenariosui/MemoryLeakTests.java",
"app/src/androidTest/java/dev/flutter/scenariosui/PlatformTextureUiTests.java",
"app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewUiTests.java",
- "app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithSurfaceViewUiTest.java",
- "app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithTextureViewUiTest.java",
"app/src/androidTest/java/dev/flutter/scenariosui/ScreenshotUtil.java",
"app/src/androidTest/java/dev/flutter/scenariosui/SpawnEngineTests.java",
"app/src/main/AndroidManifest.xml",
- "app/src/main/java/dev/flutter/scenarios/PlatformViewsActivity.java",
"app/src/main/java/dev/flutter/scenarios/SpawnedEngineActivity.java",
"app/src/main/java/dev/flutter/scenarios/StrictModeFlutterActivity.java",
- "app/src/main/java/dev/flutter/scenarios/SurfacePlatformViewFactory.java",
"app/src/main/java/dev/flutter/scenarios/TestActivity.java",
"app/src/main/java/dev/flutter/scenarios/TestableFlutterActivity.java",
+ "app/src/main/java/dev/flutter/scenarios/TextPlatformView.java",
+ "app/src/main/java/dev/flutter/scenarios/TextPlatformViewActivity.java",
"app/src/main/java/dev/flutter/scenarios/TextPlatformViewFactory.java",
- "app/src/main/java/dev/flutter/scenarios/TexturePlatformViewFactory.java",
"build.gradle",
]
diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/MemoryLeakTests.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/MemoryLeakTests.java
index 7fbf4bdb9b218..52f270ad65cd0 100644
--- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/MemoryLeakTests.java
+++ b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/MemoryLeakTests.java
@@ -9,7 +9,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
-import dev.flutter.scenarios.PlatformViewsActivity;
+import dev.flutter.scenarios.TextPlatformViewActivity;
import leakcanary.FailTestOnLeak;
import org.junit.Rule;
import org.junit.Test;
@@ -19,9 +19,9 @@
@LargeTest
public class MemoryLeakTests {
@Rule @NonNull
- public ActivityTestRule activityRule =
+ public ActivityTestRule activityRule =
new ActivityTestRule<>(
- PlatformViewsActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
+ TextPlatformViewActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
@Test
@FailTestOnLeak
@@ -29,7 +29,6 @@ public void platformViewHybridComposition_launchActivityFinishAndLaunchAgain() t
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.putExtra("scenario_name", "platform_view");
intent.putExtra("use_android_view", true);
- intent.putExtra("view_type", PlatformViewsActivity.TEXT_VIEW_PV);
activityRule.launchActivity(intent);
}
diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformTextureUiTests.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformTextureUiTests.java
index a4aa061f2a82c..fa0747b9dccb0 100644
--- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformTextureUiTests.java
+++ b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformTextureUiTests.java
@@ -5,12 +5,11 @@
package dev.flutter.scenariosui;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import androidx.annotation.NonNull;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
-import dev.flutter.scenarios.PlatformViewsActivity;
+import dev.flutter.scenarios.TextPlatformViewActivity;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -22,33 +21,29 @@ public class PlatformTextureUiTests {
Intent intent;
@Rule @NonNull
- public ActivityTestRule activityRule =
+ public ActivityTestRule activityRule =
new ActivityTestRule<>(
- PlatformViewsActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
-
- private static String goldName(String suffix) {
- return "PlatformTextureUiTests_" + suffix;
- }
+ TextPlatformViewActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
@Before
public void setUp() {
intent = new Intent(Intent.ACTION_MAIN);
// Render a texture.
intent.putExtra("use_android_view", false);
- intent.putExtra("view_type", PlatformViewsActivity.TEXT_VIEW_PV);
}
@Test
public void testPlatformView() throws Exception {
intent.putExtra("scenario_name", "platform_view");
- ScreenshotUtil.capture(activityRule.launchActivity(intent), goldName("testPlatformView"));
+ ScreenshotUtil.capture(
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformView");
}
@Test
public void testPlatformViewMultiple() throws Exception {
intent.putExtra("scenario_name", "platform_view_multiple");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultiple"));
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewMultiple");
}
@Test
@@ -56,64 +51,65 @@ public void testPlatformViewMultipleBackgroundForeground() throws Exception {
intent.putExtra("scenario_name", "platform_view_multiple_background_foreground");
ScreenshotUtil.capture(
activityRule.launchActivity(intent),
- goldName("testPlatformViewMultipleBackgroundForeground"));
+ "PlatformTextureUiTests_testPlatformViewMultipleBackgroundForeground");
}
@Test
public void testPlatformViewCliprect() throws Exception {
intent.putExtra("scenario_name", "platform_view_cliprect");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprect"));
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewCliprect");
}
@Test
public void testPlatformViewCliprrect() throws Exception {
intent.putExtra("scenario_name", "platform_view_cliprrect");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprrect"));
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewCliprrect");
}
@Test
public void testPlatformViewClippath() throws Exception {
intent.putExtra("scenario_name", "platform_view_clippath");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewClippath"));
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewClippath");
}
@Test
public void testPlatformViewTransform() throws Exception {
intent.putExtra("scenario_name", "platform_view_transform");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTransform"));
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewTransform");
}
@Test
public void testPlatformViewOpacity() throws Exception {
intent.putExtra("scenario_name", "platform_view_opacity");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewOpacity"));
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewOpacity");
}
@Test
public void testPlatformViewRotate() throws Exception {
intent.putExtra("scenario_name", "platform_view_rotate");
- PlatformViewsActivity activity = activityRule.launchActivity(intent);
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- ScreenshotUtil.capture(activity, goldName("testPlatformViewRotate"));
+ ScreenshotUtil.capture(
+ activityRule.launchActivity(intent), "PlatformTextureUiTests_testPlatformViewRotate");
}
@Test
public void testPlatformViewMultipleWithoutOverlays() throws Exception {
intent.putExtra("scenario_name", "platform_view_multiple_without_overlays");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultipleWithoutOverlays"));
+ activityRule.launchActivity(intent),
+ "PlatformTextureUiTests_testPlatformViewMultipleWithoutOverlays");
}
@Test
public void testPlatformViewTwoIntersectingOverlays() throws Exception {
intent.putExtra("scenario_name", "platform_view_two_intersecting_overlays");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTwoIntersectingOverlays"));
+ activityRule.launchActivity(intent),
+ "PlatformTextureUiTests_testPlatformViewTwoIntersectingOverlays");
}
@Test
@@ -121,6 +117,6 @@ public void testPlatformViewWithoutOverlayIntersection() throws Exception {
intent.putExtra("scenario_name", "platform_view_no_overlay_intersection");
ScreenshotUtil.capture(
activityRule.launchActivity(intent),
- goldName("testPlatformViewWithoutOverlayIntersection"));
+ "PlatformTextureUiTests_testPlatformViewWithoutOverlayIntersection");
}
}
diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewUiTests.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewUiTests.java
index 50dc5dfef600b..c9ef50d18cede 100644
--- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewUiTests.java
+++ b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewUiTests.java
@@ -5,12 +5,11 @@
package dev.flutter.scenariosui;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import androidx.annotation.NonNull;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
-import dev.flutter.scenarios.PlatformViewsActivity;
+import dev.flutter.scenarios.TextPlatformViewActivity;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -22,33 +21,29 @@ public class PlatformViewUiTests {
Intent intent;
@Rule @NonNull
- public ActivityTestRule activityRule =
+ public ActivityTestRule activityRule =
new ActivityTestRule<>(
- PlatformViewsActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
-
- private static String goldName(String suffix) {
- return "PlatformViewUiTests_" + suffix;
- }
+ TextPlatformViewActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
@Before
public void setUp() {
intent = new Intent(Intent.ACTION_MAIN);
// Render a native android view.
intent.putExtra("use_android_view", true);
- intent.putExtra("view_type", PlatformViewsActivity.TEXT_VIEW_PV);
}
@Test
public void testPlatformView() throws Exception {
intent.putExtra("scenario_name", "platform_view");
- ScreenshotUtil.capture(activityRule.launchActivity(intent), goldName("testPlatformView"));
+ ScreenshotUtil.capture(
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformView");
}
@Test
public void testPlatformViewMultiple() throws Exception {
intent.putExtra("scenario_name", "platform_view_multiple");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultiple"));
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewMultiple");
}
@Test
@@ -56,64 +51,65 @@ public void testPlatformViewMultipleBackgroundForeground() throws Exception {
intent.putExtra("scenario_name", "platform_view_multiple_background_foreground");
ScreenshotUtil.capture(
activityRule.launchActivity(intent),
- goldName("testPlatformViewMultipleBackgroundForeground"));
+ "PlatformViewUiTests_testPlatformViewMultipleBackgroundForeground");
}
@Test
public void testPlatformViewCliprect() throws Exception {
intent.putExtra("scenario_name", "platform_view_cliprect");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprect"));
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewCliprect");
}
@Test
public void testPlatformViewCliprrect() throws Exception {
intent.putExtra("scenario_name", "platform_view_cliprrect");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprrect"));
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewCliprrect");
}
@Test
public void testPlatformViewClippath() throws Exception {
intent.putExtra("scenario_name", "platform_view_clippath");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewClippath"));
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewClippath");
}
@Test
public void testPlatformViewTransform() throws Exception {
intent.putExtra("scenario_name", "platform_view_transform");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTransform"));
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewTransform");
}
@Test
public void testPlatformViewOpacity() throws Exception {
intent.putExtra("scenario_name", "platform_view_opacity");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewOpacity"));
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewOpacity");
}
@Test
public void testPlatformViewRotate() throws Exception {
intent.putExtra("scenario_name", "platform_view_rotate");
- PlatformViewsActivity activity = activityRule.launchActivity(intent);
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- ScreenshotUtil.capture(activity, goldName("testPlatformViewRotate"));
+ ScreenshotUtil.capture(
+ activityRule.launchActivity(intent), "PlatformViewUiTests_testPlatformViewRotate");
}
@Test
public void testPlatformViewMultipleWithoutOverlays() throws Exception {
intent.putExtra("scenario_name", "platform_view_multiple_without_overlays");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultipleWithoutOverlays"));
+ activityRule.launchActivity(intent),
+ "PlatformViewUiTests_testPlatformViewMultipleWithoutOverlays");
}
@Test
public void testPlatformViewTwoIntersectingOverlays() throws Exception {
intent.putExtra("scenario_name", "platform_view_two_intersecting_overlays");
ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTwoIntersectingOverlays"));
+ activityRule.launchActivity(intent),
+ "PlatformViewUiTests_testPlatformViewTwoIntersectingOverlays");
}
@Test
@@ -121,6 +117,6 @@ public void testPlatformViewWithoutOverlayIntersection() throws Exception {
intent.putExtra("scenario_name", "platform_view_no_overlay_intersection");
ScreenshotUtil.capture(
activityRule.launchActivity(intent),
- goldName("testPlatformViewWithoutOverlayIntersection"));
+ "PlatformViewUiTests_testPlatformViewWithoutOverlayIntersection");
}
}
diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithSurfaceViewUiTest.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithSurfaceViewUiTest.java
deleted file mode 100644
index b1fcf35d7d55d..0000000000000
--- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithSurfaceViewUiTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// 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 dev.flutter.scenariosui;
-
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import androidx.annotation.NonNull;
-import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
-import dev.flutter.scenarios.PlatformViewsActivity;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class PlatformViewWithSurfaceViewUiTest {
- Intent intent;
-
- @Rule @NonNull
- public ActivityTestRule activityRule =
- new ActivityTestRule<>(
- PlatformViewsActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
-
- private static String goldName(String suffix) {
- return "PlatformViewWithSurfaceViewUiTest_" + suffix;
- }
-
- @Before
- public void setUp() {
- intent = new Intent(Intent.ACTION_MAIN);
- // Render a texture.
- intent.putExtra("use_android_view", false);
- intent.putExtra("view_type", PlatformViewsActivity.SURFACE_VIEW_PV);
- }
-
- @Test
- public void testPlatformView() throws Exception {
- intent.putExtra("scenario_name", "platform_view");
- ScreenshotUtil.capture(activityRule.launchActivity(intent), goldName("testPlatformView"));
- }
-
- @Test
- public void testPlatformViewMultiple() throws Exception {
- intent.putExtra("scenario_name", "platform_view_multiple");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultiple"));
- }
-
- @Test
- public void testPlatformViewMultipleBackgroundForeground() throws Exception {
- intent.putExtra("scenario_name", "platform_view_multiple_background_foreground");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent),
- goldName("testPlatformViewMultipleBackgroundForeground"));
- }
-
- @Test
- public void testPlatformViewCliprect() throws Exception {
- intent.putExtra("scenario_name", "platform_view_cliprect");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprect"));
- }
-
- @Test
- public void testPlatformViewCliprrect() throws Exception {
- intent.putExtra("scenario_name", "platform_view_cliprrect");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprrect"));
- }
-
- @Test
- public void testPlatformViewClippath() throws Exception {
- intent.putExtra("scenario_name", "platform_view_clippath");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewClippath"));
- }
-
- @Test
- public void testPlatformViewTransform() throws Exception {
- intent.putExtra("scenario_name", "platform_view_transform");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTransform"));
- }
-
- @Test
- public void testPlatformViewOpacity() throws Exception {
- intent.putExtra("scenario_name", "platform_view_opacity");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewOpacity"));
- }
-
- @Test
- public void testPlatformViewRotate() throws Exception {
- intent.putExtra("scenario_name", "platform_view_rotate");
- PlatformViewsActivity activity = activityRule.launchActivity(intent);
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- ScreenshotUtil.capture(activity, goldName("testPlatformViewRotate"));
- }
-
- @Test
- public void testPlatformViewMultipleWithoutOverlays() throws Exception {
- intent.putExtra("scenario_name", "platform_view_multiple_without_overlays");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultipleWithoutOverlays"));
- }
-
- @Test
- public void testPlatformViewTwoIntersectingOverlays() throws Exception {
- intent.putExtra("scenario_name", "platform_view_two_intersecting_overlays");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTwoIntersectingOverlays"));
- }
-
- @Test
- public void testPlatformViewWithoutOverlayIntersection() throws Exception {
- intent.putExtra("scenario_name", "platform_view_no_overlay_intersection");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent),
- goldName("testPlatformViewWithoutOverlayIntersection"));
- }
-
- @Test
- public void testPlatformViewLargerThanDisplaySize() throws Exception {
- // Regression test for https://github.com/flutter/flutter/issues/2897.
- intent.putExtra("scenario_name", "platform_view_larger_than_display_size");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewLargerThanDisplaySize"));
- }
-}
diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithTextureViewUiTest.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithTextureViewUiTest.java
deleted file mode 100644
index 9a8dfd99878ee..0000000000000
--- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithTextureViewUiTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// 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 dev.flutter.scenariosui;
-
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import androidx.annotation.NonNull;
-import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
-import dev.flutter.scenarios.PlatformViewsActivity;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class PlatformViewWithTextureViewUiTest {
- Intent intent;
-
- @Rule @NonNull
- public ActivityTestRule activityRule =
- new ActivityTestRule<>(
- PlatformViewsActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
-
- private static String goldName(String suffix) {
- return "PlatformViewWithTextureViewUiTest_" + suffix;
- }
-
- @Before
- public void setUp() {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.putExtra("view_type", PlatformViewsActivity.TEXTURE_VIEW_PV);
- }
-
- @Test
- public void testPlatformView() throws Exception {
- intent.putExtra("scenario_name", "platform_view");
- ScreenshotUtil.capture(activityRule.launchActivity(intent), goldName("testPlatformView"));
- }
-
- @Test
- public void testPlatformViewMultiple() throws Exception {
- intent.putExtra("scenario_name", "platform_view_multiple");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultiple"));
- }
-
- @Test
- public void testPlatformViewMultipleBackgroundForeground() throws Exception {
- intent.putExtra("scenario_name", "platform_view_multiple_background_foreground");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent),
- goldName("testPlatformViewMultipleBackgroundForeground"));
- }
-
- @Test
- public void testPlatformViewCliprect() throws Exception {
- intent.putExtra("scenario_name", "platform_view_cliprect");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprect"));
- }
-
- @Test
- public void testPlatformViewCliprrect() throws Exception {
- intent.putExtra("scenario_name", "platform_view_cliprrect");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewCliprrect"));
- }
-
- @Test
- public void testPlatformViewClippath() throws Exception {
- intent.putExtra("scenario_name", "platform_view_clippath");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewClippath"));
- }
-
- @Test
- public void testPlatformViewTransform() throws Exception {
- intent.putExtra("scenario_name", "platform_view_transform");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTransform"));
- }
-
- @Test
- public void testPlatformViewOpacity() throws Exception {
- intent.putExtra("scenario_name", "platform_view_opacity");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewOpacity"));
- }
-
- @Test
- public void testPlatformViewRotate() throws Exception {
- intent.putExtra("scenario_name", "platform_view_rotate");
- PlatformViewsActivity activity = activityRule.launchActivity(intent);
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- ScreenshotUtil.capture(activity, goldName("testPlatformViewRotate"));
- }
-
- @Test
- public void testPlatformViewMultipleWithoutOverlays() throws Exception {
- intent.putExtra("scenario_name", "platform_view_multiple_without_overlays");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewMultipleWithoutOverlays"));
- }
-
- @Test
- public void testPlatformViewTwoIntersectingOverlays() throws Exception {
- intent.putExtra("scenario_name", "platform_view_two_intersecting_overlays");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent), goldName("testPlatformViewTwoIntersectingOverlays"));
- }
-
- @Test
- public void testPlatformViewWithoutOverlayIntersection() throws Exception {
- intent.putExtra("scenario_name", "platform_view_no_overlay_intersection");
- ScreenshotUtil.capture(
- activityRule.launchActivity(intent),
- goldName("testPlatformViewWithoutOverlayIntersection"));
- }
-}
diff --git a/testing/scenario_app/android/app/src/main/AndroidManifest.xml b/testing/scenario_app/android/app/src/main/AndroidManifest.xml
index 09f440887c41d..bbd62a00015cc 100644
--- a/testing/scenario_app/android/app/src/main/AndroidManifest.xml
+++ b/testing/scenario_app/android/app/src/main/AndroidManifest.xml
@@ -9,7 +9,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
() {
- @Nullable
- @Override
- public ByteBuffer encodeMessage(@Nullable Object o) {
- if (o instanceof String) {
- return StringCodec.INSTANCE.encodeMessage((String) o);
- }
- return null;
- }
-
- @Nullable
- @Override
- public Object decodeMessage(@Nullable ByteBuffer byteBuffer) {
- return StringCodec.INSTANCE.decodeMessage(byteBuffer);
- }
- });
- }
-
- @SuppressWarnings("unchecked")
- @Override
- @NonNull
- public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
- return new SurfacePlatformView(context);
- }
-
- private static class SurfacePlatformView implements PlatformView {
- static String TAG = "SurfacePlatformView";
-
- final SurfaceView surfaceView;
-
- @SuppressWarnings("unchecked")
- SurfacePlatformView(@NonNull final Context context) {
- surfaceView = new SurfaceView(context);
- surfaceView
- .getHolder()
- .addCallback(
- new SurfaceHolder.Callback() {
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.i(TAG, "surfaceCreated");
- final Surface surface = holder.getSurface();
- final Canvas canvas = surface.lockHardwareCanvas();
- canvas.drawColor(Color.WHITE);
-
- final Paint paint = new Paint();
- paint.setColor(Color.RED);
- canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 20, paint);
- surface.unlockCanvasAndPost(canvas);
- }
-
- @Override
- public void surfaceChanged(
- SurfaceHolder holder, int format, int width, int height) {
- Log.i(TAG, "surfaceChanged");
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.i(TAG, "surfaceDestroyed");
- }
- });
- }
-
- @Override
- @NonNull
- public View getView() {
- return surfaceView;
- }
-
- @Override
- public void dispose() {}
- }
-}
diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java
index 8837035e0ebe0..80323a9a41944 100644
--- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java
+++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java
@@ -84,7 +84,6 @@ public void onFlutterUiDisplayed() {
test.put("name", "animated_color_square");
}
test.put("use_android_view", launchIntent.getBooleanExtra("use_android_view", false));
- test.put("view_type", launchIntent.getStringExtra("view_type"));
getScenarioParams(test);
channel.invokeMethod("set_scenario", test);
}
diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformView.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformView.java
new file mode 100644
index 0000000000000..e834913d0eac4
--- /dev/null
+++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformView.java
@@ -0,0 +1,46 @@
+// 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 dev.flutter.scenarios;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.Choreographer;
+import android.view.View;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import io.flutter.plugin.platform.PlatformView;
+
+public class TextPlatformView implements PlatformView {
+ final TextView textView;
+
+ @SuppressWarnings("unchecked")
+ TextPlatformView(@NonNull final Context context, int id, @Nullable String params) {
+ textView = new TextView(context);
+ textView.setTextSize(72);
+ textView.setBackgroundColor(Color.rgb(255, 255, 255));
+ textView.setText(params);
+
+ // Investigate why this is needed to pass some gold tests.
+ Choreographer.getInstance()
+ .postFrameCallbackDelayed(
+ new Choreographer.FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ textView.invalidate();
+ }
+ },
+ 500);
+ }
+
+ @Override
+ @NonNull
+ public View getView() {
+ return textView;
+ }
+
+ @Override
+ public void dispose() {}
+}
diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewActivity.java
new file mode 100644
index 0000000000000..b1cfcf5354b66
--- /dev/null
+++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewActivity.java
@@ -0,0 +1,21 @@
+// 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 dev.flutter.scenarios;
+
+import androidx.annotation.NonNull;
+import io.flutter.embedding.engine.FlutterEngine;
+
+public class TextPlatformViewActivity extends TestActivity {
+ static final String TAG = "Scenarios";
+
+ @Override
+ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
+ super.configureFlutterEngine(flutterEngine);
+ flutterEngine
+ .getPlatformViewsController()
+ .getRegistry()
+ .registerViewFactory("scenarios/textPlatformView", new TextPlatformViewFactory());
+ }
+}
diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewFactory.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewFactory.java
index 93806dea105f5..3b660a0089c05 100644
--- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewFactory.java
+++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TextPlatformViewFactory.java
@@ -5,10 +5,6 @@
package dev.flutter.scenarios;
import android.content.Context;
-import android.graphics.Color;
-import android.view.Choreographer;
-import android.view.View;
-import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.MessageCodec;
@@ -45,36 +41,4 @@ public PlatformView create(@NonNull Context context, int id, @Nullable Object ar
String params = (String) args;
return new TextPlatformView(context, id, params);
}
-
- private static class TextPlatformView implements PlatformView {
- final TextView textView;
-
- @SuppressWarnings("unchecked")
- TextPlatformView(@NonNull final Context context, int id, @Nullable String params) {
- textView = new TextView(context);
- textView.setTextSize(72);
- textView.setBackgroundColor(Color.WHITE);
- textView.setText(params);
-
- // Investigate why this is needed to pass some gold tests.
- Choreographer.getInstance()
- .postFrameCallbackDelayed(
- new Choreographer.FrameCallback() {
- @Override
- public void doFrame(long frameTimeNanos) {
- textView.invalidate();
- }
- },
- 500);
- }
-
- @Override
- @NonNull
- public View getView() {
- return textView;
- }
-
- @Override
- public void dispose() {}
- }
}
diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TexturePlatformViewFactory.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TexturePlatformViewFactory.java
deleted file mode 100644
index e79dd16ccb4c5..0000000000000
--- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TexturePlatformViewFactory.java
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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 dev.flutter.scenarios;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.SurfaceTexture;
-import android.view.Choreographer;
-import android.view.TextureView;
-import android.view.View;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import io.flutter.Log;
-import io.flutter.plugin.common.MessageCodec;
-import io.flutter.plugin.common.StringCodec;
-import io.flutter.plugin.platform.PlatformView;
-import io.flutter.plugin.platform.PlatformViewFactory;
-import java.nio.ByteBuffer;
-
-@TargetApi(23)
-public final class TexturePlatformViewFactory extends PlatformViewFactory {
- TexturePlatformViewFactory() {
- super(
- new MessageCodec() {
- @Nullable
- @Override
- public ByteBuffer encodeMessage(@Nullable Object o) {
- if (o instanceof String) {
- return StringCodec.INSTANCE.encodeMessage((String) o);
- }
- return null;
- }
-
- @Nullable
- @Override
- public Object decodeMessage(@Nullable ByteBuffer byteBuffer) {
- return StringCodec.INSTANCE.decodeMessage(byteBuffer);
- }
- });
- }
-
- @SuppressWarnings("unchecked")
- @Override
- @NonNull
- public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
- return new TexturePlatformView(context);
- }
-
- private static class TexturePlatformView implements PlatformView {
- static String TAG = "TexturePlatformView";
-
- final TextureView textureView;
-
- @SuppressWarnings("unchecked")
- TexturePlatformView(@NonNull final Context context) {
- textureView = new TextureView(context);
- textureView.setSurfaceTextureListener(
- new TextureView.SurfaceTextureListener() {
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- Log.i(TAG, "onSurfaceTextureAvailable");
- final Canvas canvas = textureView.lockCanvas();
- canvas.drawColor(Color.WHITE);
-
- final Paint paint = new Paint();
- paint.setColor(Color.GREEN);
- canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 20, paint);
- textureView.unlockCanvasAndPost(canvas);
- Choreographer.getInstance()
- .postFrameCallbackDelayed(
- new Choreographer.FrameCallback() {
- @Override
- public void doFrame(long frameTimeNanos) {
- textureView.invalidate();
- }
- },
- 500);
- }
-
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- Log.i(TAG, "onSurfaceTextureDestroyed");
- return true;
- }
-
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
- Log.i(TAG, "onSurfaceTextureSizeChanged");
- }
-
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- Log.i(TAG, "onSurfaceTextureUpdated");
- }
- });
- }
-
- @Override
- @NonNull
- public View getView() {
- return textureView;
- }
-
- @Override
- public void dispose() {}
- }
-}
diff --git a/testing/scenario_app/lib/src/platform_view.dart b/testing/scenario_app/lib/src/platform_view.dart
index 8f1704e6ef6a2..4f99d01244933 100644
--- a/testing/scenario_app/lib/src/platform_view.dart
+++ b/testing/scenario_app/lib/src/platform_view.dart
@@ -114,42 +114,6 @@ class PlatformViewNoOverlayIntersectionScenario extends Scenario
}
}
-
-/// A platform view that is larger than the display size.
-/// This is only applicable on Android while using virtual displays.
-/// Related issue: https://github.com/flutter/flutter/issues/2897.
-class PlatformViewLargerThanDisplaySize extends Scenario
- with _BasePlatformViewScenarioMixin {
- /// Creates the PlatformView scenario.
- ///
- /// The [dispatcher] parameter must not be null.
- PlatformViewLargerThanDisplaySize(
- PlatformDispatcher dispatcher, {
- required this.id,
- }) : assert(dispatcher != null),
- super(dispatcher);
-
- /// The platform view identifier.
- final int id;
-
- @override
- void onBeginFrame(Duration duration) {
- final SceneBuilder builder = SceneBuilder();
-
- addPlatformView(
- id,
- dispatcher: dispatcher,
- sceneBuilder: builder,
- width: 15000,
- height: 60000,
- );
-
- finishBuilder(
- builder,
- );
- }
-}
-
/// A simple platform view with an overlay that partially intersects with the platform view.
class PlatformViewPartialIntersectionScenario extends Scenario
with _BasePlatformViewScenarioMixin {
@@ -1085,12 +1049,7 @@ void addPlatformView(
double height = 500,
String viewType = 'scenarios/textPlatformView',
}) {
- if (scenarioParams['view_type'] is String) {
- viewType = scenarioParams['view_type'];
- }
-
final String platformViewKey = '$viewType-$id';
-
if (_createdPlatformViews.containsKey(platformViewKey)) {
addPlatformViewToSceneBuilder(
id,
@@ -1101,10 +1060,9 @@ void addPlatformView(
);
return;
}
-
bool usesAndroidHybridComposition = false;
- if (scenarioParams['use_android_view'] is bool) {
- usesAndroidHybridComposition = scenarioParams['use_android_view'];
+ if (scenarioParams['use_android_view'] != null) {
+ usesAndroidHybridComposition = scenarioParams['use_android_view'] as bool;
}
const int _valueTrue = 1;
@@ -1121,9 +1079,9 @@ void addPlatformView(
_valueMap,
if (Platform.isIOS) 3, // 3 entries in map for iOS.
if (Platform.isAndroid && !usesAndroidHybridComposition)
- 6, // 6 entries in map for texture on Android.
+ 6, // 6 entries in map for virtual displays on Android.
if (Platform.isAndroid && usesAndroidHybridComposition)
- 5, // 5 entries in map for hybrid composition on Android.
+ 5, // 5 entries in map for Android views.
_valueString,
'id'.length,
...utf8.encode('id'),
diff --git a/testing/scenario_app/lib/src/scenario.dart b/testing/scenario_app/lib/src/scenario.dart
index 6e66c862280e9..f0e9267dae1a1 100644
--- a/testing/scenario_app/lib/src/scenario.dart
+++ b/testing/scenario_app/lib/src/scenario.dart
@@ -26,13 +26,13 @@ abstract class Scenario {
///
/// See [PlatformDispatcher.onDrawFrame] for more details.
void onDrawFrame() {
- if (_didScheduleScreenshot) {
- dispatcher.sendPlatformMessage('take_screenshot', null, null);
- return;
- }
- Future.delayed(const Duration(seconds: 2), () {
- _didScheduleScreenshot = true;
- dispatcher.scheduleFrame();
+ Future.delayed(const Duration(seconds: 1), () {
+ if (_didScheduleScreenshot) {
+ dispatcher.sendPlatformMessage('take_screenshot', null, null);
+ } else {
+ _didScheduleScreenshot = true;
+ dispatcher.scheduleFrame();
+ }
});
}
diff --git a/testing/scenario_app/lib/src/scenarios.dart b/testing/scenario_app/lib/src/scenarios.dart
index 99304222bd311..95554d8a796f9 100644
--- a/testing/scenario_app/lib/src/scenarios.dart
+++ b/testing/scenario_app/lib/src/scenarios.dart
@@ -24,7 +24,6 @@ Map _scenarios = {
'locale_initialization': () => LocaleInitialization(PlatformDispatcher.instance),
'platform_view': () => PlatformViewScenario(PlatformDispatcher.instance, id: _viewId++),
'platform_view_no_overlay_intersection': () => PlatformViewNoOverlayIntersectionScenario(PlatformDispatcher.instance, id: _viewId++),
- 'platform_view_larger_than_display_size': () => PlatformViewLargerThanDisplaySize(PlatformDispatcher.instance, id: _viewId++),
'platform_view_partial_intersection': () => PlatformViewPartialIntersectionScenario(PlatformDispatcher.instance, id: _viewId++),
'platform_view_two_intersecting_overlays': () => PlatformViewTwoIntersectingOverlaysScenario(PlatformDispatcher.instance, id: _viewId++),
'platform_view_one_overlay_two_intersecting_overlays': () => PlatformViewOneOverlayTwoIntersectingOverlaysScenario(PlatformDispatcher.instance, id: _viewId++),
diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml
index 41e7e89b6a6f4..a3aef00b2236b 100644
--- a/tools/android_lint/baseline.xml
+++ b/tools/android_lint/baseline.xml
@@ -100,15 +100,4 @@
column="18"/>
-
-
-
-
diff --git a/tools/android_lint/project.xml b/tools/android_lint/project.xml
index 583b66491985d..38b9f65eebcb8 100644
--- a/tools/android_lint/project.xml
+++ b/tools/android_lint/project.xml
@@ -107,9 +107,7 @@
-
-