[AT-SPI] Rework intercepting key events
[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 <dali/devel-api/common/stage.h>
23 #include <atomic>
24 #include <cstdlib>
25 #include <memory>
26
27 // INTERNAL INCLUDES
28 #include <dali/public-api/adaptor-framework/timer.h>
29
30 using namespace Dali::Accessibility;
31
32 static Dali::Timer tickTimer;
33
34 BridgeBase::BridgeBase()
35 {
36 }
37
38 BridgeBase::~BridgeBase()
39 {
40   mApplication.mChildren.clear();
41 }
42
43 void BridgeBase::AddCoalescableMessage(CoalescableMessages kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor)
44 {
45   if(delay < 0)
46   {
47     delay = 0;
48   }
49   auto countdownBase = static_cast<unsigned int>(delay * 10);
50
51   auto it = mCoalescableMessages.insert({{kind, obj}, {countdownBase, countdownBase, {}}});
52   if(it.second)
53   {
54     functor();
55   }
56   else
57   {
58     std::get<1>(it.first->second) = countdownBase;
59     std::get<2>(it.first->second) = std::move(functor);
60   }
61
62   if(!tickTimer)
63   {
64     tickTimer = Dali::Timer::New(100);
65     tickTimer.TickSignal().Connect(this, &BridgeBase::TickCoalescableMessages);
66   }
67
68   if(!tickTimer.IsRunning())
69   {
70     tickTimer.Start();
71   }
72 }
73
74 bool BridgeBase::TickCoalescableMessages()
75 {
76   for(auto it = mCoalescableMessages.begin(); it != mCoalescableMessages.end();)
77   {
78     auto& countdown     = std::get<0>(it->second);
79     auto  countdownBase = std::get<1>(it->second);
80     auto& functor       = std::get<2>(it->second);
81     if(countdown)
82     {
83       --countdown;
84     }
85     else
86     {
87       if(functor)
88       {
89         functor();
90         functor = {};
91         countdown = countdownBase;
92       }
93       else
94       {
95         it = mCoalescableMessages.erase(it);
96         continue;
97       }
98     }
99     ++it;
100   }
101   return !mCoalescableMessages.empty();
102 }
103
104 void BridgeBase::UpdateRegisteredEvents()
105 {
106   using ReturnType = std::vector<std::tuple<std::string, std::string>>;
107   mRegistry.method<DBus::ValueOrError<ReturnType>()>("GetRegisteredEvents").asyncCall([this](DBus::ValueOrError<ReturnType> msg) {
108     if(!msg)
109     {
110       LOG() << "Get registered events failed";
111       return;
112     }
113
114     IsBoundsChangedEventAllowed = false;
115
116     ReturnType values = std::get<ReturnType>(msg.getValues());
117     for(long unsigned int i = 0; i < values.size(); i++)
118     {
119       if(!std::get<1>(values[i]).compare("Object:BoundsChanged"))
120       {
121         IsBoundsChangedEventAllowed = true;
122       }
123     }
124   });
125 }
126
127 BridgeBase::ForceUpResult BridgeBase::ForceUp()
128 {
129   //TODO: checking mBusName is enough? or a new variable to check bridge state?
130   if(Bridge::ForceUp() == ForceUpResult::ALREADY_UP && !GetBusName().empty())
131   {
132     return ForceUpResult::ALREADY_UP;
133   }
134   auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
135   auto addr  = proxy.method<std::string()>(dbusLocators::atspi::GET_ADDRESS).call();
136
137   if(!addr)
138   {
139     DALI_LOG_ERROR("failed at call '%s': %s\n", dbusLocators::atspi::GET_ADDRESS, addr.getError().message.c_str());
140     return ForceUpResult::FAILED;
141   }
142
143   mConnectionPtr  = DBusWrapper::Installed()->eldbus_address_connection_get_impl(std::get<0>(addr));
144   mData->mBusName = DBus::getConnectionName(mConnectionPtr);
145   mDbusServer     = {mConnectionPtr};
146
147   {
148     DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::CACHE)};
149     AddFunctionToInterface(desc, "GetItems", &BridgeBase::GetItems);
150     mDbusServer.addInterface(AtspiDbusPathCache, desc);
151   }
152   {
153     DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::APPLICATION)};
154     AddGetSetPropertyToInterface(desc, "Id", &BridgeBase::GetId, &BridgeBase::SetId);
155     mDbusServer.addInterface(AtspiPath, desc);
156   }
157
158   mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, Accessible::GetInterfaceName(AtspiInterface::REGISTRY), mConnectionPtr};
159
160   UpdateRegisteredEvents();
161
162   mRegistry.addSignal<void(void)>("EventListenerRegistered", [this](void) {
163     UpdateRegisteredEvents();
164   });
165
166   mRegistry.addSignal<void(void)>("EventListenerDeregistered", [this](void) {
167     UpdateRegisteredEvents();
168   });
169
170   return ForceUpResult::JUST_STARTED;
171 }
172
173 void BridgeBase::ForceDown()
174 {
175   Bridge::ForceDown();
176   mRegistry      = {};
177   mDbusServer    = {};
178   mConnectionPtr = {};
179 }
180
181 const std::string& BridgeBase::GetBusName() const
182 {
183   static std::string empty;
184   return mData ? mData->mBusName : empty;
185 }
186
187 Accessible* BridgeBase::FindByPath(const std::string& name) const
188 {
189   try
190   {
191     return Find(name);
192   }
193   catch(std::domain_error&)
194   {
195     return nullptr;
196   }
197 }
198
199 void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
200 {
201   if(windowAccessible->GetInternalActor() == nullptr)
202   {
203     return;
204   }
205
206   // Prevent adding the default window twice.
207   if(!mApplication.mChildren.empty() &&
208      mApplication.mChildren[0]->GetInternalActor() == windowAccessible->GetInternalActor())
209   {
210     return;
211   }
212
213   // Adds Window to a list of Windows.
214   mApplication.mChildren.push_back(windowAccessible);
215   SetIsOnRootLevel(windowAccessible);
216 }
217
218 void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
219 {
220   for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
221   {
222     if(mApplication.mChildren[i] == windowAccessible)
223     {
224       mApplication.mChildren.erase(mApplication.mChildren.begin() + i);
225       break;
226     }
227   }
228 }
229
230 void BridgeBase::RegisterDefaultLabel(Accessible* object)
231 {
232   if(std::find(mDefaultLabels.begin(), mDefaultLabels.end(), object) == mDefaultLabels.end())
233   {
234     mDefaultLabels.push_back(object);
235   }
236 }
237
238 void BridgeBase::UnregisterDefaultLabel(Accessible* object)
239 {
240   auto it = std::find(mDefaultLabels.begin(), mDefaultLabels.end(), object);
241   if(it != mDefaultLabels.end())
242   {
243     mDefaultLabels.erase(it);
244   }
245 }
246
247 Accessible* BridgeBase::GetDefaultLabel(Accessible* root) const
248 {
249   // TODO (multi-window support): Change mDefaultLabels to a collection of vectors
250   // (one per window) and select the right one based on the window that 'root' belongs to.
251   return mDefaultLabels.empty() ? root : mDefaultLabels.back();
252 }
253
254 std::string BridgeBase::StripPrefix(const std::string& path)
255 {
256   auto size = strlen(AtspiPath);
257   return path.substr(size + 1);
258 }
259
260 Accessible* BridgeBase::Find(const std::string& path) const
261 {
262   if(path == "root")
263   {
264     return &mApplication;
265   }
266
267   void*              accessible;
268   std::istringstream tmp{path};
269   if(!(tmp >> accessible))
270   {
271     throw std::domain_error{"invalid path '" + path + "'"};
272   }
273
274   auto it = mData->mKnownObjects.find(static_cast<Accessible*>(accessible));
275   if(it == mData->mKnownObjects.end() || (*it)->IsHidden())
276   {
277     throw std::domain_error{"unknown object '" + path + "'"};
278   }
279
280   return static_cast<Accessible*>(accessible);
281 }
282
283 Accessible* BridgeBase::Find(const Address& ptr) const
284 {
285   assert(ptr.GetBus() == mData->mBusName);
286   return Find(ptr.GetPath());
287 }
288
289 Accessible* BridgeBase::FindCurrentObject() const
290 {
291   auto path = DBus::DBusServer::getCurrentObjectPath();
292   auto size = strlen(AtspiPath);
293   if(path.size() <= size)
294   {
295     throw std::domain_error{"invalid path '" + path + "'"};
296   }
297   if(path.substr(0, size) != AtspiPath)
298   {
299     throw std::domain_error{"invalid path '" + path + "'"};
300   }
301   if(path[size] != '/')
302   {
303     throw std::domain_error{"invalid path '" + path + "'"};
304   }
305   return Find(StripPrefix(path));
306 }
307
308 void BridgeBase::SetId(int id)
309 {
310   this->mId = id;
311 }
312
313 int BridgeBase::GetId()
314 {
315   return this->mId;
316 }
317
318 auto BridgeBase::GetItems() -> DBus::ValueOrError<std::vector<CacheElementType>>
319 {
320   auto root = &mApplication;
321
322   std::vector<CacheElementType> res;
323
324   std::function<void(Accessible*)> proc =
325     [&](Accessible* item) {
326       res.emplace_back(std::move(CreateCacheElement(root)));
327       for(auto i = 0u; i < item->GetChildCount(); ++i)
328       {
329         proc(item->GetChildAtIndex(i));
330       }
331     };
332
333   return res;
334 }
335
336 auto BridgeBase::CreateCacheElement(Accessible* item) -> CacheElementType
337 {
338   if(!item)
339   {
340     return {};
341   }
342
343   auto root   = &mApplication;
344   auto parent = item->GetParent();
345
346   std::vector<Address> children;
347   for(auto i = 0u; i < item->GetChildCount(); ++i)
348   {
349     children.emplace_back(item->GetChildAtIndex(i)->GetAddress());
350   }
351
352   return std::make_tuple(
353     item->GetAddress(),
354     root->GetAddress(),
355     parent ? parent->GetAddress() : Address{},
356     children,
357     item->GetInterfacesAsStrings(),
358     item->GetName(),
359     item->GetRole(),
360     item->GetDescription(),
361     item->GetStates().GetRawData());
362 }