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