private static IEnumerator UpdateLoop(string adbPath) { var renderEventFunc = NativeApi.GetRenderEventFunc(); var shouldConvertToBgra = SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11; var loggedAspectRatioWarning = false; // Waits until the end of the first frame until capturing the screen size, // because it might be incorrect when first querying it. yield return(k_WaitForEndOfFrame); var currentWidth = 0; var currentHeight = 0; var needToStartActivity = true; var prevFrameLandscape = false; RenderTexture screenTexture = null; RenderTexture targetTexture = null; RenderTexture bgrTexture = null; // Begins update loop. The coroutine will cease when the // ARCoreSession component it's called from is destroyed. for (;;) { yield return(k_WaitForEndOfFrame); var curFrameLandscape = Screen.width > Screen.height; if (prevFrameLandscape != curFrameLandscape) { needToStartActivity = true; } prevFrameLandscape = curFrameLandscape; if (needToStartActivity) { string activityName = curFrameLandscape ? "InstantPreviewLandscapeActivity" : "InstantPreviewActivity"; string output; string errors; ShellHelper.RunCommand(adbPath, "shell am start -S -n com.google.ar.core.instantpreview/." + activityName, out output, out errors); needToStartActivity = false; } // Creates a target texture to capture the preview window onto. // Some video encoders prefer the dimensions to be a multiple of 16. var targetWidth = RoundUpToNearestMultipleOf16(Screen.width); var targetHeight = RoundUpToNearestMultipleOf16(Screen.height); if (targetWidth != currentWidth || targetHeight != currentHeight) { screenTexture = new RenderTexture(targetWidth, targetHeight, 0); targetTexture = screenTexture; if (shouldConvertToBgra) { bgrTexture = new RenderTexture(screenTexture.width, screenTexture.height, 0, RenderTextureFormat.BGRA32); targetTexture = bgrTexture; } currentWidth = targetWidth; currentHeight = targetHeight; } NativeApi.Update(); InstantPreviewInput.Update(); AddInstantPreviewTrackedPoseDriverWhenNeeded(); Graphics.Blit(null, screenTexture); if (shouldConvertToBgra) { Graphics.Blit(screenTexture, bgrTexture); } var cameraTexture = Frame.CameraImage.Texture; if (!loggedAspectRatioWarning && cameraTexture != null) { var sourceWidth = cameraTexture.width; var sourceHeight = cameraTexture.height; var sourceAspectRatio = (float)sourceWidth / sourceHeight; var destinationWidth = Screen.width; var destinationHeight = Screen.height; var destinationAspectRatio = (float)destinationWidth / destinationHeight; if (Mathf.Abs(sourceAspectRatio - destinationAspectRatio) > k_MaxTolerableAspectRatioDifference) { Debug.LogWarningFormat(k_MismatchedAspectRatioWarningFormatString, sourceWidth, sourceHeight); loggedAspectRatioWarning = true; } } NativeApi.SendFrame(targetTexture.GetNativeTexturePtr()); GL.IssuePluginEvent(renderEventFunc, 1); } }
/// <summary> /// Tries to install and run the Instant Preview android app. /// </summary> /// <param name="adbPath">Path to adb to use for installing.</param> /// <param name="localVersion">Local version of Instant Preview plugin to compare installed APK against.</param> /// <returns>Enumerator for coroutine that handles installation if necessary.</returns> private static IEnumerator InstallApkAndRunIfConnected(string adbPath, string localVersion) { string apkPath = null; #if UNITY_EDITOR apkPath = UnityEditor.AssetDatabase.GUIDToAssetPath(k_ApkGuid); #endif // !UNITY_EDITOR // Early outs if set to install but the apk can't be found. if (!File.Exists(apkPath)) { Debug.LogErrorFormat("Trying to install Instant Preview APK but reference to InstantPreview.apk is " + "broken. Couldn't find an asset with .meta file guid={0}.", k_ApkGuid); yield break; } Result result = new Result(); #if !UNITY_WSA Thread checkAdbThread = new Thread((object obj) => { Result res = (Result)obj; string output; string errors; // Gets version of installed apk. ShellHelper.RunCommand(adbPath, "shell dumpsys package com.google.ar.core.instantpreview | grep versionName", out output, out errors); string installedVersion = null; if (!string.IsNullOrEmpty(output) && string.IsNullOrEmpty(errors)) { installedVersion = output.Substring(output.IndexOf('=') + 1); } // Early outs if no device is connected. if (string.Compare(errors, k_NoDevicesFoundAdbResult) == 0) { return; } // Prints errors and exits on failure. if (!string.IsNullOrEmpty(errors)) { Debug.LogError(errors); return; } if (installedVersion == null) { Debug.LogFormat( "Instant Preview app not installed on device.", apkPath); } else if (installedVersion != localVersion) { Debug.LogFormat( "Instant Preview installed version \"{0}\" does not match local version \"{1}\".", installedVersion, localVersion); } res.ShouldPromptForInstall = installedVersion != localVersion; }); checkAdbThread.Start(result); while (!checkAdbThread.Join(0)) { yield return(0); } #endif if (result.ShouldPromptForInstall) { if (PromptToInstall()) { #if !UNITY_WSA Thread installThread = new Thread(() => { string output; string errors; Debug.LogFormat( "Installing Instant Preview app version {0}.", localVersion); ShellHelper.RunCommand(adbPath, string.Format("uninstall com.google.ar.core.instantpreview", apkPath), out output, out errors); ShellHelper.RunCommand(adbPath, string.Format("install \"{0}\"", apkPath), out output, out errors); // Prints any output from trying to install. if (!string.IsNullOrEmpty(output)) { Debug.LogFormat("Instant Preview installation\n{0}", output); } if (!string.IsNullOrEmpty(errors)) { Debug.LogErrorFormat("Failed to install Instant Preview app:\n{0}", errors); } }); installThread.Start(); while (!installThread.Join(0)) { yield return(0); } #endif } else { yield break; } } }
private void PreprocessAndroidBuild() { // This function causes build error in 2020.2 if the current directory is changed. // So do the check first here. CheckCompatibilityWithAllSesssionConfigs( ARCoreProjectSettings.Instance, AndroidDependenciesHelper.GetAllSessionConfigs()); string cachedCurrentDirectory = Directory.GetCurrentDirectory(); string pluginsFolderPath = Path.Combine(cachedCurrentDirectory, AssetDatabase.GUIDToAssetPath(_pluginsFolderGuid)); string customizedManifestAarPath = Path.Combine(pluginsFolderPath, "customized_manifest.aar"); string jarPath = Path.Combine(AndroidDependenciesHelper.GetJdkPath(), "bin/jar"); var tempDirectoryPath = Path.Combine(cachedCurrentDirectory, FileUtil.GetUniqueTempPathInProject()); try { // Move to a temp directory. Directory.CreateDirectory(tempDirectoryPath); Directory.SetCurrentDirectory(tempDirectoryPath); CreateClassesJar(jarPath, tempDirectoryPath); XDocument customizedManifest = GenerateCustomizedAndroidManifest(ARCoreProjectSettings.Instance); var manifestPath = Path.Combine(tempDirectoryPath, "AndroidManifest.xml"); customizedManifest.Save(manifestPath); // Compress the new AAR. var fileListBuilder = new StringBuilder(); foreach (var filePath in Directory.GetFiles(tempDirectoryPath)) { fileListBuilder.AppendFormat(" {0}", Path.GetFileName(filePath)); } string command = string.Format( "cf customized_manifest.aar {0}", fileListBuilder.ToString()); string output; string errors; ShellHelper.RunCommand(jarPath, command, out output, out errors); if (!string.IsNullOrEmpty(errors)) { throw new BuildFailedException( string.Format( "Error creating aar for manifest: {0}", errors)); } File.Copy(Path.Combine(tempDirectoryPath, "customized_manifest.aar"), customizedManifestAarPath, true); } finally { // Cleanup. Directory.SetCurrentDirectory(cachedCurrentDirectory); Directory.Delete(tempDirectoryPath, true); AssetDatabase.Refresh(); } AssetHelper.GetPluginImporterByName("customized_manifest.aar") .SetCompatibleWithPlatform(BuildTarget.Android, true); }
/// <summary> /// Coroutine method that communicates to the Instant Preview plugin /// every frame. /// /// If Instant Preview is not the providing platform, this does nothing. /// </summary> /// <returns>Enumerator for a coroutine that updates Instant Preview /// every frame.</returns> public static IEnumerator InitializeIfNeeded() { // Terminates if instant preview is not providing the platform. if (!IsProvidingPlatform) { yield break; } // User may have explicitly disabled Instant Preview. if (ARCoreProjectSettings.Instance != null && !ARCoreProjectSettings.Instance.IsInstantPreviewEnabled) { yield break; } #if UNITY_EDITOR // When build platform is not Android, verify min game view scale is 1.0x to prevent // confusing 2x scaling when Unity editor is running on a high density display. if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android) { float minGameViewScale = GetMinGameViewScaleOrUnknown(); if (minGameViewScale != 1.0) { String viewScaleText = minGameViewScale == k_UnknownGameViewScale ? "<unknown>" : string.Format("{0}x", minGameViewScale); Debug.LogWarningFormat( "Instant Preview disabled, {0} minimum Game view scale unsupported for " + "target build platform '{1}'.\n" + "To use Instant Preview, switch build platform to '{2}' from the 'Build " + "settings' window.", viewScaleText, EditorUserBuildSettings.activeBuildTarget, BuildTarget.Android); yield break; } } // Determine if any augmented image databases need a rebuild. List <AugmentedImageDatabase> databases = new List <AugmentedImageDatabase>(); bool shouldRebuild = false; var augmentedImageDatabaseGuids = AssetDatabase.FindAssets("t:AugmentedImageDatabase"); foreach (var databaseGuid in augmentedImageDatabaseGuids) { var database = AssetDatabase.LoadAssetAtPath <AugmentedImageDatabase>( AssetDatabase.GUIDToAssetPath(databaseGuid)); databases.Add(database); shouldRebuild = shouldRebuild || database.IsBuildNeeded(); } // If the preference is to ask the user to rebuild, ask now. if (shouldRebuild && PromptToRebuildAugmentedImagesDatabase()) { foreach (var database in databases) { string error; database.BuildIfNeeded(out error); if (!string.IsNullOrEmpty(error)) { Debug.LogWarning("Failed to rebuild augmented image database: " + error); } } } #endif var adbPath = ShellHelper.GetAdbPath(); if (adbPath == null) { Debug.LogError("Instant Preview requires your Unity Android SDK path to be set. " + "Please set it under 'Preferences > External Tools > Android'. " + "You may need to install the Android SDK first."); yield break; } else if (!File.Exists(adbPath)) { Debug.LogErrorFormat( "adb not found at \"{0}\". Please verify that 'Preferences > External Tools " + "> Android' has the correct Android SDK path that the Android Platform Tools " + "are installed, and that \"{0}\" exists. You may need to install the Android " + "SDK first.", adbPath); yield break; } if (Environment.GetEnvironmentVariable("ADB_TRACE") != null) { Debug.LogWarning("Instant Preview: ADB_TRACE was defined. Unsetting environment " + "variable for compatibility with Instant Preview."); Environment.SetEnvironmentVariable("ADB_TRACE", null); } string localVersion; if (!StartServer(adbPath, out localVersion)) { yield break; } yield return(InstallApkAndRunIfConnected(adbPath, localVersion)); yield return(UpdateLoop(adbPath)); }
private void _PreprocessAndroidBuild() { // Get the Jdk path. var jdkPath = UnityEditor.EditorPrefs.GetString("JdkPath"); if (string.IsNullOrEmpty(jdkPath)) { Debug.Log("JDK path Unity pref is not set. Falling back to JAVA_HOME environment variable."); jdkPath = System.Environment.GetEnvironmentVariable("JAVA_HOME"); } if (string.IsNullOrEmpty(jdkPath)) { throw new BuildFailedException("A JDK path needs to be specified for the Android build."); } bool cloudAnchorsEnabled = !string.IsNullOrEmpty(ARCoreProjectSettings.Instance.CloudServicesApiKey); var cachedCurrentDirectory = Directory.GetCurrentDirectory(); var pluginsFolderPath = Path.Combine(cachedCurrentDirectory, AssetDatabase.GUIDToAssetPath(k_PluginsFolderGuid)); string cloudAnchorsManifestAarPath = Path.Combine(pluginsFolderPath, "cloud_anchor_manifest.aar"); var jarPath = Path.Combine(jdkPath, "bin/jar"); if (cloudAnchorsEnabled) { // If the Api Key didn't change then do nothing. if (!_IsApiKeyDirty(jarPath, cloudAnchorsManifestAarPath, ARCoreProjectSettings.Instance.CloudServicesApiKey)) { return; } // Replace the project's cloud anchor AAR with the newly generated AAR. Debug.Log("Enabling Cloud Anchors in this build."); var tempDirectoryPath = Path.Combine(cachedCurrentDirectory, FileUtil.GetUniqueTempPathInProject()); try { // Move to a temp directory. Directory.CreateDirectory(tempDirectoryPath); Directory.SetCurrentDirectory(tempDirectoryPath); var manifestTemplatePath = Path.Combine(cachedCurrentDirectory, AssetDatabase.GUIDToAssetPath(k_ManifestTemplateGuid)); // Extract the "template AAR" and remove it. string output; string errors; ShellHelper.RunCommand(jarPath, string.Format("xf \"{0}\"", manifestTemplatePath), out output, out errors); // Replace Api key template parameter in manifest file. var manifestPath = Path.Combine(tempDirectoryPath, "AndroidManifest.xml"); var manifestText = File.ReadAllText(manifestPath); manifestText = manifestText.Replace("{{CLOUD_ANCHOR_API_KEY}}", ARCoreProjectSettings.Instance.CloudServicesApiKey); File.WriteAllText(manifestPath, manifestText); // Compress the new AAR. var fileListBuilder = new StringBuilder(); foreach (var filePath in Directory.GetFiles(tempDirectoryPath)) { fileListBuilder.AppendFormat(" {0}", Path.GetFileName(filePath)); } ShellHelper.RunCommand(jarPath, string.Format("cf cloud_anchor_manifest.aar {0}", fileListBuilder.ToString()), out output, out errors); if (!string.IsNullOrEmpty(errors)) { throw new BuildFailedException( string.Format("Error creating jar for cloud anchor manifest: {0}", errors)); } File.Copy(Path.Combine(tempDirectoryPath, "cloud_anchor_manifest.aar"), cloudAnchorsManifestAarPath, true); } finally { // Cleanup. Directory.SetCurrentDirectory(cachedCurrentDirectory); Directory.Delete(tempDirectoryPath, true); AssetDatabase.Refresh(); } AssetHelper.GetPluginImporterByName("cloud_anchor_manifest.aar") .SetCompatibleWithPlatform(BuildTarget.Android, true); } else { Debug.Log("A cloud anchor API key has not been set. Cloud anchors are disabled in this build."); File.Delete(cloudAnchorsManifestAarPath); AssetDatabase.Refresh(); } }
private static void RunDirtyQualityJobs(AugmentedImageDatabase database) { if (database == null) { return; } if (_databaseForQualityJobs != database) { // If another database is already running quality evaluation, // stop all pending jobs to prioritise the current database. if (_databaseForQualityJobs != null) { _qualityBackgroundExecutor.RemoveAllPendingJobs(); } _databaseForQualityJobs = database; } UpdateDatabaseQuality(database); // Set database dirty to refresh inspector UI for each frame that there are still // pending jobs. // Otherwise if there exists one frame with no newly finished jobs, the UI will never // get refreshed. // EditorUtility.SetDirty can only be called from main thread. if (_qualityBackgroundExecutor.PendingJobsCount > 0) { EditorUtility.SetDirty(database); return; } List <AugmentedImageDatabaseEntry> dirtyEntries = database.GetDirtyQualityEntries(); if (dirtyEntries.Count == 0) { return; } string cliBinaryPath; if (!AugmentedImageDatabase.FindCliBinaryPath(out cliBinaryPath)) { return; } for (int i = 0; i < dirtyEntries.Count; ++i) { AugmentedImageDatabaseEntry image = dirtyEntries[i]; var imagePath = AssetDatabase.GetAssetPath(image.Texture); var textureGUID = image.TextureGUID; _qualityBackgroundExecutor.PushJob(() => { string quality; string error; ShellHelper.RunCommand( cliBinaryPath, string.Format("eval-img --input_image_path \"{0}\"", imagePath), out quality, out error); if (!string.IsNullOrEmpty(error)) { Debug.LogError(error); quality = "ERROR"; } lock (_updatedQualityScores) { _updatedQualityScores.Add(textureGUID, quality); } }); } // For refreshing inspector UI as new jobs have been enqueued. EditorUtility.SetDirty(database); }
private void SetApiKeyOnAndroid() { string cachedCurrentDirectory = Directory.GetCurrentDirectory(); string pluginsFolderPath = Path.Combine(cachedCurrentDirectory, AssetDatabase.GUIDToAssetPath(_pluginsFolderGuid)); string cloudAnchorsManifestAarPath = Path.Combine(pluginsFolderPath, "cloud_anchor_manifest.aar"); bool cloudAnchorsEnabled = !string.IsNullOrEmpty(ARCoreProjectSettings.Instance.CloudServicesApiKey); if (cloudAnchorsEnabled) { string jarPath = AndroidDependenciesHelper.GetJdkPath(); if (string.IsNullOrEmpty(jarPath)) { throw new BuildFailedException("Cannot find a valid JDK path in this build."); } jarPath = Path.Combine(jarPath, "bin/jar"); // If the API Key didn't change then do nothing. if (!IsApiKeyDirty(jarPath, cloudAnchorsManifestAarPath, ARCoreProjectSettings.Instance.CloudServicesApiKey)) { return; } // Replace the project's cloud anchor AAR with the newly generated AAR. Debug.Log("Enabling Cloud Anchors with API Key Authentication in this build."); var tempDirectoryPath = Path.Combine(cachedCurrentDirectory, FileUtil.GetUniqueTempPathInProject()); try { // Move to a temp directory. Directory.CreateDirectory(tempDirectoryPath); Directory.SetCurrentDirectory(tempDirectoryPath); var manifestTemplatePath = Path.Combine( cachedCurrentDirectory, AssetDatabase.GUIDToAssetPath(_manifestTemplateGuid)); // Extract the "template AAR" and remove it. string output; string errors; ShellHelper.RunCommand( jarPath, string.Format("xf \"{0}\"", manifestTemplatePath), out output, out errors); // Replace Api key template parameter in manifest file. var manifestPath = Path.Combine(tempDirectoryPath, "AndroidManifest.xml"); var manifestText = File.ReadAllText(manifestPath); manifestText = manifestText.Replace( "{{CLOUD_ANCHOR_API_KEY}}", ARCoreProjectSettings.Instance.CloudServicesApiKey); File.WriteAllText(manifestPath, manifestText); // Compress the new AAR. var fileListBuilder = new StringBuilder(); foreach (var filePath in Directory.GetFiles(tempDirectoryPath)) { fileListBuilder.AppendFormat(" {0}", Path.GetFileName(filePath)); } string command = string.Format( "cf cloud_anchor_manifest.aar {0}", fileListBuilder.ToString()); ShellHelper.RunCommand( jarPath, command, out output, out errors); if (!string.IsNullOrEmpty(errors)) { throw new BuildFailedException( string.Format( "Error creating jar for cloud anchor manifest: {0}", errors)); } File.Copy(Path.Combine(tempDirectoryPath, "cloud_anchor_manifest.aar"), cloudAnchorsManifestAarPath, true); } finally { // Cleanup. Directory.SetCurrentDirectory(cachedCurrentDirectory); Directory.Delete(tempDirectoryPath, true); AssetDatabase.Refresh(); } AssetHelper.GetPluginImporterByName("cloud_anchor_manifest.aar") .SetCompatibleWithPlatform(BuildTarget.Android, true); } else { Debug.Log( "Cloud Anchor API key has not been set in this build."); File.Delete(cloudAnchorsManifestAarPath); AssetDatabase.Refresh(); } }
private void StripAndBackupClientAar() { // Strip the <queries> tag from the arcore_client.aar when it's incompatible with // Unity's built-in gradle version. string cachedCurrentDirectory = Directory.GetCurrentDirectory(); string pluginsFolderPath = Path.Combine(cachedCurrentDirectory, AssetDatabase.GUIDToAssetPath(_pluginsFolderGuid)); string[] plugins = Directory.GetFiles(pluginsFolderPath); string clientAarPath = string.Empty; foreach (var pluginPath in plugins) { if (pluginPath.Contains(_clientAarName) && !pluginPath.Contains(".meta") && AssetHelper.GetPluginImporterByName(Path.GetFileName(pluginPath)) .GetCompatibleWithPlatform(BuildTarget.Android)) { clientAarPath = pluginPath; break; } } if (string.IsNullOrEmpty(clientAarPath)) { throw new BuildFailedException( string.Format("Cannot find a valid arcore client plugin under '{0}'", pluginsFolderPath)); } string clientAarFileName = Path.GetFileName(clientAarPath); string jarPath = AndroidDependenciesHelper.GetJdkPath(); if (string.IsNullOrEmpty(jarPath)) { throw new BuildFailedException("Cannot find a valid JDK path in this build."); } jarPath = Path.Combine(jarPath, "bin/jar"); var tempDirectoryPath = Path.Combine(cachedCurrentDirectory, FileUtil.GetUniqueTempPathInProject()); // Back up existing client AAR. string backupFilename = clientAarFileName + _backupExtension; Debug.LogFormat("Backing up {0} in {1}.", clientAarFileName, backupFilename); File.Copy(clientAarPath, Path.Combine(pluginsFolderPath, backupFilename), true); _hasBackup = true; Debug.LogFormat("Stripping the <queries> tag from {0} in this build.", clientAarFileName); try { // Move to a temp directory. Directory.CreateDirectory(tempDirectoryPath); Directory.SetCurrentDirectory(tempDirectoryPath); // Extract the existing AAR in the temp directory. string output; string errors; ShellHelper.RunCommand( jarPath, string.Format("xf \"{0}\"", clientAarPath), out output, out errors); // Strip the <queries> tag from AndroidManifest.xml. var manifestPath = Path.Combine(tempDirectoryPath, "AndroidManifest.xml"); var manifestText = File.ReadAllText(manifestPath); manifestText = System.Text.RegularExpressions.Regex.Replace( manifestText, "(/s)?<queries>(.*)</queries>(\n|\r|\r\n)", string.Empty, System.Text.RegularExpressions.RegexOptions.Singleline); File.WriteAllText(manifestPath, manifestText); // Compress the modified AAR. string command = string.Format("cf {0} .", clientAarFileName); ShellHelper.RunCommand( jarPath, command, out output, out errors); if (!string.IsNullOrEmpty(errors)) { throw new BuildFailedException( string.Format( "Error creating jar for stripped arcore client manifest: {0}", errors)); } // Override the existing client AAR with the modified one. File.Copy(Path.Combine(tempDirectoryPath, clientAarFileName), clientAarPath, true); } finally { // Cleanup. Directory.SetCurrentDirectory(cachedCurrentDirectory); Directory.Delete(tempDirectoryPath, true); AssetDatabase.Refresh(); } AssetHelper.GetPluginImporterByName(clientAarFileName) .SetCompatibleWithPlatform(BuildTarget.Android, true); }
private static void CaptureBugReport() { string desktopPath = Environment.GetFolderPath( Environment.SpecialFolder.Desktop); DateTime timeStamp = DateTime.Now; string fileNameTimestamp = timeStamp.ToString("yyyyMMdd_hhmmss"); string filePath = Path.Combine( desktopPath, _fileNamePrefix + fileNameTimestamp + ".txt"); StreamWriter writer; // Operating system and hardware info have to be handled separately based on OS switch (SystemInfo.operatingSystemFamily) { case OperatingSystemFamily.MacOSX: writer = File.CreateText(filePath); writer.WriteLine("*** GOOGLE ARCORE SDK FOR UNITY OSX BUG REPORT ***"); writer.WriteLine("Timestamp: " + timeStamp.ToString()); writer.WriteLine(); writer.WriteLine("*** OPERATING SYSTEM INFORMATION ***"); WriteCommand("system_profiler", "SPSoftwareDataType", writer); writer.WriteLine("*** GRAPHICS INFORMATION ***"); WriteCommand("system_profiler", "SPDisplaysDataType", writer); WriteOsIndependentFields(writer); string stdOut; string stdErr; // Get PATH directories to search for adb in. ShellHelper.RunCommand( "/bin/bash", "-c -l \"echo $PATH\"", out stdOut, out stdErr); stdOut.Trim(); writer.WriteLine("*** ADB VERSIONS ON PATH ***"); WriteAdbPathVersions(stdOut.Split(':'), writer); writer.WriteLine("*** TYPE -A ADB ***"); WriteCommand("/bin/bash", "-c -l \"type -a adb\"", writer); writer.WriteLine("*** RUNNING ADB PROCESSES ***"); WriteCommand( "/bin/bash", "-c -l \"ps -ef | grep -i adb | grep -v grep\"", writer); writer.WriteLine("*** RUNNING UNITY PROCESSES ***"); WriteCommand( "/bin/bash", "-c -l \"ps -ef | grep -i Unity | grep -v grep\"", writer); writer.Close(); Debug.Log( "ARCore bug report captured. File can be found here:\n" + Path.GetFullPath(filePath)); break; case OperatingSystemFamily.Windows: writer = File.CreateText(filePath); writer.WriteLine("*** GOOGLE ARCORE SDK FOR UNITY WINDOWS BUG REPORT ***"); writer.WriteLine("Timestamp: " + timeStamp.ToString()); writer.WriteLine("*** OPERATING SYSTEM INFORMATION ***"); WriteCommand("cmd.exe", "/C systeminfo", writer); writer.WriteLine("*** GRAPHICS INFORMATION ***"); WriteCommand( "cmd.exe", "/C wmic path win32_VideoController get /format:list", writer); WriteOsIndependentFields(writer); string pathStr = Environment.GetEnvironmentVariable("PATH").Trim(); writer.WriteLine("*** ADB VERSIONS ON PATH ***"); WriteAdbPathVersions(pathStr.Split(';'), writer); writer.WriteLine("*** RUNNING ADB PROCESSES ***"); WriteCommand("cmd.exe", "/C TASKLIST | c:\\Windows\\System32\\findstr.exe \"adb\"", writer); writer.WriteLine("*** RUNNING UNITY PROCESSES ***"); WriteCommand("cmd.exe", "/C TASKLIST | c:\\Windows\\System32\\findstr.exe \"Unity\"", writer); writer.Close(); Debug.Log( "ARCore bug report captured. File can be found here:\n" + Path.GetFullPath(filePath)); break; default: string dialogMessage = "ARCore does not support capturing bug reports for " + SystemInfo.operatingSystemFamily + " at this time."; EditorUtility.DisplayDialog("ARCore Bug Report", dialogMessage, "OK"); break; } }