From b17873a6d82b5b1ebc5049ba12dd1de5fb200023 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Sep 2019 13:11:45 -0700 Subject: [PATCH 1/6] init --- lib/ui/semantics.dart | 14 +++++++++++++- lib/ui/semantics/semantics_node.h | 1 + .../io/flutter/view/AccessibilityBridge.java | 5 +++++ .../ios/framework/Source/accessibility_bridge.mm | 3 +++ shell/platform/embedder/embedder.h | 2 ++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 75df7db4f21f7..379ce9eb6755f 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -290,6 +290,7 @@ class SemanticsFlag { static const int _kHasImplicitScrollingIndex = 1 << 18; static const int _kIsMultilineIndex = 1 << 19; static const int _kIsReadOnlyIndex = 1 << 20; + static const int _kIsLinkIndex = 1 << 21; const SemanticsFlag._(this.index); @@ -332,7 +333,7 @@ class SemanticsFlag { /// Whether the semantic node represents a button. /// - /// Platforms has special handling for buttons, for example Android's TalkBack + /// Platforms have special handling for buttons, for example Android's TalkBack /// and iOS's VoiceOver provides an additional hint when the focused object is /// a button. static const SemanticsFlag isButton = SemanticsFlag._(_kIsButtonIndex); @@ -348,6 +349,14 @@ class SemanticsFlag { /// Only applicable when [isTextField] is true. static const SemanticsFlag isReadOnly = SemanticsFlag._(_kIsReadOnlyIndex); + /// Whether the semantic node is an interactive link. + /// + /// Platforms have special handling for links, for example Android's TalkBack + /// and iOS's VoiceOver provides an additional hint when the focused object is + /// a link, as well as the ability to parse the links through another + /// navigation menu. + static const SemanticsFlag isLink = SemanticsFlag._(_kIsLinkIndex); + /// Whether the semantic node currently holds the user's focus. /// /// The focused element is usually the current receiver of keyboard inputs. @@ -522,6 +531,7 @@ class SemanticsFlag { _kHasImplicitScrollingIndex: hasImplicitScrolling, _kIsMultilineIndex: isMultiline, _kIsReadOnlyIndex: isReadOnly, + _kIsLinkIndex: isLink, }; @override @@ -569,6 +579,8 @@ class SemanticsFlag { return 'SemanticsFlag.isMultiline'; case _kIsReadOnlyIndex: return 'SemanticsFlag.isReadOnly'; + case _kIsLinkIndex: + return 'SemanticsFlag.isLink'; } return null; } diff --git a/lib/ui/semantics/semantics_node.h b/lib/ui/semantics/semantics_node.h index bf3d3beaf2a53..548ee587122b3 100644 --- a/lib/ui/semantics/semantics_node.h +++ b/lib/ui/semantics/semantics_node.h @@ -72,6 +72,7 @@ enum class SemanticsFlags : int32_t { // The Dart API defines the following flag but it isn't used in iOS. // kIsMultiline = 1 << 19, kIsReadOnly = 1 << 20, + kIsLink = 1 << 21, }; const int kScrollableSemanticsFlags = diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 6732c9b445591..d12b1a78eb486 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -594,6 +594,10 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { if (semanticsNode.hasFlag(Flag.IS_BUTTON)) { result.setClassName("android.widget.Button"); } + // TODO(Piinks): Update when ready for SpannableString implementation. + if (semanticsNode.hasFlag(Flag.IS_LINK)) { + result.setClassName("android.widget.Button"); + } if (semanticsNode.hasFlag(Flag.IS_IMAGE)) { result.setClassName("android.widget.ImageView"); // TODO(jonahwilliams): Figure out a way conform to the expected id from TalkBack's @@ -1627,6 +1631,7 @@ private enum Flag { // The Dart API defines the following flag but it isn't used in Android. // IS_MULTILINE(1 << 19); IS_READ_ONLY(1 << 20); + IS_LINK(1 << 21); final int value; diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index ddd5478f8c573..9fcbf90726e1d 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -407,6 +407,9 @@ - (UIAccessibilityTraits)accessibilityTraits { if ([self node].HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) { traits |= UIAccessibilityTraitUpdatesFrequently; } + if ([self node].HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) { + traits |= UIAccessibilityTraitLink; + } return traits; } diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 4953066473107..be8750d8a008f 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -170,6 +170,8 @@ typedef enum { /// /// Only applicable when kFlutterSemanticsFlagIsTextField flag is on. kFlutterSemanticsFlagIsReadOnly = 1 << 20, + /// Whether the semantics node represents a link. + kFlutterSemanticsFlagIsLink = 1 << 21, } FlutterSemanticsFlag; typedef enum { From 9895fa6ad257375b47badc1759b7775a15e7b034 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Sep 2019 16:01:34 -0700 Subject: [PATCH 2/6] ++ --- .../darwin/ios/framework/Source/accessibility_bridge.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 9fcbf90726e1d..938cec276ac37 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -407,7 +407,7 @@ - (UIAccessibilityTraits)accessibilityTraits { if ([self node].HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) { traits |= UIAccessibilityTraitUpdatesFrequently; } - if ([self node].HasFlag(flutter::SemanticsFlags::kIsLiveRegion)) { + if ([self node].HasFlag(flutter::SemanticsFlags::kIsLink)) { traits |= UIAccessibilityTraitLink; } return traits; From e999870dd0f120eb45f76e9472c17d7e929e1cf5 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 26 Sep 2019 10:40:20 -0700 Subject: [PATCH 3/6] typo --- .../android/io/flutter/view/AccessibilityBridge.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index d12b1a78eb486..941027377d1d0 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -594,9 +594,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { if (semanticsNode.hasFlag(Flag.IS_BUTTON)) { result.setClassName("android.widget.Button"); } - // TODO(Piinks): Update when ready for SpannableString implementation. + if (semanticsNode.hasFlag(Flag.IS_LINK)) { - result.setClassName("android.widget.Button"); + result.setClassName("android.text.style.URLSpan"); } if (semanticsNode.hasFlag(Flag.IS_IMAGE)) { result.setClassName("android.widget.ImageView"); @@ -1629,8 +1629,8 @@ private enum Flag { IS_TOGGLED(1 << 17), HAS_IMPLICIT_SCROLLING(1 << 18), // The Dart API defines the following flag but it isn't used in Android. - // IS_MULTILINE(1 << 19); - IS_READ_ONLY(1 << 20); + // IS_MULTILINE(1 << 19), + IS_READ_ONLY(1 << 20), IS_LINK(1 << 21); final int value; From 44ffbd2f97085039e2b38248f49d75ed901beee5 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Mon, 30 Sep 2019 09:57:09 -0700 Subject: [PATCH 4/6] Altering android a11y bridge --- .../android/io/flutter/view/AccessibilityBridge.java | 6 +----- shell/platform/embedder/embedder.h | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 941027377d1d0..0ff321aea7e76 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -591,13 +591,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } } - if (semanticsNode.hasFlag(Flag.IS_BUTTON)) { + if (semanticsNode.hasFlag(Flag.IS_BUTTON) || semanticsNode.hasFlag(Flag.IS_LINK)) { result.setClassName("android.widget.Button"); } - - if (semanticsNode.hasFlag(Flag.IS_LINK)) { - result.setClassName("android.text.style.URLSpan"); - } if (semanticsNode.hasFlag(Flag.IS_IMAGE)) { result.setClassName("android.widget.ImageView"); // TODO(jonahwilliams): Figure out a way conform to the expected id from TalkBack's diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index be8750d8a008f..e93318b3e76a3 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -63,8 +63,7 @@ typedef enum { /// Must match the `SemanticsAction` enum in semantics.dart. typedef enum { /// The equivalent of a user briefly tapping the screen with the finger - /// without - /// moving it. + /// without moving it. kFlutterSemanticsActionTap = 1 << 0, /// The equivalent of a user pressing and holding the screen with the finger /// for a few seconds without moving it. From d1c3273c4ee3a3a3b1d16fe5f9f968c5eb580a3d Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Fri, 4 Oct 2019 09:55:24 -0700 Subject: [PATCH 5/6] Fixing documentation --- lib/ui/semantics.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index ade6eae1f2f13..257944dc258b3 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -352,10 +352,9 @@ class SemanticsFlag { /// Whether the semantic node is an interactive link. /// - /// Platforms have special handling for links, for example Android's TalkBack - /// and iOS's VoiceOver provides an additional hint when the focused object is - /// a link, as well as the ability to parse the links through another - /// navigation menu. + /// Platforms have special handling for links, for example iOS's VoiceOver + /// provides an additional hint when the focused object is a link, as well as + /// the ability to parse the links through another navigation menu. static const SemanticsFlag isLink = SemanticsFlag._(_kIsLinkIndex); /// Whether the semantic node is able to hold the user's focus. From 63b690512dac0f72f48b89267aaf92bc7ca2b284 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Tue, 8 Oct 2019 13:02:37 -0700 Subject: [PATCH 6/6] Adding semantics link flag to web. --- lib/web_ui/lib/src/ui/semantics.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/web_ui/lib/src/ui/semantics.dart b/lib/web_ui/lib/src/ui/semantics.dart index c13892dc68cef..e2ec50cdb82a7 100644 --- a/lib/web_ui/lib/src/ui/semantics.dart +++ b/lib/web_ui/lib/src/ui/semantics.dart @@ -294,6 +294,7 @@ class SemanticsFlag { static const int _kIsMultilineIndex = 1 << 19; static const int _kIsReadOnlyIndex = 1 << 20; static const int _kIsFocusableIndex = 1 << 21; + static const int _kIsLinkIndex = 1 << 22; const SemanticsFlag._(this.index); @@ -341,6 +342,12 @@ class SemanticsFlag { /// a button. static const SemanticsFlag isButton = SemanticsFlag._(_kIsButtonIndex); + /// Whether the semantic node represents a link. + /// + /// Platforms have special handling for links, for example, iOS's VoiceOver + /// provides an additional hint when the focused object is a link. + static const SemanticsFlag isLink = SemanticsFlag._(_kIsButtonIndex); + /// Whether the semantic node represents a text field. /// /// Text fields are announced as such and allow text input via accessibility @@ -522,6 +529,7 @@ class SemanticsFlag { _kIsCheckedIndex: isChecked, _kIsSelectedIndex: isSelected, _kIsButtonIndex: isButton, + _kIsLinkIndex: isLink, _kIsTextFieldIndex: isTextField, _kIsFocusableIndex: isFocusable, _kIsFocusedIndex: isFocused, @@ -553,6 +561,8 @@ class SemanticsFlag { return 'SemanticsFlag.isSelected'; case _kIsButtonIndex: return 'SemanticsFlag.isButton'; + case _kIsLinkIndex: + return 'SemanticsFlag.isLink'; case _kIsTextFieldIndex: return 'SemanticsFlag.isTextField'; case _kIsFocusableIndex: