[VoiceControl] Base Code
[platform/core/csapi/uix-voice-control.git] / Tizen.Uix.VoiceControl / Tizen.Uix.VoiceControl / VoiceControlClient.cs
1 /*
2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 using System;
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using static Interop.VoiceControl;
21 using static Interop.VoiceControlCommand;
22
23 namespace Tizen.Uix.VoiceControl
24 {
25     /// <summary>
26     /// Enum for Error values that can occur
27     /// </summary>
28     public enum Error
29     {
30         /// <summary>
31         /// Successful, No error
32         /// </summary>
33         None,
34         /// <summary>
35         /// Out of Memory
36         /// </summary>
37         OutOfMemory,
38         /// <summary>
39         /// I/O error
40         /// </summary>
41         IoError,
42         /// <summary>
43         /// Invalid parameter
44         /// </summary>
45         InvalidParameter,
46         /// <summary>
47         /// No answer from the STT service
48         /// </summary>
49         TimedOut,
50         /// <summary>
51         /// Device or resource busy
52         /// </summary>
53         RecorderBusy,
54         /// <summary>
55         /// Permission denied
56         /// </summary>
57         PermissionDenied,
58         /// <summary>
59         /// VC NOT supported
60         /// </summary>
61         NotSupported,
62         /// <summary>
63         /// Invalid state
64         /// </summary>
65         InvalidState,
66         /// <summary>
67         /// Invalid language
68         /// </summary>
69         InvalidLanguage,
70         /// <summary>
71         /// No available engine
72         /// </summary>
73         EngineNotFound,
74         /// <summary>
75         /// Operation failed
76         /// </summary>
77         OperationFailed,
78         /// <summary>
79         /// Operation Rejected
80         /// </summary>
81         OperationRejected,
82         /// <summary>
83         /// List reached end
84         /// </summary>
85         IterationEnd,
86         /// <summary>
87         /// List Empty
88         /// </summary>
89         Empty,
90         /// <summary>
91         /// Service reset
92         /// </summary>
93         ServiceReset,
94         /// <summary>
95         /// Progress to ready is not finished
96         /// </summary>
97         InProgressToReady,
98         /// <summary>
99         /// Progress to recording is not finished
100         /// </summary>
101         InProgressToRecording,
102         /// <summary>
103         /// Progress to processing is not finished
104         /// </summary>
105         InProgressToProcessing
106     };
107
108     /// <summary>
109     /// Enumeration for the client state.
110     /// </summary>
111     public enum State
112     {
113         /// <summary>
114         /// 'None' state
115         /// </summary>
116         None = 0,
117         /// <summary>
118         /// 'Initialized' state
119         /// </summary>
120         Initialized = 1,
121         /// <summary>
122         /// 'Ready' state
123         /// </summary>
124         Ready = 2,
125         /// <summary>
126         /// state cannot be determined
127         /// </summary>
128         Unavailable
129     };
130
131     /// <summary>
132     /// Enumerations of service state.
133     /// </summary>
134     public enum ServiceState
135     {
136         /// <summary>
137         /// 'None' state
138         /// </summary>
139         None = 0,
140         /// <summary>
141         /// 'Ready' state
142         /// </summary>
143         Ready = 1,
144         /// <summary>
145         /// 'Recording' state
146         /// </summary>
147         Recording = 2,
148         /// <summary>
149         /// 'Processing' state
150         /// </summary>
151         Processing = 3,
152         /// <summary>
153         /// state cannot be determined
154         /// </summary>
155         Unavailable
156     };
157
158     /// <summary>
159     /// Enumerations of result event.
160     /// </summary>
161     public enum ResultEvent
162     {
163         /// <summary>
164         /// Normal result
165         /// </summary>
166         Success = 0,
167         /// <summary>
168         /// Rejected result
169         /// </summary>
170         Rejected = 1
171     };
172
173     /// <summary>
174     /// Enumerations of command type.
175     /// </summary>
176     public enum CommandType
177     {
178         /// <summary>
179         /// Foreground command by client
180         /// </summary>
181         Foreground = 1,
182         /// <summary>
183         /// Background command by client
184         /// </summary>
185         Background = 2,
186         /// <summary>
187         /// Undefined command
188         /// </summary>
189         Undefined = -1
190     };
191
192     /// <summary>
193     /// A main function of Voice Control API register command and gets notification for recognition result. 
194     /// Applications can add their own commands and be provided result when their command is recognized by user voice input.
195     /// </summary>
196     public static class VoiceControlClient
197     {
198         /// <summary>
199         /// Called when client gets the recognition result.
200         /// </summary>
201         /// <remarks>
202         /// If the duplicated commands are recognized, the event(e.g. Result.Rejected) of command may be rejected
203         /// for selecting command as priority.If you set similar or same commands or the recognized results are multi-results, cmdList has the multi commands.
204         /// </remarks>
205         /// <param name="evt">The ResultEvent</param>
206         /// <param name="cmdList">Command List</param>
207         /// <param name="result">Result</param>
208         public delegate void RecognitionResultDelegate(ResultEvent evt, VoiceCommandList cmdList, string result);
209
210         private static event EventHandler<RecognitionResultEventArgs> _recognitionResult;
211         private static event EventHandler<StateChangedEventArgs> _stateChanged;
212         private static event EventHandler<ServiceStateChangedEventArgs> _serviceStateChanged;
213         private static event EventHandler<ErrorOccuredEventArgs> _errorOccured;
214         private static event EventHandler<CurrentLanguageChangedEventArgs> _currentLanguageChanged;
215         private static VcResultCb s_resultDelegate;
216         private static VcStateChangedCb s_stateDelegate;
217         private static VcServiceStateChangedCb s_serviceStateDelegate;
218         private static VcErrorCb s_errorDelegate;
219         private static VcCurrentLanguageChangedCb s_languageDelegate;
220         private static List<string> s_supportedLanguages;
221         private static VcSupportedLanguageCb s_supportedLanguagesCb;
222         private static VcResultCb s_resultCb;
223
224         /// <summary>
225         /// Gets current language.
226         /// A language is specified as an ISO 3166 alpha-2 two letter country-code
227         /// followed by ISO 639-1 for the two-letter language code.
228         /// For example, "ko_KR" for Korean, "en_US" for American English.
229         /// Empty string is returned incase of some internal error
230         /// </summary>
231         /// <privilege>
232         /// http://tizen.org/privilege/recorder
233         /// </privilege>
234         /// <precondition>
235         /// The State must be Initialized or Ready.
236         /// </precondition>
237         public static string GetCurrentLanaguge
238         {
239             get
240             {
241                 string currentLanaguge;
242
243                 ErrorCode error = VcGetCurrentLanguage(out currentLanaguge);
244                 if (error != ErrorCode.None)
245                 {
246                     Log.Error(LogTag, "CurrentLanaguge Failed with error " + error);
247                     return "";
248                 }
249
250                 return currentLanaguge;
251             }
252         }
253
254         /// <summary>
255         /// Gets current state of voice control client. 
256         /// </summary>
257         /// <privilege>
258         /// http://tizen.org/privilege/recorder
259         /// </privilege>
260         /// <precondition>
261         /// The State must be Initialized or Ready.
262         /// </precondition>
263         public static State GetState
264         {
265             get
266             {
267                 State state;
268
269                 ErrorCode error = VcGetState(out state);
270                 if (error != ErrorCode.None)
271                 {
272                     Log.Error(LogTag, "GetState Failed with error " + error);
273                     return State.Unavailable;
274                 }
275
276                 return state;
277             }
278         }
279
280         /// <summary>
281         /// Gets current state of voice control service.
282         /// </summary>
283         /// <privilege>
284         /// http://tizen.org/privilege/recorder
285         /// </privilege>
286         /// <precondition>
287         /// The State must be Ready.
288         /// </precondition>
289         public static ServiceState GetServiceState
290         {
291             get
292             {
293                 ServiceState state;
294
295                 ErrorCode error = VcGetServiceState(out state);
296                 if (error != ErrorCode.None)
297                 {
298                     Log.Error(LogTag, "GetServiceState Failed with error " + error);
299                     return ServiceState.Unavailable;
300                 }
301
302                 return state;
303             }
304         }
305
306         /// <summary>
307         /// Sets the invocation name.
308         /// </summary>
309         /// <privilege>
310         /// http://tizen.org/privilege/recorder
311         /// </privilege>
312         /// <remarks>
313         /// Invocation name is used to activate background commands. The invocation name can be the same as the application name or any other phrase.
314         /// For example, an application "Tizen Sample" has a background command, "Play music", and the invocation name of the application is set to "Tizen Sample".
315         /// In order to activate the background command, users can say "Tizen Sample, Play music". The invocation name is dependent on the current language.
316         /// For example, if the current language is "en_US"(English), the invocation name is also "en_US".
317         /// If the current language is "ja_JP"(Japanese) and the invocation name is "en_US", the invocation name will not be recognized.
318         /// This function should be called before SetCommandList().
319         /// </remarks>
320         /// <param name="name">Invocation name that an application wants to be invoked by</param>
321         /// <exception cref="InvalidOperationException">
322         /// This Exception can be due to the following reaons
323         /// 1. Invalid parameter
324         /// 2. Invalid state
325         /// 3. Not Supported
326         /// 4. Permission Denied
327         /// </exception>
328         /// <precondition>
329         /// The State must be Ready.
330         /// </precondition>
331         public static void SetInvocationName(string name)
332         {
333             ErrorCode error = VcSetInvocationName(name);
334             if (error != ErrorCode.None)
335             {
336                 Log.Error(LogTag, "SetInvocationName Failed with error " + error);
337                 throw ExceptionFactory.CreateException(error);
338             }
339         }
340
341         /// <summary>
342         /// Initializes voice control.
343         /// </summary>
344         /// <privilege>
345         /// http://tizen.org/privilege/recorder
346         /// </privilege>
347         /// <exception cref="InvalidOperationException">
348         /// This Exception can be due to the following reaons
349         /// 1. Out Of Memory
350         /// 2. Operation Failed
351         /// 3. Not Supported
352         /// 4. Permission Denied
353         /// </exception>
354         /// <postcondition>
355         /// The State will be Initialized.
356         /// </postcondition>
357         public static void Initialize()
358         {
359             ErrorCode error = VcInitialize();
360             if (error != ErrorCode.None)
361             {
362                 Log.Error(LogTag, "Initialize Failed with error " + error);
363                 throw ExceptionFactory.CreateException(error);
364             }
365         }
366
367         /// <summary>
368         /// Deinitializes voice control.
369         /// </summary>
370         /// <privilege>
371         /// http://tizen.org/privilege/recorder
372         /// </privilege>
373         /// <exception cref="InvalidOperationException">
374         /// This Exception can be due to the following reaons
375         /// 1. Operation Failed
376         /// 2. Invalid state
377         /// 3. Not Supported
378         /// 4. Permission Denied
379         /// </exception>
380         public static void Deinitialize()
381         {
382             ErrorCode error = VcDeinitialize();
383             if (error != ErrorCode.None)
384             {
385                 Log.Error(LogTag, "Deinitialize Failed with error " + error);
386                 throw ExceptionFactory.CreateException(error);
387             }
388         }
389
390         /// <summary>
391         /// Connects the voice control service.
392         /// </summary>
393         /// <privilege>
394         /// http://tizen.org/privilege/recorder
395         /// </privilege>
396         /// <exception cref="InvalidOperationException">
397         /// This Exception can be due to the following reaons
398         /// 1. Operation Failed
399         /// 2. Not Supported
400         /// 3. Permission Denied
401         /// 4. Invalid State
402         /// </exception>
403         /// <precondition>
404         /// The State should be Initialized
405         /// </precondition>
406         /// <postcondition>
407         /// The State will be Ready
408         /// </postcondition>
409         public static void Prepare()
410         {
411             ErrorCode error = VcPrepare();
412             if (error != ErrorCode.None)
413             {
414                 Log.Error(LogTag, "Prepare Failed with error " + error);
415                 throw ExceptionFactory.CreateException(error);
416             }
417         }
418
419         /// <summary>
420         /// Disconnects the voice control service.
421         /// </summary>
422         /// <privilege>
423         /// http://tizen.org/privilege/recorder
424         /// </privilege>
425         /// <exception cref="InvalidOperationException">
426         /// This Exception can be due to the following reaons
427         /// 1. Not Supported
428         /// 2. Permission Denied
429         /// 3. Invalid State
430         /// </exception>
431         /// <precondition>
432         /// The State should be Ready
433         /// </precondition>
434         /// <postcondition>
435         /// The State should be Initialized
436         /// </postcondition>
437         public static void Unprepare()
438         {
439             ErrorCode error = VcUnprepare();
440             if (error != ErrorCode.None)
441             {
442                 Log.Error(LogTag, "Unprepare Failed with error " + error);
443                 throw ExceptionFactory.CreateException(error);
444             }
445         }
446
447         /// <summary>
448         /// Retrieves all supported languages.
449         /// A language is specified as an ISO 3166 alpha-2 two letter country-code
450         /// followed by ISO 639-1 for the two-letter language code.
451         /// For example, "ko_KR" for Korean, "en_US" for American English.
452         /// </summary>
453         /// <privilege>
454         /// http://tizen.org/privilege/recorder
455         /// </privilege>
456         /// <exception cref="InvalidOperationException">
457         /// This Exception can be due to the following reaons
458         /// 1. Operation Failed
459         /// 2. Not Supported
460         /// 3. Permission Denied
461         /// 4. Invalid State
462         /// </exception>
463         /// <precondition>
464         /// The State should be Ready or Initialized
465         /// </precondition>
466         public static IEnumerable<string> GetSupportedLangauges()
467         {
468             s_supportedLanguages = new List<string>();
469             s_supportedLanguagesCb = (IntPtr language, IntPtr userData) =>
470             {
471                 string languageStr = Marshal.PtrToStringAnsi(language);
472                 s_supportedLanguages.Add(languageStr);
473                 return true;
474             };
475             ErrorCode error = VcForeachSupportedLanguages(s_supportedLanguagesCb, IntPtr.Zero);
476             if (error != ErrorCode.None)
477             {
478                 Log.Error(LogTag, "GetSupportedLangauges Failed with error " + error);
479                 throw ExceptionFactory.CreateException(error);
480             }
481
482             return s_supportedLanguages;
483         }
484
485         /// <summary>
486         /// Gets the system command list.
487         /// </summary>
488         /// <returns>
489         /// The Command List else null in case of no System Commands
490         /// </returns>
491         /// <privilege>
492         /// http://tizen.org/privilege/recorder
493         /// </privilege>
494         /// <remarks>
495         /// In the system command list, there are system commands predefined by product manufacturers.
496         /// Those commands have the highest priority. Therefore, the user can not set any commands same with the system commands.
497         /// </remarks>
498         /// <exception cref="InvalidOperationException">
499         /// This Exception can be due to the following reaons
500         /// 1. Not Supported
501         /// 2. Permission Denied
502         /// 3. Invalid State
503         /// </exception>
504         /// <precondition>
505         /// The State should be Ready
506         /// </precondition>
507         public static VoiceCommandList GetSytemCommandList()
508         {
509             IntPtr handle = IntPtr.Zero;
510             ErrorCode error = VcGetSystemCommandList(out handle);
511             if (error != ErrorCode.None)
512             {
513                 Log.Error(LogTag, "GetSystemCommandList Failed with error " + error);
514                 throw ExceptionFactory.CreateException(error);
515             }
516
517             if (handle == IntPtr.Zero)
518             {
519                 Log.Error(LogTag, "GetSystemCommandList handle is null");
520                 return null;
521             }
522
523             SafeCommandListHandle list = new SafeCommandListHandle(handle);
524             return new VoiceCommandList(list);
525         }
526
527         /// <summary>
528         /// Requests to start the dialogue.
529         /// Using this function, the developer can request starting the dialogue to the framework.
530         /// When the developer requests the dialogue, two types of texts, dispText and uttText, can be sent by this function.dispText is a text for displaying, and uttText is that for uttering.
531         /// For example, if dispText is "October 10th" and uttText is "Today is October 10th.", "October 10th" will be displayed on the screen and "Today is October 10th." will be spoken.
532         /// Also, the developer can set whether the dialogue starts automatically or not, using autoStart.
533         /// If the developer sets autoStart as true, the framework will start to record next speech and continue the dialogue.
534         /// </summary>
535         /// <privilege>
536         /// http://tizen.org/privilege/recorder
537         /// </privilege>
538         /// <remarks>
539         /// If autoStart is true, the recognition will start again. In this case, it can be restarted up to 4 times.
540         /// </remarks>
541         /// <param name="dispText"> Text to be displayed on the screen/// </param>
542         /// <param name="uttText">Text to be spoken</param>
543         /// <param name="autoStart">A variable for setting whether the dialog session will be restarted automatically or not</param>
544         /// <exception cref="InvalidOperationException">
545         /// This Exception can be due to the following reaons
546         /// 1. Not Supported
547         /// 2. Permission Denied
548         /// 3. Invalid State
549         /// 4. Invalid parameter
550         /// </exception>
551         /// <precondition>
552         /// The State should be Ready
553         /// </precondition>
554         public static void RequestDialog(string dispText, string uttText, bool autoStart)
555         {
556             ErrorCode error = VcRequestDialog(dispText, uttText, autoStart);
557             if (error != ErrorCode.None)
558             {
559                 Log.Error(LogTag, "RequestDialog Failed with error " + error);
560                 throw ExceptionFactory.CreateException(error);
561             }
562         }
563
564         /// <summary>
565         /// Sets command list.
566         /// </summary>
567         /// <privilege>
568         /// http://tizen.org/privilege/recorder
569         /// </privilege>
570         /// <remarks>
571         /// The command type is valid for CommandType 'Foreground' or 'Background'.
572         /// The matched commands of command list should be set and they should include type and command text at least.
573         /// </remarks>
574         /// <param name="list">Command list</param>
575         /// <param name="type">Command type</param>
576         /// <exception cref="InvalidOperationException">
577         /// This Exception can be due to the following reaons
578         /// 1. Not Supported
579         /// 2. Permission Denied
580         /// 3. Invalid State
581         /// 4. Invalid parameter
582         /// </exception>
583         /// <precondition>
584         /// The State should be Ready
585         /// </precondition>
586         public static void SetCommandList(VoiceCommandList list, CommandType type)
587         {
588             if ((type == CommandType.Foreground) || (type == CommandType.Background))
589             {
590                 ErrorCode error = VcSetCommandList(list._handle, (VoiceCommandType)type);
591                 if (error != ErrorCode.None)
592                 {
593                     Log.Error(LogTag, "SetCommandList Failed with error " + error);
594                     throw ExceptionFactory.CreateException(error);
595                 }
596             }
597
598             else
599             {
600                 throw ExceptionFactory.CreateException(ErrorCode.InvalidParameter);
601             }
602         }
603
604         /// <summary>
605         /// Unsets command list.
606         /// </summary>
607         /// <privilege>
608         /// http://tizen.org/privilege/recorder
609         /// </privilege>
610         /// <param name="type">Command type</param>
611         /// <exception cref="InvalidOperationException">
612         /// This Exception can be due to the following reaons
613         /// 1. Not Supported
614         /// 2. Permission Denied
615         /// 3. Invalid State
616         /// 4. Invalid parameter
617         /// </exception>
618         /// <precondition>
619         /// The State should be Ready
620         /// </precondition>
621         public static void UnsetCommandList(CommandType type)
622         {
623             if ((type == CommandType.Foreground) || (type == CommandType.Background))
624             {
625                 VoiceCommandType commandType = VoiceCommandType.Foreground;
626                 if (type == CommandType.Background)
627                     commandType = VoiceCommandType.BackGround;
628                 ErrorCode error = VcUnsetCommandList(commandType);
629                 if (error != ErrorCode.None)
630                 {
631                     Log.Error(LogTag, "UnsetCommandList Failed with error " + error);
632                     throw ExceptionFactory.CreateException(error);
633                 }
634             }
635
636             else
637             {
638                 throw ExceptionFactory.CreateException(ErrorCode.InvalidParameter);
639             }
640         }
641
642         /// <summary>
643         /// Gets the recognition result.
644         /// </summary>
645         /// <privilege>
646         /// http://tizen.org/privilege/recorder
647         /// </privilege>
648         /// <param name="resultDelegate">
649         /// Callback function to get recognition result
650         /// </param>
651         /// <exception cref="InvalidOperationException">
652         /// This Exception can be due to the following reaons
653         /// 1. Not Supported
654         /// 2. Invalid State
655         /// 3. Invalid parameter
656         /// </exception>
657         /// <precondition>
658         /// The State should be Ready
659         /// </precondition>
660         public static void GetResult(RecognitionResultDelegate resultDelegate)
661         {
662             s_resultCb = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
663             {
664                 VoiceCommandList list = new VoiceCommandList(new SafeCommandListHandle(cmdList));
665                 string resultStr = Marshal.PtrToStringAnsi(result);
666                 resultDelegate(evt, list, resultStr);
667             };
668             ErrorCode error = VcGetResult(s_resultCb, IntPtr.Zero);
669             if (error != ErrorCode.None)
670             {
671                 Log.Error(LogTag, "GetResult Failed with error " + error);
672                 throw ExceptionFactory.CreateException(error);
673             }
674         }
675
676         /// <summary>
677         /// Event to be invoked when the recognition is done.
678         /// </summary>
679         /// <precondition>
680         /// The State should be Initialized
681         /// </precondition>
682         public static event EventHandler<RecognitionResultEventArgs> RecognitionResult
683         {
684             add
685             {
686                 s_resultDelegate = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
687                 {
688                     Log.Info(LogTag, "Recognition Result Event Triggered");
689                     if ((cmdList != null) && (result != null))
690                     {
691                         RecognitionResultEventArgs args = new RecognitionResultEventArgs(evt, cmdList, result);
692                         _recognitionResult?.Invoke(null, args);
693                     }
694                     else
695                     {
696                         Log.Info(LogTag, "Recognition Result Event null received");
697                     }
698                 };
699                 ErrorCode error = VcSetResultCb(s_resultDelegate, IntPtr.Zero);
700                 if (error != ErrorCode.None)
701                 {
702                     Log.Error(LogTag, "Add RecognitionResult Failed with error " + error);
703                 }
704                 else
705                 {
706                     _recognitionResult += value;
707                 }
708             }
709
710             remove
711             {
712                 ErrorCode error = VcUnsetResultCb();
713                 if (error != ErrorCode.None)
714                 {
715                     Log.Error(LogTag, "Remove RecognitionResult Failed with error " + error);
716                 }
717
718                 _recognitionResult -= value;
719             }
720         }
721
722         /// <summary>
723         /// Event to be invoked when VoiceControl service state changes.
724         /// </summary>
725         /// <precondition>
726         /// The State should be Initialized
727         /// </precondition>
728         public static event EventHandler<ServiceStateChangedEventArgs> ServiceStateChanged
729         {
730             add
731             {
732                 s_serviceStateDelegate = (ServiceState previous, ServiceState current, IntPtr userData) =>
733                 {
734                     ServiceStateChangedEventArgs args = new ServiceStateChangedEventArgs(previous, current);
735                     _serviceStateChanged?.Invoke(null, args);
736                 };
737                 ErrorCode error = VcSetServiceStateChangedCb(s_serviceStateDelegate, IntPtr.Zero);
738                 if (error != ErrorCode.None)
739                 {
740                     Log.Error(LogTag, "Add ServiceStateChanged Failed with error " + error);
741                 }
742                 else
743                 {
744                     _serviceStateChanged += value;
745                 }
746             }
747
748             remove
749             {
750                 ErrorCode error = VcUnsetServiceStateChangedCb();
751                 if (error != ErrorCode.None)
752                 {
753                     Log.Error(LogTag, "Remove ServiceStateChanged Failed with error " + error);
754                 }
755
756                 _serviceStateChanged -= value;
757             }
758         }
759
760         /// <summary>
761         /// Event to be invoked when VoiceControl client state changes.
762         /// </summary>
763         /// <precondition>
764         /// The State should be Initialized
765         /// </precondition>
766         public static event EventHandler<StateChangedEventArgs> StateChanged
767         {
768             add
769             {
770                 s_stateDelegate = (State previous, State current, IntPtr userData) =>
771                 {
772                     StateChangedEventArgs args = new StateChangedEventArgs(previous, current);
773                     _stateChanged?.Invoke(null, args);
774                 };
775                 ErrorCode error = VcSetStateChangedCb(s_stateDelegate, IntPtr.Zero);
776                 if (error != ErrorCode.None)
777                 {
778                     Log.Error(LogTag, "Add StateChanged Failed with error " + error);
779                 }
780                 else
781                 {
782                     _stateChanged += value;
783                 }
784             }
785
786             remove
787             {
788                 ErrorCode error = VcUnsetStateChangedCb();
789                 if (error != ErrorCode.None)
790                 {
791                     Log.Error(LogTag, "Remove StateChanged Failed with error " + error);
792                 }
793
794                 _stateChanged -= value;
795             }
796         }
797
798         /// <summary>
799         /// Event to be invoked when an error occurs.
800         /// </summary>
801         /// <precondition>
802         /// The State should be Initialized
803         /// </precondition>
804         public static event EventHandler<ErrorOccuredEventArgs> ErrorOccured
805         {
806             add
807             {
808                 s_errorDelegate = (ErrorCode reason, IntPtr userData) =>
809             {
810                 ErrorOccuredEventArgs args = new ErrorOccuredEventArgs(reason);
811                 _errorOccured?.Invoke(null, args);
812             };
813                 ErrorCode error = VcSetErrorCb(s_errorDelegate, IntPtr.Zero);
814                 if (error != ErrorCode.None)
815                 {
816                     Log.Error(LogTag, "Add ErrorOccured Failed with error " + error);
817                 }
818
819                 else
820                 {
821                     _errorOccured += value;
822                 }
823             }
824
825
826             remove
827             {
828                 ErrorCode error = VcUnsetErrorCb();
829                 if (error != ErrorCode.None)
830                 {
831                     Log.Error(LogTag, "Remove ErrorOccured Failed with error " + error);
832                 }
833
834                 _errorOccured -= value;
835             }
836         }
837
838         /// <summary>
839         /// Event to be invoked when default laungage change.
840         /// </summary>
841         /// <precondition>
842         /// The State should be Initialized
843         /// </precondition>
844         public static event EventHandler<CurrentLanguageChangedEventArgs> CurrentLanguageChanged
845         {
846             add
847             {
848                 s_languageDelegate = (IntPtr previousLanguage, IntPtr currentLanguage, IntPtr userData) =>
849             {
850                 string previousLanguageString = Marshal.PtrToStringAnsi(previousLanguage);
851                 string currentLanguageString = Marshal.PtrToStringAnsi(currentLanguage);
852                 CurrentLanguageChangedEventArgs args = new CurrentLanguageChangedEventArgs(previousLanguageString, currentLanguageString);
853                 _currentLanguageChanged?.Invoke(null, args);
854             };
855                 ErrorCode error = VcSetCurrentLanguageChangedCb(s_languageDelegate, IntPtr.Zero);
856                 if (error != ErrorCode.None)
857                 {
858                     Log.Error(LogTag, "Add CurrentLanguageChanged Failed with error " + error);
859                 }
860
861                 else
862                 {
863                     _currentLanguageChanged += value;
864                 }
865             }
866
867             remove
868             {
869                 ErrorCode error = VcUnsetCurrentLanguageChangedCb();
870                 if (error != ErrorCode.None)
871                 {
872                     Log.Error(LogTag, "Remove CurrentLanguageChanged Failed with error " + error);
873                 }
874
875                 _currentLanguageChanged -= value;
876             }
877         }
878     }
879 }