Merge "VectorImageRenderer: Remove TizenVectorImageRenderer dependency" into devel...
[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 /**
47  * @brief The BridgeImpl class is to implement some Bridge functions.
48  */
49 class BridgeImpl : public virtual BridgeBase,
50                    public BridgeAccessible,
51                    public BridgeObject,
52                    public BridgeComponent,
53                    public BridgeCollection,
54                    public BridgeAction,
55                    public BridgeValue,
56                    public BridgeText,
57                    public BridgeEditableText,
58                    public BridgeSelection,
59                    public BridgeApplication
60 {
61   DBus::DBusClient                                              mAccessibilityStatusClient;
62   DBus::DBusClient                                              mRegistryClient;
63   DBus::DBusClient                                              mDirectReadingClient;
64   bool                                                          mIsScreenReaderEnabled = false;
65   bool                                                          mIsEnabled             = false;
66   bool                                                          mIsShown               = false;
67   std::unordered_map<int32_t, std::function<void(std::string)>> mDirectReadingCallbacks;
68   Dali::Actor                                                   mHighlightedActor;
69   std::function<void(Dali::Actor)>                              mHighlightClearAction;
70   Dali::CallbackBase*                                           mIdleCallback          = NULL;
71
72 public:
73   BridgeImpl()
74   {
75   }
76
77   /**
78    * @copydoc Dali::Accessibility::Bridge::Emit()
79    */
80   Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
81   {
82     if(!IsUp())
83     {
84       return Consumed::NO;
85     }
86
87     unsigned int keyType = 0;
88
89     switch(type)
90     {
91       case KeyEventType::KEY_PRESSED:
92       {
93         keyType = 0;
94         break;
95       }
96       case KeyEventType::KEY_RELEASED:
97       {
98         keyType = 1;
99         break;
100       }
101       default:
102       {
103         return Consumed::NO;
104       }
105     }
106
107     auto methodObject = mRegistryClient.method<bool(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>)>("NotifyListenersSync");
108     auto result       = methodObject.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});
109     if(!result)
110     {
111       LOG() << result.getError().message;
112       return Consumed::NO;
113     }
114     return std::get<0>(result) ? Consumed::YES : Consumed::NO;
115   }
116
117   /**
118    * @copydoc Dali::Accessibility::Bridge::Pause()
119    */
120   void Pause() override
121   {
122     if(!IsUp())
123     {
124       return;
125     }
126
127     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
128       if(!msg)
129       {
130         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
131       }
132     },
133                                                                                         true);
134   }
135
136   /**
137    * @copydoc Dali::Accessibility::Bridge::Resume()
138    */
139   void Resume() override
140   {
141     if(!IsUp())
142     {
143       return;
144     }
145
146     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
147       if(!msg)
148       {
149         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
150       }
151     },
152                                                                                         false);
153   }
154
155   /**
156    * @copydoc Dali::Accessibility::Bridge::StopReading()
157    */
158   void StopReading(bool alsoNonDiscardable) override
159   {
160     if(!IsUp())
161     {
162       return;
163     }
164
165     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
166       if(!msg)
167       {
168         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
169       }
170     },
171                                                                                         alsoNonDiscardable);
172   }
173
174   /**
175    * @copydoc Dali::Accessibility::Bridge::Say()
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     mDirectReadingClient.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         mDirectReadingCallbacks.emplace(std::get<2>(msg), callback);
192       }
193     },
194                                                                                                                            text,
195                                                                                                                            discardable);
196   }
197
198   /**
199    * @copydoc Dali::Accessibility::Bridge::ForceDown()
200    */
201   void ForceDown() override
202   {
203     if(mData)
204     {
205       if(mData->mCurrentlyHighlightedActor && mData->mHighlightActor)
206       {
207         mData->mCurrentlyHighlightedActor.Remove(mData->mHighlightActor);
208       }
209       mData->mCurrentlyHighlightedActor = {};
210       mData->mHighlightActor            = {};
211     }
212     mHighlightedActor     = {};
213     mHighlightClearAction = {};
214     BridgeAccessible::ForceDown();
215     mRegistryClient       = {};
216     mDirectReadingClient  = {};
217     mDirectReadingCallbacks.clear();
218   }
219
220   /**
221    * @copydoc Dali::Accessibility::Bridge::Terminate()
222    */
223   void Terminate() override
224   {
225     if(mData)
226     {
227       mData->mCurrentlyHighlightedActor = {};
228       mData->mHighlightActor            = {};
229     }
230     ForceDown();
231     if((NULL != mIdleCallback) && Dali::Adaptor::IsAvailable())
232     {
233       Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
234     }
235     mAccessibilityStatusClient        = {};
236     mDbusServer                       = {};
237     mConnectionPtr                    = {};
238   }
239
240   /**
241    * @copydoc Dali::Accessibility::Bridge::ForceUp()
242    */
243   ForceUpResult ForceUp() override
244   {
245     if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
246     {
247       return ForceUpResult::ALREADY_UP;
248     }
249
250     BridgeObject::RegisterInterfaces();
251     BridgeAccessible::RegisterInterfaces();
252     BridgeComponent::RegisterInterfaces();
253     BridgeCollection::RegisterInterfaces();
254     BridgeAction::RegisterInterfaces();
255     BridgeValue::RegisterInterfaces();
256     BridgeText::RegisterInterfaces();
257     BridgeEditableText::RegisterInterfaces();
258     BridgeSelection::RegisterInterfaces();
259     BridgeApplication::RegisterInterfaces();
260
261     RegisterOnBridge(&mApplication);
262
263     mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
264     mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
265
266     mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
267       auto it = mDirectReadingCallbacks.find(id);
268       if(it != mDirectReadingCallbacks.end())
269       {
270         it->second(readingState);
271         if(readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
272         {
273           mDirectReadingCallbacks.erase(it);
274         }
275       }
276     });
277
278     auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, mConnectionPtr};
279     Address root{"", "root"};
280     auto    res = proxy.method<Address(Address)>("Embed").call(root);
281     if(!res)
282     {
283       LOG() << "Call to Embed failed: " << res.getError().message;
284     }
285     assert(res);
286
287     mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
288     if(mIsShown)
289     {
290       EmitActivate();
291     }
292     return ForceUpResult::JUST_STARTED;
293   }
294
295   /**
296    * @brief Sends a signal to dbus that the default window is activated.
297    *
298    * TODO : This is subject to change if/when we implement multi-window support.
299    * @see BridgeObject::Emit()
300    */
301   void EmitActivate()
302   {
303     auto win = mApplication.GetActiveWindow();
304     if(win)
305     {
306       win->Emit(WindowEvent::ACTIVATE, 0);
307     }
308   }
309
310   /**
311    * @brief Sends a signal to dbus that the default window is deactivated.
312    *
313    * TODO : This is subject to change if/when we implement multi-window support.
314    * @see BridgeObject::Emit()
315    */
316   void EmitDeactivate()
317   {
318     auto win = mApplication.GetActiveWindow();
319     if(win)
320     {
321       win->Emit(WindowEvent::DEACTIVATE, 0);
322     }
323   }
324
325   /**
326    * @copydoc Dali::Accessibility::Bridge::WindowHidden()
327    */
328   void WindowHidden() override
329   {
330     if(mIsShown && IsUp())
331     {
332       EmitDeactivate();
333     }
334     mIsShown = false;
335   }
336
337   /**
338    * @copydoc Dali::Accessibility::Bridge::WindowShown()
339    */
340   void WindowShown() override
341   {
342     if(!mIsShown && IsUp())
343     {
344       EmitActivate();
345     }
346     mIsShown = true;
347   }
348
349   void ReadAndListenProperty()
350   {
351     // read property
352     auto enabled = mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").get();
353     if(enabled)
354     {
355       mIsScreenReaderEnabled = std::get<0>(enabled);
356     }
357
358     enabled = mAccessibilityStatusClient.property<bool>("IsEnabled").get();
359     if(enabled)
360     {
361       mIsEnabled = std::get<0>(enabled);
362     }
363
364     if(mIsScreenReaderEnabled || mIsEnabled)
365     {
366       ForceUp();
367     }
368
369     // listen property change
370     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
371       mIsScreenReaderEnabled = res;
372       if(mIsScreenReaderEnabled || mIsEnabled)
373       {
374         ForceUp();
375       }
376       else
377       {
378         ForceDown();
379       }
380     });
381
382     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
383       mIsEnabled = res;
384       if(mIsScreenReaderEnabled || mIsEnabled)
385       {
386         ForceUp();
387       }
388       else
389       {
390         ForceDown();
391       }
392     });
393   }
394
395   bool InitializeAccessibilityStatusClient()
396   {
397     mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
398
399     if (!mAccessibilityStatusClient)
400     {
401       DALI_LOG_ERROR("Accessibility Status DbusClient is not ready\n");
402       return false;
403     }
404
405     return true;
406   }
407
408   bool OnIdleSignal()
409   {
410     if ( InitializeAccessibilityStatusClient() )
411     {
412       ReadAndListenProperty();
413       mIdleCallback = NULL;
414       return false;
415     }
416
417     return true;
418   }
419
420   /**
421    * @copydoc Dali::Accessibility::Bridge::Initialize()
422    */
423   void Initialize() override
424   {
425     if ( InitializeAccessibilityStatusClient() )
426     {
427       ReadAndListenProperty();
428       return;
429     }
430
431     // Initialize failed. Try it again on Idle
432     if( Dali::Adaptor::IsAvailable() )
433     {
434       Dali::Adaptor& adaptor = Dali::Adaptor::Get();
435       if( NULL == mIdleCallback )
436       {
437         mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
438         adaptor.AddIdle( mIdleCallback, true );
439       }
440     }
441   }
442
443   /**
444    * @copydoc Dali::Accessibility::Bridge::GetScreenReaderEnabled()
445    */
446   bool GetScreenReaderEnabled() override
447   {
448     return mIsScreenReaderEnabled;
449   }
450
451   /**
452    * @copydoc Dali::Accessibility::Bridge::IsEnabled()
453    */
454   bool IsEnabled() override
455   {
456     return mIsEnabled;
457   }
458 }; // BridgeImpl
459
460 namespace // unnamed namespace
461 {
462
463 bool INITIALIZED_BRIDGE = false;
464
465 /**
466  * @brief Creates BridgeImpl instance.
467  *
468  * @return The BridgeImpl instance
469  * @note This method is to check environment variable first. If ATSPI is disable using env, it returns dummy bridge instance.
470  */
471 Bridge* CreateBridge()
472 {
473   INITIALIZED_BRIDGE = true;
474
475   try
476   {
477     /* check environment variable first */
478     const char* envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
479     if(envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
480     {
481       return Dali::Accessibility::DummyBridge::GetInstance();
482     }
483
484     return new BridgeImpl;
485   }
486   catch(const std::exception&)
487   {
488     DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
489     return Dali::Accessibility::DummyBridge::GetInstance();
490   }
491 }
492
493 } // unnamed namespace
494
495 // Dali::Accessibility::Bridge class implementation
496
497 Bridge* Bridge::GetCurrentBridge()
498 {
499   static Bridge* bridge;
500
501   if(bridge)
502   {
503     return bridge;
504   }
505   else if(mAutoInitState == AutoInitState::ENABLED)
506   {
507     bridge = CreateBridge();
508
509     /* check environment variable for suppressing screen-reader */
510     const char* envSuppressScreenReader = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_SUPPRESS_SCREEN_READER);
511     if(envSuppressScreenReader && std::atoi(envSuppressScreenReader) != 0)
512     {
513       bridge->SuppressScreenReader(true);
514     }
515
516     return bridge;
517   }
518
519   return Dali::Accessibility::DummyBridge::GetInstance();
520 }
521
522 void Bridge::DisableAutoInit()
523 {
524   if(INITIALIZED_BRIDGE)
525   {
526     DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
527   }
528
529   mAutoInitState = AutoInitState::DISABLED;
530 }
531
532 void Bridge::EnableAutoInit()
533 {
534   mAutoInitState = AutoInitState::ENABLED;
535
536   if(INITIALIZED_BRIDGE)
537   {
538     return;
539   }
540
541   auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer();
542   auto window          = Dali::DevelWindow::Get(rootLayer);
543   auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
544
545   auto* bridge = Bridge::GetCurrentBridge();
546   bridge->AddTopLevelWindow(Dali::Accessibility::Accessible::Get(rootLayer, true));
547   bridge->SetApplicationName(applicationName);
548   bridge->Initialize();
549
550   if(window && window.IsVisible())
551   {
552     bridge->WindowShown();
553   }
554 }