// %BANNER_BEGIN% // --------------------------------------------------------------------- // %COPYRIGHT_BEGIN% // Copyright (c) 2022-2023 Magic Leap, Inc. All Rights Reserved. // Use of this file is governed by the Magic Leap 2 Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2 // Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein. // %COPYRIGHT_END% // --------------------------------------------------------------------- // %BANNER_END% using UnityEngine; using UnityEditor; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using System.Xml; using System.Linq; using System; using System.Collections.Generic; namespace MagicLeap.Spectator { public class SetupMLSpectator { #if UNITY_EDITOR_WIN private static readonly string AndroidManifestPath = Application.dataPath + "\\Plugins\\Android\\AndroidManifest.xml"; #else private static readonly string AndroidManifestPath = Application.dataPath + "/Plugins/Android/AndroidManifest.xml"; #endif private static readonly string MarkerTrackingPermission = "com.magicleap.permission.MARKER_TRACKING"; private static readonly string RecordAudioPermission = "android.permission.RECORD_AUDIO"; private static readonly string AndroidSchemaURI = "http://schemas.android.com/apk/res/android"; [MenuItem("Magic Leap/Add ML Spectator to Project")] private static void AddMLSpectatorToProject() { // Add required permissions to Android Manifest AddPermissionsToAndroidManifest( new() { MarkerTrackingPermission, RecordAudioPermission }); // Add our MLSpectator prefab to our first or current scene AddMLSpectatorPrefabToFirstOrCurrentScene(); } [MenuItem("Magic Leap/Add ML Spectator with Notifications to Project")] private static void AddMLSpectatorWithNotificationsToProject() { // Add required permissions to Android Manifest AddPermissionsToAndroidManifest( new() { MarkerTrackingPermission, RecordAudioPermission }); // Add our MLSpectator prefab to our first or current scene AddMLSpectatorPrefabToFirstOrCurrentScene(); // Add our Notification prefab to our first or current scene AddNotificationPrefabToFirstOrCurrentScene(); } private static void AddPermissionsToAndroidManifest(List addPermisions) { try { // Open our android manifest XmlDocument manifest = new XmlDocument(); manifest.Load(AndroidManifestPath); // Get a list of our permissions XmlNodeList xmlPermissions = manifest.DocumentElement.SelectNodes("uses-permission "); var permissions = xmlPermissions.Cast(). Select(x => x.GetAttribute("name", AndroidSchemaURI)); // Add the given permissions to the android manifest if they aren't already included foreach (var permission in addPermisions) { if (!permissions.Contains(permission)) { XmlElement markerPermission = manifest.CreateElement("uses-permission"); markerPermission.SetAttribute("name", AndroidSchemaURI, permission); manifest.DocumentElement.AppendChild(markerPermission); Debug.Log($"Added {permission} to Android Manifest"); } else Debug.LogWarning($"Android Manifest already contains {permission}"); } // Save our edited manifest manifest.Save(AndroidManifestPath); } catch (Exception ex) { Debug.LogWarning($"Failed to add permissions to Android Manifest - {ex.Message}"); } } private static void AddMLSpectatorPrefabToFirstOrCurrentScene() { // Find our MLSpectatorPrefabManager MLSpectatorPrefabManagerSO prefabManager = null; string[] guids = AssetDatabase.FindAssets("MLSpectatorPrefabManager"); prefabManager = guids.Select(x => AssetDatabase.LoadAssetAtPath (AssetDatabase.GUIDToAssetPath(x))).FirstOrDefault(); if (!prefabManager) { Debug.LogError("MLSpectatorPrefabManager not found."); return; } // Check if our MLSpectator prefab already exists in our scene Scene scene = EditorSceneManager.GetActiveScene(); var scenePath = SceneUtility.GetScenePathByBuildIndex(0); if (scenePath != null) { try { scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single); } catch { } } int mlSpectatorInstanceID = prefabManager.mlSpectatorPrefab.GetInstanceID(); if (scene.GetRootGameObjects().Where(x => PrefabUtility.GetCorrespondingObjectFromOriginalSource(x)?. GetInstanceID() == mlSpectatorInstanceID).Count() > 0) { Debug.LogWarning($"Scene {scene.name} already contains MLSpectator prefab."); return; } // Add our MLSpectator prefab to our scene, mark it dirty, and save it PrefabUtility.InstantiatePrefab(prefabManager.mlSpectatorPrefab); EditorSceneManager.MarkSceneDirty(scene); EditorSceneManager.SaveScene(scene); Debug.Log($"Added MLSpectator prefab to scene {scene.name}"); } private static void AddNotificationPrefabToFirstOrCurrentScene() { // Find our NotificationPrefabManager NotificationPrefabManagerSO prefabManager = null; string[] guids = AssetDatabase.FindAssets("NotificationPrefabManager"); prefabManager = guids.Select(x => AssetDatabase.LoadAssetAtPath (AssetDatabase.GUIDToAssetPath(x))).FirstOrDefault(); if (!prefabManager) { Debug.LogError("NotificationPrefabManager not found."); return; } // Check if our Notification prefab already exists in our scene Scene scene = EditorSceneManager.GetActiveScene(); var scenePath = SceneUtility.GetScenePathByBuildIndex(0); if (scenePath != null) { try { scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single); } catch { } } int notificationInstanceID = prefabManager.notificationPrefab.GetInstanceID(); if (scene.GetRootGameObjects().Where(x => PrefabUtility.GetCorrespondingObjectFromOriginalSource(x)?. GetInstanceID() == notificationInstanceID).Count() > 0) { Debug.LogWarning($"Scene {scene.name} already contains Notification prefab."); return; } // Add our Notification prefab to our scene, mark it dirty, and save it PrefabUtility.InstantiatePrefab(prefabManager.notificationPrefab); EditorSceneManager.MarkSceneDirty(scene); EditorSceneManager.SaveScene(scene); Debug.Log($"Added Notification prefab to scene {scene.name}"); } } }