[ATSPI] Add some descriptions to Bridge objects
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-base.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/accessibility/bridge/bridge-base.h>
20
21 // EXTERNAL INCLUDES
22 #include <atomic>
23 #include <cstdlib>
24 #include <memory>
25
26 // INTERNAL INCLUDES
27 #include <dali/public-api/adaptor-framework/timer.h>
28
29 using namespace Dali::Accessibility;
30
31 static Dali::Timer tickTimer;
32
33 BridgeBase::~BridgeBase()
34 {
35 }
36
37 BridgeBase::BridgeBase()
38 {
39 }
40
41 void BridgeBase::AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor)
42 {
43   if(delay < 0)
44   {
45     delay = 0;
46   }
47
48   auto it = mFilteredEvents.insert({{kind, obj}, {static_cast<unsigned int>(delay * 10), {}}});
49   if(it.second)
50   {
51     functor();
52   }
53   else
54   {
55     it.first->second.second = std::move(functor);
56   }
57
58   if(!tickTimer)
59   {
60     tickTimer = Dali::Timer::New(100);
61     tickTimer.TickSignal().Connect(this, &BridgeBase::TickFilteredEvents);
62   }
63 }
64
65 bool BridgeBase::TickFilteredEvents()
66 {
67   for(auto it = mFilteredEvents.begin(); it != mFilteredEvents.end();)
68   {
69     if(it->second.first)
70     {
71       --it->second.first;
72     }
73     else
74     {
75       if(it->second.second)
76       {
77         it->second.second();
78         it->second.second = {};
79       }
80       else
81       {
82         it = mFilteredEvents.erase(it);
83         continue;
84       }
85     }
86     ++it;
87   }
88   return !mFilteredEvents.empty();
89 }
90
91 void BridgeBase::UpdateRegisteredEvents()
92 {
93   using ReturnType = std::vector<std::tuple<std::string, std::string>>;
94   mRegistry.method<DBus::ValueOrError<ReturnType>()>("GetRegisteredEvents").asyncCall([this](DBus::ValueOrError<ReturnType> msg) {
95     if(!msg)
96     {
97       LOG() << "Get registered events failed";
98       return;
99     }
100
101     IsBoundsChangedEventAllowed = false;
102
103     ReturnType values = std::get<ReturnType>(msg.getValues());
104     for(long unsigned int i = 0; i < values.size(); i++)
105     {
106       if(!std::get<1>(values[i]).compare("Object:BoundsChanged"))
107       {
108         IsBoundsChangedEventAllowed = true;
109       }
110     }
111   });
112 }
113
114 BridgeBase::ForceUpResult BridgeBase::ForceUp()
115 {
116   if(Bridge::ForceUp() == ForceUpResult::ALREADY_UP)
117   {
118     return ForceUpResult::ALREADY_UP;
119   }
120   auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
121   auto addr  = proxy.method<std::string()>(dbusLocators::atspi::GET_ADDRESS).call();
122
123   if(!addr)
124   {
125     throw std::domain_error{std::string("failed at call '") + dbusLocators::atspi::GET_ADDRESS + "': " + addr.getError().message};
126   }
127
128   mConnectionPtr  = DBusWrapper::Installed()->eldbus_address_connection_get_impl(std::get<0>(addr));
129   mData->mBusName = DBus::getConnectionName(mConnectionPtr);
130   mDbusServer     = {mConnectionPtr};
131
132   {
133     DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCache};
134     AddFunctionToInterface(desc, "GetItems", &BridgeBase::GetItems);
135     mDbusServer.addInterface(AtspiDbusPathCache, desc);
136   }
137   {
138     DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceApplication};
139     AddGetSetPropertyToInterface(desc, "Id", &BridgeBase::GetId, &BridgeBase::SetId);
140     mDbusServer.addInterface(AtspiPath, desc);
141   }
142
143   mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, AtspiDbusInterfaceRegistry, mConnectionPtr};
144
145   UpdateRegisteredEvents();
146
147   mRegistry.addSignal<void(void)>("EventListenerRegistered", [this](void) {
148     UpdateRegisteredEvents();
149   });
150
151   mRegistry.addSignal<void(void)>("EventListenerDeregistered", [this](void) {
152     UpdateRegisteredEvents();
153   });
154
155   return ForceUpResult::JUST_STARTED;
156 }
157
158 void BridgeBase::ForceDown()
159 {
160   Bridge::ForceDown();
161   mRegistry      = {};
162   mDbusServer    = {};
163   mConnectionPtr = {};
164 }
165
166 const std::string& BridgeBase::GetBusName() const
167 {
168   static std::string empty;
169   return mData ? mData->mBusName : empty;
170 }
171
172 Accessible* BridgeBase::FindByPath(const std::string& name) const
173 {
174   try
175   {
176     return Find(name);
177   }
178   catch(std::domain_error&)
179   {
180     return nullptr;
181   }
182 }
183
184 void BridgeBase::AddPopup(Accessible* object)
185 {
186   if(std::find(mPopups.begin(), mPopups.end(), object) != mPopups.end())
187   {
188     return;
189   }
190   mPopups.push_back(object);
191   if(IsUp())
192   {
193     object->Emit(WindowEvent::ACTIVATE, 0);
194   }
195 }
196
197 void BridgeBase::RemovePopup(Accessible* object)
198 {
199   auto it = std::find(mPopups.begin(), mPopups.end(), object);
200   if(it == mPopups.end())
201   {
202     return;
203   }
204   mPopups.erase(it);
205
206   if(IsUp())
207   {
208     object->Emit(WindowEvent::DEACTIVATE, 0);
209     if(mPopups.empty())
210     {
211       mApplication.mChildren.back()->Emit(WindowEvent::ACTIVATE, 0);
212     }
213     else
214     {
215       mPopups.back()->Emit(WindowEvent::ACTIVATE, 0);
216     }
217   }
218 }
219
220 void BridgeBase::AddTopLevelWindow(Accessible* root)
221 {
222   mApplication.mChildren.push_back(root);
223   SetIsOnRootLevel(root);
224 }
225
226 void BridgeBase::RemoveTopLevelWindow(Accessible* root)
227 {
228   for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
229   {
230     if(mApplication.mChildren[i] == root)
231     {
232       mApplication.mChildren.erase(mApplication.mChildren.begin() + i);
233       break;
234     }
235   }
236 }
237
238 std::string BridgeBase::StripPrefix(const std::string& path)
239 {
240   auto size = strlen(AtspiPath);
241   return path.substr(size + 1);
242 }
243
244 Accessible* BridgeBase::Find(const std::string& path) const
245 {
246   if(path == "root")
247   {
248     return &mApplication;
249   }
250
251   void* accessible;
252   std::istringstream tmp{path};
253   if(!(tmp >> accessible))
254   {
255     throw std::domain_error{"invalid path '" + path + "'"};
256   }
257
258   auto it = mData->mKnownObjects.find(static_cast<Accessible*>(accessible));
259   if(it == mData->mKnownObjects.end())
260   {
261     throw std::domain_error{"unknown object '" + path + "'"};
262   }
263
264   return static_cast<Accessible*>(accessible);
265 }
266
267 Accessible* BridgeBase::Find(const Address& ptr) const
268 {
269   assert(ptr.GetBus() == mData->mBusName);
270   return Find(ptr.GetPath());
271 }
272
273 Accessible* BridgeBase::FindSelf() const
274 {
275   auto path  = DBus::DBusServer::getCurrentObjectPath();
276   auto size = strlen(AtspiPath);
277   if(path.size() <= size)
278   {
279     throw std::domain_error{"invalid path '" + path + "'"};
280   }
281   if(path.substr(0, size) != AtspiPath)
282   {
283     throw std::domain_error{"invalid path '" + path + "'"};
284   }
285   if(path[size] != '/')
286   {
287     throw std::domain_error{"invalid path '" + path + "'"};
288   }
289   return Find(StripPrefix(path));
290 }
291
292 void BridgeBase::SetId(int id)
293 {
294   this->mId = id;
295 }
296
297 int BridgeBase::GetId()
298 {
299   return this->mId;
300 }
301
302 auto BridgeBase::GetItems() -> DBus::ValueOrError<std::vector<CacheElementType>>
303 {
304   auto root = &mApplication;
305
306   std::vector<CacheElementType> res;
307
308   std::function<void(Accessible*)> proc =
309     [&](Accessible* item) {
310       res.emplace_back(std::move(CreateCacheElement(root)));
311       for(auto i = 0u; i < item->GetChildCount(); ++i)
312       {
313         proc(item->GetChildAtIndex(i));
314       }
315     };
316
317   return res;
318 }
319
320 auto BridgeBase::CreateCacheElement(Accessible* item) -> CacheElementType
321 {
322   if(!item)
323   {
324     return {};
325   }
326
327   auto root   = &mApplication;
328   auto parent = item->GetParent();
329
330   std::vector<Address> children;
331   for(auto i = 0u; i < item->GetChildCount(); ++i)
332   {
333     children.emplace_back(item->GetChildAtIndex(i)->GetAddress());
334   }
335
336   return std::make_tuple(
337     item->GetAddress(),
338     root->GetAddress(),
339     parent ? parent->GetAddress() : Address{},
340     children,
341     item->GetInterfaces(),
342     item->GetName(),
343     item->GetRole(),
344     item->GetDescription(),
345     item->GetStates().GetRawData());
346 }