Update default label on EmitAccessibilityEvent if control is modal 25/316825/4
authorYoungsun Suh <youngsun.suh@samsung.com>
Thu, 29 Aug 2024 02:19:26 +0000 (11:19 +0900)
committerYoungsun Suh <youngsun.suh@samsung.com>
Thu, 29 Aug 2024 07:50:20 +0000 (16:50 +0900)
Change-Id: I4f8cc3455ea6942e40506da886898c539effc7cb

automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp
dali-toolkit/devel-api/controls/control-accessible.cpp
dali-toolkit/devel-api/controls/control-accessible.h
dali-toolkit/devel-api/controls/control-devel.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/internal/controls/popup/popup-impl.cpp

index 92d41d3..6822a3d 100644 (file)
 
 using namespace Dali::Toolkit;
 
-void utc_dali_accessibility_controls_bridge_up_startup(void)
-{
-  test_return_value = TET_UNDEF;
-  DBusWrapper::Install(std::unique_ptr<DBusWrapper>(new TestDBusWrapper));
-}
-
-void utc_dali_accessibility_controls_bridge_up_cleanup(void)
+namespace
 {
-  test_return_value = TET_PASS;
-  //DBusWrapper::Install({}) is a de-install
-  DBusWrapper::Install({});
+const auto flushCoalescableMessage = [](Dali::ToolkitTestApplication& application) {
+  Dali::Timer timer = Timer::New(0);
+  for(int i = 0; i < 11; ++i)
+  {
+    application.SendNotification();
+    application.Render();
+    timer.MockEmitSignal();
+  }
+};
 }
 
 namespace Dali
@@ -405,16 +405,6 @@ int UtcDaliControlAccessibilityState(void)
   application.GetScene().Add(control);
   auto accessible = Dali::Accessibility::Accessible::Get(control);
 
-  const auto flushCoalescableMessage = [&]() {
-    Dali::Timer timer = Timer::New(0);
-    for(int i = 0; i < 11; ++i)
-    {
-      application.SendNotification();
-      application.Render();
-      timer.MockEmitSignal();
-    }
-  };
-
   Dali::Accessibility::TestEnableSC(true);
   DALI_TEST_CHECK(!Dali::Accessibility::TestStateChangedCalled());
 
@@ -475,7 +465,7 @@ int UtcDaliControlAccessibilityState(void)
     DALI_TEST_CHECK(states[Dali::Accessibility::State::CHECKED]);
 
     Dali::Accessibility::TestResetStateChangedResult();
-    flushCoalescableMessage();
+    flushCoalescableMessage(application);
 
     // CHECKED: true -> false
     inputStates[DevelControl::AccessibilityState::CHECKED] = false;
@@ -488,7 +478,7 @@ int UtcDaliControlAccessibilityState(void)
     DALI_TEST_CHECK(!states[Dali::Accessibility::State::CHECKED]);
 
     Dali::Accessibility::TestResetStateChangedResult();
-    flushCoalescableMessage();
+    flushCoalescableMessage(application);
   }
 
   // state-changed:selected event is emitted if the object is highlighted and selectable
@@ -508,7 +498,7 @@ int UtcDaliControlAccessibilityState(void)
     DALI_TEST_CHECK(states[Dali::Accessibility::State::SELECTED]);
 
     Dali::Accessibility::TestResetStateChangedResult();
-    flushCoalescableMessage();
+    flushCoalescableMessage(application);
 
     // SELECTED: true -> false
     inputStates[DevelControl::AccessibilityState::SELECTED] = false;
@@ -520,7 +510,7 @@ int UtcDaliControlAccessibilityState(void)
     states = DevelControl::GetAccessibilityStates(control);
     DALI_TEST_CHECK(!states[Dali::Accessibility::State::SELECTED]);
     Dali::Accessibility::TestResetStateChangedResult();
-    flushCoalescableMessage();
+    flushCoalescableMessage(application);
   }
 
   // state-changed event is NOT emitted if object is not checkable or selectable
@@ -1888,3 +1878,60 @@ int UtcDaliWebViewAccessible(void)
 
   END_TEST;
 }
+
+int UtcDaliEmitAccessibilityStateChanged(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Accessibility::TestEnableSC(true);
+
+  auto root = Control::New();
+  root.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+  root.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, DevelControl::AccessibilityRole::CONTAINER);
+
+  auto dialog = Control::New();
+  dialog.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
+  dialog.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, DevelControl::AccessibilityRole::DIALOG);
+  root.Add(dialog);
+
+  auto button = Control::New();
+  button.SetProperty(Actor::Property::SIZE, Vector2(20, 20));
+  button.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, DevelControl::AccessibilityRole::BUTTON);
+  root.Add(button);
+
+  auto rootAccessible   = dynamic_cast<DevelControl::ControlAccessible*>(Accessibility::Accessible::Get(root));
+  auto dialogAccessible = dynamic_cast<DevelControl::ControlAccessible*>(Accessibility::Accessible::Get(dialog));
+  auto buttonAccessible = dynamic_cast<DevelControl::ControlAccessible*>(Accessibility::Accessible::Get(button));
+
+  application.GetScene().Add(root);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(Accessibility::Bridge::GetCurrentBridge()->GetDefaultLabel(rootAccessible) != dialogAccessible);
+
+  // modal role: State is emitted and Default label is registered
+  DevelControl::EmitAccessibilityStateChanged(dialog, Accessibility::State::SHOWING, 1);
+
+  DALI_TEST_CHECK(Dali::Accessibility::TestStateChangedCalled());
+  DALI_TEST_CHECK(Dali::Accessibility::TestStateChangedResult("showing", 1));
+  DALI_TEST_CHECK(Accessibility::Bridge::GetCurrentBridge()->GetDefaultLabel(rootAccessible) == dialogAccessible);
+
+  Dali::Accessibility::TestResetStateChangedResult();
+  flushCoalescableMessage(application);
+
+  // modal role: State is emitted and Default label is unregistered
+  DevelControl::EmitAccessibilityStateChanged(dialog, Accessibility::State::SHOWING, 0);
+
+  DALI_TEST_CHECK(Dali::Accessibility::TestStateChangedCalled());
+  DALI_TEST_CHECK(Dali::Accessibility::TestStateChangedResult("showing", 0));
+  DALI_TEST_CHECK(Accessibility::Bridge::GetCurrentBridge()->GetDefaultLabel(rootAccessible) != dialogAccessible);
+
+  // non-modal role: State is emitted but Default label is not registered
+  DevelControl::EmitAccessibilityStateChanged(button, Accessibility::State::SHOWING, 1);
+
+  DALI_TEST_CHECK(Dali::Accessibility::TestStateChangedCalled());
+  DALI_TEST_CHECK(Dali::Accessibility::TestStateChangedResult("showing", 1));
+  DALI_TEST_CHECK(Accessibility::Bridge::GetCurrentBridge()->GetDefaultLabel(rootAccessible) != buttonAccessible);
+
+  END_TEST;
+}
index cc13b19..66ddc33 100644 (file)
@@ -191,9 +191,9 @@ Dali::Accessibility::Role ConvertRawRoleToAtspiRole(int32_t rawRole)
 
 bool IsModalRole(int32_t rawRole)
 {
-  using Dali::Accessibility::Role;
-  Role role = ConvertRawRoleToAtspiRole(rawRole);
-  return role == Role::ALERT || role == Role::DIALOG || role == Role::POPUP_MENU;
+  return IsRoleV2(rawRole) && (static_cast<AccessibilityRole>(rawRole) == AccessibilityRole::ALERT ||
+                               static_cast<AccessibilityRole>(rawRole) == AccessibilityRole::DIALOG ||
+                               static_cast<AccessibilityRole>(rawRole) == AccessibilityRole::POPUP_MENU);
 }
 
 bool IsHighlightableRole(int32_t rawRole)
@@ -694,4 +694,16 @@ void ControlAccessible::OnStatePropertySet(AccessibilityStates newStates)
   mStatesSnapshot = newStates;
 }
 
+bool ControlAccessible::IsModal(Actor actor)
+{
+  bool isModalPropertySet = actor.GetProperty<bool>(Property::ACCESSIBILITY_IS_MODAL);
+  if(isModalPropertySet)
+  {
+    return true;
+  }
+
+  int32_t rawRole = actor.GetProperty<int32_t>(Property::ACCESSIBILITY_ROLE);
+  return IsModalRole(rawRole);
+}
+
 } // namespace Dali::Toolkit::DevelControl
index c3f9551..2c43259 100644 (file)
@@ -288,6 +288,11 @@ public:
    */
   void OnStatePropertySet(AccessibilityStates newStates);
 
+  /**
+   * @brief Returns true if given actor is considered as modal by propeties set.
+   */
+  static bool IsModal(Actor actor);
+
 private:
   /**
    * @brief Appliys relavant accessibility properties to AT-SPI states.
index 1e5e311..72e7ab1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -313,6 +313,35 @@ bool IsCreateAccessibleEnabled(Toolkit::Control control)
   return GetControlImplementation(control).IsCreateAccessibleEnabled();
 }
 
+void EmitAccessibilityStateChanged(Dali::Actor actor, Accessibility::State state, int newValue)
+{
+  auto accessible = Accessibility::Accessible::GetOwningPtr(actor);
+  if(DALI_LIKELY(accessible))
+  {
+    auto control = Toolkit::Control::DownCast(actor);
+    if(DALI_LIKELY(control))
+    {
+      if(state == Accessibility::State::SHOWING)
+      {
+        bool isModal = ControlAccessible::IsModal(control);
+        if(isModal)
+        {
+          if(newValue == 1)
+          {
+            Accessibility::Bridge::GetCurrentBridge()->RegisterDefaultLabel(accessible);
+          }
+          else
+          {
+            Accessibility::Bridge::GetCurrentBridge()->UnregisterDefaultLabel(accessible);
+          }
+        }
+      }
+    }
+
+    accessible->EmitStateChanged(state, newValue, 0);
+  }
+}
+
 } // namespace DevelControl
 
 } // namespace Toolkit
index 941d293..3fe85d9 100644 (file)
@@ -656,6 +656,15 @@ DALI_TOOLKIT_API void EnableCreateAccessible(Toolkit::Control control, bool enab
  */
 DALI_TOOLKIT_API bool IsCreateAccessibleEnabled(Toolkit::Control control);
 
+/**
+ * @brief The method to emit accessibility state-changed event to accessibility clients
+ *
+ * @param actor The actor that has accessibility state change.
+ * @param state  The accessibility state.
+ * @param newValue new value to set.
+ */
+DALI_TOOLKIT_API void EmitAccessibilityStateChanged(Dali::Actor actor, Dali::Accessibility::State state, int newValue);
+
 } // namespace DevelControl
 
 } // namespace Toolkit
index 73a18e5..16c9ea2 100644 (file)
@@ -343,7 +343,7 @@ void Popup::OnInitialize()
 
   SetupTouch();
 
-  self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::DIALOG);
+  self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, DevelControl::AccessibilityRole::DIALOG);
 }
 
 DevelControl::ControlAccessible* Popup::CreateAccessibleObject()
@@ -728,15 +728,13 @@ void Popup::SetDisplayState(Toolkit::Popup::DisplayState displayState)
   }
 
   // Convert the bool state to the actual display state to use.
-  mDisplayState   = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
-  auto accessible = Dali::Accessibility::Accessible::GetOwningPtr(Self());
+  mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
 
   if(display)
   {
     // Update the state to indicate the current intent.
     mDisplayState = Toolkit::Popup::SHOWING;
-    Dali::Accessibility::Bridge::GetCurrentBridge()->RegisterDefaultLabel(accessible);
-    accessible->EmitShowing(true);
+    DevelControl::EmitAccessibilityStateChanged(Self(), Accessibility::State::SHOWING, 1);
 
     // We want the popup to have key input focus when it is displayed
     SetKeyInputFocus();
@@ -790,9 +788,8 @@ void Popup::SetDisplayState(Toolkit::Popup::DisplayState displayState)
   else // Not visible.
   {
     mDisplayState = Toolkit::Popup::HIDING;
-    Dali::Accessibility::Bridge::GetCurrentBridge()->UnregisterDefaultLabel(accessible);
     ClearKeyInputFocus();
-    accessible->EmitShowing(false);
+    DevelControl::EmitAccessibilityStateChanged(Self(), Accessibility::State::SHOWING, 0);
     // Restore the keyboard focus when popup is hidden.
     if(mPreviousFocusedActor && mPreviousFocusedActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
     {