Handle camera privileges. (#58)
authorPiotr Czaja/Tizen Services & IoT (PLT) /SRPOL/Engineer/Samsung Electronics <p.czaja@samsung.com>
Mon, 7 Jun 2021 14:56:33 +0000 (16:56 +0200)
committerPiotr Czaja <p.czaja@samsung.com>
Tue, 14 Sep 2021 11:01:34 +0000 (13:01 +0200)
* Handle camera privileges.
* Add toast message.

* Fix typo.
* Apply fixes after review.
* Replace toast by notification.
* Fix warnings.
* Apply fixes after review.
* Apply fixes after review.

Fitness/Services/NavigationService.cs
Fitness/Services/PrivilegeService.cs [new file with mode: 0644]
Fitness/ViewModels/ExercisePreviewViewModel.cs
Fitness/ViewModels/MainViewModel.cs
Fitness/Views/LoadingView.cs
Fitness/Views/MainView.xaml.cs
Fitness/Views/ScanningView.cs
Fitness/res/toast/toast_background.png [new file with mode: 0644]
Fitness/tizen-manifest.xml

index da85bbc9518d5794da0d31068fd274d643e3fd64..0411200c418be62f91b3584488b99bff02a63249 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Threading.Tasks;
 using Fitness.Controls;
 using Fitness.Views;
 using Tizen.NUI;
@@ -44,14 +45,22 @@ namespace Fitness.Services
             navigation.Push(new ExercisePreviewView(workoutId));
         }
 
-        public void NavigateToScanningView()
+        public async Task NavigateToScanningView()
         {
-            navigation.Push(new ScanningView());
+            var result = await PrivilegeService.Instance.CheckCameraPrivilege();
+            if (result == Tizen.Security.RequestResult.AllowForever)
+            {
+                navigation.Push(new ScanningView());
+            }
         }
 
-        public void NavigateToLoadingView()
+        public async Task NavigateToLoadingView()
         {
-            navigation.Push(new LoadingView());
+            var result = await PrivilegeService.Instance.CheckCameraPrivilege();
+            if (result == Tizen.Security.RequestResult.AllowForever)
+            {
+                navigation.Push(new LoadingView());
+            }
         }
 
         public void NavigateToSummaryView()
diff --git a/Fitness/Services/PrivilegeService.cs b/Fitness/Services/PrivilegeService.cs
new file mode 100644 (file)
index 0000000..d2ce299
--- /dev/null
@@ -0,0 +1,119 @@
+using System.Threading.Tasks;
+using Tizen.Applications;
+using Tizen.NUI;
+using Tizen.NUI.Components;
+using Tizen.Security;
+
+namespace Fitness.Services
+{
+    /// <summary>
+    /// Class for handling privacy privileges requests.
+    /// </summary>
+    public class PrivilegeService
+    {
+        private static PrivilegeService instance;
+        private string privilege;
+        private TaskCompletionSource<RequestResult> taskCompletionSource;
+
+        private PrivilegeService()
+        {
+        }
+
+        /// <summary>
+        /// Gets the instance of the <see cref="PrivilegeService"/> class.
+        /// </summary>
+        public static PrivilegeService Instance
+        {
+            get
+            {
+                if (instance == null)
+                {
+                    instance = new PrivilegeService();
+                }
+
+                return instance;
+            }
+        }
+
+        /// <summary>
+        /// Checks the status of camera privacy privilege permission and asks user to grant access if necessary.
+        /// </summary>
+        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
+        public async Task<RequestResult> CheckCameraPrivilege()
+        {
+            const string Privilege = "http://tizen.org/privilege/camera";
+            const string Message = "This view can't be shown without camera privilege.";
+
+            var result = await CheckPrivilege(Privilege);
+            if (result != RequestResult.AllowForever)
+            {
+                Notification
+                    .MakeToast(Message, Notification.ToastBottom)
+                    .Post(Notification.ToastLong);
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// Checks the status of privacy privilege permission and asks user to grant access if necessary.
+        /// </summary>
+        /// <param name="privilege">Privacy privilege to be processed.</param>
+        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
+        public Task<RequestResult> CheckPrivilege(string privilege)
+        {
+            this.privilege = privilege;
+            taskCompletionSource = new TaskCompletionSource<RequestResult>();
+
+            CheckResult result = PrivacyPrivilegeManager.CheckPermission(privilege);
+
+            switch (result)
+            {
+                case CheckResult.Ask:
+                    RegisterResponseHandler();
+                    PrivacyPrivilegeManager.RequestPermission(privilege);
+                    break;
+                case CheckResult.Allow:
+                    taskCompletionSource.SetResult(RequestResult.AllowForever);
+                    break;
+                case CheckResult.Deny:
+                    taskCompletionSource.SetResult(RequestResult.DenyForever);
+                    break;
+                default:
+                    break;
+            }
+
+            return taskCompletionSource.Task;
+        }
+
+        private void RegisterResponseHandler()
+        {
+            if (PrivacyPrivilegeManager.GetResponseContext(privilege).TryGetTarget(out var context))
+            {
+                context.ResponseFetched += PPM_RequestResponse;
+            }
+        }
+
+        private void UnregisterResponseHandler()
+        {
+            if (PrivacyPrivilegeManager.GetResponseContext(privilege).TryGetTarget(out var context))
+            {
+                context.ResponseFetched -= PPM_RequestResponse;
+            }
+        }
+
+        private void PPM_RequestResponse(object sender, RequestResponseEventArgs e)
+        {
+            if (e.cause == CallCause.Answer)
+            {
+                taskCompletionSource.SetResult(e.result);
+            }
+            else
+            {
+                Services.Logger.Info($"Error occurred during requesting permission for {e.privilege}");
+            }
+
+            UnregisterResponseHandler();
+        }
+    }
+}
index ce5531c45e92087af4bc837e44634547e834e4b2..cb72f9f508553caa9b631140ed94e55f353d8638 100644 (file)
@@ -16,7 +16,7 @@ namespace Fitness.ViewModels
 
         public ExercisePreviewViewModel()
         {
-            Skip = new Command(NavigationService.Instance.NavigateToLoadingView);
+            Skip = new Command(() => _ = NavigationService.Instance.NavigateToLoadingView());
             PreviousWorkout = new Command(GoPrevious);
             NextWorkout = new Command(GoNext);
 
index e86fccf40a476226c729386dd3ebe6f0ec4afc26..95a34cddc459e4d52055d05d83bd84c01dca29a5 100644 (file)
@@ -16,7 +16,7 @@ namespace Fitness.ViewModels
         public MainViewModel()
         {
             WatchPreview = new Command(() => { NavigationService.Instance.NavigateToExercisePreviewView(SelectedWorkout.Id); });
-            StartWorkout = new Command(() => { NavigationService.Instance.NavigateToScanningView(); });
+            StartWorkout = new Command(() => _ = NavigationService.Instance.NavigateToScanningView());
             Exit = new Command(() => { Tizen.NUI.NUIApplication.Current.Exit(); });
 
             Workouts = WorkoutRepository.Instance.GetAll();
index 4d41d0f2e74e386417942b2f64e19b9f983ed346..50d6faeb4647342f6cde3e1c8271426cc33e1ca8 100644 (file)
@@ -1,5 +1,7 @@
+using System.Threading.Tasks;
 using Fitness.Controls;
-using Tizen.NUI.BaseComponents;
+using Fitness.Services;
+using Tizen.Security;
 
 namespace Fitness.Views
 {
index 1e4aae10df3a415e6a620c6e5195f7b013e083aa..c80e8ede00d3618a5801c88f5e0739ab43d28177 100644 (file)
@@ -2,30 +2,14 @@ using Fitness.Controls;
 using Tizen.NUI;
 using Tizen.NUI.BaseComponents;
 using Tizen.NUI.Components;
-using Tizen.Security;
 
 namespace Fitness.Views
 {
     public partial class MainView : Fitness.Controls.Page
     {
-        private const string CameraPrivilege = "http://tizen.org/privilege/camera";
-
         public MainView()
         {
-            CheckPrivilege();
-
             InitializeComponent();
         }
-
-        private void CheckPrivilege()
-        {
-            CheckResult result = PrivacyPrivilegeManager.CheckPermission(CameraPrivilege);
-            Services.Logger.Info($"Privilege \"{CameraPrivilege}\" : {result}");
-
-            if (result == CheckResult.Ask)
-            {
-                PrivacyPrivilegeManager.RequestPermission(CameraPrivilege);
-            }
-        }
     }
 }
index fc2b842c498add9c641b11dd35d17eb4c1dc0b7c..8c5d30b320cfffb03f492b199a8603457a960894 100644 (file)
@@ -29,7 +29,7 @@ namespace Fitness.Views
         /// </summary>
         protected override void OnDisappearing()
         {
-            if (cameraView.PreviewState == Tizen.Multimedia.CameraState.Preview)
+            if (cameraView?.PreviewState == Tizen.Multimedia.CameraState.Preview)
             {
                 cameraView.Preview -= DetectPreview;
                 cameraView.StopPreview();
diff --git a/Fitness/res/toast/toast_background.png b/Fitness/res/toast/toast_background.png
new file mode 100644 (file)
index 0000000..ae33a27
Binary files /dev/null and b/Fitness/res/toast/toast_background.png differ
index 4b0b9814d6ae98ad273d168adada17ca6565b680..f61790666574963b5a58e667cb6e662f5c7f8d00 100644 (file)
@@ -14,5 +14,6 @@
   </ui-application>
   <privileges>
     <privilege>http://tizen.org/privilege/camera</privilege>
+    <privilege>http://tizen.org/privilege/window.priority.set</privilege>
   </privileges>
 </manifest>