diff --git a/engine/src/flutter/lib/ui/semantics.dart b/engine/src/flutter/lib/ui/semantics.dart index 59052b157b..bb9d586e41 100644 --- a/engine/src/flutter/lib/ui/semantics.dart +++ b/engine/src/flutter/lib/ui/semantics.dart @@ -45,7 +45,6 @@ class SemanticsAction { static const int _kMoveCursorBackwardByWordIndex = 1 << 20; static const int _kSetTextIndex = 1 << 21; static const int _kFocusIndex = 1 << 22; - static const int _kScrollToOffsetIndex = 1 << 23; // READ THIS: if you add an action here, you MUST update the // numSemanticsActions value in testing/dart/semantics_test.dart and // lib/web_ui/test/engine/semantics/semantics_api_test.dart, or tests @@ -87,17 +86,6 @@ class SemanticsAction { /// scrollable. static const SemanticsAction scrollDown = SemanticsAction._(_kScrollDownIndex, 'scrollDown'); - /// A request to scroll the scrollable container to a given scroll offset. - /// - /// The payload of this [SemanticsAction] is a flutter-standard-encoded - /// [Float64List] of length 2 containing the target horizontal and vertical - /// offsets (in logical pixels) the receiving scrollable container should - /// scroll to. - /// - /// This action is used by iOS Full Keyboard Access to reveal contents that - /// are currently not visible in the viewport. - static const SemanticsAction scrollToOffset = SemanticsAction._(_kScrollToOffsetIndex, 'scrollToOffset'); - /// A request to increase the value represented by the semantics node. /// /// For example, this action might be recognized by a slider control. @@ -277,7 +265,6 @@ class SemanticsAction { _kScrollRightIndex: scrollRight, _kScrollUpIndex: scrollUp, _kScrollDownIndex: scrollDown, - _kScrollToOffsetIndex: scrollToOffset, _kIncreaseIndex: increase, _kDecreaseIndex: decrease, _kShowOnScreenIndex: showOnScreen, @@ -777,7 +764,7 @@ base class LocaleStringAttribute extends StringAttribute { _initLocaleStringAttribute(this, range.start, range.end, locale.toLanguageTag()); } - /// The language of this attribute. + /// The lanuage of this attribute. final Locale locale; @Native(symbol: 'NativeStringAttribute::initLocaleStringAttribute') diff --git a/engine/src/flutter/lib/ui/semantics/semantics_node.h b/engine/src/flutter/lib/ui/semantics/semantics_node.h index 0f02ff3202..98d84c6c6a 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_node.h +++ b/engine/src/flutter/lib/ui/semantics/semantics_node.h @@ -43,7 +43,6 @@ enum class SemanticsAction : int32_t { kMoveCursorBackwardByWord = 1 << 20, kSetText = 1 << 21, kFocus = 1 << 22, - kScrollToOffset = 1 << 23, }; const int kVerticalScrollSemanticsActions = diff --git a/engine/src/flutter/lib/web_ui/lib/semantics.dart b/engine/src/flutter/lib/web_ui/lib/semantics.dart index 786eaacc54..be36411520 100644 --- a/engine/src/flutter/lib/web_ui/lib/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/semantics.dart @@ -33,7 +33,6 @@ class SemanticsAction { static const int _kMoveCursorBackwardByWordIndex = 1 << 20; static const int _kSetTextIndex = 1 << 21; static const int _kFocusIndex = 1 << 22; - static const int _kScrollToOffsetIndex = 1 << 23; static const SemanticsAction tap = SemanticsAction._(_kTapIndex, 'tap'); static const SemanticsAction longPress = SemanticsAction._(_kLongPressIndex, 'longPress'); @@ -41,7 +40,6 @@ class SemanticsAction { static const SemanticsAction scrollRight = SemanticsAction._(_kScrollRightIndex, 'scrollRight'); static const SemanticsAction scrollUp = SemanticsAction._(_kScrollUpIndex, 'scrollUp'); static const SemanticsAction scrollDown = SemanticsAction._(_kScrollDownIndex, 'scrollDown'); - static const SemanticsAction scrollToOffset = SemanticsAction._(_kScrollToOffsetIndex, 'scrollToOffset'); static const SemanticsAction increase = SemanticsAction._(_kIncreaseIndex, 'increase'); static const SemanticsAction decrease = SemanticsAction._(_kDecreaseIndex, 'decrease'); static const SemanticsAction showOnScreen = SemanticsAction._(_kShowOnScreenIndex, 'showOnScreen'); @@ -67,7 +65,6 @@ class SemanticsAction { _kScrollRightIndex: scrollRight, _kScrollUpIndex: scrollUp, _kScrollDownIndex: scrollDown, - _kScrollToOffsetIndex: scrollToOffset, _kIncreaseIndex: increase, _kDecreaseIndex: decrease, _kShowOnScreenIndex: showOnScreen, diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_api_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_api_test.dart index e56242639b..8df41a7cae 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_api_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_api_test.dart @@ -29,7 +29,7 @@ void testMain() { }); // This must match the number of actions in lib/ui/semantics.dart - const int numSemanticsActions = 24; + const int numSemanticsActions = 23; test('SemanticsAction.values refers to all actions.', () async { expect(SemanticsAction.values.length, equals(numSemanticsActions)); for (int index = 0; index < numSemanticsActions; ++index) { diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 51d2070929..0f28573023 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -2120,8 +2120,7 @@ public class AccessibilityBridge extends AccessibilityNodeProvider { MOVE_CURSOR_FORWARD_BY_WORD(1 << 19), MOVE_CURSOR_BACKWARD_BY_WORD(1 << 20), SET_TEXT(1 << 21), - FOCUS(1 << 22), - SCROLL_TO_OFFSET(1 << 23); + FOCUS(1 << 22); public final int value; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h index e5f2f6343b..28b9b56362 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h @@ -18,30 +18,10 @@ NS_ASSUME_NONNULL_BEGIN * sends all of selector calls from accessibility services to the * owner SemanticsObject. */ -@interface FlutterSemanticsScrollView : UIScrollView +@interface FlutterSemanticsScrollView : UIScrollView @property(nonatomic, weak, nullable) SemanticsObject* semanticsObject; -/// Whether this scroll view's content offset is actively being updated by UIKit -/// or other the system services. -/// -/// This flag is set by the `FlutterSemanticsScrollView` itself, typically in -/// one of the `UIScrollViewDelegate` methods. -/// -/// When this flag is true, the `SemanticsObject` implementation ignores all -/// content offset updates coming from the Flutter framework, to prevent -/// potential feedback loops (especially when the framework is only echoing -/// the new content offset back to this scroll view). -/// -/// For example, to scroll a scrollable container with iOS full keyboard access, -/// the iOS focus system uses a display link to scroll the container to the -/// desired offset animatedly. If the user changes the scroll offset during the -/// animation, the display link will be invalidated and the scrolling animation -/// will be interrupted. For simplicity, content offset updates coming from the -/// framework will be ignored in the relatively short animation duration (~1s), -/// allowing the scrolling animation to finish. -@property(nonatomic, readonly) BOOL isDoingSystemScrolling; - - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm index c6952c72b7..9b74e2ddab 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm @@ -15,8 +15,6 @@ FLUTTER_ASSERT_ARC self = [super initWithFrame:CGRectZero]; if (self) { _semanticsObject = semanticsObject; - _isDoingSystemScrolling = NO; - self.delegate = self; } return self; } @@ -107,14 +105,4 @@ FLUTTER_ASSERT_ARC return self.semanticsObject.children.count; } -- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView - withVelocity:(CGPoint)velocity - targetContentOffset:(inout CGPoint*)targetContentOffset { - _isDoingSystemScrolling = YES; -} - -- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView { - _isDoingSystemScrolling = NO; -} - @end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm index c3262de538..3448b92805 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject+UIFocusSystem.mm @@ -3,10 +3,7 @@ // found in the LICENSE file. #import "SemanticsObject.h" -#include "flutter/lib/ui/semantics/semantics_node.h" -#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" FLUTTER_ASSERT_ARC @@ -30,19 +27,10 @@ FLUTTER_ASSERT_ARC // translated to calls such as -[NSObject accessibilityActivate]), while most // other key events are dispatched to the framework. @interface SemanticsObject (UIFocusSystem) -/// The `UIFocusItem` that represents this SemanticsObject. -/// -/// For regular `SemanticsObject`s, this method returns `self`, -/// for `FlutterScrollableSemanticsObject`s, this method returns its scroll view. -- (id)focusItem; @end @implementation SemanticsObject (UIFocusSystem) -- (id)focusItem { - return self; -} - #pragma mark - UIFocusEnvironment Conformance - (void)setNeedsFocusUpdate { @@ -61,7 +49,7 @@ FLUTTER_ASSERT_ARC - (id)parentFocusEnvironment { // The root SemanticsObject node's parent is the FlutterView. - return self.parent.focusItem ?: self.bridge->view(); + return self.parent ?: self.bridge->view(); } - (NSArray>*)preferredFocusEnvironments { @@ -83,57 +71,8 @@ FLUTTER_ASSERT_ARC return self.node.HasAction(flutter::SemanticsAction::kTap); } -// The frame is described in the `coordinateSpace` of the -// `parentFocusEnvironment` (all `parentFocusEnvironment`s are `UIFocusItem`s). -// -// See also the `coordinateSpace` implementation. -// TODO(LongCatIsLooong): use CoreGraphics types. - (CGRect)frame { - SkPoint quad[4] = {SkPoint::Make(self.node.rect.left(), self.node.rect.top()), - SkPoint::Make(self.node.rect.left(), self.node.rect.bottom()), - SkPoint::Make(self.node.rect.right(), self.node.rect.top()), - SkPoint::Make(self.node.rect.right(), self.node.rect.bottom())}; - - SkM44 transform = self.node.transform; - FlutterSemanticsScrollView* scrollView; - for (SemanticsObject* ancestor = self.parent; ancestor; ancestor = ancestor.parent) { - if ([ancestor isKindOfClass:[FlutterScrollableSemanticsObject class]]) { - scrollView = ((FlutterScrollableSemanticsObject*)ancestor).scrollView; - break; - } - transform = ancestor.node.transform * transform; - } - - for (auto& vertex : quad) { - SkV4 vector = transform.map(vertex.x(), vertex.y(), 0, 1); - vertex = SkPoint::Make(vector.x / vector.w, vector.y / vector.w); - } - - SkRect rect; - rect.setBounds(quad, 4); - // If this UIFocusItemContainer's coordinateSpace is a UIScrollView, offset - // the rect by `contentOffset` because the contentOffset translation is - // incorporated into the paint transform at different node depth in UIKit - // and Flutter. In Flutter, the translation is added to the cells - // while in UIKit the viewport's bounds is manipulated (IOW, each cell's frame - // in the UIScrollView coordinateSpace does not change when the UIScrollView - // scrolls). - CGRect unscaledRect = - CGRectMake(rect.x() + scrollView.bounds.origin.x, rect.y() + scrollView.bounds.origin.y, - rect.width(), rect.height()); - if (scrollView) { - return unscaledRect; - } - // `rect` could be in physical pixels since the root RenderObject ("RenderView") - // applies a transform that turns logical pixels to physical pixels. Undo the - // transform by dividing the coordinates by the screen's scale factor, if this - // UIFocusItem's reported `coordinateSpace` is the root view (which means this - // UIFocusItem is not inside of a scroll view). - // - // Screen can be nil if the FlutterView is covered by another native view. - CGFloat scale = (self.bridge->view().window.screen ?: UIScreen.mainScreen).scale; - return CGRectMake(unscaledRect.origin.x / scale, unscaledRect.origin.y / scale, - unscaledRect.size.width / scale, unscaledRect.size.height / scale); + return self.accessibilityFrame; } #pragma mark - UIFocusItemContainer Conformance @@ -148,94 +87,16 @@ FLUTTER_ASSERT_ARC // // This method is only supposed to return items within the given // rect but returning everything in the subtree seems to work fine. - NSMutableArray>* reversedItems = + NSMutableArray* reversedItems = [[NSMutableArray alloc] initWithCapacity:self.childrenInHitTestOrder.count]; for (NSUInteger i = 0; i < self.childrenInHitTestOrder.count; ++i) { - SemanticsObject* child = self.childrenInHitTestOrder[self.childrenInHitTestOrder.count - 1 - i]; - [reversedItems addObject:child.focusItem]; + [reversedItems + addObject:self.childrenInHitTestOrder[self.childrenInHitTestOrder.count - 1 - i]]; } return reversedItems; } - (id)coordinateSpace { - // A regular SemanticsObject uses the same coordinate space as its parent. - return self.parent.coordinateSpace ?: self.bridge->view(); -} - -@end - -/// Scrollable containers interact with the iOS focus engine using the -/// `UIFocusItemScrollableContainer` protocol. The said protocol (and other focus-related protocols) -/// does not provide means to inform the focus system of layout changes. In order for the focus -/// highlight to update properly as the scroll view scrolls, this implementation incorporates a -/// UIScrollView into the focus hierarchy to workaround the highlight update problem. -/// -/// As a result, in the current implementation only scrollable containers and the root node -/// establish their own `coordinateSpace`s. All other `UIFocusItemContainter`s use the same -/// `coordinateSpace` as the containing UIScrollView, or the root `FlutterView`, whichever is -/// closer. -/// -/// See also the `frame` method implementation. -#pragma mark - Scrolling - -@interface FlutterScrollableSemanticsObject (CoordinateSpace) -@end - -@implementation FlutterScrollableSemanticsObject (CoordinateSpace) -- (id)coordinateSpace { - // A scrollable SemanticsObject uses the same coordinate space as the scroll view. - // This may not work very well in nested scroll views. - return self.scrollView; -} - -- (id)focusItem { - return self.scrollView; -} - -@end - -@interface FlutterSemanticsScrollView (UIFocusItemScrollableContainer) < - UIFocusItemScrollableContainer> -@end - -@implementation FlutterSemanticsScrollView (UIFocusItemScrollableContainer) - -#pragma mark - FlutterSemanticsScrollView UIFocusItemScrollableContainer Conformance - -- (CGSize)visibleSize { - return self.frame.size; -} - -- (void)setContentOffset:(CGPoint)contentOffset { - [super setContentOffset:contentOffset]; - // Do no send flutter::SemanticsAction::kScrollToOffset if it's triggered - // by a framework update. - if (![self.semanticsObject isAccessibilityBridgeAlive] || !self.isDoingSystemScrolling) { - return; - } - - double offset[2] = {contentOffset.x, contentOffset.y}; - FlutterStandardTypedData* offsetData = [FlutterStandardTypedData - typedDataWithFloat64:[NSData dataWithBytes:&offset length:sizeof(offset)]]; - NSData* encoded = [[FlutterStandardMessageCodec sharedInstance] encode:offsetData]; - self.semanticsObject.bridge->DispatchSemanticsAction( - self.semanticsObject.uid, flutter::SemanticsAction::kScrollToOffset, - fml::MallocMapping::Copy(encoded.bytes, encoded.length)); -} - -- (BOOL)canBecomeFocused { - return NO; -} - -- (id)parentFocusEnvironment { - return self.semanticsObject.parentFocusEnvironment; -} - -- (NSArray>*)preferredFocusEnvironments { - return nil; -} - -- (NSArray>*)focusItemsInRect:(CGRect)rect { - return [self.semanticsObject focusItemsInRect:rect]; + return self.bridge->view(); } @end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h index 2c9e051611..d3441ec005 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h @@ -10,7 +10,6 @@ #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/semantics/semantics_node.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge_ios.h" constexpr int32_t kRootNodeId = 0; @@ -187,7 +186,7 @@ constexpr float kScrollExtentMaxForInf = 1000; /// The semantics object for scrollable. This class creates an UIScrollView to interact with the /// iOS. @interface FlutterScrollableSemanticsObject : SemanticsObject -@property(nonatomic, readonly) FlutterSemanticsScrollView* scrollView; + @end /** diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm index 39882196e8..8212c2fd01 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm @@ -154,8 +154,6 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) { _scrollView = [[FlutterSemanticsScrollView alloc] initWithSemanticsObject:self]; [_scrollView setShowsHorizontalScrollIndicator:NO]; [_scrollView setShowsVerticalScrollIndicator:NO]; - [_scrollView setContentInset:UIEdgeInsetsZero]; - [_scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; [self.bridge->view() addSubview:_scrollView]; } return self; @@ -176,10 +174,7 @@ CGRect ConvertRectToGlobal(SemanticsObject* reference, CGRect local_rect) { // contentOffset is 0.0, only the scroll down action is available. self.scrollView.frame = self.accessibilityFrame; self.scrollView.contentSize = [self contentSizeInternal]; - // See the documentation on `isDoingSystemScrolling`. - if (!self.scrollView.isDoingSystemScrolling) { - [self.scrollView setContentOffset:self.contentOffsetInternal animated:NO]; - } + [self.scrollView setContentOffset:[self contentOffsetInternal] animated:NO]; } - (id)nativeAccessibility { diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm index 02fb11f983..ff514b6730 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm @@ -7,7 +7,6 @@ #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h" #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h" #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h" @@ -20,10 +19,6 @@ const float kFloatCompareEpsilon = 0.001; @interface SemanticsObject (UIFocusSystem) @end -@interface FlutterScrollableSemanticsObject (UIFocusItemScrollableContainer) < - UIFocusItemScrollableContainer> -@end - @interface TextInputSemanticsObject (Test) - (UIView*)textInputSurrogate; @end @@ -670,7 +665,7 @@ const float kFloatCompareEpsilon = 0.001; XCTAssertEqual(container.semanticsObject, parentObject); } -- (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets { +- (void)testFlutterScrollableSemanticsObjectHidesScrollBar { fml::WeakPtrFactory factory( new flutter::testing::MockAccessibilityBridge()); fml::WeakPtr bridge = factory.GetWeakPtr(); @@ -690,9 +685,6 @@ const float kFloatCompareEpsilon = 0.001; XCTAssertFalse(scrollView.showsHorizontalScrollIndicator); XCTAssertFalse(scrollView.showsVerticalScrollIndicator); - XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior, - UIScrollViewContentInsetAdjustmentNever); - XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero)); } - (void)testSemanticsObjectBuildsAttributedString { @@ -1163,19 +1155,6 @@ const float kFloatCompareEpsilon = 0.001; [self waitForExpectationsWithTimeout:1 handler:nil]; } -- (void)testSliderSemanticsObject { - fml::WeakPtrFactory factory( - new flutter::testing::MockAccessibilityBridge()); - fml::WeakPtr bridge = factory.GetWeakPtr(); - - flutter::SemanticsNode node; - node.flags = static_cast(flutter::SemanticsFlags::kIsSlider); - SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0]; - [object setSemanticsNode:&node]; - [object accessibilityBridgeDidFinishUpdate]; - XCTAssertEqual([object accessibilityActivate], YES); -} - - (void)testUIFocusItemConformance { fml::WeakPtrFactory factory( new flutter::testing::MockAccessibilityBridge()); @@ -1228,57 +1207,17 @@ const float kFloatCompareEpsilon = 0.001; XCTAssertTrue([itemsInRect containsObject:child2]); } -- (void)testUIFocusItemScrollableContainerConformance { +- (void)testSliderSemanticsObject { fml::WeakPtrFactory factory( new flutter::testing::MockAccessibilityBridge()); - fml::WeakPtr bridge = factory.GetWeakPtr(); - FlutterScrollableSemanticsObject* scrollable = - [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:5]; + fml::WeakPtr bridge = factory.GetWeakPtr(); - // setContentOffset - CGPoint p = CGPointMake(123.0, 456.0); - [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView - withVelocity:CGPointZero - targetContentOffset:&p]; - scrollable.scrollView.contentOffset = p; - [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView]; - XCTAssertEqual(bridge->observations.size(), (size_t)1); - XCTAssertEqual(bridge->observations[0].id, 5); - XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset); - - std::vector args = bridge->observations[0].args; - XCTAssertEqual(args.size(), 3 * sizeof(CGFloat)); - - NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()]; - FlutterStandardTypedData* decoded = [[FlutterStandardMessageCodec sharedInstance] decode:encoded]; - CGPoint point = CGPointZero; - memcpy(&point, decoded.data.bytes, decoded.data.length); - XCTAssertTrue(CGPointEqualToPoint(point, p)); -} - -- (void)testUIFocusItemScrollableContainerNoFeedbackLoops { - fml::WeakPtrFactory factory( - new flutter::testing::MockAccessibilityBridge()); - fml::WeakPtr bridge = factory.GetWeakPtr(); - FlutterScrollableSemanticsObject* scrollable = - [[FlutterScrollableSemanticsObject alloc] initWithBridge:bridge uid:5]; - - // setContentOffset - const CGPoint p = CGPointMake(0.0, 456.0); - scrollable.scrollView.contentOffset = p; - bridge->observations.clear(); - - const SkScalar scrollPosition = p.y + 0.0000000000000001; flutter::SemanticsNode node; - node.flags = static_cast(flutter::SemanticsFlags::kHasImplicitScrolling); - node.actions = flutter::kVerticalScrollSemanticsActions; - node.rect = SkRect::MakeXYWH(0, 0, 100, 200); - node.scrollExtentMax = 10000; - node.scrollPosition = scrollPosition; - node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0}; - [scrollable setSemanticsNode:&node]; - [scrollable accessibilityBridgeDidFinishUpdate]; - - XCTAssertEqual(bridge->observations.size(), (size_t)0); + node.flags = static_cast(flutter::SemanticsFlags::kIsSlider); + SemanticsObject* object = [[SemanticsObject alloc] initWithBridge:bridge uid:0]; + [object setSemanticsNode:&node]; + [object accessibilityBridgeDidFinishUpdate]; + XCTAssertEqual([object accessibilityActivate], YES); } + @end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h index cae8cde089..4ccd57b1bb 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h @@ -15,18 +15,10 @@ namespace testing { class SemanticsActionObservation { public: SemanticsActionObservation(int32_t observed_id, SemanticsAction observed_action) - : id(observed_id), action(observed_action), args({}) {} - - SemanticsActionObservation(int32_t observed_id, - SemanticsAction observed_action, - fml::MallocMapping& args) - : id(observed_id), - action(observed_action), - args(args.GetMapping(), args.GetMapping() + args.GetSize()) {} + : id(observed_id), action(observed_action) {} int32_t id; SemanticsAction action; - std::vector args; }; class MockAccessibilityBridge : public AccessibilityBridgeIos { @@ -46,7 +38,7 @@ class MockAccessibilityBridge : public AccessibilityBridgeIos { void DispatchSemanticsAction(int32_t id, SemanticsAction action, fml::MallocMapping args) override { - SemanticsActionObservation observation(id, action, args); + SemanticsActionObservation observation(id, action); observations.push_back(observation); } void AccessibilityObjectDidBecomeFocused(int32_t id) override {} @@ -77,7 +69,7 @@ class MockAccessibilityBridgeNoWindow : public AccessibilityBridgeIos { void DispatchSemanticsAction(int32_t id, SemanticsAction action, fml::MallocMapping args) override { - SemanticsActionObservation observation(id, action, args); + SemanticsActionObservation observation(id, action); observations.push_back(observation); } void AccessibilityObjectDidBecomeFocused(int32_t id) override {} diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index 8ca474222d..f0df9973f4 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -164,9 +164,6 @@ typedef enum { kFlutterSemanticsActionSetText = 1 << 21, /// Request that the respective focusable widget gain input focus. kFlutterSemanticsActionFocus = 1 << 22, - /// Request that scrolls the current scrollable container to a given scroll - /// offset. - kFlutterSemanticsActionScrollToOffset = 1 << 23, } FlutterSemanticsAction; /// The set of properties that may be associated with a semantics node. diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc index 987b9303ba..b9f443035a 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc @@ -161,9 +161,6 @@ std::string NodeActionsToString(const flutter::SemanticsNode& node) { if (node.HasAction(flutter::SemanticsAction::kScrollUp)) { output += "kScrollUp|"; } - if (node.HasAction(flutter::SemanticsAction::kScrollToOffset)) { - output += "kScrollToOffset|"; - } if (node.HasAction(flutter::SemanticsAction::kSetSelection)) { output += "kSetSelection|"; } diff --git a/engine/src/flutter/testing/dart/semantics_test.dart b/engine/src/flutter/testing/dart/semantics_test.dart index 8b2f889210..a5841e7d1d 100644 --- a/engine/src/flutter/testing/dart/semantics_test.dart +++ b/engine/src/flutter/testing/dart/semantics_test.dart @@ -22,7 +22,7 @@ void main() { }); // This must match the number of actions in lib/ui/semantics.dart - const int numSemanticsActions = 24; + const int numSemanticsActions = 23; test('SemanticsAction.values refers to all actions.', () async { expect(SemanticsAction.values.length, equals(numSemanticsActions)); for (int index = 0; index < numSemanticsActions; ++index) {