[NUI][AT-SPI] Fix Accessibility.Say interop (#5612)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Accessibility / Accessibility.cs
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 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using System.Diagnostics.CodeAnalysis;
22 using System.Runtime.InteropServices;
23 using Tizen.NUI.BaseComponents;
24
25 namespace Tizen.NUI.Accessibility
26 {
27     /// <summary>
28     /// Accessibility provides Dali-ATSPI interface which has functionality of Screen-Reader and general accessibility
29     /// </summary>
30     // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
31     [SuppressMessage("Microsoft.Design", "CA1724: Type names should not match namespaces")]
32     [SuppressMessage("Microsoft.Design", "CA1001:Types that own disposable fields should be disposable", Justification = "This is a singleton class and is not disposed")]
33     [EditorBrowsable(EditorBrowsableState.Never)]
34     public static class Accessibility
35     {
36         #region Constructor
37         [SuppressMessage("Microsoft.Performance", "CA1810: Initialize reference type static fields inline", Justification = "Need to call native code")]
38         static Accessibility()
39         {
40             enabledSignalHandler = () =>
41             {
42                 Enabled?.Invoke(typeof(Accessibility), EventArgs.Empty);
43             };
44
45             disabledSignalHandler = () =>
46             {
47                 Disabled?.Invoke(typeof(Accessibility), EventArgs.Empty);
48             };
49
50             screenReaderEnabledSignalHandler = () =>
51             {
52                 ScreenReaderEnabled?.Invoke(typeof(Accessibility), EventArgs.Empty);
53             };
54
55             screenReaderDisabledSignalHandler = () =>
56             {
57                 ScreenReaderDisabled?.Invoke(typeof(Accessibility), EventArgs.Empty);
58             };
59
60             Interop.Accessibility.RegisterEnabledDisabledSignalHandler(enabledSignalHandler, disabledSignalHandler);
61             Interop.Accessibility.RegisterScreenReaderEnabledDisabledSignalHandler(screenReaderEnabledSignalHandler, screenReaderDisabledSignalHandler);
62         }
63         #endregion Constructor
64
65         #region Property
66         /// <summary>
67         /// Flag to check whether the state of Accessibility is enabled or not.
68         /// </summary>
69         /// <remarks>
70         /// Getter returns true if Accessibility is enabled, false otherwise.
71         /// </remarks>
72         /// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
73         [EditorBrowsable(EditorBrowsableState.Never)]
74         public static bool IsEnabled
75         {
76             get
77             {
78                 return (bool)Interop.Accessibility.IsEnabled();
79             }
80         }
81
82         /// <summary>
83         /// Flag to check whether the state of Screen Reader is enabled or not.
84         /// </summary>
85         /// <remarks>
86         /// Getter returns true if Screen Reader is enabled, false otherwise.
87         /// </remarks>
88         /// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
89         [EditorBrowsable(EditorBrowsableState.Never)]
90         public static bool IsScreenReaderEnabled
91         {
92             get
93             {
94                 return (bool)Interop.Accessibility.IsScreenReaderEnabled();
95             }
96         }
97
98         #endregion Property
99
100         #region Method
101         /// <summary>
102         /// Start to speak
103         /// </summary>
104         /// <param name="sentence">Content to be spoken</param>
105         /// <param name="discardable">true to be stopped and discarded when other Say is triggered</param>
106         /// <returns></returns>
107         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
108         [EditorBrowsable(EditorBrowsableState.Never)]
109         public static void Say(string sentence, bool discardable)
110         {
111             Interop.Accessibility.Say(sentence, discardable, SayFinishedEventCallback);
112             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
113         }
114
115         /// <summary>
116         /// To make Say be paused or resumed
117         /// </summary>
118         /// <param name="pause">true to be paused, false to be resumed</param>
119         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
120         [EditorBrowsable(EditorBrowsableState.Never)]
121         public static void PauseResume(bool pause)
122         {
123             Interop.Accessibility.PauseResume(pause);
124             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
125         }
126
127         /// <summary>
128         /// Cancels anything screen-reader is reading / has queued to read
129         /// </summary>
130         /// <param name="alsoNonDiscardable">whether to cancel non-discardable readings as well</param>
131         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
132         [EditorBrowsable(EditorBrowsableState.Never)]
133         public static void StopReading(bool alsoNonDiscardable)
134         {
135             Interop.Accessibility.StopReading(alsoNonDiscardable);
136             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
137         }
138
139         /// <summary>
140         /// Suppress reading of screen-reader
141         /// </summary>
142         /// <param name="suppress">whether to suppress reading of screen-reader</param>
143         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
144         [EditorBrowsable(EditorBrowsableState.Never)]
145         public static bool SuppressScreenReader(bool suppress)
146         {
147             bool ret = Interop.Accessibility.SuppressScreenReader(suppress);
148             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
149             return ret;
150         }
151
152         /// <summary>
153         /// Re-enables auto-initialization of AT-SPI bridge
154         /// </summary>
155         /// <remarks>
156         /// Normal applications do not have to call this function. The AT-SPI bridge is initialized on demand.
157         /// </remarks>
158         [EditorBrowsable(EditorBrowsableState.Never)]
159         public static void BridgeEnableAutoInit()
160         {
161             Interop.Accessibility.BridgeEnableAutoInit();
162             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
163         }
164
165         /// <summary>
166         /// Blocks auto-initialization of AT-SPI bridge
167         /// </summary>
168         /// <remarks>
169         /// Use this only if your application starts before DBus does, and call it early in Main().
170         /// When DBus is ready, call BridgeEnableAutoInit().
171         /// </remarks>
172         [EditorBrowsable(EditorBrowsableState.Never)]
173         public static void BridgeDisableAutoInit()
174         {
175             Interop.Accessibility.BridgeDisableAutoInit();
176             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
177         }
178
179         /// <summary>
180         ///  Get View that is used to highlight widget.
181         /// </summary>
182         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
183         [EditorBrowsable(EditorBrowsableState.Never)]
184         public static View GetHighlightFrameView()
185         {
186             var ptr = Interop.ControlDevel.DaliAccessibilityAccessibleGetHighlightActor();
187             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
188             if (ptr == IntPtr.Zero)
189                 return null;
190             return new View(ptr, true);
191         }
192
193         /// <summary>
194         ///  Set view that will be used to highlight widget.
195         /// </summary>
196         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
197         [EditorBrowsable(EditorBrowsableState.Never)]
198         public static void SetHighlightFrameView(View view)
199         {
200             Interop.ControlDevel.DaliAccessibilityAccessibleSetHighlightActor(View.getCPtr(view));
201             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
202         }
203
204         /// <summary>
205         ///  Get highligted View.
206         /// </summary>
207         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
208         [EditorBrowsable(EditorBrowsableState.Never)]
209         public static View GetCurrentlyHighlightedView()
210         {
211             var ptr = Interop.ControlDevel.DaliAccessibilityAccessibleGetCurrentlyHighlightedActor();
212
213             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
214
215             return dummyHandle.GetInstanceSafely<View>(ptr);
216         }
217
218         /// <summary>
219         ///  Clear highlight.
220         /// </summary>
221         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
222         [EditorBrowsable(EditorBrowsableState.Never)]
223         public static bool ClearCurrentlyHighlightedView()
224         {
225             var view = GetCurrentlyHighlightedView();
226
227             return view?.ClearAccessibilityHighlight() ?? false;
228         }
229         #endregion Method
230
231
232         #region Event, Enum, Struct, ETC
233         /// <summary>
234         /// Enum of Say finished event argument status
235         /// </summary>
236         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
237         [EditorBrowsable(EditorBrowsableState.Never)]
238         public enum SayFinishedState
239         {
240             /// <summary>
241             /// Invalid
242             /// </summary>
243             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
244             [EditorBrowsable(EditorBrowsableState.Never)]
245             Invalid = -1,
246             /// <summary>
247             /// Cancelled
248             /// </summary>
249             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
250             [EditorBrowsable(EditorBrowsableState.Never)]
251             Cancelled = 1,
252             /// <summary>
253             /// Stopped
254             /// </summary>
255             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
256             [EditorBrowsable(EditorBrowsableState.Never)]
257             Stopped = 2,
258             /// <summary>
259             /// Skipped
260             /// </summary>
261             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
262             [EditorBrowsable(EditorBrowsableState.Never)]
263             Skipped = 3,
264             /// <summary>
265             /// Paused
266             /// </summary>
267             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
268             [EditorBrowsable(EditorBrowsableState.Never)]
269             Paused = 4,
270             /// <summary>
271             /// Resumed
272             /// </summary>
273             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
274             [EditorBrowsable(EditorBrowsableState.Never)]
275             Resumed = 5
276         }
277
278         /// <summary>
279         /// When Say is finished, this event is triggered
280         /// </summary>
281         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
282         [EditorBrowsable(EditorBrowsableState.Never)]
283         public static event EventHandler<SayFinishedEventArgs> SayFinished;
284
285         /// <summary>
286         /// Triggered whenever the value of IsEnabled would change from false to true
287         /// </summary>
288         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
289         [EditorBrowsable(EditorBrowsableState.Never)]
290         public static event EventHandler Enabled;
291
292         /// <summary>
293         /// Triggered whenever the value of IsEnabled would change from true to false
294         /// </summary>
295         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
296         [EditorBrowsable(EditorBrowsableState.Never)]
297         public static event EventHandler Disabled;
298
299         /// <summary>
300         /// Triggered whenever the value of IsScreenReaderEnabled would change from false to true
301         /// </summary>
302         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
303         [EditorBrowsable(EditorBrowsableState.Never)]
304         public static event EventHandler ScreenReaderEnabled;
305
306         /// <summary>
307         /// Triggered whenever the value of IsScreenReaderEnabled would change from true to false
308         /// </summary>
309         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
310         [EditorBrowsable(EditorBrowsableState.Never)]
311         public static event EventHandler ScreenReaderDisabled;
312
313         #endregion Event, Enum, Struct, ETC
314
315         #region Private
316         private static Interop.Accessibility.EnabledDisabledSignalHandler enabledSignalHandler = null;
317
318         private static Interop.Accessibility.EnabledDisabledSignalHandler disabledSignalHandler = null;
319
320         private static Interop.Accessibility.EnabledDisabledSignalHandler screenReaderEnabledSignalHandler = null;
321
322         private static Interop.Accessibility.EnabledDisabledSignalHandler screenReaderDisabledSignalHandler = null;
323
324         private static readonly IReadOnlyDictionary<string, SayFinishedState> sayFinishedStateDictionary = new Dictionary<string, SayFinishedState>
325         {
326             ["ReadingCancelled"] = SayFinishedState.Cancelled,
327             ["ReadingStopped"] = SayFinishedState.Stopped,
328             ["ReadingSkipped"] = SayFinishedState.Skipped,
329             ["ReadingPaused"] = SayFinishedState.Paused,
330             ["ReadingResumed"] = SayFinishedState.Resumed,
331         };
332
333         private static void SayFinishedEventCallback(string status)
334         {
335             var result = sayFinishedStateDictionary.GetValueOrDefault(status, SayFinishedState.Invalid);
336             NUILog.Debug($"sayFinishedEventCallback(res={result}) called!");
337
338             SayFinished?.Invoke(typeof(Accessibility), new SayFinishedEventArgs(result));
339         }
340
341         private static BaseHandle dummyHandle = new BaseHandle();
342
343         #endregion Private
344     }
345
346     /// <summary>
347     ///  Say Finished event arguments
348     /// </summary>
349     // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
350     [EditorBrowsable(EditorBrowsableState.Never)]
351     public class SayFinishedEventArgs : EventArgs
352     {
353         /// <summary>
354         /// The state of Say finished
355         /// </summary>
356         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
357         [EditorBrowsable(EditorBrowsableState.Never)]
358         public Accessibility.SayFinishedState State
359         {
360             private set;
361             get;
362         }
363
364         internal SayFinishedEventArgs(Accessibility.SayFinishedState state)
365         {
366             State = state;
367             NUILog.Debug($"SayFinishedEventArgs Constructor! State={State}");
368         }
369     }
370 }