0b9ee80af749adfeff9f7228ef97ec51be3eaccb
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / ViewAccessibility.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.Runtime.InteropServices;
22 using Tizen.NUI;
23
24 namespace Tizen.NUI.BaseComponents
25 {
26     /// <summary>
27     /// AccessibilityRange is used to store data related with Text.
28     /// </summary>
29     [EditorBrowsable(EditorBrowsableState.Never)]
30     public class AccessibilityRange
31     {
32         /// <summary>
33         /// Start position in stored text.
34         /// </summary>
35         public int StartOffset { get; set; } = 0;
36
37         /// <summary>
38         /// End position in stored text.
39         /// </summary>
40         public int EndOffset { get; set; } = 0;
41
42         /// <summary>
43         /// Text content in stored text.
44         /// </summary>
45         public string Content { get; set; } = "";
46     }
47
48     /// <summary>
49     /// View is the base class for all views.
50     /// </summary>
51     /// <since_tizen> 3 </since_tizen>
52     public partial class View
53     {
54         ///////////////////////////////////////////////////////////////////
55         // ****************** Accessibility Attributes ****************** //
56         ///////////////////////////////////////////////////////////////////
57
58         /// <summary>
59         /// Dictionary of accessibility attributes (key-value pairs of strings).
60         /// </summary>
61         [EditorBrowsable(EditorBrowsableState.Never)]
62         public Dictionary<string, string> AccessibilityAttributes { get; } = new Dictionary<string, string>();
63
64         /// <summary>
65         /// Dictionary of dynamically-evaluated accessibility attributes (key-value pairs of strings).
66         /// </summary>
67         [EditorBrowsable(EditorBrowsableState.Never)]
68         public Dictionary<string, Func<string>> AccessibilityDynamicAttributes { get; } = new Dictionary<string, Func<string>>();
69
70         ///////////////////////////////////////////////////////////////////
71         // ************************** Highlight ************************ //
72         ///////////////////////////////////////////////////////////////////
73
74         /// <summary>
75         /// Clears accessibility highlight.
76         /// </summary>
77         /// <returns>True if cleared, otherwise false when it is not possible</returns>
78         [EditorBrowsable(EditorBrowsableState.Never)]
79         public bool ClearAccessibilityHighlight()
80         {
81             bool result = Interop.ControlDevel.DaliToolkitDevelControlClearAccessibilityHighlight(SwigCPtr);
82             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
83             return result;
84         }
85
86         /// <summary>
87         /// Grabs accessibility highlight.
88         /// </summary>
89         /// <returns>True if cleared, otherwise false when it is not possible</returns>
90         [EditorBrowsable(EditorBrowsableState.Never)]
91         public bool GrabAccessibilityHighlight()
92         {
93             bool result = Interop.ControlDevel.DaliToolkitDevelControlGrabAccessibilityHighlight(SwigCPtr);
94             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
95             return result;
96         }
97
98         /// <summary>
99         /// Flag to check whether this view is highlighted or not.
100         /// </summary>
101         [EditorBrowsable(EditorBrowsableState.Never)]
102         protected bool IsHighlighted
103         {
104             get
105             {
106                 return (this == Accessibility.Accessibility.GetCurrentlyHighlightedView());
107             }
108         }
109
110         ///////////////////////////////////////////////////////////////////
111         // ****************** Accessibility Relations ******************* //
112         ///////////////////////////////////////////////////////////////////
113
114         /// <summary>
115         /// Creates relation between objects.
116         /// </summary>
117         /// <param name="second">Object which will be in relation.</param>
118         /// <param name="relation">Relation type.</param>
119         /// <exception cref="ArgumentNullException">You must pass valid object. NULL could not be in relation.</exception>
120         [EditorBrowsable(EditorBrowsableState.Never)]
121         public void AppendAccessibilityRelation(View second, AccessibilityRelationType relation)
122         {
123             if (second is null)
124             {
125                 throw new ArgumentNullException(nameof(second));
126             }
127
128             Interop.ControlDevel.DaliToolkitDevelControlAppendAccessibilityRelation(SwigCPtr, second.SwigCPtr, (int)relation);
129             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
130         }
131
132         /// <summary>
133         /// Removes accessibility relation.
134         /// </summary>
135         /// <param name="second">Object which will be removed in relation</param>
136         /// <param name="relation">Relation type</param>
137         [EditorBrowsable(EditorBrowsableState.Never)]
138         public void RemoveAccessibilityRelation(View second, AccessibilityRelationType relation)
139         {
140             if (second is null)
141             {
142                 throw new ArgumentNullException(nameof(second));
143             }
144
145             Interop.ControlDevel.DaliToolkitDevelControlRemoveAccessibilityRelation(SwigCPtr, second.SwigCPtr, (int)relation);
146             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
147         }
148
149         /// <summary>
150         /// Removes all previously appended relations.
151         /// </summary>
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         public void ClearAccessibilityRelations()
154         {
155             Interop.ControlDevel.DaliToolkitDevelControlClearAccessibilityRelations(SwigCPtr);
156             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
157         }
158
159         /// <summary>
160         /// Gets accessibility collection connected with the current object.
161         /// </summary>
162         /// <returns>A dictionary mapping a relation type to a set of objects in that relation</returns>
163         [EditorBrowsable(EditorBrowsableState.Never)]
164         public Dictionary<AccessibilityRelationType, List<View>> GetAccessibilityRelations()
165         {
166             var list = new List<KeyValuePair<int, IntPtr>>();
167             var listHandle = GCHandle.Alloc(list);
168             var callback = new Interop.ControlDevel.GetAccessibilityRelationsCallback(GetAccessibilityRelationsCallback);
169
170             Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityRelations(SwigCPtr, callback, GCHandle.ToIntPtr(listHandle));
171             listHandle.Free();
172             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
173
174             var result = new Dictionary<AccessibilityRelationType, List<View>>();
175
176             foreach (var pair in list)
177             {
178                 var key = (AccessibilityRelationType)pair.Key;
179                 var value = this.GetInstanceSafely<View>(pair.Value);
180
181                 if (!result.ContainsKey(key))
182                 {
183                     result[key] = new List<View>();
184                 }
185
186                 result[key].Add(value);
187             }
188
189             return result;
190         }
191
192         private static void GetAccessibilityRelationsCallback(int relationType, IntPtr relationTarget, IntPtr userData)
193         {
194             var handle = GCHandle.FromIntPtr(userData);
195             var list = (List<KeyValuePair<int, IntPtr>>)handle.Target;
196
197             list.Add(new KeyValuePair<int, IntPtr>(relationType, relationTarget));
198         }
199
200         ///////////////////////////////////////////////////////////////////
201         // ********************* ReadingInfoType *********************** //
202         ///////////////////////////////////////////////////////////////////
203
204         /// <summary>
205         /// Sets accessibility reading information.
206         /// </summary>
207         /// <param name="type">Reading information type</param>
208         [EditorBrowsable(EditorBrowsableState.Never)]
209         public void SetAccessibilityReadingInfoTypes(AccessibilityReadingInfoTypes type)
210         {
211             Interop.ControlDevel.DaliToolkitDevelControlSetAccessibilityReadingInfoTypes(SwigCPtr, (int)type);
212             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
213         }
214
215         /// <summary>
216         /// Gets accessibility reading information.
217         /// </summary>
218         /// <returns>Reading information type</returns>
219         [EditorBrowsable(EditorBrowsableState.Never)]
220         public AccessibilityReadingInfoTypes GetAccessibilityReadingInfoTypes()
221         {
222             AccessibilityReadingInfoTypes result = (AccessibilityReadingInfoTypes)Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityReadingInfoTypes(SwigCPtr);
223             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
224             return result;
225         }
226
227         ///////////////////////////////////////////////////////////////////
228         // ******************** Accessibility States ******************* //
229         ///////////////////////////////////////////////////////////////////
230
231         /// <summary>
232         /// Notifies sending notifications about the current states to accessibility clients.
233         /// </summary>
234         /// <remarks>
235         /// In essence, this is equivalent to calling EmitAccessibilityStateChangedEvent in a loop for all specified states.
236         /// If recursive mode is specified, all children of the Accessibility object will also re-emit the states.
237         /// </remarks>
238         /// <param name="states">Accessibility States</param>
239         /// <param name="notifyMode">Controls the notification strategy</param>
240         [EditorBrowsable(EditorBrowsableState.Never)]
241         public void NotifyAccessibilityStatesChange(AccessibilityStates states, AccessibilityStatesNotifyMode notifyMode)
242         {
243             if (states is null)
244             {
245                 throw new ArgumentNullException(nameof(states));
246             }
247
248             Interop.ControlDevel.DaliToolkitDevelControlNotifyAccessibilityStateChange(SwigCPtr, states.BitMask, (int)notifyMode);
249             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
250         }
251
252         /// <summary>
253         /// Gets Accessibility States.
254         /// </summary>
255         /// <returns>Accessibility States</returns>
256         [EditorBrowsable(EditorBrowsableState.Never)]
257         public AccessibilityStates GetAccessibilityStates()
258         {
259             var result = new AccessibilityStates { BitMask = Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityStates(SwigCPtr) };
260             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
261             return result;
262         }
263
264         ///////////////////////////////////////////////////////////////////
265         // ************************ Accessible ************************* //
266         ///////////////////////////////////////////////////////////////////
267
268         /// <summary>
269         /// Emits accessibility property changed event.
270         /// </summary>
271         /// <param name="changeEvent">Property changed event</param>
272         [EditorBrowsable(EditorBrowsableState.Never)]
273         public void EmitAccessibilityEvent(AccessibilityPropertyChangeEvent changeEvent)
274         {
275             Interop.ControlDevel.DaliAccessibilityEmitAccessibilityEvent(SwigCPtr, Convert.ToInt32(changeEvent));
276             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
277         }
278
279         /// <summary>
280         /// Emits accessibility states changed event.
281         /// </summary>
282         /// <param name="state">Accessibility state</param>
283         /// <param name="equal">True if the state is set or enabled, otherwise false</param>
284         [EditorBrowsable(EditorBrowsableState.Never)]
285         public void EmitAccessibilityStateChangedEvent(AccessibilityState state, bool equal)
286         {
287             Interop.ControlDevel.DaliAccessibilityEmitAccessibilityStateChangedEvent(SwigCPtr, (int)state, Convert.ToInt32(equal));
288             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
289         }
290
291         /// <summary>
292         /// Emits accessibility text inserted event.
293         /// </summary>
294         /// <param name="cursorPosition">Text cursor position</param>
295         /// <param name="length">Text length</param>
296         /// <param name="content">Inserted text content</param>
297         [EditorBrowsable(EditorBrowsableState.Never)]
298         public void EmitTextInsertedEvent(int cursorPosition, int length, string content)
299         {
300             Interop.ControlDevel.DaliAccessibilityEmitTextInsertedEvent(SwigCPtr, cursorPosition, length, content);
301             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
302         }
303
304         /// <summary>
305         /// Emits accessibility text deleted event.
306         /// </summary>
307         /// <param name="cursorPosition">Text cursor position</param>
308         /// <param name="length">Text length</param>
309         /// <param name="content">Inserted text content</param>
310         [EditorBrowsable(EditorBrowsableState.Never)]
311         public void EmitTextDeletedEvent(int cursorPosition, int length, string content)
312         {
313             Interop.ControlDevel.DaliAccessibilityEmitTextDeletedEvent(SwigCPtr, cursorPosition, length, content);
314             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
315         }
316
317         /// <summary>
318         /// Emits accessibility text cursor moved event.
319         /// </summary>
320         /// <param name="cursorPosition">The new cursor position</param>
321         [EditorBrowsable(EditorBrowsableState.Never)]
322         public void EmitTextCursorMovedEvent(int cursorPosition)
323         {
324             Interop.ControlDevel.DaliAccessibilityEmitTextCursorMovedEvent(SwigCPtr, cursorPosition);
325             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
326         }
327
328         /// <summary>
329         /// Emits accessibility scroll started event.
330         /// </summary>
331         [EditorBrowsable(EditorBrowsableState.Never)]
332         public void EmitScrollStartedEvent()
333         {
334             Interop.ControlDevel.DaliAccessibilityEmitScrollStartedEvent(SwigCPtr);
335             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
336         }
337
338         /// <summary>
339         /// Emits accessibility scroll finished event.
340         /// </summary>
341         [EditorBrowsable(EditorBrowsableState.Never)]
342         public void EmitScrollFinishedEvent()
343         {
344             Interop.ControlDevel.DaliAccessibilityEmitScrollFinishedEvent(SwigCPtr);
345             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
346         }
347
348         /// <summary>
349         /// Modifiable collection of suppressed AT-SPI events (D-Bus signals).
350         /// </summary>
351         [EditorBrowsable(EditorBrowsableState.Never)]
352         public AccessibilityEvents AccessibilitySuppressedEvents
353         {
354             get
355             {
356                 return new AccessibilityEvents { Owner = this };
357             }
358         }
359
360         ///////////////////////////////////////////////////////////////////
361         // ************************** Bridge *************************** //
362         ///////////////////////////////////////////////////////////////////
363
364         /// <summary>
365         /// Registers component as a source of an accessibility "default label".
366         /// The "Default label" is a text that could be read by screen-reader immediately
367         /// after the navigation context has changed (window activates, popup shows up, tab changes)
368         /// and before first UI element is highlighted.
369         /// </summary>
370         [EditorBrowsable(EditorBrowsableState.Never)]
371         public void RegisterDefaultLabel()
372         {
373             Interop.ControlDevel.DaliAccessibilityBridgeRegisterDefaultLabel(SwigCPtr);
374             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
375         }
376
377         /// <summary>
378         /// Unregisters component that has been registered previously as a source of an accessibility "default label".
379         /// The "Default label" is a text that could be read by screen-reader immediately
380         /// after the navigation context has changed (window activates, popup shows up, tab changes)
381         /// and before first UI element is highlighted.
382         /// </summary>
383         [EditorBrowsable(EditorBrowsableState.Never)]
384         public void UnregisterDefaultLabel()
385         {
386             Interop.ControlDevel.DaliAccessibilityBridgeUnregisterDefaultLabel(SwigCPtr);
387             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
388         }
389
390         [EditorBrowsable(EditorBrowsableState.Never)]
391         protected override void Dispose(bool disposing)
392         {
393             if (disposed)
394             {
395                 return;
396             }
397
398             internalName = null;
399
400             if (SwigCPtr.Handle != IntPtr.Zero && global::System.Threading.Thread.CurrentThread.ManagedThreadId == Registry.Instance.SavedApplicationThread.ManagedThreadId)
401             {
402                 Interop.ControlDevel.DaliAccessibilityDetachAccessibleObject(SwigCPtr);
403                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
404             }
405
406             if (disposing == false)
407             {
408                 if (IsNativeHandleInvalid() || SwigCMemOwn == false)
409                 {
410                     // at this case, implicit nor explicit dispose is not required. No native object is made.
411                     disposed = true;
412                     return;
413                 }
414             }
415
416             if (disposing)
417             {
418                 Unparent();
419             }
420
421             base.Dispose(disposing);
422         }
423
424         [EditorBrowsable(EditorBrowsableState.Never)]
425         protected static readonly string AccessibilityActivateAction = "activate";
426         [EditorBrowsable(EditorBrowsableState.Never)]
427         protected static readonly string AccessibilityReadingSkippedAction = "ReadingSkipped";
428         [EditorBrowsable(EditorBrowsableState.Never)]
429         protected static readonly string AccessibilityReadingCancelledAction = "ReadingCancelled";
430         [EditorBrowsable(EditorBrowsableState.Never)]
431         protected static readonly string AccessibilityReadingStoppedAction = "ReadingStopped";
432         [EditorBrowsable(EditorBrowsableState.Never)]
433         protected static readonly string AccessibilityReadingPausedAction = "ReadingPaused";
434         [EditorBrowsable(EditorBrowsableState.Never)]
435         protected static readonly string AccessibilityReadingResumedAction = "ReadingResumed";
436
437         [EditorBrowsable(EditorBrowsableState.Never)]
438         private static readonly string[] AccessibilityActions = {
439             AccessibilityActivateAction,
440             AccessibilityReadingSkippedAction,
441             AccessibilityReadingCancelledAction,
442             AccessibilityReadingStoppedAction,
443             AccessibilityReadingPausedAction,
444             AccessibilityReadingResumedAction,
445         };
446
447         [EditorBrowsable(EditorBrowsableState.Never)]
448         protected virtual string AccessibilityGetName()
449         {
450             return "";
451         }
452
453         [EditorBrowsable(EditorBrowsableState.Never)]
454         protected virtual string AccessibilityGetDescription()
455         {
456             return "";
457         }
458
459         [EditorBrowsable(EditorBrowsableState.Never)]
460         protected virtual bool AccessibilityDoAction(string name)
461         {
462             if (name == AccessibilityActivateAction)
463             {
464                 if (ActivateSignal?.Empty() == false)
465                 {
466                     ActivateSignal?.Emit();
467                     return true;
468                 }
469                 else
470                 {
471                     return OnAccessibilityActivated();
472                 }
473             }
474             else if (name == AccessibilityReadingSkippedAction)
475             {
476                 if (ReadingSkippedSignal?.Empty() == false)
477                 {
478                     ReadingSkippedSignal?.Emit();
479                     return true;
480                 }
481                 else
482                 {
483                     return OnAccessibilityReadingSkipped();
484                 }
485             }
486             else if (name == AccessibilityReadingCancelledAction)
487             {
488                 if (ReadingCancelledSignal?.Empty() == false)
489                 {
490                     ReadingCancelledSignal?.Emit();
491                     return true;
492                 }
493                 else
494                 {
495                     return OnAccessibilityReadingCancelled();
496                 }
497             }
498             else if (name == AccessibilityReadingStoppedAction)
499             {
500                 if (ReadingStoppedSignal?.Empty() == false)
501                 {
502                     ReadingStoppedSignal?.Emit();
503                     return true;
504                 }
505                 else
506                 {
507                     return OnAccessibilityReadingStopped();
508                 }
509             }
510             else if (name == AccessibilityReadingPausedAction)
511             {
512                 if (ReadingPausedSignal?.Empty() == false)
513                 {
514                     ReadingPausedSignal?.Emit();
515                     return true;
516                 }
517                 else
518                 {
519                     return OnAccessibilityReadingPaused();
520                 }
521             }
522             else if (name == AccessibilityReadingResumedAction)
523             {
524                 if (ReadingResumedSignal?.Empty() == false)
525                 {
526                     ReadingResumedSignal?.Emit();
527                     return true;
528                 }
529                 else
530                 {
531                     return OnAccessibilityReadingResumed();
532                 }
533             }
534             else
535             {
536                 return false;
537             }
538         }
539
540         [EditorBrowsable(EditorBrowsableState.Never)]
541         protected virtual AccessibilityStates AccessibilityCalculateStates()
542         {
543             var states = AccessibilityInitialStates;
544
545             states[AccessibilityState.Focused] = this.State == States.Focused;
546             states[AccessibilityState.Enabled] = this.State != States.Disabled;
547             states[AccessibilityState.Sensitive] = this.Sensitive;
548
549             return states;
550         }
551
552         [EditorBrowsable(EditorBrowsableState.Never)]
553         protected virtual int AccessibilityGetActionCount()
554         {
555             return AccessibilityActions.Length;
556         }
557
558         [EditorBrowsable(EditorBrowsableState.Never)]
559         protected virtual string AccessibilityGetActionName(int index)
560         {
561             if (index >= 0 && index < AccessibilityActions.Length)
562             {
563                 return AccessibilityActions[index];
564             }
565             else
566             {
567                 return "";
568             }
569         }
570
571         [EditorBrowsable(EditorBrowsableState.Never)]
572         protected virtual bool AccessibilityIsScrollable()
573         {
574             return false;
575         }
576
577         [EditorBrowsable(EditorBrowsableState.Never)]
578         protected virtual bool AccessibilityScrollToChild(View child)
579         {
580             return false;
581         }
582
583         /// <summary>
584         /// This method is called when the control accessibility is activated.<br />
585         /// Derived classes should override this to perform custom accessibility activation.<br />
586         /// </summary>
587         /// <returns>True if this control can perform accessibility activation.</returns>
588         [EditorBrowsable(EditorBrowsableState.Never)]
589         protected virtual bool OnAccessibilityActivated()
590         {
591             return FocusManager.Instance.SetCurrentFocusView(this);
592         }
593
594         /// <summary>
595         /// This method is called when reading is skipped.
596         /// </summary>
597         /// <returns>True if information was served.</returns>
598         [EditorBrowsable(EditorBrowsableState.Never)]
599         protected virtual bool OnAccessibilityReadingSkipped()
600         {
601             return false;
602         }
603
604         /// <summary>
605         /// This method is called when reading is cancelled.
606         /// </summary>
607         /// <returns>True if information was served.</returns>
608         [EditorBrowsable(EditorBrowsableState.Never)]
609         protected virtual bool OnAccessibilityReadingCancelled()
610         {
611             return false;
612         }
613
614         /// <summary>
615         /// This method is called when reading is stopped.
616         /// </summary>
617         /// <returns>True if information was served.</returns>
618         [EditorBrowsable(EditorBrowsableState.Never)]
619         protected virtual bool OnAccessibilityReadingStopped()
620         {
621             return false;
622         }
623
624         /// <summary>
625         /// This method is called when reading was paused.
626         /// </summary>
627         /// <returns>True if information was served.</returns>
628         [EditorBrowsable(EditorBrowsableState.Never)]
629         protected virtual bool OnAccessibilityReadingPaused()
630         {
631             return false;
632         }
633
634         /// <summary>
635         /// This method is called when reading is resumed.
636         /// </summary>
637         /// <returns>True if information was served.</returns>
638         [EditorBrowsable(EditorBrowsableState.Never)]
639         protected virtual bool OnAccessibilityReadingResumed()
640         {
641             return false;
642         }
643     }
644 }