2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Collections.Generic;
20 using System.Runtime.InteropServices;
21 using System.Threading.Tasks;
23 namespace Tizen.Applications
26 /// Represents the control message to exchange between applications.
30 /// public class AppControlExample : UIApplication
33 /// protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
35 /// AppControl appControl = new AppControl();
36 /// appControl.ApplicationId = "org.tizen.calculator";
37 /// AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
44 /// <since_tizen> 3 </since_tizen>
45 public class AppControl
47 private const string LogTag = "Tizen.Applications";
49 private static Dictionary<int, Interop.AppControl.ResultCallback> s_resultNativeCallbackMaps = new Dictionary<int, Interop.AppControl.ResultCallback>();
50 private static Dictionary<int, AppControlReplyCallback> s_replyCallbackMaps = new Dictionary<int, AppControlReplyCallback>();
51 private static int s_reaustId = 0;
53 private readonly SafeAppControlHandle _handle;
55 private string _operation = null;
56 private string _mime = null;
57 private string _uri = null;
58 private string _category = null;
59 private string _applicationId = null;
60 private ExtraDataCollection _extraData = null;
63 /// Initializes the instance of the AppControl class.
65 /// <exception cref="InvalidOperationException">Thrown when failed to create the AppControl handle.</exception>
66 /// <since_tizen> 3 </since_tizen>
69 Interop.AppControl.ErrorCode err = Interop.AppControl.Create(out _handle);
70 if (err != Interop.AppControl.ErrorCode.None)
72 throw new InvalidOperationException("Failed to create the appcontrol handle. Err = " + err);
77 /// Initializes the instance of the AppControl class with a parameter.
79 /// <param name="enableAppStartedResultEvent">The flag value to receive an additional launch result event on the launch request.</param>
80 /// <exception cref="InvalidOperationException">Thrown when failed to create the AppControl handle.</exception>
81 /// <since_tizen> 3 </since_tizen>
82 public AppControl(bool enableAppStartedResultEvent)
84 Interop.AppControl.ErrorCode err = Interop.AppControl.Create(out _handle);
85 if (err != Interop.AppControl.ErrorCode.None)
87 throw new InvalidOperationException("Failed to create the appcontrol handle. Err = " + err);
90 if (enableAppStartedResultEvent)
92 err = Interop.AppControl.EnableAppStartedResultEvent(_handle);
93 if (err != Interop.AppControl.ErrorCode.None)
95 throw new InvalidOperationException("Failed to set EnableAppStartedResultEvent");
101 /// Initializes the instance of the AppControl class with the SafeAppControlHandle.
103 /// <param name="handle"></param>
104 /// <since_tizen> 3 </since_tizen>
105 public AppControl(SafeAppControlHandle handle)
109 throw new ArgumentNullException("handle");
112 Interop.AppControl.ErrorCode err = Interop.AppControl.DangerousClone(out _handle, handle.DangerousGetHandle());
113 if (err != Interop.AppControl.ErrorCode.None)
115 throw new InvalidOperationException("Failed to clone the appcontrol handle. Err = " + err);
119 private AppControl(IntPtr handle)
121 Interop.AppControl.ErrorCode err = Interop.AppControl.DangerousClone(out _handle, handle);
122 if (err != Interop.AppControl.ErrorCode.None)
124 throw new InvalidOperationException("Failed to clone the appcontrol handle. Err = " + err);
128 private static Interop.AppControl.ReplyCallback s_replyNativeCallback = (launchHandle, replyHandle, result, userData) =>
130 int requestId = (int)userData;
131 lock (s_replyCallbackMaps)
133 if (s_replyCallbackMaps.ContainsKey(requestId))
135 s_replyCallbackMaps[requestId](new AppControl(launchHandle), new AppControl(replyHandle), (AppControlReplyResult)result);
136 if (result != Interop.AppControl.AppStartedStatus)
138 lock (s_replyCallbackMaps)
140 s_replyCallbackMaps.Remove(requestId);
147 #region Public Properties
150 /// Gets the SafeAppControlHandle instance.
152 /// <since_tizen> 3 </since_tizen>
153 public SafeAppControlHandle SafeAppControlHandle
162 /// Gets and sets the operation to be performed.
165 /// The operation is the mandatory information for the launch request. If the operation is not specified,
166 /// AppControlOperations.Default is used for the launch request. If the operation is AppControlOperations.Default,
167 /// the package information is mandatory to explicitly launch the application.
168 /// (if the operation is null for setter, it clears the previous value.)
172 /// AppControl appControl = new AppControl();
173 /// appControl.Operation = AppControlOperations.Default;
174 /// Log.Debug(LogTag, "Operation: " + appControl.Operation);
177 /// <since_tizen> 3 </since_tizen>
178 public string Operation
182 if (String.IsNullOrEmpty(_operation))
184 Interop.AppControl.ErrorCode err = Interop.AppControl.GetOperation(_handle, out _operation);
185 if (err != Interop.AppControl.ErrorCode.None)
187 Log.Warn(LogTag, "Failed to get the operation from the appcontrol. Err = " + err);
194 Interop.AppControl.ErrorCode err = Interop.AppControl.SetOperation(_handle, value);
195 if (err == Interop.AppControl.ErrorCode.None)
201 Log.Warn(LogTag, "Failed to set the operation to the appcontrol. Err = " + err);
207 /// Gets and sets the explicit MIME type of the data.
210 /// (if the mime is null for setter, it clears the previous value.)
214 /// AppControl appControl = new AppControl();
215 /// appControl.Mime = "image/jpg";
216 /// Log.Debug(LogTag, "Mime: " + appControl.Mime);
219 /// <since_tizen> 3 </since_tizen>
224 if (String.IsNullOrEmpty(_mime))
226 Interop.AppControl.ErrorCode err = Interop.AppControl.GetMime(_handle, out _mime);
227 if (err != Interop.AppControl.ErrorCode.None)
229 Log.Warn(LogTag, "Failed to get the mime from the appcontrol. Err = " + err);
236 Interop.AppControl.ErrorCode err = Interop.AppControl.SetMime(_handle, value);
237 if (err == Interop.AppControl.ErrorCode.None)
243 Log.Warn(LogTag, "Failed to set the mime to the appcontrol. Err = " + err);
249 /// Gets and sets the URI of the data.
252 /// Since Tizen 2.4, if the parameter 'uri' is started with 'file://' and
253 /// it is a regular file in this application's data path, which can be obtained
254 /// by property DataPath in ApplicationInfo class,
255 /// it will be shared to the callee application.
256 /// Framework will grant a temporary permission to the callee application for this file and
257 /// revoke it when the callee application is terminated.
258 /// The callee application can just read it.
259 /// (if the uri is null for setter, it clears the previous value.)
263 /// public class AppControlExample : UIApplication
266 /// protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
269 /// AppControl appControl = new AppControl();
270 /// appContrl.Uri = this.ApplicationInfo.DataPath + "image.jpg";
271 /// Log.Debug(LogTag, "Set Uri: " + appControl.Uri);
276 /// <since_tizen> 3 </since_tizen>
281 if (String.IsNullOrEmpty(_uri))
283 Interop.AppControl.ErrorCode err = Interop.AppControl.GetUri(_handle, out _uri);
284 if (err != Interop.AppControl.ErrorCode.None)
286 Log.Warn(LogTag, "Failed to get the uri from the appcontrol. Err = " + err);
293 Interop.AppControl.ErrorCode err = Interop.AppControl.SetUri(_handle, value);
294 if (err == Interop.AppControl.ErrorCode.None)
300 Log.Warn(LogTag, "Failed to set the uri to the appcontrol. Err = " + err);
306 /// Gets and sets the explicit category.
309 /// (if the category is null for setter, it clears the previous value.)
311 /// <since_tizen> 3 </since_tizen>
312 public string Category
316 if (String.IsNullOrEmpty(_category))
318 Interop.AppControl.ErrorCode err = Interop.AppControl.GetCategory(_handle, out _category);
319 if (err != Interop.AppControl.ErrorCode.None)
321 Log.Warn(LogTag, "Failed to get the category from the appcontrol. Err = " + err);
328 Interop.AppControl.ErrorCode err = Interop.AppControl.SetCategory(_handle, value);
329 if (err == Interop.AppControl.ErrorCode.None)
335 Log.Warn(LogTag, "Failed to set the category to the appcontrol. Err = " + err);
341 /// Gets and sets the application ID to explicitly launch.
344 /// (if the application ID is null for setter, it clears the previous value.)
348 /// AppControl appControl = new AppControl();
349 /// appControl.ApplicationId = "org.tizen.calculator";
350 /// Log.Debug(LogTag, "ApplicationId: " + appControl.ApplicationId);
353 /// <since_tizen> 3 </since_tizen>
354 public string ApplicationId
358 if (String.IsNullOrEmpty(_applicationId))
360 Interop.AppControl.ErrorCode err = Interop.AppControl.GetAppId(_handle, out _applicationId);
361 if (err != Interop.AppControl.ErrorCode.None)
363 Log.Warn(LogTag, "Failed to get the application id from the AppControl. Err = " + err);
366 return _applicationId;
370 Interop.AppControl.ErrorCode err = Interop.AppControl.SetAppId(_handle, value);
371 if (err == Interop.AppControl.ErrorCode.None)
373 _applicationId = value;
377 Log.Warn(LogTag, "Failed to set the application id to the AppControl. Err = " + err);
383 /// Gets and sets the launch mode of the application.
386 /// Although, LaunchMode were set as AppControlLaunchMode.Group, the
387 /// callee application would be launched as a single mode
388 /// if the manifest file of callee application defined the launch mode as "single".
389 /// This property can just set the preference of the caller application to launch an application.
390 /// Sub-applications, which were launched as a group mode always have own process.
391 /// Since Tizen 3.0, if launch mode is not set in the caller application control,
392 /// this property returns the AppControlLaunchMode.Single launch mode.
396 /// AppControl appControl = new AppControl();
397 /// appControl.LaunchMode = AppControlLaunchMode.Group;
400 /// <since_tizen> 3 </since_tizen>
401 public AppControlLaunchMode LaunchMode
406 Interop.AppControl.ErrorCode err = Interop.AppControl.GetLaunchMode(_handle, out value);
407 if (err != Interop.AppControl.ErrorCode.None)
409 Log.Warn(LogTag, "Failed to get the LaunchMode from the AppControl. Err = " + err);
411 return (AppControlLaunchMode)value;
415 Interop.AppControl.ErrorCode err = Interop.AppControl.SetLaunchMode(_handle, (int)value);
416 if (err != Interop.AppControl.ErrorCode.None)
418 Log.Warn(LogTag, "Failed to set the LaunchMode to the AppControl. Err = " + err);
424 /// Gets the collection of the extra data.
427 /// Extra data for communication between AppControls.
431 /// AppControl appControl = new AppControl();
432 /// appControl.ExtraData.Add("key", "value");
436 /// <since_tizen> 3 </since_tizen>
437 public ExtraDataCollection ExtraData
441 if (_extraData == null)
442 _extraData = new ExtraDataCollection(_handle);
447 #endregion // Public Properties
450 /// Retrieves all applications that can be launched to handle the given app_control request.
452 /// <param name="control">The AppControl.</param>
453 /// <returns>ApplicationIds.</returns>
454 /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid parameter.</exception>
457 /// IEnumerable<string> applicationIds = AppControl.GetMatchedApplicationIds(control);
458 /// if (applicationIds != null)
460 /// foreach (string id in applicationIds)
467 /// <since_tizen> 3 </since_tizen>
468 public static IEnumerable<string> GetMatchedApplicationIds(AppControl control)
472 throw new ArgumentNullException("control");
475 List<string> ids = new List<string>();
476 Interop.AppControl.AppMatchedCallback callback = (handle, applicationId, userData) =>
478 if (applicationId == null)
483 ids.Add(applicationId);
487 Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachAppMatched(control._handle, callback, IntPtr.Zero);
488 if (err != Interop.AppControl.ErrorCode.None)
490 throw new InvalidOperationException("Failed to get matched application ids. err = " + err);
497 /// Sends the launch request.
500 /// The operation is mandatory information for the launch request.
501 /// If the operation is not specified, AppControlOperations.Default is used by default.
502 /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
503 /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
504 /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
505 /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
507 /// <param name="launchRequest">The AppControl.</param>
508 /// <exception cref="ArgumentNullException">Thrown when failed because of a null argument.</exception>
509 /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
510 /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
511 /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
514 /// AppControl appControl = new AppControl();
515 /// appControl.ApplicationId = "org.tizen.calculator";
516 /// AppControl.SendLaunchRequest(appControl);
519 /// <since_tizen> 3 </since_tizen>
520 public static void SendLaunchRequest(AppControl launchRequest)
522 SendLaunchRequest(launchRequest, null);
526 /// Sends the launch request.
529 /// The operation is mandatory information for the launch request.
530 /// If the operation is not specified, AppControlOperations.Default is used by default.
531 /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
532 /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
533 /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
534 /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
536 /// <param name="launchRequest">The AppControl.</param>
537 /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
538 /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
539 /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
540 /// <exception cref="Exceptions.LaunchFailedException">Thrown when the request failed to launch the application.</exception>
541 /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
542 /// <exception cref="Exceptions.OutOfMemoryException">Thrown when the memory is insufficient.</exception>
543 /// <exception cref="Exceptions.PermissionDeniedException">Thrown when the permission is denied.</exception>
544 /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
545 /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
548 /// AppControl appControl = new AppControl();
549 /// appControl.ApplicationId = "org.tizen.calculator";
550 /// AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) => {
555 /// <since_tizen> 3 </since_tizen>
556 public static void SendLaunchRequest(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
558 if (launchRequest == null)
560 throw new ArgumentNullException("launchRequest");
563 Interop.AppControl.ErrorCode err;
565 if (replyAfterLaunching != null)
568 lock (s_replyCallbackMaps)
571 s_replyCallbackMaps[id] = replyAfterLaunching;
573 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, s_replyNativeCallback, (IntPtr)id);
577 err = Interop.AppControl.SendLaunchRequest(launchRequest._handle, null, IntPtr.Zero);
580 if (err != Interop.AppControl.ErrorCode.None)
584 case Interop.AppControl.ErrorCode.InvalidParameter:
585 throw new ArgumentException("Invalid Arguments");
586 case Interop.AppControl.ErrorCode.TimedOut:
587 throw new TimeoutException("Timed out");
588 case Interop.AppControl.ErrorCode.OutOfMemory:
589 throw new Exceptions.OutOfMemoryException("Out-of-memory");
590 case Interop.AppControl.ErrorCode.AppNotFound:
591 throw new Exceptions.AppNotFoundException("App not found");
592 case Interop.AppControl.ErrorCode.LaunchRejected:
593 throw new Exceptions.LaunchRejectedException("Launch rejected");
594 case Interop.AppControl.ErrorCode.LaunchFailed:
595 throw new Exceptions.LaunchFailedException("Launch failed");
596 case Interop.AppControl.ErrorCode.PermissionDenied:
597 throw new Exceptions.PermissionDeniedException("Permission denied");
600 throw new Exceptions.LaunchRejectedException("Launch rejected");
606 /// Sends the terminate request to the application that is launched by AppControl.
609 /// You are not allowed to terminate other general applications using this API.
610 /// This API can be used to terminate sub-applications, which were launched as a group mode by the caller application.
611 /// Once the callee application is being terminated by this API,
612 /// other applications, which were launched by the callee application as a group mode will be terminated as well.
614 /// <param name="terminateRequest">The AppControl.</param>
615 /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
616 /// <exception cref="InvalidOperationException">Thrown when failed because of an invalid operation.</exception>
617 /// <exception cref="TimeoutException">Thrown when failed because of timeout.</exception>
620 /// AppControl terminateRequest = new AppControl();
621 /// terminateRequest.ApplicationId = "org.tizen.calculator";
622 /// AppControl.SendTerminateRequest(terminateRequest);
625 /// <since_tizen> 3 </since_tizen>
626 public static void SendTerminateRequest(AppControl terminateRequest)
628 if (terminateRequest == null)
630 throw new ArgumentNullException("terminateRequest");
632 Interop.AppControl.ErrorCode err;
634 err = Interop.AppControl.SendTerminateRequest(terminateRequest._handle);
636 if (err != Interop.AppControl.ErrorCode.None)
640 case Interop.AppControl.ErrorCode.InvalidParameter:
641 throw new ArgumentException("Invalid Arguments");
642 case Interop.AppControl.ErrorCode.TimedOut:
643 throw new TimeoutException("Timed out");
645 throw new InvalidOperationException("Error = " + err);
651 /// Sends the launch request asynchronously.
654 /// The operation is mandatory information for the launch request.
655 /// If the operation is not specified, AppControlOperations.Default is used by default.
656 /// If the operation is AppControlOperations.Default, the application ID is mandatory to explicitly launch the application.<br/>
657 /// Since Tizen 2.4, the launch request of the service application over out of packages is restricted by the platform.
658 /// Also, implicit launch requests are NOT delivered to service applications since 2.4.
659 /// To launch a service application, an explicit launch request with the application ID given by property ApplicationId MUST be sent.
661 /// <param name="launchRequest">The AppControl.</param>
662 /// <param name="replyAfterLaunching">The callback function to be called when the reply is delivered.</param>
663 /// <returns>A task with the result of the launch request.</returns>
664 /// <exception cref="ArgumentException">Thrown when failed because of the argument is invalid.</exception>
665 /// <exception cref="Exceptions.AppNotFoundException">Thrown when the application to run is not found.</exception>
666 /// <exception cref="Exceptions.LaunchRejectedException">Thrown when the launch request is rejected.</exception>
667 /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
668 /// <since_tizen> 6 </since_tizen>
669 public static Task<AppControlResult> SendLaunchRequestAsync(AppControl launchRequest, AppControlReplyCallback replyAfterLaunching)
671 if (launchRequest == null)
673 throw new ArgumentNullException(nameof(launchRequest));
676 var task = new TaskCompletionSource<AppControlResult>();
677 Interop.AppControl.ErrorCode err;
680 lock (s_resultNativeCallbackMaps)
682 requestId = s_reaustId++;
683 s_resultNativeCallbackMaps[requestId] = (handle, result, userData) =>
685 task.SetResult((AppControlResult)result);
686 lock (s_resultNativeCallbackMaps)
688 s_resultNativeCallbackMaps.Remove((int)userData);
693 if (replyAfterLaunching != null)
695 lock (s_replyCallbackMaps)
697 s_replyCallbackMaps[requestId] = replyAfterLaunching;
699 err = Interop.AppControl.SendLaunchRequestAsync(launchRequest.SafeAppControlHandle, s_resultNativeCallbackMaps[requestId], s_replyNativeCallback, (IntPtr)requestId);
703 err = Interop.AppControl.SendLaunchRequestAsync(launchRequest.SafeAppControlHandle, s_resultNativeCallbackMaps[requestId], null, (IntPtr)requestId);
706 if (err != Interop.AppControl.ErrorCode.None)
710 case Interop.AppControl.ErrorCode.InvalidParameter:
711 throw new ArgumentException("Invalid Arguments");
712 case Interop.AppControl.ErrorCode.AppNotFound:
713 throw new Exceptions.AppNotFoundException("App not found");
714 case Interop.AppControl.ErrorCode.LaunchRejected:
715 throw new Exceptions.LaunchRejectedException("Launch rejected");
716 case Interop.AppControl.ErrorCode.PermissionDenied:
717 throw new Exceptions.PermissionDeniedException("Permission denied");
720 throw new Exceptions.LaunchRejectedException("Launch rejected");
728 /// Class for extra data.
730 /// <since_tizen> 3 </since_tizen>
731 public class ExtraDataCollection
733 private readonly SafeAppControlHandle _handle;
735 internal ExtraDataCollection(SafeAppControlHandle handle)
744 /// The function replaces any existing value for the given key.
746 /// <param name="key">The name of the extra data.</param>
747 /// <param name="value">The value associated with the given key.</param>
748 /// <exception cref="ArgumentNullException">Thrown when a key or a value is a zero-length string.</exception>
749 /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
752 /// AppControl appControl = new AppControl();
753 /// appControl.ExtraData.Add("myKey", "myValue");
756 /// <since_tizen> 3 </since_tizen>
757 public void Add(string key, string value)
759 if (string.IsNullOrEmpty(key))
761 throw new ArgumentNullException("key");
763 if (string.IsNullOrEmpty(value))
765 throw new ArgumentNullException("value");
767 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraData(_handle, key, value);
768 if (err != Interop.AppControl.ErrorCode.None)
772 case Interop.AppControl.ErrorCode.InvalidParameter:
773 throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
774 case Interop.AppControl.ErrorCode.KeyRejected:
775 throw new ArgumentException("Key is rejected: the key is system-defined key.");
777 throw new InvalidOperationException("Error = " + err);
786 /// The function replaces any existing value for the given key.
788 /// <param name="key">The name of the extra data.</param>
789 /// <param name="value">The value associated with the given key.</param>
790 /// <exception cref="ArgumentNullException">Thrown when key or value is a zero-length string.</exception>
791 /// <exception cref="ArgumentException">Thrown when the application tries to use the same key with the system-defined key.</exception>
794 /// AppControl appControl = new AppControl();
795 /// string[] myValues = new string[] { "first", "second", "third" };
796 /// appControl.ExtraData.Add("myKey", myValues);
799 /// <since_tizen> 3 </since_tizen>
800 public void Add(string key, IEnumerable<string> value)
802 if (string.IsNullOrEmpty(key))
804 throw new ArgumentNullException("key");
808 throw new ArgumentNullException("value");
810 string[] valueArray = value.ToArray();
811 Interop.AppControl.ErrorCode err = Interop.AppControl.AddExtraDataArray(_handle, key, valueArray, valueArray.Length);
812 if (err != Interop.AppControl.ErrorCode.None)
816 case Interop.AppControl.ErrorCode.InvalidParameter:
817 throw new ArgumentException("Invalid parameter: key or value is a zero-length string");
818 case Interop.AppControl.ErrorCode.KeyRejected:
819 throw new ArgumentException("Key is rejected: the key is system-defined key.");
821 throw new InvalidOperationException("Error = " + err);
827 /// Gets the extra data.
829 /// <typeparam name="T">Only string and IEnumerable<string></typeparam>
830 /// <param name="key">The name of extra data.</param>
831 /// <returns>The value associated with the given key.</returns>
832 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
833 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
834 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
837 /// AppControl appControl = new AppControl();
838 /// string myValue = appControl.ExtraData.Get<string>("myKey");
841 /// <since_tizen> 3 </since_tizen>
842 public T Get<T>(string key)
844 object ret = Get(key);
849 /// Gets the extra data.
851 /// <param name="key">The name of extra data.</param>
852 /// <returns>The value associated with the given key.</returns>
853 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
854 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
855 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
858 /// AppControl appControl = new AppControl();
859 /// string myValue = appControl.ExtraData.Get("myKey") as string;
860 /// if (myValue != null)
866 /// <since_tizen> 3 </since_tizen>
867 public object Get(string key)
869 if (IsCollection(key))
871 return GetDataCollection(key);
880 /// Gets all keys in extra data.
882 /// <returns>The keys in the AppControl.</returns>
883 /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
886 /// AppControl appControl = new AppControl();
887 /// IEnumerable<string> keys = appControl.GetKeys();
888 /// if (keys != null)
890 /// foreach (string key in keys)
897 /// <since_tizen> 3 </since_tizen>
898 public IEnumerable<string> GetKeys()
900 List<string> keys = new List<string>();
901 Interop.AppControl.ExtraDataCallback callback = (handle, key, userData) =>
912 Interop.AppControl.ErrorCode err = Interop.AppControl.ForeachExtraData(_handle, callback, IntPtr.Zero);
913 if (err != Interop.AppControl.ErrorCode.None)
915 throw new InvalidOperationException("Failed to get keys. err = " + err);
922 /// Tries getting the extra data.
924 /// <param name="key">The name of extra data.</param>
925 /// <param name="value">The value associated with the given key.</param>
926 /// <returns>The result whether getting the value is done.</returns>
927 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
928 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
929 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
932 /// AppControl appControl = new AppControl();
933 /// string myValue = string.Empty;
934 /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
935 /// if (result != null)
941 /// <since_tizen> 3 </since_tizen>
942 public bool TryGet(string key, out string value)
944 if (string.IsNullOrEmpty(key))
946 throw new ArgumentNullException("key");
948 Interop.AppControl.GetExtraData(_handle, key, out value);
955 value = default(string);
961 /// Tries getting the extra data.
963 /// <param name="key">The name of extra data.</param>
964 /// <param name="value">The value associated with the given key.</param>
965 /// <returns>The result whether getting the value is done.</returns>
966 /// <exception cref="ArgumentNullException">Thrown when the key is an invalid parameter.</exception>
967 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
968 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
971 /// AppControl appControl = new AppControl();
972 /// IEnumerable<string> myValue = null;
973 /// bool result = appControl.ExtraData.TryGet("myKey", out myValue);
976 /// foreach (string value in myValue)
983 /// <since_tizen> 3 </since_tizen>
984 public bool TryGet(string key, out IEnumerable<string> value)
986 if (string.IsNullOrEmpty(key))
988 throw new ArgumentNullException("key");
990 IntPtr valuePtr = IntPtr.Zero;
992 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
993 if (err == Interop.AppControl.ErrorCode.None && valuePtr != IntPtr.Zero)
995 List<string> stringList = new List<string>();
996 for (int i = 0; i < len; ++i)
998 IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
999 stringList.Add(Marshal.PtrToStringAnsi(charArr));
1000 Interop.Libc.Free(charArr);
1002 Interop.Libc.Free(valuePtr);
1008 value = default(IEnumerable<string>);
1014 /// Removes the extra data.
1016 /// <param name="key">The name of the extra data.</param>
1017 /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
1018 /// <exception cref="KeyNotFoundException">Thrown when the key is not found.</exception>
1019 /// <exception cref="ArgumentException">Thrown when the key is rejected.</exception>
1022 /// AppControl appControl = new AppControl();
1023 /// appControl.ExtraData.Remove("myKey");
1026 /// <since_tizen> 3 </since_tizen>
1027 public void Remove(string key)
1029 if (string.IsNullOrEmpty(key))
1031 throw new ArgumentNullException("key");
1033 Interop.AppControl.ErrorCode err = Interop.AppControl.RemoveExtraData(_handle, key);
1034 if (err != Interop.AppControl.ErrorCode.None)
1038 case Interop.AppControl.ErrorCode.InvalidParameter:
1039 throw new ArgumentException("Invalid parameter: key is a zero-length string");
1040 case Interop.AppControl.ErrorCode.KeyNotFound:
1041 throw new KeyNotFoundException("Key is not found"); ;
1042 case Interop.AppControl.ErrorCode.KeyRejected:
1043 throw new ArgumentException("Key is rejected: the key is system-defined key.");
1045 throw new InvalidOperationException("Error = " + err);
1051 /// Counts keys in the extra data.
1053 /// <returns>The number of counting keys.</returns>
1054 /// <exception cref="InvalidOperationException">Thrown when the key is an invalid parameter.</exception>
1057 /// AppControl appControl = new AppControl();
1058 /// int numberOfKeys = appControl.ExtraData.Count();
1061 /// <since_tizen> 3 </since_tizen>
1064 return GetKeys().Count();
1068 /// Checks whether the extra data associated with the given key is of the collection data type.
1070 /// <param name="key">The name of the extra data.</param>
1071 /// <returns>If true, the extra data is of the array data type, otherwise false.</returns>
1072 /// <exception cref="ArgumentNullException">Thrown when the key is a zero-length string.</exception>
1073 /// <exception cref="InvalidOperationException">Thrown when failed to check the key.</exception>
1076 /// AppControl appControl = new AppControl();
1077 /// bool result = appControl.ExtraData.IsCollection("myKey");
1080 /// <since_tizen> 3 </since_tizen>
1081 public bool IsCollection(string key)
1083 if (string.IsNullOrEmpty(key))
1085 throw new ArgumentNullException("key");
1087 bool isArray = false;
1088 Interop.AppControl.ErrorCode err = Interop.AppControl.IsExtraDataArray(_handle, key, out isArray);
1089 if (err != Interop.AppControl.ErrorCode.None)
1091 throw new InvalidOperationException("Error = " + err);
1096 private string GetData(string key)
1098 if (string.IsNullOrEmpty(key))
1100 throw new ArgumentNullException("key");
1102 string value = string.Empty;
1103 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraData(_handle, key, out value);
1104 if (err != Interop.AppControl.ErrorCode.None)
1108 case Interop.AppControl.ErrorCode.InvalidParameter:
1109 throw new ArgumentException("Invalid parameter: key is a zero-length string");
1110 case Interop.AppControl.ErrorCode.KeyNotFound:
1111 throw new KeyNotFoundException("Key is not found"); ;
1112 case Interop.AppControl.ErrorCode.InvalidDataType:
1113 throw new ArgumentException("Invalid data type: value is data collection type");
1114 case Interop.AppControl.ErrorCode.KeyRejected:
1115 throw new ArgumentException("Key is rejected: the key is system-defined key.");
1117 throw new InvalidOperationException("Error = " + err);
1123 private IEnumerable<string> GetDataCollection(string key)
1125 if (string.IsNullOrEmpty(key))
1127 throw new ArgumentNullException("key");
1129 IntPtr valuePtr = IntPtr.Zero;
1131 Interop.AppControl.ErrorCode err = Interop.AppControl.GetExtraDataArray(_handle, key, out valuePtr, out len);
1132 if (err != Interop.AppControl.ErrorCode.None)
1136 case Interop.AppControl.ErrorCode.InvalidParameter:
1137 throw new ArgumentException("Invalid parameter: key is a zero-length string");
1138 case Interop.AppControl.ErrorCode.KeyNotFound:
1139 throw new KeyNotFoundException("Key is not found"); ;
1140 case Interop.AppControl.ErrorCode.InvalidDataType:
1141 throw new ArgumentException("Invalid data type: value is data collection type");
1142 case Interop.AppControl.ErrorCode.KeyRejected:
1143 throw new ArgumentException("Key is rejected: the key is system-defined key.");
1145 throw new InvalidOperationException("Error = " + err);
1149 List<string> valueArray = new List<string>();
1150 if (valuePtr != IntPtr.Zero)
1152 for (int i = 0; i < len; ++i)
1154 IntPtr charArr = Marshal.ReadIntPtr(valuePtr, IntPtr.Size * i);
1155 valueArray.Add(Marshal.PtrToStringAnsi(charArr));
1156 Interop.Libc.Free(charArr);
1158 Interop.Libc.Free(valuePtr);