Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/IOKit.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm
Expand Down
1 change: 1 addition & 0 deletions shell/platform/darwin/ios/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ source_set("ios_test_flutter_mrc") {
"framework/Source/FlutterEngineTest_mrc.mm",
"framework/Source/FlutterPlatformPluginTest.mm",
"framework/Source/FlutterPlatformViewsTest.mm",
"framework/Source/FlutterViewTest.mm",
"framework/Source/accessibility_bridge_test.mm",
]
deps = [
Expand Down
8 changes: 7 additions & 1 deletion shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -761,14 +761,20 @@ - (void)showAutocorrectionPromptRectForStart:(NSUInteger)start
arguments:@[ @(client), @(start), @(end) ]];
}

#pragma mark - Screenshot Delegate
#pragma mark - FlutterViewEngineDelegate

- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
asBase64Encoded:(BOOL)base64Encode {
FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
return _shell->Screenshot(type, base64Encode);
}

- (void)flutterViewAccessibilityDidCall {
if (self.viewController.view.accessibilityElements == nil) {
[self ensureSemanticsEnabled];
}
}

- (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
return _binaryMessenger;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@

FLUTTER_ASSERT_NOT_ARC

@interface FlutterEngineSpy : FlutterEngine
@property(nonatomic) BOOL ensureSemanticsEnabledCalled;
@end

@implementation FlutterEngineSpy

- (void)ensureSemanticsEnabled {
_ensureSemanticsEnabledCalled = YES;
}

@end

@interface FlutterEngineTest_mrc : XCTestCase
@end

Expand Down Expand Up @@ -41,4 +53,11 @@ - (void)testSpawnsShareGpuContext {
[spawn release];
}

- (void)testEnableSemanticsWhenFlutterViewAccessibilityDidCall {
FlutterEngineSpy* engine = [[FlutterEngineSpy alloc] initWithName:@"foobar"];
engine.ensureSemanticsEnabledCalled = NO;
[engine flutterViewAccessibilityDidCall];
XCTAssertTrue(engine.ensureSemanticsEnabledCalled);
}

@end
10 changes: 10 additions & 0 deletions shell/platform/darwin/ios/framework/Source/FlutterView.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@
asBase64Encoded:(BOOL)base64Encode;

- (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController;

/**
* A callback that is called when iOS queries accessibility information of the Flutter view.
*
* This is useful to predict the current iOS accessibility status. For example, there is
* no API to listen whether voice control is turned on or off. The Flutter engine uses
* this callback to enable semantics in order to catch the case that voice control is
* on.
*/
- (void)flutterViewAccessibilityDidCall;
@end

@interface FlutterView : UIView
Expand Down
13 changes: 13 additions & 0 deletions shell/platform/darwin/ios/framework/Source/FlutterView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,17 @@ - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
CGContextRestoreGState(context);
}

- (BOOL)isAccessibilityElement {
// iOS does not provide an API to query whether the voice control
// is turned on or off. It is likely at least one of the assitive
// technologies is turned on if this method is called. If we do
// not catch it in notification center, we will catch it here.
//
// TODO(chunhtai): Remove this workaround once iOS provides an
// API to query whether voice control is enabled.
// https://github.com/flutter/flutter/issues/76808.
[_delegate flutterViewAccessibilityDidCall];
return NO;
}

@end
52 changes: 52 additions & 0 deletions shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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.

#import <XCTest/XCTest.h>

#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"

@interface FakeDelegate : NSObject <FlutterViewEngineDelegate>
@property(nonatomic) BOOL callbackCalled;
@end

@implementation FakeDelegate {
std::shared_ptr<flutter::FlutterPlatformViewsController> _platformViewsController;
}

- (instancetype)init {
_callbackCalled = NO;
_platformViewsController = std::shared_ptr<flutter::FlutterPlatformViewsController>(nullptr);
return self;
}

- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
asBase64Encoded:(BOOL)base64Encode {
return {};
}

- (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController {
return _platformViewsController;
}

- (void)flutterViewAccessibilityDidCall {
_callbackCalled = YES;
}

@end

@interface FlutterViewTest : XCTestCase
@end

@implementation FlutterViewTest

- (void)testFlutterViewEnableSemanticsWhenIsAccessibilityElementIsCalled {
FakeDelegate* delegate = [[FakeDelegate alloc] init];
FlutterView* view = [[FlutterView alloc] initWithDelegate:delegate opaque:NO];
delegate.callbackCalled = NO;
XCTAssertFalse(view.isAccessibilityElement);
XCTAssertTrue(delegate.callbackCalled);
}

@end