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