// // /*===============================================================================
// // 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
}
}