[ATSPI] Fix for DefaultLabel 21/267321/10
authorLukasz Oleksak <l.oleksak@samsung.com>
Wed, 1 Dec 2021 11:48:17 +0000 (12:48 +0100)
committerLukasz Oleksak <l.oleksak@samsung.com>
Mon, 13 Dec 2021 10:47:47 +0000 (10:47 +0000)
Previously the call to GetDefaultLabelInfo() was delegated by bridge to
the corresponding Accessible object which computed the reply locally (by default returned self).
However default labels should be managed globally within given application.

This patch:

* replaces existing API AddPopup()/RemovePopup() by RegisterDefaultLabel()/UnregisterDefaultLabel()
  which has wider applicability (not only for popups)
* changes the logic of GetDefaultLabelInfo() to compute default label object globally

Related patches:
https://review.tizen.org/gerrit/#/c/platform/core/uifw/dali-toolkit/+/267323/
https://review.tizen.org/gerrit/#/c/platform/core/uifw/dali-csharp-binder/+/267375/

Change-Id: I68ccaf55835109139ba00e2204fcdfcf2627d403

dali/devel-api/adaptor-framework/accessibility-impl.h
dali/internal/accessibility/bridge/accessible.cpp
dali/internal/accessibility/bridge/bridge-accessible.cpp
dali/internal/accessibility/bridge/bridge-accessible.h
dali/internal/accessibility/bridge/bridge-base.cpp
dali/internal/accessibility/bridge/bridge-base.h
dali/internal/accessibility/bridge/dummy-atspi.cpp
dali/internal/accessibility/bridge/dummy-atspi.h

index fed9592..57d6fde 100644 (file)
@@ -35,8 +35,8 @@
 
 //INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/accessibility.h>
-#include <dali/public-api/adaptor-framework/window.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/adaptor-framework/window.h>
 
 namespace Dali
 {
@@ -105,25 +105,38 @@ struct DALI_ADAPTOR_API Bridge
   virtual void RemoveTopLevelWindow(Accessible* object) = 0;
 
   /**
-   * @brief Adds popup window.
+   * @brief Adds object on the top of the stack of "default label" sourcing objects.
    *
-   * Hierarchy of objects visible for accessibility clients is based on tree-like
-   * structure created from Actors objects. This method adds new popup to the tree.
+   * @see GetDefaultLabel
    *
    * @param[in] object The accessible object
    */
-  virtual void AddPopup(Accessible* object) = 0;
+  virtual void RegisterDefaultLabel(Accessible* object) = 0;
 
   /**
-   * @brief Removes popup window.
+   * @brief Removes object from the stack of "default label" sourcing objects.
    *
-   * Hierarchy of objects visible for accessibility clients is based on tree-like
-   * structure created from Actors objects. This method removes previously added
-   * popup window.
+   * @see GetDefaultLabel
    *
    * @param[in] object The accessible object
    */
-  virtual void RemovePopup(Accessible* object) = 0;
+  virtual void UnregisterDefaultLabel(Accessible* object) = 0;
+
+  /**
+   * @brief Gets the top-most object from the stack of "default label" sourcing objects.
+   *
+   * The "default label" is a reading material (text) derived from an accesibility object
+   * that could be read by screen-reader immediately after the navigation context has changed
+   * (window activates, popup shows up, tab changes) and before first UI element is highlighted.
+   *
+   * @return The handler to accessibility object
+   * @note This is a Tizen only feature not present in upstream ATSPI.
+   * Feature can be enabled/disabled for particular context root object
+   * by setting value of its accessibility attribute "default_label".
+   * Following strings are valid values for "default_label" attribute: "enabled", "disabled".
+   * Any other value will be interpreted as "enabled".
+   */
+  virtual Accessible* GetDefaultLabel() const = 0;
 
   /**
    * @brief Sets name of current application which will be visible on accessibility bus.
@@ -718,13 +731,6 @@ public:
   virtual Address GetAddress();
 
   /**
-   * @brief Gets accessibility object, which is "default label" for this object.
-   *
-   * @return The Accessible object
-   */
-  virtual Accessible* GetDefaultLabel();
-
-  /**
    * @brief Deputes an object to perform provided gesture.
    *
    * @param[in] gestureInfo The structure describing the gesture
index 7d6010e..ca6bc78 100644 (file)
@@ -236,11 +236,6 @@ bool Accessible::IsProxy()
   return false;
 }
 
-Accessible* Accessible::GetDefaultLabel()
-{
-  return this;
-}
-
 void Accessible::NotifyAccessibilityStateChange(Dali::Accessibility::States states, bool isRecursive)
 {
   if(auto data = GetBridgeData())
index 2b3d24a..189a091 100644 (file)
@@ -32,7 +32,6 @@ using namespace Dali::Accessibility;
 
 namespace
 {
-
 bool SortVertically(Component* lhs, Component* rhs)
 {
   auto leftRect  = lhs->GetExtents(CoordinateType::WINDOW);
@@ -63,8 +62,8 @@ std::vector<std::vector<Component*>> SplitLines(const std::vector<Component*>& c
   }
 
   std::vector<std::vector<Component*>> lines(1);
-  Dali::Rect<> lineRect = (*first)->GetExtents(CoordinateType::WINDOW);
-  Dali::Rect<> rect;
+  Dali::Rect<>                         lineRect = (*first)->GetExtents(CoordinateType::WINDOW);
+  Dali::Rect<>                         rect;
 
   // Split into lines
   for(auto it = first; it != children.end(); ++it)
@@ -251,7 +250,7 @@ static std::string GetComponentInfo(Component* obj)
   std::ostringstream object;
   auto               extent = obj->GetExtents(CoordinateType::SCREEN);
   object << "name: " << obj->GetName() << " extent: (" << extent.x << ", "
-    << extent.y << "), [" << extent.width << ", " << extent.height << "]";
+         << extent.y << "), [" << extent.width << ", " << extent.height << "]";
   return object.str();
 }
 
@@ -354,13 +353,13 @@ static Accessible* GetDeputyOfProxyInParent(Accessible* obj)
   return nullptr;
 }
 
-static std::vector<Component*> GetScrollableParents(Accessible *accessible)
+static std::vector<Component*> GetScrollableParents(Accessibleaccessible)
 {
   std::vector<Component*> scrollableParents;
 
   while(accessible)
   {
-    accessible = accessible->GetParent();
+    accessible     = accessible->GetParent();
     auto component = dynamic_cast<Component*>(accessible);
     if(component && component->IsScrollable())
     {
@@ -370,7 +369,7 @@ static std::vector<Component*> GetScrollableParents(Accessible *accessible)
   return scrollableParents;
 }
 
-static std::vector<Component*> GetNonDuplicatedScrollableParents(Accessible *child, Accessible *start)
+static std::vector<Component*> GetNonDuplicatedScrollableParents(Accessible* child, Accessible* start)
 {
   auto scrollableParentsOfChild = GetScrollableParents(child);
   auto scrollableParentsOfStart = GetScrollableParents(start);
@@ -381,14 +380,13 @@ static std::vector<Component*> GetNonDuplicatedScrollableParents(Accessible *chi
   {
     scrollableParentsOfChild.pop_back();
     scrollableParentsOfStart.pop_back();
-   }
+  }
 
   return scrollableParentsOfChild;
 }
 
 } // anonymous namespace
 
-
 BridgeAccessible::BridgeAccessible()
 {
 }
@@ -649,8 +647,8 @@ std::vector<Component*> BridgeAccessible::GetValidChildren(const std::vector<Acc
   std::vector<Component*> vec;
 
   Dali::Rect<> scrollableParentExtents;
-  auto nonDuplicatedScrollableParents = GetNonDuplicatedScrollableParents(children.front(), start);
-  if (!nonDuplicatedScrollableParents.empty())
+  auto         nonDuplicatedScrollableParents = GetNonDuplicatedScrollableParents(children.front(), start);
+  if(!nonDuplicatedScrollableParents.empty())
   {
     scrollableParentExtents = nonDuplicatedScrollableParents.front()->GetExtents(CoordinateType::WINDOW);
   }
@@ -690,7 +688,6 @@ void BridgeAccessible::SortChildrenFromTopLeft(std::vector<Dali::Accessibility::
   children = sortedChildren;
 }
 
-
 template<class T>
 struct CycleDetection
 {
@@ -861,7 +858,7 @@ Accessible* BridgeAccessible::CalculateNeighbor(Accessible* root, Accessible* st
     // 2. parent after all children in backward traversing
     // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
     //    Objects with those roles shouldnt be reachable, when navigating next / prev.
-    bool areAllChildrenVisitedOrMovingForward= (children.size() == 0 || forward || areAllChildrenVisited);
+    bool areAllChildrenVisitedOrMovingForward = (children.size() == 0 || forward || areAllChildrenVisited);
 
     if(!forceNext && node != start && areAllChildrenVisitedOrMovingForward && IsObjectAcceptable(node))
     {
@@ -879,7 +876,7 @@ Accessible* BridgeAccessible::CalculateNeighbor(Accessible* root, Accessible* st
     // be checked first before using the elm_layout as a node.
     if(forceNext && forward)
     {
-      auto deputy = GetDeputyOfProxyInParent(node);
+      auto deputy            = GetDeputyOfProxyInParent(node);
       nextRelatedInDirection = GetObjectInRelation(deputy, RelationType::FLOWS_TO);
     }
 
@@ -1041,7 +1038,11 @@ std::string BridgeAccessible::GetName()
 
 DBus::ValueOrError<Accessible*, uint32_t, std::unordered_map<std::string, std::string>> BridgeAccessible::GetDefaultLabelInfo()
 {
-  auto defaultLabel = FindSelf()->GetDefaultLabel();
+  auto defaultLabel = GetDefaultLabel();
+  if(defaultLabel == nullptr)
+  {
+    defaultLabel = FindSelf();
+  }
   // By default, the text is taken from navigation context root's accessibility properties name and description.
   return {defaultLabel, static_cast<uint32_t>(defaultLabel->GetRole()), defaultLabel->GetAttributes()};
 }
index 219db3b..38fd049 100644 (file)
@@ -33,7 +33,6 @@
 class BridgeAccessible : public virtual BridgeBase
 {
 protected:
-
   /**
    * @brief Constructor.
    */
@@ -50,10 +49,10 @@ public:
    */
   enum class NeighborSearchMode
   {
-    NORMAL                          = 0,   ///< Normal
-    RECURSE_FROM_ROOT               = 1,   ///< Recurse from root
-    CONTINUE_AFTER_FAILED_RECURSION = 2,   ///< Continue after failed recursion
-    RECURSE_TO_OUTSIDE              = 3,   ///< Recurse to outside
+    NORMAL                          = 0, ///< Normal
+    RECURSE_FROM_ROOT               = 1, ///< Recurse from root
+    CONTINUE_AFTER_FAILED_RECURSION = 2, ///< Continue after failed recursion
+    RECURSE_TO_OUTSIDE              = 3, ///< Recurse to outside
   };
 
   using ReadingMaterialType = DBus::ValueOrError<
@@ -177,7 +176,7 @@ public:
    *
    * The "Default label" is a text that could be read by screen-reader immediately
    * after the navigation context has changed (window activates, popup shows up, tab changes) and before first UI element is highlighted.
-   * @return The array containing the default label, its role, and its attributes
+   * @return The array containing the Accessible object being a source of default label text, its role, and its attributes
    * @note This is a Tizen only feature not present in upstream ATSPI.
    * Feature can be enabled/disabled for particular context root object by setting value of its accessibility attribute "default_label".
    */
@@ -286,7 +285,6 @@ private:
    */
   Dali::Accessibility::Component* CalculateNavigableAccessibleAtPoint(Dali::Accessibility::Accessible* root, Dali::Accessibility::Point point, Dali::Accessibility::CoordinateType type, unsigned int maxRecursionDepth);
 
-
 protected:
   bool mIsScreenReaderSuppressed = false;
 };
index 23c6c60..816194a 100644 (file)
@@ -184,42 +184,6 @@ Accessible* BridgeBase::FindByPath(const std::string& name) const
   }
 }
 
-void BridgeBase::AddPopup(Accessible* object)
-{
-  if(std::find(mPopups.begin(), mPopups.end(), object) != mPopups.end())
-  {
-    return;
-  }
-  mPopups.push_back(object);
-  if(IsUp())
-  {
-    object->Emit(WindowEvent::ACTIVATE, 0);
-  }
-}
-
-void BridgeBase::RemovePopup(Accessible* object)
-{
-  auto it = std::find(mPopups.begin(), mPopups.end(), object);
-  if(it == mPopups.end())
-  {
-    return;
-  }
-  mPopups.erase(it);
-
-  if(IsUp())
-  {
-    object->Emit(WindowEvent::DEACTIVATE, 0);
-    if(mPopups.empty())
-    {
-      mApplication.mChildren.back()->Emit(WindowEvent::ACTIVATE, 0);
-    }
-    else
-    {
-      mPopups.back()->Emit(WindowEvent::ACTIVATE, 0);
-    }
-  }
-}
-
 void BridgeBase::OnWindowVisibilityChanged(Dali::Window window, bool visible)
 {
   if(visible)
@@ -231,7 +195,6 @@ void BridgeBase::OnWindowVisibilityChanged(Dali::Window window, bool visible)
   {
     Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(window); // Called when Window is hidden and iconified.
   }
-
 }
 
 void BridgeBase::OnWindowFocusChanged(Dali::Window window, bool focusIn)
@@ -264,6 +227,8 @@ void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
   mApplication.mChildren.push_back(windowAccessible);
   SetIsOnRootLevel(windowAccessible);
 
+  RegisterDefaultLabel(windowAccessible);
+
   Dali::Window window = Dali::DevelWindow::Get(windowAccessible->GetInternalActor());
   if(window)
   {
@@ -287,6 +252,8 @@ void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
     }
   }
 
+  UnregisterDefaultLabel(windowAccessible);
+
   for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
   {
     if(mApplication.mChildren[i] == windowAccessible)
@@ -297,6 +264,23 @@ void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
   }
 }
 
+void BridgeBase::RegisterDefaultLabel(Accessible* object)
+{
+  if(std::find(mDefaultLabels.begin(), mDefaultLabels.end(), object) == mDefaultLabels.end())
+  {
+    mDefaultLabels.push_back(object);
+  }
+}
+
+void BridgeBase::UnregisterDefaultLabel(Accessible* object)
+{
+  auto it = std::find(mDefaultLabels.begin(), mDefaultLabels.end(), object);
+  if(it != mDefaultLabels.end())
+  {
+    mDefaultLabels.erase(it);
+  }
+}
+
 std::string BridgeBase::StripPrefix(const std::string& path)
 {
   auto size = strlen(AtspiPath);
@@ -310,7 +294,7 @@ Accessible* BridgeBase::Find(const std::string& path) const
     return &mApplication;
   }
 
-  void* accessible;
+  void*              accessible;
   std::istringstream tmp{path};
   if(!(tmp >> accessible))
   {
@@ -334,7 +318,7 @@ Accessible* BridgeBase::Find(const Address& ptr) const
 
 Accessible* BridgeBase::FindSelf() const
 {
-  auto path  = DBus::DBusServer::getCurrentObjectPath();
+  auto path = DBus::DBusServer::getCurrentObjectPath();
   auto size = strlen(AtspiPath);
   if(path.size() <= size)
   {
index 62a0094..d604994 100644 (file)
@@ -19,9 +19,9 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
 #include <dali/public-api/dali-adaptor-version.h>
 #include <dali/public-api/signals/connection-tracker.h>
-#include <dali/public-api/actors/layer.h>
 #include <memory>
 
 // INTERNAL INCLUDES
@@ -227,14 +227,22 @@ public:
   void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
 
   /**
-   * @copydoc Dali::Accessibility::Bridge::AddPopup()
+   * @copydoc Dali::Accessibility::Bridge::RegisterDefaultLabel()
+   */
+  void RegisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::UnregisterDefaultLabel()
    */
-  void AddPopup(Dali::Accessibility::Accessible* object) override;
+  void UnregisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
 
   /**
-   * @copydoc Dali::Accessibility::Bridge::RemovePopup()
+   * @copydoc Dali::Accessibility::Bridge::GetDefaultLabel()
    */
-  void RemovePopup(Dali::Accessibility::Accessible* object) override;
+  Dali::Accessibility::Accessible* GetDefaultLabel() const override
+  {
+    return mDefaultLabels.empty() ? nullptr : mDefaultLabels.back();
+  }
 
   /**
    * @copydoc Dali::Accessibility::Bridge::GetApplication()
@@ -432,10 +440,9 @@ public:
 
 protected:
   mutable AppAccessible                         mApplication;
-  std::vector<Dali::Accessibility::Accessible*> mPopups;
+  std::vector<Dali::Accessibility::Accessible*> mDefaultLabels;
 
 private:
-
   /**
    * @brief Sets an ID.
    * @param[in] id An ID (integer value)
index 518330f..06d9074 100644 (file)
@@ -34,11 +34,6 @@ std::vector<Accessibility::Accessible*> Accessibility::Accessible::GetChildren()
   return {};
 }
 
-Accessibility::Accessible* Accessibility::Accessible::GetDefaultLabel()
-{
-  return nullptr;
-}
-
 Accessibility::Address Accessibility::Accessible::GetAddress()
 {
   return {};
index 06995b9..38f6cab 100644 (file)
@@ -43,14 +43,19 @@ struct DummyBridge : Dali::Accessibility::Bridge
   {
   }
 
-  void AddPopup(Accessibility::Accessible* object) override
+  void RegisterDefaultLabel(Accessibility::Accessible* object) override
   {
   }
 
-  void RemovePopup(Accessibility::Accessible* object) override
+  void UnregisterDefaultLabel(Accessibility::Accessible* object) override
   {
   }
 
+  Dali::Accessibility::Accessible* GetDefaultLabel() const override
+  {
+    return nullptr;
+  }
+
   void SetApplicationName(std::string name) override
   {
   }