version 2.0.0
This commit is contained in:
313
com.htc.upm.vive.openxr/Editor/AndroidManifestProcess.cs
Normal file
313
com.htc.upm.vive.openxr/Editor/AndroidManifestProcess.cs
Normal file
@@ -0,0 +1,313 @@
|
||||
// Copyright HTC Corporation All Rights Reserved.
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEditor.PackageManager;
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using VIVE.OpenXR.Hand;
|
||||
using VIVE.OpenXR.Tracker;
|
||||
|
||||
// Reference to Unity's OpenXR package
|
||||
|
||||
namespace VIVE.OpenXR.Editor
|
||||
{
|
||||
internal class ModifyAndroidManifest : OpenXRFeatureBuildHooks
|
||||
{
|
||||
public override int callbackOrder => 1;
|
||||
|
||||
public override Type featureType => typeof(VIVEFocus3Feature);
|
||||
|
||||
protected override void OnPreprocessBuildExt(BuildReport report)
|
||||
{
|
||||
}
|
||||
|
||||
private static string _manifestPath;
|
||||
|
||||
protected override void OnPostGenerateGradleAndroidProjectExt(string path)
|
||||
{
|
||||
_manifestPath = GetManifestPath(path);
|
||||
|
||||
var androidManifest = new AndroidManifest(_manifestPath);
|
||||
//androidManifest.AddVIVECategory();
|
||||
androidManifest.AddViveSDKVersion();
|
||||
androidManifest.AddUnityVersion();
|
||||
androidManifest.AddOpenXRPermission();
|
||||
androidManifest.AddOpenXRFeatures();
|
||||
androidManifest.Save();
|
||||
}
|
||||
|
||||
protected override void OnPostprocessBuildExt(BuildReport report)
|
||||
{
|
||||
if (File.Exists(_manifestPath))
|
||||
File.Delete(_manifestPath);
|
||||
}
|
||||
|
||||
private string _manifestFilePath;
|
||||
|
||||
private string GetManifestPath(string basePath)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_manifestFilePath)) return _manifestFilePath;
|
||||
|
||||
var pathBuilder = new StringBuilder(basePath);
|
||||
pathBuilder.Append(Path.DirectorySeparatorChar).Append("src");
|
||||
pathBuilder.Append(Path.DirectorySeparatorChar).Append("main");
|
||||
pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml");
|
||||
_manifestFilePath = pathBuilder.ToString();
|
||||
|
||||
return _manifestFilePath;
|
||||
}
|
||||
|
||||
private class AndroidXmlDocument : XmlDocument
|
||||
{
|
||||
private string m_Path;
|
||||
protected XmlNamespaceManager nsMgr;
|
||||
public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
public AndroidXmlDocument(string path)
|
||||
{
|
||||
m_Path = path;
|
||||
using (var reader = new XmlTextReader(m_Path))
|
||||
{
|
||||
reader.Read();
|
||||
Load(reader);
|
||||
}
|
||||
|
||||
nsMgr = new XmlNamespaceManager(NameTable);
|
||||
nsMgr.AddNamespace("android", AndroidXmlNamespace);
|
||||
}
|
||||
|
||||
public string Save()
|
||||
{
|
||||
return SaveAs(m_Path);
|
||||
}
|
||||
|
||||
public string SaveAs(string path)
|
||||
{
|
||||
using (var writer = new XmlTextWriter(path, new UTF8Encoding(false)))
|
||||
{
|
||||
writer.Formatting = Formatting.Indented;
|
||||
Save(writer);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class CheckIfSimultaneousInteractionEnabled
|
||||
{
|
||||
const string LOG_TAG = "CheckIfSimultaneousInteractionEnabled ";
|
||||
static StringBuilder m_sb = null;
|
||||
static StringBuilder sb
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_sb == null) { m_sb = new StringBuilder(); }
|
||||
return m_sb;
|
||||
}
|
||||
}
|
||||
static void DEBUG(StringBuilder msg) { Debug.Log(msg); }
|
||||
|
||||
internal const string MENU_NAME = "VIVE/Interaction Mode/Enable Simultaneous Interaction";
|
||||
|
||||
private static bool m_IsEnabled = false;
|
||||
public static bool IsEnabled { get { return m_IsEnabled; } }
|
||||
|
||||
static CheckIfSimultaneousInteractionEnabled()
|
||||
{
|
||||
m_IsEnabled = EditorPrefs.GetBool(MENU_NAME, false);
|
||||
|
||||
/// Delaying until first editor tick so that the menu
|
||||
/// will be populated before setting check state, and
|
||||
/// re-apply correct action
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
PerformAction(m_IsEnabled);
|
||||
};
|
||||
}
|
||||
|
||||
[MenuItem(MENU_NAME, priority = 601)]
|
||||
private static void ToggleAction()
|
||||
{
|
||||
/// Toggling action
|
||||
PerformAction(!m_IsEnabled);
|
||||
}
|
||||
|
||||
public static void PerformAction(bool enabled)
|
||||
{
|
||||
/// Set checkmark on menu item
|
||||
Menu.SetChecked(MENU_NAME, enabled);
|
||||
|
||||
/// Saving editor state
|
||||
EditorPrefs.SetBool(MENU_NAME, enabled);
|
||||
|
||||
m_IsEnabled = enabled;
|
||||
|
||||
sb.Clear().Append(LOG_TAG).Append(m_IsEnabled ? "Enable " : "Disable ").Append("Simultaneous Interaction."); DEBUG(sb);
|
||||
}
|
||||
|
||||
[MenuItem(MENU_NAME, validate = true, priority = 601)]
|
||||
public static bool ValidateEnabled()
|
||||
{
|
||||
Menu.SetChecked(MENU_NAME, m_IsEnabled);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class AndroidManifest : AndroidXmlDocument
|
||||
{
|
||||
private readonly XmlElement IntetnFilterElement;
|
||||
private readonly XmlElement ManifestElement;
|
||||
private readonly XmlElement ApplicationElement;
|
||||
|
||||
public AndroidManifest(string path) : base(path)
|
||||
{
|
||||
IntetnFilterElement = SelectSingleNode("/manifest/application/activity/intent-filter") as XmlElement;
|
||||
ManifestElement = SelectSingleNode("/manifest") as XmlElement;
|
||||
ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
|
||||
}
|
||||
|
||||
private XmlAttribute CreateAndroidAttribute(string key, string value)
|
||||
{
|
||||
XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
|
||||
attr.Value = value;
|
||||
return attr;
|
||||
}
|
||||
|
||||
private const string FAKE_VERSION = "0.0.0";
|
||||
|
||||
private static string SearchPackageVersion(string packageName)
|
||||
{
|
||||
var listRequest = Client.List(true);
|
||||
do
|
||||
{
|
||||
if (listRequest.IsCompleted)
|
||||
{
|
||||
if (listRequest.Result == null)
|
||||
{
|
||||
Debug.Log("List result: is empty");
|
||||
return FAKE_VERSION;
|
||||
}
|
||||
|
||||
foreach (var pi in listRequest.Result)
|
||||
{
|
||||
//Debug.Log("List has: " + pi.name + " == " + packageName);
|
||||
if (pi.name == packageName)
|
||||
{
|
||||
Debug.Log("Found " + packageName);
|
||||
|
||||
return pi.version;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(100);
|
||||
} while (true);
|
||||
return FAKE_VERSION;
|
||||
}
|
||||
|
||||
internal void AddViveSDKVersion()
|
||||
{
|
||||
var newUsesFeature = CreateElement("meta-data");
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("name", "com.htc.ViveOpenXR.SdkVersion"));
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("value", SearchPackageVersion("com.htc.upm.vive.openxr")));
|
||||
ApplicationElement.AppendChild(newUsesFeature);
|
||||
}
|
||||
|
||||
internal void AddUnityVersion()
|
||||
{
|
||||
var newUsesFeature = CreateElement("meta-data");
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("name", "com.htc.vr.content.UnityVersion"));
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("value", Application.unityVersion));
|
||||
ApplicationElement.AppendChild(newUsesFeature);
|
||||
}
|
||||
|
||||
internal void AddVIVECategory()
|
||||
{
|
||||
var md = IntetnFilterElement.AppendChild(CreateElement("category"));
|
||||
md.Attributes.Append(CreateAndroidAttribute("name", "com.htc.intent.category.VRAPP"));
|
||||
}
|
||||
|
||||
internal void AddOpenXRPermission()
|
||||
{
|
||||
var md = ManifestElement.AppendChild(CreateElement("uses-permission"));
|
||||
md.Attributes.Append(CreateAndroidAttribute("name", "org.khronos.openxr.permission.OPENXR"));
|
||||
|
||||
md = ManifestElement.AppendChild(CreateElement("uses-permission"));
|
||||
md.Attributes.Append(CreateAndroidAttribute("name", "org.khronos.openxr.permission.OPENXR_SYSTEM"));
|
||||
|
||||
var md2 = IntetnFilterElement.AppendChild(CreateElement("category"));
|
||||
md2.Attributes.Append(CreateAndroidAttribute("name", "org.khronos.openxr.intent.category.IMMERSIVE_HMD"));
|
||||
}
|
||||
|
||||
internal void AddOpenXRFeatures()
|
||||
{
|
||||
bool enableViveWristTracker = false;
|
||||
bool enableViveHandTracking = false;
|
||||
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
|
||||
if (null == settings)
|
||||
return;
|
||||
|
||||
foreach (var feature in settings.GetFeatures<OpenXRInteractionFeature>())
|
||||
{
|
||||
if (feature is ViveWristTracker)
|
||||
{
|
||||
enableViveWristTracker = feature.enabled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
|
||||
{
|
||||
if (feature is ViveHandTracking)
|
||||
{
|
||||
enableViveHandTracking = feature.enabled;
|
||||
break; ;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log("enableViveWristTracker " + enableViveWristTracker);
|
||||
if (enableViveWristTracker)
|
||||
{
|
||||
{
|
||||
var newUsesFeature = CreateElement("uses-feature");
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("name", "wave.feature.handtracking"));
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("required", "true"));
|
||||
ManifestElement.AppendChild(newUsesFeature);
|
||||
}
|
||||
{
|
||||
var newUsesFeature = CreateElement("uses-feature");
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("name", "wave.feature.tracker"));
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("required", "true"));
|
||||
ManifestElement.AppendChild(newUsesFeature);
|
||||
}
|
||||
}
|
||||
else if (enableViveHandTracking)
|
||||
{
|
||||
{
|
||||
var newUsesFeature = CreateElement("uses-feature");
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("name", "wave.feature.handtracking"));
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("required", "true"));
|
||||
ManifestElement.AppendChild(newUsesFeature);
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckIfSimultaneousInteractionEnabled.IsEnabled)
|
||||
{
|
||||
var newUsesFeature = CreateElement("uses-feature");
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("name", "wave.feature.simultaneous_interaction"));
|
||||
newUsesFeature.Attributes.Append(CreateAndroidAttribute("required", "true"));
|
||||
ManifestElement.AppendChild(newUsesFeature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user