Skip to content

Commit 977cb0e

Browse files
authored
Access on/off labels accessibility setting for switches on iOS (flutter#30764)
1 parent 8029680 commit 977cb0e

File tree

6 files changed

+95
-18
lines changed

6 files changed

+95
-18
lines changed

lib/ui/window.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ class AccessibilityFeatures {
771771
static const int _kBoldTextIndex = 1 << 3;
772772
static const int _kReduceMotionIndex = 1 << 4;
773773
static const int _kHighContrastIndex = 1 << 5;
774+
static const int _kOnOffSwitchLabelsIndex = 1 << 6;
774775

775776
// A bitfield which represents each enabled feature.
776777
final int _index;
@@ -803,6 +804,11 @@ class AccessibilityFeatures {
803804
/// Only supported on iOS.
804805
bool get highContrast => _kHighContrastIndex & _index != 0;
805806

807+
/// The platform is requesting to show on/off labels inside switches.
808+
///
809+
/// Only supported on iOS.
810+
bool get onOffSwitchLabels => _kOnOffSwitchLabelsIndex & _index != 0;
811+
806812
@override
807813
String toString() {
808814
final List<String> features = <String>[];
@@ -818,6 +824,8 @@ class AccessibilityFeatures {
818824
features.add('reduceMotion');
819825
if (highContrast)
820826
features.add('highContrast');
827+
if (onOffSwitchLabels)
828+
features.add('onOffSwitchLabels');
821829
return 'AccessibilityFeatures$features';
822830
}
823831

lib/ui/window/platform_configuration.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum class AccessibilityFeatureFlag : int32_t {
3535
kBoldText = 1 << 3,
3636
kReduceMotion = 1 << 4,
3737
kHighContrast = 1 << 5,
38+
kOnOffSwitchLabels = 1 << 6,
3839
};
3940

4041
//--------------------------------------------------------------------------

lib/web_ui/lib/window.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class AccessibilityFeatures {
148148
static const int _kBoldTextIndex = 1 << 3;
149149
static const int _kReduceMotionIndex = 1 << 4;
150150
static const int _kHighContrastIndex = 1 << 5;
151+
static const int _kOnOffSwitchLabelsIndex = 1 << 6;
151152

152153
// A bitfield which represents each enabled feature.
153154
final int _index;
@@ -158,6 +159,7 @@ class AccessibilityFeatures {
158159
bool get boldText => _kBoldTextIndex & _index != 0;
159160
bool get reduceMotion => _kReduceMotionIndex & _index != 0;
160161
bool get highContrast => _kHighContrastIndex & _index != 0;
162+
bool get onOffSwitchLabels => _kOnOffSwitchLabelsIndex & _index != 0;
161163

162164
@override
163165
String toString() {
@@ -180,6 +182,9 @@ class AccessibilityFeatures {
180182
if (highContrast) {
181183
features.add('highContrast');
182184
}
185+
if (onOffSwitchLabels) {
186+
features.add('onOffSwitchLabels');
187+
}
183188
return 'AccessibilityFeatures$features';
184189
}
185190

shell/platform/darwin/ios/framework/Source/FlutterViewController.mm

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,13 @@ - (void)setupNotificationCenterObservers {
331331
name:UIAccessibilityDarkerSystemColorsStatusDidChangeNotification
332332
object:nil];
333333

334+
if (@available(iOS 13.0, *)) {
335+
[center addObserver:self
336+
selector:@selector(onAccessibilityStatusChanged:)
337+
name:UIAccessibilityOnOffSwitchLabelsDidChangeNotification
338+
object:nil];
339+
}
340+
334341
[center addObserver:self
335342
selector:@selector(onUserSettingsChanged:)
336343
name:UIContentSizeCategoryDidChangeNotification
@@ -1417,19 +1424,7 @@ - (void)onAccessibilityStatusChanged:(NSNotification*)notification {
14171424
return;
14181425
}
14191426
auto platformView = [_engine.get() platformView];
1420-
int32_t flags = 0;
1421-
if (UIAccessibilityIsInvertColorsEnabled()) {
1422-
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kInvertColors);
1423-
}
1424-
if (UIAccessibilityIsReduceMotionEnabled()) {
1425-
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kReduceMotion);
1426-
}
1427-
if (UIAccessibilityIsBoldTextEnabled()) {
1428-
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kBoldText);
1429-
}
1430-
if (UIAccessibilityDarkerSystemColorsEnabled()) {
1431-
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kHighContrast);
1432-
}
1427+
int32_t flags = [self accessibilityFlags];
14331428
#if TARGET_OS_SIMULATOR
14341429
// There doesn't appear to be any way to determine whether the accessibility
14351430
// inspector is enabled on the simulator. We conservatively always turn on the
@@ -1447,6 +1442,35 @@ - (void)onAccessibilityStatusChanged:(NSNotification*)notification {
14471442
#endif
14481443
}
14491444

1445+
- (int32_t)accessibilityFlags {
1446+
int32_t flags = 0;
1447+
if (UIAccessibilityIsInvertColorsEnabled()) {
1448+
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kInvertColors);
1449+
}
1450+
if (UIAccessibilityIsReduceMotionEnabled()) {
1451+
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kReduceMotion);
1452+
}
1453+
if (UIAccessibilityIsBoldTextEnabled()) {
1454+
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kBoldText);
1455+
}
1456+
if (UIAccessibilityDarkerSystemColorsEnabled()) {
1457+
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kHighContrast);
1458+
}
1459+
if ([FlutterViewController accessibilityIsOnOffSwitchLabelsEnabled]) {
1460+
flags |= static_cast<int32_t>(flutter::AccessibilityFeatureFlag::kOnOffSwitchLabels);
1461+
}
1462+
1463+
return flags;
1464+
}
1465+
1466+
+ (BOOL)accessibilityIsOnOffSwitchLabelsEnabled {
1467+
if (@available(iOS 13, *)) {
1468+
return UIAccessibilityIsOnOffSwitchLabelsEnabled();
1469+
} else {
1470+
return NO;
1471+
}
1472+
}
1473+
14501474
#pragma mark - Set user settings
14511475

14521476
- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {

shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#import <XCTest/XCTest.h>
77

88
#include "flutter/fml/platform/darwin/message_loop_darwin.h"
9+
#import "flutter/lib/ui/window/platform_configuration.h"
910
#import "flutter/lib/ui/window/viewport_metrics.h"
1011
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
1112
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
@@ -25,10 +26,6 @@ - (void)sendKeyEvent:(const FlutterKeyEvent&)event
2526
userData:(nullable void*)userData;
2627
@end
2728

28-
namespace flutter {
29-
class PointerDataPacket {};
30-
}
31-
3229
/// Sometimes we have to use a custom mock to avoid retain cycles in OCMock.
3330
/// Used for testing low memory notification.
3431
@interface FlutterEnginePartialMock : FlutterEngine
@@ -617,6 +614,46 @@ - (void)testItReportsHighContrastWhenTraitCollectionRequestsIt {
617614
[mockTraitCollection stopMocking];
618615
}
619616

617+
- (void)testItReportsAccessibilityOnOffSwitchLabelsFlagNotSet {
618+
if (@available(iOS 13, *)) {
619+
// noop
620+
} else {
621+
return;
622+
}
623+
624+
// Setup test.
625+
FlutterViewController* viewController =
626+
[[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil];
627+
id partialMockViewController = OCMPartialMock(viewController);
628+
OCMStub([partialMockViewController accessibilityIsOnOffSwitchLabelsEnabled]).andReturn(NO);
629+
630+
// Exercise behavior under test.
631+
int32_t flags = [partialMockViewController accessibilityFlags];
632+
633+
// Verify behavior.
634+
XCTAssert((flags & (int32_t)flutter::AccessibilityFeatureFlag::kOnOffSwitchLabels) == 0);
635+
}
636+
637+
- (void)testItReportsAccessibilityOnOffSwitchLabelsFlagSet {
638+
if (@available(iOS 13, *)) {
639+
// noop
640+
} else {
641+
return;
642+
}
643+
644+
// Setup test.
645+
FlutterViewController* viewController =
646+
[[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil bundle:nil];
647+
id partialMockViewController = OCMPartialMock(viewController);
648+
OCMStub([partialMockViewController accessibilityIsOnOffSwitchLabelsEnabled]).andReturn(YES);
649+
650+
// Exercise behavior under test.
651+
int32_t flags = [partialMockViewController accessibilityFlags];
652+
653+
// Verify behavior.
654+
XCTAssert((flags & (int32_t)flutter::AccessibilityFeatureFlag::kOnOffSwitchLabels) != 0);
655+
}
656+
620657
- (void)testPerformOrientationUpdateForcesOrientationChange {
621658
[self orientationTestWithOrientationUpdate:UIInterfaceOrientationMaskPortrait
622659
currentOrientation:UIInterfaceOrientationLandscapeLeft
@@ -1052,7 +1089,7 @@ - (void)testMouseSupport API_AVAILABLE(ios(13.4)) {
10521089
[vc scrollEvent:mockPanGestureRecognizer];
10531090

10541091
[[[self.mockEngine verify] ignoringNonObjectArgs]
1055-
dispatchPointerDataPacket:std::make_unique<flutter::PointerDataPacket>()];
1092+
dispatchPointerDataPacket:std::make_unique<flutter::PointerDataPacket>(0)];
10561093
}
10571094

10581095
@end

shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern NSNotificationName const FlutterViewControllerShowHomeIndicator;
2929

3030
@interface FlutterViewController () <FlutterViewResponder>
3131

32+
@property(class, nonatomic, readonly) BOOL accessibilityIsOnOffSwitchLabelsEnabled;
3233
@property(nonatomic, readonly) BOOL isPresentingViewController;
3334
@property(nonatomic, readonly) BOOL isVoiceOverRunning;
3435
@property(nonatomic, retain) FlutterKeyboardManager* keyboardManager;
@@ -45,6 +46,7 @@ extern NSNotificationName const FlutterViewControllerShowHomeIndicator;
4546
nextAction:(void (^)())nextAction API_AVAILABLE(ios(13.4));
4647
- (void)addInternalPlugins;
4748
- (void)deregisterNotifications;
49+
- (int32_t)accessibilityFlags;
4850
@end
4951

5052
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_

0 commit comments

Comments
 (0)