7bccb4c11dfabc41b6cc20c5b59d7cedb464b3fb
[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 #if (NUI_DEBUG_ON)
24 using tlog = Tizen.Log;
25 #endif
26
27 namespace Tizen.NUI.Accessibility
28 {
29     /// <summary>
30     /// Accessibility provides Dali-ATSPI interface which has functionality of Screen-Reader and general accessibility
31     /// </summary>
32     // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
33     [SuppressMessage("Microsoft.Design", "CA1724: Type names should not match namespaces")]
34     [SuppressMessage("Microsoft.Design", "CA1001:Types that own disposable fields should be disposable", Justification = "This is a singleton class and is not disposed")]
35     [EditorBrowsable(EditorBrowsableState.Never)]
36     public class Accessibility
37     {
38         #region Constructor, Destructor, Dispose
39         private Accessibility()
40         {
41             dummy = new View();
42             dummy.Name = "dali-atspi-singleton";
43         }
44         /// <summary>
45         /// destructor. This is HiddenAPI. recommended not to use in public.
46         /// </summary>
47         ~Accessibility()
48         {
49             Tizen.Log.Debug("NUI", $"Accessibility is destroyed\n");
50         }
51         #endregion Constructor, Destructor, Dispose
52
53
54         #region Property
55         /// <summary>
56         /// Instance for singleton
57         /// </summary>
58         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
59         [EditorBrowsable(EditorBrowsableState.Never)]
60         public static Accessibility Instance
61         {
62             get => accessibility;
63         }
64         #endregion Property
65
66
67         #region Method
68         /// <summary>
69         /// Get the current status
70         /// </summary>
71         /// <returns>Current enabled status</returns>
72         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
73         [EditorBrowsable(EditorBrowsableState.Never)]
74         static public bool GetStatus()
75         {
76             return true;
77         }
78
79         /// <summary>
80         /// Start to speak
81         /// </summary>
82         /// <param name="sentence">Content to be spoken</param>
83         /// <param name="discardable">true to be stopped and discarded when other Say is triggered</param>
84         /// <returns></returns>
85         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
86         [EditorBrowsable(EditorBrowsableState.Never)]
87         public bool Say(string sentence, bool discardable)
88         {
89             IntPtr callbackIntPtr = IntPtr.Zero;
90             if (sayFinishedEventHandler != null)
91             {
92                 callback = SayFinishedEventCallback;
93                 callbackIntPtr = Marshal.GetFunctionPointerForDelegate<Delegate>(callback);
94             }
95             bool ret = Interop.Accessibility.Say(View.getCPtr(dummy), sentence, discardable, callbackIntPtr);
96             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
97             return ret;
98         }
99
100         /// <summary>
101         /// To make Say be paused or resumed
102         /// </summary>
103         /// <param name="pause">true to be paused, false to be resumed</param>
104         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
105         [EditorBrowsable(EditorBrowsableState.Never)]
106         public void PauseResume(bool pause)
107         {
108             Interop.Accessibility.PauseResume(View.getCPtr(dummy), pause);
109             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
110         }
111
112         /// <summary>
113         /// Cancels anything screen-reader is reading / has queued to read
114         /// </summary>
115         /// <param name="alsoNonDiscardable">whether to cancel non-discardable readings as well</param>
116         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
117         [EditorBrowsable(EditorBrowsableState.Never)]
118         public void StopReading(bool alsoNonDiscardable)
119         {
120             Interop.Accessibility.StopReading(View.getCPtr(dummy), alsoNonDiscardable);
121             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
122         }
123
124         /// <summary>
125         ///  Get View that is used to highlight widget.
126         /// </summary>
127         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
128         [EditorBrowsable(EditorBrowsableState.Never)]
129         public View GetHighlightFrameView()
130         {
131             var ptr = Interop.ControlDevel.DaliAccessibilityAccessibleGetHighlightActor();
132             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
133             if (ptr == IntPtr.Zero)
134                 return null;
135             return new View(ptr, true);
136         }
137
138         /// <summary>
139         ///  Set view that will be used to highlight widget.
140         /// </summary>
141         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
142         [EditorBrowsable(EditorBrowsableState.Never)]
143         public void SetHighlightFrameView(View view)
144         {
145             Interop.ControlDevel.DaliAccessibilityAccessibleSetHighlightActor(View.getCPtr(view));
146             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
147         }
148
149         /// <summary>
150         ///  Get highligted View.
151         /// </summary>
152         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
153         [EditorBrowsable(EditorBrowsableState.Never)]
154         public View GetCurrentlyHighlightedView()
155         {
156             var ptr = Interop.ControlDevel.DaliAccessibilityAccessibleGetCurrentlyHighlightedActor();
157             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
158             if (ptr == IntPtr.Zero)
159                 return null;
160             return new View(ptr, true);
161         }
162
163         /// <summary>
164         ///  Clear highlight.
165         /// </summary>
166         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
167         [EditorBrowsable(EditorBrowsableState.Never)]
168         public bool ClearCurrentlyHighlightedView()
169         {
170             using (View view = GetCurrentlyHighlightedView())
171             {
172                 return view?.ClearAccessibilityHighlight() ?? false;
173             }
174         }
175         #endregion Method
176
177
178         #region Event, Enum, Struct, ETC
179         /// <summary>
180         /// Enum of Say finished event argument status
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 enum SayFinishedState
185         {
186             /// <summary>
187             /// Invalid
188             /// </summary>
189             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
190             [EditorBrowsable(EditorBrowsableState.Never)]
191             Invalid = -1,
192             /// <summary>
193             /// Cancelled
194             /// </summary>
195             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
196             [EditorBrowsable(EditorBrowsableState.Never)]
197             Cancelled = 1,
198             /// <summary>
199             /// Stopped
200             /// </summary>
201             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
202             [EditorBrowsable(EditorBrowsableState.Never)]
203             Stopped = 2,
204             /// <summary>
205             /// Skipped
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             Skipped = 3,
210             /// <summary>
211             /// Paused
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             Paused = 4,
216             /// <summary>
217             /// Resumed
218             /// </summary>
219             // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
220             [EditorBrowsable(EditorBrowsableState.Never)]
221             Resumed = 5
222         }
223
224         /// <summary>
225         /// When Say is finished, this event is triggered
226         /// </summary>
227         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
228         [EditorBrowsable(EditorBrowsableState.Never)]
229         public event EventHandler<SayFinishedEventArgs> SayFinished
230         {
231             add => sayFinishedEventHandler += value;
232             remove => sayFinishedEventHandler -= value;
233         }
234         #endregion Event, Enum, Struct, ETC
235
236
237         #region Internal
238         internal void PauseResume(View target, bool pause)
239         {
240             Interop.Accessibility.PauseResume(View.getCPtr(target), pause);
241             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
242         }
243
244         internal bool Say(View target, string sentence, bool discardable)
245         {
246             IntPtr callbackIntPtr = IntPtr.Zero;
247             if (sayFinishedEventHandler != null)
248             {
249                 callback = SayFinishedEventCallback;
250                 callbackIntPtr = Marshal.GetFunctionPointerForDelegate<Delegate>(callback);
251             }
252             bool ret = Interop.Accessibility.Say(View.getCPtr(target), sentence, discardable, callbackIntPtr);
253             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
254             return ret;
255         }
256         #endregion Internal
257
258
259         #region Private
260         private static readonly Accessibility accessibility = new Accessibility();
261
262         private event EventHandler<SayFinishedEventArgs> sayFinishedEventHandler;
263
264         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
265         private delegate void SayFinishedEventCallbackType(int result);
266
267         private SayFinishedEventCallbackType callback = null;
268
269         private void SayFinishedEventCallback(int result)
270         {
271             tlog.Fatal(tag, $"sayFinishedEventCallback(res={result}) called!");
272             sayFinishedEventHandler?.Invoke(this, new SayFinishedEventArgs(result));
273         }
274
275         private View dummy;
276
277         private static string tag = "NUITEST";
278         #endregion Private
279     }
280
281     /// <summary>
282     ///  Say Finished event arguments
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     public class SayFinishedEventArgs : EventArgs
287     {
288         /// <summary>
289         /// The state of Say finished
290         /// </summary>
291         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
292         [EditorBrowsable(EditorBrowsableState.Never)]
293         public Accessibility.SayFinishedState State
294         {
295             private set;
296             get;
297         }
298
299         internal SayFinishedEventArgs(int result)
300         {
301             State = (Accessibility.SayFinishedState)(result);
302             tlog.Fatal("NUITEST", $"SayFinishedEventArgs Constructor! State={State}");
303         }
304     }
305 }