[PrivacyPrivilegeManager] Add new API for checking & requesting multiple privileges...
authorxerrni <xerrni@users.noreply.github.com>
Fri, 16 Nov 2018 07:54:19 +0000 (08:54 +0100)
committerSeungkeun Lee <sngn.lee@samsung.com>
Fri, 16 Nov 2018 07:54:19 +0000 (16:54 +0900)
* [PrivacyPrivilegeManager] Fix ResponseContext Lifetime issue

* [PrivacyPrivilegeManager] Add new API for checking & requesting multiple privileges at once

Signed-off-by: Ernest Borowski <e.borowski@partner.samsung.com>
src/Tizen.Security.PrivacyPrivilegeManager/Interop/Interop.PrivacyPrivilegeManager.cs
src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security.PrivacyPrivilegeManager.sln
src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/PermissionRequestResponse.cs [new file with mode: 0644]
src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/PrivacyPrivilegeManager.cs
src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/RequestResponseEventArgs.cs
src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/RequestResponseMultipleEventArgs.cs [new file with mode: 0644]

index da6d21a..983636c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
@@ -53,10 +53,27 @@ internal static partial class Interop
         //[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
         internal delegate void RequestResponseCallback(CallCause cause, RequestResult result, string privilege, IntPtr userData);
 
+        //[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
+        internal delegate void RequestMultipleResponseCallback(CallCause cause,
+                                                               [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] RequestResult[] results,
+                                                               [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] string[] privileges,
+                                                               uint privilegesCount, IntPtr userData);
+
         [DllImport(Libraries.PrivacyPrivilegeManager, EntryPoint = "ppm_check_permission")]
         internal static extern ErrorCode CheckPermission(string privilege, out CheckResult result);
 
+        [DllImport(Libraries.PrivacyPrivilegeManager, EntryPoint = "ppm_check_permissions")]
+        internal static extern ErrorCode CheckPermissions([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]string[] privileges,
+                                                          uint privilegesCount,
+                                                          [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] CheckResult[] results);
+
+
         [DllImport(Libraries.PrivacyPrivilegeManager, EntryPoint = "ppm_request_permission")]
         internal static extern ErrorCode RequestPermission(string privilege, RequestResponseCallback callback, IntPtr userData);
+
+        [DllImport(Libraries.PrivacyPrivilegeManager, EntryPoint = "ppm_request_permissions")]
+        internal static extern ErrorCode RequestPermissions([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] string[] privileges,
+                                                            uint privilegesCount, RequestMultipleResponseCallback callback, IntPtr userData);
+
     }
 }
index f740e19..efc22cb 100644 (file)
@@ -1,9 +1,8 @@
-
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
 VisualStudioVersion = 15.0.26124.0
 MinimumVisualStudioVersion = 15.0.26124.0
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tizen.Security.PrivacyPrivilegeManager", "Tizen.Security.PrivacyPrivilegeManager.csproj", "{588EBECE-A11C-4837-80F3-5EDECFC17E5E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Security.PrivacyPrivilegeManager", "Tizen.Security.PrivacyPrivilegeManager.csproj", "{588EBECE-A11C-4837-80F3-5EDECFC17E5E}"
 EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -14,21 +13,24 @@ Global
                Release|x64 = Release|x64
                Release|x86 = Release|x86
        EndGlobalSection
-       GlobalSection(SolutionProperties) = preSolution
-               HideSolutionNode = FALSE
-       EndGlobalSection
        GlobalSection(ProjectConfigurationPlatforms) = postSolution
                {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x64.ActiveCfg = Debug|x64
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x64.Build.0 = Debug|x64
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x86.ActiveCfg = Debug|x86
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x86.Build.0 = Debug|x86
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x64.Build.0 = Debug|Any CPU
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Debug|x86.Build.0 = Debug|Any CPU
                {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|Any CPU.Build.0 = Release|Any CPU
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x64.ActiveCfg = Release|x64
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x64.Build.0 = Release|x64
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x86.ActiveCfg = Release|x86
-               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x86.Build.0 = Release|x86
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x64.ActiveCfg = Release|Any CPU
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x64.Build.0 = Release|Any CPU
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x86.ActiveCfg = Release|Any CPU
+               {588EBECE-A11C-4837-80F3-5EDECFC17E5E}.Release|x86.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {938329CD-8EF9-430F-A061-0AE8567C0F87}
        EndGlobalSection
 EndGlobal
diff --git a/src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/PermissionRequestResponse.cs b/src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/PermissionRequestResponse.cs
new file mode 100644 (file)
index 0000000..fa17723
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Tizen.Security
+{
+    /// <summary>
+    /// Holds information about privilege request result.
+    /// </summary>
+    public class PermissionRequestResponse
+    {
+        /// <summary>
+        /// The result of a permission request.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public RequestResult Result { get; internal set; }
+
+        /// <summary>
+        /// The privilege for which a permission was requested for.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public string Privilege { get; internal set; }
+    }
+}
index a69f60d..83de89a 100644 (file)
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+/*
+ * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
 
 using System;
 using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
 using Tizen.Internals.Errors;
 
 namespace Tizen.Security
@@ -27,22 +29,58 @@ namespace Tizen.Security
     public static class PrivacyPrivilegeManager
     {
         private const string LogTag = "Tizen.Privilege";
-        private static Interop.PrivacyPrivilegeManager.RequestResponseCallback s_requestResponseCb;
+        private static IDictionary<string, WeakReference<ResponseContext>> s_responseWeakMap = new Dictionary<string, WeakReference<ResponseContext>>();
+        private static Interop.PrivacyPrivilegeManager.RequestResponseCallback s_requestResponseCb =
+                       (Interop.PrivacyPrivilegeManager.CallCause cause, Interop.PrivacyPrivilegeManager.RequestResult result,
+                           string privilege, IntPtr userData) =>
+                        {
+                            try
+                            {
+                                if (s_responseWeakMap.TryGetValue(privilege, out WeakReference<ResponseContext> weakRef))
+                                {
+                                    if (weakRef.TryGetTarget(out ResponseContext context))
+                                    {
+                                        context.FireEvent((CallCause)cause, (RequestResult)result);
+                                    }
+                                    else
+                                    {
+                                        s_responseWeakMap.Remove(privilege);
+                                        Log.Error(LogTag, "No response context for: " + privilege);
+                                    }
+                                }
+                                else
+                                {
+                                    Log.Error(LogTag, "No listener for: " + privilege);
+                                }
+                            }
+                            catch (Exception e)
+                            {
+                                Log.Error(LogTag, "Exception in callback : " + e.Message);
+                            }
+                            s_PrivilegesInProgress.Remove(privilege);
+                        };
+
         private static IDictionary<string, ResponseContext> s_responseMap = new Dictionary<string, ResponseContext>();
+        private static HashSet<string> s_PrivilegesInProgress = new HashSet<string>();
 
-        static PrivacyPrivilegeManager()
+        private static string[] CheckPrivilegesArgument(IEnumerable<string> privileges, string methodName)
         {
-            s_requestResponseCb = (Interop.PrivacyPrivilegeManager.CallCause cause, Interop.PrivacyPrivilegeManager.RequestResult result, string privilege, IntPtr userData) =>
+            if (privileges == null || !privileges.Any())
             {
-                try
-                {
-                    s_responseMap[privilege].FireEvent((CallCause)cause, (RequestResult) result);
-                }
-                catch (Exception e)
+                Log.Error(LogTag, "privileges for " + methodName + " are null or empty.");
+                throw new ArgumentException("privileges for " + methodName + " are null or empty.");
+            }
+
+            foreach (var privilege in privileges)
+            {
+                if (string.IsNullOrEmpty(privilege))
                 {
-                    Log.Error(LogTag, "Exception in callback : " + e.Message);
+                    Log.Error(LogTag, " At least one privilege for " + methodName + " is null or empty.");
+                    throw new ArgumentException(" At least one privilege for " + methodName + " is null or empty.");
                 }
-            };
+            }
+
+            return privileges as string[] ?? privileges.ToArray();
         }
 
         /// <summary>
@@ -85,6 +123,61 @@ namespace Tizen.Security
         }
 
         /// <summary>
+        /// Gets the status of a privacy privileges permission.
+        /// </summary>
+        /// <param name="privileges">The privacy privileges to be checked.</param>
+        /// <returns>The permission setting for a respective privileges.</returns>
+        /// <exception cref="ArgumentException">Thrown when an invalid parameter is passed.</exception>
+        /// <exception cref="OutOfMemoryException">Thrown when a memory error occurred.</exception>
+        /// <exception cref="System.IO.IOException">Thrown when the method failed due to an internal I/O error.</exception>
+        /// <example>
+        /// <code>
+        ///     string[] privileges = new [] {"http://tizen.org/privilege/account.read",
+        ///                                   "http://tizen.org/privilege/alarm"};
+        ///     CheckResult[] results = PrivacyPrivilegeManager.CheckPermissions(privileges).ToArray();
+        ///     List&lt;string&gt; privilegesWithAskStatus = new List&lt;string&gt;();
+        ///     for (int iterator = 0; iterator &lt; results.Length; ++iterator)
+        ///     {
+        ///         switch (results[iterator])
+        ///         {
+        ///             case CheckResult.Allow:
+        ///                 // Privilege can be used
+        ///                 break;
+        ///             case CheckResult.Deny:
+        ///                 // Privilege can't be used
+        ///                 break;
+        ///             case CheckResult.Ask:
+        ///                 // User permission request required
+        ///                 privilegesWithAskStatus.Add(privileges[iterator]);
+        ///                 break;
+        ///         }
+        ///     }
+        ///     PrivacyPrivilegeManager.RequestPermissions(privilegesWithAskStatus);
+        /// </code>
+        /// </example>
+        /// <since_tizen> 6 </since_tizen>
+        public static IEnumerable<CheckResult> CheckPermissions(IEnumerable<string> privileges)
+        {
+            string[] privilegesArray = CheckPrivilegesArgument(privileges, "CheckPermissions");
+
+            Interop.PrivacyPrivilegeManager.CheckResult[] results = new Interop.PrivacyPrivilegeManager.CheckResult[privilegesArray.Length];
+            int ret = (int)Interop.PrivacyPrivilegeManager.CheckPermissions(privilegesArray, (uint)privilegesArray.Length, results);
+            if (ret != (int)Interop.PrivacyPrivilegeManager.ErrorCode.None)
+            {
+                Log.Error(LogTag, "Failed to check permission");
+                throw PrivacyPrivilegeManagerErrorFactory.GetException(ret);
+            }
+
+            CheckResult[] checkResults = new CheckResult[results.Length];
+            for (int iterator = 0; iterator < results.Length; ++iterator)
+            {
+                checkResults[iterator] = (CheckResult)results[iterator];
+            }
+            return checkResults;
+        }
+
+
+        /// <summary>
         /// Triggers the permission request for a user.
         /// </summary>
         /// <param name="privilege">The privacy privilege to be requested.</param>
@@ -112,15 +205,121 @@ namespace Tizen.Security
         /// <since_tizen> 4 </since_tizen>
         public static void RequestPermission(string privilege)
         {
+            if (!s_PrivilegesInProgress.Add(privilege))
+            {
+                Log.Error(LogTag, "Request for this privilege: " + privilege + " is already in progress.");
+                throw new ArgumentException("Request for this privilege: " + privilege + " is already in progress.");
+            }
+
             int ret = (int)Interop.PrivacyPrivilegeManager.RequestPermission(privilege, s_requestResponseCb, IntPtr.Zero);
             if (ret != (int)Interop.PrivacyPrivilegeManager.ErrorCode.None)
             {
                 Log.Error(LogTag, "Failed to request permission");
+                s_PrivilegesInProgress.Remove(privilege);
                 throw PrivacyPrivilegeManagerErrorFactory.GetException(ret);
             }
         }
 
         /// <summary>
+        /// Triggers the permissions request for a user.
+        /// </summary>
+        /// <param name="privileges">The privacy privileges to be requested.</param>
+        /// <exception cref="ArgumentException">Thrown when an invalid parameter is passed.</exception>
+        /// <exception cref="OutOfMemoryException">Thrown when a memory error occurred.</exception>
+        /// <exception cref="System.IO.IOException">Thrown when the method failed due to an internal I/O error.</exception>
+        /// <returns>Permission request Task</returns>
+        /// <example>
+        /// <code>
+        ///     string[] privileges = new [] {"http://tizen.org/privilege/account.read",
+        ///                                   "http://tizen.org/privilege/alarm"};
+        ///     CheckResult[] results = PrivacyPrivilegeManager.CheckPermissions(privileges).ToArray();
+        ///     List&lt;string&gt; privilegesWithAskStatus = new List&lt;string&gt;();
+        ///     for (int iterator = 0; iterator &lt; results.Length; ++iterator)
+        ///     {
+        ///         switch (results[iterator])
+        ///         {
+        ///             case CheckResult.Allow:
+        ///                 // Privilege can be used
+        ///                 break;
+        ///             case CheckResult.Deny:
+        ///                 // Privilege can't be used
+        ///                 break;
+        ///             case CheckResult.Ask:
+        ///                 // User permission request required
+        ///                 privilegesWithAskStatus.Add(privileges[iterator]);
+        ///                 break;
+        ///         }
+        ///     }
+        ///     IEnumerable&lt;PermissionRequestResponse&gt; responses = PrivacyPrivilegeManager.RequestPermissions(privilegesWithAskStatus).Result;
+        ///     //handle responses
+        /// </code>
+        /// </example>
+        /// <since_tizen> 6 </since_tizen>
+        public static Task<RequestMultipleResponseEventArgs> RequestPermissions(IEnumerable<string> privileges)
+        {
+            string[] privilegesArray = CheckPrivilegesArgument(privileges, "RequestPermissions");
+
+            for (int iterator = 0; iterator < privilegesArray.Length; ++iterator)
+            {
+                if (!s_PrivilegesInProgress.Add(privilegesArray[iterator]))
+                {
+                    Log.Error(LogTag, "Request for this privilege: " + privilegesArray[iterator] + " is already in progress.");
+
+                    for (int removeIterator = iterator - 1; removeIterator >= 0; --removeIterator)
+                    {
+                        s_PrivilegesInProgress.Remove(privilegesArray[removeIterator]);
+                    }
+                    Log.Error(LogTag, "Request for this privilege: " + privilegesArray[iterator] + " is already in progress.");
+                    throw new ArgumentException("Request for this privilege: " + privilegesArray[iterator] + " is already in progress.");
+                }
+            }
+
+            Log.Info(LogTag, "Sending request for permissions: " + string.Join(" ", privilegesArray));
+
+            TaskCompletionSource<RequestMultipleResponseEventArgs> permissionResponsesTask = new TaskCompletionSource<RequestMultipleResponseEventArgs>();
+            int ret = (int)Interop.PrivacyPrivilegeManager.RequestPermissions(privilegesArray, (uint)privilegesArray.Length,
+                        (Interop.PrivacyPrivilegeManager.CallCause cause, Interop.PrivacyPrivilegeManager.RequestResult[] results,
+                        string[] requestedPrivileges, uint privilegesCount, IntPtr userData) =>
+                        {
+                            Log.Info(LogTag, "Sending request for permissions: ");
+                            RequestMultipleResponseEventArgs requestResponse = new RequestMultipleResponseEventArgs();
+                            PermissionRequestResponse[] permissionResponses = new PermissionRequestResponse[privilegesCount];
+
+                            for (int iterator = 0; iterator < privilegesCount; ++iterator)
+                            {
+                                permissionResponses[iterator] = new PermissionRequestResponse
+                                {
+                                    Privilege = requestedPrivileges[iterator],
+                                    Result = (RequestResult)results[iterator]
+                                };
+                            }
+                            requestResponse.Cause = (CallCause)cause;
+                            requestResponse.Responses = permissionResponses;
+
+                            foreach (string privilege in requestedPrivileges)
+                            {
+                                s_PrivilegesInProgress.Remove(privilege);
+                            }
+                            permissionResponsesTask.SetResult(requestResponse);
+                        }, IntPtr.Zero);
+
+            if (ret != (int)Interop.PrivacyPrivilegeManager.ErrorCode.None)
+            {
+                Log.Error(LogTag, "Failed to request permissions.");
+                foreach (string privilege in privileges)
+                {
+                    s_PrivilegesInProgress.Remove(privilege);
+                }
+                throw PrivacyPrivilegeManagerErrorFactory.GetException(ret);
+            }
+            else
+            {
+                Log.Info(LogTag, "Requesting permissions successfull.");
+                return permissionResponsesTask.Task;
+            }
+        }
+
+        /// <summary>
         /// Gets the response context for a given privilege.
         /// </summary>
         /// <seealso cref="ResponseContext"/>
@@ -173,11 +372,12 @@ namespace Tizen.Security
         /// <since_tizen> 4 </since_tizen>
         public static WeakReference<ResponseContext> GetResponseContext(string privilege)
         {
-            if (!s_responseMap.ContainsKey(privilege))
+            if (!(s_responseWeakMap.TryGetValue(privilege, out WeakReference<ResponseContext> weakRef) && weakRef.TryGetTarget(out ResponseContext context)))
             {
-                s_responseMap[privilege] = new ResponseContext(privilege);
+                context = new ResponseContext(privilege);
+                s_responseWeakMap[privilege] = new WeakReference<ResponseContext>(context);
             }
-            return new WeakReference<ResponseContext>(s_responseMap[privilege]);
+            return s_responseWeakMap[privilege];
         }
 
         /// <summary>
@@ -202,6 +402,13 @@ namespace Tizen.Security
             {
                 add
                 {
+                    if (_ResponseFetched == null)
+                    {
+                        if (!s_responseMap.ContainsKey(_privilege))
+                        {
+                            s_responseMap[_privilege] = this;
+                        }
+                    }
                     _ResponseFetched += value;
                 }
 
@@ -210,7 +417,10 @@ namespace Tizen.Security
                     _ResponseFetched -= value;
                     if (_ResponseFetched == null)
                     {
-                        s_responseMap.Remove(_privilege);
+                        if (s_responseMap.ContainsKey(_privilege))
+                        {
+                            s_responseMap.Remove(_privilege);
+                        }
                     }
                 }
             }
@@ -219,7 +429,7 @@ namespace Tizen.Security
 
             internal void FireEvent(CallCause _cause, RequestResult _result)
             {
-                _ResponseFetched?.Invoke(null, new RequestResponseEventArgs() { cause = _cause, result = _result, privilege = _privilege });
+                _ResponseFetched?.Invoke(this, new RequestResponseEventArgs { cause = _cause, result = _result, privilege = _privilege });
             }
         }
     }
@@ -229,7 +439,7 @@ namespace Tizen.Security
         static internal Exception GetException(int error)
         {
             Interop.PrivacyPrivilegeManager.ErrorCode errCode = (Interop.PrivacyPrivilegeManager.ErrorCode)error;
-            switch(errCode)
+            switch (errCode)
             {
                 case Interop.PrivacyPrivilegeManager.ErrorCode.InvalidParameter:
                     return new ArgumentException("Invalid parameter");
index fe2b0ec..efbdf5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
@@ -42,5 +42,21 @@ namespace Tizen.Security
         /// </summary>
         /// <since_tizen> 4 </since_tizen>
         public string privilege { get; internal set; }
+
+        /// <summary>
+        /// The response for privilege request
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public PermissionRequestResponse Response
+        {
+            get
+            {
+                return new PermissionRequestResponse
+                {
+                    Result = result,
+                    Privilege = privilege,
+                };
+            }
+        }
     }
 }
diff --git a/src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/RequestResponseMultipleEventArgs.cs b/src/Tizen.Security.PrivacyPrivilegeManager/Tizen.Security/RequestResponseMultipleEventArgs.cs
new file mode 100644 (file)
index 0000000..c4a49d1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace Tizen.Security
+{
+    /// <summary>
+    /// This class is an event argument of the RequestResponse event.
+    /// </summary>
+    /// <since_tizen> 6 </since_tizen>
+
+    public class RequestMultipleResponseEventArgs : EventArgs
+    {
+        /// <summary>
+        /// The cause of a triggered response.
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public CallCause Cause { get; internal set; }
+
+        /// <summary>
+        /// The response for privilege request
+        /// </summary>
+        /// <since_tizen> 6 </since_tizen>
+        public IEnumerable<PermissionRequestResponse> Responses { get; internal set; }
+    }
+}