[Tizen][AT-SPI] Move AccessibilityAttributes to Accessible 99/309099/2 accepted/tizen_7.0_unified tizen_7.0 accepted/tizen/7.0/unified/20240418.084438
authorArtur Świgoń <a.swigon@samsung.com>
Thu, 28 Mar 2024 12:02:06 +0000 (13:02 +0100)
committerArtur Świgoń <a.swigon@samsung.com>
Tue, 9 Apr 2024 08:12:46 +0000 (10:12 +0200)
This patch allows setting arbitrary attributes on the Accessible level.
Previously this was only possible for Control, and thus application-side
customization of the attributes was unavailable for some other classes (most
notably Layer, which stands in for Window in the AT-SPI tree).

Change-Id: Iccdf65eb0b078f1962b31fbf3f6091d7e7d3f07d

dali/devel-api/adaptor-framework/accessibility.cpp
dali/devel-api/adaptor-framework/actor-accessible.cpp
dali/devel-api/adaptor-framework/actor-accessible.h
dali/devel-api/adaptor-framework/proxy-accessible.h
dali/devel-api/atspi-interfaces/accessible.h
dali/internal/accessibility/bridge/bridge-base.h

index 804ed61..5c5d1ce 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/public-api/object/type-info.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <map>
+#include <sstream>
 #include <string_view>
 
 // INTERNAL INCLUDES
@@ -197,6 +198,79 @@ std::string Accessible::GetRoleName() const
   return std::string{it->second};
 }
 
+void Accessible::UpdateAttributes(Attributes& attributes) const
+{
+  using MapType = std::map<ReadingInfoType, std::string_view>;
+
+  static const std::string readingInfoTypeKey = "reading_info_type";
+  static const char        separator          = '|';
+  static const MapType     readingInfoTypeMap{
+    {ReadingInfoType::NAME, "name"},
+    {ReadingInfoType::ROLE, "role"},
+    {ReadingInfoType::DESCRIPTION, "description"},
+    {ReadingInfoType::STATE, "state"},
+  };
+
+  bool allEnabled = mReadingInfoTypes[ReadingInfoType::NAME]
+    && mReadingInfoTypes[ReadingInfoType::ROLE]
+    && mReadingInfoTypes[ReadingInfoType::DESCRIPTION]
+    && mReadingInfoTypes[ReadingInfoType::STATE];
+
+  if(DALI_LIKELY(allEnabled))
+  {
+    attributes.erase(readingInfoTypeKey);
+    return;
+  }
+
+  std::stringstream buf;
+  for(auto& item : readingInfoTypeMap)
+  {
+    if(mReadingInfoTypes[item.first])
+    {
+      if(buf.tellp()) // non-empty
+      {
+        buf << separator;
+      }
+
+      buf << item.second;
+    }
+  }
+
+  attributes.insert_or_assign(readingInfoTypeKey, buf.str());
+}
+
+const Attributes& Accessible::GetAttributes() const
+{
+  UpdateAttributes(mAttributes);
+
+  return mAttributes;
+}
+
+bool Accessible::SetAttribute(const std::string& key, const std::string& value)
+{
+  return mAttributes.insert_or_assign(key, value).second;
+}
+
+bool Accessible::UnsetAttribute(const std::string& key)
+{
+  return (mAttributes.erase(key) > 0);
+}
+
+void Accessible::ClearAttributes()
+{
+  mAttributes.clear();
+}
+
+ReadingInfoTypes Accessible::GetReadingInfoTypes() const
+{
+  return mReadingInfoTypes;
+}
+
+void Accessible::SetReadingInfoTypes(ReadingInfoTypes types)
+{
+  mReadingInfoTypes = types;
+}
+
 AtspiInterfaces Accessible::GetInterfaces() const
 {
   if(!mInterfaces)
@@ -459,22 +533,19 @@ public:
     return state;
   }
 
-  Attributes GetAttributes() const override
+  void UpdateAttributes(Attributes& attributes) const override
   {
-    Attributes attributes;
+    static const std::string resIDKey = "resID";
 
-    if(mRoot)
+    ActorAccessible::UpdateAttributes(attributes);
+
+    if(mRoot && attributes.find(resIDKey) == attributes.end())
     {
       Dali::Window window                         = Dali::DevelWindow::Get(Self());
       Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
-      attributes["resID"]                         = windowImpl.GetNativeResourceId();
-    }
 
-    Dali::TypeInfo type;
-    Self().GetTypeInfo(type);
-    attributes["class"] = type.GetName();
-
-    return attributes;
+      attributes.emplace(resIDKey, windowImpl.GetNativeResourceId());
+    }
   }
 
   bool DoGesture(const GestureInfo& gestureInfo) override
index 6f940a7..56125f2 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/actors/actor-devel.h>
+#include <dali/public-api/object/type-info.h>
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/window-devel.h>
@@ -177,6 +178,23 @@ void ActorAccessible::DoGetChildren(std::vector<Accessible*>& children)
   }
 }
 
+void ActorAccessible::UpdateAttributes(Attributes& attributes) const
+{
+  static const std::string classKey = "class";
+
+  Accessible::UpdateAttributes(attributes);
+
+  if(attributes.find(classKey) == attributes.end())
+  {
+    Dali::TypeInfo typeInfo;
+    Self().GetTypeInfo(typeInfo);
+    if(typeInfo)
+    {
+      attributes.emplace(classKey, typeInfo.GetName());
+    }
+  }
+}
+
 void ActorAccessible::UpdateChildren()
 {
   if(!mChildrenDirty)
index 1cf3812..777ae9c 100644 (file)
@@ -146,6 +146,11 @@ protected:
    */
   virtual void DoGetChildren(std::vector<Accessible*>& children);
 
+  /**
+   * @copydoc Dali::Accessibility::Accessible::UpdateAttributes()
+   */
+  void UpdateAttributes(Attributes& attributes) const override;
+
 private:
   // Extra overload for OnChildrenChanged() to connect to signals directly
   void OnChildrenChanged(Dali::Actor);
index 33e6b1b..7d4ff21 100644 (file)
@@ -104,11 +104,6 @@ public:
     return {};
   }
 
-  Attributes GetAttributes() const override
-  {
-    return {};
-  }
-
   bool IsProxy() const override
   {
     return true;
index 554fb73..2ba4791 100644 (file)
@@ -250,9 +250,73 @@ public:
   /**
    * @brief Gets accessibility attributes.
    *
+   * Attributes are key-value string pairs which can be used to transfer arbitrary
+   * information from the application to a client such as a screen reader or an
+   * automation framework.
+   *
+   * Typically, attributes are used when the data does not fit any other category
+   * with a dedicated API (name, description, states etc.).
+   *
+   * @see Accessible::SetAttribute()
+   * @see Accessible::UnsetAttribute()
+   * @see Accessible::ClearAttributes()
+   * @see Accessible::UpdateAttributes()
+   *
    * @return The map of attributes and their values
    */
-  virtual Attributes GetAttributes() const = 0;
+  const Attributes& GetAttributes() const;
+
+  /**
+   * @brief Sets an attribute
+   *
+   * The key will be created if necessary and the old attribute value (if any) will be replaced.
+   *
+   * @param[in] key Attribute key
+   * @param[in] value Attribute value
+   *
+   * @return True if the key was created, false otherwise (only value was updated)
+   */
+  bool SetAttribute(const std::string& key, const std::string& value);
+
+  /**
+   * @brief Unsets an attribute
+   *
+   * The key-value pair is removed from the attribute collection.
+   *
+   * @param[in] key Attribute key
+   *
+   * @return True if there was such a key, false otherwise
+   */
+  bool UnsetAttribute(const std::string& key);
+
+  /**
+   * @brief Unsets all attributes
+   *
+   * @see Accessible::UnsetAttribute()
+   */
+  void ClearAttributes();
+
+  /**
+   * @brief Gets the reading info types
+   *
+   * @return Reading info types bitmask
+   * @see Accessible::SetReadingInfoTypes()
+   */
+  ReadingInfoTypes GetReadingInfoTypes() const;
+
+  /**
+   * @brief Sets the reading info types
+   *
+   * The reading info types are individual pieces of information (name, role etc.)
+   * that can be read by the screen reader. This method can be used to enable and
+   * disable reading specific pieces.
+   *
+   * @param[in] types Reading info types bitmask
+   *
+   * @note The types will appear in GetAttributes() under the "reading_info_type" key.
+   * @see Accessible::GetAttributes()
+   */
+  void SetReadingInfoTypes(ReadingInfoTypes types);
 
   /**
    * @brief Checks if this is hidden.
@@ -398,6 +462,21 @@ protected:
    */
   virtual AtspiInterfaces DoGetInterfaces() const;
 
+  /**
+   * @brief Updates the attribute collection
+   *
+   * This method, which is always called by GetAttributes(), can be overriden to
+   * provide lazily-calculated or dynamically-calculated (i.e. non-constant)
+   * attributes. When overriding, make sure to call the base class implementation
+   * first.
+   *
+   * @note The attribute collection is non-empty on entry
+   * @see Accessible::GetAttributes()
+   *
+   * @param[inout] attributes The attribute collection to update
+   */
+  virtual void UpdateAttributes(Attributes& attributes) const;
+
 public:
   /**
    * @brief Gets the highlight actor.
@@ -484,9 +563,10 @@ private:
 
   mutable std::weak_ptr<Bridge::Data> mBridgeData;
   mutable AtspiInterfaces             mInterfaces;
+  mutable Attributes                  mAttributes;
+  ReadingInfoTypes                    mReadingInfoTypes = ~ReadingInfoTypes(); // all set
   AtspiEvents                         mSuppressedEvents;
   bool                                mIsOnRootLevel = false;
-
 }; // Accessible class
 
 namespace Internal
index 8426ce4..5abe6d5 100644 (file)
@@ -116,11 +116,6 @@ public:
     return result;
   }
 
-  Dali::Accessibility::Attributes GetAttributes() const override
-  {
-    return {};
-  }
-
   /**
    * @brief Gets the Accessible object from the window.
    *