094d2c5febdb25f3c14f243c7618e1d02f857f04
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-base.h
1 #ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
2 #define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/dali-adaptor-version.h>
24 #include <dali/public-api/signals/connection-tracker.h>
25 #include <memory>
26 #include <tuple>
27
28 // INTERNAL INCLUDES
29 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
30 #include <dali/devel-api/adaptor-framework/window-devel.h>
31 #include <dali/devel-api/atspi-interfaces/accessible.h>
32 #include <dali/devel-api/atspi-interfaces/application.h>
33 #include <dali/devel-api/atspi-interfaces/collection.h>
34 #include <dali/devel-api/atspi-interfaces/socket.h>
35 #include <dali/internal/accessibility/bridge/accessibility-common.h>
36
37 /**
38  * @brief The ApplicationAccessible class is to define Accessibility Application.
39  */
40 class ApplicationAccessible : public virtual Dali::Accessibility::Accessible,
41                               public virtual Dali::Accessibility::Application,
42                               public virtual Dali::Accessibility::Collection,
43                               public virtual Dali::Accessibility::Component,
44                               public virtual Dali::Accessibility::Socket
45 {
46 public:
47   Dali::Accessibility::ProxyAccessible          mParent;
48   std::vector<Dali::Accessibility::Accessible*> mChildren;
49   std::string                                   mName;
50   std::string                                   mToolkitName{"dali"};
51   bool                                          mIsEmbedded{false};
52
53   std::string GetName() const override
54   {
55     return mName;
56   }
57
58   std::string GetDescription() const override
59   {
60     return "";
61   }
62
63   Dali::Accessibility::Accessible* GetParent() override
64   {
65     return &mParent;
66   }
67
68   size_t GetChildCount() const override
69   {
70     return mChildren.size();
71   }
72
73   std::vector<Dali::Accessibility::Accessible*> GetChildren() override
74   {
75     return mChildren;
76   }
77
78   Dali::Accessibility::Accessible* GetChildAtIndex(size_t index) override
79   {
80     auto size = mChildren.size();
81     if(index >= size)
82     {
83       throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(size) + " children"};
84     }
85     return mChildren[index];
86   }
87
88   size_t GetIndexInParent() override
89   {
90     if(mIsEmbedded)
91     {
92       return 0u;
93     }
94
95     throw std::domain_error{"can't call GetIndexInParent on application object"};
96   }
97
98   Dali::Accessibility::Role GetRole() const override
99   {
100     return Dali::Accessibility::Role::APPLICATION;
101   }
102
103   Dali::Accessibility::States GetStates() override
104   {
105     Dali::Accessibility::States result;
106
107     for(auto* child : mChildren)
108     {
109       result = result | child->GetStates();
110     }
111
112     return result;
113   }
114
115   Dali::Accessibility::Attributes GetAttributes() const override
116   {
117     return {};
118   }
119
120   /**
121    * @brief Gets the Accessible object from the window.
122    *
123    * @param[in] window The window to find
124    * @return Null if mChildren is empty, otherwise the Accessible object
125    * @note Currently, the default window would be returned when mChildren is not empty.
126    */
127   Dali::Accessibility::Accessible* GetWindowAccessible(Dali::Window window)
128   {
129     if(mChildren.empty())
130     {
131       return nullptr;
132     }
133
134     Dali::Layer rootLayer = window.GetRootLayer();
135
136     // Find a child which is related to the window.
137     for(auto i = 0u; i < mChildren.size(); ++i)
138     {
139       if(rootLayer == mChildren[i]->GetInternalActor())
140       {
141         return mChildren[i];
142       }
143     }
144
145     // If can't find its children, return the default window.
146     return mChildren[0];
147   }
148
149   bool DoGesture(const Dali::Accessibility::GestureInfo& gestureInfo) override
150   {
151     return false;
152   }
153
154   std::vector<Dali::Accessibility::Relation> GetRelationSet() override
155   {
156     return {};
157   }
158
159   Dali::Actor GetInternalActor() override
160   {
161     return Dali::Actor{};
162   }
163
164   Dali::Accessibility::Address GetAddress() const override
165   {
166     return {"", "root"};
167   }
168
169   // Application
170
171   std::string GetToolkitName() const override
172   {
173     return mToolkitName;
174   }
175
176   std::string GetVersion() const override
177   {
178     return std::to_string(Dali::ADAPTOR_MAJOR_VERSION) + "." + std::to_string(Dali::ADAPTOR_MINOR_VERSION);
179   }
180
181   // Socket
182
183   Dali::Accessibility::Address Embed(Dali::Accessibility::Address plug) override
184   {
185     mIsEmbedded = true;
186     mParent.SetAddress(plug);
187
188     return GetAddress();
189   }
190
191   void Unembed(Dali::Accessibility::Address plug) override
192   {
193     if(mParent.GetAddress() == plug)
194     {
195       mIsEmbedded = false;
196       mParent.SetAddress({});
197       Dali::Accessibility::Bridge::GetCurrentBridge()->SetExtentsOffset(0, 0);
198     }
199   }
200
201   void SetOffset(std::int32_t x, std::int32_t y) override
202   {
203     if(!mIsEmbedded)
204     {
205       return;
206     }
207
208     Dali::Accessibility::Bridge::GetCurrentBridge()->SetExtentsOffset(x, y);
209   }
210
211   // Component
212
213   Dali::Rect<> GetExtents(Dali::Accessibility::CoordinateType type) const override
214   {
215     using limits = std::numeric_limits<float>;
216
217     float minX = limits::max();
218     float minY = limits::max();
219     float maxX = limits::min();
220     float maxY = limits::min();
221
222     for(Dali::Accessibility::Accessible* child : mChildren)
223     {
224       auto* component = Dali::Accessibility::Component::DownCast(child);
225       if(!component)
226       {
227         continue;
228       }
229
230       auto extents = component->GetExtents(type);
231
232       minX = std::min(minX, extents.x);
233       minY = std::min(minY, extents.y);
234       maxX = std::max(maxX, extents.x + extents.width);
235       maxY = std::max(maxY, extents.y + extents.height);
236     }
237
238     return {minX, minY, maxX - minX, maxY - minY};
239   }
240
241   Dali::Accessibility::ComponentLayer GetLayer() const override
242   {
243     return Dali::Accessibility::ComponentLayer::WINDOW;
244   }
245
246   std::int16_t GetMdiZOrder() const override
247   {
248     return 0;
249   }
250
251   bool GrabFocus() override
252   {
253     return false;
254   }
255
256   double GetAlpha() const override
257   {
258     return 0.0;
259   }
260
261   bool GrabHighlight() override
262   {
263     return false;
264   }
265
266   bool ClearHighlight() override
267   {
268     return false;
269   }
270
271   bool IsScrollable() const override
272   {
273     return false;
274   }
275 };
276
277 /**
278  * @brief Enumeration for CoalescableMessages.
279  */
280 enum class CoalescableMessages
281 {
282   BOUNDS_CHANGED, ///< Bounds changed
283   SET_OFFSET, ///< Set offset
284 };
285
286 // Custom specialization of std::hash
287 namespace std
288 {
289 template<>
290 struct hash<std::pair<CoalescableMessages, Dali::Accessibility::Accessible*>>
291 {
292   size_t operator()(std::pair<CoalescableMessages, Dali::Accessibility::Accessible*> value) const
293   {
294     return (static_cast<size_t>(value.first) * 131) ^ reinterpret_cast<size_t>(value.second);
295   }
296 };
297 } // namespace std
298
299 /**
300  * @brief The BridgeBase class is basic class for Bridge functions.
301  */
302 class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker
303 {
304   std::unordered_map<std::pair<CoalescableMessages, Dali::Accessibility::Accessible*>, std::tuple<unsigned int, unsigned int, std::function<void()>>> mCoalescableMessages;
305
306   /**
307    * @brief Removes all CoalescableMessages using Tick signal.
308    *
309    * @return False if mCoalescableMessages is empty, otherwise true.
310    */
311   bool TickCoalescableMessages();
312
313 public:
314   /**
315    * @brief Adds CoalescableMessages, Accessible, and delay time to mCoalescableMessages.
316    *
317    * @param[in] kind CoalescableMessages enum value
318    * @param[in] obj Accessible object
319    * @param[in] delay The delay time
320    * @param[in] functor The function to be called // NEED TO UPDATE!
321    */
322   void AddCoalescableMessage(CoalescableMessages kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
323
324   /**
325    * @brief Callback when the visibility of the window is changed.
326    *
327    * @param[in] window The window to be changed
328    * @param[in] visible The visibility of the window
329    */
330   void OnWindowVisibilityChanged(Dali::Window window, bool visible);
331
332   /**
333    * @brief Callback when the window focus is changed.
334    *
335    * @param[in] window The window whose focus is changed
336    * @param[in] focusIn Whether the focus is in/out
337    */
338   void OnWindowFocusChanged(Dali::Window window, bool focusIn);
339
340   /**
341    * @copydoc Dali::Accessibility::Bridge::GetBusName()
342    */
343   const std::string& GetBusName() const override;
344
345   /**
346    * @copydoc Dali::Accessibility::Bridge::AddTopLevelWindow()
347    */
348   void AddTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
349
350   /**
351    * @copydoc Dali::Accessibility::Bridge::RemoveTopLevelWindow()
352    */
353   void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
354
355   /**
356    * @copydoc Dali::Accessibility::Bridge::RegisterDefaultLabel()
357    */
358   void RegisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
359
360   /**
361    * @copydoc Dali::Accessibility::Bridge::UnregisterDefaultLabel()
362    */
363   void UnregisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
364
365   /**
366    * @copydoc Dali::Accessibility::Bridge::GetDefaultLabel()
367    */
368   Dali::Accessibility::Accessible* GetDefaultLabel(Dali::Accessibility::Accessible* root) const override;
369
370   /**
371    * @copydoc Dali::Accessibility::Bridge::GetApplication()
372    */
373   Dali::Accessibility::Accessible* GetApplication() const override
374   {
375     return &mApplication;
376   }
377
378   /**
379    * @brief Adds function to dbus interface.
380    */
381   template<typename SELF, typename... RET, typename... ARGS>
382   void AddFunctionToInterface(
383     DBus::DBusInterfaceDescription& desc, const std::string& funcName, DBus::ValueOrError<RET...> (SELF::*funcPtr)(ARGS...))
384   {
385     if(auto self = dynamic_cast<SELF*>(this))
386       desc.addMethod<DBus::ValueOrError<RET...>(ARGS...)>(
387         funcName,
388         [=](ARGS... args) -> DBus::ValueOrError<RET...> {
389           try
390           {
391             return (self->*funcPtr)(std::move(args)...);
392           }
393           catch(std::domain_error& e)
394           {
395             return DBus::Error{e.what()};
396           }
397         });
398   }
399
400   /**
401    * @brief Adds 'Get' property to dbus interface.
402    */
403   template<typename T, typename SELF>
404   void AddGetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
405                                  const std::string&              funcName,
406                                  T (SELF::*funcPtr)())
407   {
408     if(auto self = dynamic_cast<SELF*>(this))
409       desc.addProperty<T>(funcName,
410                           [=]() -> DBus::ValueOrError<T> {
411                             try
412                             {
413                               return (self->*funcPtr)();
414                             }
415                             catch(std::domain_error& e)
416                             {
417                               return DBus::Error{e.what()};
418                             }
419                           },
420                           {});
421   }
422
423   /**
424    * @brief Adds 'Set' property to dbus interface.
425    */
426   template<typename T, typename SELF>
427   void AddSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
428                                  const std::string&              funcName,
429                                  void (SELF::*funcPtr)(T))
430   {
431     if(auto self = dynamic_cast<SELF*>(this))
432       desc.addProperty<T>(funcName, {}, [=](T t) -> DBus::ValueOrError<void> {
433         try
434         {
435           (self->*funcPtr)(std::move(t));
436           return {};
437         }
438         catch(std::domain_error& e)
439         {
440           return DBus::Error{e.what()};
441         }
442       });
443   }
444
445   /**
446    * @brief Adds 'Set' and 'Get' properties to dbus interface.
447    */
448   template<typename T, typename T1, typename SELF>
449   void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
450                                     const std::string&              funcName,
451                                     T1 (SELF::*funcPtrGet)(),
452                                     DBus::ValueOrError<void> (SELF::*funcPtrSet)(T))
453   {
454     if(auto self = dynamic_cast<SELF*>(this))
455       desc.addProperty<T>(
456         funcName,
457         [=]() -> DBus::ValueOrError<T> {
458           try
459           {
460             return (self->*funcPtrGet)();
461           }
462           catch(std::domain_error& e)
463           {
464             return DBus::Error{e.what()};
465           }
466         },
467         [=](T t) -> DBus::ValueOrError<void> {
468           try
469           {
470             (self->*funcPtrSet)(std::move(t));
471             return {};
472           }
473           catch(std::domain_error& e)
474           {
475             return DBus::Error{e.what()};
476           }
477         });
478   }
479
480   /**
481    * @brief Adds 'Get' and 'Set' properties to dbus interface.
482    */
483   template<typename T, typename T1, typename SELF>
484   void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
485                                     const std::string&              funcName,
486                                     T1 (SELF::*funcPtrGet)(),
487                                     void (SELF::*funcPtrSet)(T))
488   {
489     if(auto self = dynamic_cast<SELF*>(this))
490       desc.addProperty<T>(
491         funcName,
492         [=]() -> DBus::ValueOrError<T> {
493           try
494           {
495             return (self->*funcPtrGet)();
496           }
497           catch(std::domain_error& e)
498           {
499             return DBus::Error{e.what()};
500           }
501         },
502         [=](T t) -> DBus::ValueOrError<void> {
503           try
504           {
505             (self->*funcPtrSet)(std::move(t));
506             return {};
507           }
508           catch(std::domain_error& e)
509           {
510             return DBus::Error{e.what()};
511           }
512         });
513   }
514
515   /**
516    * @brief Gets the string of the path excluding the specified prefix.
517    *
518    * @param path The path to get
519    * @return The string stripped of the specific prefix
520    */
521   static std::string StripPrefix(const std::string& path);
522
523   /**
524    * @brief Finds the Accessible object according to the path.
525    *
526    * @param[in] path The path for Accessible object
527    * @return The Accessible object corresponding to the path
528    */
529   Dali::Accessibility::Accessible* Find(const std::string& path) const;
530
531   /**
532    * @brief Finds the Accessible object with the given address.
533    *
534    * @param[in] ptr The unique Address of the object
535    * @return The Accessible object corresponding to the path
536    */
537   Dali::Accessibility::Accessible* Find(const Dali::Accessibility::Address& ptr) const;
538
539   /**
540    * @brief Returns the target object of the currently executed DBus method call.
541    *
542    * @return The Accessible object
543    * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
544    * because DBus handles the invocation target separately from the method arguments.
545    * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
546    * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
547    */
548   Dali::Accessibility::Accessible* FindCurrentObject() const;
549
550   /**
551    * @brief Returns the target object of the currently executed DBus method call.
552    *
553    * This method tries to downcast the return value of FindCurrentObject() to the requested type,
554    * issuing an error reply to the DBus caller if the requested type is not implemented. Whether
555    * a given type is implemented is decided based on the return value of Accessible::GetInterfaces()
556    * for the current object.
557    *
558    * @tparam I The requested AT-SPI interface
559    * @return The Accessible object (cast to a more derived type)
560    *
561    * @see FindCurrentObject()
562    * @see Dali::Accessibility::AtspiInterface
563    * @see Dali::Accessibility::AtspiInterfaceType
564    * @see Dali::Accessibility::Accessible::GetInterfaces()
565    */
566   template<Dali::Accessibility::AtspiInterface I>
567   auto* FindCurrentObjectWithInterface() const
568   {
569     using Type = Dali::Accessibility::AtspiInterfaceType<I>;
570
571     Type* result;
572     auto* currentObject = FindCurrentObject();
573     DALI_ASSERT_DEBUG(currentObject); // FindCurrentObject() throws domain_error
574
575     if(!(result = Dali::Accessibility::Accessible::DownCast<I>(currentObject)))
576     {
577       std::stringstream s;
578
579       s << "Object " << currentObject->GetAddress().ToString();
580       s << " does not implement ";
581       s << Dali::Accessibility::Accessible::GetInterfaceName(I);
582
583       throw std::domain_error{s.str()};
584     }
585
586     return result;
587   }
588
589   /**
590    * @copydoc Dali::Accessibility::Bridge::FindByPath()
591    */
592   Dali::Accessibility::Accessible* FindByPath(const std::string& name) const override;
593
594   /**
595    * @copydoc Dali::Accessibility::Bridge::SetApplicationName()
596    */
597   void SetApplicationName(std::string name) override
598   {
599     mApplication.mName = std::move(name);
600   }
601
602   /**
603    * @copydoc Dali::Accessibility::Bridge::SetToolkitName()
604    */
605   void SetToolkitName(std::string_view toolkitName) override
606   {
607     mApplication.mToolkitName = std::string{toolkitName};
608   }
609
610 protected:
611   mutable ApplicationAccessible                 mApplication;
612   std::vector<Dali::Accessibility::Accessible*> mDefaultLabels;
613   bool                                          mIsScreenReaderSuppressed = false;
614
615 private:
616   /**
617    * @brief Sets an ID.
618    * @param[in] id An ID (integer value)
619    */
620   void SetId(int id);
621
622   /**
623    * @brief Gets the ID.
624    * @return The ID to be set
625    */
626   int GetId();
627
628   /**
629    * @brief Update registered events.
630    */
631   void UpdateRegisteredEvents();
632
633   using CacheElementType = std::tuple<
634     Dali::Accessibility::Address,
635     Dali::Accessibility::Address,
636     Dali::Accessibility::Address,
637     std::vector<Dali::Accessibility::Address>,
638     std::vector<std::string>,
639     std::string,
640     Dali::Accessibility::Role,
641     std::string,
642     std::array<uint32_t, 2>>;
643
644   /**
645    * @brief Gets Items  // NEED TO UPDATE!
646    *
647    * @return
648    */
649   DBus::ValueOrError<std::vector<CacheElementType>> GetItems();
650
651   /**
652    * @brief Creates CacheElement.
653    *
654    * CreateCacheElement method works for GetItems which is a part of ATSPI protocol.
655    * ATSPI client library (libatspi from at-spi2-core) depending on cacheing policy configuration uses GetItems
656    * to pre-load entire accessible tree from application to its own cache in single dbus call.
657    * Otherwise the particular nodes in a tree are cached lazily when client library tries to access them.
658    * @param item Accessible to get information
659    * @return The elements to be cached
660    */
661   CacheElementType CreateCacheElement(Dali::Accessibility::Accessible* item);
662
663 protected:
664   BridgeBase();
665   virtual ~BridgeBase();
666
667   /**
668    * @copydoc Dali::Accessibility::Bridge::ForceUp()
669    */
670   ForceUpResult ForceUp() override;
671
672   /**
673    * @copydoc Dali::Accessibility::Bridge::ForceDown()
674    */
675   void ForceDown() override;
676
677   DBus::DBusServer           mDbusServer;
678   DBusWrapper::ConnectionPtr mConnectionPtr;
679   int                        mId = 0;
680   DBus::DBusClient           mRegistry;
681   bool                       IsBoundsChangedEventAllowed{false};
682 };
683
684 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H