diff --git a/Editor/BuildResources/ARCoreAndroidKeylessDependencies.template b/Editor/BuildResources/ARCoreAndroidKeylessDependencies.template deleted file mode 100755 index dc3b26c..0000000 --- a/Editor/BuildResources/ARCoreAndroidKeylessDependencies.template +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/Editor/BuildResources/ARCoreiOSDependencies.template b/Editor/BuildResources/ARCoreiOSDependencies.template index b5b32e5..3f53217 100755 --- a/Editor/BuildResources/ARCoreiOSDependencies.template +++ b/Editor/BuildResources/ARCoreiOSDependencies.template @@ -1,6 +1,6 @@ - + diff --git a/Editor/BuildResources/cloud_anchor_manifest.aartemplate b/Editor/BuildResources/cloud_anchor_manifest.aartemplate deleted file mode 100755 index 83206f2..0000000 Binary files a/Editor/BuildResources/cloud_anchor_manifest.aartemplate and /dev/null differ diff --git a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs b/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs index 65ab57c..633a1cf 100755 --- a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs +++ b/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs @@ -20,6 +20,7 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal { + using Google.XR.ARCoreExtensions.Internal; using UnityEditor; using UnityEngine; diff --git a/Editor/Scripts/Internal/AndroidDependenciesHelper.cs b/Editor/Scripts/Internal/AndroidDependenciesHelper.cs index 0097fe8..3e095ec 100755 --- a/Editor/Scripts/Internal/AndroidDependenciesHelper.cs +++ b/Editor/Scripts/Internal/AndroidDependenciesHelper.cs @@ -39,8 +39,6 @@ public static class AndroidDependenciesHelper // Editor/Google.JarResolver_{version}.dll.meta private const string _jarResolverGuid = "a8f371f579f2426d93a8c958438275b7"; - private static readonly string _templateFileExtension = ".template"; - private static readonly string _playServiceDependencyFileExtension = ".xml"; /// /// Gets all session configs from active scenes. @@ -113,50 +111,6 @@ public static void SetAndroidPluginEnabled(bool enabledDependencies, pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, enabledDependencies); } - /// - /// Handle the addition or removal Android dependencies using the ExternalDependencyManager. - /// Adding the dependencies is done by renaming the dependencies .template file to a .xml - /// file so that it will be picked up by the ExternalDependencyManager plugin. - /// - /// If set to true enabled dependencies. - /// Dependencies template GUID. - public static void UpdateAndroidDependencies(bool enabledDependencies, - string dependenciesTemplateGuid) - { - string dependenciesTemplatePath = - AssetDatabase.GUIDToAssetPath(dependenciesTemplateGuid); - if (dependenciesTemplatePath == null) - { - Debug.LogError( - "ARCoreExtensions: Failed to enable Android dependencies xml. " + - "Template file is missing."); - return; - } - - string dependenciesXMLPath = dependenciesTemplatePath.Replace( - _templateFileExtension, _playServiceDependencyFileExtension); - - if (enabledDependencies && !File.Exists(dependenciesXMLPath)) - { - Debug.LogFormat( - "Adding {0}.", - System.IO.Path.GetFileNameWithoutExtension(dependenciesTemplatePath)); - - File.Copy(dependenciesTemplatePath, dependenciesXMLPath); - AssetDatabase.Refresh(); - } - else if (!enabledDependencies && File.Exists(dependenciesXMLPath)) - { - Debug.LogFormat( - "Removing {0}.", - System.IO.Path.GetFileNameWithoutExtension(dependenciesTemplatePath)); - - File.Delete(dependenciesXMLPath); - File.Delete(dependenciesXMLPath + ".meta"); - AssetDatabase.Refresh(); - } - } - /// /// Uses reflection to find the GooglePlayServices.PlayServicesResolver class and invoke /// the public static method, MenuResolve() in order to resolve dependencies change. diff --git a/Editor/Scripts/Internal/AndroidKeylessPreprocessBuild.cs b/Editor/Scripts/Internal/AndroidKeylessPreprocessBuild.cs deleted file mode 100755 index c8153c4..0000000 --- a/Editor/Scripts/Internal/AndroidKeylessPreprocessBuild.cs +++ /dev/null @@ -1,131 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -namespace Google.XR.ARCoreExtensions.Editor.Internal -{ - using System.Diagnostics.CodeAnalysis; - using UnityEditor; - using UnityEditor.Build; - using UnityEditor.Build.Reporting; - using UnityEditor.Callbacks; - using UnityEngine; - - /// - /// This handles the addition and removal of dependencies into the App's build. - /// For BatchMode builds, perform clean after a build is complete. - /// - public class AndroidKeylessPreprocessBuild : IPreprocessBuildWithReport - { - private const string _androidKeylessDependenciesGuid = "1fc346056f53a42949a3dcadaae39d67"; - - /// - /// Gets Callback order. - /// - [SuppressMessage("UnityRules.UnityStyleRules", - "US1109:PublicPropertiesMustBeUpperCamelCase", Justification = "Overriden property.")] - public int callbackOrder - { - get - { - return 0; - } - } - - /// - /// Callback after the build is done. - /// - /// Build target platform. - /// Path to build project. - [PostProcessBuild(1)] - public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) - { - if (target == BuildTarget.Android && IsKeylessAuthenticationEnabled()) - { - PostprocessAndroidBuild(); - } - } - - /// - /// Preprocess step for Android Build. - /// - /// Whether to enable or disable keyless. - public static void PreprocessAndroidBuild(bool enabledKeyless) - { - AndroidDependenciesHelper.UpdateAndroidDependencies( - enabledKeyless, _androidKeylessDependenciesGuid); - - if (enabledKeyless) - { - Debug.Log("ARCoreExtensions: Including Keyless dependencies in this build."); - AndroidDependenciesHelper.DoPlayServicesResolve(); - } - } - - /// - /// Callback before the build is started. - /// - /// A report containing information about the build, - /// such as its target platform and output path. - public void OnPreprocessBuild(BuildReport report) - { - if (report.summary.platform == BuildTarget.Android) - { - if (IsKeylessAuthenticationEnabled()) - { - Debug.Log("ARCoreExtensions: " + - "Enabling Cloud Anchors with Keyless Authentication in this build."); - } - - PreprocessAndroidBuild(IsKeylessAuthenticationEnabled()); - } - } - - private static void PostprocessAndroidBuild() - { - Debug.Log("ARCoreExtensions: Cleaning up Keyless dependencies."); - - // Run the pre-process step with Keyless disabled so project files get reset. - // Then run the ExternalDependencyManager dependency resolution which will remove - // the Keyless dependencies. - PreprocessAndroidBuild(false); - AndroidDependenciesHelper.DoPlayServicesResolve(); - } - - private static bool IsKeylessAuthenticationEnabled() - { - return ARCoreExtensionsProjectSettings.Instance.AndroidAuthenticationStrategySetting == - AndroidAuthenticationStrategy.Keyless && IsCloudAnchorModeEnabled(); - } - - private static bool IsCloudAnchorModeEnabled() - { - foreach (ARCoreExtensionsConfig config in - AndroidDependenciesHelper.GetAllSessionConfigs().Keys) - { - if (config.CloudAnchorMode != CloudAnchorMode.Disabled) - { - return true; - } - } - - return false; - } - } -} diff --git a/Editor/Scripts/Internal/AndroidSupportPreprocessBuild.cs b/Editor/Scripts/Internal/AndroidSupportPreprocessBuild.cs index b719353..66d8e38 100755 --- a/Editor/Scripts/Internal/AndroidSupportPreprocessBuild.cs +++ b/Editor/Scripts/Internal/AndroidSupportPreprocessBuild.cs @@ -89,7 +89,7 @@ private bool CheckARCoreLoader() return false; } - foreach (var loader in generalSettings.Manager.loaders) + foreach (var loader in generalSettings.Manager.activeLoaders) { if (loader is ARCoreLoader) { diff --git a/Editor/Scripts/Internal/CloudAnchorPreprocessBuild.cs b/Editor/Scripts/Internal/CloudAnchorPreprocessBuild.cs deleted file mode 100755 index 148c6f9..0000000 --- a/Editor/Scripts/Internal/CloudAnchorPreprocessBuild.cs +++ /dev/null @@ -1,259 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -namespace Google.XR.ARCoreExtensions.Editor.Internal -{ - using System.Diagnostics.CodeAnalysis; - using System.IO; - using System.Text; - using System.Xml; - using Google.XR.ARCoreExtensions.Internal; - using UnityEditor; - using UnityEditor.Build; - using UnityEditor.Build.Reporting; - using UnityEditor.Callbacks; - using UnityEngine; - - /// - /// Build preprocess for Cloud Anchor. - /// - [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", - Justification = "Internal")] - public class CloudAnchorPreprocessBuild : IPreprocessBuildWithReport - { - private const string _cloudAnchorManifestFileName = "cloud_anchor_manifest.aar"; - - // GUID of folder [ARCore Extensions Package]/Editor/BuildResources/ - private const string _manifestTemplateFolderGUID = "117437286c43f4eeb845c3257f2a8546"; - - // GUID of folder [ARCore Extensions Package]/Runtime/Plugins/ - private const string _pluginsFolderGUID = "7503bf199a08d47b681b4e1496fae841"; - - [SuppressMessage("UnityRules.UnityStyleRules", - "US1109:PublicPropertiesMustBeUpperCamelCase", Justification = "Overriden property.")] - public int callbackOrder - { - get - { - return 0; - } - } - - public void OnPreprocessBuild(BuildReport report) - { - if (report.summary.platform == UnityEditor.BuildTarget.Android) - { - PreprocessAndroidBuild(); - } - else if (report.summary.platform == UnityEditor.BuildTarget.iOS) - { - PreprocessIOSBuild(); - } - } - - public void PreprocessAndroidBuild() - { - SetApiKeyOnAndroid(); - } - - public void PreprocessIOSBuild() - { - SetApiKeyOnIOS(); - } - - private void SetApiKeyOnAndroid() - { - bool cloudAnchorsEnabled = !string.IsNullOrEmpty( - ARCoreExtensionsProjectSettings.Instance.AndroidCloudServicesApiKey); - - var cachedCurrentDirectory = Directory.GetCurrentDirectory(); - var cloudAnchorsManifestAARPath = Path.GetFullPath( - Path.Combine(AssetDatabase.GUIDToAssetPath(_pluginsFolderGUID), - _cloudAnchorManifestFileName)); - - 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, - ARCoreExtensionsProjectSettings.Instance.AndroidCloudServicesApiKey)) - { - 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 - { - // Locate cloud_anchor_manifest.aartemplate from the package cache. - var manifestTemplatePath = Path.GetFullPath( - Path.Combine(AssetDatabase.GUIDToAssetPath(_manifestTemplateFolderGUID), - _cloudAnchorManifestFileName + "template")); - - // Move to a temp directory. - Directory.CreateDirectory(tempDirectoryPath); - Directory.SetCurrentDirectory(tempDirectoryPath); - - // 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}}", - ARCoreExtensionsProjectSettings.Instance.AndroidCloudServicesApiKey); - 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 {0} {1}", _cloudAnchorManifestFileName, fileListBuilder); - - 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, _cloudAnchorManifestFileName), - cloudAnchorsManifestAARPath, true); - } - finally - { - // Cleanup. - Directory.SetCurrentDirectory(cachedCurrentDirectory); - Directory.Delete(tempDirectoryPath, true); - - AssetDatabase.Refresh(); - } - - AssetHelper.GetPluginImporterByName(_cloudAnchorManifestFileName) - .SetCompatibleWithPlatform(BuildTarget.Android, true); - } - else - { - Debug.Log( - "Cloud Anchor API key has not been set. API key authentication will " + - "be disabled in this build."); - if (File.Exists(cloudAnchorsManifestAARPath)) - { - File.Delete(cloudAnchorsManifestAARPath); - } - - AssetDatabase.Refresh(); - } - } - - private void SetApiKeyOnIOS() - { - if (string.IsNullOrEmpty( - ARCoreExtensionsProjectSettings.Instance.IOSCloudServicesApiKey)) - { - RuntimeConfig.SetIOSApiKey(string.Empty); - return; - } - - if (!ARCoreExtensionsProjectSettings.Instance.IsIOSSupportEnabled) - { - Debug.LogWarning("Failed to enable Cloud Anchor on iOS because iOS Support " + - "is not enabled. Go to 'Project Settings > XR > ARCore Extensionts' " + - "to change the settings."); - RuntimeConfig.SetIOSApiKey(string.Empty); - return; - } - - RuntimeConfig.SetIOSApiKey( - ARCoreExtensionsProjectSettings.Instance.IOSCloudServicesApiKey); - } - - private bool IsApiKeyDirty(string jarPath, string aarPath, string apiKey) - { - bool isApiKeyDirty = true; - var cachedCurrentDirectory = Directory.GetCurrentDirectory(); - var tempDirectoryPath = - Path.Combine(cachedCurrentDirectory, FileUtil.GetUniqueTempPathInProject()); - - if (!File.Exists(aarPath)) - { - return isApiKeyDirty; - } - - try - { - // Move to a temp directory. - Directory.CreateDirectory(tempDirectoryPath); - Directory.SetCurrentDirectory(tempDirectoryPath); - var tempAarPath = Path.Combine(tempDirectoryPath, _cloudAnchorManifestFileName); - File.Copy(aarPath, tempAarPath, true); - - // Extract the aar. - string output; - string errors; - ShellHelper.RunCommand(jarPath, string.Format("xf \"{0}\"", tempAarPath), - out output, out errors); - - // Read API key parameter in manifest file. - var manifestPath = Path.Combine(tempDirectoryPath, "AndroidManifest.xml"); - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(manifestPath); - XmlNode metaDataNode = - xmlDocument.SelectSingleNode("/manifest/application/meta-data"); - string oldApiKey = metaDataNode.Attributes["android:value"].Value; - isApiKeyDirty = !apiKey.Equals(oldApiKey); - } - finally - { - // Cleanup. - Directory.SetCurrentDirectory(cachedCurrentDirectory); - Directory.Delete(tempDirectoryPath, true); - } - - return isApiKeyDirty; - } - } -} diff --git a/Editor/Scripts/Internal/DependentModules/DependentModuleBase.cs b/Editor/Scripts/Internal/DependentModules/DependentModuleBase.cs deleted file mode 100755 index ee388e0..0000000 --- a/Editor/Scripts/Internal/DependentModules/DependentModuleBase.cs +++ /dev/null @@ -1,83 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -namespace Google.XR.ARCoreExtensions.Editor.Internal -{ - using System; - using System.Xml; - using UnityEngine; - - /// - /// The interface needed for a feature module. - /// - public class DependentModuleBase : IDependentModule - { - /// - /// Checking whether it needs to be included in the customized AndroidManifest. - /// The default values for new fields in ARCoreExtensionsProjectSettings should cause the - /// associated module to return false. - /// - /// ARCore Extensions Project Settings. - /// The boolean shows whether the module is enabled. - public virtual bool IsEnabled(ARCoreExtensionsProjectSettings settings) - { - return false; - } - - /// - /// Return the XML snippet to include if this module is enabled. The string output will be - /// added as a child node of the ‘manifest’ node of the customized AndroidManifest.xml. - /// The android namespace will be available. - /// - /// ARCore Extensions Project Settings. - /// The XML string snippet to add as a child of node 'manifest'. - public virtual string GetAndroidManifestSnippet(ARCoreExtensionsProjectSettings settings) - { - return string.Empty; - } - - /// - /// Checking whether this module is compatible with given ARCoreExtensionsConfig. - /// If it returns false, the preprocessbuild will throw a general Build Failure Error. - /// A feature developer should use this function to log detailed error messages that - /// also include a recommendation of how to resolve the issue. - /// - /// ARCore Extensions Project Settings. - /// ARCore Extensions Config. - /// The boolean shows whether the ARCoreExtensionsProjectSettings is compatible - /// with the ARCoreExtensionsConfig. - public virtual bool IsCompatibleWithSessionConfig( - ARCoreExtensionsProjectSettings settings, ARCoreExtensionsConfig sessionConfig) - { - return true; - } - - /// - /// Return the Proguard snippet to include if this module is enabled. The string output - /// will be added into "proguard-user.txt" directly. - /// - /// ARCore Extensions Project Settings. - /// The proguard rule string snippet. - public virtual string GetProguardSnippet(ARCoreExtensionsProjectSettings settings) - { - return string.Empty; - } - } -} diff --git a/Editor/Scripts/Internal/DependentModules/IDependentModule.cs b/Editor/Scripts/Internal/DependentModules/IDependentModule.cs deleted file mode 100755 index 5d35497..0000000 --- a/Editor/Scripts/Internal/DependentModules/IDependentModule.cs +++ /dev/null @@ -1,71 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -namespace Google.XR.ARCoreExtensions.Editor.Internal -{ - using System; - using System.Xml; - using UnityEngine; - - /// - /// The interface needed for a feature module. - /// - public interface IDependentModule - { - /// - /// Checking whether it needs to be included in the customized AndroidManifest. - /// The default values for new fields in ARCoreExtensionsProjectSettings should cause the - /// associated module to return false. - /// - /// ARCore Extensions Project Settings. - /// The boolean shows whether the module is enabled. - bool IsEnabled(ARCoreExtensionsProjectSettings settings); - - /// - /// Return the XML snippet to include if this module is enabled. The string output will be - /// added as a child node of the ‘manifest’ node of the customized AndroidManifest.xml. - /// The android namespace will be available. - /// - /// ARCore Extensions Project Settings. - /// The XML string snippet to add as a child of node 'manifest'. - string GetAndroidManifestSnippet(ARCoreExtensionsProjectSettings settings); - - /// - /// Checking whether this module is compatible with given ARCoreExtensionsConfig. - /// If it returns false, the preprocessbuild will throw a general Build Failure Error. - /// A feature developer should use this function to log detailed error messages that - /// also include a recommendation of how to resolve the issue. - /// - /// ARCore Extensions Project Settings. - /// ARCore Extensions Config. - /// The boolean shows whether the ARCoreExtensionsProjectSettings is compatible - /// with the ARCoreExtensionsConfig. - bool IsCompatibleWithSessionConfig( - ARCoreExtensionsProjectSettings settings, ARCoreExtensionsConfig sessionConfig); - - /// - /// Return the Proguard snippet to include if this module is enabled. The string output - /// will be added into "proguard-user.txt" directly. - /// - /// ARCore Extensions Project Settings. - /// The proguard rule string snippet. - string GetProguardSnippet(ARCoreExtensionsProjectSettings settings); - } -} diff --git a/Editor/Scripts/Internal/DependentModules/KeylessModule.cs b/Editor/Scripts/Internal/DependentModules/KeylessModule.cs deleted file mode 100755 index 25df0ce..0000000 --- a/Editor/Scripts/Internal/DependentModules/KeylessModule.cs +++ /dev/null @@ -1,60 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -namespace Google.XR.ARCoreExtensions.Editor.Internal -{ - using System; - using System.IO; - using System.Xml; - using System.Xml.Linq; - using UnityEngine; - - /// - /// The implemented class of keyless module. - /// - public class KeylessModule : DependentModuleBase - { - /// - /// Checking whether it needs to be included in the customized AndroidManifest. - /// The default values for new fields in ARCoreProjectSettings should cause the - /// associated module to return false. - /// - /// ARCore Extensions Project Settings. - /// The boolean shows whether the module is enabled. - public override bool IsEnabled(ARCoreExtensionsProjectSettings settings) - { - return settings.AndroidAuthenticationStrategySetting == - AndroidAuthenticationStrategy.Keyless; - } - - /// - /// Return the Proguard to include if this module is enabled. The string output will be - /// added into "proguard-user.txt" directly. - /// - /// ARCore Extensions Project Settings. - /// The proguard rule string snippet. - public override string GetProguardSnippet(ARCoreExtensionsProjectSettings settings) - { - return @"-keep class com.google.android.gms.common.** { *; } - -keep class com.google.android.gms.auth.** { *; } - -keep class com.google.android.gms.tasks.** { *; }"; - } - } -} diff --git a/Editor/Scripts/Internal/IOSSupportPreprocessBuild.cs b/Editor/Scripts/Internal/IOSSupportPreprocessBuild.cs index 1885803..176acaa 100755 --- a/Editor/Scripts/Internal/IOSSupportPreprocessBuild.cs +++ b/Editor/Scripts/Internal/IOSSupportPreprocessBuild.cs @@ -21,6 +21,7 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal { using System.Diagnostics.CodeAnalysis; + using Google.XR.ARCoreExtensions.Internal; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; diff --git a/Editor/BuildResources/ARCoreAndroidKeylessDependencies.template.meta b/Editor/Scripts/Internal/ModulesWorkflow.meta old mode 100644 new mode 100755 similarity index 67% rename from Editor/BuildResources/ARCoreAndroidKeylessDependencies.template.meta rename to Editor/Scripts/Internal/ModulesWorkflow.meta index 31ffc1e..b494f36 --- a/Editor/BuildResources/ARCoreAndroidKeylessDependencies.template.meta +++ b/Editor/Scripts/Internal/ModulesWorkflow.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: 1fc346056f53a42949a3dcadaae39d67 +guid: 41ca9eab70ed9465382ea220764b3baa +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Editor/Scripts/Internal/DependentModules/DependentModulesManager.cs b/Editor/Scripts/Internal/ModulesWorkflow/CompatibilityCheckPreprocessBuild.cs similarity index 59% rename from Editor/Scripts/Internal/DependentModules/DependentModulesManager.cs rename to Editor/Scripts/Internal/ModulesWorkflow/CompatibilityCheckPreprocessBuild.cs index b54bed5..ada1500 100755 --- a/Editor/Scripts/Internal/DependentModules/DependentModulesManager.cs +++ b/Editor/Scripts/Internal/ModulesWorkflow/CompatibilityCheckPreprocessBuild.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // // Copyright 2020 Google LLC // @@ -20,19 +20,20 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal { + using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; + using Google.XR.ARCoreExtensions.Internal; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; + using UnityEngine; /// - /// Manager for available modules. + /// Manage the dependencies for compatibility and requirements check. /// - public class DependentModulesManager : IPreprocessBuildWithReport + public class CompatibilityCheckPreprocessBuild : IPreprocessBuildWithReport { - private static List _modules; - [SuppressMessage( "UnityRules.UnityStyleRules", "US1109:PublicPropertiesMustBeUpperCamelCase", Justification = "Overriden property.")] @@ -42,25 +43,11 @@ public int callbackOrder { get { - return 0; - } - } - - /// - /// Get Feature Dependent Modules. - /// - /// The list of available modules. - public static List GetModules() - { - if (_modules == null) - { - _modules = new List() - { - new KeylessModule(), - }; + // This preprocess would mark which modules are required. + // It should execute before all other Module Framework workflow. + // Skip 0 so other developers could let their workflow run first. + return 1; } - - return _modules; } /// @@ -70,36 +57,48 @@ public static List GetModules() /// such as its target platform and output path. public void OnPreprocessBuild(BuildReport report) { - if (report.summary.platform == BuildTarget.Android) + UnityEditor.BuildTarget buildTarget = report.summary.platform; + if (DependentModulesManager.GetModules().Count == 0) { - if (GetModules().Count == 0) - { - return; - } - - CheckCompatibilityWithAllSesssionConfigs( - ARCoreExtensionsProjectSettings.Instance, - AndroidDependenciesHelper.GetAllSessionConfigs()); + return; } + + CheckCompatibilityWithAllSesssionConfigs( + ARCoreExtensionsProjectSettings.Instance, + AndroidDependenciesHelper.GetAllSessionConfigs(), + buildTarget); } private static void CheckCompatibilityWithAllSesssionConfigs( ARCoreExtensionsProjectSettings settings, - Dictionary sessionToSceneMap) + Dictionary sessionToSceneMap, + UnityEditor.BuildTarget buildTarget) { - List featureModules = GetModules(); + List featureModules = + DependentModulesManager.GetModules(); foreach (IDependentModule module in featureModules) { + ModuleNecessity moduleNecessity = ModuleNecessity.NotRequired; foreach (var entry in sessionToSceneMap) { - if (!module.IsCompatibleWithSessionConfig( - settings, entry.Key)) + ARCoreExtensionsConfig sessionConfig = entry.Key; + if (!module.IsCompatible(settings, sessionConfig, buildTarget)) { throw new BuildFailedException( string.Format( "{0} isn't compatible with the ARCoreExtensionsConfig in {1}", module.GetType().Name, entry.Value)); } + + moduleNecessity = (ModuleNecessity)Math.Max( + (int)moduleNecessity, + (int)module.GetModuleNecessity(sessionConfig)); + } + + if (moduleNecessity == ModuleNecessity.NotRequired && + module.IsEnabled(settings, buildTarget)) + { + Debug.LogWarning(module.GetEnabledNotRequiredWarning(buildTarget)); } } } diff --git a/Editor/Scripts/Internal/AndroidKeylessPreprocessBuild.cs.meta b/Editor/Scripts/Internal/ModulesWorkflow/CompatibilityCheckPreprocessBuild.cs.meta similarity index 83% rename from Editor/Scripts/Internal/AndroidKeylessPreprocessBuild.cs.meta rename to Editor/Scripts/Internal/ModulesWorkflow/CompatibilityCheckPreprocessBuild.cs.meta index cc46bf9..6bed263 100755 --- a/Editor/Scripts/Internal/AndroidKeylessPreprocessBuild.cs.meta +++ b/Editor/Scripts/Internal/ModulesWorkflow/CompatibilityCheckPreprocessBuild.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 13814dbe62b6449c4a009714d91e5fd6 +guid: 38d5c23c3c85843bda4420b2926638ff MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Scripts/Internal/CustomizedManifestInjection.cs b/Editor/Scripts/Internal/ModulesWorkflow/CustomizedManifestInjection.cs similarity index 93% rename from Editor/Scripts/Internal/CustomizedManifestInjection.cs rename to Editor/Scripts/Internal/ModulesWorkflow/CustomizedManifestInjection.cs index 9c6bc4f..91f7ec0 100755 --- a/Editor/Scripts/Internal/CustomizedManifestInjection.cs +++ b/Editor/Scripts/Internal/ModulesWorkflow/CustomizedManifestInjection.cs @@ -24,7 +24,9 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal using System.Diagnostics.CodeAnalysis; using System.IO; using System.Xml.Linq; + using Google.XR.ARCoreExtensions.Internal; using UnityEditor.Android; + using UnityEngine; /// /// Inject customized manifest after the Android Gradle project is generated. @@ -42,7 +44,8 @@ public int callbackOrder { get { - return 0; + // Skip 0 so other developers could let their workflow run first. + return 1; } } @@ -61,7 +64,7 @@ public static XDocument GenerateCustomizedAndroidManifest( List featureModules = DependentModulesManager.GetModules(); foreach (IDependentModule module in featureModules) { - if (module.IsEnabled(settings)) + if (module.IsEnabled(settings, UnityEditor.BuildTarget.Android)) { XDocument xDocument = AndroidManifestMerger.TransferToXDocument( diff --git a/Editor/Scripts/Internal/CustomizedManifestInjection.cs.meta b/Editor/Scripts/Internal/ModulesWorkflow/CustomizedManifestInjection.cs.meta similarity index 100% rename from Editor/Scripts/Internal/CustomizedManifestInjection.cs.meta rename to Editor/Scripts/Internal/ModulesWorkflow/CustomizedManifestInjection.cs.meta diff --git a/Editor/Scripts/Internal/ModulesWorkflow/ExternalDependencyResolverPreprocessBuild.cs b/Editor/Scripts/Internal/ModulesWorkflow/ExternalDependencyResolverPreprocessBuild.cs new file mode 100755 index 0000000..68ec420 --- /dev/null +++ b/Editor/Scripts/Internal/ModulesWorkflow/ExternalDependencyResolverPreprocessBuild.cs @@ -0,0 +1,188 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Editor.Internal +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Linq; + using System.Text; + using System.Xml; + using System.Xml.Linq; + using Google.XR.ARCoreExtensions.Internal; + using UnityEditor; + using UnityEditor.Build; + using UnityEditor.Build.Reporting; + using UnityEditor.Callbacks; + using UnityEditor.XR.Management; + using UnityEngine; + using UnityEngine.XR.ARCore; + using UnityEngine.XR.Management; + + /// + /// Manage the dependencies for play service resolver. + /// + public class ExternalDependencyResolverPreprocessBuild : IPreprocessBuildWithReport + { + private const string _buildResourceFolderGUID = "117437286c43f4eeb845c3257f2a8546"; + private const string _dependenciesDirectory = "/DependenciesTempFolder"; + private const string _androidDependenciesFileSuffix = "Dependencies.xml"; + private const string _androidDependenciesFormat = + @" + + {0} + + "; + + private static HashSet _enabledIOSTemplate = new HashSet(); + + [SuppressMessage( + "UnityRules.UnityStyleRules", "US1109:PublicPropertiesMustBeUpperCamelCase", + Justification = "Overriden property.")] + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", + Justification = "Overriden property.")] + public int callbackOrder + { + get + { + // This preprocess build might need to check whether the module is required. + // So it should be executed after CompatiblityCheckPreprocessBuild. + return 2; + } + } + + /// + /// Callback after the build is done. + /// + /// Build target platform. + /// Path to build project. + [PostProcessBuild(1)] + public static void OnPostprocessBuild( + UnityEditor.BuildTarget target, string pathToBuiltProject) + { + if (target == UnityEditor.BuildTarget.Android) + { + Debug.Log("ARCoreExtensions: Cleaning up Android library dependencies."); + string folderPath = + AssetDatabase.GUIDToAssetPath(_buildResourceFolderGUID) + + _dependenciesDirectory; + Directory.Delete(folderPath, true); + AssetDatabase.Refresh(); + AndroidDependenciesHelper.DoPlayServicesResolve(); + } + else if (target == UnityEditor.BuildTarget.iOS) + { + foreach (string enabledTemplateFile in _enabledIOSTemplate) + { + Debug.LogFormat("ARCoreExtensions: Cleaning up {0} in PostprocessBuild.", + enabledTemplateFile); + IOSSupportHelper.UpdateIOSPodDependencies(false, enabledTemplateFile); + } + } + } + + /// + /// A callback before the build is started to manage the dependecies. + /// + /// A report containing information about the build. + public void OnPreprocessBuild(BuildReport report) + { + UnityEditor.BuildTarget buildTarget = report.summary.platform; + if (buildTarget == UnityEditor.BuildTarget.Android) + { + ManageAndroidDependencies(ARCoreExtensionsProjectSettings.Instance); + } + else if (buildTarget == UnityEditor.BuildTarget.iOS) + { + ManageIOSDependencies(ARCoreExtensionsProjectSettings.Instance); + } + } + + /// + /// Manage the ios dependecies based on the project settings. + /// + /// + /// The used by current build. + /// + public void ManageIOSDependencies(ARCoreExtensionsProjectSettings settings) + { + _enabledIOSTemplate.Clear(); + List featureModules = DependentModulesManager.GetModules(); + foreach (IDependentModule module in featureModules) + { + string iOSDependenciesTemplateFile = module.GetIOSDependenciesTemplateFileName(); + if (!string.IsNullOrEmpty(iOSDependenciesTemplateFile)) + { + bool isModuleEnabled = module.IsEnabled( + settings, UnityEditor.BuildTarget.iOS); + if (isModuleEnabled) + { + Debug.LogFormat("ARCoreExtensions: Include {0} for {1}.", + iOSDependenciesTemplateFile, module.GetType().Name); + _enabledIOSTemplate.Add(iOSDependenciesTemplateFile); + IOSSupportHelper.UpdateIOSPodDependencies( + true, iOSDependenciesTemplateFile); + } + else + { + Debug.LogFormat("ARCoreExtensions: Exclude {0} for {1}.", + iOSDependenciesTemplateFile, module.GetType().Name); + IOSSupportHelper.UpdateIOSPodDependencies( + false, iOSDependenciesTemplateFile); + } + } + } + } + + /// + /// Manage the android dependecies based on the project settings. + /// + /// The used by + /// current build. + public void ManageAndroidDependencies(ARCoreExtensionsProjectSettings settings) + { + List featureModules = DependentModulesManager.GetModules(); + string folderPath = + AssetDatabase.GUIDToAssetPath(_buildResourceFolderGUID) + _dependenciesDirectory; + Directory.CreateDirectory(folderPath); + foreach (IDependentModule module in featureModules) + { + if (module.IsEnabled(settings, UnityEditor.BuildTarget.Android)) + { + string dependenciesSnippet = module.GetAndroidDependenciesSnippet(settings); + if (!string.IsNullOrEmpty(dependenciesSnippet)) + { + string fileName = module.GetType().Name + _androidDependenciesFileSuffix; + string fullPath = Path.Combine(folderPath, fileName); + string finalSnippet = XDocument.Parse(string.Format( + _androidDependenciesFormat, dependenciesSnippet)).ToString(); + File.WriteAllText(fullPath, finalSnippet); + Debug.LogFormat("Module {0} added Android library dependencies:\n{1}", + module.GetType().Name, finalSnippet); + AssetDatabase.Refresh(); + AndroidDependenciesHelper.DoPlayServicesResolve(); + } + } + } + } + } +} diff --git a/Runtime/Scripts/Internal/Helpers/DllImportNoop.cs.meta b/Editor/Scripts/Internal/ModulesWorkflow/ExternalDependencyResolverPreprocessBuild.cs.meta similarity index 83% rename from Runtime/Scripts/Internal/Helpers/DllImportNoop.cs.meta rename to Editor/Scripts/Internal/ModulesWorkflow/ExternalDependencyResolverPreprocessBuild.cs.meta index 8d2df2d..5e77845 100755 --- a/Runtime/Scripts/Internal/Helpers/DllImportNoop.cs.meta +++ b/Editor/Scripts/Internal/ModulesWorkflow/ExternalDependencyResolverPreprocessBuild.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 33ea112444e8a4525ade1534a5acd5de +guid: 6e8d3dbef26b24135982dc0d8d82f289 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Scripts/Internal/ProguardInjectionPreprocessBuild.cs b/Editor/Scripts/Internal/ModulesWorkflow/ProguardInjectionPreprocessBuild.cs similarity index 95% rename from Editor/Scripts/Internal/ProguardInjectionPreprocessBuild.cs rename to Editor/Scripts/Internal/ModulesWorkflow/ProguardInjectionPreprocessBuild.cs index ffbb815..7afe331 100755 --- a/Editor/Scripts/Internal/ProguardInjectionPreprocessBuild.cs +++ b/Editor/Scripts/Internal/ModulesWorkflow/ProguardInjectionPreprocessBuild.cs @@ -28,6 +28,7 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal using System.Text; using System.Xml; using System.Xml.Linq; + using Google.XR.ARCoreExtensions.Internal; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; @@ -57,7 +58,9 @@ public int callbackOrder { get { - return 0; + // This preprocess build might need to check whether the module is required. + // So it should be executed after CompatiblityCheckPreprocessBuild. + return 2; } } @@ -85,7 +88,7 @@ public void InjectModuleProguardRules(ARCoreExtensionsProjectSettings settings) List featureModules = DependentModulesManager.GetModules(); foreach (IDependentModule module in featureModules) { - if (module.IsEnabled(settings)) + if (module.IsEnabled(settings, UnityEditor.BuildTarget.Android)) { string moduleProguardSnippet = module.GetProguardSnippet(settings); if (!string.IsNullOrEmpty(moduleProguardSnippet)) diff --git a/Editor/Scripts/Internal/ProguardInjectionPreprocessBuild.cs.meta b/Editor/Scripts/Internal/ModulesWorkflow/ProguardInjectionPreprocessBuild.cs.meta similarity index 100% rename from Editor/Scripts/Internal/ProguardInjectionPreprocessBuild.cs.meta rename to Editor/Scripts/Internal/ModulesWorkflow/ProguardInjectionPreprocessBuild.cs.meta diff --git a/Editor/Scripts/Internal/ModulesWorkflow/RuntimeConfigPreprocessBuild.cs b/Editor/Scripts/Internal/ModulesWorkflow/RuntimeConfigPreprocessBuild.cs new file mode 100755 index 0000000..a82a022 --- /dev/null +++ b/Editor/Scripts/Internal/ModulesWorkflow/RuntimeConfigPreprocessBuild.cs @@ -0,0 +1,104 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Editor.Internal +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using Google.XR.ARCoreExtensions.Internal; + using UnityEditor; + using UnityEditor.Build; + using UnityEditor.Build.Reporting; + using UnityEngine; + + /// + /// Mark modules enabled in RuntimeConfig. + /// + public class RuntimeConfigPreprocessBuild : IPreprocessBuildWithReport + { + [SuppressMessage( + "UnityRules.UnityStyleRules", "US1109:PublicPropertiesMustBeUpperCamelCase", + Justification = "Overriden property.")] + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", + Justification = "Overriden property.")] + public int callbackOrder + { + get + { + // This preprocess build might need to check whether the module is required. + // So it should be executed after CompatiblityCheckPreprocessBuild. + return 2; + } + } + + /// + /// A callback before the build is started to mark modules enabled. + /// + /// A report containing information about the build. + public void OnPreprocessBuild(BuildReport report) + { + UnityEditor.BuildTarget buildTarget = report.summary.platform; + + if (buildTarget == BuildTarget.Android) + { + SetEnabledModules(ARCoreExtensionsProjectSettings.Instance); + } + else if (buildTarget == BuildTarget.iOS) + { + SetApiKeyOnIOS(ARCoreExtensionsProjectSettings.Instance); + } + } + + private void SetApiKeyOnIOS(ARCoreExtensionsProjectSettings settings) + { + if (string.IsNullOrEmpty(settings.IOSCloudServicesApiKey)) + { + RuntimeConfig.SetIOSApiKey(string.Empty); + return; + } + + if (!settings.IsIOSSupportEnabled) + { + Debug.LogWarning("Failed to enable Cloud Anchor on iOS because iOS Support " + + "is not enabled. Go to 'Project Settings > XR > ARCore Extensionts' " + + "to change the settings."); + RuntimeConfig.SetIOSApiKey(string.Empty); + return; + } + + RuntimeConfig.SetIOSApiKey(settings.IOSCloudServicesApiKey); + } + + private void SetEnabledModules(ARCoreExtensionsProjectSettings settings) + { + List modulesEnabled = new List(); + foreach (IDependentModule module in DependentModulesManager.GetModules()) + { + if (module.IsEnabled(settings, UnityEditor.BuildTarget.Android)) + { + modulesEnabled.Add(module.GetType().Name); + } + } + + RuntimeConfig.SetEnabledModules(modulesEnabled); + } + } +} diff --git a/Editor/Scripts/Internal/CloudAnchorPreprocessBuild.cs.meta b/Editor/Scripts/Internal/ModulesWorkflow/RuntimeConfigPreprocessBuild.cs.meta similarity index 83% rename from Editor/Scripts/Internal/CloudAnchorPreprocessBuild.cs.meta rename to Editor/Scripts/Internal/ModulesWorkflow/RuntimeConfigPreprocessBuild.cs.meta index e669aa4..d16a254 100755 --- a/Editor/Scripts/Internal/CloudAnchorPreprocessBuild.cs.meta +++ b/Editor/Scripts/Internal/ModulesWorkflow/RuntimeConfigPreprocessBuild.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4e522121c94e148eb95f0586e6566d17 +guid: 25229d05643da400fac5b329cd13bcc0 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/BuildResources/cloud_anchor_manifest.aartemplate.meta b/Runtime/Configurations.meta old mode 100755 new mode 100644 similarity index 67% rename from Editor/BuildResources/cloud_anchor_manifest.aartemplate.meta rename to Runtime/Configurations.meta index 7253f2d..6661f44 --- a/Editor/BuildResources/cloud_anchor_manifest.aartemplate.meta +++ b/Runtime/Configurations.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: c6b1856c3179a4a77a14f3e05b5aae92 +guid: 1e9d7617a66a14f17a884923b585dd46 +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Runtime/Configurations/RuntimeSettings.meta b/Runtime/Configurations/RuntimeSettings.meta new file mode 100644 index 0000000..8555d09 --- /dev/null +++ b/Runtime/Configurations/RuntimeSettings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c75c71eeed444479690ce1dd3992c62b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Configurations/RuntimeSettings/RuntimeConfig.asset b/Runtime/Configurations/RuntimeSettings/RuntimeConfig.asset new file mode 100644 index 0000000..f3645de --- /dev/null +++ b/Runtime/Configurations/RuntimeSettings/RuntimeConfig.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e33f0ae6a91754a3d8a1f4e1a8ddd0d6, type: 3} + m_Name: RuntimeConfig + m_EditorClassIdentifier: + IOSCloudServicesApiKey: + ModulesEnabled: [] diff --git a/Runtime/Configurations/RuntimeSettings/RuntimeConfig.asset.meta b/Runtime/Configurations/RuntimeSettings/RuntimeConfig.asset.meta new file mode 100644 index 0000000..00f1c15 --- /dev/null +++ b/Runtime/Configurations/RuntimeSettings/RuntimeConfig.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 36a0f794e5d52427489bca483b96310b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Plugins/ARPresto.aar b/Runtime/Plugins/ARPresto.aar index b7820ad..8bc0f43 100755 Binary files a/Runtime/Plugins/ARPresto.aar and b/Runtime/Plugins/ARPresto.aar differ diff --git a/Runtime/Plugins/arcore_client.aar b/Runtime/Plugins/arcore_client.aar index 42b2253..5d72998 100755 Binary files a/Runtime/Plugins/arcore_client.aar and b/Runtime/Plugins/arcore_client.aar differ diff --git a/Runtime/Plugins/cloud_anchor_manifest.aar b/Runtime/Plugins/cloud_anchor_manifest.aar deleted file mode 100644 index 34c16f8..0000000 Binary files a/Runtime/Plugins/cloud_anchor_manifest.aar and /dev/null differ diff --git a/Runtime/Plugins/cloud_anchor_manifest.aar.meta b/Runtime/Plugins/cloud_anchor_manifest.aar.meta deleted file mode 100644 index 06cf48c..0000000 --- a/Runtime/Plugins/cloud_anchor_manifest.aar.meta +++ /dev/null @@ -1,32 +0,0 @@ -fileFormatVersion: 2 -guid: 579f1bee3bba04ff28081b06e1508c30 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: {} - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Scripts/ARCoreExtensions.cs b/Runtime/Scripts/ARCoreExtensions.cs index 3fb62ca..92c46cd 100755 --- a/Runtime/Scripts/ARCoreExtensions.cs +++ b/Runtime/Scripts/ARCoreExtensions.cs @@ -272,6 +272,19 @@ public void Update() _cachedConfig = ScriptableObject.CreateInstance(); _cachedConfig.CopyFrom(ARCoreExtensionsConfig); + List modules = DependentModulesManager.GetModules(); + foreach (var module in modules) + { + string[] permissions = module.GetRuntimePermissions(_cachedConfig); + foreach (var permission in permissions) + { + if (!AndroidPermissionsManager.IsPermissionGranted(permission)) + { + _requiredPermissionNames.Add(permission); + } + } + } + if (_requiredPermissionNames.Count > 0) { RequestPermission(); @@ -295,7 +308,7 @@ private void RequestPermission() { // Waiting for current request. if (!AndroidPermissionsManager.IsPermissionGranted( - AndroidPermissionsManager._cameraPermission) || + AndroidPermissionsManager._cameraPermission) || !string.IsNullOrEmpty(_currentPermissionRequest)) { return; diff --git a/Runtime/Scripts/ARCoreRecordingConfig.cs b/Runtime/Scripts/ARCoreRecordingConfig.cs index 1ee31a3..a69103b 100755 --- a/Runtime/Scripts/ARCoreRecordingConfig.cs +++ b/Runtime/Scripts/ARCoreRecordingConfig.cs @@ -21,11 +21,16 @@ namespace Google.XR.ARCoreExtensions { using System; + using System.Collections.Generic; using UnityEngine; /// /// Configuration to record camera and sensor data from an ARCore session. /// + [CreateAssetMenu( + fileName = "ARCoreRecordingConfig", + menuName = "ARCore Extensions/ARCore Recording Config", + order = 3)] public class ARCoreRecordingConfig : ScriptableObject { /// @@ -43,5 +48,12 @@ public class ARCoreRecordingConfig : ScriptableObject /// black screen until the session is resumed. /// public bool AutoStopOnPause = true; - } + + /// + /// The list of to add the recording config. This field is not + /// available in the editor and should be set at runtime. + /// + [HideInInspector] + public List Tracks = new List(); + } } diff --git a/Runtime/Scripts/ARPlaybackManager.cs b/Runtime/Scripts/ARPlaybackManager.cs index 47566e7..baf3ec8 100755 --- a/Runtime/Scripts/ARPlaybackManager.cs +++ b/Runtime/Scripts/ARPlaybackManager.cs @@ -20,18 +20,23 @@ namespace Google.XR.ARCoreExtensions { + using System; + using System.Collections.Generic; using Google.XR.ARCoreExtensions.Internal; + using UnityEngine; + using UnityEngine.XR.ARFoundation; + using UnityEngine.XR.ARSubsystems; /// /// Provides access to session playback functionality. /// - public static class ARPlaybackManager + public class ARPlaybackManager : MonoBehaviour { /// /// Gets the current state of the playback. /// /// The current . - public static PlaybackStatus PlaybackStatus + public PlaybackStatus PlaybackStatus { get { @@ -45,25 +50,103 @@ public static PlaybackStatus PlaybackStatus /// sensor data. /// /// Restrictions: - /// - Due to the way session data is processed, ARCore APIs may sometimes produce different - /// results during playback than during recording and produce different results during - /// subsequent playback sessions. For exmaple, the number of detected planes and other - /// trackables, the precise timing of their detection and their pose over time may be - /// different in subsequent playback sessions. - /// - Can only be called while the session is paused. Playback of the MP4 dataset file will - /// start once the session is resumed. - /// - The MP4 dataset file must use the same camera facing direction as is configured in the - /// session. - /// + /// + /// + /// Can only be called while the session is paused. Playback of the MP4 dataset file will + /// start once the session is resumed. + /// + /// + /// The MP4 dataset file must use the same camera facing direction as is configured in the + /// session. + /// + /// + /// Due to the way session data is processed, ARCore APIs may sometimes produce different + /// results during playback than during recording and produce different results during + /// subsequent playback sessions. For exmaple, the number of detected planes and other + /// trackables, the precise timing of their detection and their pose over time may be + /// different in subsequent playback sessions. + /// + /// + /// Once playback has started pausing the session (by disabling the ARSession) will + /// suspend processing of all camera image frames and any other recorded sensor data in + /// the dataset. Camera image frames and sensor frame data that is discarded in this way + /// will not be reprocessed when the session is again resumed (by re-enabling the + /// ARSession). AR tracking for the session will generally suffer due to the gap in + /// processed data. + /// + /// + /// /// The filepath of the MP4 dataset. Null if /// stopping the playback and resuming a live feed. /// .Success if playback filepath was /// set without issue. Otherwise, the will indicate the /// error. - public static PlaybackResult SetPlaybackDataset(string datasetFilepath) + public PlaybackResult SetPlaybackDataset(string datasetFilepath) { + if (ARCoreExtensions._instance.currentARCoreSessionHandle == IntPtr.Zero && + ARCoreExtensions._instance.Session.subsystem != null && + ARCoreExtensions._instance.Session.subsystem.nativePtr != null) + { + return PlaybackResult.SessionNotReady; + } + return SessionApi.SetPlaybackDataset( ARCoreExtensions._instance.currentARCoreSessionHandle, datasetFilepath); } + + /// + /// Gets the set of data recorded to the given track available during playback on this + /// frame. + /// Note, currently playback continues internally while the session is paused. Therefore, on + /// pause/resume, track data discovered internally will be discarded to prevent stale track + /// data from flowing through when the session resumed. + /// Note, if the app's frame rate is higher than ARCore's frame rate, subsequent + /// objects may reference the same underlying ARCore Frame, + /// which would mean the list of returned could be the same. + /// One can differentiate by examining . + /// + /// The ID of the track being queried. + /// Returns a list of . Will be empty if none are available. + /// + public List GetUpdatedTrackData(Guid trackId) + { + if (ARCoreExtensions._instance.currentARCoreSessionHandle == IntPtr.Zero && + ARCoreExtensions._instance.Session.subsystem != null && + ARCoreExtensions._instance.Session.subsystem.nativePtr != null) + { + Debug.LogWarning("Failed to fetch track data. The Session is not yet available. " + + "Try again later."); + return new List(); + } + + ARCameraManager cameraManager = ARCoreExtensions._instance.CameraManager; + + var cameraParams = new XRCameraParams + { + zNear = cameraManager.GetComponent().nearClipPlane, + zFar = cameraManager.GetComponent().farClipPlane, + screenWidth = Screen.width, + screenHeight = Screen.height, + screenOrientation = Screen.orientation + }; + + if (!cameraManager.subsystem.TryGetLatestFrame(cameraParams, out XRCameraFrame frame)) + { + Debug.LogWarning("Failed to fetch track data. The current XRCameraFrame is not " + + "available. Try again later."); + return new List(); + } + + if (frame.timestampNs == 0 || frame.nativePtr == IntPtr.Zero) + { + Debug.LogWarning("Failed to fetch track data. The current XRCameraFrame is not " + + "ready. Try again later."); + return new List(); + } + + return FrameApi.GetUpdatedTrackData( + ARCoreExtensions._instance.currentARCoreSessionHandle, frame.FrameHandle(), + trackId); + } } } diff --git a/Runtime/Scripts/ARRecordingManager.cs b/Runtime/Scripts/ARRecordingManager.cs index 318d685..89cd742 100755 --- a/Runtime/Scripts/ARRecordingManager.cs +++ b/Runtime/Scripts/ARRecordingManager.cs @@ -23,17 +23,19 @@ namespace Google.XR.ARCoreExtensions using System; using Google.XR.ARCoreExtensions.Internal; using UnityEngine; + using UnityEngine.XR.ARFoundation; + using UnityEngine.XR.ARSubsystems; /// /// Provides access to session recording functionality. /// - public static class ARRecordingManager + public class ARRecordingManager : MonoBehaviour { /// /// Gets the current state of the recorder. /// /// The current . - public static RecordingStatus RecordingStatus + public RecordingStatus RecordingStatus { get { @@ -57,8 +59,15 @@ public static RecordingStatus RecordingStatus /// start on the next Session resume.) Or a if there was an /// error. /// - public static RecordingResult StartRecording(ARCoreRecordingConfig config) + public RecordingResult StartRecording(ARCoreRecordingConfig config) { + if (ARCoreExtensions._instance.currentARCoreSessionHandle == IntPtr.Zero && + ARCoreExtensions._instance.Session.subsystem != null && + ARCoreExtensions._instance.Session.subsystem.nativePtr != null) + { + return RecordingResult.SessionNotReady; + } + return SessionApi.StartRecording( ARCoreExtensions._instance.currentARCoreSessionHandle, config); } @@ -70,9 +79,72 @@ public static RecordingResult StartRecording(ARCoreRecordingConfig config) /// .OK if the recording was stopped /// successfully, or .ErrorRecordingFailed if there was /// an error. - public static RecordingResult StopRecording() + public RecordingResult StopRecording() { return SessionApi.StopRecording(ARCoreExtensions._instance.currentARCoreSessionHandle); } + + /// + /// Writes a data sample in the specified external data track. The external samples recorded + /// using this API will be muxed into the recorded MP4 dataset in a corresponding additional + /// MP4 stream. + /// + /// For smooth playback of the MP4 on video players and for future compatibility + /// of the MP4 datasets with ARCore's playback of external data tracks it is + /// recommended that the external samples are recorded at a frequency no higher + /// than 90kHz. + /// + /// Additionally, if the external samples are recorded at a frequency lower than + /// 1Hz, empty padding samples will be automatically recorded at approximately + /// one second intervals to fill in the gaps. + /// + /// Recording external samples introduces additional CPU and/or I/O overhead and + /// may affect app performance. + /// + /// The unique ID of the track being recorded to. This will be + /// the used to configure the track. + /// The data being recorded at current time. + /// .OK if the data was recorded successfully, + /// or a different if there was an error. + /// + public RecordingResult RecordTrackData(Guid trackId, byte[] data) + { + if (ARCoreExtensions._instance.currentARCoreSessionHandle == IntPtr.Zero && + ARCoreExtensions._instance.Session.subsystem != null && + ARCoreExtensions._instance.Session.subsystem.nativePtr != null) + { + Debug.LogWarning("Failed to record track data. The Session is not yet available. " + + "Try again later."); + return RecordingResult.ErrorIllegalState; + } + + ARCameraManager cameraManager = ARCoreExtensions._instance.CameraManager; + var cameraParams = new XRCameraParams + { + zNear = cameraManager.GetComponent().nearClipPlane, + zFar = cameraManager.GetComponent().farClipPlane, + screenWidth = Screen.width, + screenHeight = Screen.height, + screenOrientation = Screen.orientation + }; + + if (!cameraManager.subsystem.TryGetLatestFrame(cameraParams, out XRCameraFrame frame)) + { + Debug.LogWarning("Failed to record track data. The current XRCameraFrame is not " + + "available. Try again later."); + return RecordingResult.ErrorIllegalState; + } + + if (frame.timestampNs == 0 || frame.nativePtr == IntPtr.Zero) + { + Debug.LogWarning("Failed to record track data. The current XRCameraFrame is not " + + "ready. Try again later."); + return RecordingResult.ErrorRecordingFailed; + } + + return FrameApi.RecordTrackData( + ARCoreExtensions._instance.currentARCoreSessionHandle, frame.FrameHandle(), trackId, + data); + } } } diff --git a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettings.cs b/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs similarity index 83% rename from Editor/Scripts/Internal/ARCoreExtensionsProjectSettings.cs rename to Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs index d34d82a..28cf534 100755 --- a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettings.cs +++ b/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs @@ -18,7 +18,8 @@ // //----------------------------------------------------------------------- -namespace Google.XR.ARCoreExtensions.Editor.Internal +#if UNITY_EDITOR +namespace Google.XR.ARCoreExtensions.Internal { using System; using System.Diagnostics.CodeAnalysis; @@ -37,10 +38,11 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal Justification = "Internal.")] public enum AndroidAuthenticationStrategy { - None = 0, + [DisplayName("Do Not Use")] + DoNotUse = 0, [DisplayName("Keyless (recommended)")] Keyless = 1, - [DisplayName("Api Key")] + [DisplayName("API Key")] ApiKey = 2, } @@ -53,10 +55,11 @@ public enum AndroidAuthenticationStrategy Justification = "Internal.")] public enum IOSAuthenticationStrategy { - None = 0, + [DisplayName("Do Not Use")] + DoNotUse = 0, [DisplayName("Authentication Token (recommended)")] AuthenticationToken = 1, - [DisplayName("Api Key")] + [DisplayName("API Key")] ApiKey = 2, } @@ -82,9 +85,8 @@ public class ARCoreExtensionsProjectSettings /// [DisplayName("Android Authentication Strategy")] [DynamicHelp("GetAndroidStrategyHelpInfo")] - [EnumRange("GetAndroidStrategyRange")] public AndroidAuthenticationStrategy AndroidAuthenticationStrategySetting = - AndroidAuthenticationStrategy.None; + AndroidAuthenticationStrategy.DoNotUse; /// /// Android Api Key. @@ -99,9 +101,8 @@ public class ARCoreExtensionsProjectSettings [DisplayName("iOS Authentication Strategy")] [DisplayCondition("IsIosStrategyDisplayed")] [DynamicHelp("GetIosStrategyHelpInfo")] - [EnumRange("GetIosStrategyRange")] public IOSAuthenticationStrategy IOSAuthenticationStrategySetting = - IOSAuthenticationStrategy.None; + IOSAuthenticationStrategy.DoNotUse; /// /// IOS Api Key. @@ -139,8 +140,8 @@ public void Load() { // Default settings. IsIOSSupportEnabled = false; - AndroidAuthenticationStrategySetting = AndroidAuthenticationStrategy.None; - IOSAuthenticationStrategySetting = IOSAuthenticationStrategy.None; + AndroidAuthenticationStrategySetting = AndroidAuthenticationStrategy.DoNotUse; + IOSAuthenticationStrategySetting = IOSAuthenticationStrategy.DoNotUse; AndroidCloudServicesApiKey = string.Empty; IOSCloudServicesApiKey = string.Empty; @@ -155,20 +156,14 @@ public void Load() } } - if (AndroidAuthenticationStrategySetting == AndroidAuthenticationStrategy.None) + if (!string.IsNullOrEmpty(AndroidCloudServicesApiKey)) { - AndroidAuthenticationStrategySetting = - string.IsNullOrEmpty(AndroidCloudServicesApiKey) ? - AndroidAuthenticationStrategy.Keyless : - AndroidAuthenticationStrategy.ApiKey; + AndroidAuthenticationStrategySetting = AndroidAuthenticationStrategy.ApiKey; } - if (IOSAuthenticationStrategySetting == IOSAuthenticationStrategy.None) + if (!string.IsNullOrEmpty(IOSCloudServicesApiKey)) { - IOSAuthenticationStrategySetting = - string.IsNullOrEmpty(IOSCloudServicesApiKey) ? - IOSAuthenticationStrategy.AuthenticationToken : - IOSAuthenticationStrategy.ApiKey; + IOSAuthenticationStrategySetting = IOSAuthenticationStrategy.ApiKey; } // Update the settings version as needed. @@ -228,20 +223,6 @@ public HelpAttribute GetAndroidStrategyHelpInfo() } } - /// - /// Reflection function used by 'EnumRange' for property - /// 'AndroidAuthenticationStrategySetting'. - /// - /// Enum range for 'AndroidAuthenticationStrategySetting'. - public Array GetAndroidStrategyRange() - { - return new AndroidAuthenticationStrategy[] - { - AndroidAuthenticationStrategy.ApiKey, - AndroidAuthenticationStrategy.Keyless, - }; - } - /// /// Reflection function used by 'DisplayCondition' for property /// 'IOSAuthenticationStrategySetting'. @@ -274,19 +255,6 @@ public bool IsIosApiKeyFieldDisplayed() } } - /// - /// Reflection function used by 'EnumRange' for property 'IOSAuthenticationStrategy'. - /// - /// Enum range for 'IOSAuthenticationStrategy'. - public Array GetIosStrategyRange() - { - return new IOSAuthenticationStrategy[] - { - IOSAuthenticationStrategy.ApiKey, - IOSAuthenticationStrategy.AuthenticationToken, - }; - } - /// /// Reflection function used by 'DynamicHelp' for property 'IOSAuthenticationStrategy'. /// @@ -300,6 +268,15 @@ public HelpAttribute GetIosStrategyHelpInfo() " authentication strategy is selected.", HelpAttribute.HelpMessageType.Warning); } + else if (IOSAuthenticationStrategySetting == + IOSAuthenticationStrategy.AuthenticationToken) + { + return new HelpAttribute( + "Authentication Token is selected as the Cloud Anchor Authentication. " + + "To authenticate with the Google Cloud Anchor Service, use " + + "ARAnchorManager.SetAuthToken(string) in runtime.", + HelpAttribute.HelpMessageType.Info); + } else { return null; @@ -312,7 +289,7 @@ public HelpAttribute GetIosStrategyHelpInfo() /// would be input as the parameter to this attribute. Note, the function must return /// the type bool, take no parameters, and be a member of ARCoreProjectSettings. /// - internal class DisplayConditionAttribute : Attribute + public class DisplayConditionAttribute : Attribute { /// /// Reflection function that return the type bool, take no parameters, @@ -335,7 +312,7 @@ public DisplayConditionAttribute(string checkingFunction) /// It could be used for either a field or an enum. If this attribute isn’t provided, /// then the default field name would be the field name. /// - internal class DisplayNameAttribute : Attribute + public class DisplayNameAttribute : Attribute { /// /// Display string in the GUI. @@ -357,7 +334,7 @@ public DisplayNameAttribute(string displayString) /// The function must be a member of ARCoreProjectSettings, return the type /// System.Array, and take no parameters. /// - internal class EnumRangeAttribute : Attribute + public class EnumRangeAttribute : Attribute { /// /// Reflection function that return the type System.Array, take no parameters, @@ -375,3 +352,4 @@ public EnumRangeAttribute(string checkingFunction) } } } +#endif // UNITY_EDITOR diff --git a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettings.cs.meta b/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs.meta similarity index 100% rename from Editor/Scripts/Internal/ARCoreExtensionsProjectSettings.cs.meta rename to Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs.meta diff --git a/Editor/Scripts/Internal/DependentModules.meta b/Runtime/Scripts/Internal/DependentModules.meta similarity index 77% rename from Editor/Scripts/Internal/DependentModules.meta rename to Runtime/Scripts/Internal/DependentModules.meta index bea415b..2cf2a15 100755 --- a/Editor/Scripts/Internal/DependentModules.meta +++ b/Runtime/Scripts/Internal/DependentModules.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 823db635f36294ff8aa76dbe3fea715b +guid: 531c14ab915ee4cb4bc02c2fa157ee16 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Runtime/Scripts/Internal/DependentModules/DependentModuleBase.cs b/Runtime/Scripts/Internal/DependentModules/DependentModuleBase.cs new file mode 100755 index 0000000..6092704 --- /dev/null +++ b/Runtime/Scripts/Internal/DependentModules/DependentModuleBase.cs @@ -0,0 +1,166 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.Xml; + using UnityEngine; + + /// + /// The interface needed for a feature module. + /// + public class DependentModuleBase : IDependentModule + { + /// + /// Get the permissions required by this module during the runtime. + /// + /// ARCore Extensions Config. + /// + /// The array containing the Runtime Permissions’ names required by this module. + /// + public virtual string[] GetRuntimePermissions(ARCoreExtensionsConfig sessionConfig) + { + return Array.Empty(); + } + +#if UNITY_EDITOR + /// + /// Checking whether it needs to be included into the application. If it returns true, + /// all related content, including AndroidManifest, proguard rules and Android external + /// dependencies would be injected during build time. The default values for new fields in + /// ARCoreExtensionsProjectSettings should guarantee the associated module to return false. + /// + /// ARCore Extensions Project Settings. + /// Target build platform. + /// The boolean shows whether the module is enabled. + public virtual bool IsEnabled(ARCoreExtensionsProjectSettings settings, + UnityEditor.BuildTarget buildTarget) + { + return false; + } + + /// + /// Checking whether this module is compatible with given ARCoreExtensionsConfig and + /// ARCoreExtensionsProjectSettings. If it returns false, the + /// CompatibilityCheckPreprocessBuild will throw a general Build Failure Error. + /// A feature developer should use this function to log detailed error messages that + /// also include a recommendation of how to resolve the issue. Note: This method is + /// called once per session config. Do not log any warning or info messages here to + /// avoid duplicated and/or conflicted information. + /// + /// ARCore Extensions Project Settings. + /// ARCore Extensions Config. + /// Target build platform. + /// The boolean shows whether the ARCoreExtensionsProjectSettings is compatible + /// with the ARCoreExtensionsConfig. + public virtual bool IsCompatible( + ARCoreExtensionsProjectSettings settings, ARCoreExtensionsConfig sessionConfig, + UnityEditor.BuildTarget buildTarget) + { + if (GetModuleNecessity(sessionConfig) == ModuleNecessity.Required && + !IsEnabled(settings, buildTarget)) + { + Debug.LogErrorFormat("{0} is required but not enabled.", this.GetType().Name); + return false; + } + + return true; + } + + /// + /// Checking whether this module is required with given ARCoreExtensionsConfig. + /// In CompatibilityCheckPreprocessBuild, it would loop all explicit sessionConfigs + /// via this funcion. If no session configs require this module but this module is + /// still enabled, then a warning returned by + /// will be logged. + /// + /// ARCore Extensions Config. + /// + /// Whether the module is Required/NotRequired/Optional by the sessionConfig. + /// + public virtual ModuleNecessity GetModuleNecessity(ARCoreExtensionsConfig sessionConfig) + { + return ModuleNecessity.NotRequired; + } + + /// + /// In CompatibilityCheckPreprocessBuild, if no session configs require this + /// module but this module is still enabled, it would call this function to get + /// a warning message. + /// + /// Target build platform. + /// + /// The warning message if this module is enabled but not required by any sessionConfigs. + /// + public virtual string GetEnabledNotRequiredWarning(UnityEditor.BuildTarget buildTarget) + { + return string.Format("{0} is enabled but not required. Should it be disabled?", + this.GetType().Name); + } + + /// + /// Return the XML snippet to include if this module is enabled. The string output will be + /// added as a child node of the ‘manifest’ node of the customized AndroidManifest.xml. + /// The android namespace will be available. + /// + /// ARCore Extensions Project Settings. + /// The XML string snippet to add as a child of node 'manifest'. + public virtual string GetAndroidManifestSnippet(ARCoreExtensionsProjectSettings settings) + { + return string.Empty; + } + + /// + /// Return the Proguard snippet to include if this module is enabled. The string output + /// will be added into "proguard-user.txt" directly. + /// + /// ARCore Extensions Project Settings. + /// The proguard rule string snippet. + public virtual string GetProguardSnippet(ARCoreExtensionsProjectSettings settings) + { + return string.Empty; + } + + /// + /// Return the snippet to be used in External Dependencies Resolvor while building + /// Android app. The string output will be added into a new created file whose name + /// would combine the module name and "Dependencies.xml". + /// + /// ARCore Extensions Project Settings. + /// The string snippet to be used in Play Services Resolver. + public virtual string GetAndroidDependenciesSnippet( + ARCoreExtensionsProjectSettings settings) + { + return string.Empty; + } + + /// + /// Return the iOS dependency template file name of this module, which would be used by + /// External Dependencies Resolvor while building iOS app. + /// + /// iOS dependency template file name of this module. + public virtual string GetIOSDependenciesTemplateFileName() + { + return string.Empty; + } +#endif // UNITY_EDITOR + } +} diff --git a/Editor/Scripts/Internal/DependentModules/DependentModuleBase.cs.meta b/Runtime/Scripts/Internal/DependentModules/DependentModuleBase.cs.meta similarity index 100% rename from Editor/Scripts/Internal/DependentModules/DependentModuleBase.cs.meta rename to Runtime/Scripts/Internal/DependentModules/DependentModuleBase.cs.meta diff --git a/Runtime/Scripts/Internal/DependentModules/DependentModulesManager.cs b/Runtime/Scripts/Internal/DependentModules/DependentModulesManager.cs new file mode 100755 index 0000000..b473cb1 --- /dev/null +++ b/Runtime/Scripts/Internal/DependentModules/DependentModulesManager.cs @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using UnityEditor; + + /// + /// Manager for available modules. + /// + public class DependentModulesManager + { + private static List _modules; + + /// + /// Get Feature Dependent Modules. + /// + /// The list of all modules. + public static List GetModules() + { + if (_modules == null) + { + List modules = new List() + { + new AuthenticationModule(), + }; + +#if UNITY_EDITOR + _modules = modules; +#else + List modulesEnabled = RuntimeConfig.Instance.ModulesEnabled; + _modules = modules.FindAll( + module => modulesEnabled.Contains(module.GetType().Name)); +#endif + } + + return _modules; + } + + } +} diff --git a/Editor/Scripts/Internal/DependentModules/DependentModulesManager.cs.meta b/Runtime/Scripts/Internal/DependentModules/DependentModulesManager.cs.meta similarity index 100% rename from Editor/Scripts/Internal/DependentModules/DependentModulesManager.cs.meta rename to Runtime/Scripts/Internal/DependentModules/DependentModulesManager.cs.meta diff --git a/Runtime/Scripts/Internal/DependentModules/FeatureModules.meta b/Runtime/Scripts/Internal/DependentModules/FeatureModules.meta new file mode 100755 index 0000000..e9dc0a9 --- /dev/null +++ b/Runtime/Scripts/Internal/DependentModules/FeatureModules.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 414cd56feb69f4d678badec7ceee68fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/Internal/DependentModules/FeatureModules/AuthenticationModule.cs b/Runtime/Scripts/Internal/DependentModules/FeatureModules/AuthenticationModule.cs new file mode 100755 index 0000000..c116836 --- /dev/null +++ b/Runtime/Scripts/Internal/DependentModules/FeatureModules/AuthenticationModule.cs @@ -0,0 +1,242 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.IO; + using System.Xml; + using System.Xml.Linq; + using UnityEngine; + + /// + /// The implemented class of Authentication Module. + /// + public class AuthenticationModule : DependentModuleBase + { +#if UNITY_EDITOR + /// + /// Checking whether it needs to be included into the application. If it returns true, + /// all related content, including AndroidManifest, proguard rules and Android external + /// dependencies would be injected during build time. The default values for new fields in + /// ARCoreExtensionsProjectSettings should guarantee the associated module to return false. + /// + /// ARCore Extensions Project Settings. + /// Target build platform. + /// The boolean shows whether the module is enabled. + public override bool IsEnabled(ARCoreExtensionsProjectSettings settings, + UnityEditor.BuildTarget buildTarget) + { + if (buildTarget == UnityEditor.BuildTarget.iOS) + { + bool isEnabled = settings.IOSAuthenticationStrategySetting != + IOSAuthenticationStrategy.DoNotUse; + if (settings.IsIOSSupportEnabled && !isEnabled) + { + Debug.LogWarning( + "Cloud Anchor APIs require one of the iOS authentication strategies. " + + "If it’s not in use, you can uncheck iOS Support Enabled in " + + "Edit > Project Settings > XR > ARCore Extensions " + + "so ARCore Extensions won’t import Cloud Anchor iOS cocoapod into " + + "your project."); + } + + return isEnabled; + } + else + { + return settings.AndroidAuthenticationStrategySetting != + AndroidAuthenticationStrategy.DoNotUse; + } + } + + /// + /// Checking whether this module is compatible with given ARCoreExtensionsConfig and + /// ARCoreExtensionsProjectSettings. If it returns false, the + /// CompatibilityCheckPreprocessBuild will throw a general Build Failure Error. + /// A feature developer should use this function to log detailed error messages that + /// also include a recommendation of how to resolve the issue. Note: This method is + /// called once per session config. Do not log any warning or info messages here to + /// avoid duplicated and/or conflicted information. + /// + /// ARCore Extensions Project Settings. + /// ARCore Extensions Config. + /// Target build platform. + /// The boolean shows whether the ARCoreExtensionsProjectSettings is compatible + /// with the ARCoreExtensionsConfig. + public override bool IsCompatible( + ARCoreExtensionsProjectSettings settings, ARCoreExtensionsConfig sessionConfig, + UnityEditor.BuildTarget buildTarget) + { + if (buildTarget == UnityEditor.BuildTarget.iOS) + { + if (sessionConfig.CloudAnchorMode == CloudAnchorMode.Enabled && + settings.IOSAuthenticationStrategySetting == + IOSAuthenticationStrategy.DoNotUse) + { + Debug.LogErrorFormat( + "Cloud Anchor authentication is required by CloudAnchorMode {0}. " + + "An iOS Authentication Strategy must be set in " + + "Edit > Project Settings > XR > ARCore Extensions > " + + "iOS Authentication Strategy when CloudAnchorMode is {0}", + sessionConfig.CloudAnchorMode); + return false; + } + + return true; + } + else + { + if (sessionConfig.CloudAnchorMode == CloudAnchorMode.Enabled && + settings.AndroidAuthenticationStrategySetting == + AndroidAuthenticationStrategy.DoNotUse) + { + Debug.LogErrorFormat( + "Cloud Anchor authentication is required by CloudAnchorMode {0}. " + + "An Android Authentication Strategy must be set in " + + "Edit > Project Settings > XR > ARCore Extensions > " + + "Android Authentication Strategy when CloudAnchorMode is {0}.", + sessionConfig.CloudAnchorMode); + return false; + } + + return true; + } + } + + /// + /// Checking whether this module is required with given ARCoreExtensionsConfig. + /// In CompatibilityCheckPreprocessBuild, it would loop all explicit sessionConfigs + /// via this funcion. If no session configs require this module but this module is + /// still enabled, then a warning returned by + /// will be logged. + /// + /// ARCore Extensions Config. + /// + /// Whether the module is Required/NotRequired/Optional by the sessionConfig. + /// + public override ModuleNecessity GetModuleNecessity(ARCoreExtensionsConfig sessionConfig) + { + if (sessionConfig.CloudAnchorMode != CloudAnchorMode.Disabled) + { + return ModuleNecessity.Required; + } + + return ModuleNecessity.NotRequired; + } + + /// + /// In CompatibilityCheckPreprocessBuild, if no session configs require this + /// module but this module is still enabled, it would call this function to get + /// a warning message. + /// + /// Target build platform. + /// + /// The warning message if this module is enabled but not required by any sessionConfigs. + /// + public override string GetEnabledNotRequiredWarning( + UnityEditor.BuildTarget buildTarget) + { + if (buildTarget == UnityEditor.BuildTarget.iOS) + { + return "Cloud Anchor Authentication is enabled in " + + "ARCore Extensions Project Settings " + + "but Cloud Anchor is not used in any Scenes in Build.\n" + + "To turn off authentication, select Do Not Use in Edit > " + + "Project Settings > XR > ARCore Extensions > iOS Authentication Strategy."; + } + else + { + return "Cloud Anchor Authentication is enabled in " + + "ARCore Extensions Project Settings " + + "but Cloud Anchor is not used in any Scenes in Build.\n" + + "To turn off authentication, select Do Not Use in Edit > " + + "Project Settings > XR > ARCore Extensions > Android Authentication Strategy."; + } + } + + /// + /// Return the XML snippet needs to be included if location module is enabled. + /// The string output would be added as a child node of in the ‘manifest’ node + /// of the customized AndroidManifest.xml. The android namespace would be provided + /// and feature developers could use it directly. + /// + /// ARCore Extensions Project Settings. + /// The XML string snippet to add as a child of node 'manifest'. + public override string GetAndroidManifestSnippet(ARCoreExtensionsProjectSettings settings) + { + if (!string.IsNullOrEmpty(settings.AndroidCloudServicesApiKey)) + { + return string.Format( + @" + + ", + settings.AndroidCloudServicesApiKey); + } + + return string.Empty; + } + + /// + /// Return the Proguard to include if this module is enabled. The string output will be + /// added into "proguard-user.txt" directly. + /// + /// ARCore Extensions Project Settings. + /// The proguard rule string snippet. + public override string GetProguardSnippet(ARCoreExtensionsProjectSettings settings) + { + if (settings.AndroidAuthenticationStrategySetting == + AndroidAuthenticationStrategy.Keyless) + { + return @"-keep class com.google.android.gms.common.** { *; } + -keep class com.google.android.gms.auth.** { *; } + -keep class com.google.android.gms.tasks.** { *; }"; + } + + return string.Empty; + } + + /// + /// Return the snippet to be used in Play Services Resolver while building Android app. + /// The string output will be added into a new created file whose name would combine the + /// module name and "Dependencies.xml". + /// + /// ARCore Extensions Project Settings. + /// The dependencies to be resolved in Play Services Resolver. + public override string GetAndroidDependenciesSnippet( + ARCoreExtensionsProjectSettings settings) + { + if (settings.AndroidAuthenticationStrategySetting == + AndroidAuthenticationStrategy.Keyless) + { + return @" + "; + } + + return string.Empty; + } +#endif // UNITY_EDITOR + } +} diff --git a/Editor/Scripts/Internal/DependentModules/KeylessModule.cs.meta b/Runtime/Scripts/Internal/DependentModules/FeatureModules/AuthenticationModule.cs.meta similarity index 100% rename from Editor/Scripts/Internal/DependentModules/KeylessModule.cs.meta rename to Runtime/Scripts/Internal/DependentModules/FeatureModules/AuthenticationModule.cs.meta diff --git a/Runtime/Scripts/Internal/DependentModules/IDependentModule.cs b/Runtime/Scripts/Internal/DependentModules/IDependentModule.cs new file mode 100755 index 0000000..296bad2 --- /dev/null +++ b/Runtime/Scripts/Internal/DependentModules/IDependentModule.cs @@ -0,0 +1,151 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.Xml; + using UnityEngine; + + /// + /// The necessity of module. + /// + public enum ModuleNecessity + { + /// + /// The module isn't required. + /// + NotRequired = 0, + + /// + /// The module is optional. + /// + Optional = 1, + + /// + /// The module is required. + /// + Required = 2, + } + + /// + /// The interface needed for a feature module. + /// + public interface IDependentModule + { + /// + /// Get the permissions required by this module during the runtime. + /// + /// ARCore Extensions Config. + /// + /// The array containing the Runtime Permissions’ names required by this module. + /// + string[] GetRuntimePermissions(ARCoreExtensionsConfig sessionConfig); + +#if UNITY_EDITOR + /// + /// Checking whether it needs to be included into the application. If it returns true, + /// all related content, including AndroidManifest, proguard rules and Android external + /// dependencies would be injected during build time. The default values for new fields in + /// ARCoreExtensionsProjectSettings should guarantee the associated module to return false. + /// + /// ARCore Extensions Project Settings. + /// Target build platform. + /// The boolean shows whether the module is enabled. + bool IsEnabled(ARCoreExtensionsProjectSettings settings, + UnityEditor.BuildTarget buildTarget); + + /// + /// Checking whether this module is compatible with given ARCoreExtensionsConfig and + /// ARCoreExtensionsProjectSettings. If it returns false, the + /// CompatibilityCheckPreprocessBuild will throw a general Build Failure Error. + /// A feature developer should use this function to log detailed error messages that + /// also include a recommendation of how to resolve the issue. Note: This method is + /// called once per session config. Do not log any warning or info messages here to + /// avoid duplicated and/or conflicted information. + /// + /// ARCore Extensions Project Settings. + /// ARCore Extensions Config. + /// Target build platform. + /// The boolean shows whether the ARCoreExtensionsProjectSettings is compatible + /// with the ARCoreExtensionsConfig. + bool IsCompatible( + ARCoreExtensionsProjectSettings settings, ARCoreExtensionsConfig sessionConfig, + UnityEditor.BuildTarget buildTarget); + + /// + /// Checking whether this module is required with given ARCoreExtensionsConfig. + /// In CompatibilityCheckPreprocessBuild, it would loop all explicit sessionConfigs + /// via this funcion. If no session configs require this module but this module is + /// still enabled, then a warning returned by + /// will be logged. + /// + /// ARCore Extensions Config. + /// Target build platform. + /// + /// Whether the module is Required/NotRequired/Optional by the sessionConfig. + /// + ModuleNecessity GetModuleNecessity(ARCoreExtensionsConfig sessionConfig); + + /// + /// In CompatibilityCheckPreprocessBuild, if no session configs require this + /// module but this module is still enabled, it would call this function to get + /// a warning message. + /// + /// + /// The warning message if this module is enabled but not required by any sessionConfigs. + /// + string GetEnabledNotRequiredWarning(UnityEditor.BuildTarget buildTarget); + + /// + /// Return the XML snippet to include if this module is enabled. The string output will be + /// added as a child node of the ‘manifest’ node of the customized AndroidManifest.xml. + /// The android namespace will be available. + /// + /// ARCore Extensions Project Settings. + /// The XML string snippet to add as a child of node 'manifest'. + string GetAndroidManifestSnippet(ARCoreExtensionsProjectSettings settings); + + /// + /// Return the Proguard snippet to include if this module is enabled. The string output + /// will be added into "proguard-user.txt" directly. + /// + /// ARCore Extensions Project Settings. + /// The proguard rule string snippet. + string GetProguardSnippet(ARCoreExtensionsProjectSettings settings); + + /// + /// Return the snippet to be used in External Dependencies Resolvor while building + /// Android app. The string output will be added into a new created file whose name + /// would combine the module name and "Dependencies.xml". + /// + /// ARCore Extensions Project Settings. + /// The string snippet to be used in Play Services Resolver. + string GetAndroidDependenciesSnippet(ARCoreExtensionsProjectSettings settings); + + /// + /// Return the iOS dependency template file name of this module, which would be used by + /// External Dependencies Resolvor while building iOS app. + /// + /// iOS dependency template file name of this module. + string GetIOSDependenciesTemplateFileName(); +#endif // UNITY_EDITOR + } +} diff --git a/Editor/Scripts/Internal/DependentModules/IDependentModule.cs.meta b/Runtime/Scripts/Internal/DependentModules/IDependentModule.cs.meta similarity index 100% rename from Editor/Scripts/Internal/DependentModules/IDependentModule.cs.meta rename to Runtime/Scripts/Internal/DependentModules/IDependentModule.cs.meta diff --git a/Runtime/Scripts/Internal/Helpers/DllImportNoop.cs b/Runtime/Scripts/Internal/Helpers/DllImportNoop.cs deleted file mode 100755 index 32bd9c3..0000000 --- a/Runtime/Scripts/Internal/Helpers/DllImportNoop.cs +++ /dev/null @@ -1,29 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -namespace Google.XR.ARCoreExtensions.Internal -{ - internal class DllImportNoop : System.Attribute - { - public DllImportNoop(string dllName) - { - } - } -} diff --git a/Runtime/Scripts/Internal/IOSSupportManager.cs b/Runtime/Scripts/Internal/IOSSupportManager.cs index 7aa0b13..01b27b2 100755 --- a/Runtime/Scripts/Internal/IOSSupportManager.cs +++ b/Runtime/Scripts/Internal/IOSSupportManager.cs @@ -79,6 +79,14 @@ public IntPtr ARCoreSessionHandle } } + public IntPtr ARCoreFrameHandle + { + get + { + return _frameHandle; + } + } + public void SetEnabled(bool enabled) { _isEnabled = enabled; diff --git a/Runtime/Scripts/Internal/RuntimeConfig.cs b/Runtime/Scripts/Internal/RuntimeConfig.cs index 0ee63b3..4fb2535 100755 --- a/Runtime/Scripts/Internal/RuntimeConfig.cs +++ b/Runtime/Scripts/Internal/RuntimeConfig.cs @@ -20,6 +20,7 @@ namespace Google.XR.ARCoreExtensions.Internal { + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -34,6 +35,8 @@ public class RuntimeConfig : ScriptableObject public string IOSCloudServicesApiKey; + public List ModulesEnabled = new List(); + // GUID to folder [ARCore Extensions]/Runtime private const string _runtimeFolderGUID = "df6f7c8173aef4ce18044d1392042d34"; @@ -92,6 +95,13 @@ public static void SetIOSApiKey(string apiKey) Instance.IOSCloudServicesApiKey = apiKey; UploadInstance(); } + + public static void SetEnabledModules(List modulesEnabled) + { + LoadInstance(); + Instance.ModulesEnabled = modulesEnabled; + UploadInstance(); + } #endif public void OnEnable() diff --git a/Runtime/Scripts/Internal/Wrappers/AnchorApi.cs b/Runtime/Scripts/Internal/Wrappers/AnchorApi.cs index c4f9090..209c12f 100755 --- a/Runtime/Scripts/Internal/Wrappers/AnchorApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/AnchorApi.cs @@ -86,8 +86,6 @@ public static void Release( ExternApi.ArAnchor_release(anchorHandle); } - [SuppressMessage("UnityRules.UnityStyleRules", "US1113:MethodsMustBeUpperCamelCase", - Justification = "External call.")] private struct ExternApi { [DllImport(ApiConstants.ARCoreNativeApi)] diff --git a/Runtime/Scripts/Internal/Wrappers/CameraConfigApi.cs b/Runtime/Scripts/Internal/Wrappers/CameraConfigApi.cs index 76d1da8..f1bdcd0 100755 --- a/Runtime/Scripts/Internal/Wrappers/CameraConfigApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/CameraConfigApi.cs @@ -22,11 +22,10 @@ namespace Google.XR.ARCoreExtensions.Internal { using System; using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; using UnityEngine; -#if UNITY_IOS && !UNITY_EDITOR - using AndroidImport = Google.XR.ARCoreExtensions.Internal.DllImportNoop; -#else +#if UNITY_ANDROID using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; #endif @@ -36,8 +35,10 @@ public static CameraConfigFacingDirection GetFacingDirection( IntPtr sessionHandle, IntPtr cameraConfigHandle) { CameraConfigFacingDirection facingDirection = CameraConfigFacingDirection.Back; +#if UNITY_ANDROID ExternApi.ArCameraConfig_getFacingDirection(sessionHandle, cameraConfigHandle, ref facingDirection); +#endif return facingDirection; } @@ -46,8 +47,10 @@ public static Vector2Int GetTextureDimensions( { int width = 0; int height = 0; +#if UNITY_ANDROID ExternApi.ArCameraConfig_getTextureDimensions( sessionHandle, cameraConfigHandle, ref width, ref height); +#endif return new Vector2Int(width, height); } @@ -56,8 +59,10 @@ public static Vector2Int GetFPSRange( { int minFps = 0; int maxFps = 0; +#if UNITY_ANDROID ExternApi.ArCameraConfig_getFpsRange( sessionHandle, cameraConfigHandle, ref minFps, ref maxFps); +#endif return new Vector2Int(minFps, maxFps); } @@ -65,8 +70,10 @@ public static CameraConfigDepthSensorUsage GetDepthSensorUsage( IntPtr sessionHandle, IntPtr cameraConfigHandle) { int depth = (int)CameraConfigDepthSensorUsage.DoNotUse; +#if UNITY_ANDROID ExternApi.ArCameraConfig_getDepthSensorUsage( sessionHandle, cameraConfigHandle, ref depth); +#endif return (CameraConfigDepthSensorUsage)depth; } @@ -74,16 +81,16 @@ public static CameraConfigStereoCameraUsage GetStereoCameraUsage( IntPtr sessionHandle, IntPtr cameraConfigHandle) { int stereo = (int)CameraConfigStereoCameraUsage.DoNotUse; +#if UNITY_ANDROID ExternApi.ArCameraConfig_getStereoCameraUsage(sessionHandle, cameraConfigHandle, ref stereo); +#endif return (CameraConfigStereoCameraUsage)stereo; } - [SuppressMessage("UnityRules.UnityStyleRules", "US1113:MethodsMustBeUpperCamelCase", - Justification = "External call.")] private struct ExternApi { -#pragma warning disable 626 +#if UNITY_ANDROID [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArCameraConfig_getFacingDirection( IntPtr sessionHandle, @@ -105,7 +112,7 @@ public static extern void ArCameraConfig_getDepthSensorUsage( [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArCameraConfig_getStereoCameraUsage( IntPtr sessionHandle, IntPtr cameraConfigHandle, ref int stereoCameraUsage); -#pragma warning restore 626 +#endif // UNITY_ANDROID } } } diff --git a/Runtime/Scripts/Internal/Wrappers/CameraConfigFilterApi.cs b/Runtime/Scripts/Internal/Wrappers/CameraConfigFilterApi.cs index f3254a2..4e6049d 100755 --- a/Runtime/Scripts/Internal/Wrappers/CameraConfigFilterApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/CameraConfigFilterApi.cs @@ -21,10 +21,9 @@ namespace Google.XR.ARCoreExtensions.Internal { using System; + using System.Runtime.InteropServices; -#if UNITY_IOS && !UNITY_EDITOR - using AndroidImport = Google.XR.ARCoreExtensions.Internal.DllImportNoop; -#else +#if UNITY_ANDROID using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; #endif @@ -35,18 +34,20 @@ public static void UpdateFilter(IntPtr sessionHandle, IntPtr filterHandle, { if (extensionsFilter != null) { +#if UNITY_ANDROID ExternApi.ArCameraConfigFilter_setTargetFps( sessionHandle, filterHandle, (int)extensionsFilter.TargetCameraFramerate); ExternApi.ArCameraConfigFilter_setDepthSensorUsage( sessionHandle, filterHandle, (int)extensionsFilter.DepthSensorUsage); ExternApi.ArCameraConfigFilter_setStereoCameraUsage( sessionHandle, filterHandle, (int)extensionsFilter.StereoCameraUsage); +#endif } } private struct ExternApi { -#pragma warning disable 626 +#if UNITY_ANDROID [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArCameraConfigFilter_setTargetFps(IntPtr sessionHandle, IntPtr cameraConfigFilterHandle, int fpsFilter); @@ -58,7 +59,7 @@ public static extern void ArCameraConfigFilter_setDepthSensorUsage(IntPtr sessio [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArCameraConfigFilter_setStereoCameraUsage( IntPtr sessionHandle, IntPtr cameraConfigFilterHandle, int stereoFilter); -#pragma warning restore 626 +#endif } } } diff --git a/Runtime/Scripts/Internal/Wrappers/FrameApi.cs b/Runtime/Scripts/Internal/Wrappers/FrameApi.cs new file mode 100755 index 0000000..1f76f6e --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/FrameApi.cs @@ -0,0 +1,121 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.Collections.Generic; + using System.Runtime.InteropServices; + using UnityEngine; + +#if UNITY_ANDROID + using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; +#elif UNITY_IOS && ARCORE_EXTENSIONS_IOS_SUPPORT + using IOSImport = System.Runtime.InteropServices.DllImportAttribute; +#endif + + internal class FrameApi + { + + public static RecordingResult RecordTrackData( + IntPtr sessionHandle, IntPtr frameHandle, Guid trackId, byte[] data) + { + ApiArStatus status = ApiArStatus.ErrorFatal; +#if UNITY_ANDROID + GCHandle trackIdHandle = GCHandle.Alloc(trackId.ToByteArray(), GCHandleType.Pinned); + GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); + + status = ExternApi.ArFrame_recordTrackData( + sessionHandle, + frameHandle, + trackIdHandle.AddrOfPinnedObject(), + dataHandle.AddrOfPinnedObject(), + data.Length); + + if (trackIdHandle.IsAllocated) + { + trackIdHandle.Free(); + } + + if (dataHandle.IsAllocated) + { + dataHandle.Free(); + } +#endif + + return status.ToRecordingResult(); + } + + public static List GetUpdatedTrackData(IntPtr sessionHandle, + IntPtr frameHandle, + Guid trackId) + { + List trackDataList = new List(); +#if UNITY_ANDROID + IntPtr listHandle = TrackDataListApi.Create(sessionHandle); + + GCHandle trackIdHandle = GCHandle.Alloc(trackId.ToByteArray(), + GCHandleType.Pinned); + + ExternApi.ArFrame_getUpdatedTrackData(sessionHandle, + frameHandle, + trackIdHandle.AddrOfPinnedObject(), + listHandle); + + if (trackIdHandle.IsAllocated) + { + trackIdHandle.Free(); + } + + int count = TrackDataListApi.GetCount(sessionHandle, listHandle); + for (int i = 0; i < count; i++) + { + IntPtr trackDataHandle = + TrackDataListApi.AcquireItem(sessionHandle, listHandle, i); + + TrackData trackData; + trackData.FrameTimestamp = + TrackDataApi.GetFrameTimestamp(sessionHandle, trackDataHandle); + trackData.Data = TrackDataApi.GetData(sessionHandle, trackDataHandle); + + trackDataList.Add(trackData); + } + + TrackDataListApi.Destroy(listHandle); +#endif // UNITY_ANDROID + return trackDataList; + } + private struct ExternApi + { +#if UNITY_ANDROID + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern ApiArStatus ArFrame_recordTrackData( + IntPtr sessionHandle, IntPtr frameHandle, IntPtr trackIdBytes, IntPtr payloadBytes, + int payloadSize); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArFrame_getUpdatedTrackData( + IntPtr sessionHandle, IntPtr frameHandle, IntPtr trackId, IntPtr trackDataList); +#elif UNITY_IOS && ARCORE_EXTENSIONS_IOS_SUPPORT +#endif + } + } +} diff --git a/Runtime/Scripts/Internal/Wrappers/FrameApi.cs.meta b/Runtime/Scripts/Internal/Wrappers/FrameApi.cs.meta new file mode 100755 index 0000000..aaeec86 --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/FrameApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d8d85540aba543d69d2c8862f5b0246 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/Internal/Wrappers/PoseApi.cs b/Runtime/Scripts/Internal/Wrappers/PoseApi.cs index 34071bd..8e5477b 100755 --- a/Runtime/Scripts/Internal/Wrappers/PoseApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/PoseApi.cs @@ -60,8 +60,6 @@ public static ApiPose ExtractPoseValue( return apiPose; } - [SuppressMessage("UnityRules.UnityStyleRules", "US1113:MethodsMustBeUpperCamelCase", - Justification = "External call.")] private struct ExternApi { [DllImport(ApiConstants.ARCoreNativeApi)] diff --git a/Runtime/Scripts/Internal/Wrappers/RecordingConfigApi.cs b/Runtime/Scripts/Internal/Wrappers/RecordingConfigApi.cs index f951b73..11f58d1 100755 --- a/Runtime/Scripts/Internal/Wrappers/RecordingConfigApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/RecordingConfigApi.cs @@ -21,10 +21,9 @@ namespace Google.XR.ARCoreExtensions.Internal { using System; + using System.Runtime.InteropServices; -#if UNITY_IOS && ARCORE_EXTENSIONS_IOS_SUPPORT - using AndroidImport = Google.XR.ARCoreExtensions.Internal.DllImportNoop; -#else +#if UNITY_ANDROID using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; #endif @@ -33,6 +32,7 @@ internal class RecordingConfigApi public static IntPtr Create(IntPtr sessionHandle, ARCoreRecordingConfig config) { IntPtr configHandle = IntPtr.Zero; +#if UNITY_ANDROID ExternApi.ArRecordingConfig_create(sessionHandle, ref configHandle); if (config != null) @@ -45,19 +45,33 @@ public static IntPtr Create(IntPtr sessionHandle, ARCoreRecordingConfig config) sessionHandle, configHandle, config.AutoStopOnPause ? 1 : 0); + foreach (Track track in config.Tracks) + { + IntPtr trackHandle = TrackApi.Create(sessionHandle, track); + + ExternApi.ArRecordingConfig_addTrack(sessionHandle, configHandle, trackHandle); + + // Internally the recording config uses the TrackData to generate its + // own local structures, so it is appropriate to destroy it after sending it to + // the recording config. + TrackApi.Destroy(trackHandle); + } } +#endif return configHandle; } public static void Destroy(IntPtr recordingConfigHandle) { +#if UNITY_ANDROID ExternApi.ArRecordingConfig_destroy(recordingConfigHandle); +#endif } private struct ExternApi { -#pragma warning disable 626 +#if UNITY_ANDROID [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArRecordingConfig_create( IntPtr session, ref IntPtr configHandle); @@ -73,7 +87,11 @@ public static extern void ArRecordingConfig_setMp4DatasetFilePath( [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArRecordingConfig_setAutoStopOnPause( IntPtr session, IntPtr configHandle, int configEnabled); -#pragma warning restore 626 + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArRecordingConfig_addTrack( + IntPtr session, IntPtr configHandle, IntPtr trackHandle); +#endif } } } diff --git a/Runtime/Scripts/Internal/Wrappers/SessionApi.cs b/Runtime/Scripts/Internal/Wrappers/SessionApi.cs index f6582df..ba5663d 100755 --- a/Runtime/Scripts/Internal/Wrappers/SessionApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/SessionApi.cs @@ -26,12 +26,10 @@ namespace Google.XR.ARCoreExtensions.Internal using System.Runtime.InteropServices; using UnityEngine; -#if UNITY_IOS && !UNITY_EDITOR - using AndroidImport = Google.XR.ARCoreExtensions.Internal.DllImportNoop; - using IOSImport = System.Runtime.InteropServices.DllImportAttribute; -#else +#if UNITY_ANDROID using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; - using IOSImport = Google.XR.ARCoreExtensions.Internal.DllImportNoop; +#elif UNITY_IOS && ARCORE_EXTENSIONS_IOS_SUPPORT + using IOSImport = System.Runtime.InteropServices.DllImportAttribute; #endif internal class SessionApi @@ -42,20 +40,16 @@ public static void ReleaseFrame(IntPtr frameHandle) } public static void UpdateSessionConfig( - IntPtr sessionHandle, - IntPtr configHandle, - ARCoreExtensionsConfig config) + IntPtr sessionHandle, IntPtr configHandle, ARCoreExtensionsConfig config) { #if UNITY_ANDROID ApiCloudAnchorMode cloudAnchorMode = (ApiCloudAnchorMode)config.CloudAnchorMode; ExternApi.ArConfig_setCloudAnchorMode( sessionHandle, configHandle, cloudAnchorMode); -#endif +#endif // UNITY_ANDROID } - public static IntPtr HostCloudAnchor( - IntPtr sessionHandle, - IntPtr anchorHandle) + public static IntPtr HostCloudAnchor(IntPtr sessionHandle, IntPtr anchorHandle) { IntPtr cloudAnchorHandle = IntPtr.Zero; ApiArStatus status = ExternApi.ArSession_hostAndAcquireNewCloudAnchor( @@ -70,10 +64,7 @@ public static IntPtr HostCloudAnchor( return cloudAnchorHandle; } - public static IntPtr HostCloudAnchor( - IntPtr sessionHandle, - IntPtr anchorHandle, - int ttlDays) + public static IntPtr HostCloudAnchor(IntPtr sessionHandle, IntPtr anchorHandle, int ttlDays) { IntPtr cloudAnchorHandle = IntPtr.Zero; ApiArStatus status = ExternApi.ArSession_hostAndAcquireNewCloudAnchorWithTtl( @@ -89,12 +80,12 @@ public static IntPtr HostCloudAnchor( public static void SetAuthToken(IntPtr sessionHandle, string authToken) { +#if UNITY_IOS && ARCORE_EXTENSIONS_IOS_SUPPORT ExternApi.ArSession_setAuthToken(sessionHandle, authToken); +#endif } - public static IntPtr ResolveCloudAnchor( - IntPtr sessionHandle, - string cloudAnchorId) + public static IntPtr ResolveCloudAnchor(IntPtr sessionHandle, string cloudAnchorId) { IntPtr cloudAnchorHandle = IntPtr.Zero; ApiArStatus status = ExternApi.ArSession_resolveAndAcquireNewCloudAnchor( @@ -129,45 +120,52 @@ public static FeatureMapQuality EstimateFeatureMapQualityForHosting( public static RecordingStatus GetRecordingStatus(IntPtr sessionHandle) { ApiRecordingStatus apiStatus = ApiRecordingStatus.None; +#if UNITY_ANDROID ExternApi.ArSession_getRecordingStatus(sessionHandle, ref apiStatus); +#endif return apiStatus.ToRecordingStatus(); } public static RecordingResult StartRecording( IntPtr sessionHandle, ARCoreRecordingConfig config) { + ApiArStatus status = ApiArStatus.ErrorFatal; +#if UNITY_ANDROID IntPtr recordingConfigHandle = RecordingConfigApi.Create(sessionHandle, config); - - ApiArStatus status = ExternApi.ArSession_startRecording( - sessionHandle, recordingConfigHandle); - + status = ExternApi.ArSession_startRecording(sessionHandle, recordingConfigHandle); RecordingConfigApi.Destroy(recordingConfigHandle); +#endif return status.ToRecordingResult(); } public static RecordingResult StopRecording(IntPtr sessionHandle) { - ApiArStatus status = ExternApi.ArSession_stopRecording(sessionHandle); + ApiArStatus status = ApiArStatus.ErrorFatal; +#if UNITY_ANDROID + status = ExternApi.ArSession_stopRecording(sessionHandle); +#endif return status.ToRecordingResult(); } public static PlaybackStatus GetPlaybackStatus(IntPtr sessionHandle) { ApiPlaybackStatus apiStatus = ApiPlaybackStatus.None; +#if UNITY_ANDROID ExternApi.ArSession_getPlaybackStatus(sessionHandle, ref apiStatus); +#endif return apiStatus.ToPlaybackStatus(); } public static PlaybackResult SetPlaybackDataset( IntPtr sessionHandle, string datasetFilepath) { - ApiArStatus status = - ExternApi.ArSession_setPlaybackDataset(sessionHandle, datasetFilepath); + ApiArStatus status = ApiArStatus.ErrorFatal; +#if UNITY_ANDROID + status = ExternApi.ArSession_setPlaybackDataset(sessionHandle, datasetFilepath); +#endif return status.ToPlaybackResult(); } - [SuppressMessage("UnityRules.UnityStyleRules", "US1113:MethodsMustBeUpperCamelCase", - Justification = "External call.")] private struct ExternApi { [DllImport(ApiConstants.ARCoreNativeApi)] @@ -191,19 +189,21 @@ public static extern ApiArStatus ArSession_hostAndAcquireNewCloudAnchorWithTtl( IntPtr anchorHandle, int ttlDays, ref IntPtr cloudAnchorHandle); +#if UNITY_IOS && ARCORE_EXTENSIONS_IOS_SUPPORT - [DllImport(ApiConstants.ARCoreNativeApi)] + [IOSImport(ApiConstants.ARCoreNativeApi)] public static extern void ArSession_setAuthToken( IntPtr sessionHandle, String authToken); +#endif [DllImport(ApiConstants.ARCoreNativeApi)] public static extern ApiArStatus ArSession_estimateFeatureMapQualityForHosting( IntPtr sessionHandle, IntPtr poseHandle, ref int featureMapQuality); +#if UNITY_ANDROID -#pragma warning disable 626 [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern void ArSession_getConfig( IntPtr sessionHandle, @@ -254,7 +254,7 @@ public static extern void ArSession_getPlaybackStatus( [AndroidImport(ApiConstants.ARCoreNativeApi)] public static extern ApiArStatus ArSession_setPlaybackDataset( IntPtr sessionHandle, string datasetFilepath); -#pragma warning restore 626 +#endif // UNITY_ANDROID } } } diff --git a/Runtime/Scripts/Internal/Wrappers/TrackApi.cs b/Runtime/Scripts/Internal/Wrappers/TrackApi.cs new file mode 100755 index 0000000..c9803dd --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/TrackApi.cs @@ -0,0 +1,96 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.Runtime.InteropServices; + using UnityEngine; + +#if UNITY_ANDROID + using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; +#endif // UNITY_ANDROID + + internal class TrackApi + { + public static IntPtr Create(IntPtr sessionHandle, Track track) + { + IntPtr trackHandle = IntPtr.Zero; +#if UNITY_ANDROID + ExternApi.ArTrack_create(sessionHandle, ref trackHandle); + + // Track ID + GCHandle trackIdHandle = GCHandle.Alloc(track.Id.ToByteArray(), GCHandleType.Pinned); + ExternApi.ArTrack_setId(sessionHandle, trackHandle, trackIdHandle.AddrOfPinnedObject()); + + if (trackIdHandle.IsAllocated) + { + trackIdHandle.Free(); + } + + // Metadata + GCHandle metadataHandle = GCHandle.Alloc(track.Metadata, GCHandleType.Pinned); + ExternApi.ArTrack_setMetadata(sessionHandle, trackHandle, + metadataHandle.AddrOfPinnedObject(), + track.Metadata.Length); + + if (metadataHandle.IsAllocated) + { + metadataHandle.Free(); + } + + // Mime Type + ExternApi.ArTrack_setMimeType(sessionHandle, trackHandle, track.MimeType); +#endif // UNITY_ANDROID + return trackHandle; + } + + public static void Destroy(IntPtr trackHandle) + { +#if UNITY_ANDROID + ExternApi.ArTrack_destroy(trackHandle); +#endif + } + + private struct ExternApi + { +#if UNITY_ANDROID + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrack_create(IntPtr session, ref IntPtr trackHandle); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrack_destroy(IntPtr trackHandle); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrack_setId(IntPtr session, IntPtr trackHandle, + IntPtr trackIdBytes); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrack_setMetadata(IntPtr session, IntPtr trackHandle, + IntPtr metadataBytes, + int metadataBufferSize); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrack_setMimeType(IntPtr session, IntPtr trackHandle, + string mimeType); +#endif + } + } +} diff --git a/Runtime/Scripts/Internal/Wrappers/TrackApi.cs.meta b/Runtime/Scripts/Internal/Wrappers/TrackApi.cs.meta new file mode 100755 index 0000000..661ea39 --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/TrackApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02e3f1682b14a4d28b0f38c5284dc000 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/Internal/Wrappers/TrackDataApi.cs b/Runtime/Scripts/Internal/Wrappers/TrackDataApi.cs new file mode 100755 index 0000000..b8d89fe --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/TrackDataApi.cs @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.Runtime.InteropServices; + using UnityEngine; + +#if UNITY_ANDROID + using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; +#endif + + internal class TrackDataApi + { + public static long GetFrameTimestamp(IntPtr sessionHandle, IntPtr trackDataHandle) + { + long timestamp = 0L; +#if UNITY_ANDROID + ExternApi.ArTrackData_getFrameTimestamp(sessionHandle, trackDataHandle, ref timestamp); +#endif + return timestamp; + } + + public static byte[] GetData(IntPtr sessionHandle, IntPtr trackDataHandle) + { + IntPtr dataPtr = IntPtr.Zero; + int size = 0; +#if UNITY_ANDROID + ExternApi.ArTrackData_getData(sessionHandle, trackDataHandle, ref dataPtr, ref size); +#endif + byte[] data = new byte[size]; + if (size > 0) + { + Marshal.Copy(dataPtr, data, 0, size); + } + + return data; + } + + public static void Release(IntPtr trackDataHandle) + { +#if UNITY_ANDROID + ExternApi.ArTrackData_release(trackDataHandle); +#endif + } + + private struct ExternApi + { +#if UNITY_ANDROID + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackData_getFrameTimestamp( + IntPtr sessionHandle, IntPtr trackDataHandle, ref long timestamp); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackData_getData( + IntPtr sessionHandle, IntPtr trackDataHandle, ref IntPtr dataBytesHandle, + ref int size); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackData_release(IntPtr trackDataHandle); +#endif // UNITY_ANDROID + } + } +} diff --git a/Runtime/Scripts/Internal/Wrappers/TrackDataApi.cs.meta b/Runtime/Scripts/Internal/Wrappers/TrackDataApi.cs.meta new file mode 100755 index 0000000..9148726 --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/TrackDataApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94bb7b75444494ac18123ab5840b184d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/Internal/Wrappers/TrackDataListApi.cs b/Runtime/Scripts/Internal/Wrappers/TrackDataListApi.cs new file mode 100755 index 0000000..75f7496 --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/TrackDataListApi.cs @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.Internal +{ + using System; + using System.Runtime.InteropServices; + using UnityEngine; + +#if UNITY_ANDROID + using AndroidImport = System.Runtime.InteropServices.DllImportAttribute; +#endif + + internal class TrackDataListApi + { + public static IntPtr Create(IntPtr sessionHandle) + { + IntPtr handle = IntPtr.Zero; +#if UNITY_ANDROID + ExternApi.ArTrackDataList_create(sessionHandle, ref handle); +#endif + return handle; + } + + public static void Destroy(IntPtr listHandle) + { +#if UNITY_ANDROID + ExternApi.ArTrackDataList_destroy(listHandle); +#endif + } + + public static int GetCount(IntPtr sessionHandle, IntPtr listHandle) + { + int count = 0; +#if UNITY_ANDROID + ExternApi.ArTrackDataList_getSize(sessionHandle, listHandle, ref count); +#endif + return count; + } + + public static IntPtr AcquireItem(IntPtr sessionHandle, IntPtr listHandle, int index) + { + IntPtr trackDataHandle = IntPtr.Zero; +#if UNITY_ANDROID + ExternApi.ArTrackDataList_acquireItem(sessionHandle, listHandle, index, + ref trackDataHandle); +#endif + return trackDataHandle; + } + + private struct ExternApi + { +#if UNITY_ANDROID + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackDataList_create( + IntPtr sessionHandle, ref IntPtr trackDataListHandle); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackDataList_destroy(IntPtr trackDataListHandle); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackDataList_getSize( + IntPtr sessionHandle, IntPtr trackDataListHandle, ref int outSize); + + [AndroidImport(ApiConstants.ARCoreNativeApi)] + public static extern void ArTrackDataList_acquireItem( + IntPtr sessionHandle, IntPtr trackDataListHandle, int index, + ref IntPtr outTrackData); +#endif // UNITY_ANDROID + } + } +} diff --git a/Runtime/Scripts/Internal/Wrappers/TrackDataListApi.cs.meta b/Runtime/Scripts/Internal/Wrappers/TrackDataListApi.cs.meta new file mode 100755 index 0000000..50d6e04 --- /dev/null +++ b/Runtime/Scripts/Internal/Wrappers/TrackDataListApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82b6aafa1b16f479e9b39201bd96e90b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/PlaybackResult.cs b/Runtime/Scripts/PlaybackResult.cs index fd0218d..3554412 100755 --- a/Runtime/Scripts/PlaybackResult.cs +++ b/Runtime/Scripts/PlaybackResult.cs @@ -30,6 +30,18 @@ public enum PlaybackResult /// OK, + /// + /// The call to + /// failed because ARCore is currently attempting to resume or pause the session. + /// + /// Try calling it again in the next frame. Note: + /// + /// Resuming session may require several frames to complete. + /// Pausing session may take up to 10 seconds to pause. + /// + /// + SessionNotReady, + /// /// The session was not paused when setting the playback dataset. /// diff --git a/Runtime/Scripts/RecordingResult.cs b/Runtime/Scripts/RecordingResult.cs index 8c4c099..674ec66 100755 --- a/Runtime/Scripts/RecordingResult.cs +++ b/Runtime/Scripts/RecordingResult.cs @@ -31,7 +31,22 @@ public enum RecordingResult OK, /// - /// The was null or invalid. + /// The call to + /// failed because ARCore is currently attempting to resume or pause the session. + /// + /// Try calling it again in the next frame. Note: + /// + /// Resuming session may require several frames to complete. + /// Pausing session may take up to 10 seconds to pause. + /// + /// + SessionNotReady, + + /// + /// When using , this + /// means the was null or invalid. + /// When using , + /// this means the track id or payload given are null or invalid. /// ErrorInvalidArgument, @@ -41,7 +56,10 @@ public enum RecordingResult ErrorRecordingFailed, /// - /// A recording is already in progress. + /// When using , this + /// means a recording is already in progress. + /// When using , this means + /// the session may not be ready yet, common immediately after resume. /// ErrorIllegalState, } diff --git a/Runtime/Scripts/Track.cs b/Runtime/Scripts/Track.cs new file mode 100755 index 0000000..6c9d9e1 --- /dev/null +++ b/Runtime/Scripts/Track.cs @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions +{ + using System; + using UnityEngine; + + /// + /// Definition of a track to record on. Data recorded to a given track will be muxed into a + /// corresponding MP4 stream. + /// + public struct Track + { + /// + /// Unique ID for the track. + /// + public Guid Id; + + /// + /// Arbitrary byte array describing the track. The encoding is the user's choice. This is + /// a null-terminated string. + /// + public byte[] Metadata; + + /// + /// MIME type of the track data as a null terminated string. + /// + public string MimeType; + } +} diff --git a/Runtime/Scripts/Track.cs.meta b/Runtime/Scripts/Track.cs.meta new file mode 100755 index 0000000..ababb37 --- /dev/null +++ b/Runtime/Scripts/Track.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab88d3d1402a84c96a33a74b6f5ce929 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/TrackData.cs b/Runtime/Scripts/TrackData.cs new file mode 100755 index 0000000..431ce05 --- /dev/null +++ b/Runtime/Scripts/TrackData.cs @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions +{ + using System; + using UnityEngine; + + /// + /// Data that was recorded to an external Track. Retrievable through Frame. + /// + public struct TrackData + { + /// + /// The timestamp in nanoseconds of the frame the given was + /// recorded on. If frames are skipped during playback, the played back external track data + /// may be attached to a later frame. This timestamp is equal to the result of + /// + /// on the frame during which track data was written. + /// + public long FrameTimestamp; + + /// + /// The byte data array that was recorded via + /// . + /// + public byte[] Data; + } +} diff --git a/Runtime/Scripts/TrackData.cs.meta b/Runtime/Scripts/TrackData.cs.meta new file mode 100755 index 0000000..fb7f394 --- /dev/null +++ b/Runtime/Scripts/TrackData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3b92a325a77c4d049f71d89881dbdc3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/VersionInfo.cs b/Runtime/Scripts/VersionInfo.cs index 41ec22a..295936a 100755 --- a/Runtime/Scripts/VersionInfo.cs +++ b/Runtime/Scripts/VersionInfo.cs @@ -28,6 +28,6 @@ public class VersionInfo /// /// The current ARCore Extensions package version. /// - public static readonly string Version = "1.23.0"; + public static readonly string Version = "1.24.0"; } } diff --git a/Samples~/CloudAnchors/Scripts/CloudAnchorsExampleController.cs b/Samples~/CloudAnchors/Scripts/CloudAnchorsExampleController.cs index f185014..ff007bb 100755 --- a/Samples~/CloudAnchors/Scripts/CloudAnchorsExampleController.cs +++ b/Samples~/CloudAnchors/Scripts/CloudAnchorsExampleController.cs @@ -370,7 +370,9 @@ public void Update() } else if (!IsOriginPlaced && _currentMode == ApplicationMode.Hosting) { +#pragma warning disable CS0618 // TODO(b/181068602): Modify the way of adding anchor. ARAnchor anchor = AnchorManager.AddAnchor(hitResults[0].pose); +#pragma warning restore CS0618 WorldOrigin = anchor.transform; InstantiateAnchor(anchor); OnAnchorInstantiated(true); diff --git a/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs b/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs index f899cd5..b6f83cb 100755 --- a/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs +++ b/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs @@ -382,7 +382,9 @@ private void PerformHitTest(Vector2 touchPos) new Vector3(0.0f, Controller.MainCamera.transform.eulerAngles.y, 0.0f); } +#pragma warning disable CS0618 // TODO(b/181068602): Modify the way of adding anchor. _anchor = Controller.AnchorManager.AddAnchor(hitPose); +#pragma warning restore CS0618 } if (_anchor != null) diff --git a/package.json b/package.json index 5a096fc..3572fb4 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.google.ar.core.arfoundation.extensions", "displayName": "ARCore Extensions", - "version": "1.23.0", + "version": "1.24.0", "unity": "2019.4", "description": "Google ARCore Extensions for AR Foundation. This package provides access to ARCore features not covered by AR Foundation's cross platform API.", "author": @@ -10,8 +10,8 @@ }, "dependencies": { - "com.unity.xr.arfoundation": "4.1.0-preview.10", - "com.unity.xr.arcore": "4.1.0-preview.10" + "com.unity.xr.arfoundation": "4.1.5", + "com.unity.xr.arcore": "4.1.5" }, "samples": [ {