[M120 Migration][VD][Accessibility] TV customization of accessibility 15/308415/4
authorjiangyuwei <yuwei.jiang@samsung.com>
Mon, 25 Mar 2024 07:13:55 +0000 (15:13 +0800)
committerBot Blink <blinkbot@samsung.com>
Wed, 27 Mar 2024 20:52:44 +0000 (20:52 +0000)
1. TTS does not output for blur and focus on the same node

2. Ignore uncheck event for radio button

3. Do not emit children-changed::remove when subtree will be deleted

4. Avoid description and name completely same

5. Set focus ring color to blue on tizen TV

6. Show focus ring on tv browser

References:
  - https://review.tizen.org/gerrit/#/c/291477/

Change-Id: I183f4702cd43744f8f4bc7fb12a40bcdb74f2b7a
Signed-off-by: jiangyuwei <yuwei.jiang@samsung.com>
content/browser/accessibility/browser_accessibility_manager.cc
third_party/blink/renderer/core/exported/web_view_impl.cc
third_party/blink/renderer/core/layout/layout_theme.cc
third_party/blink/renderer/modules/accessibility/ax_object.cc
third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
tizen_src/chromium_impl/ui/accessibility/platform/ax_platform_node_efl.cc
ui/accessibility/platform/ax_platform_node_auralinux.cc

index 95a81ac..5bd0206 100644 (file)
@@ -406,6 +406,17 @@ bool BrowserAccessibilityManager::OnAccessibilityEvents(
   if (!use_custom_device_scale_factor_for_testing_)
     UpdateDeviceScaleFactor();
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  // if blur event, last_focused_node_ should be set to root or nullptr
+  // for next focus change event. And it may be already set to nullptr
+  // in OnAtomicUpdateFinished, do not reset it here in this case.
+  // for case: blur -> change content -> refocus on the same node
+  for (const ui::AXEvent& event : details.events) {
+    if (event.event_type == ax::mojom::Event::kBlur && GetLastFocusedNode())
+      SetLastFocusedNode(GetRoot());
+  }
+#endif
+
   // Optionally merge multiple tree updates into fewer updates.
   const std::vector<ui::AXTreeUpdate>* tree_updates = &details.updates;
   std::vector<ui::AXTreeUpdate> merged_tree_updates;
index 3045cba..6db04fe 100644 (file)
@@ -3642,7 +3642,11 @@ void WebViewImpl::UpdateRendererPreferences(
 
 #if defined(USE_AURA)
   if (renderer_preferences_.use_custom_colors) {
+#if !BUILDFLAG(IS_TIZEN_TV)
+    // It will set focus ring color to default, but for tizen TV,
+    // focus ring color will be set in layout_theme_chromium_tizen.cc.
     SetFocusRingColor(renderer_preferences_.focus_ring_color);
+#endif
     SetSelectionColors(renderer_preferences_.active_selection_bg_color,
                        renderer_preferences_.active_selection_fg_color,
                        renderer_preferences_.inactive_selection_bg_color,
@@ -3651,9 +3655,13 @@ void WebViewImpl::UpdateRendererPreferences(
   }
 #endif
 
+#if !BUILDFLAG(IS_TIZEN_TV)
+  // It will set focus ring color to default, but for tizen TV,
+  // focus ring color will be set in layout_theme_chromium_tizen.cc.
   if (renderer_preferences_.use_custom_colors) {
     SetFocusRingColor(renderer_preferences_.focus_ring_color);
   }
+#endif
 
   if (old_accept_languages != renderer_preferences_.accept_languages)
     AcceptLanguagesChanged();
index 8213d02..7573328 100644 (file)
 #include "ui/base/ui_base_features.h"
 #include "ui/native_theme/native_theme.h"
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "third_party/blink/public/platform/web_application_type.h"
+#endif
+
 // The methods in this file are shared by all themes on every platform.
 
 namespace blink {
@@ -421,6 +425,22 @@ bool LayoutTheme::IsControlStyled(ControlPart part,
 
 bool LayoutTheme::ShouldDrawDefaultFocusRing(const Node* node,
                                              const ComputedStyle& style) const {
+#if BUILDFLAG(IS_TIZEN)
+  bool should_draw = false;
+  if (node) {
+    LocalFrame* frame = node->GetDocument().GetFrame();
+    Settings* settings = nullptr;
+    if (frame)
+      settings = frame->GetSettings();
+#if BUILDFLAG(IS_TIZEN_TV)
+    if (IsWebBrowser() && settings && settings->GetSpatialNavigationEnabled())
+      should_draw = true;
+#endif
+  }
+  if (!should_draw)
+    return false;
+#endif
+
   if (!node)
     return true;
   if (!style.HasEffectiveAppearance() && !node->IsLink())
index 8793fc9..0f08deb 100644 (file)
@@ -1828,7 +1828,15 @@ void AXObject::SerializeNameAndDescriptionAttributes(
   AXObjectVector description_objects;
   String description =
       Description(name_from, description_from, &description_objects);
+#if BUILDFLAG(IS_TIZEN_TV)
+  // If description string is identical with name string, abandon it.
+  // Delete leading and trailing white space characters before comparing.
+  if (!description.empty() &&
+      base::TrimWhitespaceASCII(description.Utf8(), base::TRIM_ALL) !=
+          base::TrimWhitespaceASCII(name.Utf8(), base::TRIM_ALL)) {
+#else
   if (!description.empty()) {
+#endif
     DCHECK(description_from != ax::mojom::blink::DescriptionFrom::kNone);
     TruncateAndAddStringAttribute(
         node_data, ax::mojom::blink::StringAttribute::kDescription,
index 6f604e7..11c1b7a 100644 (file)
@@ -4298,6 +4298,14 @@ void AXObjectCacheImpl::HandleFocusedUIElementChanged(
   if (old_focused_element) {
     DeferTreeUpdate(TreeUpdateReason::kNodeLostFocus, old_focused_element);
   }
+#if BUILDFLAG(IS_TIZEN_TV)
+  else {
+    // If old_focused_element's ax object is nullptr, set it to root,
+    // or else the blur event can not be sent to browser process.
+    // for case: blur -> change content -> refocus on the same node
+    PostNotification(Root(), ax::mojom::Event::kBlur);
+  }
+#endif
 
   UpdateActiveAriaModalDialog(new_focused_element);
 
index 5f784a7..c200a80 100644 (file)
@@ -102,11 +102,10 @@ void AXPlatformNodeEfl::SetInterfaceMaskFromObject(
   // AX_ATTR_NAME attribute value which contains link or heading contents will
   // be read by screen-reader anyway as it is returned from get_name atk
   // interface.
-  switch (GetData().role) {
-    case ax::mojom::Role::kHeading:
-    case ax::mojom::Role::kLink:
-      return;
-  }
+  if (GetData().role == ax::mojom::Role::kHeading ||
+      GetData().role == ax::mojom::Role::kLink)
+    return;
+
   if (IsTextObjectType() || IsColorWell() || IsSection())
     interface_mask.Add(ImplementedAtkInterfaces::Value::kText);
 
@@ -197,7 +196,7 @@ std::string AXPlatformNodeEfl::GetObjectValue() const {
       GetData().GetStringAttribute(ax::mojom::StringAttribute::kValue);
   if (!value.empty())
     return value;
-  for (uint32_t i = 0; i < GetChildCount(); i++) {
+  for (int i = 0; i < GetChildCount(); i++) {
     AXPlatformNodeEfl* obj = ToAXPlatformNodeEfl(
         AXPlatformNode::FromNativeViewAccessible(ChildAtIndex(i)));
     if (obj) {
@@ -295,8 +294,9 @@ bool AXPlatformNodeEfl::IsDocument() const {
     case ax::mojom::Role::kRootWebArea:
     case ax::mojom::Role::kPdfRoot:
       return true;
+    default:
+      return false;
   }
-  return false;
 }
 
 bool AXPlatformNodeEfl::IsAccessible() const {
@@ -371,7 +371,7 @@ std::string AXPlatformNodeEfl::GetSupplementaryText() const {
 
 std::string AXPlatformNodeEfl::GetChildrenText() const {
   std::string text;
-  for (uint32_t i = 0; i < GetChildCount(); i++) {
+  for (int i = 0; i < GetChildCount(); i++) {
     AXPlatformNodeEfl* obj = ToAXPlatformNodeEfl(
         AXPlatformNode::FromNativeViewAccessible(ChildAtIndex(i)));
     if (obj) {
@@ -397,7 +397,7 @@ std::string AXPlatformNodeEfl::GetChildrenText() const {
 }
 
 bool AXPlatformNodeEfl::HasOnlyTextChildren() const {
-  for (uint32_t i = 0; i < GetChildCount(); i++) {
+  for (int i = 0; i < GetChildCount(); i++) {
     AXPlatformNodeEfl* obj = ToAXPlatformNodeEfl(
         AXPlatformNode::FromNativeViewAccessible(ChildAtIndex(i)));
     if (obj && !obj->IsTextObjectType())
@@ -407,7 +407,7 @@ bool AXPlatformNodeEfl::HasOnlyTextChildren() const {
 }
 
 bool AXPlatformNodeEfl::HasOnlyTextAndImageChildren() const {
-  for (uint32_t i = 0; i < GetChildCount(); i++) {
+  for (int i = 0; i < GetChildCount(); i++) {
     AXPlatformNodeEfl* obj = ToAXPlatformNodeEfl(
         AXPlatformNode::FromNativeViewAccessible(ChildAtIndex(i)));
     if (obj && !obj->IsTextObjectType() &&
@@ -468,10 +468,7 @@ std::string AXPlatformNodeEfl::GetSubTreeSpeechContent() const {
   std::string result;
 
   // if name from contents, will get it from children
-  if (static_cast<ax::mojom::NameFrom>(
-          GetData().GetIntAttribute(ax::mojom::IntAttribute::kNameFrom)) !=
-          ax::mojom::NameFrom::kContents &&
-      !GetData()
+  if (!GetData()
            .GetStringAttribute(ax::mojom::StringAttribute::kName)
            .empty()) {
     result.append(
@@ -487,7 +484,13 @@ std::string AXPlatformNodeEfl::GetSubTreeSpeechContent() const {
     result.append(" ");
   }
 
-  for (uint32_t i = 0; i < GetChildCount(); i++) {
+  // if name from contents, children contents have already been merged in name
+  if (static_cast<ax::mojom::NameFrom>(
+          GetData().GetIntAttribute(ax::mojom::IntAttribute::kNameFrom)) ==
+      ax::mojom::NameFrom::kContents)
+    return result;
+
+  for (int i = 0; i < GetChildCount(); i++) {
     AXPlatformNodeEfl* obj = ToAXPlatformNodeEfl(
         AXPlatformNode::FromNativeViewAccessible(ChildAtIndex(i)));
     if (obj) {
index a4da26f..e115a5c 100644 (file)
@@ -3517,6 +3517,15 @@ void AXPlatformNodeAuraLinux::OnCheckedStateChanged() {
   if (!obj)
     return;
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  // Checking one radio button alway happened when uncheck another button,
+  // Sometimes the uncheck event comes after the check event and interrupt
+  // the reading of check event (see browser setting page), so ignore it
+  if (ax::mojom::Role::kRadioButton == GetData().role &&
+      GetData().GetCheckedState() == ax::mojom::CheckedState::kFalse)
+    return;
+#endif
+
   atk_object_notify_state_change(
       ATK_OBJECT(obj), GetAtkStateTypeForCheckableNode(),
       GetData().GetCheckedState() != ax::mojom::CheckedState::kFalse);
@@ -3768,8 +3777,10 @@ void AXPlatformNodeAuraLinux::OnFocused() {
     return;
   }
 
+#if !BUILDFLAG(IS_TIZEN_TV)
   if (atk_object == g_current_focused)
     return;
+#endif
 
   SetActiveViewsDialog();
 
@@ -4093,6 +4104,12 @@ void AXPlatformNodeAuraLinux::OnSubtreeCreated() {
 }
 
 void AXPlatformNodeAuraLinux::OnSubtreeWillBeDeleted() {
+#if BUILDFLAG(IS_TIZEN_TV)
+  // Tizen screen reader not support children-changed event and after
+  // "children-changed::remove" sent, ATK have a callback to get state
+  // that could cause crash in GetFocusFromThisOrDescendantFrame
+  return;
+#else
   // There is a chance there won't be a parent as we're in the deletion process.
   // We also don't want to notify if this is an ignored node
   if (!GetParent() || GetData().IsIgnored())
@@ -4108,6 +4125,7 @@ void AXPlatformNodeAuraLinux::OnSubtreeWillBeDeleted() {
                         : -1;
   g_signal_emit_by_name(GetParent(), "children-changed::remove", index_gint,
                         atk_object);
+#endif
 }
 
 void AXPlatformNodeAuraLinux::OnParentChanged() {