Merge branch 'devel/master' into tizen
[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 keyType = 0;
103
104     switch(type)
105     {
106       case KeyEventType::KEY_PRESSED:
107       {
108         keyType = 0;
109         break;
110       }
111       case KeyEventType::KEY_RELEASED:
112       {
113         keyType = 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>{keyType, 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(mData)
203     {
204       if(mData->mCurrentlyHighlightedActor && mData->mHighlightActor)
205       {
206         mData->mCurrentlyHighlightedActor.Remove(mData->mHighlightActor);
207       }
208       mData->mCurrentlyHighlightedActor = {};
209       mData->mHighlightActor            = {};
210     }
211     highlightedActor     = {};
212     highlightClearAction = {};
213     BridgeAccessible::ForceDown();
214     registryClient      = {};
215     directReadingClient = {};
216     directReadingCallbacks.clear();
217   }
218
219   void Terminate() override
220   {
221     if(mData)
222     {
223       mData->mCurrentlyHighlightedActor = {};
224       mData->mHighlightActor            = {};
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 dbusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
318     auto enabled = dbusClient.property<bool>("ScreenReaderEnabled").get();
319     if(enabled)
320     {
321       screenReaderEnabled = std::get<0>(enabled);
322     }
323
324     enabled = dbusClient.property<bool>("IsEnabled").get();
325     if(enabled)
326     {
327       isEnabled = std::get<0>(enabled);
328     }
329
330     if(screenReaderEnabled || isEnabled)
331     {
332       ForceUp();
333     }
334   }
335
336   bool GetScreenReaderEnabled()
337   {
338     return screenReaderEnabled;
339   }
340
341   bool IsEnabled()
342   {
343     return isEnabled;
344   }
345 };
346
347 static bool bridgeInitialized;
348
349 static Bridge* CreateBridge()
350 {
351   bridgeInitialized = true;
352
353   try
354   {
355     /* check environment variable first */
356     const char* envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
357     if(envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
358     {
359       return Dali::Accessibility::DummyBridge::GetInstance();
360     }
361
362     return new BridgeImpl;
363   }
364   catch(const std::exception&)
365   {
366     DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
367     return Dali::Accessibility::DummyBridge::GetInstance();
368   }
369 }
370
371 Bridge* Bridge::GetCurrentBridge()
372 {
373   static Bridge* bridge;
374
375   if(bridge)
376   {
377     return bridge;
378   }
379   else if(autoInitState == AutoInitState::ENABLED)
380   {
381     bridge = CreateBridge();
382
383     /* check environment variable for suppressing screen-reader */
384     const char* envSuppressScreenReader = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_SUPPRESS_SCREEN_READER);
385     if(envSuppressScreenReader && std::atoi(envSuppressScreenReader) != 0)
386     {
387       bridge->SuppressScreenReader(true);
388     }
389
390     return bridge;
391   }
392
393   return Dali::Accessibility::DummyBridge::GetInstance();
394 }
395
396 void Bridge::DisableAutoInit()
397 {
398   if(bridgeInitialized)
399   {
400     DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
401   }
402
403   autoInitState = AutoInitState::DISABLED;
404 }
405
406 void Bridge::EnableAutoInit()
407 {
408   autoInitState = AutoInitState::ENABLED;
409
410   if(bridgeInitialized)
411   {
412     return;
413   }
414
415   auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer();
416   auto window          = Dali::DevelWindow::Get(rootLayer);
417   auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
418
419   auto* bridge = Bridge::GetCurrentBridge();
420   bridge->AddTopLevelWindow(Dali::Accessibility::Accessible::Get(rootLayer, true));
421   bridge->SetApplicationName(applicationName);
422   bridge->Initialize();
423
424   if(window && window.IsVisible())
425   {
426     bridge->ApplicationShown();
427   }
428 }