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