public override void OnPreferenceGUI()
            {
                const string title = "OpenVR";

                if (canSupport)
                {
                    var wasSupported = support;
                    support          = m_foldouter.ShowFoldoutButtonOnToggleEnabled(new GUIContent(title, "VIVE, VIVE Pro, VIVE Pro Eye, VIVE Cosmos\nOculus Rift, Oculus Rift S, Windows MR"), wasSupported);
                    s_symbolChanged |= wasSupported != support;
                }
                else
                {
                    GUILayout.BeginHorizontal();
                    Foldouter.ShowFoldoutBlank();

                    if (activeBuildTargetGroup != BuildTargetGroup.Standalone)
                    {
                        GUI.enabled = false;
                        ShowToggle(new GUIContent(title, "Standalone platform required."), false, GUILayout.Width(230f));
                        GUI.enabled = true;
                        GUILayout.FlexibleSpace();
                        ShowSwitchPlatformButton(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64);
                    }
#if UNITY_2020_2_OR_NEWER && FALSE // openxr not fully supported yet
                    else if (!PackageManagerHelper.IsPackageInList(OPENXR_PLUGIN_PACKAGE_NAME))
                    {
                        GUI.enabled = false;
                        ShowToggle(new GUIContent(title, "OpenXR Plugin ackage required."), false, GUILayout.Width(230f));
                        GUI.enabled = true;
                        GUILayout.FlexibleSpace();
                        ShowAddPackageButton("OpenXR Plugin", OPENXR_PLUGIN_PACKAGE_NAME);
                    }
#elif UNITY_2019_3_OR_NEWER && FALSE // openvr xr plugin on Valve registry is obsolete
                    else if (!PackageManagerHelper.IsPackageInList(OPENVR_XR_PACKAGE_NAME))
                    {
                        GUI.enabled = false;
                        ShowToggle(new GUIContent(title, "OpenVR XR Plugin package required."), false, GUILayout.Width(230f));
                        GUI.enabled = true;
                        GUILayout.FlexibleSpace();

                        if (GUILayout.Button(new GUIContent("Add OpenVR XR Plugin Package", "Add " + OPENVR_XR_PACKAGE_NAME + " to Package Manager"), GUILayout.ExpandWidth(false)))
                        {
                            if (!ManifestUtils.CheckRegistryExists(ValveRegistry))
                            {
                                ManifestUtils.AddRegistry(ValveRegistry);
                            }

                            PackageManagerHelper.AddToPackageList(OPENVR_XR_PACKAGE_NAME);
                            VIUProjectSettings.Instance.isInstallingOpenVRXRPlugin = true;
                        }
                    }
#elif UNITY_2018_2_OR_NEWER && FALSE // obsolete
                    else if (!PackageManagerHelper.IsPackageInList(OPENVR_PACKAGE_NAME))
                    {
                        GUI.enabled = false;
                        ShowToggle(new GUIContent(title, "OpenVR (Desktop) package required."), false, GUILayout.Width(230f));
                        GUI.enabled = true;
                        GUILayout.FlexibleSpace();
                        ShowAddPackageButton("OpenVR (Desktop)", OPENVR_PACKAGE_NAME);
                    }
#endif
                    else if (!VRModule.isSteamVRPluginDetected)
                    {
                        GUI.enabled = false;
                        ShowToggle(new GUIContent(title, "SteamVR Plugin required."), false, GUILayout.Width(230f));
                        GUI.enabled = true;
                        GUILayout.FlexibleSpace();
                        ShowUrlLinkButton(URL_STEAM_VR_PLUGIN);
                    }

                    GUILayout.EndHorizontal();
                }

                if (support && m_foldouter.isExpended)
                {
                    EditorGUI.indentLevel += 2;

                    // Vive Hand Tracking Submodule
                    const string vhtSdkUrl = "https://developer.vive.com/resources/vive-sense/sdk/vive-hand-tracking-sdk/";
                    const string vhtTitle  = "Enable Vive Hand Tracking";
                    if (!VRModule.isViveHandTrackingDetected)
                    {
                        GUILayout.BeginHorizontal();
                        GUI.enabled = false;
                        EditorGUILayout.ToggleLeft(new GUIContent(vhtTitle, "Vive Hand Tracking SDK required"), false, GUILayout.Width(230f));
                        GUI.enabled = true;
                        GUILayout.FlexibleSpace();
                        ShowUrlLinkButton(vhtSdkUrl);
                        GUILayout.EndHorizontal();
                    }
                    else
                    {
                        EditorGUI.BeginChangeCheck();
                        VRModuleSettings.activateViveHandTrackingSubmodule = EditorGUILayout.ToggleLeft(new GUIContent(vhtTitle, "Works on Vive, VIVE Pro, Vive Pro Eye, VIVE Cosmos, VIVE Cosmos XR and Valve Index"), VRModuleSettings.activateViveHandTrackingSubmodule);
                        s_guiChanged |= EditorGUI.EndChangeCheck();
                    }

                    if (VRModule.isSteamVRPluginDetected)
                    {
                        EditorGUI.BeginChangeCheck();
                    }
                    else
                    {
                        GUI.enabled = false;
                    }

                    // Skeleton mode
                    VIUSettings.steamVRLeftSkeletonMode  = (SteamVRSkeletonMode)EditorGUILayout.EnumPopup(new GUIContent("Left Controller Skeleton", "This effects RenderModelHook's behaviour"), VIUSettings.steamVRLeftSkeletonMode);
                    VIUSettings.steamVRRightSkeletonMode = (SteamVRSkeletonMode)EditorGUILayout.EnumPopup(new GUIContent("Right Controller Skeleton", "This effects RenderModelHook's behaviour"), VIUSettings.steamVRRightSkeletonMode);

                    VIUSettings.autoLoadExternalCameraConfigOnStart = EditorGUILayout.ToggleLeft(new GUIContent("Load Config and Enable External Camera on Start", "You can also load config by calling ExternalCameraHook.LoadConfigFromFile(path) in script."), VIUSettings.autoLoadExternalCameraConfigOnStart);
                    if (!VIUSettings.autoLoadExternalCameraConfigOnStart)
                    {
                        GUI.enabled = false;
                    }
                    {
                        EditorGUI.indentLevel++;

                        EditorGUI.BeginChangeCheck();
                        VIUSettings.externalCameraConfigFilePath = EditorGUILayout.DelayedTextField(new GUIContent("Config Path"), VIUSettings.externalCameraConfigFilePath);
                        if (string.IsNullOrEmpty(VIUSettings.externalCameraConfigFilePath))
                        {
                            VIUSettings.externalCameraConfigFilePath = VIUSettings.EXTERNAL_CAMERA_CONFIG_FILE_PATH_DEFAULT_VALUE;
                            EditorGUI.EndChangeCheck();
                        }
                        else if (EditorGUI.EndChangeCheck() && VIUSettings.externalCameraConfigFilePath.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
                        {
                            VIUSettings.externalCameraConfigFilePath = VIUSettings.EXTERNAL_CAMERA_CONFIG_FILE_PATH_DEFAULT_VALUE;
                        }
                        // Create button that writes default config file
                        if (VIUSettings.autoLoadExternalCameraConfigOnStart && !File.Exists(VIUSettings.externalCameraConfigFilePath))
                        {
                            if (VRModule.isSteamVRPluginDetected)
                            {
                                s_guiChanged |= EditorGUI.EndChangeCheck();
                            }
                            ShowCreateExCamCfgButton();
                            if (VRModule.isSteamVRPluginDetected)
                            {
                                EditorGUI.BeginChangeCheck();
                            }
                        }

                        EditorGUI.indentLevel--;
                    }
                    if (!VIUSettings.autoLoadExternalCameraConfigOnStart)
                    {
                        GUI.enabled = true;
                    }

                    VIUSettings.enableExternalCameraSwitch = EditorGUILayout.ToggleLeft(new GUIContent("Enable External Camera Switch", VIUSettings.EX_CAM_UI_SWITCH_TOOLTIP), VIUSettings.enableExternalCameraSwitch);
                    if (!VIUSettings.enableExternalCameraSwitch)
                    {
                        GUI.enabled = false;
                    }
                    {
                        EditorGUI.indentLevel++;

                        VIUSettings.externalCameraSwitchKey         = (KeyCode)EditorGUILayout.EnumPopup("Switch Key", VIUSettings.externalCameraSwitchKey);
                        VIUSettings.externalCameraSwitchKeyModifier = (KeyCode)EditorGUILayout.EnumPopup("Switch Key Modifier", VIUSettings.externalCameraSwitchKeyModifier);

                        EditorGUI.indentLevel--;
                    }
                    if (!VIUSettings.enableExternalCameraSwitch)
                    {
                        GUI.enabled = true;
                    }

                    EditorGUI.indentLevel -= 2;

                    if (VRModule.isSteamVRPluginDetected)
                    {
                        s_guiChanged |= EditorGUI.EndChangeCheck();
                    }
                    else
                    {
                        GUI.enabled = true;
                    }
                }

                if (support && !VRModule.isSteamVRPluginDetected && !PackageManagerHelper.IsPackageInList(OPENXR_PLUGIN_PACKAGE_NAME))
                {
                    EditorGUI.indentLevel += 2;

                    GUILayout.BeginHorizontal();
                    EditorGUILayout.HelpBox(
#if VIU_XR_GENERAL_SETTINGS
                        "Input" +
#elif UNITY_2017_1_OR_NEWER
                        "External-Camera(Mix-Reality), animated controller model" +
                        ", VIVE Controller haptics(vibration)" +
                        ", VIVE Tracker USB/Pogo-pin input" +
#else
                        "External-Camera(Mix-Reality), animated controller model" +
                        ", VIVE Controller haptics(vibration)" +
                        ", VIVE Tracker device" +
#endif
                        " NOT supported! " +
                        "Install SteamVR Plugin to get support."
                        , MessageType.Warning);

                    s_warningHeight = Mathf.Max(s_warningHeight, GUILayoutUtility.GetLastRect().height);
                    GUILayout.FlexibleSpace();

                    GUILayout.BeginVertical(GUILayout.Height(s_warningHeight));
                    GUILayout.FlexibleSpace();
                    ShowUrlLinkButton(URL_STEAM_VR_PLUGIN, "Get SteamVR Plugin");
                    GUILayout.FlexibleSpace();
                    GUILayout.EndVertical();

                    GUILayout.EndHorizontal();

                    EditorGUI.indentLevel -= 2;
                }

#if UNITY_2019_3_OR_NEWER
                if (VIUProjectSettings.Instance.isInstallingOpenVRXRPlugin)
                {
                    bool isPackageInstalled = PackageManagerHelper.IsPackageInList(OPENVR_XR_PACKAGE_NAME) ||
                                              PackageManagerHelper.IsPackageInList(OPENVR_XR_PACKAGE_NAME_OLD);
                    bool isLoaderEnabled = XRPluginManagementUtils.IsXRLoaderEnabled(SteamVRModule.OPENVR_XR_LOADER_NAME, BuildTargetGroup.Standalone);
                    if (isPackageInstalled && !isLoaderEnabled)
                    {
                        XRPluginManagementUtils.SetXRLoaderEnabled(SteamVRModule.OPENVR_XR_LOADER_CLASS_NAME, BuildTargetGroup.Standalone, true);
                        OpenVRSDK.enabled = true;

                        VIUProjectSettings.Instance.isInstallingOpenVRXRPlugin = false;
                    }
                }
#endif
            }
        public UnityXRRecommendedSettings()
        {
#if VIU_OPENXR && VIU_XR_GENERAL_SETTINGS
            Add(new VIUVersionCheck.RecommendedSetting <int>
            {
                settingTitle     = "Review OpenXR Project Validation Issues",
                skipCheckFunc    = () => !VIUSettingsEditor.PackageManagerHelper.IsPackageInList(VIUSettingsEditor.OPENXR_PLUGIN_PACKAGE_NAME) || !XRPluginManagementUtils.IsXRLoaderEnabled(UnityXRModule.OPENXR_LOADER_NAME, VIUSettingsEditor.activeBuildTargetGroup),
                currentValueFunc = () => {
                    OpenXRProjectValidation.GetCurrentValidationIssues(s_tempOpenXRValidationIssues, VIUSettingsEditor.activeBuildTargetGroup);
                    return(s_tempOpenXRValidationIssues.Count);
                },
                setValueFunc = (int value) =>
                {
                    try
                    {
                        Assembly openXREditorAsm = null;
                        foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
                        {
                            if (asm.GetName().Name == "Unity.XR.OpenXR.Editor")
                            {
                                openXREditorAsm = asm;
                                break;
                            }
                        }

                        MethodInfo openWindowMethod = openXREditorAsm.GetType("UnityEditor.XR.OpenXR.OpenXRProjectValidationWindow", true).GetMethod("ShowWindow", BindingFlags.NonPublic | BindingFlags.Static);
                        openWindowMethod.Invoke(null, new object[] { VIUSettingsEditor.activeBuildTargetGroup });
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("Failed to open OpenXRProjectValidationWindow: " + e);
                    }
                },
                recommendedValue = 0,
            });

            Add(new VIUVersionCheck.RecommendedSetting <bool>
            {
                settingTitle     = "Enable All Feature Sets",
                skipCheckFunc    = () => !VIUSettingsEditor.PackageManagerHelper.IsPackageInList(VIUSettingsEditor.OPENXR_PLUGIN_PACKAGE_NAME) || !XRPluginManagementUtils.IsXRLoaderEnabled(UnityXRModule.OPENXR_LOADER_NAME, VIUSettingsEditor.activeBuildTargetGroup),
                currentValueFunc = () =>
                {
                    return(OpenXRSettings.ActiveBuildTargetInstance.GetFeatures <OpenXRInteractionFeature>().All(feature => feature.enabled));
                },
                setValueFunc = (bool value) =>
                {
                    if (!value)
                    {
                        return;
                    }

                    OpenXRFeature[] features = OpenXRSettings.ActiveBuildTargetInstance.GetFeatures <OpenXRInteractionFeature>();
                    foreach (OpenXRFeature feature in features)
                    {
                        feature.enabled = true;
                    }
                },
                recommendedValue = true,
            });
#endif
        }