Use Marshal.FreeHGlobal() instead of Libc.Free() (#5628)
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.Common / Tizen.Applications / AppControl.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.ComponentModel;
20 using System.Linq;
21 using System.Runtime.InteropServices;
22 using System.Threading.Tasks;
23
24 namespace Tizen.Applications
25 {
26     /// <summary>
27     /// Represents the control message to exchange between applications.
28     /// </summary>
29     /// <example>
30     /// <code>
31     /// public class AppControlExample : UIApplication
32     /// {
33     ///     /// ...
34     ///     protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
35     ///     {
36     ///         AppControl appControl = new AppControl();
37     ///         appControl.ApplicationId = "org.tizen.calculator";
38     ///         AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
39     ///             // ...
40     ///         });
41     ///     }
42     /// }
43     /// </code>
44     /// </example>
45     /// <since_tizen> 3 </since_tizen>
46     public class AppControl
47     {
48         private const string LogTag = "Tizen.Applications";
49
50         private static Dictionary<int, Interop.AppControl.ResultCallback> s_resultNativeCallbackMaps = new Dictionary<int, Interop.AppControl.ResultCallback>();
51         private static Dictionary<int, AppControlReplyCallback> s_replyCallbackMaps = new Dictionary<int, AppControlReplyCallback>();
52         private static int s_reaustId = 0;
53
54         private readonly SafeAppControlHandle _handle;
55
56         private string _operation = null;
57         private string _mime = null;
58         private string _uri = null;
59         private string _category = null;
60         private string _applicationId = null;
61         private ExtraDataCollection _extraData = null;
62         private string _componentId = null;
63
64         /// <summary>
65         /// Initializes the instance of the AppControl class.
66         /// </summary>
67         /// <exception cref="InvalidOperationException">Thrown when failed to create the AppControl handle.</exception>
68         /// <since_tizen> 3 </since_tizen>
69         public AppControl()
70         {
71             Interop.AppControl.ErrorCode err = Interop.AppControl.Create(out _handle);
72             if (err != Interop.AppControl.ErrorCode.None)
73             {
74                 throw new InvalidOperationException("Failed to create the appcontrol handle. Err = " + err);
75             }
76         }
77
78         /// <summary>
79         /// Initializes the instance of the AppControl class with a parameter.
80         /// </summary>
81         /// <param name="enableAppStartedResultEvent">The flag value to receive an additional launch result event on the launch request.</param>
82         /// <exception cref="InvalidOperationException">Thrown when failed to create the AppControl handle.</exception>
83         /// <since_tizen> 3 </since_tizen>
84         public AppControl(bool enableAppStartedResultEvent)
85         {
86             Interop.AppControl.ErrorCode err = Interop.AppControl.Create(out _handle);
87             if (err != Interop.AppControl.ErrorCode.None)
88             {
89                 throw new InvalidOperationException("Failed to create the appcontrol handle. Err = " + err);
90             }
91
92             if (enableAppStartedResultEvent)
93             {
94                 err = Interop.AppControl.EnableAppStartedResultEvent(_handle);
95                 if (err != Interop.AppControl.ErrorCode.None)
96                 {
97                     throw new InvalidOperationException("Failed to set EnableAppStartedResultEvent");
98                 }
99             }
100         }
101
102         /// <summary>
103         /// Initializes the instance of the AppControl class with the SafeAppControlHandle.
104         /// </summary>
105         /// <param name="handle"></param>
106         /// <since_tizen> 3 </since_tizen>
107         public AppControl(SafeAppControlHandle handle)
108         {
109             if (handle == null)
110             {
111                 throw new ArgumentNullException(nameof(handle));
112             }
113
114             if (handle.IsInvalid)
115             {
116                 throw new ArgumentNullException(nameof(handle), "handle is invalid");
117             }
118
119             bool mustRelease = false;
120             try
121             {
122                 handle.DangerousAddRef(ref mustRelease);
123                 Interop.AppControl.ErrorCode err = Interop.AppControl.DangerousClone(out _handle, handle.DangerousGetHandle());
124                 if (err != Interop.AppControl.ErrorCode.None)
125                 {
126                     throw new InvalidOperationException("Failed to clone the appcontrol handle. Err = " + err);
127                 }
128             }
129             catch (ObjectDisposedException e)
130             {
131                 throw new ArgumentNullException(nameof(handle), e.Message);
132             }
133             finally
134             {
135                 if (mustRelease)
136                 {
137                     handle.DangerousRelease();
138                 }
139             }
140         }
141
142         private AppControl(IntPtr handle)
143         {
144             Interop.AppControl.ErrorCode err = Interop.AppControl.DangerousClone(out _handle, handle);
145             if (err != Interop.AppControl.ErrorCode.None)
146             {
147                 throw new InvalidOperationException("Failed to clone the appcontrol handle. Err = " + err);
148             }
149         }
150
151         private static Interop.AppControl.ReplyCallback s_replyNativeCallback = (launchHandle, replyHandle, result, userData) =>
152         {
153             int requestId = (int)userData;
154             lock (s_replyCallbackMaps)
155             {
156                 if (s_replyCallbackMaps.ContainsKey(requestId))
157                 {
158                     s_replyCallbackMaps[requestId](new AppControl(launchHandle), new AppControl(replyHandle), (AppControlReplyResult)result);
159                     if (result != Interop.AppControl.AppStartedStatus)
160                     {
161                         s_replyCallbackMaps.Remove(requestId);
162                     }
163                 }
164             }
165         };
166
167 #region Public Properties
168
169         /// <summary>
170         /// Gets the SafeAppControlHandle instance.
171         /// </summary>
172         /// <since_tizen> 3 </since_tizen>
173         public SafeAppControlHandle SafeAppControlHandle
174         {
175             get
176             {
177                 return _handle;
178             }
179         }
180
181         /// <summary>
182         /// Gets and sets the operation to be performed.
183         /// </summary>
184         /// <value>
185         /// The operation is the mandatory information for the launch request. If the operation is not specified,
186         /// AppControlOperations.Default is used for the launch request. If the operation is AppControlOperations.Default,
187         /// the package information is mandatory to explicitly launch the application.
188         /// (if the operation is null for setter, it clears the previous value.)
189         /// </value>
190         /// <example>
191         /// <code>
192         /// AppControl appControl = new AppControl();
193         /// appControl.Operation = AppControlOperations.Default;
194         /// Log.Debug(LogTag, "Operation: " + appControl.Operation);
195         /// </code>
196         /// </example>
197         /// <since_tizen> 3 </since_tizen>
198         public string Operation
199         {
200             get
201             {
202                 if (String.IsNullOrEmpty(_operation))
203                 {
204                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetOperation(_handle, out _operation);
205                     if (err != Interop.AppControl.ErrorCode.None)
206                     {
207                         Log.Warn(LogTag, "Failed to get the operation from the appcontrol. Err = " + err);
208                     }
209                 }
210                 return _operation;
211             }
212             set
213             {
214                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetOperation(_handle, value);
215                 if (err == Interop.AppControl.ErrorCode.None)
216                 {
217                     _operation = value;
218                 }
219                 else
220                 {
221                     Log.Warn(LogTag, "Failed to set the operation to the appcontrol. Err = " + err);
222                 }
223             }
224         }
225
226         /// <summary>
227         /// Gets and sets the explicit MIME type of the data.
228         /// </summary>
229         /// <value>
230         /// (if the mime is null for setter, it clears the previous value.)
231         /// </value>
232         /// <example>
233         /// <code>
234         /// AppControl appControl = new AppControl();
235         /// appControl.Mime = "image/jpg";
236         /// Log.Debug(LogTag, "Mime: " + appControl.Mime);
237         /// </code>
238         /// </example>
239         /// <since_tizen> 3 </since_tizen>
240         public string Mime
241         {
242             get
243             {
244                 if (String.IsNullOrEmpty(_mime))
245                 {
246                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetMime(_handle, out _mime);
247                     if (err != Interop.AppControl.ErrorCode.None)
248                     {
249                         Log.Warn(LogTag, "Failed to get the mime from the appcontrol. Err = " + err);
250                     }
251                 }
252                 return _mime;
253             }
254             set
255             {
256                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetMime(_handle, value);
257                 if (err == Interop.AppControl.ErrorCode.None)
258                 {
259                     _mime = value;
260                 }
261                 else
262                 {
263                     Log.Warn(LogTag, "Failed to set the mime to the appcontrol. Err = " + err);
264                 }
265             }
266         }
267
268         /// <summary>
269         /// Gets and sets the URI of the data.
270         /// </summary>
271         /// <value>
272         /// Since Tizen 2.4, if the parameter 'uri' is started with 'file://' and
273         /// it is a regular file in this application's data path, which can be obtained
274         /// by property DataPath in ApplicationInfo class,
275         /// it will be shared to the callee application.
276         /// Framework will grant a temporary permission to the callee application for this file and
277         /// revoke it when the callee application is terminated.
278         /// The callee application can just read it.
279         /// (if the uri is null for setter, it clears the previous value.)
280         /// </value>
281         /// <example>
282         /// <code>
283         /// public class AppControlExample : UIApplication
284         /// {
285         ///     ...
286         ///     protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
287         ///     {
288         ///         ...
289         ///         AppControl appControl = new AppControl();
290         ///         appContrl.Uri = this.ApplicationInfo.DataPath + "image.jpg";
291         ///         Log.Debug(LogTag, "Set Uri: " + appControl.Uri);
292         ///     }
293         /// }
294         /// </code>
295         /// </example>
296         /// <since_tizen> 3 </since_tizen>
297 #pragma warning disable CA1056
298         public string Uri
299 #pragma warning restore CA1056
300         {
301             get
302             {
303                 if (String.IsNullOrEmpty(_uri))
304                 {
305                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetUri(_handle, out _uri);
306                     if (err != Interop.AppControl.ErrorCode.None)
307                     {
308                         Log.Warn(LogTag, "Failed to get the uri from the appcontrol. Err = " + err);
309                     }
310                 }
311                 return _uri;
312             }
313             set
314             {
315                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetUri(_handle, value);
316                 if (err == Interop.AppControl.ErrorCode.None)
317                 {
318                     _uri = value;
319                 }
320                 else
321                 {
322                     Log.Warn(LogTag, "Failed to set the uri to the appcontrol. Err = " + err);
323                 }
324             }
325         }
326
327         /// <summary>
328         /// Gets and sets the explicit category.
329         /// </summary>
330         /// <value>
331         /// (if the category is null for setter, it clears the previous value.)
332         /// </value>
333         /// <since_tizen> 3 </since_tizen>
334         public string Category
335         {
336             get
337             {
338                 if (String.IsNullOrEmpty(_category))
339                 {
340                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetCategory(_handle, out _category);
341                     if (err != Interop.AppControl.ErrorCode.None)
342                     {
343                         Log.Warn(LogTag, "Failed to get the category from the appcontrol. Err = " + err);
344                     }
345                 }
346                 return _category;
347             }
348             set
349             {
350                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetCategory(_handle, value);
351                 if (err == Interop.AppControl.ErrorCode.None)
352                 {
353                     _category = value;
354                 }
355                 else
356                 {
357                     Log.Warn(LogTag, "Failed to set the category to the appcontrol. Err = " + err);
358                 }
359             }
360         }
361
362         /// <summary>
363         /// Gets and sets the application ID to explicitly launch.
364         /// </summary>
365         /// <value>
366         /// (if the application ID is null for setter, it clears the previous value.)
367         /// </value>
368         /// <example>
369         /// <code>
370         /// AppControl appControl = new AppControl();
371         /// appControl.ApplicationId = "org.tizen.calculator";
372         /// Log.Debug(LogTag, "ApplicationId: " + appControl.ApplicationId);
373         /// </code>
374         /// </example>
375         /// <since_tizen> 3 </since_tizen>
376         public string ApplicationId
377         {
378             get
379             {
380                 if (String.IsNullOrEmpty(_applicationId))
381                 {
382                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetAppId(_handle, out _applicationId);
383                     if (err != Interop.AppControl.ErrorCode.None)
384                     {
385                         Log.Warn(LogTag, "Failed to get the application id from the AppControl. Err = " + err);
386                     }
387                 }
388                 return _applicationId;
389             }
390             set
391             {
392                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetAppId(_handle, value);
393                 if (err == Interop.AppControl.ErrorCode.None)
394                 {
395                     _applicationId = value;
396                 }
397                 else
398                 {
399                     Log.Warn(LogTag, "Failed to set the application id to the AppControl. Err = " + err);
400                 }
401             }
402         }
403
404         /// <summary>
405         /// Gets and sets the launch mode of the application.
406         /// </summary>
407         /// <value>
408         /// Although, LaunchMode were set as AppControlLaunchMode.Group, the
409         /// callee application would be launched as a single mode
410         /// if the manifest file of callee application defined the launch mode as "single".
411         /// This property can just set the preference of the caller application to launch an application.
412         /// Sub-applications, which were launched as a group mode always have own process.
413         /// Since Tizen 3.0, if launch mode is not set in the caller application control,
414         /// this property returns the AppControlLaunchMode.Single launch mode.
415         /// </value>
416         /// <example>
417         /// <code>
418         /// AppControl appControl = new AppControl();
419         /// appControl.LaunchMode = AppControlLaunchMode.Group;
420         /// </code>
421         /// </example>
422         /// <since_tizen> 3 </since_tizen>
423         public AppControlLaunchMode LaunchMode
424         {
425             get
426             {
427                 int value = 0;
428                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetLaunchMode(_handle, out value);
429                 if (err != Interop.AppControl.ErrorCode.None)
430                 {
431                     Log.Warn(LogTag, "Failed to get the LaunchMode from the AppControl. Err = " + err);
432                 }
433                 return (AppControlLaunchMode)value;
434             }
435             set
436             {
437                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetLaunchMode(_handle, (int)value);
438                 if (err != Interop.AppControl.ErrorCode.None)
439                 {
440                     Log.Warn(LogTag, "Failed to set the LaunchMode to the AppControl. Err = " + err);
441                 }
442             }
443         }
444
445         /// <summary>
446         /// Gets the collection of the extra data.
447         /// </summary>
448         /// <value>
449         /// Extra data for communication between AppControls.
450         /// </value>
451         /// <example>
452         /// <code>
453         /// AppControl appControl = new AppControl();
454         /// appControl.ExtraData.Add("key", "value");
455         /// ...
456         /// </code>
457         /// </example>
458         /// <since_tizen> 3 </since_tizen>
459         public ExtraDataCollection ExtraData
460         {
461             get
462             {
463                 if (_extraData == null)
464                     _extraData = new ExtraDataCollection(_handle);
465                 return _extraData;
466             }
467         }
468
469         /// <summary>
470         /// Gets and sets the component ID to explicitly launch a component.
471         /// </summary>
472         /// <value>
473         /// (if the component ID is null for setter, it clears the previous value.)
474         /// From Tizen 5.5, a new application model is supported that is component-based application.
475         /// This property is for launching component-based application. If it's not set, the main component of component-based application will be launched.
476         /// If the target app is not component-based application, setting property is meaningless.
477         /// </value>
478         /// <example>
479         /// <code>
480         /// AppControl appControl = new AppControl();
481         /// appControl.ApplicationId = "org.tizen.component-based-app"; // component-based application
482         /// appControl.ComponentId = "org.tizen.frame-component";
483         /// AppControl.SendLaunchRequest(appControl);
484         /// </code>
485         /// </example>
486         /// <since_tizen> 6 </since_tizen>
487         public string ComponentId
488         {
489             get
490             {
491                 if (String.IsNullOrEmpty(_componentId))
492                 {
493                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetComponentId(_handle, out _componentId);
494                     if (err != Interop.AppControl.ErrorCode.None)
495                     {
496                         Log.Warn(LogTag, "Failed to get the component id from the AppControl. Err = " + err);
497                     }
498                 }
499                 return _componentId;
500             }
501             set
502             {
503                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetComponentId(_handle, value);
504                 if (err == Interop.AppControl.ErrorCode.None)
505                 {
506                     _componentId = value;
507                 }
508                 else
509                 {
510                     Log.Warn(LogTag, "Failed to set the component id to the AppControl. Err = " + err);
511                 }
512             }
513         }
514
515 #endregion // Public Properties
516
517         /// <summary>
518         /// Retrieves all applications that can be launched to handle the given app_control request.
519         /// </summary>
520         /// <param name="control">The AppControl.</param>
521         /// <returns>ApplicationIds.</returns>
522         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid parameter.</exception>
523         /// <example>
524         /// <code>
525         /// IEnumerable&lt;string&gt; applicationIds = AppControl.GetMatchedApplicationIds(control);
526         /// if (applicationIds != null)
527         /// {
528         ///     foreach (string id in applicationIds)
529         ///     {
530         ///         // ...
531         ///     }
532         /// }
533         /// </code>
534         /// </example>
535         /// <since_tizen> 3 </since_tizen>
536         public static IEnumerable<string> GetMatchedApplicationIds(AppControl control)
537         {
538             if (control == null)
539             {
540                 throw new ArgumentNullException(nameof(control));
541             }
542
543             List<string> ids = new List<string>();
544             Interop.AppControl.AppMatchedCallback callback = (handle, applicationId, userData) =>
545             {
546                 if (applicationId == null)
547                 {
548                         return false;
549                 }
550
551                 ids.Add(applicationId);
552                 return true;
553             };
554
555             Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachAppMatched(control._handle, callback, IntPtr.Zero);
556             if (err != Interop.AppControl.ErrorCode.None)
557             {
558                     throw new InvalidOperationException("Failed to get matched application ids. err = " + err);
559             }
560
561             return ids;
562         }
563
564         /// <summary>
565         /// Sends the launch request.
566         /// </summary>
567         /// <remarks>
568         /// The operation is mandatory information for the launch request.
569         /// If the operation is not specified, AppControlOperations.Default is used by default.
570         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
571         /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
572         /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
573         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
574         /// </remarks>
575         /// <param name="launchRequest">The AppControl.</param>
576         /// <exception cref="ArgumentNullException">Thrown when failed because of a null argument.</exception>
577         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
578         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
579         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
580         /// <example>
581         /// <code>
582         /// AppControl appControl = new AppControl();
583         /// appControl.ApplicationId = "org.tizen.calculator";
584         /// AppControl.SendLaunchRequest(appControl);
585         /// </code>
586         /// </example>
587         /// <since_tizen> 3 </since_tizen>
588         public static void SendLaunchRequest(AppControl launchRequest)
589         {
590             SendLaunchRequest(launchRequest, null);
591         }
592
593         /// <summary>
594         /// Sends the launch request with setting timeout.
595         /// </summary>
596         /// <remarks>
597         /// The operation is mandatory information for the launch request.
598         /// If the operation is not specified, AppControlOperations.Default is used by default.
599         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
600         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.<br/>
601         /// It can set receiving timeout interval using timeout parameter.
602         /// If there is an error that is not related to timeout, the error is returned immediately regardless of the timeout value.
603         /// </remarks>
604         /// <param name="launchRequest">The AppControl.</param>
605         /// <param name="timeout">The timeout in milliseconds, the timeout range is 5000 to 30000.</param>
606         /// <exception cref="ArgumentNullException">Thrown when failed because of a null argument.</exception>
607         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
608         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
609         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
610         /// <example>
611         /// <code>
612         /// AppControl appControl = new AppControl();
613         /// appControl.ApplicationId = "org.tizen.calculator";
614         /// AppControl.SendLaunchRequest(appControl, 10000);
615         /// </code>
616         /// </example>
617         /// <since_tizen> 7.5 </since_tizen>
618         [EditorBrowsable(EditorBrowsableState.Never)]
619         public static void SendLaunchRequest(AppControl launchRequest, uint timeout)
620         {
621             SendLaunchRequest(launchRequest, timeout, null);
622         }
623
624         /// <summary>
625         /// Sends the launch request.
626         /// </summary>
627         /// <remarks>
628         /// The operation is mandatory information for the launch request.
629         /// If the operation is not specified, AppControlOperations.Default is used by default.
630         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
631         /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
632         /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
633         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
634         /// </remarks>
635         /// <param name="launchRequest">The AppControl.</param>
636         /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
637         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
638         /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
639         /// <exception cref="Exceptions.LaunchFailedException">Thrown when the request failed to launch the application.</exception>
640         /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
641         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
642         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
643         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
644         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
645         /// <example>
646         /// <code>
647         /// AppControl appControl = new AppControl();
648         /// appControl.ApplicationId = "org.tizen.calculator";
649         /// AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
650         ///     // ...
651         /// });
652         /// </code>
653         /// </example>
654         /// <since_tizen> 3 </since_tizen>
655         public static void SendLaunchRequest(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
656         {
657             if (launchRequest == null)
658             {
659                 throw new ArgumentNullException(nameof(launchRequest));
660             }
661
662             Interop.AppControl.ErrorCode err;
663
664             if (replyAfterLaunching != null)
665             {
666                 int id = 0;
667                 lock (s_replyCallbackMaps)
668                 {
669                     id = s_reaustId++;
670                     s_replyCallbackMaps[id] = replyAfterLaunching;
671                 }
672                 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, s_replyNativeCallback, (IntPtr)id);
673             }
674             else
675             {
676                 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, null, IntPtr.Zero);
677             }
678
679             if (err != Interop.AppControl.ErrorCode.None)
680             {
681                 switch (err)
682                 {
683                     case Interop.AppControl.ErrorCode.InvalidParameter:
684                         throw new ArgumentException("Invalid Arguments");
685                     case Interop.AppControl.ErrorCode.TimedOut:
686                         throw new TimeoutException("Timed out");
687                     case Interop.AppControl.ErrorCode.OutOfMemory:
688                         throw new Exceptions.OutOfMemoryException("Out-of-memory");
689                     case Interop.AppControl.ErrorCode.AppNotFound:
690                         throw new Exceptions.AppNotFoundException("App(" + launchRequest.ApplicationId + ") not found. Operation(" + launchRequest.Operation + ")");
691                     case Interop.AppControl.ErrorCode.LaunchRejected:
692                         throw new Exceptions.LaunchRejectedException("Launch rejected");
693                     case Interop.AppControl.ErrorCode.LaunchFailed:
694                         throw new Exceptions.LaunchFailedException("Launch failed");
695                     case Interop.AppControl.ErrorCode.PermissionDenied:
696                         throw new Exceptions.PermissionDeniedException("Permission denied");
697
698                     default:
699                         throw new Exceptions.LaunchRejectedException("Launch rejected");
700                 }
701             }
702         }
703
704         /// <summary>
705         /// Sends the launch request with setting timeout
706         /// </summary>
707         /// <remarks>
708         /// The operation is mandatory information for the launch request.
709         /// If the operation is not specified, AppControlOperations.Default is used by default.
710         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
711         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.<br/>
712         /// It can set receiving timeout interval using timeout parameter.
713         /// If there is an error that is not related to timeout, the error is returned immediately regardless of the timeout value.
714         /// </remarks>
715         /// <param name="launchRequest">The AppControl.</param>
716         /// <param name="timeout">The timeout in milliseconds, the timeout range is 5000 to 30000.</param>
717         /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
718         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
719         /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
720         /// <exception cref="Exceptions.LaunchFailedException">Thrown when the request failed to launch the application.</exception>
721         /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
722         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
723         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
724         /// <exception cref="TimeoutException">Thrown when failed because of timeout. The timeout interval is set by timeout parameter.</exception>
725         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
726         /// <example>
727         /// <code>
728         /// AppControl appControl = new AppControl();
729         /// appControl.ApplicationId = "org.tizen.calculator";
730         /// AppControl.SendLaunchRequest(appControl, 10000, (launchRequest, replyRequest, result) => {
731         ///     // ...
732         /// });
733         /// </code>
734         /// </example>
735         /// <since_tizen> 7.5 </since_tizen>
736         [EditorBrowsable(EditorBrowsableState.Never)]
737         public static void SendLaunchRequest(AppControl launchRequest, uint timeout, AppControlReplyCallback replyAfterLaunching)
738         {
739             if (launchRequest == null)
740             {
741                 throw new ArgumentNullException(nameof(launchRequest));
742             }
743
744             Interop.AppControl.ErrorCode err;
745
746             if (replyAfterLaunching != null)
747             {
748                 int id = 0;
749                 lock (s_replyCallbackMaps)
750                 {
751                     id = s_reaustId++;
752                     s_replyCallbackMaps[id] = replyAfterLaunching;
753                 }
754                 err = Interop.AppControl.SendLaunchRequestWithTimeout(launchRequest._handle, timeout, s_replyNativeCallback, (IntPtr)id);
755             }
756             else
757             {
758                 err = Interop.AppControl.SendLaunchRequestWithTimeout(launchRequest._handle, timeout, null, IntPtr.Zero);
759             }
760
761             if (err != Interop.AppControl.ErrorCode.None)
762             {
763                 switch (err)
764                 {
765                     case Interop.AppControl.ErrorCode.InvalidParameter:
766                         throw new ArgumentException("Invalid Arguments");
767                     case Interop.AppControl.ErrorCode.TimedOut:
768                         throw new TimeoutException("Timed out");
769                     case Interop.AppControl.ErrorCode.OutOfMemory:
770                         throw new Exceptions.OutOfMemoryException("Out-of-memory");
771                     case Interop.AppControl.ErrorCode.AppNotFound:
772                         throw new Exceptions.AppNotFoundException("App(" + launchRequest.ApplicationId + ") not found. Operation(" + launchRequest.Operation + ")");
773                     case Interop.AppControl.ErrorCode.LaunchRejected:
774                         throw new Exceptions.LaunchRejectedException("Launch rejected");
775                     case Interop.AppControl.ErrorCode.LaunchFailed:
776                         throw new Exceptions.LaunchFailedException("Launch failed");
777                     case Interop.AppControl.ErrorCode.PermissionDenied:
778                         throw new Exceptions.PermissionDeniedException("Permission denied");
779
780                     default:
781                         throw new Exceptions.LaunchRejectedException("Launch rejected");
782                 }
783             }
784         }
785
786         /// <summary>
787         /// Sends the terminate request to the application that is launched by AppControl.
788         /// </summary>
789         /// <remarks>
790         /// You are not allowed to terminate other general applications using this API.
791         /// This API can be used to terminate sub-applications, which were launched as a group mode by the caller application.
792         /// Once the callee application is being terminated by this API,
793         /// other applications, which were launched by the callee application as a group mode will be terminated as well.
794         /// </remarks>
795         /// <param name="terminateRequest">The AppControl.</param>
796         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
797         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
798         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
799         /// <example>
800         /// <code>
801         /// AppControl terminateRequest = new AppControl();
802         /// terminateRequest.ApplicationId = "org.tizen.calculator";
803         /// AppControl.SendTerminateRequest(terminateRequest);
804         /// </code>
805         /// </example>
806         /// <since_tizen> 3 </since_tizen>
807         public static void SendTerminateRequest(AppControl terminateRequest)
808         {
809             if (terminateRequest == null)
810             {
811                 throw new ArgumentNullException(nameof(terminateRequest));
812             }
813             Interop.AppControl.ErrorCode err;
814
815             err = Interop.AppControl.SendTerminateRequest(terminateRequest._handle);
816
817             if (err != Interop.AppControl.ErrorCode.None)
818             {
819                 switch (err)
820                 {
821                     case Interop.AppControl.ErrorCode.InvalidParameter:
822                         throw new ArgumentException("Invalid Arguments");
823                     case Interop.AppControl.ErrorCode.TimedOut:
824                         throw new TimeoutException("Timed out");
825                     default:
826                         throw new InvalidOperationException("Error = " + err);
827                 }
828             }
829         }
830
831         /// <summary>
832         /// Sends the launch request asynchronously.
833         /// </summary>
834         /// <remarks>
835         /// The operation is mandatory information for the launch request.
836         /// If the operation is not specified, AppControlOperations.Default is used by default.
837         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
838         /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
839         /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
840         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
841         /// </remarks>
842         /// <param name="launchRequest">The AppControl.</param>
843         /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
844         /// <returns>A task with the result of the launch request.</returns>
845         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
846         /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
847         /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
848         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
849         /// <since_tizen> 6 </since_tizen>
850         public static Task<AppControlResult> SendLaunchRequestAsync(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
851         {
852             if (launchRequest == null)
853             {
854                 throw new ArgumentNullException(nameof(launchRequest));
855             }
856
857             var task = new TaskCompletionSource<AppControlResult>();
858             Interop.AppControl.ErrorCode err;
859             int requestId = 0;
860
861             lock (s_resultNativeCallbackMaps)
862             {
863                 requestId = s_reaustId++;
864                 s_resultNativeCallbackMaps[requestId] = (handle, result, userData) =>
865                 {
866                     task.SetResult((AppControlResult)result);
867                     lock (s_resultNativeCallbackMaps)
868                     {
869                         s_resultNativeCallbackMaps.Remove((int)userData);
870                     }
871                 };
872             }
873
874             if (replyAfterLaunching != null)
875             {
876                 lock (s_replyCallbackMaps)
877                 {
878                     s_replyCallbackMaps[requestId] = replyAfterLaunching;
879                 }
880                 err = Interop.AppControl.SendLaunchRequestAsync(launchRequest.SafeAppControlHandle, s_resultNativeCallbackMaps[requestId], s_replyNativeCallback, (IntPtr)requestId);
881             }
882             else
883             {
884                 err = Interop.AppControl.SendLaunchRequestAsync(launchRequest.SafeAppControlHandle, s_resultNativeCallbackMaps[requestId], null, (IntPtr)requestId);
885             }
886
887             if (err != Interop.AppControl.ErrorCode.None)
888             {
889                 switch (err)
890                 {
891                     case Interop.AppControl.ErrorCode.InvalidParameter:
892                         throw new ArgumentException("Invalid Arguments");
893                     case Interop.AppControl.ErrorCode.AppNotFound:
894                         throw new Exceptions.AppNotFoundException("App(" + launchRequest.ApplicationId + ") not found. Operation(" + launchRequest.Operation + ")");
895                     case Interop.AppControl.ErrorCode.LaunchRejected:
896                         throw new Exceptions.LaunchRejectedException("Launch rejected");
897                     case Interop.AppControl.ErrorCode.PermissionDenied:
898                         throw new Exceptions.PermissionDeniedException("Permission denied");
899
900                     default:
901                         throw new Exceptions.LaunchRejectedException("Launch rejected");
902                 }
903             }
904
905             return task.Task;
906         }
907
908         /// <summary>
909         /// Sets the auto restart.
910         /// </summary>
911         /// <remarks>
912         /// The functionality of this method only applies to the caller application.
913         /// The auto restart cannot be applied to other applications. The application ID set in the AppControl is ignored.
914         /// This method is only available for platform level signed applications.
915         /// </remarks>
916         /// <param name="appControl">The AppControl.</param>
917         /// <exception cref="ArgumentNullException">Thrown when the argument is null.</exception>
918         /// <exception cref="ArgumentException">Thrown when the argument is invalid.</exception>
919         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
920         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
921         /// <exception cref="InvalidOperationException">Thrown when the memory is insufficient.</exception>
922         [EditorBrowsable(EditorBrowsableState.Never)]
923         public static void SetAutoRestart(AppControl appControl)
924         {
925             if (appControl == null)
926             {
927                 throw new ArgumentNullException(nameof(appControl));
928             }
929
930             Interop.AppControl.ErrorCode err = Interop.AppControl.SetAutoRestart(appControl.SafeAppControlHandle);
931             if (err != Interop.AppControl.ErrorCode.None)
932             {
933                 switch (err)
934                 {
935                     case Interop.AppControl.ErrorCode.InvalidParameter:
936                         throw new ArgumentException("Invalid arguments");
937                     case Interop.AppControl.ErrorCode.PermissionDenied:
938                         throw new Exceptions.PermissionDeniedException("Permission denied");
939                     case Interop.AppControl.ErrorCode.OutOfMemory:
940                         throw new Exceptions.OutOfMemoryException("Out of memory");
941                     default:
942                         throw new InvalidOperationException("err = " + err);
943                 }
944             }
945         }
946
947         /// <summary>
948         /// Unsets the auto restart.
949         /// </summary>
950         /// <remarks>
951         /// The functionality of this method only applies to the caller application.
952         /// This method is only available for platform level signed applications.
953         /// </remarks>
954         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
955         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
956         /// <exception cref="InvalidOperationException">Thrown when the memory is insufficient.</exception>
957         [EditorBrowsable(EditorBrowsableState.Never)]
958         public static void UnsetAutoRestart()
959         {
960             Interop.AppControl.ErrorCode err = Interop.AppControl.UnsetAutoRestart();
961             if (err != Interop.AppControl.ErrorCode.None)
962             {
963                 switch (err)
964                 {
965                     case Interop.AppControl.ErrorCode.PermissionDenied:
966                         throw new Exceptions.PermissionDeniedException("Permission denied");
967                     case Interop.AppControl.ErrorCode.OutOfMemory:
968                         throw new Exceptions.OutOfMemoryException("Out of memory");
969                     default:
970                         throw new InvalidOperationException("err = " + err);
971                 }
972             }
973         }
974
975         /// <summary>
976         /// Gets all default applications.
977         /// </summary>
978         /// <returns>ApplicationIds.</returns>
979         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
980         /// <example>
981         /// <code>
982         /// IEnumerable&lt;string&gt; applicationIds = AppControl.GetDefaultApplicationIds();
983         /// if (applicationIds != null)
984         /// {
985         ///     foreach (string id in applicationIds)
986         ///     {
987         ///         // ...
988         ///     }
989         /// }
990         /// </code>
991         /// </example>
992         /// <since_tizen> 11 </since_tizen>
993         [EditorBrowsable(EditorBrowsableState.Never)]
994         public static IEnumerable<string> GetDefaultApplicationIds()
995         {
996             List<string> ids = new List<string>();
997             Interop.AppControl.DefaultApplicationCallback callback = (applicationId, userData) =>
998             {
999                 if (applicationId == null)
1000                 {
1001                     return false;
1002                 }
1003
1004                 ids.Add(applicationId);
1005                 return true;
1006             };
1007
1008             Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachDefaultApplication(callback, IntPtr.Zero);
1009             if (err != Interop.AppControl.ErrorCode.None)
1010             {
1011                 throw new InvalidOperationException("Failed to get default application Ids. err = " + err);
1012             }
1013
1014             return ids;
1015         }
1016
1017         /// <summary>
1018         /// Sets the window position.
1019         /// </summary>
1020         /// <param name="windowPosition">The window position object.</param>
1021         /// <exception cref="ArgumentNullException">Thrown when the argument is null.</exception>
1022         /// <exception cref="ArgumentException">Thrown when the argument is invalid.</exception>
1023         /// <exception cref="InvalidOperationException">Thrown when the invalid operation error occurs.</exception>
1024         /// <since_tizen> 11 </since_tizen>
1025         public void SetWindowPosition(WindowPosition windowPosition)
1026         {
1027             if (windowPosition == null)
1028             {
1029                 throw new ArgumentNullException(nameof(windowPosition));
1030             }
1031
1032             Interop.AppControl.ErrorCode err = Interop.AppControl.SetWindowPosition(this.SafeAppControlHandle, windowPosition.PositionX, windowPosition.PositionY, windowPosition.Width, windowPosition.Height);
1033             if (err != Interop.AppControl.ErrorCode.None)
1034             {
1035                 if (err == Interop.AppControl.ErrorCode.InvalidParameter)
1036                 {
1037                     throw new ArgumentException("Invalid arguments");
1038                 }
1039                 else
1040                 {
1041                     throw new InvalidOperationException("err = " + err);
1042                 }
1043             }
1044         }
1045
1046         /// <summary>
1047         /// Gets the window position.
1048         /// </summary>
1049         /// <returns>The window position.</returns>
1050         /// <exception cref="InvalidOperationException">Thrown when the invalid operation error occurs.</exception>
1051         /// <since_tizen> 11 </since_tizen>
1052         public WindowPosition GetWindowPosition()
1053         {
1054             Interop.AppControl.ErrorCode err = Interop.AppControl.GetWindowPosition(this.SafeAppControlHandle, out int x, out int y, out int w, out int h);
1055             if (err != Interop.AppControl.ErrorCode.None)
1056             {
1057                 throw new InvalidOperationException("err = " + err);
1058             }
1059
1060             return new WindowPosition(x, y, w, h);
1061         }
1062
1063         /// <summary>
1064         /// Class for extra data.
1065         /// </summary>
1066         /// <since_tizen> 3 </since_tizen>
1067 #pragma warning disable CA1034
1068         public class ExtraDataCollection
1069 #pragma warning restore CA1034
1070         {
1071             private readonly SafeAppControlHandle _handle;
1072
1073             internal ExtraDataCollection(SafeAppControlHandle handle)
1074             {
1075                 _handle = handle;
1076             }
1077
1078             /// <summary>
1079             /// Adds extra data.
1080             /// </summary>
1081             /// <remarks>
1082             /// The function replaces any existing value for the given key.
1083             /// </remarks>
1084             /// <param name="key">The name of the extra data.</param>
1085             /// <param name="value">The value associated with the given key.</param>
1086             /// <exception cref="ArgumentNullException">Thrown when a key or a value is a zero-length string.</exception>
1087             /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
1088             /// <example>
1089             /// <code>
1090             /// AppControl appControl = new AppControl();
1091             /// appControl.ExtraData.Add("myKey", "myValue");
1092             /// </code>
1093             /// </example>
1094             /// <since_tizen> 3 </since_tizen>
1095             public void Add(string key, string value)
1096             {
1097                 if (string.IsNullOrEmpty(key))
1098                 {
1099                     throw new ArgumentNullException(nameof(key));
1100                 }
1101                 if (string.IsNullOrEmpty(value))
1102                 {
1103                     throw new ArgumentNullException(nameof(value));
1104                 }
1105                 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraData(_handle, key, value);
1106                 if (err != Interop.AppControl.ErrorCode.None)
1107                 {
1108                     switch (err)
1109                     {
1110                         case Interop.AppControl.ErrorCode.InvalidParameter:
1111                             throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
1112                         case Interop.AppControl.ErrorCode.KeyRejected:
1113                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1114                         default:
1115                             throw new InvalidOperationException("Error = " + err);
1116                     }
1117                 }
1118             }
1119
1120             /// <summary>
1121             /// Adds extra data.
1122             /// </summary>
1123             /// <remarks>
1124             /// The function replaces any existing value for the given key.
1125             /// </remarks>
1126             /// <param name="key">The name of the extra data.</param>
1127             /// <param name="value">The value associated with the given key.</param>
1128             /// <exception cref="ArgumentNullException">Thrown when key or value is a zero-length string.</exception>
1129             /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
1130             /// <example>
1131             /// <code>
1132             /// AppControl appControl = new AppControl();
1133             /// string[] myValues = new string[] { "first", "second", "third" };
1134             /// appControl.ExtraData.Add("myKey", myValues);
1135             /// </code>
1136             /// </example>
1137             /// <since_tizen> 3 </since_tizen>
1138             public void Add(string key, IEnumerable<string> value)
1139             {
1140                 if (string.IsNullOrEmpty(key))
1141                 {
1142                     throw new ArgumentNullException(nameof(key));
1143                 }
1144                 if (value == null)
1145                 {
1146                     throw new ArgumentNullException(nameof(value));
1147                 }
1148                 string[] valueArray = value.ToArray();
1149                 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraDataArray(_handle, key, valueArray, valueArray.Length);
1150                 if (err != Interop.AppControl.ErrorCode.None)
1151                 {
1152                     switch (err)
1153                     {
1154                         case Interop.AppControl.ErrorCode.InvalidParameter:
1155                             throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
1156                         case Interop.AppControl.ErrorCode.KeyRejected:
1157                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1158                         default:
1159                             throw new InvalidOperationException("Error = " + err);
1160                     }
1161                 }
1162             }
1163
1164             /// <summary>
1165             /// Gets the extra data.
1166             /// </summary>
1167             /// <typeparam name="T">Only string and IEnumerable&lt;string&gt;</typeparam>
1168             /// <param name="key">The name of extra data.</param>
1169             /// <returns>The value associated with the given key.</returns>
1170             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1171             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1172             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1173             /// <example>
1174             /// <code>
1175             /// AppControl appControl = new AppControl();
1176             /// string myValue = appControl.ExtraData.Get&lt;string&gt;("myKey");
1177             /// </code>
1178             /// </example>
1179             /// <since_tizen> 3 </since_tizen>
1180             public T Get<T>(string key)
1181             {
1182                 object ret = Get(key);
1183                 return (T)ret;
1184             }
1185
1186             /// <summary>
1187             /// Gets the extra data.
1188             /// </summary>
1189             /// <param name="key">The name of extra data.</param>
1190             /// <returns>The value associated with the given key.</returns>
1191             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1192             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1193             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1194             /// <example>
1195             /// <code>
1196             /// AppControl appControl = new AppControl();
1197             /// string myValue = appControl.ExtraData.Get("myKey") as string;
1198             /// if (myValue != null)
1199             /// {
1200             ///     // ...
1201             /// }
1202             /// </code>
1203             /// </example>
1204             /// <since_tizen> 3 </since_tizen>
1205             public object Get(string key)
1206             {
1207                 if (IsCollection(key))
1208                 {
1209                     return GetDataCollection(key);
1210                 }
1211                 else
1212                 {
1213                     return GetData(key);
1214                 }
1215             }
1216
1217             /// <summary>
1218             /// Gets all keys in extra data.
1219             /// </summary>
1220             /// <returns>The keys in the AppControl.</returns>
1221             /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
1222             /// <example>
1223             /// <code>
1224             /// AppControl appControl = new AppControl();
1225             /// IEnumerable&lt;string&gt; keys = appControl.GetKeys();
1226             /// if (keys != null)
1227             /// {
1228             ///     foreach (string key in keys)
1229             ///     {
1230             ///         // ...
1231             ///     }
1232             /// }
1233             /// </code>
1234             /// </example>
1235             /// <since_tizen> 3 </since_tizen>
1236             public IEnumerable<string> GetKeys()
1237             {
1238                 List<string> keys = new List<string>();
1239                 Interop.AppControl.ExtraDataCallback callback = (handle, key, userData) =>
1240                 {
1241                     if (key == null)
1242                     {
1243                         return false;
1244                     }
1245
1246                     keys.Add(key);
1247                     return true;
1248                 };
1249
1250                 Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachExtraData(_handle, callback, IntPtr.Zero);
1251                 if (err != Interop.AppControl.ErrorCode.None)
1252                 {
1253                     throw new InvalidOperationException("Failed to get keys. err = " + err);
1254                 }
1255
1256                 return keys;
1257             }
1258
1259             /// <summary>
1260             /// Tries getting the extra data.
1261             /// </summary>
1262             /// <param name="key">The name of extra data.</param>
1263             /// <param name="value">The value associated with the given key.</param>
1264             /// <returns>The result whether getting the value is done.</returns>
1265             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1266             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1267             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1268             /// <example>
1269             /// <code>
1270             /// AppControl appControl = new AppControl();
1271             /// string myValue = string.Empty;
1272             /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
1273             /// if (result != null)
1274             /// {
1275             ///     // ...
1276             /// }
1277             /// </code>
1278             /// </example>
1279             /// <since_tizen> 3 </since_tizen>
1280             public bool TryGet(string key, out string value)
1281             {
1282                 if (string.IsNullOrEmpty(key))
1283                 {
1284                     throw new ArgumentNullException(nameof(key));
1285                 }
1286                 Interop.AppControl.GetExtraData(_handle, key, out value);
1287                 if (value != null)
1288                 {
1289                     return true;
1290                 }
1291                 else
1292                 {
1293                     value = default(string);
1294                     return false;
1295                 }
1296             }
1297
1298             /// <summary>
1299             /// Tries getting the extra data.
1300             /// </summary>
1301             /// <param name="key">The name of extra data.</param>
1302             /// <param name="value">The value associated with the given key.</param>
1303             /// <returns>The result whether getting the value is done.</returns>
1304             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1305             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1306             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1307             /// <example>
1308             /// <code>
1309             /// AppControl appControl = new AppControl();
1310             /// IEnumerable&lt;string&gt; myValue = null;
1311             /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
1312             /// if (result)
1313             /// {
1314             ///     foreach (string value in myValue)
1315             ///     {
1316             ///         // ...
1317             ///     }
1318             /// }
1319             /// </code>
1320             /// </example>
1321             /// <since_tizen> 3 </since_tizen>
1322             public bool TryGet(string key, out IEnumerable<string> value)
1323             {
1324                 if (string.IsNullOrEmpty(key))
1325                 {
1326                     throw new ArgumentNullException(nameof(key));
1327                 }
1328                 IntPtr valuePtr = IntPtr.Zero;
1329                 int len = -1;
1330                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
1331                 if (err == Interop.AppControl.ErrorCode.None && valuePtr != IntPtr.Zero)
1332                 {
1333                     List<string> stringList = new List<string>();
1334                     for (int i = 0; i < len; ++i)
1335                     {
1336                         IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
1337                         stringList.Add(Marshal.PtrToStringAnsi(charArr));
1338                         Marshal.FreeHGlobal(charArr);
1339                     }
1340                     Marshal.FreeHGlobal(valuePtr);
1341                     value = stringList;
1342                     return true;
1343                 }
1344                 else
1345                 {
1346                     value = default(IEnumerable<string>);
1347                     return false;
1348                 }
1349             }
1350
1351             /// <summary>
1352             /// Removes the extra data.
1353             /// </summary>
1354             /// <param name="key">The name of the extra data.</param>
1355             /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
1356             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1357             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1358             /// <example>
1359             /// <code>
1360             /// AppControl appControl = new AppControl();
1361             /// appControl.ExtraData.Remove("myKey");
1362             /// </code>
1363             /// </example>
1364             /// <since_tizen> 3 </since_tizen>
1365             public void Remove(string key)
1366             {
1367                 if (string.IsNullOrEmpty(key))
1368                 {
1369                     throw new ArgumentNullException(nameof(key));
1370                 }
1371                 Interop.AppControl.ErrorCode err = Interop.AppControl.RemoveExtraData(_handle, key);
1372                 if (err != Interop.AppControl.ErrorCode.None)
1373                 {
1374                     switch (err)
1375                     {
1376                         case Interop.AppControl.ErrorCode.InvalidParameter:
1377                             throw new ArgumentException("Invalid parameter: key is a zero-length string");
1378                         case Interop.AppControl.ErrorCode.KeyNotFound:
1379                             throw new KeyNotFoundException("Key is not found"); ;
1380                         case Interop.AppControl.ErrorCode.KeyRejected:
1381                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1382                         default:
1383                             throw new InvalidOperationException("Error = " + err);
1384                     }
1385                 }
1386             }
1387
1388             /// <summary>
1389             /// Counts keys in the extra data.
1390             /// </summary>
1391             /// <returns>The number of counting keys.</returns>
1392             /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
1393             /// <example>
1394             /// <code>
1395             /// AppControl appControl = new AppControl();
1396             /// int numberOfKeys = appControl.ExtraData.Count();
1397             /// </code>
1398             /// </example>
1399             /// <since_tizen> 3 </since_tizen>
1400             public int Count()
1401             {
1402                 return GetKeys().Count();
1403             }
1404
1405             /// <summary>
1406             /// Checks whether the extra data associated with the given key is of the collection data type.
1407             /// </summary>
1408             /// <param name="key">The name of the extra data.</param>
1409             /// <returns>If true, the extra data is of the array data type, otherwise false.</returns>
1410             /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
1411             /// <exception cref="InvalidOperationException">Thrown when failed to check the key.</exception>
1412             /// <example>
1413             /// <code>
1414             /// AppControl appControl = new AppControl();
1415             /// bool result = appControl.ExtraData.IsCollection("myKey");
1416             /// </code>
1417             /// </example>
1418             /// <since_tizen> 3 </since_tizen>
1419             public bool IsCollection(string key)
1420             {
1421                 if (string.IsNullOrEmpty(key))
1422                 {
1423                     throw new ArgumentNullException(nameof(key));
1424                 }
1425                 bool isArray = false;
1426                 Interop.AppControl.ErrorCode err = Interop.AppControl.IsExtraDataArray(_handle, key, out isArray);
1427                 if (err != Interop.AppControl.ErrorCode.None)
1428                 {
1429                     throw new InvalidOperationException("Error = " + err);
1430                 }
1431                 return isArray;
1432             }
1433
1434             private string GetData(string key)
1435             {
1436                 if (string.IsNullOrEmpty(key))
1437                 {
1438                     throw new ArgumentNullException(nameof(key));
1439                 }
1440                 string value = string.Empty;
1441                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraData(_handle, key, out value);
1442                 if (err != Interop.AppControl.ErrorCode.None)
1443                 {
1444                     switch (err)
1445                     {
1446                         case Interop.AppControl.ErrorCode.InvalidParameter:
1447                             throw new ArgumentException("Invalid parameter: key is a zero-length string");
1448                         case Interop.AppControl.ErrorCode.KeyNotFound:
1449                             throw new KeyNotFoundException("Key is not found"); ;
1450                         case Interop.AppControl.ErrorCode.InvalidDataType:
1451                             throw new ArgumentException("Invalid data type: value is data collection type");
1452                         case Interop.AppControl.ErrorCode.KeyRejected:
1453                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1454                         default:
1455                             throw new InvalidOperationException("Error = " + err);
1456                     }
1457                 }
1458                 return value;
1459             }
1460
1461             private IEnumerable<string> GetDataCollection(string key)
1462             {
1463                 if (string.IsNullOrEmpty(key))
1464                 {
1465                     throw new ArgumentNullException(nameof(key));
1466                 }
1467                 IntPtr valuePtr = IntPtr.Zero;
1468                 int len = -1;
1469                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
1470                 if (err != Interop.AppControl.ErrorCode.None)
1471                 {
1472                     switch (err)
1473                     {
1474                         case Interop.AppControl.ErrorCode.InvalidParameter:
1475                             throw new ArgumentException("Invalid parameter: key is a zero-length string");
1476                         case Interop.AppControl.ErrorCode.KeyNotFound:
1477                             throw new KeyNotFoundException("Key is not found"); ;
1478                         case Interop.AppControl.ErrorCode.InvalidDataType:
1479                             throw new ArgumentException("Invalid data type: value is data collection type");
1480                         case Interop.AppControl.ErrorCode.KeyRejected:
1481                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1482                         default:
1483                             throw new InvalidOperationException("Error = " + err);
1484                     }
1485                 }
1486
1487                 List<string> valueArray = new List<string>();
1488                 if (valuePtr != IntPtr.Zero)
1489                 {
1490                     for (int i = 0; i < len; ++i)
1491                     {
1492                         IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
1493                         valueArray.Add(Marshal.PtrToStringAnsi(charArr));
1494                         Marshal.FreeHGlobal(charArr);
1495                     }
1496                     Marshal.FreeHGlobal(valuePtr);
1497                 }
1498                 return valueArray;
1499             }
1500         }
1501     }
1502 }