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