[AT-SPI] Prevent crashing Say method when s-r is turned off
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.cpp
1 /*
2  * Copyright (c) 2019 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/integration-api/debug.h>
22 #include <iostream>
23 #include <unordered_map>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
27 #include <dali/internal/accessibility/bridge/bridge-action.h>
28 #include <dali/internal/accessibility/bridge/bridge-collection.h>
29 #include <dali/internal/accessibility/bridge/bridge-component.h>
30 #include <dali/internal/accessibility/bridge/bridge-object.h>
31 #include <dali/internal/accessibility/bridge/bridge-value.h>
32 #include <dali/internal/accessibility/bridge/bridge-text.h>
33 #include <dali/internal/accessibility/bridge/bridge-editable-text.h>
34
35 using namespace Dali::Accessibility;
36
37 class BridgeImpl : public virtual BridgeBase,
38                    public BridgeAccessible,
39                    public BridgeObject,
40                    public BridgeComponent,
41                    public BridgeCollection,
42                    public BridgeAction,
43                    public BridgeValue,
44                    public BridgeText,
45                    public BridgeEditableText
46 {
47   DBus::DBusClient listenOnAtspiEnabledSignalClient;
48   DBus::DBusClient registryClient, directReadingClient;
49   bool screenReaderEnabled = false;
50   bool isEnabled = false;
51   bool isShown = false;
52   std::unordered_map <int32_t, std::function<void(std::string)>> directReadingCallbacks;
53   Dali::Actor highlightedActor;
54   std::function<void(Dali::Actor)> highlightClearAction;
55
56 public:
57   BridgeImpl()
58   {
59     listenOnAtspiEnabledSignalClient = DBus::DBusClient{ A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION };
60
61     listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "ScreenReaderEnabled", [this]( bool res )
62       {
63         screenReaderEnabled = res;
64         if( screenReaderEnabled || isEnabled )
65         {
66           ForceUp();
67         }
68         else
69         {
70           ForceDown();
71         }
72       }
73     );
74
75     listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "IsEnabled", [this]( bool res )
76       {
77         isEnabled = res;
78         if( screenReaderEnabled || isEnabled )
79         {
80           ForceUp();
81         }
82         else
83         {
84           ForceDown();
85         }
86       }
87     );
88   }
89
90   Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) override
91   {
92     if (!IsUp())
93     {
94       return Consumed::NO;
95     }
96
97     unsigned int evType = 0;
98
99     switch( type )
100     {
101       case KeyEventType::KEY_PRESSED:
102       {
103         evType = 0;
104         break;
105       }
106       case KeyEventType::KEY_RELEASED:
107       {
108         evType = 1;
109         break;
110       }
111       default:
112       {
113         return Consumed::NO;
114       }
115     }
116     auto m = registryClient.method< bool( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool > ) >( "NotifyListenersSync" );
117     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} );
118     if( !result )
119     {
120       LOG() << result.getError().message;
121       return Consumed::NO;
122     }
123     return std::get< 0 >( result ) ? Consumed::YES : Consumed::NO;
124   }
125
126   void Pause() override
127   {
128     if (!IsUp())
129     {
130       return;
131     }
132
133     auto r = directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).call( true );
134     if (!r)
135     {
136       LOG() << "Direct reading command failed (" << r.getError().message << ")";
137     }
138   }
139
140   void Resume() override
141   {
142     if (!IsUp())
143     {
144       return;
145     }
146
147     auto r = directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).call( false );
148     if (!r)
149     {
150       LOG() << "Direct reading command failed (" << r.getError().message << ")";
151     }
152   }
153
154   void Say( const std::string& text, bool discardable, std::function< void(std::string) > callback ) override
155   {
156     if (!IsUp())
157     {
158       return;
159     }
160
161     auto commandId = directReadingClient.method< DBus::ValueOrError< std::string, bool, int32_t >( std::string, bool ) > ( "ReadCommand" ).call( text, discardable );
162     if ( !commandId )
163     {
164       LOG() << "Direct reading command failed (" << commandId.getError().message << ")";
165     }
166     else if( callback )
167     {
168       directReadingCallbacks.emplace( std::get< 2 >( commandId ), callback);
169     }
170   }
171
172   void ForceDown() override
173   {
174     if (data)
175     {
176       if (data->currentlyHighlightedActor && data->highlightActor)
177       {
178         data->currentlyHighlightedActor.Remove(data->highlightActor);
179       }
180       data->currentlyHighlightedActor = {};
181       data->highlightActor = {};
182     }
183     highlightedActor = {};
184     highlightClearAction = {};
185     BridgeAccessible::ForceDown();
186     registryClient = {};
187     directReadingClient = {};
188     directReadingCallbacks.clear();
189   }
190
191   void Terminate() override
192   {
193     if (data)
194     {
195       data->currentlyHighlightedActor = {};
196       data->highlightActor = {};
197     }
198     ForceDown();
199     listenOnAtspiEnabledSignalClient = {};
200     dbusServer = {};
201     con = {};
202   }
203
204   ForceUpResult ForceUp() override
205   {
206     if( BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP )
207     {
208       return ForceUpResult::ALREADY_UP;
209     }
210
211     BridgeObject::RegisterInterfaces();
212     BridgeAccessible::RegisterInterfaces();
213     BridgeComponent::RegisterInterfaces();
214     BridgeCollection::RegisterInterfaces();
215     BridgeAction::RegisterInterfaces();
216     BridgeValue::RegisterInterfaces();
217     BridgeText::RegisterInterfaces();
218     BridgeEditableText::RegisterInterfaces();
219
220     RegisterOnBridge( &application );
221
222     registryClient = { AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, con };
223     directReadingClient = DBus::DBusClient{ DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, con };
224     directReadingClient.addSignal< void(int32_t, std::string) >( "ReadingStateChanged", [=]( int32_t id, std::string readingState )
225       {
226         auto it = directReadingCallbacks.find( id );
227         if (it != directReadingCallbacks.end())
228         {
229           it->second( readingState );
230           if (readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
231             directReadingCallbacks.erase( it );
232         }
233       }
234     );
235
236     auto proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, con};
237     Address root{"", "root"};
238     auto res = proxy.method< Address( Address ) >( "Embed" ).call( root );
239     if (!res)
240     {
241       LOG() << "Call to Embed failed: " << res.getError().message;
242     }
243     assert( res );
244     application.parent.SetAddress( std::move( std::get< 0 >( res ) ) );
245     if (isShown)
246     {
247       EmitActivate();
248     }
249     return ForceUpResult::JUST_STARTED;
250   }
251
252   void EmitActivate()
253   {
254     auto win = application.getActiveWindow();
255     if (win)
256     {
257       win->Emit( WindowEvent::ACTIVATE, 0 );
258     }
259   }
260
261   void EmitDeactivate()
262   {
263     auto win = application.getActiveWindow();
264     if (win)
265     {
266       win->Emit( WindowEvent::DEACTIVATE, 0 );
267     }
268   }
269
270   void ApplicationHidden() override
271   {
272     if ( isShown && IsUp() )
273     {
274       EmitDeactivate();
275     }
276     isShown = false;
277   }
278
279   void ApplicationShown() override
280   {
281     if ( !isShown && IsUp() )
282     {
283       EmitActivate();
284     }
285     isShown = true;
286   }
287
288   void Initialize() override
289   {
290     auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
291     auto p = req.property< bool >( "ScreenReaderEnabled" ).get();
292     if( p )
293     {
294       screenReaderEnabled = std::get< 0 >( p );
295     }
296     p = req.property< bool >( "IsEnabled" ).get();
297     if( p )
298     {
299       isEnabled = std::get< 0 >( p );
300     }
301     if( screenReaderEnabled || isEnabled )
302     {
303       ForceUp();
304     }
305   }
306
307   bool GetScreenReaderEnabled()
308   {
309     return screenReaderEnabled;
310   }
311
312   bool GetIsEnabled()
313   {
314     return isEnabled;
315   }
316
317 };
318
319 Bridge* Bridge::GetCurrentBridge()
320 {
321   static BridgeImpl *bridge = new BridgeImpl;
322   return bridge;
323 }
324