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