Revert "[ios][pv] accept/reject gesture based on hitTest (with new wi… (#179895)

…dget API) (#179659)"

This reverts commit 87d15897b220d62339c77260b429c645515b09e7.

*Replace this paragraph with a description of what this PR is changing
or adding, and why. Consider including before/after screenshots.*

We found a quick fix ([PR
here](https://github.com/flutter/flutter/pull/179908)), so revert it and
revisit `hitTest` later.

*List which issues are fixed by this PR. You must list at least one
issue. An issue is not required if the PR fixes something trivial like a
typo.*

NA

*If you had to change anything in the [flutter/tests] repo, include a
link to the migration guide as per the [breaking change policy].*

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
hellohuanlin 2025-12-16 11:35:46 -08:00 committed by GitHub
parent f51f445221
commit 8dedaeaf41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 66 additions and 1055 deletions

View File

@ -151,7 +151,6 @@ source_set("ui") {
"window/platform_message_response_dart.h",
"window/platform_message_response_dart_port.cc",
"window/platform_message_response_dart_port.h",
"window/point_data.h",
"window/pointer_data.cc",
"window/pointer_data.h",
"window/pointer_data_packet.cc",

View File

@ -307,18 +307,6 @@ void _dispatchPointerDataPacket(ByteData packet) {
PlatformDispatcher.instance._dispatchPointerDataPacket(packet);
}
// TODO(hellohuanlin): rename function to _onHitTest.
// See: https://github.com/flutter/flutter/issues/179762.
@pragma('vm:entry-point')
bool _platformViewShouldAcceptTouch(int viewId, double x, double y) {
assert(PlatformDispatcher.instance._views.containsKey(viewId), 'View $viewId does not exist.');
final FlutterView view = PlatformDispatcher.instance._views[viewId]!;
final offset = Offset(x, y);
final request = HitTestRequest(view: view, offset: offset);
final HitTestResponse response = PlatformDispatcher.instance._hitTest(request);
return response.isPlatformView;
}
@pragma('vm:entry-point')
void _dispatchSemanticsAction(int viewId, int nodeId, int action, ByteData? args) {
PlatformDispatcher.instance._dispatchSemanticsAction(viewId, nodeId, action, args);
@ -429,30 +417,6 @@ void _invoke3<A1, A2, A3>(
}
}
/// Invokes [callback] inside the given [zone] passing it [arg1],
/// and returns a nullable result of the specified type.
///
/// The 1 in the name refers to the number of arguments expected by
/// the callback (and thus passed to this function, in addition to the
/// callback itself and the zone in which the callback is executed).
R? _invoke1WithReturn<A1, R>(R Function(A1 a1)? callback, Zone zone, A1 arg1) {
if (callback == null) {
return null;
}
if (identical(zone, Zone.current)) {
return callback(arg1);
} else {
return runZonedGuarded(
() {
return callback(arg1);
},
(e, s) {
zone.handleUncaughtError(e, s);
},
);
}
}
bool _isLoopback(String host) {
if (host.isEmpty) {
return false;

View File

@ -43,9 +43,6 @@ typedef KeyDataCallback = bool Function(KeyData data);
/// Signature for [PlatformDispatcher.onSemanticsActionEvent].
typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action);
/// Signature for [PlatformDispatcher.onHitTest].
typedef HitTestCallback = HitTestResponse Function(HitTestRequest request);
/// Signature for responses to platform messages.
///
/// Used as a parameter to [PlatformDispatcher.sendPlatformMessage] and
@ -1391,18 +1388,6 @@ class PlatformDispatcher {
_onSemanticsActionEventZone = Zone.current;
}
/// A callback invoked when platform wants to hit test a [FlutterView].
///
/// For example, this is used by iOS to determine if a gesture hits a
/// [UIKitView].
HitTestCallback? get onHitTest => _onHitTest;
HitTestCallback? _onHitTest;
Zone _onHitTestZone = Zone.root;
set onHitTest(HitTestCallback? callback) {
_onHitTest = callback;
_onHitTestZone = Zone.current;
}
// Called from the engine via hooks.dart.
void _updateFrameData(int frameNumber) {
final FrameData previous = _frameData;
@ -1440,15 +1425,6 @@ class PlatformDispatcher {
);
}
HitTestResponse _hitTest(HitTestRequest request) {
return _invoke1WithReturn<HitTestRequest, HitTestResponse>(
onHitTest,
_onHitTestZone,
request,
) ??
HitTestResponse.empty;
}
ErrorCallback? _onError;
Zone? _onErrorZone;
@ -3213,42 +3189,3 @@ enum ViewFocusDirection {
/// This is typically result of the user pressing shift + tab.
backward,
}
/// A request to evaluate the content of a view at a specific position.
///
/// See also:
///
/// * [PlatformDispatcher.onHitTest], the callback that the platform
/// invokes to hit test a view at a specific position.
/// * [HitTestResponse], the result of a hit test request.
class HitTestRequest {
/// Creates a hit test request.
const HitTestRequest({required this.view, required this.offset});
/// The view that should be hit tested.
final FlutterView view;
/// The position in the [view] that should be hit tested.
final Offset offset;
}
/// The results of hit testing a view at a specific position.
///
/// See also:
///
/// * [PlatformDispatcher.onHitTest], the callback that the platform
/// invokes to hit test a view at a specific position.
/// * [HitTestRequest], the request to hit test a view at a specific position.
class HitTestResponse {
/// Creates a hit test response.
const HitTestResponse({required this.isPlatformView});
/// A response with no hit entries.
static const HitTestResponse empty = HitTestResponse(isPlatformView: false);
/// Whether the first hit test entry is a platform view.
///
/// The first hit test entry is typically the child that is
/// visually "on top" (i.e., paints later).
final bool isPlatformView;
}

View File

@ -77,12 +77,6 @@ void PlatformConfiguration::DidCreateIsolate() {
dispatch_pointer_data_packet_.Set(
tonic::DartState::Current(),
Dart_GetField(library, tonic::ToDart("_dispatchPointerDataPacket")));
// The embedded native view (e.g. UIView on iOS) is called "platform view"
// on framework side, but "embedded native view" on engine side. On the other
// hand, "platform view" refers to the whole flutter view on engine side.
embedded_native_view_should_accept_touch_.Set(
tonic::DartState::Current(),
Dart_GetField(library, tonic::ToDart("_platformViewShouldAcceptTouch")));
dispatch_semantics_action_.Set(
tonic::DartState::Current(),
Dart_GetField(library, tonic::ToDart("_dispatchSemanticsAction")));
@ -394,26 +388,6 @@ void PlatformConfiguration::DispatchPointerDataPacket(
tonic::DartInvoke(dispatch_pointer_data_packet_.Get(), {data_handle}));
}
bool PlatformConfiguration::EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) {
std::shared_ptr<tonic::DartState> dart_state =
embedded_native_view_should_accept_touch_.dart_state().lock();
if (!dart_state) {
return false;
}
tonic::DartState::Scope scope(dart_state);
Dart_Handle dart_result = tonic::DartInvoke(
embedded_native_view_should_accept_touch_.Get(),
{tonic::ToDart(view_id), tonic::ToDart(touch_began_location.x),
tonic::ToDart(touch_began_location.y)});
if (tonic::CheckAndHandleError(dart_result)) {
return false;
}
return tonic::DartConverter<bool>::FromDart(dart_result);
}
void PlatformConfiguration::DispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,

View File

@ -15,7 +15,6 @@
#include "flutter/fml/time/time_point.h"
#include "flutter/lib/ui/semantics/semantics_update.h"
#include "flutter/lib/ui/window/platform_message_response.h"
#include "flutter/lib/ui/window/point_data.h"
#include "flutter/lib/ui/window/pointer_data_packet.h"
#include "flutter/lib/ui/window/view_focus.h"
#include "flutter/lib/ui/window/viewport_metrics.h"
@ -462,22 +461,6 @@ class PlatformConfiguration final {
///
void DispatchPointerDataPacket(const PointerDataPacket& packet);
//----------------------------------------------------------------------------
/// @brief Requests from the engine if an embedded native view should
/// accept touch at a given touch location.
///
///
/// @param[in] view_id The identifier of the flutter view that
/// hosts the embedded view.
/// @param[in] touch_began_location The touch began location.
///
/// @return true if the embedded view should accept touch; false
/// otherwise.
///
bool EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location);
//----------------------------------------------------------------------------
/// @brief Notifies the framework that the embedder encountered an
/// accessibility related action on the specified node. This call
@ -601,7 +584,6 @@ class PlatformConfiguration final {
tonic::DartPersistentValue update_accessibility_features_;
tonic::DartPersistentValue dispatch_platform_message_;
tonic::DartPersistentValue dispatch_pointer_data_packet_;
tonic::DartPersistentValue embedded_native_view_should_accept_touch_;
tonic::DartPersistentValue dispatch_semantics_action_;
tonic::DartPersistentValue begin_frame_;
tonic::DartPersistentValue draw_frame_;

View File

@ -1,17 +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.
#ifndef FLUTTER_LIB_UI_WINDOW_POINT_DATA_H_
#define FLUTTER_LIB_UI_WINDOW_POINT_DATA_H_
namespace flutter {
// Represents a point on screen.
struct PointData {
double x;
double y;
};
} // namespace flutter
#endif // FLUTTER_LIB_UI_WINDOW_POINT_DATA_H_

View File

@ -11,7 +11,6 @@ typedef TimingsCallback = void Function(List<FrameTiming> timings);
typedef PointerDataPacketCallback = void Function(PointerDataPacket packet);
typedef KeyDataCallback = bool Function(KeyData data);
typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action);
typedef HitTestCallback = HitTestResponse Function(HitTestRequest request);
typedef PlatformMessageResponseCallback = void Function(ByteData? data);
typedef PlatformMessageCallback =
void Function(String name, ByteData? data, PlatformMessageResponseCallback? callback);
@ -155,9 +154,6 @@ abstract class PlatformDispatcher {
SemanticsActionEventCallback? get onSemanticsActionEvent;
set onSemanticsActionEvent(SemanticsActionEventCallback? callback);
HitTestCallback? get onHitTest;
set onHitTest(HitTestCallback? callback);
ErrorCallback? get onError;
set onError(ErrorCallback? callback);
@ -605,15 +601,3 @@ final class ViewFocusEvent {
enum ViewFocusState { unfocused, focused }
enum ViewFocusDirection { undefined, forward, backward }
class HitTestRequest {
const HitTestRequest({required this.view, required this.offset});
final FlutterView view;
final Offset offset;
}
class HitTestResponse {
const HitTestResponse({required this.isPlatformView});
static const HitTestResponse empty = HitTestResponse(isPlatformView: false);
final bool isPlatformView;
}

View File

@ -1368,13 +1368,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
_onSemanticsActionEventZone = Zone.current;
}
/// A callback invoked when platform wants to hit test a [FlutterView].
///
/// For example, this is used by iOS to determine if a gesture hits a
/// [UIKitView].
@override
ui.HitTestCallback? onHitTest;
/// Engine code should use this method instead of the callback directly.
/// Otherwise zones won't work properly.
void invokeOnSemanticsAction(int viewId, int nodeId, ui.SemanticsAction action, ByteData? args) {

View File

@ -374,18 +374,6 @@ bool RuntimeController::DispatchPointerDataPacket(
return false;
}
bool RuntimeController::EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) {
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
TRACE_EVENT0("flutter",
"RuntimeController::EmbeddedNativeViewShouldAcceptTouch");
return platform_configuration->EmbeddedNativeViewShouldAcceptTouch(
view_id, touch_began_location);
}
return false;
}
bool RuntimeController::DispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,

View File

@ -18,7 +18,6 @@
#include "flutter/lib/ui/text/font_collection.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/lib/ui/window/platform_configuration.h"
#include "flutter/lib/ui/window/point_data.h"
#include "flutter/lib/ui/window/pointer_data_packet.h"
#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
#include "flutter/lib/ui/window/view_focus.h"
@ -477,23 +476,6 @@ class RuntimeController : public PlatformConfigurationClient,
///
bool DispatchPointerDataPacket(const PointerDataPacket& packet);
// TODO(hellohuanlin): we should make make this a generic HitTest API.
//----------------------------------------------------------------------------
/// @brief Requests from the engine if an embedded native view should
/// accept touch at a given touch location.
///
///
/// @param[in] view_id The identifier of the flutter view that
/// hosts the embedded view.
/// @param[in] touch_began_location The touch began location.
///
/// @return true if the embedded view should accept touch; false
/// otherwise.
///
bool EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location);
//----------------------------------------------------------------------------
/// @brief Dispatch the semantics action to the specified accessibility
/// node.

View File

@ -476,16 +476,6 @@ void Engine::DispatchPointerDataPacket(
pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
}
bool Engine::EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) {
if (runtime_controller_) {
return runtime_controller_->EmbeddedNativeViewShouldAcceptTouch(
view_id, touch_began_location);
}
return false;
}
void Engine::DispatchSemanticsAction(int64_t view_id,
int node_id,
SemanticsAction action,

View File

@ -829,22 +829,6 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id);
//----------------------------------------------------------------------------
/// @brief Requests from the engine if an embedded native view should
/// accept touch at a given touch location.
///
///
/// @param[in] view_id The identifier of the flutter view that
/// hosts the embedded view.
/// @param[in] touch_began_location The touch began location.
///
/// @return true if the embedded view should accept touch; false
/// otherwise.
///
bool EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location);
//----------------------------------------------------------------------------
/// @brief Notifies the engine that the embedder encountered an
/// accessibility related action on the specified node. This call

View File

@ -35,13 +35,6 @@ void PlatformView::DispatchPointerDataPacket(
delegate_.OnPlatformViewDispatchPointerDataPacket(std::move(packet));
}
bool PlatformView::EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) {
return delegate_.OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
view_id, touch_began_location);
}
void PlatformView::DispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,

View File

@ -182,21 +182,6 @@ class PlatformView {
virtual void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) = 0;
//--------------------------------------------------------------------------
/// @brief Requests the delegate if an embedded native view should
/// accept touch at a given touch location.
///
/// @param[in] view_id The identifier of the flutter view
/// that hosts the embedded view.
/// @param[in] touch_began_location The touch began location.
///
/// @return true if the embedded view should accept touch; false
/// otherwise.
///
virtual bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) = 0;
//--------------------------------------------------------------------------
/// @brief Notifies the delegate that the platform view has encountered
/// an accessibility related action on the specified node. This
@ -752,22 +737,6 @@ class PlatformView {
///
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet);
//----------------------------------------------------------------------------
/// @brief Requests from the engine if an embedded view should accept
/// touch at a given touch location.
///
///
/// @param[in] view_id The identifier of the flutter view that
/// hosts the embedded view.
/// @param[in] touch_began_location The touch began location.
///
/// @return true if the embedded view should accept touch; false
/// otherwise.
///
bool EmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location);
//--------------------------------------------------------------------------
/// @brief Used by the embedder to specify a texture that it wants the
/// rasterizer to composite within the Flutter layer tree. All

View File

@ -1226,17 +1226,6 @@ void Shell::OnPlatformViewDispatchPointerDataPacket(
next_pointer_flow_id_++;
}
bool Shell::OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (engine_) {
return engine_->EmbeddedNativeViewShouldAcceptTouch(view_id,
touch_began_location);
}
return false;
}
// |PlatformView::Delegate|
void Shell::OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,

View File

@ -608,10 +608,6 @@ class Shell final : public PlatformView::Delegate,
void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) override;
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,

View File

@ -142,11 +142,6 @@ class MockPlatformViewDelegate : public PlatformView::Delegate {
(std::unique_ptr<PointerDataPacket> packet),
(override));
MOCK_METHOD(bool,
OnPlatformViewEmbeddedNativeViewShouldAcceptTouch,
(int64_t view_id, const flutter::PointData touch_began_location),
(override));
MOCK_METHOD(void,
OnPlatformViewDispatchSemanticsAction,
(int64_t view_id,

View File

@ -268,17 +268,6 @@ typedef enum {
* but never recognizing the gesture (and never invoking actions).
*/
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded,
/**
* Flutter blocks all the touch event callbacks and UIGestureRecognizers on the platform view as
* soon as it decides they should be blocked.
*
* This is similar to FlutterPlatformViewGestureRecognizersBlockingPolicyEager. However,
* internally it performs hit test rather than a blocking gesture recognizer. This addresses
* a few bugs related to WKWebView being untappable. See
* https://github.com/flutter/flutter/issues/175099.
*/
FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly,
// NOLINTEND(readability-identifier-naming)
} FlutterPlatformViewGestureRecognizersBlockingPolicy;

View File

@ -386,14 +386,6 @@ NSString* const kFlutterApplicationRegistrarKey = @"io.flutter.flutter.applicati
self.platformView->DispatchPointerDataPacket(std::move(packet));
}
- (BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(flutter::PointData)location
viewId:(uint64_t)viewId {
if (!self.platformView) {
return NO;
}
return self.platformView->EmbeddedNativeViewShouldAcceptTouch(viewId, location);
}
- (void)installFirstFrameCallback:(void (^)(void))block {
if (!self.platformView) {
return;

View File

@ -35,11 +35,6 @@ class FakeDelegate : public PlatformView::Delegate {
void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) override {}
void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet) override {
}
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) override {
return false;
}
void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,

View File

@ -37,8 +37,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics;
- (void)dispatchPointerDataPacket:(std::unique_ptr<flutter::PointerDataPacket>)packet;
- (BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(flutter::PointData)location
viewId:(uint64_t)viewId;
- (fml::RefPtr<fml::TaskRunner>)platformTaskRunner;
- (fml::RefPtr<fml::TaskRunner>)uiTaskRunner;

View File

@ -511,9 +511,8 @@ static BOOL _preparedOnce = NO;
@interface FlutterTouchInterceptingView ()
@property(nonatomic, weak, readonly) UIView* embeddedView;
@property(nonatomic, weak, readonly) UIViewController<FlutterViewResponder>* flutterViewController;
@property(nonatomic, weak, readonly) FlutterPlatformViewsController* platformViewsController;
@property(nonatomic, readonly) FlutterDelayingGestureRecognizer* delayingRecognizer;
@property(nonatomic, readonly) FlutterPlatformViewGestureRecognizersBlockingPolicy blockingPolicy;
@end
@implementation FlutterTouchInterceptingView
@ -525,8 +524,6 @@ static BOOL _preparedOnce = NO;
if (self) {
self.multipleTouchEnabled = YES;
_embeddedView = embeddedView;
_platformViewsController = platformViewsController;
_flutterViewController = platformViewsController.flutterViewController;
embeddedView.autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
@ -542,12 +539,7 @@ static BOOL _preparedOnce = NO;
forwardingRecognizer:forwardingRecognizer];
_blockingPolicy = blockingPolicy;
// For hit test, don't block gestures using delaying recognizer. However, we still
// forward touches so Flutter can process it in its gesture arena (e.g. dismiss a
// drop-down menu when tapping outside of the menu but inside the platform view).
if (blockingPolicy != FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly) {
[self addGestureRecognizer:_delayingRecognizer];
}
[self addGestureRecognizer:_delayingRecognizer];
[self addGestureRecognizer:forwardingRecognizer];
}
return self;
@ -586,33 +578,8 @@ static BOOL _preparedOnce = NO;
return NO;
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
if (_blockingPolicy == FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly) {
// In release mode, FlutterTouchInterceptingView's init is called before flutterViewController
// is set on platformViewsController.
if (self.flutterViewController == nil) {
_flutterViewController = self.platformViewsController.flutterViewController;
}
CGPoint pointInFlutterView = [self convertPoint:point toView:self.flutterViewController.view];
// Consult the framework on if the touch should be handled by the platform view.
// If NO, the touch is handled by a Flutter widget and should be blocked (by returning self).
// If YES, the touch should continue to the standard hit-testing (through super), allowing the
// touch to be delivered to the underlying native platform view or one of its subviews.
if (![self.flutterViewController
platformViewShouldAcceptTouchAtTouchBeganLocation:pointInFlutterView]) {
return self;
}
}
return [super hitTest:point withEvent:event];
}
- (void)blockGesture {
switch (_blockingPolicy) {
case FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly:
// No-op. Handled by hit test.
break;
case FlutterPlatformViewGestureRecognizersBlockingPolicyEager:
// We block all other gesture recognizers immediately in this policy.
self.delayingRecognizer.state = UIGestureRecognizerStateEnded;
@ -769,12 +736,6 @@ static BOOL _preparedOnce = NO;
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
FML_DCHECK(_currentTouchPointersCount >= 0);
if (_currentTouchPointersCount == 0) {
// TODO(hellohuanlin): the following comment is likely incorrect and very misleading.
// The actual reason is a race condition when platform view is created before
// flutterViewController is set in platformViewsController in debug mode. We should clean up the
// code, either fix the race condition, or make flutterViewController a computed property rather
// than a stored property.
//
// At the start of each gesture sequence, we reset the `_flutterViewController`,
// so that all the touch events in the same sequence are forwarded to the same
// `_flutterViewController`.

View File

@ -10,10 +10,8 @@
#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
#include "flutter/flow/surface_frame.h"
#include "flutter/flow/view_slicer.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/synchronization/count_down_latch.h"
#import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.h"
@ -26,11 +24,6 @@ using flutter::DlRoundRect;
static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5;
static NSString* const kGestureBlockingPolicyEagerValue = @"eager";
static NSString* const kGestureBlockingPolicyWaitUntilTouchesEndedValue = @"waitUntilTouchesEnded";
static NSString* const kGestureBlockingPolicyFallbackToPluginDefault = @"fallbackToPluginDefault";
static NSString* const kGestureBlockingPolicyTouchBlockingOnly = @"touchBlockingOnly";
struct LayerData {
DlRect rect;
int64_t view_id;
@ -110,7 +103,7 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) {
// The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view.
@property(nonatomic, readonly)
std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>&
gestureRecognizersBlockingPoliciesByType;
gestureRecognizersBlockingPolicies;
/// The size of the current onscreen surface in physical pixels.
@property(nonatomic, assign) DlISize frameSize;
@ -245,7 +238,7 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) {
std::unordered_map<int64_t, std::unique_ptr<flutter::EmbedderViewSlice>> _slices;
std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*> _factories;
std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
_gestureRecognizersBlockingPoliciesByType;
_gestureRecognizersBlockingPolicies;
fml::RefPtr<fml::TaskRunner> _platformTaskRunner;
std::unordered_map<int64_t, PlatformViewData> _platformViews;
std::unordered_map<int64_t, flutter::EmbeddedViewParams> _currentCompositionParams;
@ -336,32 +329,10 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) {
// Set a unique view identifier, so the platform view can be identified in unit tests.
platformView.accessibilityIdentifier = [NSString stringWithFormat:@"platform_view[%lld]", viewId];
NSString* gestureBlockingPolicyValue = args[@"gestureBlockingPolicy"];
FlutterPlatformViewGestureRecognizersBlockingPolicy gestureBlockingPolicy;
if ([gestureBlockingPolicyValue isEqualToString:kGestureBlockingPolicyTouchBlockingOnly]) {
gestureBlockingPolicy = FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly;
} else if ([gestureBlockingPolicyValue isEqualToString:kGestureBlockingPolicyEagerValue]) {
gestureBlockingPolicy = FlutterPlatformViewGestureRecognizersBlockingPolicyEager;
} else if ([gestureBlockingPolicyValue
isEqualToString:kGestureBlockingPolicyWaitUntilTouchesEndedValue]) {
gestureBlockingPolicy =
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded;
} else if ([gestureBlockingPolicyValue
isEqualToString:kGestureBlockingPolicyFallbackToPluginDefault]) {
gestureBlockingPolicy = self.gestureRecognizersBlockingPoliciesByType[viewType];
} else {
NSString* errorMessage =
[NSString stringWithFormat:@"Unsupported gesture blocking policy: %@, so we fallback to "
@"use the policy set via engine API.",
gestureBlockingPolicyValue];
[FlutterLogger logError:errorMessage];
gestureBlockingPolicy = self.gestureRecognizersBlockingPoliciesByType[viewType];
}
FlutterTouchInterceptingView* touchInterceptor =
[[FlutterTouchInterceptingView alloc] initWithEmbeddedView:platformView
platformViewsController:self
gestureRecognizersBlockingPolicy:gestureBlockingPolicy];
FlutterTouchInterceptingView* touchInterceptor = [[FlutterTouchInterceptingView alloc]
initWithEmbeddedView:platformView
platformViewsController:self
gestureRecognizersBlockingPolicy:self.gestureRecognizersBlockingPolicies[viewType]];
ChildClippingView* clippingView = [[ChildClippingView alloc] initWithFrame:CGRectZero];
[clippingView addSubview:touchInterceptor];
@ -431,7 +402,7 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) {
std::string idString([factoryId UTF8String]);
FML_CHECK(self.factories.count(idString) == 0);
self.factories[idString] = factory;
self.gestureRecognizersBlockingPoliciesByType[idString] = gestureRecognizerBlockingPolicy;
self.gestureRecognizersBlockingPolicies[idString] = gestureRecognizerBlockingPolicy;
}
- (void)beginFrameWithSize:(DlISize)frameSize {
@ -1091,10 +1062,9 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) {
- (std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*>&)factories {
return _factories;
}
- (std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>&)
gestureRecognizersBlockingPoliciesByType {
return _gestureRecognizersBlockingPoliciesByType;
gestureRecognizersBlockingPolicies {
return _gestureRecognizersBlockingPolicies;
}
- (std::unordered_map<int64_t, PlatformViewData>&)platformViews {

View File

@ -253,11 +253,6 @@ class FlutterPlatformViewsTestMockPlatformViewDelegate : public PlatformView::De
void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) override {}
void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet) override {
}
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) override {
return false;
}
void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,
@ -332,8 +327,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
@ -391,8 +385,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -489,8 +482,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -572,8 +564,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -655,8 +646,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -739,8 +729,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -869,8 +858,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -1026,8 +1014,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -1331,8 +1318,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -1749,8 +1735,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -1814,8 +1799,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -1924,8 +1908,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2003,8 +1986,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2080,8 +2062,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2156,8 +2137,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2237,8 +2217,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2338,8 +2317,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2447,8 +2425,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2573,8 +2550,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2682,8 +2658,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2808,8 +2783,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -2878,8 +2852,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -3005,8 +2978,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -3121,8 +3093,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -3188,8 +3159,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -3293,12 +3263,9 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockWebView",
@"gestureBlockingPolicy" : @"eager"
}]
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{@"id" : @2, @"viewType" : @"MockWebView"}]
result:result];
XCTAssertNotNil(gMockPlatformView);
@ -3439,8 +3406,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockNestedWrapperWebView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockNestedWrapperWebView"
}]
result:result];
@ -3499,8 +3465,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -3527,342 +3492,6 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], forwardingRecognizer);
}
- (void)testFlutterPlatformViewBlockGestureHitTestPolicyShouldNotAddDelayingRecognizer {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
[flutterPlatformViewsController registerViewFactory:factory
withId:@"MockFlutterPlatformView"
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly];
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"touchBlockingOnly"
}]
result:result];
XCTAssertNotNil(gMockPlatformView);
// Find touch inteceptor view
UIView* touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertNotNil(touchInterceptorView);
XCTAssert(touchInterceptorView.gestureRecognizers.count == 1);
UIGestureRecognizer* forwardingRecognizer = touchInterceptorView.gestureRecognizers[0];
XCTAssert([forwardingRecognizer isKindOfClass:[ForwardingGestureRecognizer class]]);
}
- (void)testFlutterPlatformViewBlockGestureUnderNonHitTestPolicyShouldAddDelayingRecognizer {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
[flutterPlatformViewsController
registerViewFactory:factory
withId:@"MockFlutterPlatformView"
gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
}]
result:result];
XCTAssertNotNil(gMockPlatformView);
// Find touch inteceptor view
UIView* touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertNotNil(touchInterceptorView);
XCTAssert(touchInterceptorView.gestureRecognizers.count == 2);
UIGestureRecognizer* delayingRecognizer = touchInterceptorView.gestureRecognizers[0];
UIGestureRecognizer* forwardingRecognizer = touchInterceptorView.gestureRecognizers[1];
XCTAssert([delayingRecognizer isKindOfClass:[FlutterDelayingGestureRecognizer class]]);
XCTAssert([forwardingRecognizer isKindOfClass:[ForwardingGestureRecognizer class]]);
}
- (void)testFlutterPlatformViewBlockGestureHitTestPolicyAcceptGesture {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
FlutterViewController* mockFlutterViewController = OCMClassMock([FlutterViewController class]);
flutterPlatformViewsController.flutterViewController = mockFlutterViewController;
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
[flutterPlatformViewsController registerViewFactory:factory
withId:@"MockFlutterPlatformView"
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly];
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
}]
result:result];
XCTAssertNotNil(gMockPlatformView);
// Find touch inteceptor view
UIView* touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertNotNil(touchInterceptorView);
touchInterceptorView.frame = CGRectMake(0, 0, 100, 100);
CGPoint touchBeganLocation = CGPointMake(1, 1);
UIEvent* mockEvent = OCMClassMock([UIEvent class]);
OCMStub([mockEvent type]).andReturn(UIEventTypeTouches);
OCMStub([mockFlutterViewController
platformViewShouldAcceptTouchAtTouchBeganLocation:touchBeganLocation])
.andReturn(YES);
UIView* hitTestResult = [touchInterceptorView hitTest:touchBeganLocation withEvent:mockEvent];
XCTAssert(hitTestResult == gMockPlatformView);
}
- (void)testFlutterPlatformViewBlockGestureHitTestPolicyRejectGesture {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
FlutterViewController* mockFlutterViewController = OCMClassMock([FlutterViewController class]);
flutterPlatformViewsController.flutterViewController = mockFlutterViewController;
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
[flutterPlatformViewsController registerViewFactory:factory
withId:@"MockFlutterPlatformView"
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly];
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"touchBlockingOnly"
}]
result:result];
XCTAssertNotNil(gMockPlatformView);
// Find touch inteceptor view
UIView* touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertNotNil(touchInterceptorView);
touchInterceptorView.frame = CGRectMake(0, 0, 100, 100);
CGPoint touchBeganLocation = CGPointMake(1, 1);
UIEvent* mockEvent = OCMClassMock([UIEvent class]);
OCMStub([mockEvent type]).andReturn(UIEventTypeTouches);
OCMStub([mockFlutterViewController
platformViewShouldAcceptTouchAtTouchBeganLocation:touchBeganLocation])
.andReturn(NO);
UIView* hitTestResult = [touchInterceptorView hitTest:touchBeganLocation withEvent:mockEvent];
XCTAssert(hitTestResult == touchInterceptorView);
}
- (void)testFlutterPlatformViewGestureBlockingPolicyMapping {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
FlutterViewController* mockFlutterViewController = OCMClassMock([FlutterViewController class]);
flutterPlatformViewsController.flutterViewController = mockFlutterViewController;
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
[flutterPlatformViewsController registerViewFactory:factory
withId:@"MockFlutterPlatformView"
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded];
FlutterResult result = ^(id result) {
};
// eager
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
}]
result:result];
UIView* touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertEqual(((FlutterTouchInterceptingView*)touchInterceptorView).blockingPolicy,
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
// waitUntilTouchesEnded
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{
@"id" : @3,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"waitUntilTouchesEnded"
}]
result:result];
touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertEqual(((FlutterTouchInterceptingView*)touchInterceptorView).blockingPolicy,
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded);
// touchBlockingOnly
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{
@"id" : @4,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"touchBlockingOnly"
}]
result:result];
touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertEqual(((FlutterTouchInterceptingView*)touchInterceptorView).blockingPolicy,
FlutterPlatformViewGestureRecognizersBlockingPolicyTouchBlockingOnly);
// fallbackToPluginDefault (which is waitUntilTouchesEnded)
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{
@"id" : @5,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"fallbackToPluginDefault"
}]
result:result];
touchInterceptorView = gMockPlatformView;
while (touchInterceptorView != nil &&
![touchInterceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInterceptorView = touchInterceptorView.superview;
}
XCTAssertEqual(((FlutterTouchInterceptingView*)touchInterceptorView).blockingPolicy,
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded);
}
- (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
@ -3894,8 +3523,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -3979,8 +3607,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -4035,9 +3662,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @0,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -4105,8 +3730,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @0,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* view1 = gMockPlatformView;
@ -4116,8 +3740,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* view2 = gMockPlatformView;
@ -4214,8 +3837,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @0,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* view1 = gMockPlatformView;
@ -4225,8 +3847,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* view2 = gMockPlatformView;
@ -4407,8 +4028,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -4458,8 +4078,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -4511,8 +4130,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* view1 = gMockPlatformView;
@ -4522,8 +4140,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* view2 = gMockPlatformView;
@ -4601,8 +4218,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -4702,16 +4318,14 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @0,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -4818,8 +4432,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
@ -4889,8 +4502,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
@ -4962,8 +4574,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
@ -5064,8 +4675,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @0,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -5074,8 +4684,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @1,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
@ -5147,8 +4756,7 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView",
@"gestureBlockingPolicy" : @"eager"
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];

View File

@ -152,7 +152,6 @@
// Sets flutterAccessibilityContainer as this view's accessibilityContainer.
@property(nonatomic, retain) id flutterAccessibilityContainer;
@property(nonatomic, readonly) FlutterPlatformViewGestureRecognizersBlockingPolicy blockingPolicy;
@end
@interface UIView (FirstResponder)

View File

@ -102,11 +102,6 @@ class MockPlatformViewDelegate : public PlatformView::Delegate {
void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) override {}
void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet) override {
}
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) override {
return false;
}
void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,

View File

@ -1384,12 +1384,6 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
[self dispatchTouches:touches pointerDataChangeOverride:&cancel event:nullptr];
}
- (BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(CGPoint)location {
flutter::PointData point{location.x, location.y};
return [self.engine platformViewShouldAcceptTouchAtTouchBeganLocation:point
viewId:self.viewIdentifier];
}
#pragma mark - Touch events rate correction
- (void)createTouchRateCorrectionVSyncClientIfNeeded {

View File

@ -47,12 +47,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)forceTouchesCancelled:(NSSet*)touches;
/**
* Returns YES if a platform view should accept the gesture started at specified location.
* Returns NO otherwise. The touch location is with respect to flutter view's coordinate space.
*/
- (BOOL)platformViewShouldAcceptTouchAtTouchBeganLocation:(CGPoint)location;
@end
NS_ASSUME_NONNULL_END

View File

@ -82,11 +82,6 @@ class MockDelegate : public PlatformView::Delegate {
void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) override {}
void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet) override {
}
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) override {
return false;
}
void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,
SemanticsAction action,

View File

@ -30,11 +30,6 @@ class MockDelegate : public PlatformView::Delegate {
void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) override {}
void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet) override {
}
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) override {
return false;
}
void OnPlatformViewSendViewFocusEvent(const ViewFocusEvent& event) override {}
void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
int32_t node_id,

View File

@ -52,10 +52,6 @@ class MockDelegate : public PlatformView::Delegate {
OnPlatformViewDispatchPointerDataPacket,
(std::unique_ptr<PointerDataPacket> packet),
(override));
MOCK_METHOD(bool,
OnPlatformViewEmbeddedNativeViewShouldAcceptTouch,
(int64_t view_id, const flutter::PointData touch_began_location),
(override));
MOCK_METHOD(void,
OnPlatformViewDispatchSemanticsAction,
(int64_t view_id,

View File

@ -16,7 +16,6 @@
#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/lib/ui/window/point_data.h"
#include "flutter/lib/ui/window/pointer_data.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"

View File

@ -117,12 +117,6 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate {
pointer_packets_.push_back(std::move(packet));
}
// |flutter::PlatformView::Delegate|
bool OnPlatformViewEmbeddedNativeViewShouldAcceptTouch(
int64_t view_id,
const flutter::PointData touch_began_location) {
return false;
}
// |flutter::PlatformView::Delegate|
void OnPlatformViewDispatchKeyDataPacket(
std::unique_ptr<flutter::KeyDataPacket> packet,
std::function<void(bool)> callback) {}

View File

@ -11,7 +11,7 @@ library;
import 'dart:async';
import 'dart:collection';
import 'dart:ui' as ui show HitTestRequest, HitTestResponse, PointerDataPacket;
import 'dart:ui' as ui show PointerDataPacket;
import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart';
@ -37,9 +37,6 @@ export 'pointer_signal_resolver.dart' show PointerSignalResolver;
typedef _HandleSampleTimeChangedCallback = void Function();
/// Abstract class that represents a hit test target backed by a embedded native view.
abstract class NativeHitTestTarget {}
/// Class that implements clock used for sampling.
class SamplingClock {
/// Returns current time.
@ -281,9 +278,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
void initInstances() {
super.initInstances();
_instance = this;
platformDispatcher
..onPointerDataPacket = _handlePointerDataPacket
..onHitTest = _handleHitTest;
platformDispatcher.onPointerDataPacket = _handlePointerDataPacket;
}
/// The singleton instance of this object.
@ -324,17 +319,6 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
}
}
ui.HitTestResponse _handleHitTest(ui.HitTestRequest request) {
final result = HitTestResult();
hitTestInView(result, request.offset, request.view.viewId);
if (result.path.isEmpty) {
return ui.HitTestResponse.empty;
}
final HitTestTarget firstHit = result.path.first.target;
return ui.HitTestResponse(isPlatformView: firstHit is NativeHitTestTarget);
}
double? _devicePixelRatioForView(int viewId) {
return platformDispatcher.view(id: viewId)?.devicePixelRatio;
}

View File

@ -416,8 +416,7 @@ abstract class RenderDarwinPlatformView<T extends DarwinPlatformViewController>
///
/// * [UiKitView], which is a widget that is used to show a UIView.
/// * [PlatformViewsService], which is a service for controlling platform views.
class RenderUiKitView extends RenderDarwinPlatformView<UiKitViewController>
implements NativeHitTestTarget {
class RenderUiKitView extends RenderDarwinPlatformView<UiKitViewController> {
/// Creates a render object for an iOS UIView.
RenderUiKitView({
required super.viewController,

View File

@ -257,8 +257,6 @@ class PlatformViewsService {
static Future<UiKitViewController> initUiKitView({
required int id,
required String viewType,
UiKitViewGestureBlockingPolicy gestureBlockingPolicy =
UiKitViewGestureBlockingPolicy.fallbackToPluginDefault,
required TextDirection layoutDirection,
dynamic creationParams,
MessageCodec<dynamic>? creationParamsCodec,
@ -266,25 +264,9 @@ class PlatformViewsService {
}) async {
assert(creationParams == null || creationParamsCodec != null);
final String gestureBlockingPolicyValue;
switch (gestureBlockingPolicy) {
case UiKitViewGestureBlockingPolicy.eager:
gestureBlockingPolicyValue = 'eager';
case UiKitViewGestureBlockingPolicy.waitUntilTouchesEnded:
gestureBlockingPolicyValue = 'waitUntilTouchesEnded';
case UiKitViewGestureBlockingPolicy.fallbackToPluginDefault:
gestureBlockingPolicyValue = 'fallbackToPluginDefault';
case UiKitViewGestureBlockingPolicy.touchBlockingOnly:
gestureBlockingPolicyValue = 'touchBlockingOnly';
}
// TODO(amirh): pass layoutDirection once the system channel supports it.
// https://github.com/flutter/flutter/issues/133682
final args = <String, dynamic>{
'id': id,
'viewType': viewType,
'gestureBlockingPolicy': gestureBlockingPolicyValue,
};
final args = <String, dynamic>{'id': id, 'viewType': viewType};
if (creationParams != null) {
final ByteData paramsByteData = creationParamsCodec!.encodeMessage(creationParams)!;
args['params'] = Uint8List.view(paramsByteData.buffer, 0, paramsByteData.lengthInBytes);
@ -1592,30 +1574,6 @@ abstract class DarwinPlatformViewController {
}
}
/// How touch event callbacks and gesture recognizers of a platform view are blocked.
/// This replaces engine's FlutterPlatformViewGestureRecognizersBlockingPolicy enum in FlutterPlugin.h.
enum UiKitViewGestureBlockingPolicy {
/// Flutter blocks all the UIGestureRecognizers on the platform view as soon as it
/// decides they should be blocked.
eager,
/// Flutter blocks the platform view's UIGestureRecognizers from recognizing only after
/// touchesEnded was invoked.
waitUntilTouchesEnded,
/// Flutter blocks all the UIGestureRecognizers on the platform view as soon as it
/// decides they should be blocked.
///
/// This is similar to FlutterPlatformViewGestureRecognizersBlockingPolicyEager. However,
/// internally it performs hit test rather than a blocking gesture recognizer. This addresses
/// a few bugs related to WKWebView being untappable. See
/// https://github.com/flutter/flutter/issues/175099.
touchBlockingOnly,
/// Fallback to use the policy set by the `registerViewFactory` engine API in FlutterPlugin.h.
fallbackToPluginDefault,
}
/// Controller for an iOS platform view.
///
/// View controllers create and interact with the underlying UIView.

View File

@ -317,7 +317,6 @@ class UiKitView extends _DarwinView {
const UiKitView({
super.key,
required super.viewType,
this.gestureBlockingPolicy = UiKitViewGestureBlockingPolicy.fallbackToPluginDefault,
super.onPlatformViewCreated,
super.hitTestBehavior = PlatformViewHitTestBehavior.opaque,
super.layoutDirection,
@ -326,9 +325,6 @@ class UiKitView extends _DarwinView {
super.gestureRecognizers,
}) : assert(creationParams == null || creationParamsCodec != null);
/// The gesture blocking policy that controls touch and gesture blocking behaviors.
final UiKitViewGestureBlockingPolicy gestureBlockingPolicy;
@override
State<UiKitView> createState() => _UiKitViewState();
}
@ -969,7 +965,6 @@ class _UiKitViewState
return PlatformViewsService.initUiKitView(
id: id,
viewType: widget.viewType,
gestureBlockingPolicy: widget.gestureBlockingPolicy,
layoutDirection: _layoutDirection!,
creationParams: widget.creationParams,
creationParamsCodec: widget.creationParamsCodec,

View File

@ -7,15 +7,11 @@ import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
typedef HandleEventCallback = void Function(PointerEvent event);
typedef HandleHitTestInViewCallback =
void Function(HitTestResult result, Offset position, int viewId);
class TestGestureFlutterBinding extends BindingBase
with GestureBinding, SchedulerBinding, ServicesBinding, TestDefaultBinaryMessengerBinding {
class TestGestureFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding {
@override
void initInstances() {
super.initInstances();
@ -54,108 +50,11 @@ class TestGestureFlutterBinding extends BindingBase
super.handleEvent(event, entry);
onHandleEvent?.call(event);
}
HandleHitTestInViewCallback? onHitTestInView;
@override
void hitTestInView(HitTestResult result, Offset position, int viewId) {
if (onHitTestInView != null) {
onHitTestInView!(result, position, viewId);
return;
}
super.hitTestInView(result, position, viewId);
}
}
class _DummyHitTestTarget implements HitTestTarget {
@override
void handleEvent(PointerEvent event, HitTestEntry entry) {
// Nothing to do.
}
}
class _DummyNativeHitTestTarget implements NativeHitTestTarget, HitTestTarget {
@override
void handleEvent(PointerEvent event, HitTestEntry entry) {
// Nothing to do.
}
}
class _FakeFlutterView extends Fake implements FlutterView {
@override
final int viewId = 0;
}
void main() {
final TestGestureFlutterBinding binding = TestGestureFlutterBinding.ensureInitialized();
binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, (
MethodCall methodCall,
) async {
return null;
});
tearDown(() {
binding.onHitTestInView = null;
});
test('Platform view hit test should not accept gesture if no hit', () {
// not found
TestGestureFlutterBinding.instance.onHitTestInView =
(HitTestResult result, Offset position, int viewId) {};
final request = ui.HitTestRequest(view: _FakeFlutterView(), offset: const Offset(1, 1));
final ui.HitTestResponse repsonse =
GestureBinding.instance.platformDispatcher.onHitTest?.call(request) ??
ui.HitTestResponse.empty;
expect(repsonse.isPlatformView, isFalse);
});
test('Platform view hit test should not accept gesture if no platform view', () {
TestGestureFlutterBinding.instance.onHitTestInView =
(HitTestResult result, Offset position, int viewId) {
result.add(HitTestEntry(_DummyHitTestTarget()));
};
final request = ui.HitTestRequest(view: _FakeFlutterView(), offset: const Offset(1, 1));
final ui.HitTestResponse repsonse =
GestureBinding.instance.platformDispatcher.onHitTest?.call(request) ??
ui.HitTestResponse.empty;
expect(repsonse.isPlatformView, isFalse);
});
test('Platform view hit test should not accept gesture if first hit is not a platform view', () {
TestGestureFlutterBinding.instance.onHitTestInView =
(HitTestResult result, Offset position, int viewId) {
result.add(HitTestEntry(_DummyHitTestTarget()));
result.add(HitTestEntry(_DummyNativeHitTestTarget()));
};
final request = ui.HitTestRequest(view: _FakeFlutterView(), offset: const Offset(1, 1));
final ui.HitTestResponse repsonse =
GestureBinding.instance.platformDispatcher.onHitTest?.call(request) ??
ui.HitTestResponse.empty;
expect(repsonse.isPlatformView, isFalse);
});
test('Platform view hit test should accept gesture if first hit is a platform view', () {
TestGestureFlutterBinding.instance.onHitTestInView =
(HitTestResult result, Offset position, int viewId) {
result.add(HitTestEntry(_DummyNativeHitTestTarget()));
result.add(HitTestEntry(_DummyHitTestTarget()));
};
final request = ui.HitTestRequest(view: _FakeFlutterView(), offset: const Offset(1, 1));
final ui.HitTestResponse repsonse =
GestureBinding.instance.platformDispatcher.onHitTest?.call(request) ??
ui.HitTestResponse.empty;
expect(repsonse.isPlatformView, isTrue);
});
test('Pointer tap events', () {
const packet = ui.PointerDataPacket(
data: <ui.PointerData>[