10de55bf560aafaf607a78168d708f856e756203
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.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
20 // EXTERNAL INCLUDES
21 #include <dali/integration-api/debug.h>
22 #include <iostream>
23 #include <unordered_map>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
27 #include <dali/internal/accessibility/bridge/bridge-action.h>
28 #include <dali/internal/accessibility/bridge/bridge-collection.h>
29 #include <dali/internal/accessibility/bridge/bridge-component.h>
30 #include <dali/internal/accessibility/bridge/bridge-editable-text.h>
31 #include <dali/internal/accessibility/bridge/bridge-object.h>
32 #include <dali/internal/accessibility/bridge/bridge-text.h>
33 #include <dali/internal/accessibility/bridge/bridge-value.h>
34 #include <dali/internal/accessibility/bridge/dummy-atspi.h>
35 #include <dali/internal/system/common/environment-variables.h>
36 #include <dali/devel-api/adaptor-framework/environment-variable.h>
37
38 using namespace Dali::Accessibility;
39
40 class BridgeImpl : public virtual BridgeBase,
41                    public BridgeAccessible,
42                    public BridgeObject,
43                    public BridgeComponent,
44                    public BridgeCollection,
45                    public BridgeAction,
46                    public BridgeValue,
47                    public BridgeText,
48                    public BridgeEditableText
49 {
50   DBus::DBusClient                                              listenOnAtspiEnabledSignalClient;
51   DBus::DBusClient                                              registryClient, directReadingClient;
52   bool                                                          screenReaderEnabled = false;
53   bool                                                          isEnabled           = false;
54   bool                                                          isShown             = false;
55   std::unordered_map<int32_t, std::function<void(std::string)>> directReadingCallbacks;
56   Dali::Actor                                                   highlightedActor;
57   std::function<void(Dali::Actor)>                              highlightClearAction;
58
59 public:
60   BridgeImpl()
61   {
62     listenOnAtspiEnabledSignalClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
63
64     listenOnAtspiEnabledSignalClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
65       screenReaderEnabled = res;
66       if(screenReaderEnabled || isEnabled)
67       {
68         ForceUp();
69       }
70       else
71       {
72         ForceDown();
73       }
74     });
75
76     listenOnAtspiEnabledSignalClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
77       isEnabled = res;
78       if(screenReaderEnabled || isEnabled)
79       {
80         ForceUp();
81       }
82       else
83       {
84         ForceDown();
85       }
86     });
87   }
88
89   Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
90   {
91     if(!IsUp())
92     {
93       return Consumed::NO;
94     }
95
96     unsigned int evType = 0;
97
98     switch(type)
99     {
100       case KeyEventType::KEY_PRESSED:
101       {
102         evType = 0;
103         break;
104       }
105       case KeyEventType::KEY_RELEASED:
106       {
107         evType = 1;
108         break;
109       }
110       default:
111       {
112         return Consumed::NO;
113       }
114     }
115     auto m      = registryClient.method<bool(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>)>("NotifyListenersSync");
116     auto result = m.call(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>{evType, 0, static_cast<int32_t>(keyCode), 0, static_cast<int32_t>(timeStamp), keyName, isText ? 1 : 0});
117     if(!result)
118     {
119       LOG() << result.getError().message;
120       return Consumed::NO;
121     }
122     return std::get<0>(result) ? Consumed::YES : Consumed::NO;
123   }
124
125   void Pause() override
126   {
127     if(!IsUp())
128     {
129       return;
130     }
131
132     directReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
133       if(!msg)
134       {
135         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
136       }
137     },
138                                                                                         true);
139   }
140
141   void Resume() override
142   {
143     if(!IsUp())
144     {
145       return;
146     }
147
148     directReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
149       if(!msg)
150       {
151         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
152       }
153     },
154                                                                                         false);
155   }
156
157   void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
158   {
159     if(!IsUp())
160     {
161       return;
162     }
163
164     directReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
165       if(!msg)
166       {
167         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
168       }
169       else if(callback)
170       {
171         directReadingCallbacks.emplace(std::get<2>(msg), callback);
172       }
173     },
174                                                                                                                            text,
175                                                                                                                            discardable);
176   }
177
178   void ForceDown() override
179   {
180     if(data)
181     {
182       if(data->currentlyHighlightedActor && data->highlightActor)
183       {
184         data->currentlyHighlightedActor.Remove(data->highlightActor);
185       }
186       data->currentlyHighlightedActor = {};
187       data->highlightActor            = {};
188     }
189     highlightedActor     = {};
190     highlightClearAction = {};
191     BridgeAccessible::ForceDown();
192     registryClient      = {};
193     directReadingClient = {};
194     directReadingCallbacks.clear();
195   }
196
197   void Terminate() override
198   {
199     if(data)
200     {
201       data->currentlyHighlightedActor = {};
202       data->highlightActor            = {};
203     }
204     ForceDown();
205     listenOnAtspiEnabledSignalClient = {};
206     dbusServer                       = {};
207     con                              = {};
208   }
209
210   ForceUpResult ForceUp() override
211   {
212     if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
213     {
214       return ForceUpResult::ALREADY_UP;
215     }
216
217     BridgeObject::RegisterInterfaces();
218     BridgeAccessible::RegisterInterfaces();
219     BridgeComponent::RegisterInterfaces();
220     BridgeCollection::RegisterInterfaces();
221     BridgeAction::RegisterInterfaces();
222     BridgeValue::RegisterInterfaces();
223     BridgeText::RegisterInterfaces();
224     BridgeEditableText::RegisterInterfaces();
225
226     RegisterOnBridge(&application);
227
228     registryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, con};
229     directReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, con};
230     directReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
231       auto it = directReadingCallbacks.find(id);
232       if(it != directReadingCallbacks.end())
233       {
234         it->second(readingState);
235         if(readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
236           directReadingCallbacks.erase(it);
237       }
238     });
239
240     auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, con};
241     Address root{"", "root"};
242     auto    res = proxy.method<Address(Address)>("Embed").call(root);
243     if(!res)
244     {
245       LOG() << "Call to Embed failed: " << res.getError().message;
246     }
247     assert(res);
248     application.parent.SetAddress(std::move(std::get<0>(res)));
249     if(isShown)
250     {
251       EmitActivate();
252     }
253     return ForceUpResult::JUST_STARTED;
254   }
255
256   void EmitActivate()
257   {
258     auto win = application.getActiveWindow();
259     if(win)
260     {
261       win->Emit(WindowEvent::ACTIVATE, 0);
262     }
263   }
264
265   void EmitDeactivate()
266   {
267     auto win = application.getActiveWindow();
268     if(win)
269     {
270       win->Emit(WindowEvent::DEACTIVATE, 0);
271     }
272   }
273
274   void ApplicationHidden() override
275   {
276     if(isShown && IsUp())
277     {
278       EmitDeactivate();
279     }
280     isShown = false;
281   }
282
283   void ApplicationShown() override
284   {
285     if(!isShown && IsUp())
286     {
287       EmitActivate();
288     }
289     isShown = true;
290   }
291
292   void Initialize() override
293   {
294     auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
295     auto p   = req.property<bool>("ScreenReaderEnabled").get();
296     if(p)
297     {
298       screenReaderEnabled = std::get<0>(p);
299     }
300     p = req.property<bool>("IsEnabled").get();
301     if(p)
302     {
303       isEnabled = std::get<0>(p);
304     }
305     if(screenReaderEnabled || isEnabled)
306     {
307       ForceUp();
308     }
309   }
310
311   bool GetScreenReaderEnabled()
312   {
313     return screenReaderEnabled;
314   }
315
316   bool GetIsEnabled()
317   {
318     return isEnabled;
319   }
320 };
321
322 static Bridge* CreateBridge()
323 {
324   try
325   {
326     /* check environment variable first */
327     const char *envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
328     if (envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
329     {
330       return Dali::Accessibility::DummyBridge::GetInstance();
331     }
332
333     return new BridgeImpl;
334   }
335   catch (const std::exception&)
336   {
337     DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
338     return Dali::Accessibility::DummyBridge::GetInstance();
339   }
340 }
341
342 Bridge* Bridge::GetCurrentBridge()
343 {
344   static Bridge* bridge = CreateBridge();
345   return bridge;
346 }