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