public CameraConfigDepthSensorUsage GetDepthSensorUsage(IntPtr cameraConfigHandle)
        {
            int depthSensorUsage = (int)CameraConfigDepthSensorUsage.DoNotUse;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access ARCamera DepthSensorUsage");
                return((CameraConfigDepthSensorUsage)depthSensorUsage);
            }

            ExternApi.ArCameraConfig_getDepthSensorUsage(
                _nativeSession.SessionHandle, cameraConfigHandle, ref depthSensorUsage);
            return((CameraConfigDepthSensorUsage)depthSensorUsage);
        }
Пример #2
0
        public void GetImageDimensions(IntPtr cameraConfigHandle, out int width, out int height)
        {
            width  = 0;
            height = 0;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access ARCamera image dimensions");
                return;
            }

            ExternApi.ArCameraConfig_getImageDimensions(
                m_NativeSession.SessionHandle, cameraConfigHandle, ref width, ref height);
        }
Пример #3
0
        public void CreateSession(ARCoreSession sessionComponent)
        {
            sessionComponent.StartCoroutine(InstantPreviewManager.InitializeIfNeeded());

            if (SessionComponent != null)
            {
                Debug.LogError("Multiple ARCore session components cannot exist in the scene. " +
                               "Destroying the newest.");
                GameObject.Destroy(sessionComponent);
                return;
            }

            SessionComponent = sessionComponent;
        }
        public int AddAugmentedImageAtRuntime(IntPtr augmentedImageDatabaseHandle, string name,
                                              AugmentedImageSrc imageSrc, float width)
        {
            int outIndex = -1;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage(
                    "add images to Augmented Image database");
                return(outIndex);
            }

            GCHandle grayscaleBytesHandle = ConvertTextureToGrayscaleBytes(imageSrc);

            if (grayscaleBytesHandle.AddrOfPinnedObject() == IntPtr.Zero)
            {
                return(-1);
            }

            ApiArStatus status;

            if (width > 0)
            {
                status = ExternApi.ArAugmentedImageDatabase_addImageWithPhysicalSize(
                    _nativeSession.SessionHandle, augmentedImageDatabaseHandle, name,
                    grayscaleBytesHandle.AddrOfPinnedObject(), imageSrc._width,
                    imageSrc._height, imageSrc._width, width, ref outIndex);
            }
            else
            {
                status = ExternApi.ArAugmentedImageDatabase_addImage(
                    _nativeSession.SessionHandle, augmentedImageDatabaseHandle, name,
                    grayscaleBytesHandle.AddrOfPinnedObject(), imageSrc._width,
                    imageSrc._height, imageSrc._width, ref outIndex);
            }

            if (grayscaleBytesHandle.IsAllocated)
            {
                grayscaleBytesHandle.Free();
            }

            if (status != ApiArStatus.Success)
            {
                Debug.LogWarningFormat(
                    "Failed to add aumented image at runtime with status {0}", status);
                return(-1);
            }

            return(outIndex);
        }
        public void GetFpsRange(IntPtr cameraConfigHandle, out int minFps, out int maxFps)
        {
            minFps = 0;
            maxFps = 0;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access ARCamera FpsRange");
                return;
            }

            ExternApi.ArCameraConfig_getFpsRange(
                _nativeSession.SessionHandle, cameraConfigHandle, ref minFps, ref maxFps);
        }
Пример #6
0
        public void CreateSession(ARCoreSession session)
        {
            session.StartCoroutine(InstantPreviewManager.InitializeIfNeeded());

            if (m_SessionComponent != null)
            {
                //Debug.LogError("Multiple session components cannot exist in the scene. " +
                //"Destroying the newest.");
                //GameObject.Destroy(session);
                //return;
            }

            m_SessionComponent = session;
            EnableSession();
        }
Пример #7
0
        public ApiCameraConfigFacingDirection GetFacingDirection(IntPtr cameraConfigHandle)
        {
            ApiCameraConfigFacingDirection direction = ApiCameraConfigFacingDirection.Back;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access ARCamera facing direction");
                return(direction);
            }

            ExternApi.ArCameraConfig_getFacingDirection(
                m_NativeSession.SessionHandle, cameraConfigHandle, ref direction);

            return(direction);
        }
Пример #8
0
        public LostTrackingReason GetLostTrackingReason(IntPtr cameraHandle)
        {
            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("determine tracking failure " +
                                                               "reasons");
                return(LostTrackingReason.None);
            }

            ApiTrackingFailureReason apiTrackingFailureReason = ApiTrackingFailureReason.None;

            ExternApi.ArCamera_getTrackingFailureReason(m_NativeSession.SessionHandle,
                                                        cameraHandle, ref apiTrackingFailureReason);
            return(apiTrackingFailureReason.ToLostTrackingReason());
        }
Пример #9
0
        public CameraConfig GetCameraConfig()
        {
            IntPtr cameraConfigHandle = m_NativeSession.CameraConfigApi.Create();

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access camera config");
                return(new CameraConfig());
            }

            ExternApi.ArSession_getCameraConfig(m_NativeSession.SessionHandle, cameraConfigHandle);
            CameraConfig currentCameraConfig = _CreateCameraConfig(cameraConfigHandle);

            m_NativeSession.CameraConfigApi.Destroy(cameraConfigHandle);
            return(currentCameraConfig);
        }
        private void _SetConfiguration(ARCoreSessionConfig config)
        {
            // There is no configuration to set.
            if (config == null)
            {
                return;
            }

            // The configuration has not been updated.
            if (m_CachedConfig != null && config.Equals(m_CachedConfig) &&
                (config.AugmentedImageDatabase == null ||
                 !config.AugmentedImageDatabase.m_IsDirty) &&
                !ExperimentManager.Instance.IsConfigurationDirty)
            {
                return;
            }

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                if (config.LightEstimationMode != LightEstimationMode.Disabled)
                {
                    InstantPreviewManager.LogLimitedSupportMessage("enable 'Light Estimation'");
                    config.LightEstimationMode = LightEstimationMode.Disabled;
                }

                if (config.AugmentedImageDatabase != null)
                {
                    InstantPreviewManager.LogLimitedSupportMessage("enable 'Augmented Images'");
                    config.AugmentedImageDatabase = null;
                }

                if (config.AugmentedFaceMode == AugmentedFaceMode.Mesh)
                {
                    InstantPreviewManager.LogLimitedSupportMessage("enable 'Augmented Faces'");
                    config.AugmentedFaceMode = AugmentedFaceMode.Disabled;
                }
            }

            var prestoConfig = new ApiPrestoConfig(config);

            ExternApi.ArPresto_setConfiguration(ref prestoConfig);
            m_CachedConfig = ScriptableObject.CreateInstance <ARCoreSessionConfig>();
            m_CachedConfig.CopyFrom(config);
        }
Пример #11
0
        private void _UpdateTextureIfNeeded()
        {
            // If running in editor, updates background texture from Instant Preview only.
            Texture2D previewBackgroundTexture = BackgroundTexture;

            if (InstantPreviewManager.UpdateBackgroundTextureIfNeeded(ref previewBackgroundTexture))
            {
                BackgroundTexture = previewBackgroundTexture;
                return;
            }

            IntPtr frameHandle = IntPtr.Zero;

            ExternApi.ArPresto_getFrame(ref frameHandle);

            int backgroundTextureId = ExternApi.ArCoreUnity_getBackgroundTextureId();

            if (frameHandle == IntPtr.Zero)
            {
                // This prevents using a texture that has not been filled out by ARCore.
                return;
            }
            else if (backgroundTextureId == -1)
            {
                return;
            }
            else if (BackgroundTexture != null &&
                     BackgroundTexture.GetNativeTexturePtr().ToInt32() == backgroundTextureId)
            {
                return;
            }
            else if (BackgroundTexture == null)
            {
                // The Unity-cached size and format of the texture (0x0, ARGB) is not the
                // actual format of the texture. This is okay because the texture is not
                // accessed by pixels, it is accessed with UV coordinates.
                BackgroundTexture = Texture2D.CreateExternalTexture(0, 0, TextureFormat.ARGB32, false,
                                                                    false, new IntPtr(backgroundTextureId));
                return;
            }

            BackgroundTexture.UpdateExternalTexture(new IntPtr(backgroundTextureId));
        }
        public AsyncTask <ApkAvailabilityStatus> CheckApkAvailability()
        {
            Action <ApkAvailabilityStatus>    onComplete;
            AsyncTask <ApkAvailabilityStatus> task =
                new AsyncTask <ApkAvailabilityStatus>(out onComplete);

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("determine ARCore APK " +
                                                               "availability");
                return(task);
            }

            ExternApi.ArPresto_checkApkAvailability(_checkApkAvailabilityResultCallback,
                                                    IntPtr.Zero);

            _pendingAvailabilityCheckCallbacks.Add(onComplete);

            return(task);
        }
        public AsyncTask <ApkInstallationStatus> RequestApkInstallation(bool userRequested)
        {
            Action <ApkInstallationStatus>    onComplete;
            AsyncTask <ApkInstallationStatus> task =
                new AsyncTask <ApkInstallationStatus>(out onComplete);

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("request installation of ARCore " +
                                                               "APK");
                return(task);
            }

            ExternApi.ArPresto_requestApkInstallation(userRequested,
                                                      _requestApkInstallationResultCallback, IntPtr.Zero);

            _pendingInstallationRequestCallbacks.Add(onComplete);

            return(task);
        }
Пример #14
0
        private void _SetCameraDirection(DeviceCameraDirection cameraDirection)
        {
            // The camera direction has not changed.
            if (m_CachedCameraDirection.HasValue && m_CachedCameraDirection.Value == cameraDirection)
            {
                return;
            }

            if (InstantPreviewManager.IsProvidingPlatform && cameraDirection == DeviceCameraDirection.BackFacing)
            {
                return;
            }
            else if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("enable front-facing (selfie) camera");
                m_CachedCameraDirection = DeviceCameraDirection.BackFacing;
                if (SessionComponent != null)
                {
                    SessionComponent.DeviceCameraDirection = DeviceCameraDirection.BackFacing;
                }

                return;
            }

            if (OnSessionSetEnabled != null)
            {
                OnSessionSetEnabled(false);
            }

            var apiCameraDirection = cameraDirection == DeviceCameraDirection.BackFacing ?
                                     ApiPrestoDeviceCameraDirection.BackFacing : ApiPrestoDeviceCameraDirection.FrontFacing;

            ExternApi.ArPresto_setDeviceCameraDirection(apiCameraDirection);
            m_CachedCameraDirection = cameraDirection;

            if (OnSessionSetEnabled != null)
            {
                OnSessionSetEnabled(true);
            }
        }
        /// <summary>
        /// Coroutine method that communicates to the Instant Preview plugin
        /// every frame.
        ///
        /// If not running in the editor, this does nothing.
        /// </summary>
        /// <returns>Enumerator for a coroutine that updates Instant Preview
        /// every frame.</returns>
        public static IEnumerator InitializeIfNeeded()
        {
            // Terminates if not running in editor.
            if (!Application.isEditor)
            {
                yield break;
            }

            // User may have explicitly disabled Instant Preview.
            if (ARCoreProjectSettings.Instance != null &&
                !ARCoreProjectSettings.Instance.IsInstantPreviewEnabled)
            {
                yield break;
            }

            var adbPath = InstantPreviewManager.GetAdbPath();

            if (adbPath == null)
            {
                Debug.LogError("Instant Preview requires your Unity Android SDK path to be set. Please set it under " +
                               "Preferences/External Tools/Android. You may need to install the Android SDK first.");
                yield break;
            }
            else if (!File.Exists(adbPath))
            {
                Debug.LogErrorFormat("adb not found at \"{0}\". Please add adb to your SDK path and restart the Unity editor.", adbPath);
                yield break;
            }

            string localVersion;

            if (!StartServer(adbPath, out localVersion))
            {
                yield break;
            }

            yield return(InstallApkAndRunIfConnected(adbPath, localVersion));

            yield return(UpdateLoop());
        }
        private bool SetCameraDirection(DeviceCameraDirection cameraDirection)
        {
            // The camera direction has not changed.
            if (_cachedCameraDirection.HasValue &&
                _cachedCameraDirection.Value == cameraDirection)
            {
                return(false);
            }

            if (InstantPreviewManager.IsProvidingPlatform &&
                cameraDirection == DeviceCameraDirection.BackFacing)
            {
                return(false);
            }
            else if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage(
                    "enable front-facing (selfie) camera");
                _cachedCameraDirection = DeviceCameraDirection.BackFacing;
                if (SessionComponent != null)
                {
                    SessionComponent.DeviceCameraDirection = DeviceCameraDirection.BackFacing;
                }

                return(false);
            }

            _cachedCameraDirection = cameraDirection;
            ApiPrestoStatus prestoStatus = ApiPrestoStatus.Uninitialized;

            ExternApi.ArPresto_getStatus(ref prestoStatus);
            if (prestoStatus == ApiPrestoStatus.ErrorInvalidCameraConfig)
            {
                // if the session is paused by invalid camera configuration,
                // attempt to recover by changing the camera direction:
                OnBeforeResumeSession(_cachedSessionHandle);
            }

            return(true);
        }
Пример #17
0
        private void _EarlyUpdate()
        {
            AsyncTask.OnUpdate();
            _UpdateTextureIfNeeded();

            if (m_SessionComponent != null)
            {
                var config = m_SessionComponent.SessionConfig;
                if (config != null)
                {
                    ExternApi.ArPresto_setConfiguration(new ApiPrestoConfig(config));
                }
            }

            if (m_NativeSession != null)
            {
                m_NativeSession.SessionApi.SetDisplayGeometry(
                    Screen.orientation, Screen.width, Screen.height);
                m_NativeSession.OnUpdate();
            }

            InstantPreviewManager.OnEarlyUpdate(m_SessionComponent);
        }
Пример #18
0
        public CameraIntrinsics GetTextureIntrinsics(IntPtr cameraHandle)
        {
            IntPtr cameraIntrinsicsHandle = IntPtr.Zero;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access GPU texture intrinsics");
                return(new CameraIntrinsics());
            }

            ExternApi.ArCameraIntrinsics_create(
                m_NativeSession.SessionHandle, ref cameraIntrinsicsHandle);

            ExternApi.ArCamera_getTextureIntrinsics(
                m_NativeSession.SessionHandle, cameraHandle, cameraIntrinsicsHandle);

            CameraIntrinsics textureIntrinsics =
                _GetCameraIntrinsicsFromHandle(cameraIntrinsicsHandle);

            ExternApi.ArCameraIntrinsics_destroy(cameraIntrinsicsHandle);

            return(textureIntrinsics);
        }
Пример #19
0
        public Int32 AddImageAtRuntime(
            IntPtr databaseHandle, string name, Texture2D image, float width)
        {
            Int32 outIndex = -1;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("add images to Augmented Image " +
                                                               "database");
                return(outIndex);
            }

            GCHandle grayscaleBytesHandle = _ConvertTextureToGrayscaleBytes(image);

            if (grayscaleBytesHandle.AddrOfPinnedObject() == IntPtr.Zero)
            {
                return(-1);
            }

            ApiArStatus status = ExternApi.ArPrestoAugmentedImageDatabase_addImageAtRuntime(
                databaseHandle, name, grayscaleBytesHandle.AddrOfPinnedObject(), image.width,
                image.height, image.width, width, ref outIndex);

            if (grayscaleBytesHandle.IsAllocated)
            {
                grayscaleBytesHandle.Free();
            }

            if (status != ApiArStatus.Success)
            {
                Debug.LogWarningFormat(
                    "Failed to add aumented image at runtime with status {0}", status);
                return(-1);
            }

            return(outIndex);
        }
Пример #20
0
        public bool GetAllCameraMetadataTags(
            IntPtr cameraMetadataHandle, List <CameraMetadataTag> resultList)
        {
            IntPtr ndkMetadataHandle = IntPtr.Zero;

            if (InstantPreviewManager.IsProvidingPlatform)
            {
                InstantPreviewManager.LogLimitedSupportMessage("access camera metadata tags");
                return(false);
            }

            ExternApi.ArImageMetadata_getNdkCameraMetadata(m_NativeSession.SessionHandle,
                                                           cameraMetadataHandle, ref ndkMetadataHandle);

            IntPtr          tagsHandle = IntPtr.Zero;
            int             tagsCount  = 0;
            NdkCameraStatus status     = ExternApi.ACameraMetadata_getAllTags(
                ndkMetadataHandle, ref tagsCount, ref tagsHandle);

            if (status != NdkCameraStatus.Ok)
            {
                ARDebug.LogErrorFormat(
                    "ACameraMetadata_getAllTags error with native camera error code: {0}",
                    status);
                return(false);
            }

            for (int i = 0; i < tagsCount; i++)
            {
                resultList.Add((CameraMetadataTag)Marshal.PtrToStructure(
                                   MarshalingHelper.GetPtrToUnmanagedArrayElement <int>(tagsHandle, i),
                                   typeof(int)));
            }

            return(true);
        }
Пример #21
0
        private void _OnEarlyUpdate()
        {
            _SetCameraTextureName();

            // Update session activity before EarlyUpdate.
            if (m_HaveDisableToEnableTransition)
            {
                _SetSessionEnabled(false);
                _SetSessionEnabled(true);
                m_HaveDisableToEnableTransition = false;

                // Avoid firing session enable event twice.
                if (m_DesiredSessionState.HasValue && m_DesiredSessionState.Value)
                {
                    m_DesiredSessionState = null;
                }
            }

            if (m_DesiredSessionState.HasValue)
            {
                _SetSessionEnabled(m_DesiredSessionState.Value);
                m_DesiredSessionState = null;
            }

            // Perform updates before calling ArPresto_update.
            if (SessionComponent != null)
            {
                IntPtr previousSession = IntPtr.Zero;
                ExternApi.ArPresto_getSession(ref previousSession);

                if (UpdateSessionFeatures != null)
                {
                    UpdateSessionFeatures();
                }

                _SetCameraDirection(SessionComponent.DeviceCameraDirection);

                IntPtr currentSession = IntPtr.Zero;
                ExternApi.ArPresto_getSession(ref currentSession);

                // Fire the session enabled event when the underlying session has been changed
                // due to session feature update(camera direction etc).
                if (previousSession != currentSession)
                {
                    _FireOnSessionSetEnabled(false);
                    _FireOnSessionSetEnabled(true);
                }

                // Validate and convert the SessionConfig to a Instant Preview supported config by
                // logging and disabling limited supported features.
                if (InstantPreviewManager.IsProvidingPlatform &&
                    SessionComponent.SessionConfig != null &&
                    !InstantPreviewManager.ValidateSessionConfig(SessionComponent.SessionConfig))
                {
                    // A new SessionConfig object will be created based on the original
                    // SessionConfig with all limited support features disabled.
                    SessionComponent.SessionConfig =
                        InstantPreviewManager.GenerateInstantPreviewSupportedConfig(
                            SessionComponent.SessionConfig);
                }

                _UpdateConfiguration(SessionComponent.SessionConfig);
            }

            _UpdateDisplayGeometry();

            // Update ArPresto and potentially ArCore.
            ExternApi.ArPresto_update();
            if (SystemInfo.graphicsMultiThreaded && !InstantPreviewManager.IsProvidingPlatform)
            {
                // Synchronize render thread with update call.
                ExternApi.ARCoreRenderingUtils_CreatePostUpdateFence();
            }

            SessionStatus previousSessionStatus = SessionStatus;

            // Get state information from ARPresto.
            ApiPrestoStatus prestoStatus = ApiPrestoStatus.Uninitialized;

            ExternApi.ArPresto_getStatus(ref prestoStatus);
            SessionStatus = prestoStatus.ToSessionStatus();

            LostTrackingReason = LostTrackingReason.None;
            if (NativeSession != null && SessionStatus == SessionStatus.LostTracking)
            {
                var cameraHandle = NativeSession.FrameApi.AcquireCamera();
                LostTrackingReason = NativeSession.CameraApi.GetLostTrackingReason(cameraHandle);
                NativeSession.CameraApi.Release(cameraHandle);
            }

            // If the current status is an error, check if the SessionStatus error state changed.
            if (SessionStatus.IsError() &&
                previousSessionStatus.IsError() != SessionStatus.IsError())
            {
                // Disable internal session bits so we properly pause the session due to error.
                _FireOnSessionSetEnabled(false);
                m_DisabledSessionOnErrorState = true;
            }
            else if (SessionStatus.IsValid() && m_DisabledSessionOnErrorState)
            {
                if (SessionComponent.enabled)
                {
                    _FireOnSessionSetEnabled(true);
                }

                m_DisabledSessionOnErrorState = false;
            }

            // Get the current session from presto and note if it has changed.
            IntPtr sessionHandle = IntPtr.Zero;

            ExternApi.ArPresto_getSession(ref sessionHandle);
            IsSessionChangedThisFrame = m_CachedSessionHandle != sessionHandle;
            m_CachedSessionHandle     = sessionHandle;

            ExternApi.ArPresto_getFrame(ref m_CachedFrameHandle);

            // Update the native session with the newest frame.
            if (NativeSession != null)
            {
                NativeSession.OnUpdate(m_CachedFrameHandle);
            }

            _UpdateTextureIfNeeded();

            if (EarlyUpdate != null)
            {
                EarlyUpdate();
            }
        }
Пример #22
0
        /// <summary>
        /// Coroutine method that communicates to the Instant Preview plugin
        /// every frame.
        ///
        /// If not running in the editor, this does nothing.
        /// </summary>
        /// <returns>Enumerator for a coroutine that updates Instant Preview
        /// every frame.</returns>
        public static IEnumerator InitializeIfNeeded()
        {
            // Terminates if not running in editor.
            if (!Application.isEditor)
            {
                yield break;
            }
            // User may have explicitly disabled Instant Preview.
            if (ARCoreProjectSettings.Instance != null &&
                !ARCoreProjectSettings.Instance.IsInstantPreviewEnabled)
            {
                yield break;
            }
#if UNITY_EDITOR
            // Determine if any augmented image databases need a rebuild.
            List <AugmentedImageDatabase> databases = new List <AugmentedImageDatabase>();
            bool shouldRebuild = false;
            var  augmentedImageDatabaseGuids = AssetDatabase.FindAssets("t:AugmentedImageDatabase");
            foreach (var databaseGuid in augmentedImageDatabaseGuids)
            {
                var database = AssetDatabase.LoadAssetAtPath <AugmentedImageDatabase>(
                    AssetDatabase.GUIDToAssetPath(databaseGuid));
                databases.Add(database);
                shouldRebuild = shouldRebuild || database.IsBuildNeeded();
            }
            // If the preference is to ask the user to rebuild, ask now.
            if (shouldRebuild && PromptToRebuildAugmentedImagesDatabase())
            {
                foreach (var database in databases)
                {
                    string error;
                    database.BuildIfNeeded(out error);
                    if (!string.IsNullOrEmpty(error))
                    {
                        Debug.LogWarning("Failed to rebuild augmented " +
                                         "image database: " + error);
                    }
                }
            }
#endif
            var adbPath = InstantPreviewManager.GetAdbPath();
            if (adbPath == null)
            {
                Debug.LogError("Instant Preview requires your Unity Android SDK path to be set. Please set it under " +
                               "'Preferences > External Tools > Android'. You may need to install the Android SDK first.");
                yield break;
            }
            else if (!File.Exists(adbPath))
            {
                Debug.LogErrorFormat("adb not found at \"{0}\". Please add adb to your SDK path and restart the Unity editor.", adbPath);
                yield break;
            }
            string localVersion;
            if (!StartServer(adbPath, out localVersion))
            {
                yield break;
            }
            yield return(InstallApkAndRunIfConnected(adbPath, localVersion));

            yield return(UpdateLoop(adbPath));
        }
        /// <summary>
        /// Coroutine method that communicates to the Instant Preview plugin
        /// every frame.
        ///
        /// If not running in the editor, this does nothing.
        /// </summary>
        /// <returns>Enumerator for a coroutine that updates Instant Preview
        /// every frame.</returns>
        public static IEnumerator InitializeIfNeeded()
        {
            // Terminates if not running in editor.
            if (!Application.isEditor)
            {
                yield break;
            }

            // User may have explicitly disabled Instant Preview.
            if (ARCoreProjectSettings.Instance != null &&
                !ARCoreProjectSettings.Instance.IsInstantPreviewEnabled)
            {
                yield break;
            }

#if UNITY_EDITOR
            // When build platform is not Android, verify min game view scale is 1.0x to prevent
            // confusing 2x scaling when Unity editor is running on a high density display.
            if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
            {
                float minGameViewScale = GetMinGameViewScaleOrUnknown();
                if (minGameViewScale != 1.0)
                {
                    String viewScaleText = minGameViewScale == k_UnknownGameViewScale ?
                                           "<unknown>" : string.Format("{0}x", minGameViewScale);
                    Debug.LogWarningFormat(
                        "Instant Preview disabled, {0} minimum Game view scale unsupported for target build platform" +
                        " '{1}'.\n" +
                        "To use Instant Preview, switch build platform to '{2}' from the 'Build settings' window.",
                        viewScaleText, EditorUserBuildSettings.activeBuildTarget, BuildTarget.Android);
                    yield break;
                }
            }

            // Determine if any augmented image databases need a rebuild.
            List <AugmentedImageDatabase> databases = new List <AugmentedImageDatabase>();
            bool shouldRebuild = false;

            var augmentedImageDatabaseGuids = AssetDatabase.FindAssets("t:AugmentedImageDatabase");
            foreach (var databaseGuid in augmentedImageDatabaseGuids)
            {
                var database = AssetDatabase.LoadAssetAtPath <AugmentedImageDatabase>(
                    AssetDatabase.GUIDToAssetPath(databaseGuid));
                databases.Add(database);

                shouldRebuild = shouldRebuild || database.IsBuildNeeded();
            }

            // If the preference is to ask the user to rebuild, ask now.
            if (shouldRebuild && PromptToRebuildAugmentedImagesDatabase())
            {
                foreach (var database in databases)
                {
                    string error;
                    database.BuildIfNeeded(out error);
                    if (!string.IsNullOrEmpty(error))
                    {
                        Debug.LogWarning("Failed to rebuild augmented image database: " + error);
                    }
                }
            }
#endif

            var adbPath = InstantPreviewManager.GetAdbPath();
            if (adbPath == null)
            {
                Debug.LogError("Instant Preview requires your Unity Android SDK path to be set. " +
                               "Please set it under 'Preferences > External Tools > Android'. " +
                               "You may need to install the Android SDK first.");
                yield break;
            }
            else if (!File.Exists(adbPath))
            {
                Debug.LogErrorFormat("adb not found at \"{0}\". Please verify that 'Preferences > " +
                                     "External Tools > Android' has the correct Android SDK path that the Android Platform " +
                                     "Tools are installed, and that \"{0}\" exists. You may need to install the Android " +
                                     "SDK first.", adbPath);
                yield break;
            }

            string localVersion;
            if (!StartServer(adbPath, out localVersion))
            {
                yield break;
            }

            yield return(InstallApkAndRunIfConnected(adbPath, localVersion));

            yield return(UpdateLoop(adbPath));
        }