Merge branch 'devel/master' into devel/graphics
[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/devel-api/adaptor-framework/environment-variable.h>
27 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
28 #include <dali/internal/accessibility/bridge/bridge-action.h>
29 #include <dali/internal/accessibility/bridge/bridge-collection.h>
30 #include <dali/internal/accessibility/bridge/bridge-component.h>
31 #include <dali/internal/accessibility/bridge/bridge-editable-text.h>
32 #include <dali/internal/accessibility/bridge/bridge-object.h>
33 #include <dali/internal/accessibility/bridge/bridge-text.h>
34 #include <dali/internal/accessibility/bridge/bridge-value.h>
35 #include <dali/internal/accessibility/bridge/dummy-atspi.h>
36 #include <dali/internal/system/common/environment-variables.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 StopReading(bool alsoNonDiscardable) override
158   {
159     if(!IsUp())
160     {
161       return;
162     }
163
164     directReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
165       if(!msg)
166       {
167         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
168       }
169     },
170                                                                                         alsoNonDiscardable);
171   }
172
173   void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
174   {
175     if(!IsUp())
176     {
177       return;
178     }
179
180     directReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
181       if(!msg)
182       {
183         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
184       }
185       else if(callback)
186       {
187         directReadingCallbacks.emplace(std::get<2>(msg), callback);
188       }
189     },
190                                                                                                                            text,
191                                                                                                                            discardable);
192   }
193
194   void ForceDown() override
195   {
196     if(data)
197     {
198       if(data->currentlyHighlightedActor && data->highlightActor)
199       {
200         data->currentlyHighlightedActor.Remove(data->highlightActor);
201       }
202       data->currentlyHighlightedActor = {};
203       data->highlightActor            = {};
204     }
205     highlightedActor     = {};
206     highlightClearAction = {};
207     BridgeAccessible::ForceDown();
208     registryClient      = {};
209     directReadingClient = {};
210     directReadingCallbacks.clear();
211   }
212
213   void Terminate() override
214   {
215     if(data)
216     {
217       data->currentlyHighlightedActor = {};
218       data->highlightActor            = {};
219     }
220     ForceDown();
221     listenOnAtspiEnabledSignalClient = {};
222     dbusServer                       = {};
223     con                              = {};
224   }
225
226   ForceUpResult ForceUp() override
227   {
228     if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
229     {
230       return ForceUpResult::ALREADY_UP;
231     }
232
233     BridgeObject::RegisterInterfaces();
234     BridgeAccessible::RegisterInterfaces();
235     BridgeComponent::RegisterInterfaces();
236     BridgeCollection::RegisterInterfaces();
237     BridgeAction::RegisterInterfaces();
238     BridgeValue::RegisterInterfaces();
239     BridgeText::RegisterInterfaces();
240     BridgeEditableText::RegisterInterfaces();
241
242     RegisterOnBridge(&application);
243
244     registryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, con};
245     directReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, con};
246     directReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
247       auto it = directReadingCallbacks.find(id);
248       if(it != directReadingCallbacks.end())
249       {
250         it->second(readingState);
251         if(readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
252           directReadingCallbacks.erase(it);
253       }
254     });
255
256     auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, con};
257     Address root{"", "root"};
258     auto    res = proxy.method<Address(Address)>("Embed").call(root);
259     if(!res)
260     {
261       LOG() << "Call to Embed failed: " << res.getError().message;
262     }
263     assert(res);
264     application.parent.SetAddress(std::move(std::get<0>(res)));
265     if(isShown)
266     {
267       EmitActivate();
268     }
269     return ForceUpResult::JUST_STARTED;
270   }
271
272   void EmitActivate()
273   {
274     auto win = application.getActiveWindow();
275     if(win)
276     {
277       win->Emit(WindowEvent::ACTIVATE, 0);
278     }
279   }
280
281   void EmitDeactivate()
282   {
283     auto win = application.getActiveWindow();
284     if(win)
285     {
286       win->Emit(WindowEvent::DEACTIVATE, 0);
287     }
288   }
289
290   void ApplicationHidden() override
291   {
292     if(isShown && IsUp())
293     {
294       EmitDeactivate();
295     }
296     isShown = false;
297   }
298
299   void ApplicationShown() override
300   {
301     if(!isShown && IsUp())
302     {
303       EmitActivate();
304     }
305     isShown = true;
306   }
307
308   void Initialize() override
309   {
310     auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
311     auto p   = req.property<bool>("ScreenReaderEnabled").get();
312     if(p)
313     {
314       screenReaderEnabled = std::get<0>(p);
315     }
316     p = req.property<bool>("IsEnabled").get();
317     if(p)
318     {
319       isEnabled = std::get<0>(p);
320     }
321     if(screenReaderEnabled || isEnabled)
322     {
323       ForceUp();
324     }
325   }
326
327   bool GetScreenReaderEnabled()
328   {
329     return screenReaderEnabled;
330   }
331
332   bool GetIsEnabled()
333   {
334     return isEnabled;
335   }
336 };
337
338 static bool bridgeInitialized;
339
340 static Bridge* CreateBridge()
341 {
342   bridgeInitialized = true;
343
344   try
345   {
346     /* check environment variable first */
347     const char* envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
348     if(envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
349     {
350       return Dali::Accessibility::DummyBridge::GetInstance();
351     }
352
353     return new BridgeImpl;
354   }
355   catch(const std::exception&)
356   {
357     DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
358     return Dali::Accessibility::DummyBridge::GetInstance();
359   }
360 }
361
362 Bridge* Bridge::GetCurrentBridge()
363 {
364   static Bridge* bridge;
365
366   if(bridge)
367   {
368     return bridge;
369   }
370   else if(autoInitState == AutoInitState::ENABLED)
371   {
372     bridge = CreateBridge();
373
374     /* check environment variable for suppressing screen-reader */
375     const char* envSuppressScreenReader = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_SUPPRESS_SCREEN_READER);
376     if(envSuppressScreenReader && std::atoi(envSuppressScreenReader) != 0)
377     {
378       bridge->SuppressScreenReader(true);
379     }
380
381     return bridge;
382   }
383
384   return Dali::Accessibility::DummyBridge::GetInstance();
385 }
386
387 void Bridge::DisableAutoInit()
388 {
389   if(bridgeInitialized)
390   {
391     DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
392   }
393
394   autoInitState = AutoInitState::DISABLED;
395 }
396
397 void Bridge::EnableAutoInit(Accessible* topLevelWindow, const std::string& applicationName)
398 {
399   autoInitState = AutoInitState::ENABLED;
400
401   if(bridgeInitialized)
402   {
403     return;
404   }
405
406   auto* bridge = Bridge::GetCurrentBridge();
407   bridge->AddTopLevelWindow(topLevelWindow);
408   bridge->SetApplicationName(applicationName);
409   bridge->Initialize();
410 }