// // /*=============================================================================== // // Copyright (C) 2025 PhantomsXR Ltd. All Rights Reserved. // // // // This file is part of the Phantom.XRMOD.QuestModule.Runtime. // // // // The XR-MOD cannot be copied, distributed, or made available to // // third-parties for commercial purposes without written permission of PhantomsXR Ltd. // // // // Contact nswell@phantomsxr.com for licensing requests. // // ===============================================================================*/ using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Android; using PCD = Phantom.XRMOD.QuestModule.Runtime.PassthroughCameraDebugger; namespace Phantom.XRMOD.QuestModule.Runtime { /// /// Manages permission requests for Passthrough Camera access on Meta Quest. /// public class PassthroughCameraPermissions : MonoBehaviour { /// /// List of additional permissions to request on startup. /// Default includes "com.oculus.permission.USE_SCENE". /// [SerializeField] public List PermissionRequestsOnStartup = new() {"com.oculus.permission.USE_SCENE"}; /// /// Required permissions for accessing the Passthrough Camera. /// public static readonly string[] CameraPermissions = { "android.permission.CAMERA", // Required to use WebCamTexture object. "horizonos.permission.HEADSET_CAMERA" // Required to access the Passthrough Camera API in Horizon OS v74 and above. }; /// /// Indicates whether camera permissions have been granted. /// public static bool? HasCameraPermission { get; private set; } private static bool s_askedOnce; #if UNITY_ANDROID /// /// Request camera permission if the permission is not authorized by the user. /// /// Checks if permissions are already granted. If not, requests them via . /// /// public void AskCameraPermissions() { if (s_askedOnce) { return; } s_askedOnce = true; if (IsAllCameraPermissionsGranted()) { HasCameraPermission = true; PCD.DebugMessage(LogType.Log, "PCA: All camera permissions granted."); } else { PCD.DebugMessage(LogType.Log, "PCA: Requesting camera permissions."); var callbacks = new PermissionCallbacks(); callbacks.PermissionDenied += PermissionCallbacksPermissionDenied; callbacks.PermissionGranted += PermissionCallbacksPermissionGranted; callbacks.PermissionDeniedAndDontAskAgain += PermissionCallbacksPermissionDenied; // It's important to request all necessary permissions in one request because only one 'PermissionCallbacks' instance is supported at a time. var allPermissions = CameraPermissions.Concat(PermissionRequestsOnStartup).ToArray(); Permission.RequestUserPermissions(allPermissions, callbacks); } } /// /// Permission Granted callback /// /// Name of the granted permission. private static void PermissionCallbacksPermissionGranted(string permissionName) { PCD.DebugMessage(LogType.Log, $"PCA: Permission {permissionName} Granted"); // Only initialize the WebCamTexture object if both permissions are granted if (IsAllCameraPermissionsGranted()) { HasCameraPermission = true; } } /// /// Permission Denied callback. /// /// Name of the denied permission. private static void PermissionCallbacksPermissionDenied(string permissionName) { PCD.DebugMessage(LogType.Warning, $"PCA: Permission {permissionName} Denied"); HasCameraPermission = false; s_askedOnce = false; } /// /// Checks if all required camera permissions are authorized. /// /// True if all permissions in are granted. private static bool IsAllCameraPermissionsGranted() => CameraPermissions.All(Permission.HasUserAuthorizedPermission); #endif } }