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