Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
11 KiB

  1. /************************************************************************************
  2. Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
  3. Licensed under the Oculus SDK License Version 3.4.1 (the "License");
  4. you may not use the Oculus SDK except in compliance with the License,
  5. which is provided at the time of installation or download, or which
  6. otherwise accompanies this software in either electronic or hard copy form.
  7. You may obtain a copy of the License at
  8. https://developer.oculus.com/licenses/sdk-3.4.1
  9. Unless required by applicable law or agreed to in writing, the Oculus SDK
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ************************************************************************************/
  15. using UnityEngine;
  16. using UnityEditor;
  17. using System.IO;
  18. using System.Xml;
  19. public class OVRManifestPreprocessor
  20. {
  21. [MenuItem("Oculus/Tools/Create store-compatible AndroidManifest.xml", false, 100000)]
  22. public static void GenerateManifestForSubmission()
  23. {
  24. var so = ScriptableObject.CreateInstance(typeof(OVRPluginUpdaterStub));
  25. var script = MonoScript.FromScriptableObject(so);
  26. string assetPath = AssetDatabase.GetAssetPath(script);
  27. string editorDir = Directory.GetParent(assetPath).FullName;
  28. string srcFile = editorDir + "/AndroidManifest.OVRSubmission.xml";
  29. if (!File.Exists(srcFile))
  30. {
  31. Debug.LogError("Cannot find Android manifest template for submission." +
  32. " Please delete the OVR folder and reimport the Oculus Utilities.");
  33. return;
  34. }
  35. string manifestFolder = Application.dataPath + "/Plugins/Android";
  36. if (!Directory.Exists(manifestFolder))
  37. Directory.CreateDirectory(manifestFolder);
  38. string dstFile = manifestFolder + "/AndroidManifest.xml";
  39. if (File.Exists(dstFile))
  40. {
  41. if (!EditorUtility.DisplayDialog("AndroidManifest.xml Already Exists!", "Would you like to replace the existing manifest with a new one? All modifications will be lost.", "Replace", "Cancel"))
  42. {
  43. return;
  44. }
  45. }
  46. PatchAndroidManifest(srcFile, dstFile, false);
  47. AssetDatabase.Refresh();
  48. }
  49. [MenuItem("Oculus/Tools/Update AndroidManifest.xml")]
  50. public static void UpdateAndroidManifest()
  51. {
  52. string manifestFile = "Assets/Plugins/Android/AndroidManifest.xml";
  53. if (!File.Exists(manifestFile))
  54. {
  55. Debug.LogError("Unable to update manifest because it does not exist! Run \"Create store-compatible AndroidManifest.xml\" first");
  56. return;
  57. }
  58. if (!EditorUtility.DisplayDialog("Update AndroidManifest.xml", "This will overwrite all Oculus specific AndroidManifest Settings. Continue?", "Overwrite", "Cancel"))
  59. {
  60. return;
  61. }
  62. PatchAndroidManifest(manifestFile, skipExistingAttributes: false);
  63. AssetDatabase.Refresh();
  64. }
  65. [MenuItem("Oculus/Tools/Remove AndroidManifest.xml")]
  66. public static void RemoveAndroidManifest()
  67. {
  68. AssetDatabase.DeleteAsset("Assets/Plugins/Android/AndroidManifest.xml");
  69. AssetDatabase.Refresh();
  70. }
  71. private static void AddOrRemoveTag(XmlDocument doc, string @namespace, string path, string elementName, string name, bool required, bool modifyIfFound, params string[] attrs) // name, value pairs
  72. {
  73. var nodes = doc.SelectNodes(path + "/" + elementName);
  74. XmlElement element = null;
  75. foreach (XmlElement e in nodes)
  76. {
  77. if (name == null || name == e.GetAttribute("name", @namespace))
  78. {
  79. element = e;
  80. break;
  81. }
  82. }
  83. if (required)
  84. {
  85. if (element == null)
  86. {
  87. var parent = doc.SelectSingleNode(path);
  88. element = doc.CreateElement(elementName);
  89. element.SetAttribute("name", @namespace, name);
  90. parent.AppendChild(element);
  91. }
  92. for (int i = 0; i < attrs.Length; i += 2)
  93. {
  94. if (modifyIfFound || string.IsNullOrEmpty(element.GetAttribute(attrs[i], @namespace)))
  95. {
  96. if (attrs[i + 1] != null)
  97. {
  98. element.SetAttribute(attrs[i], @namespace, attrs[i + 1]);
  99. }
  100. else
  101. {
  102. element.RemoveAttribute(attrs[i], @namespace);
  103. }
  104. }
  105. }
  106. }
  107. else
  108. {
  109. if (element != null && modifyIfFound)
  110. {
  111. element.ParentNode.RemoveChild(element);
  112. }
  113. }
  114. }
  115. public static void PatchAndroidManifest(string sourceFile, string destinationFile = null, bool skipExistingAttributes = true, bool enableSecurity = false)
  116. {
  117. if (destinationFile == null)
  118. {
  119. destinationFile = sourceFile;
  120. }
  121. bool modifyIfFound = !skipExistingAttributes;
  122. try
  123. {
  124. OVRProjectConfig projectConfig = OVRProjectConfig.GetProjectConfig();
  125. // Load android manfiest file
  126. XmlDocument doc = new XmlDocument();
  127. doc.Load(sourceFile);
  128. string androidNamepsaceURI;
  129. XmlElement element = (XmlElement)doc.SelectSingleNode("/manifest");
  130. if (element == null)
  131. {
  132. UnityEngine.Debug.LogError("Could not find manifest tag in android manifest.");
  133. return;
  134. }
  135. // Get android namespace URI from the manifest
  136. androidNamepsaceURI = element.GetAttribute("xmlns:android");
  137. if (string.IsNullOrEmpty(androidNamepsaceURI))
  138. {
  139. UnityEngine.Debug.LogError("Could not find Android Namespace in manifest.");
  140. return;
  141. }
  142. // remove launcher and leanback launcher
  143. AddOrRemoveTag(doc,
  144. androidNamepsaceURI,
  145. "/manifest/application/activity/intent-filter",
  146. "category",
  147. "android.intent.category.LAUNCHER",
  148. required: false,
  149. modifyIfFound: true); // always remove launcher
  150. AddOrRemoveTag(doc,
  151. androidNamepsaceURI,
  152. "/manifest/application/activity/intent-filter",
  153. "category",
  154. "android.intent.category.LEANBACK_LAUNCHER",
  155. required: false,
  156. modifyIfFound: true); // always remove leanback launcher
  157. // add info category
  158. AddOrRemoveTag(doc,
  159. androidNamepsaceURI,
  160. "/manifest/application/activity/intent-filter",
  161. "category",
  162. "android.intent.category.INFO",
  163. required: true,
  164. modifyIfFound: true); // always add info launcher
  165. // First add or remove headtracking flag if targeting Quest
  166. AddOrRemoveTag(doc,
  167. androidNamepsaceURI,
  168. "/manifest",
  169. "uses-feature",
  170. "android.hardware.vr.headtracking",
  171. OVRDeviceSelector.isTargetDeviceQuest,
  172. modifyIfFound,
  173. "version", "1",
  174. "required", OVRDeviceSelector.isTargetDeviceGearVrOrGo ? "false" : "true");
  175. // If Quest is the target device, add the handtracking manifest tags if needed
  176. // Mapping of project setting to manifest setting:
  177. // OVRProjectConfig.HandTrackingSupport.ControllersOnly => manifest entry not present
  178. // OVRProjectConfig.HandTrackingSupport.ControllersAndHands => manifest entry present and required=false
  179. // OVRProjectConfig.HandTrackingSupport.HandsOnly => manifest entry present and required=true
  180. OVRProjectConfig.HandTrackingSupport targetHandTrackingSupport = OVRProjectConfig.GetProjectConfig().handTrackingSupport;
  181. bool handTrackingEntryNeeded = OVRDeviceSelector.isTargetDeviceQuest && (targetHandTrackingSupport != OVRProjectConfig.HandTrackingSupport.ControllersOnly);
  182. AddOrRemoveTag(doc,
  183. androidNamepsaceURI,
  184. "/manifest",
  185. "uses-feature",
  186. "oculus.software.handtracking",
  187. handTrackingEntryNeeded,
  188. modifyIfFound,
  189. "required", (targetHandTrackingSupport == OVRProjectConfig.HandTrackingSupport.HandsOnly) ? "true" : "false");
  190. AddOrRemoveTag(doc,
  191. androidNamepsaceURI,
  192. "/manifest",
  193. "uses-permission",
  194. "oculus.permission.handtracking",
  195. handTrackingEntryNeeded,
  196. modifyIfFound);
  197. // Add Colorspace metadata if targeting Quest
  198. AddOrRemoveTag(doc,
  199. androidNamepsaceURI,
  200. "/manifest/application",
  201. "meta-data",
  202. "com.oculus.application.colorspace",
  203. OVRDeviceSelector.isTargetDeviceQuest && projectConfig.colorGamut != OVRProjectConfig.ColorGamut.Default,
  204. modifyIfFound,
  205. "value", OVRProjectConfig.ColorGamutToString(projectConfig.colorGamut));
  206. // Add focus aware tag if this app is targeting Quest
  207. AddOrRemoveTag(doc,
  208. androidNamepsaceURI,
  209. "/manifest/application/activity",
  210. "meta-data",
  211. "com.oculus.vr.focusaware",
  212. OVRDeviceSelector.isTargetDeviceQuest,
  213. modifyIfFound,
  214. "value", projectConfig.focusAware ? "true" : "false");
  215. // make sure the VR Mode tag is set in the manifest
  216. AddOrRemoveTag(doc,
  217. androidNamepsaceURI,
  218. "/manifest/application",
  219. "meta-data",
  220. "com.samsung.android.vr.application.mode",
  221. true,
  222. modifyIfFound,
  223. "value", "vr_only");
  224. // make sure android label and icon are set in the manifest
  225. AddOrRemoveTag(doc,
  226. androidNamepsaceURI,
  227. "/manifest",
  228. "application",
  229. null,
  230. true,
  231. modifyIfFound,
  232. "label", "@string/app_name",
  233. #if UNITY_2018_2_OR_NEWER
  234. "icon", "@mipmap/app_icon",
  235. #else
  236. "icon", "@drawable/app_icon",
  237. #endif
  238. // Disable allowBackup in manifest and add Android NSC XML file
  239. "allowBackup", projectConfig.disableBackups ? "false" : "true",
  240. "networkSecurityConfig", projectConfig.enableNSCConfig && enableSecurity ? "@xml/network_sec_config" : null
  241. );
  242. doc.Save(destinationFile);
  243. }
  244. catch (System.Exception e)
  245. {
  246. UnityEngine.Debug.LogException(e);
  247. }
  248. }
  249. }