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