[Applications.AppControl] Add new internal APIs (#4877)
[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         public string Uri
298         {
299             get
300             {
301                 if (String.IsNullOrEmpty(_uri))
302                 {
303                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetUri(_handle, out _uri);
304                     if (err != Interop.AppControl.ErrorCode.None)
305                     {
306                         Log.Warn(LogTag, "Failed to get the uri from the appcontrol. Err = " + err);
307                     }
308                 }
309                 return _uri;
310             }
311             set
312             {
313                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetUri(_handle, value);
314                 if (err == Interop.AppControl.ErrorCode.None)
315                 {
316                     _uri = value;
317                 }
318                 else
319                 {
320                     Log.Warn(LogTag, "Failed to set the uri to the appcontrol. Err = " + err);
321                 }
322             }
323         }
324
325         /// <summary>
326         /// Gets and sets the explicit category.
327         /// </summary>
328         /// <value>
329         /// (if the category is null for setter, it clears the previous value.)
330         /// </value>
331         /// <since_tizen> 3 </since_tizen>
332         public string Category
333         {
334             get
335             {
336                 if (String.IsNullOrEmpty(_category))
337                 {
338                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetCategory(_handle, out _category);
339                     if (err != Interop.AppControl.ErrorCode.None)
340                     {
341                         Log.Warn(LogTag, "Failed to get the category from the appcontrol. Err = " + err);
342                     }
343                 }
344                 return _category;
345             }
346             set
347             {
348                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetCategory(_handle, value);
349                 if (err == Interop.AppControl.ErrorCode.None)
350                 {
351                     _category = value;
352                 }
353                 else
354                 {
355                     Log.Warn(LogTag, "Failed to set the category to the appcontrol. Err = " + err);
356                 }
357             }
358         }
359
360         /// <summary>
361         /// Gets and sets the application ID to explicitly launch.
362         /// </summary>
363         /// <value>
364         /// (if the application ID is null for setter, it clears the previous value.)
365         /// </value>
366         /// <example>
367         /// <code>
368         /// AppControl appControl = new AppControl();
369         /// appControl.ApplicationId = "org.tizen.calculator";
370         /// Log.Debug(LogTag, "ApplicationId: " + appControl.ApplicationId);
371         /// </code>
372         /// </example>
373         /// <since_tizen> 3 </since_tizen>
374         public string ApplicationId
375         {
376             get
377             {
378                 if (String.IsNullOrEmpty(_applicationId))
379                 {
380                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetAppId(_handle, out _applicationId);
381                     if (err != Interop.AppControl.ErrorCode.None)
382                     {
383                         Log.Warn(LogTag, "Failed to get the application id from the AppControl. Err = " + err);
384                     }
385                 }
386                 return _applicationId;
387             }
388             set
389             {
390                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetAppId(_handle, value);
391                 if (err == Interop.AppControl.ErrorCode.None)
392                 {
393                     _applicationId = value;
394                 }
395                 else
396                 {
397                     Log.Warn(LogTag, "Failed to set the application id to the AppControl. Err = " + err);
398                 }
399             }
400         }
401
402         /// <summary>
403         /// Gets and sets the launch mode of the application.
404         /// </summary>
405         /// <value>
406         /// Although, LaunchMode were set as AppControlLaunchMode.Group, the
407         /// callee application would be launched as a single mode
408         /// if the manifest file of callee application defined the launch mode as "single".
409         /// This property can just set the preference of the caller application to launch an application.
410         /// Sub-applications, which were launched as a group mode always have own process.
411         /// Since Tizen 3.0, if launch mode is not set in the caller application control,
412         /// this property returns the AppControlLaunchMode.Single launch mode.
413         /// </value>
414         /// <example>
415         /// <code>
416         /// AppControl appControl = new AppControl();
417         /// appControl.LaunchMode = AppControlLaunchMode.Group;
418         /// </code>
419         /// </example>
420         /// <since_tizen> 3 </since_tizen>
421         public AppControlLaunchMode LaunchMode
422         {
423             get
424             {
425                 int value = 0;
426                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetLaunchMode(_handle, out value);
427                 if (err != Interop.AppControl.ErrorCode.None)
428                 {
429                     Log.Warn(LogTag, "Failed to get the LaunchMode from the AppControl. Err = " + err);
430                 }
431                 return (AppControlLaunchMode)value;
432             }
433             set
434             {
435                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetLaunchMode(_handle, (int)value);
436                 if (err != Interop.AppControl.ErrorCode.None)
437                 {
438                     Log.Warn(LogTag, "Failed to set the LaunchMode to the AppControl. Err = " + err);
439                 }
440             }
441         }
442
443         /// <summary>
444         /// Gets the collection of the extra data.
445         /// </summary>
446         /// <value>
447         /// Extra data for communication between AppControls.
448         /// </value>
449         /// <example>
450         /// <code>
451         /// AppControl appControl = new AppControl();
452         /// appControl.ExtraData.Add("key", "value");
453         /// ...
454         /// </code>
455         /// </example>
456         /// <since_tizen> 3 </since_tizen>
457         public ExtraDataCollection ExtraData
458         {
459             get
460             {
461                 if (_extraData == null)
462                     _extraData = new ExtraDataCollection(_handle);
463                 return _extraData;
464             }
465         }
466
467         /// <summary>
468         /// Gets and sets the component ID to explicitly launch a component.
469         /// </summary>
470         /// <value>
471         /// (if the component ID is null for setter, it clears the previous value.)
472         /// From Tizen 5.5, a new application model is supported that is component-based application.
473         /// This property is for launching component-based application. If it's not set, the main component of component-based application will be launched.
474         /// If the target app is not component-based application, setting property is meaningless.
475         /// </value>
476         /// <example>
477         /// <code>
478         /// AppControl appControl = new AppControl();
479         /// appControl.ApplicationId = "org.tizen.component-based-app"; // component-based application
480         /// appControl.ComponentId = "org.tizen.frame-component";
481         /// AppControl.SendLaunchRequest(appControl);
482         /// </code>
483         /// </example>
484         /// <since_tizen> 6 </since_tizen>
485         public string ComponentId
486         {
487             get
488             {
489                 if (String.IsNullOrEmpty(_componentId))
490                 {
491                     Interop.AppControl.ErrorCode err = Interop.AppControl.GetComponentId(_handle, out _componentId);
492                     if (err != Interop.AppControl.ErrorCode.None)
493                     {
494                         Log.Warn(LogTag, "Failed to get the component id from the AppControl. Err = " + err);
495                     }
496                 }
497                 return _componentId;
498             }
499             set
500             {
501                 Interop.AppControl.ErrorCode err = Interop.AppControl.SetComponentId(_handle, value);
502                 if (err == Interop.AppControl.ErrorCode.None)
503                 {
504                     _componentId = value;
505                 }
506                 else
507                 {
508                     Log.Warn(LogTag, "Failed to set the component id to the AppControl. Err = " + err);
509                 }
510             }
511         }
512
513 #endregion // Public Properties
514
515         /// <summary>
516         /// Retrieves all applications that can be launched to handle the given app_control request.
517         /// </summary>
518         /// <param name="control">The AppControl.</param>
519         /// <returns>ApplicationIds.</returns>
520         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid parameter.</exception>
521         /// <example>
522         /// <code>
523         /// IEnumerable&lt;string&gt; applicationIds = AppControl.GetMatchedApplicationIds(control);
524         /// if (applicationIds != null)
525         /// {
526         ///     foreach (string id in applicationIds)
527         ///     {
528         ///         // ...
529         ///     }
530         /// }
531         /// </code>
532         /// </example>
533         /// <since_tizen> 3 </since_tizen>
534         public static IEnumerable<string> GetMatchedApplicationIds(AppControl control)
535         {
536             if (control == null)
537             {
538                 throw new ArgumentNullException("control");
539             }
540
541             List<string> ids = new List<string>();
542             Interop.AppControl.AppMatchedCallback callback = (handle, applicationId, userData) =>
543             {
544                 if (applicationId == null)
545                 {
546                         return false;
547                 }
548
549                 ids.Add(applicationId);
550                 return true;
551             };
552
553             Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachAppMatched(control._handle, callback, IntPtr.Zero);
554             if (err != Interop.AppControl.ErrorCode.None)
555             {
556                     throw new InvalidOperationException("Failed to get matched application ids. err = " + err);
557             }
558
559             return ids;
560         }
561
562         /// <summary>
563         /// Sends the launch request.
564         /// </summary>
565         /// <remarks>
566         /// The operation is mandatory information for the launch request.
567         /// If the operation is not specified, AppControlOperations.Default is used by default.
568         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
569         /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
570         /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
571         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
572         /// </remarks>
573         /// <param name="launchRequest">The AppControl.</param>
574         /// <exception cref="ArgumentNullException">Thrown when failed because of a null argument.</exception>
575         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
576         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
577         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
578         /// <example>
579         /// <code>
580         /// AppControl appControl = new AppControl();
581         /// appControl.ApplicationId = "org.tizen.calculator";
582         /// AppControl.SendLaunchRequest(appControl);
583         /// </code>
584         /// </example>
585         /// <since_tizen> 3 </since_tizen>
586         public static void SendLaunchRequest(AppControl launchRequest)
587         {
588             SendLaunchRequest(launchRequest, null);
589         }
590
591         /// <summary>
592         /// Sends the launch request with setting timeout.
593         /// </summary>
594         /// <remarks>
595         /// The operation is mandatory information for the launch request.
596         /// If the operation is not specified, AppControlOperations.Default is used by default.
597         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
598         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.<br/>
599         /// It can set receiving timeout interval using timeout parameter.
600         /// If there is an error that is not related to timeout, the error is returned immediately regardless of the timeout value.
601         /// </remarks>
602         /// <param name="launchRequest">The AppControl.</param>
603         /// <param name="timeout">The timeout in milliseconds, the timeout range is 5000 to 30000.</param>
604         /// <exception cref="ArgumentNullException">Thrown when failed because of a null argument.</exception>
605         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
606         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
607         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
608         /// <example>
609         /// <code>
610         /// AppControl appControl = new AppControl();
611         /// appControl.ApplicationId = "org.tizen.calculator";
612         /// AppControl.SendLaunchRequest(appControl, 10000);
613         /// </code>
614         /// </example>
615         /// <since_tizen> 7.5 </since_tizen>
616         [EditorBrowsable(EditorBrowsableState.Never)]
617         public static void SendLaunchRequest(AppControl launchRequest, uint timeout)
618         {
619             SendLaunchRequest(launchRequest, timeout, null);
620         }
621
622         /// <summary>
623         /// Sends the launch request.
624         /// </summary>
625         /// <remarks>
626         /// The operation is mandatory information for the launch request.
627         /// If the operation is not specified, AppControlOperations.Default is used by default.
628         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
629         /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
630         /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
631         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
632         /// </remarks>
633         /// <param name="launchRequest">The AppControl.</param>
634         /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
635         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
636         /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
637         /// <exception cref="Exceptions.LaunchFailedException">Thrown when the request failed to launch the application.</exception>
638         /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
639         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
640         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
641         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
642         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
643         /// <example>
644         /// <code>
645         /// AppControl appControl = new AppControl();
646         /// appControl.ApplicationId = "org.tizen.calculator";
647         /// AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
648         ///     // ...
649         /// });
650         /// </code>
651         /// </example>
652         /// <since_tizen> 3 </since_tizen>
653         public static void SendLaunchRequest(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
654         {
655             if (launchRequest == null)
656             {
657                 throw new ArgumentNullException("launchRequest");
658             }
659
660             Interop.AppControl.ErrorCode err;
661
662             if (replyAfterLaunching != null)
663             {
664                 int id = 0;
665                 lock (s_replyCallbackMaps)
666                 {
667                     id = s_reaustId++;
668                     s_replyCallbackMaps[id] = replyAfterLaunching;
669                 }
670                 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, s_replyNativeCallback, (IntPtr)id);
671             }
672             else
673             {
674                 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, null, IntPtr.Zero);
675             }
676
677             if (err != Interop.AppControl.ErrorCode.None)
678             {
679                 switch (err)
680                 {
681                     case Interop.AppControl.ErrorCode.InvalidParameter:
682                         throw new ArgumentException("Invalid Arguments");
683                     case Interop.AppControl.ErrorCode.TimedOut:
684                         throw new TimeoutException("Timed out");
685                     case Interop.AppControl.ErrorCode.OutOfMemory:
686                         throw new Exceptions.OutOfMemoryException("Out-of-memory");
687                     case Interop.AppControl.ErrorCode.AppNotFound:
688                         throw new Exceptions.AppNotFoundException("App(" + launchRequest.ApplicationId + ") not found. Operation(" + launchRequest.Operation + ")");
689                     case Interop.AppControl.ErrorCode.LaunchRejected:
690                         throw new Exceptions.LaunchRejectedException("Launch rejected");
691                     case Interop.AppControl.ErrorCode.LaunchFailed:
692                         throw new Exceptions.LaunchFailedException("Launch failed");
693                     case Interop.AppControl.ErrorCode.PermissionDenied:
694                         throw new Exceptions.PermissionDeniedException("Permission denied");
695
696                     default:
697                         throw new Exceptions.LaunchRejectedException("Launch rejected");
698                 }
699             }
700         }
701
702         /// <summary>
703         /// Sends the launch request with setting timeout
704         /// </summary>
705         /// <remarks>
706         /// The operation is mandatory information for the launch request.
707         /// If the operation is not specified, AppControlOperations.Default is used by default.
708         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
709         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.<br/>
710         /// It can set receiving timeout interval using timeout parameter.
711         /// If there is an error that is not related to timeout, the error is returned immediately regardless of the timeout value.
712         /// </remarks>
713         /// <param name="launchRequest">The AppControl.</param>
714         /// <param name="timeout">The timeout in milliseconds, the timeout range is 5000 to 30000.</param>
715         /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
716         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
717         /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
718         /// <exception cref="Exceptions.LaunchFailedException">Thrown when the request failed to launch the application.</exception>
719         /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
720         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
721         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
722         /// <exception cref="TimeoutException">Thrown when failed because of timeout. The timeout interval is set by timeout parameter.</exception>
723         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
724         /// <example>
725         /// <code>
726         /// AppControl appControl = new AppControl();
727         /// appControl.ApplicationId = "org.tizen.calculator";
728         /// AppControl.SendLaunchRequest(appControl, 10000, (launchRequest, replyRequest, result) => {
729         ///     // ...
730         /// });
731         /// </code>
732         /// </example>
733         /// <since_tizen> 7.5 </since_tizen>
734         [EditorBrowsable(EditorBrowsableState.Never)]
735         public static void SendLaunchRequest(AppControl launchRequest, uint timeout, AppControlReplyCallback replyAfterLaunching)
736         {
737             if (launchRequest == null)
738             {
739                 throw new ArgumentNullException("launchRequest");
740             }
741
742             Interop.AppControl.ErrorCode err;
743
744             if (replyAfterLaunching != null)
745             {
746                 int id = 0;
747                 lock (s_replyCallbackMaps)
748                 {
749                     id = s_reaustId++;
750                     s_replyCallbackMaps[id] = replyAfterLaunching;
751                 }
752                 err = Interop.AppControl.SendLaunchRequestWithTimeout(launchRequest._handle, timeout, s_replyNativeCallback, (IntPtr)id);
753             }
754             else
755             {
756                 err = Interop.AppControl.SendLaunchRequestWithTimeout(launchRequest._handle, timeout, null, IntPtr.Zero);
757             }
758
759             if (err != Interop.AppControl.ErrorCode.None)
760             {
761                 switch (err)
762                 {
763                     case Interop.AppControl.ErrorCode.InvalidParameter:
764                         throw new ArgumentException("Invalid Arguments");
765                     case Interop.AppControl.ErrorCode.TimedOut:
766                         throw new TimeoutException("Timed out");
767                     case Interop.AppControl.ErrorCode.OutOfMemory:
768                         throw new Exceptions.OutOfMemoryException("Out-of-memory");
769                     case Interop.AppControl.ErrorCode.AppNotFound:
770                         throw new Exceptions.AppNotFoundException("App(" + launchRequest.ApplicationId + ") not found. Operation(" + launchRequest.Operation + ")");
771                     case Interop.AppControl.ErrorCode.LaunchRejected:
772                         throw new Exceptions.LaunchRejectedException("Launch rejected");
773                     case Interop.AppControl.ErrorCode.LaunchFailed:
774                         throw new Exceptions.LaunchFailedException("Launch failed");
775                     case Interop.AppControl.ErrorCode.PermissionDenied:
776                         throw new Exceptions.PermissionDeniedException("Permission denied");
777
778                     default:
779                         throw new Exceptions.LaunchRejectedException("Launch rejected");
780                 }
781             }
782         }
783
784         /// <summary>
785         /// Sends the terminate request to the application that is launched by AppControl.
786         /// </summary>
787         /// <remarks>
788         /// You are not allowed to terminate other general applications using this API.
789         /// This API can be used to terminate sub-applications, which were launched as a group mode by the caller application.
790         /// Once the callee application is being terminated by this API,
791         /// other applications, which were launched by the callee application as a group mode will be terminated as well.
792         /// </remarks>
793         /// <param name="terminateRequest">The AppControl.</param>
794         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
795         /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
796         /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
797         /// <example>
798         /// <code>
799         /// AppControl terminateRequest = new AppControl();
800         /// terminateRequest.ApplicationId = "org.tizen.calculator";
801         /// AppControl.SendTerminateRequest(terminateRequest);
802         /// </code>
803         /// </example>
804         /// <since_tizen> 3 </since_tizen>
805         public static void SendTerminateRequest(AppControl terminateRequest)
806         {
807             if (terminateRequest == null)
808             {
809                 throw new ArgumentNullException("terminateRequest");
810             }
811             Interop.AppControl.ErrorCode err;
812
813             err = Interop.AppControl.SendTerminateRequest(terminateRequest._handle);
814
815             if (err != Interop.AppControl.ErrorCode.None)
816             {
817                 switch (err)
818                 {
819                     case Interop.AppControl.ErrorCode.InvalidParameter:
820                         throw new ArgumentException("Invalid Arguments");
821                     case Interop.AppControl.ErrorCode.TimedOut:
822                         throw new TimeoutException("Timed out");
823                     default:
824                         throw new InvalidOperationException("Error = " + err);
825                 }
826             }
827         }
828
829         /// <summary>
830         /// Sends the launch request asynchronously.
831         /// </summary>
832         /// <remarks>
833         /// The operation is mandatory information for the launch request.
834         /// If the operation is not specified, AppControlOperations.Default is used by default.
835         /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
836         /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
837         /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
838         /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
839         /// </remarks>
840         /// <param name="launchRequest">The AppControl.</param>
841         /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
842         /// <returns>A task with the result of the launch request.</returns>
843         /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
844         /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
845         /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
846         /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
847         /// <since_tizen> 6 </since_tizen>
848         public static Task<AppControlResult> SendLaunchRequestAsync(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
849         {
850             if (launchRequest == null)
851             {
852                 throw new ArgumentNullException(nameof(launchRequest));
853             }
854
855             var task = new TaskCompletionSource<AppControlResult>();
856             Interop.AppControl.ErrorCode err;
857             int requestId = 0;
858
859             lock (s_resultNativeCallbackMaps)
860             {
861                 requestId = s_reaustId++;
862                 s_resultNativeCallbackMaps[requestId] = (handle, result, userData) =>
863                 {
864                     task.SetResult((AppControlResult)result);
865                     lock (s_resultNativeCallbackMaps)
866                     {
867                         s_resultNativeCallbackMaps.Remove((int)userData);
868                     }
869                 };
870             }
871
872             if (replyAfterLaunching != null)
873             {
874                 lock (s_replyCallbackMaps)
875                 {
876                     s_replyCallbackMaps[requestId] = replyAfterLaunching;
877                 }
878                 err = Interop.AppControl.SendLaunchRequestAsync(launchRequest.SafeAppControlHandle, s_resultNativeCallbackMaps[requestId], s_replyNativeCallback, (IntPtr)requestId);
879             }
880             else
881             {
882                 err = Interop.AppControl.SendLaunchRequestAsync(launchRequest.SafeAppControlHandle, s_resultNativeCallbackMaps[requestId], null, (IntPtr)requestId);
883             }
884
885             if (err != Interop.AppControl.ErrorCode.None)
886             {
887                 switch (err)
888                 {
889                     case Interop.AppControl.ErrorCode.InvalidParameter:
890                         throw new ArgumentException("Invalid Arguments");
891                     case Interop.AppControl.ErrorCode.AppNotFound:
892                         throw new Exceptions.AppNotFoundException("App(" + launchRequest.ApplicationId + ") not found. Operation(" + launchRequest.Operation + ")");
893                     case Interop.AppControl.ErrorCode.LaunchRejected:
894                         throw new Exceptions.LaunchRejectedException("Launch rejected");
895                     case Interop.AppControl.ErrorCode.PermissionDenied:
896                         throw new Exceptions.PermissionDeniedException("Permission denied");
897
898                     default:
899                         throw new Exceptions.LaunchRejectedException("Launch rejected");
900                 }
901             }
902
903             return task.Task;
904         }
905
906         /// <summary>
907         /// Sets the auto restart.
908         /// </summary>
909         /// <remarks>
910         /// The functionality of this method only applies to the caller application.
911         /// The auto restart cannot be applied to other applications. The application ID set in the AppControl is ignored.
912         /// This method is only available for platform level signed applications.
913         /// </remarks>
914         /// <param name="appControl">The AppControl.</param>
915         /// <exception cref="ArgumentNullException">Thrown when the argument is null.</exception>
916         /// <exception cref="ArgumentException">Thrown when the argument is invalid.</exception>
917         /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
918         /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
919         /// <exception cref="InvalidOperationException">Thrown when the memory is insufficient.</exception>
920         [EditorBrowsable(EditorBrowsableState.Never)]
921         public static void SetAutoRestart(AppControl appControl)
922         {
923             if (appControl == null)
924             {
925                 throw new ArgumentNullException(nameof(appControl));
926             }
927
928             Interop.AppControl.ErrorCode err = Interop.AppControl.SetAutoRestart(appControl.SafeAppControlHandle);
929             if (err != Interop.AppControl.ErrorCode.None)
930             {
931                 switch (err)
932                 {
933                     case Interop.AppControl.ErrorCode.InvalidParameter:
934                         throw new ArgumentException("Invalid arguments");
935                     case Interop.AppControl.ErrorCode.PermissionDenied:
936                         throw new Exceptions.PermissionDeniedException("Permission denied");
937                     case Interop.AppControl.ErrorCode.OutOfMemory:
938                         throw new Exceptions.OutOfMemoryException("Out of memory");
939                     default:
940                         throw new InvalidOperationException("err = " + err);
941                 }
942             }
943         }
944
945         /// <summary>
946         /// Class for extra data.
947         /// </summary>
948         /// <since_tizen> 3 </since_tizen>
949         public class ExtraDataCollection
950         {
951             private readonly SafeAppControlHandle _handle;
952
953             internal ExtraDataCollection(SafeAppControlHandle handle)
954             {
955                 _handle = handle;
956             }
957
958             /// <summary>
959             /// Adds extra data.
960             /// </summary>
961             /// <remarks>
962             /// The function replaces any existing value for the given key.
963             /// </remarks>
964             /// <param name="key">The name of the extra data.</param>
965             /// <param name="value">The value associated with the given key.</param>
966             /// <exception cref="ArgumentNullException">Thrown when a key or a value is a zero-length string.</exception>
967             /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
968             /// <example>
969             /// <code>
970             /// AppControl appControl = new AppControl();
971             /// appControl.ExtraData.Add("myKey", "myValue");
972             /// </code>
973             /// </example>
974             /// <since_tizen> 3 </since_tizen>
975             public void Add(string key, string value)
976             {
977                 if (string.IsNullOrEmpty(key))
978                 {
979                     throw new ArgumentNullException("key");
980                 }
981                 if (string.IsNullOrEmpty(value))
982                 {
983                     throw new ArgumentNullException("value");
984                 }
985                 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraData(_handle, key, value);
986                 if (err != Interop.AppControl.ErrorCode.None)
987                 {
988                     switch (err)
989                     {
990                         case Interop.AppControl.ErrorCode.InvalidParameter:
991                             throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
992                         case Interop.AppControl.ErrorCode.KeyRejected:
993                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
994                         default:
995                             throw new InvalidOperationException("Error = " + err);
996                     }
997                 }
998             }
999
1000             /// <summary>
1001             /// Adds extra data.
1002             /// </summary>
1003             /// <remarks>
1004             /// The function replaces any existing value for the given key.
1005             /// </remarks>
1006             /// <param name="key">The name of the extra data.</param>
1007             /// <param name="value">The value associated with the given key.</param>
1008             /// <exception cref="ArgumentNullException">Thrown when key or value is a zero-length string.</exception>
1009             /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
1010             /// <example>
1011             /// <code>
1012             /// AppControl appControl = new AppControl();
1013             /// string[] myValues = new string[] { "first", "second", "third" };
1014             /// appControl.ExtraData.Add("myKey", myValues);
1015             /// </code>
1016             /// </example>
1017             /// <since_tizen> 3 </since_tizen>
1018             public void Add(string key, IEnumerable<string> value)
1019             {
1020                 if (string.IsNullOrEmpty(key))
1021                 {
1022                     throw new ArgumentNullException("key");
1023                 }
1024                 if (value == null)
1025                 {
1026                     throw new ArgumentNullException("value");
1027                 }
1028                 string[] valueArray = value.ToArray();
1029                 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraDataArray(_handle, key, valueArray, valueArray.Length);
1030                 if (err != Interop.AppControl.ErrorCode.None)
1031                 {
1032                     switch (err)
1033                     {
1034                         case Interop.AppControl.ErrorCode.InvalidParameter:
1035                             throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
1036                         case Interop.AppControl.ErrorCode.KeyRejected:
1037                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1038                         default:
1039                             throw new InvalidOperationException("Error = " + err);
1040                     }
1041                 }
1042             }
1043
1044             /// <summary>
1045             /// Gets the extra data.
1046             /// </summary>
1047             /// <typeparam name="T">Only string and IEnumerable&lt;string&gt;</typeparam>
1048             /// <param name="key">The name of extra data.</param>
1049             /// <returns>The value associated with the given key.</returns>
1050             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1051             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1052             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1053             /// <example>
1054             /// <code>
1055             /// AppControl appControl = new AppControl();
1056             /// string myValue = appControl.ExtraData.Get&lt;string&gt;("myKey");
1057             /// </code>
1058             /// </example>
1059             /// <since_tizen> 3 </since_tizen>
1060             public T Get<T>(string key)
1061             {
1062                 object ret = Get(key);
1063                 return (T)ret;
1064             }
1065
1066             /// <summary>
1067             /// Gets the extra data.
1068             /// </summary>
1069             /// <param name="key">The name of extra data.</param>
1070             /// <returns>The value associated with the given key.</returns>
1071             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1072             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1073             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1074             /// <example>
1075             /// <code>
1076             /// AppControl appControl = new AppControl();
1077             /// string myValue = appControl.ExtraData.Get("myKey") as string;
1078             /// if (myValue != null)
1079             /// {
1080             ///     // ...
1081             /// }
1082             /// </code>
1083             /// </example>
1084             /// <since_tizen> 3 </since_tizen>
1085             public object Get(string key)
1086             {
1087                 if (IsCollection(key))
1088                 {
1089                     return GetDataCollection(key);
1090                 }
1091                 else
1092                 {
1093                     return GetData(key);
1094                 }
1095             }
1096
1097             /// <summary>
1098             /// Gets all keys in extra data.
1099             /// </summary>
1100             /// <returns>The keys in the AppControl.</returns>
1101             /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
1102             /// <example>
1103             /// <code>
1104             /// AppControl appControl = new AppControl();
1105             /// IEnumerable&lt;string&gt; keys = appControl.GetKeys();
1106             /// if (keys != null)
1107             /// {
1108             ///     foreach (string key in keys)
1109             ///     {
1110             ///         // ...
1111             ///     }
1112             /// }
1113             /// </code>
1114             /// </example>
1115             /// <since_tizen> 3 </since_tizen>
1116             public IEnumerable<string> GetKeys()
1117             {
1118                 List<string> keys = new List<string>();
1119                 Interop.AppControl.ExtraDataCallback callback = (handle, key, userData) =>
1120                 {
1121                     if (key == null)
1122                     {
1123                         return false;
1124                     }
1125
1126                     keys.Add(key);
1127                     return true;
1128                 };
1129
1130                 Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachExtraData(_handle, callback, IntPtr.Zero);
1131                 if (err != Interop.AppControl.ErrorCode.None)
1132                 {
1133                     throw new InvalidOperationException("Failed to get keys. err = " + err);
1134                 }
1135
1136                 return keys;
1137             }
1138
1139             /// <summary>
1140             /// Tries getting the extra data.
1141             /// </summary>
1142             /// <param name="key">The name of extra data.</param>
1143             /// <param name="value">The value associated with the given key.</param>
1144             /// <returns>The result whether getting the value is done.</returns>
1145             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1146             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1147             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1148             /// <example>
1149             /// <code>
1150             /// AppControl appControl = new AppControl();
1151             /// string myValue = string.Empty;
1152             /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
1153             /// if (result != null)
1154             /// {
1155             ///     // ...
1156             /// }
1157             /// </code>
1158             /// </example>
1159             /// <since_tizen> 3 </since_tizen>
1160             public bool TryGet(string key, out string value)
1161             {
1162                 if (string.IsNullOrEmpty(key))
1163                 {
1164                     throw new ArgumentNullException("key");
1165                 }
1166                 Interop.AppControl.GetExtraData(_handle, key, out value);
1167                 if (value != null)
1168                 {
1169                     return true;
1170                 }
1171                 else
1172                 {
1173                     value = default(string);
1174                     return false;
1175                 }
1176             }
1177
1178             /// <summary>
1179             /// Tries getting the extra data.
1180             /// </summary>
1181             /// <param name="key">The name of extra data.</param>
1182             /// <param name="value">The value associated with the given key.</param>
1183             /// <returns>The result whether getting the value is done.</returns>
1184             /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
1185             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1186             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1187             /// <example>
1188             /// <code>
1189             /// AppControl appControl = new AppControl();
1190             /// IEnumerable&lt;string&gt; myValue = null;
1191             /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
1192             /// if (result)
1193             /// {
1194             ///     foreach (string value in myValue)
1195             ///     {
1196             ///         // ...
1197             ///     }
1198             /// }
1199             /// </code>
1200             /// </example>
1201             /// <since_tizen> 3 </since_tizen>
1202             public bool TryGet(string key, out IEnumerable<string> value)
1203             {
1204                 if (string.IsNullOrEmpty(key))
1205                 {
1206                     throw new ArgumentNullException("key");
1207                 }
1208                 IntPtr valuePtr = IntPtr.Zero;
1209                 int len = -1;
1210                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
1211                 if (err == Interop.AppControl.ErrorCode.None && valuePtr != IntPtr.Zero)
1212                 {
1213                     List<string> stringList = new List<string>();
1214                     for (int i = 0; i < len; ++i)
1215                     {
1216                         IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
1217                         stringList.Add(Marshal.PtrToStringAnsi(charArr));
1218                         Interop.Libc.Free(charArr);
1219                     }
1220                     Interop.Libc.Free(valuePtr);
1221                     value = stringList;
1222                     return true;
1223                 }
1224                 else
1225                 {
1226                     value = default(IEnumerable<string>);
1227                     return false;
1228                 }
1229             }
1230
1231             /// <summary>
1232             /// Removes the extra data.
1233             /// </summary>
1234             /// <param name="key">The name of the extra data.</param>
1235             /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
1236             /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1237             /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1238             /// <example>
1239             /// <code>
1240             /// AppControl appControl = new AppControl();
1241             /// appControl.ExtraData.Remove("myKey");
1242             /// </code>
1243             /// </example>
1244             /// <since_tizen> 3 </since_tizen>
1245             public void Remove(string key)
1246             {
1247                 if (string.IsNullOrEmpty(key))
1248                 {
1249                     throw new ArgumentNullException("key");
1250                 }
1251                 Interop.AppControl.ErrorCode err = Interop.AppControl.RemoveExtraData(_handle, key);
1252                 if (err != Interop.AppControl.ErrorCode.None)
1253                 {
1254                     switch (err)
1255                     {
1256                         case Interop.AppControl.ErrorCode.InvalidParameter:
1257                             throw new ArgumentException("Invalid parameter: key is a zero-length string");
1258                         case Interop.AppControl.ErrorCode.KeyNotFound:
1259                             throw new KeyNotFoundException("Key is not found"); ;
1260                         case Interop.AppControl.ErrorCode.KeyRejected:
1261                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1262                         default:
1263                             throw new InvalidOperationException("Error = " + err);
1264                     }
1265                 }
1266             }
1267
1268             /// <summary>
1269             /// Counts keys in the extra data.
1270             /// </summary>
1271             /// <returns>The number of counting keys.</returns>
1272             /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
1273             /// <example>
1274             /// <code>
1275             /// AppControl appControl = new AppControl();
1276             /// int numberOfKeys = appControl.ExtraData.Count();
1277             /// </code>
1278             /// </example>
1279             /// <since_tizen> 3 </since_tizen>
1280             public int Count()
1281             {
1282                 return GetKeys().Count();
1283             }
1284
1285             /// <summary>
1286             /// Checks whether the extra data associated with the given key is of the collection data type.
1287             /// </summary>
1288             /// <param name="key">The name of the extra data.</param>
1289             /// <returns>If true, the extra data is of the array data type, otherwise false.</returns>
1290             /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
1291             /// <exception cref="InvalidOperationException">Thrown when failed to check the key.</exception>
1292             /// <example>
1293             /// <code>
1294             /// AppControl appControl = new AppControl();
1295             /// bool result = appControl.ExtraData.IsCollection("myKey");
1296             /// </code>
1297             /// </example>
1298             /// <since_tizen> 3 </since_tizen>
1299             public bool IsCollection(string key)
1300             {
1301                 if (string.IsNullOrEmpty(key))
1302                 {
1303                     throw new ArgumentNullException("key");
1304                 }
1305                 bool isArray = false;
1306                 Interop.AppControl.ErrorCode err = Interop.AppControl.IsExtraDataArray(_handle, key, out isArray);
1307                 if (err != Interop.AppControl.ErrorCode.None)
1308                 {
1309                     throw new InvalidOperationException("Error = " + err);
1310                 }
1311                 return isArray;
1312             }
1313
1314             private string GetData(string key)
1315             {
1316                 if (string.IsNullOrEmpty(key))
1317                 {
1318                     throw new ArgumentNullException("key");
1319                 }
1320                 string value = string.Empty;
1321                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraData(_handle, key, out value);
1322                 if (err != Interop.AppControl.ErrorCode.None)
1323                 {
1324                     switch (err)
1325                     {
1326                         case Interop.AppControl.ErrorCode.InvalidParameter:
1327                             throw new ArgumentException("Invalid parameter: key is a zero-length string");
1328                         case Interop.AppControl.ErrorCode.KeyNotFound:
1329                             throw new KeyNotFoundException("Key is not found"); ;
1330                         case Interop.AppControl.ErrorCode.InvalidDataType:
1331                             throw new ArgumentException("Invalid data type: value is data collection type");
1332                         case Interop.AppControl.ErrorCode.KeyRejected:
1333                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1334                         default:
1335                             throw new InvalidOperationException("Error = " + err);
1336                     }
1337                 }
1338                 return value;
1339             }
1340
1341             private IEnumerable<string> GetDataCollection(string key)
1342             {
1343                 if (string.IsNullOrEmpty(key))
1344                 {
1345                     throw new ArgumentNullException("key");
1346                 }
1347                 IntPtr valuePtr = IntPtr.Zero;
1348                 int len = -1;
1349                 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
1350                 if (err != Interop.AppControl.ErrorCode.None)
1351                 {
1352                     switch (err)
1353                     {
1354                         case Interop.AppControl.ErrorCode.InvalidParameter:
1355                             throw new ArgumentException("Invalid parameter: key is a zero-length string");
1356                         case Interop.AppControl.ErrorCode.KeyNotFound:
1357                             throw new KeyNotFoundException("Key is not found"); ;
1358                         case Interop.AppControl.ErrorCode.InvalidDataType:
1359                             throw new ArgumentException("Invalid data type: value is data collection type");
1360                         case Interop.AppControl.ErrorCode.KeyRejected:
1361                             throw new ArgumentException("Key is rejected: the key is system-defined key.");
1362                         default:
1363                             throw new InvalidOperationException("Error = " + err);
1364                     }
1365                 }
1366
1367                 List<string> valueArray = new List<string>();
1368                 if (valuePtr != IntPtr.Zero)
1369                 {
1370                     for (int i = 0; i < len; ++i)
1371                     {
1372                         IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
1373                         valueArray.Add(Marshal.PtrToStringAnsi(charArr));
1374                         Interop.Libc.Free(charArr);
1375                     }
1376                     Interop.Libc.Free(valuePtr);
1377                 }
1378                 return valueArray;
1379             }
1380         }
1381     }
1382 }