一.pico程序开机自启
把应用的包名写在创建的config.txt文件中并将config.txt文件放在设备文件目录根目录,安装应用,重启设备。就可以通过配置文件开机自启动第三方应用的.
具体步骤如下:
1.创建config.txt
open_guide:1
------
home_pkg:com.ttt.ttt
------
2.将config.txt放入设备根目录
二、打开开发者模式开启
pico4打开开发者模式打开手机桌面【设置】,在设置主界面,找到【我的设备】,进入到我的设备界面,向下滑动找到【全部参数】,在全部参数界面,可以看到手机的【型号】【运行内存】等;
下滑找到一个【MIUI版本】,快速点击MIUI版本七次,在屏幕下方会弹出,一个【您现在处于开发者模式!】,即可成功进入开发者模式,然后返回到设置主界面,在上方搜索框中搜索【开发者选项】,点击进入开发者选项,可以看到上方【开启开发者选项】已开启,点击右侧的【开关按钮】即可关闭;
三.机器卡死的情况下恢复出厂设置:
三、 Android权限:
<!--<meta-data android:name="pico_advance_interface" android:value="0"/>-->//这行代码可以支持远程控制设备重启或者自启动
项目的AndroidManifest.xml如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="29" android:compileSdkVersionCodename="\ 10" android:installLocation="preferExternal" package="com.XKC.NYS_Hall" platformBuildVersionCode="29" platformBuildVersionName="10">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.REORDER_TASKS"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.REMOVE_TASKS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DELETE_PACKAGES"/>
<uses-permission android:name="pvr.permission.ACCESS_VOICE_ASSISTANT"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INJECT_EVENTS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.BATTERY_STATS"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application android:allowBackup="false" android:icon="@mipmap/app_icon" android:label="@string/app_name" android:requestLegacyExternalStorage="true" android:supportsRtl="true" android:usesCleartextTraffic="true" >
<activity android:configChanges="locale|fontScale|keyboard|keyboardHidden|layoutDirection|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" android:hardwareAccelerated="false" android:launchMode="singleTask" android:name="com.unity3d.player.UnityPlayerActivity" android:screenOrientation="landscape" android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
<meta-data android:name="android.notch_support" android:value="true"/>
</activity>
<meta-data android:name="unity.splash-mode" android:value="0"/>
<meta-data android:name="unity.splash-enable" android:value="true"/>
<meta-data android:name="notch.config" android:value="portrait|landscape"/>
<meta-data android:name="unity.build-id" android:value="8efff4e7-1044-4c65-88b6-20d207b9c8b9"/>
<meta-data android:name="pvr.app.type" android:value="vr"/>
<meta-data android:name="pvr.sdk.version" android:value="XR Platform_1.2.4.7"/>
<meta-data android:name="enable_cpt" android:value="0"/>
<meta-data android:name="enable_entitlementcheck" android:value="0"/>
<meta-data android:name="pico_advance_interface" android:value="0"/>
<meta-data android:name="pico_scope" android:value="get_user_info"/>
<meta-data android:name="com.pvr.instructionset" android:value="32"/>
<activity android:excludeFromRecents="true" android:exported="true" android:launchMode="singleTask" android:name="com.pico.loginpaysdk.auth.TransferStationActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="com.pico.loginpaysdk.intent.action.AuthCallback"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
服务端发送指令重启设备的相关代码
Debug.Log("设备重启");
PXR_Enterprise.ControlSetDeviceAction(DeviceControlEnum.DEVICE_CONTROL_REBOOT, (k) =>
{
Debug.LogError(k == 1 ? $"错误代码{k}:重启失败" : $"错误代码{k}:没有权限");
});
关于服务端控制的所有代码:
using BestHTTP;
using BestHTTP.JSON.LitJson;
using BestHTTP.WebSocket;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Timers;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.XR;
public class NYSWebController : MonoBehaviour
{
private WEBGameTypeEnum WEBGameType;
private const string ProdServer = "wss://vr.66nao.com/ws";
private const string DevServer = "wss://vr-test.66nao.com/ws";
// private const string DevServer = "wss://dev.drbrain.net/ws";
protected const string CompleteCodeURL = "/brain-service-api/bh-screening-report/complete_types/";
WebSocket webSocket;
private float lastHeartTime;
public static NYSWebController Instance;
private void Awake()
{
Instance = this;
}
private void Start()
{
SceneManager.sceneLoaded += SceneLoaded;
Timer loopKeepConnectTimer = new Timer(3000);
loopKeepConnectTimer.Elapsed += LoopKeepConnectTimer_Elapsed;
loopKeepConnectTimer.AutoReset = true;
loopKeepConnectTimer.Enabled = true;
}
private void Update()
{
if (webSocket != null && webSocket.IsOpen)
{
if (Time.time - lastHeartTime > 5)
{
CloseWebSocket();
}
}
#region DebugCode
if (PicoManager.Input_GetKeyDown(XRNode.RightHand, CommonUsages.primaryButton))
{
//暂停键
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_DBQ_A\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_SYMBOL_SEARCH\"}");
//EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_EMCA\"}");
}
if (PicoManager.Input_GetKeyDown(XRNode.RightHand, CommonUsages.secondaryButton))
{
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"VOICE_MAN\"}");
//EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_VOCABULARY_TEST\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_SYMBOL_SEARCH\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_SYMBOL_SEARCH\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"SKIP_HOME\"}");
}
if (Input.GetKeyDown(KeyCode.Z))
{
//EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_CONTINUE_SCREEN_PCAT1692323300085\"}");
OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_SCREEN_MULTIPLE_SYMBOL_SEARCH,SYMMETRY_SPAN,PORTRAIT_MEMORY,ORIGAMI_TEST,VOCABULARY_TEST\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_SCREEN_MULTIPLE_PORTRAIT_MEMORY,ORIGAMI_TEST,VOCABULARY_TEST\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"VOICE_MAN\"}");
// OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"SKIP_HOME\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_EMCA\"}");
//GameEventArg arg = EventDispatcher.Instance.GetEventArg((int)EventID.HALL_STARTRAPIDTRAINING);
//arg.SetArg(0, "测试ID");
//var str = "SYMBOL_SEARCH,SYMMETRY_SPAN,PORTRAIT_MEMORY".Split(',');
//List<string> sceneList = new List<string>();
//for (int i = 0; i < str.Length; i++)
//{
// sceneList.Add(Enums.GetDesc((WEBGameTypeEnum)Enum.Parse(typeof(WEBGameTypeEnum), str[i])));
//}
//arg.SetArg(1, sceneList);
//EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_EMCA\"}");
}
if (Input.GetKeyDown(KeyCode.X))
{
OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"CHANGE_GAMESCENE_0\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"PAUSE_EMCA\"}");
// EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"PAUSE_SCREEN\"}");
//EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_RECALIBRATE);
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_SYMBOL_SEARCH\"}");
}
if (Input.GetKeyDown(KeyCode.C))
{
// OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"PLAY_GUIDEVIDEO_1004\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"CONTINUE_SCREEN\"}");
// OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"CHANGE_USER\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_MMSE\"}");
//OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"OVER_SCREEN\", \"no\":\"\"}");
OnMessage(webSocket, "{\"message\":\"设备控制消息\", \"type\":\"START_MOCA\"}");
}
#endregion
}
void InitWebsocket()
{
webSocket = new WebSocket(new Uri(NYSNetManager.Instance.OperatingEnvironmentType == NYSNetManager.OperatingEnvironmentTypeEnum.生产环境 ? ProdServer : DevServer));
webSocket.OnOpen += WebOnOpen;
webSocket.OnBinary += OnBinary;
webSocket.OnMessage += OnMessage;
webSocket.OnClosed += OnClosed;
webSocket.OnError += OnError;
}
void WebSocketConnect()
{
if (NYSManager.Instance.DeviceData.ID == 0) return;
try
{
InitWebsocket();
webSocket.Open();
}
catch (Exception e)
{
Debug.Log("连接异常" + e.Message);
CloseWebSocket();
}
}
private void OnError(WebSocket webSocket, string reason)
{
string errorMsg = string.Empty;
CloseWebSocket();
}
private void OnClosed(WebSocket webSocket, ushort code, string message)
{
CloseWebSocket();
}
private void WebOnOpen(WebSocket webSocket)
{
lastHeartTime = Time.time;
if (NYSManager.Instance.DeviceData.ID != 0)
{
SendLoginMsg(NYSManager.Instance.DeviceData.ID);
}
}
private void LoopKeepConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (webSocket == null || webSocket.IsOpen == false)
{
WebSocketConnect();
}
SendMsg("ping");
}
private void OnMessage(WebSocket webSocket, string message)
{
WebMessage data = JsonMapper.ToObject<WebMessage>(message);
switch (data.message)
{
case "登录成功":
break;
case "pong":
lastHeartTime = Time.time;
break;
case "设备控制消息":
int subtemp = data.type.IndexOf("_");
string firstField = data.type.Substring(0, subtemp);
string secondField = data.type.Substring(subtemp + 1);
string lastField = data.type.Substring(data.type.LastIndexOf("_") + 1);
Debug.Log("首字符:" + firstField + "中间字符:" + secondField + "最后字符:" + lastField);
if (data.type.Contains("GUIDEVIDEO"))
{
int firstUnderscoreIndex = data.type.IndexOf("_");
string firststr = data.type.Substring(0, firstUnderscoreIndex);
int lastUnderscoreIndex = data.type.LastIndexOf("_");
string laststr = data.type.Substring(lastUnderscoreIndex + 1);
HJVideoManger.Instance.PlayVideo(firststr, laststr);
return;
}
//暂时断续处理
//START_CONTINUE_SCREEN_PCAT1693184485645
if (data.type.Contains("START_CONTINUE_SCREEN_"))
{
GetRapidContinue(lastField);
return;
}
//暂时多选处理
if (data.type.Contains("START_SCREEN_MULTIPLE_"))
{
var quizlist = data.type.Replace("START_SCREEN_MULTIPLE_", "").Split(',');
//GameEventArg arg = EventDispatcher.Instance.GetEventArg((int)EventID.HALL_STARTRAPIDTRAINING);
List<string> sceneList = new List<string>();
for (int i = 0; i < quizlist.Length; i++)
{
sceneList.Add(Enums.GetDesc((WEBGameTypeEnum)Enum.Parse(typeof(WEBGameTypeEnum), quizlist[i])));
}
//arg.SetArg(1, sceneList);
//EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
NYSWebTrainManager.Instance.ChangeState(NYSWebTrainState.RAPIDTRAIN_MULTIPLE, null, sceneList);
return;
}
//设备控制
switch (firstField)
{
case "CHANGE"://CHANGE_USER
if (secondField == "USER")
{
NYSNetManager.GetDeviceData(NYSManager.Instance.TokenData.Token);
if (SceneLoader.Instance.currentSceneIndex == 1)
{
HallAudio.Instance.PlayAudio("man_prompt");
HJVideoManger.Instance.OffVideo();
}
}
else if (secondField.Contains("GAMESCENE"))
{
SkinManager.SaveGameSkin(int.Parse(lastField));
}
return;
case "RESET"://"RESET_VIEW":
InputDevices.GetDeviceAtXRNode(XRNode.Head).subsystem.TryRecenter();
return;
case "SKIP"://"SKIP_HOME":
//if (SceneLoader.Instance.currentGameSceneName == Enums.GetDesc(WEBGameTypeEnum.EMCA))
//{
// EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_BACKHOMETRIGGER);
//}
//else
//{
// SceneLoader.Instance.BackHall();
//}
SceneLoader.Instance.BackHall();
return;
case "RESTART":
Debug.Log("设备重启");
PXR_Enterprise.ControlSetDeviceAction(DeviceControlEnum.DEVICE_CONTROL_REBOOT, (k) =>
{
Debug.LogError(k == 1 ? $"错误代码{k}:重启失败" : $"错误代码{k}:没有权限");
});
return;
case "VOICE":
if (lastField.Equals("MAN"))
{
GameAudioManager.VoiceActor = VoiceActorType.Male;
}
else
{
GameAudioManager.VoiceActor = VoiceActorType.Female;
}
break;
}
//Debug.Log(firstField+secondField);
//游戏控制
switch (secondField)
{
case "SCREEN":
if (firstField == "START")
NYSWebTrainManager.Instance.ChangeState(NYSWebTrainState.RAPIDTRAIN_AUTO);
else if (firstField == "PAUSE")
EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_SCENEPAUSE);
else if (firstField == "OVER")
{
if (data.no == "" || data.no == MmseWriteAnsers.Instance.no)
{
QuestionManage.Instance.GameOver();
}
}
else
EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_SCENECONTINUE);
return;
case "SYMBOL_SEARCH":
WEBGameType = WEBGameTypeEnum.SYMBOL_SEARCH;
break;
case "SYMMETRY_SPAN":
WEBGameType = WEBGameTypeEnum.SYMMETRY_SPAN;
break;
case "PORTRAIT_MEMORY":
WEBGameType = WEBGameTypeEnum.PORTRAIT_MEMORY;
break;
case "ORIGAMI_TEST":
WEBGameType = WEBGameTypeEnum.ORIGAMI_TEST;
break;
case "VOCABULARY_TEST":
WEBGameType = WEBGameTypeEnum.VOCABULARY_TEST;
break;
case "MMSE":
WEBGameType = WEBGameTypeEnum.MMSE;
break;
case "MOCA":
WEBGameType = WEBGameTypeEnum.MOCA;
break;
case "EMCA":
WEBGameType = WEBGameTypeEnum.EMCA;
break;
}
switch (firstField)
{
case "START":
if (SceneLoader.Instance.currentGameSceneName == Enums.GetDesc(WEBGameTypeEnum.EMCA) && WEBGameType == WEBGameTypeEnum.EMCA)
{
EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_STARTHOMETRIGGER);
}
else
{
NYSWebTrainManager.Instance.ChangeState(NYSWebTrainState.WEBSTART, Enums.GetDesc(WEBGameType), true);
}
return;
case "PAUSE":
EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_SCENEPAUSE);
break;
case "CONTINUE":
EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_SCENECONTINUE);
break;
case "RECALIBRATE":
EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_RECALIBRATE);
break;
case "OVER":
//EventDispatcher.Instance.Dispatch((int)EventID.WEBCONTROL_ENDGAME);
SceneLoader.Instance.BackHall();
break;
}
WEBGameType = WEBGameTypeEnum.NULL;
break;
}
}
private void GetRapidContinue(string ssid)
{
NYSNetManager.NYSHTTPRequest($"{NYSNetManager.Instance.GetFullServerURL(CompleteCodeURL + ssid)}",
(bool isSuccess, JsonData jsonData) =>
{
if (isSuccess)
{
if (jsonData != null)
{
RapidDataPack rdp = JsonMapper.ToObject<RapidDataPack>(jsonData.ToJson());
//GameEventArg arg = EventDispatcher.Instance.GetEventArg((int)EventID.HALL_STARTRAPIDTRAINING);
//arg.SetArg(0, ssid);
var str = rdp.types.Split(',');
List<string> sceneList = new List<string>();
for (int i = 0; i < str.Length; i++)
{
sceneList.Add(Enums.GetDesc((WEBGameTypeEnum)Enum.Parse(typeof(WEBGameTypeEnum), str[i])));
}
//arg.SetArg(1, sceneList);
//EventDispatcher.Instance.Dispatch((int)EventID.HALL_STARTRAPIDTRAINING);
NYSWebTrainManager.Instance.ChangeState(NYSWebTrainState.RAPIDTRAIN_CONTINUE, ssid, sceneList);
}
}
else
{
Debug.Log("get RapidContinue failed");
}
},
HTTPMethods.Get,
"Authorization",
NYSManager.Instance.TokenData.Token);
}
private void OnBinary(WebSocket webSocket, byte[] data)
{
Debug.Log("接收二进制" + data.Length);
}
public void SendLoginMsg(int userid)
{
LonginMsg longinMsg = new LonginMsg();
longinMsg.tempevent = "login";
longinMsg.formUserId = userid;
longinMsg.platform = "DEVICE";
string datahead = "brain" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
longinMsg.sign = datahead + NYSUtils.GetMD5("{}".Length + "{}");
string data = longinMsg.SaveToString();
data = data.Remove(data.IndexOf("temp"), 4);
webSocket?.Send(data);
}
/// <summary>
/// 发送录制消息给服务器
/// </summary>
/// <param name="type"></param>
public void SendRecordMsg(string type)
{
RecordMsg recordMsg = new RecordMsg();
recordMsg.tempevent = "screenRecordTips";
recordMsg.formUserId = NYSManager.Instance.DeviceData.ID;
recordMsg.platform = "DEVICE";
recordMsg.type = type;
string datahead = "brain" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
recordMsg.sign = datahead + NYSUtils.GetMD5("{}".Length + "{}");
string data = recordMsg.SaveToString();
data = data.Remove(data.IndexOf("temp"), 4);
webSocket?.Send(data);
}
private void SendMsg(string msg)
{
if (webSocket != null && webSocket.IsOpen)
{
webSocket.Send(msg);
}
}
private void SceneLoaded(Scene arg0, LoadSceneMode arg1)
{
if (WEBGameType == WEBGameTypeEnum.NULL || arg0.name.Equals(Enums.GetDesc(WEBGameType)) == false) return;
WEBGameType = WEBGameTypeEnum.NULL;
}
private void OnDestroy()
{
CloseWebSocket();
}
private void CloseWebSocket()
{
if (webSocket != null)
{
webSocket.OnOpen -= WebOnOpen;
webSocket.OnBinary -= OnBinary;
webSocket.OnMessage -= OnMessage;
webSocket.OnClosed -= OnClosed;
webSocket.OnError -= OnError;
webSocket.Close();
webSocket = null;
}
}
private struct LonginMsg
{
public string tempevent;
public int formUserId;
public string platform;
public string sign;
public string SaveToString()
{
return JsonUtility.ToJson(this);
}
}
private struct RecordMsg
{
public string tempevent;
public int formUserId;
public string platform;
public string sign;
public string type;
public string SaveToString()
{
return JsonUtility.ToJson(this);
}
}
private struct WebMessage
{
public string message;
public string type;
public string no;
}
public enum WEBControlTypeEnum
{
NULL, CHANGE, RESET, SKIP, START, PAUSE, CONTINUE, RECALIBRATE
}
private class RapidDataPack
{
public string types;
}
}
public enum WEBGameTypeEnum
{
NULL,
[Description("QuizEMCA")] EMCA,
[Description("QuizSymbolSearch")] SYMBOL_SEARCH,
[Description("QuizSymmetrySpan")] SYMMETRY_SPAN,
[Description("QuizPortraitMemory")] PORTRAIT_MEMORY,
[Description("QuizPaperFolding")] ORIGAMI_TEST,
[Description("QuizVocabulary")] VOCABULARY_TEST,
[Description("MMSE")] MMSE,
[Description("智能MoCA")] MOCA,
}