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