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