Files
VR-WuKong/Packages/PICO Unity Integration SDK-3.3.2-20251111/Editor/PXR_BuildProcessor.cs

689 lines
37 KiB
C#
Raw Normal View History

2025-11-13 17:40:28 +08:00
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Xml;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor.Android;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor;
using UnityEditor.XR.Management;
using UnityEngine.XR.Management;
#if UNITY_OPENXR
#if XR_HAND
using UnityEngine.XR.Hands.OpenXR;
#endif
#if PICO_OPENXR_SDK
//using UnityEngine.XR.Hands.OpenXR;
using Unity.XR.OpenXR.Features.PICOSupport;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
#endif
#endif
namespace Unity.XR.PXR.Editor
{
public class PXR_BuildProcessor : XRBuildHelper<PXR_Settings>
{
public override string BuildSettingsKey { get { return "Unity.XR.PXR.Settings"; } }
public static bool IsLoaderExists(bool isPlatform = false)
{
XRGeneralSettings generalSettings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Android);
if (generalSettings == null) return false;
var assignedSettings = generalSettings.AssignedSettings;
if (assignedSettings == null) return false;
bool isPxrOpenXRFeatureEnabled = false;
bool isPxrOpenXRExtensionsEnabled = false;
#if UNITY_2021_1_OR_NEWER
foreach (XRLoader loader in assignedSettings.activeLoaders)
{
if (loader is PXR_Loader) return true;
#if PICO_OPENXR_SDK
if (loader is OpenXRLoader)
{
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
{
if (feature is PICOFeature)
{
isPxrOpenXRFeatureEnabled = feature.enabled;
if (!isPlatform)
{
return isPxrOpenXRFeatureEnabled;
}
}
if (feature is OpenXRExtensions)
{
isPxrOpenXRExtensionsEnabled = feature.enabled;
if (isPlatform)
{
return isPxrOpenXRExtensionsEnabled;
}
}
}
}
#endif
}
#else
foreach (XRLoader loader in assignedSettings.loaders)
{
if (loader is PXR_Loader) return true;
#if PICO_OPENXR_SDK
if (loader is OpenXRLoader)
{
Debug.Log("PXRLog [Build Check]OpenXR is enabled");
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
{
if (feature is PXR_OpenXRFeature)
{
return true;
}
if (feature is PXR_OpenXRFeature)
{
isPxrOpenXRFeatureEnabled = feature.enabled;
if (!isPlatform)
{
return isPxrOpenXRFeatureEnabled;
}
}
if (feature is PXR_OpenXRExtensions)
{
isPxrOpenXRExtensionsEnabled = feature.enabled;
if (isPlatform)
{
return isPxrOpenXRExtensionsEnabled;
}
}
}
}
#endif
}
#endif
return false;
}
private PXR_Settings PxrSettings
{
get
{
return SettingsForBuildTargetGroup(BuildTargetGroup.Android) as PXR_Settings;
}
}
private void SetRequiredPluginInBuild()
{
PluginImporter[] plugins = PluginImporter.GetAllImporters();
foreach (PluginImporter plugin in plugins)
{
if (plugin.assetPath.Contains("PxrPlatform.aar"))
{
plugin.SetIncludeInBuildDelegate((path) =>
{
return IsLoaderExists(true);
});
}
if (plugin.assetPath.Contains(".ForUnitySDK.aar"))
{
Debug.Log("PXRLog [Build Check]OpenXR is enabled");
plugin.SetIncludeInBuildDelegate((path) =>
{
#if PICO_OPENXR_SDK
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
{
if (feature is PICOFeature)
{
return feature.enabled;
}
}
return false;
#else
return IsLoaderExists(true);
#endif
});
}
}
}
public override void OnPreprocessBuild(BuildReport report)
{
SetRequiredPluginInBuild();
if (report.summary.platformGroup != BuildTargetGroup.Android)
return;
if (!IsLoaderExists())
return;
GraphicsDeviceType firstGfxType =
PlayerSettings.GetGraphicsAPIs(EditorUserBuildSettings.activeBuildTarget)[0];
if (firstGfxType != GraphicsDeviceType.OpenGLES3 && firstGfxType != GraphicsDeviceType.Vulkan && firstGfxType != GraphicsDeviceType.OpenGLES2)
throw new BuildFailedException($"PICO Plugin on mobile platforms nonsupport the {firstGfxType}");
if (PxrSettings.stereoRenderingModeAndroid == PXR_Settings.StereoRenderingModeAndroid.Multiview && firstGfxType == GraphicsDeviceType.OpenGLES2)
PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new GraphicsDeviceType[] { GraphicsDeviceType.OpenGLES3 });
if (PlayerSettings.Android.minSdkVersion < AndroidSdkVersions.AndroidApiLevel29)
throw new BuildFailedException("Android Minimum API must be set to 29 or higher for PICO Plugin.");
base.OnPreprocessBuild(report);
}
}
#if UNITY_2021_3_OR_NEWER
internal class PXR_BuildHooks : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder { get; }
private static readonly Dictionary<string, string> AndroidBootConfigVars = new Dictionary<string, string>()
{
{ "xr-usable-core-mask-enabled", "1"},
{ "xr-require-backbuffer-textures", "0" },
{ "xr-hide-memoryless-render-texture", "1" },
{ "xr-vulkan-extension-fragment-density-map-enabled", "1"}
};
public void OnPreprocessBuild(BuildReport report)
{
if (report.summary.platformGroup == BuildTargetGroup.Android)
{
var bootConfig = new BootConfig(report);
bootConfig.ReadBootConfig();
foreach (var entry in AndroidBootConfigVars)
{
bootConfig.SetValueForKey(entry.Key, entry.Value);
}
bootConfig.WriteBootConfig();
var issues = PXR_ProjectValidationRequired.GetValidationIssues();
foreach (var issue in issues)
{
if (issue.error)
{
Debug.LogError($"PXR SDK validation failed: {issue.description}");
throw new BuildFailedException($"There are unresolved PXR configuration errors");
}
}
}
}
public void OnPostprocessBuild(BuildReport report)
{
if (report.summary.platformGroup == BuildTargetGroup.Android)
{
BootConfig bootConfig = new BootConfig(report);
bootConfig.ReadBootConfig();
foreach (KeyValuePair<string, string> entry in AndroidBootConfigVars)
{
bootConfig.ClearEntryForKeyAndValue(entry.Key, entry.Value);
}
bootConfig.WriteBootConfig();
}
}
}
/// <summary>
/// Small utility class for reading, updating and writing boot config.
/// </summary>
internal class BootConfig
{
private const string XrBootSettingsKey = "xr-boot-settings";
private readonly Dictionary<string, string> bootConfigSettings;
private readonly string buildTargetName;
public BootConfig(BuildReport report)
{
bootConfigSettings = new Dictionary<string, string>();
buildTargetName = BuildPipeline.GetBuildTargetName(report.summary.platform);
}
public void ReadBootConfig()
{
bootConfigSettings.Clear();
string xrBootSettings = EditorUserBuildSettings.GetPlatformSettings(buildTargetName, XrBootSettingsKey);
if (!string.IsNullOrEmpty(xrBootSettings))
{
var bootSettings = xrBootSettings.Split(';');
foreach (var bootSetting in bootSettings)
{
var setting = bootSetting.Split(':');
if (setting.Length == 2 && !string.IsNullOrEmpty(setting[0]) && !string.IsNullOrEmpty(setting[1]))
{
bootConfigSettings.Add(setting[0], setting[1]);
}
}
}
}
public void SetValueForKey(string key, string value) => bootConfigSettings[key] = value;
public bool TryGetValue(string key, out string value) => bootConfigSettings.TryGetValue(key, out value);
public void ClearEntryForKeyAndValue(string key, string value)
{
if (bootConfigSettings.TryGetValue(key, out string dictValue) && dictValue == value)
{
bootConfigSettings.Remove(key);
}
}
public void WriteBootConfig()
{
bool firstEntry = true;
var sb = new System.Text.StringBuilder();
foreach (var kvp in bootConfigSettings)
{
if (!firstEntry)
{
sb.Append(";");
}
sb.Append($"{kvp.Key}:{kvp.Value}");
firstEntry = false;
}
EditorUserBuildSettings.SetPlatformSettings(buildTargetName, XrBootSettingsKey, sb.ToString());
}
}
#endif
#if UNITY_ANDROID
internal class PXR_Manifest : IPostGenerateGradleAndroidProject
{
public void OnPostGenerateGradleAndroidProject(string path)
{
if (!PXR_BuildProcessor.IsLoaderExists())
return;
string originManifestPath = path + "/src/main/AndroidManifest.xml";
XmlDocument doc = new XmlDocument();
doc.Load(originManifestPath);
string manifestTagPath = "/manifest";
string applicationTagPath = manifestTagPath + "/application";
string metaDataTagPath = applicationTagPath + "/meta-data";
string usesPermissionTagName = "uses-permission";
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.app.type"}},new Dictionary<string, string>{{"value","vr"}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pxr.sdk.version_code"}},new Dictionary<string, string>{{"value", "5140"}});
doc.InsertAttributeInTargetTag(applicationTagPath,null, new Dictionary<string, string>() {{"requestLegacyExternalStorage", "true"}});
#if PICO_OPENXR_SDK
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","use.pxr.sdk"}},new Dictionary<string, string>{{"value", "2"}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.sdk.version"}},new Dictionary<string, string>{{"value","Unity OpenXR "+PXR_Constants.SDKVersion}});
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
bool mrPermission = false;
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
{
if (feature is PICOSceneCapture)
{
if (feature.enabled)
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_scene_anchor" } },
new Dictionary<string, string> { { "value", "1" } });
mrPermission = true;
}
else
{
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_scene_anchor" } });
}
}
if (feature is PICOSpatialAnchor)
{
if (feature.enabled)
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_spatial_anchor" } },
new Dictionary<string, string> { { "value", "1" } });
mrPermission = true;
}
else
{
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_spatial_anchor" } });
}
}
if (feature is PICOSpatialMesh)
{
if (feature.enabled)
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mesh_anchor" } },
new Dictionary<string, string> { { "value", "1" } });
mrPermission = true;
}
else
{
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mesh_anchor" } });
}
}
#if XR_HAND
if (feature is HandTracking)
{
if (feature.enabled)
{
if (PXR_OpenXRProjectSetting.GetProjectConfig().isHandTracking)
{
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName,
new Dictionary<string, string> { { "name", "com.picovr.permission.HAND_TRACKING" } });
if (PXR_OpenXRProjectSetting.GetProjectConfig().handTrackingSupportType == HandTrackingSupport.HandsOnly)
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } },
new Dictionary<string, string> { { "value", "1" } });
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } });
}
else
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } },
new Dictionary<string, string> { { "value", "1" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } },
new Dictionary<string, string> { { "value", "1" } });
}
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "Hand_Tracking_HighFrequency" } },
new Dictionary<string, string> { { "value", PXR_OpenXRProjectSetting.GetProjectConfig().highFrequencyHand ? "1" : "0" } });
}
else
{
doc.RemoveNameValueElementInTag(manifestTagPath, usesPermissionTagName,
"android:name", "com.picovr.permission.HAND_TRACKING");
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } });
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "Hand_Tracking_HighFrequency" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } },
new Dictionary<string, string> { { "value", "1" } });
}
}
else
{
doc.RemoveNameValueElementInTag(manifestTagPath, usesPermissionTagName,
"android:name", "com.picovr.permission.HAND_TRACKING");
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } });
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "Hand_Tracking_HighFrequency" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } },
new Dictionary<string, string> { { "value", "1" } });
}
}
}
#else
}
doc.RemoveNameValueElementInTag(manifestTagPath, usesPermissionTagName,
"android:name", "com.picovr.permission.HAND_TRACKING");
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } });
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "Hand_Tracking_HighFrequency" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } },
new Dictionary<string, string> { { "value", "1" } });
#endif
if (PXR_OpenXRProjectSetting.GetProjectConfig().isEyeTracking)
{
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName,
new Dictionary<string, string> { { "name", "com.picovr.permission.EYE_TRACKING" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "picovr.software.eye_tracking" } },
new Dictionary<string, string> { { "value", "1" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "eyetracking_calibration" } },
new Dictionary<string, string> { { "value", PXR_OpenXRProjectSetting.GetProjectConfig().isEyeTrackingCalibration ? "true" : "false" } });
}
else
{
doc.RemoveNameValueElementInTag(manifestTagPath, usesPermissionTagName,
"android:name", "com.picovr.permission.EYE_TRACKING");
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "picovr.software.eye_tracking" } });
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "eyetracking_calibration" } });
}
if (PXR_OpenXRProjectSetting.GetProjectConfig().MRSafeguard)
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mr_safeguard" } },
new Dictionary<string, string> { { "value", PXR_OpenXRProjectSetting.GetProjectConfig().MRSafeguard ? "1" : "0" } });
}
else
{
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mr_safeguard" } });
}
if (mrPermission)
{
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName,
new Dictionary<string, string> { { "name", "com.picovr.permission.SPATIAL_DATA" } });
}
else
{
doc.RemoveNameValueElementInTag(manifestTagPath, usesPermissionTagName,
"android:name", "com.picovr.permission.SPATIAL_DATA");
}
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.app.splash" } },
new Dictionary<string, string> { { "value", PXR_OpenXRProjectSetting.GetProjectConfig().GetSystemSplashScreen(path) } });
#else
var settings = PXR_XmlTools.GetSettings();
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","use.pxr.sdk"}},new Dictionary<string, string>{{"value", "1"}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.sdk.version"}},new Dictionary<string, string>{{"value","XR Platform_"+PXR_Constants.SDKVersion}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","enable_cpt"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().useContentProtect ? "1" : "0"}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","Enable_AdaptiveHandModel"}},new Dictionary<string, string> {{"value",PXR_ProjectSetting.GetProjectConfig().adaptiveHand ? "1" : "0" }});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","Hand_Tracking_HighFrequency"}},new Dictionary<string, string> {{"value",PXR_ProjectSetting.GetProjectConfig().highFrequencyHand ? "1" : "0" }});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","rendering_mode"}},new Dictionary<string, string>{{"value",((int)settings.stereoRenderingModeAndroid).ToString()}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","display_rate"}},new Dictionary<string, string>{{"value",((int)settings.systemDisplayFrequency).ToString()}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","color_Space"}},new Dictionary<string, string>{{"value",QualitySettings.activeColorSpace == ColorSpace.Linear ? "1" : "0"}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","MRCsupport"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().openMRC ? "1" : "0" }});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.LateLatching"}}, new Dictionary<string, string> {{"value",PXR_ProjectSetting.GetProjectConfig().latelatching ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.LateLatchingDebug"}}, new Dictionary<string, string> {{"value", PXR_ProjectSetting.GetProjectConfig().latelatching && PXR_ProjectSetting.GetProjectConfig().latelatchingDebug ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.app.splash"} },new Dictionary<string, string>{{"value",settings.GetSystemSplashScreen(path)}});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","PICO.swift.feature"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().bodyTracking ? "1" : "0" }});
doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","adaptive_resolution"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().adaptiveResolution ? "1" : "0" }});
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mr_safeguard" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().mrSafeguard ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_vst" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().videoSeeThrough ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_anchor" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "mr_map_mgr_auto_start" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_spatial_anchor" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_cloud_anchor" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().sharedAnchor ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mesh_anchor" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialMesh ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_scene_anchor" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().sceneCapture ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.SuperResolution" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().superResolution ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.NormalSharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().normalSharpening ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.QualitySharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().qualitySharpening ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.FixedFoveatedSharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().fixedFoveatedSharpening ? "1" : "0" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.SelfAdaptiveSharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().selfAdaptiveSharpening ? "1" : "0" } });
doc.CreateElementInTag(manifestTagPath,usesPermissionTagName,new Dictionary<string, string>{{"name","android.permission.WRITE_SETTINGS"}});
if (PXR_ProjectSetting.GetProjectConfig().eyeTracking || PXR_ProjectSetting.GetProjectConfig().enableETFR)
{
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName, new Dictionary<string, string> { { "name", "com.picovr.permission.EYE_TRACKING" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "picovr.software.eye_tracking" } }, new Dictionary<string, string> { { "value", "1" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "eyetracking_calibration" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().eyetrackingCalibration ? "true" : "false" } });
}
if (PXR_ProjectSetting.GetProjectConfig().spatialAnchor || PXR_ProjectSetting.GetProjectConfig().sceneCapture || PXR_ProjectSetting.GetProjectConfig().spatialMesh || PXR_ProjectSetting.GetProjectConfig().sharedAnchor)
{
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName,
new Dictionary<string, string> { { "name", "com.picovr.permission.SPATIAL_DATA" } });
}
if (PXR_ProjectSetting.GetProjectConfig().handTracking)
{
if (PXR_ProjectSetting.GetProjectConfig().handTrackingSupportType==HandTrackingSupport.HandsOnly)
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } },
new Dictionary<string, string> { { "value", "1" } });
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } });
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName,
new Dictionary<string, string> { { "name", "com.picovr.permission.HAND_TRACKING" } });
}
else
{
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } },
new Dictionary<string, string> { { "value", "1" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } },
new Dictionary<string, string> { { "value", "1" } });
doc.CreateElementInTag(manifestTagPath, usesPermissionTagName,
new Dictionary<string, string> { { "name", "com.picovr.permission.HAND_TRACKING" } });
}
}
else
{
doc.RemoveAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "handtracking" } });
doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "controller" } },
new Dictionary<string, string> { { "value", "1" } });
doc.RemoveNameValueElementInTag(manifestTagPath, usesPermissionTagName,
"android:name", "com.picovr.permission.HAND_TRACKING");
}
if (PXR_ProjectSetting.GetProjectConfig().faceTracking) { doc.CreateElementInTag(manifestTagPath, usesPermissionTagName, new Dictionary<string, string> { { "name", "com.picovr.permission.FACE_TRACKING" } }); }
if (PXR_ProjectSetting.GetProjectConfig().lipsyncTracking) { doc.CreateElementInTag(manifestTagPath, usesPermissionTagName, new Dictionary<string, string> { { "name", "android.permission.RECORD_AUDIO" } }); }
if (PXR_ProjectSetting.GetProjectConfig().faceTracking) { doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "picovr.software.face_tracking" } }, new Dictionary<string, string> { { "value", "false/true" } }); }
#endif
doc.Save(originManifestPath);
}
public int callbackOrder { get { return 10000; } }
}
#endif
public static class PXR_XmlTools
{
static readonly string androidURI = "http://schemas.android.com/apk/res/android";
public static void InsertAttributeInTargetTag(this XmlDocument doc, string tagPath, Dictionary<string, string> filterDic, Dictionary<string, string> attributeDic)
{
XmlElement targetElement = null;
if (filterDic == null)
targetElement = doc.SelectSingleNode(tagPath) as XmlElement;
else
{
XmlNodeList nodeList = doc.SelectNodes(tagPath);
if (nodeList != null)
{
foreach (XmlNode node in nodeList)
{
if (FilterCheck(node as XmlElement, filterDic))
{
targetElement = node as XmlElement;
break;
}
}
}
}
if (targetElement == null)
{
string parentPath = tagPath.Substring(0, tagPath.LastIndexOf("/"));
string tagName = tagPath.Substring(tagPath.LastIndexOf("/") + 1);
foreach (var item in attributeDic)
filterDic.Add(item.Key, item.Value);
doc.CreateElementInTag(parentPath, tagName, filterDic);
}
else UpdateOrCreateAttribute(targetElement, attributeDic);
}
public static void RemoveAttributeInTargetTag(this XmlDocument doc, string tagPath, Dictionary<string, string> filterDic)
{
if (filterDic != null)
{
XmlNodeList nodeList = doc.SelectNodes(tagPath);
if (nodeList != null)
{
foreach (XmlNode node in nodeList)
{
if (FilterCheck(node as XmlElement, filterDic))
{
node.ParentNode?.RemoveChild(node);
break;
}
}
}
}
}
public static void RemoveNameValueElementInTag(this XmlDocument doc, string parentPath, string tag, string name,
string value)
{
var xmlNodeList = doc.SelectNodes(parentPath + "/" + tag);
foreach (XmlNode node in xmlNodeList)
{
var attributeList = ((XmlElement)node).Attributes;
foreach (XmlAttribute attrib in attributeList)
{
if (attrib.Name == name && attrib.Value == value)
{
node.ParentNode?.RemoveChild(node);
}
}
}
}
public static void CreateElementInTag(this XmlDocument doc, string parentPath, string tagName,
Dictionary<string, string> attributeDic)
{
XmlNode parentNode = doc.SelectSingleNode(parentPath);
if (parentNode == null)
{
return;
}
foreach (XmlNode childNode in parentNode.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
if (FilterCheck((XmlElement)childNode, attributeDic))
return;
}
}
XmlElement newElement = doc.CreateElement(tagName);
UpdateOrCreateAttribute(newElement, attributeDic);
parentNode.AppendChild(newElement);
}
private static bool FilterCheck(XmlElement element, Dictionary<string, string> filterDic)
{
foreach (var filterCase in filterDic)
{
string caseValue = element.GetAttribute(filterCase.Key, androidURI);
if (String.IsNullOrEmpty(caseValue) || caseValue != filterCase.Value)
return false;
}
return true;
}
private static void UpdateOrCreateAttribute(XmlElement element, Dictionary<string, string> attributeDic)
{
foreach (var attributeItem in attributeDic)
{
element.SetAttribute(attributeItem.Key, androidURI, attributeItem.Value);
}
}
public static PXR_Settings GetSettings()
{
PXR_Settings settings = null;
#if UNITY_EDITOR
UnityEditor.EditorBuildSettings.TryGetConfigObject<PXR_Settings>("Unity.XR.PXR.Settings", out settings);
#endif
#if UNITY_ANDROID && !UNITY_EDITOR
settings = PXR_Settings.settings;
#endif
return settings;
}
}
}