Merge branch 'dev_robotaxi-d-app-module_290_220715_2.9.0' into dev_robotaxi-d-app-module-videoprocess

# Conflicts:
#	OCH/mogo-och-taxi-passenger/src/main/res/values/strings.xml
This commit is contained in:
yangyakun
2022-07-19 17:06:42 +08:00
188 changed files with 5113 additions and 768 deletions

View File

@@ -1,18 +1,26 @@
package com.mogo.eagle.core.function.hmi.ui
import android.animation.Animator
import android.content.*
import android.graphics.*
import android.graphics.drawable.*
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Bundle
import android.text.TextUtils
import android.transition.*
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.view.WindowManager.LayoutParams
import android.view.animation.*
import android.widget.*
import androidx.core.view.*
import androidx.lifecycle.lifecycleScope
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.commons.mvp.MvpFragment
import com.mogo.commons.voice.AIAssist
import com.mogo.commons.voice.*
import com.mogo.eagle.core.data.bindingcar.AdUpgradeStateHelper
import com.mogo.eagle.core.data.bindingcar.IPCUpgradeStateInfo
import com.mogo.eagle.core.data.camera.CameraEntity
@@ -27,6 +35,7 @@ import com.mogo.eagle.core.data.report.ReportEntity
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotRecordListener
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
import com.mogo.eagle.core.function.api.hmi.IMoGoHmiViewProxy
import com.mogo.eagle.core.function.api.hmi.IMoGoHmiViewProxy.IViewNotificationProvider
import com.mogo.eagle.core.function.api.hmi.view.IViewLimitingVelocity
import com.mogo.eagle.core.function.api.hmi.view.IViewNotification
import com.mogo.eagle.core.function.api.hmi.view.IViewTrafficLight
@@ -55,14 +64,19 @@ import com.mogo.eagle.core.function.hmi.ui.setting.ReportListFloatWindow
import com.mogo.eagle.core.function.hmi.ui.tools.AdUpgradeDialog
import com.mogo.eagle.core.function.hmi.ui.tools.AutoPilotAndCheckView
import com.mogo.eagle.core.function.hmi.ui.widget.V2XNotificationView
import com.mogo.eagle.core.utilcode.kotlin.*
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.*
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_HMI
import com.mogo.eagle.core.utilcode.reminder.*
import com.mogo.eagle.core.utilcode.reminder.api.*
import com.mogo.eagle.core.utilcode.reminder.api.IReminder.IStateChangeListener
import com.mogo.eagle.core.utilcode.reminder.api.impl.*
import com.mogo.eagle.core.utilcode.util.SoundUtils
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.eagle.core.utilcode.util.TimeUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.module.common.enums.EventTypeEnum
import com.mogo.module.common.enums.*
import kotlinx.android.synthetic.main.fragment_hmi.*
import kotlinx.coroutines.*
import mogo_msg.MogoReportMsg
@@ -82,15 +96,13 @@ import kotlin.collections.ArrayList
IMoGoHmiViewProxy,
MoGoHmiContract.View,
IMoGoAutopilotRecordListener,
IMoGoAutopilotStatusListener {
IMoGoAutopilotStatusListener, IViewNotificationProvider {
private val TAG = "MoGoHmiFragment"
// DebugSettingView
private var mDebugSettingViewFloat: WarningFloat.Builder? = null
private var mDebugSettingView: DebugSettingView? = null
// V2X、OBU、云端推送预警弹窗
private var mWarningFloat: WarningFloat.Builder? = null
private var mNoticeFloat: WarningFloat.Builder? = null
@@ -113,7 +125,7 @@ import kotlin.collections.ArrayList
private var mViewLimitingVelocity: IViewLimitingVelocity? = null
// V2X预警弹窗 View 代理
private var mViewNotification: IViewNotification? = null
private var mViewNotificationProvider: IViewNotificationProvider? = null
//工控机节点上报列表
private var reportList = arrayListOf<ReportEntity>()
@@ -123,6 +135,8 @@ import kotlin.collections.ArrayList
private var adUpgradeDialog: AdUpgradeDialog?=null
private var speakJob: Job? = null
override fun vipIdentification(visible: Boolean) {
ThreadUtils.runOnUiThread {
if (visible) {
@@ -174,7 +188,7 @@ import kotlin.collections.ArrayList
// 首次初始化使用默认视图
setProxyTrafficLightView(viewTrafficLightVr)
setProxyLimitingSpeedView(viewLimitingVelocity)
setProxyNotificationView(V2XNotificationView(view.context))
setViewNotificationProvider(this)
context?.also {
if (!AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
@@ -183,7 +197,8 @@ import kotlin.collections.ArrayList
}
}
@OptIn(ExperimentalCoroutinesApi::class)
override fun getNotificationView(): IViewNotification? = context?.let { V2XNotificationView(it) }
override fun onAutopilotRecordResult(recordPanel: RecordPanelOuterClass.RecordPanel) {
if (HmiBuildConfig.isShowBadCaseView && recordPanel.type == 1 && recordPanel.stat == 100) {
CallerDevaToolsManager.onReceiveBadCaseRecord(recordPanel)
@@ -256,11 +271,8 @@ import kotlin.collections.ArrayList
}
}
/**
* 设置 V2X 通知 代理View
*/
override fun setProxyNotificationView(view: IViewNotification) {
mViewNotification = view
override fun setViewNotificationProvider(provider: IViewNotificationProvider) {
mViewNotificationProvider = provider
}
/**
@@ -379,7 +391,13 @@ import kotlin.collections.ArrayList
// 控制 BadCase 按钮展示
if (HmiBuildConfig.isShowBadCaseView) {
CallerDevaToolsManager.initBadCase(vsBadCaseToolsView)
ivBadCaseTools.visibility = View.VISIBLE
ivAiCollectTools.visibility = View.VISIBLE
CallerDevaToolsManager.initBadCase(ivBadCaseTools)
CallerDevaToolsManager.initAiCollect(ivAiCollectTools)
}else{
ivBadCaseTools.visibility = View.GONE
ivAiCollectTools.visibility = View.GONE
}
// 控制 红绿灯 展示
@@ -525,88 +543,97 @@ import kotlin.collections.ArrayList
alertContent: CharSequence?,
ttsContent: String?,
tag: String?,
listenerIMoGo: IMoGoWarningStatusListener?,
listener: IMoGoWarningStatusListener?,
playTts: Boolean,
expireTime: Long
) {
val playTTS = playTts && !AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)
lifecycleScope.launchWhenResumed {
activity?.let {
val floatWindow = mWarningFloat
val showTag = floatWindow?.config?.floatTag
if (floatWindow == null || TextUtils.isEmpty(showTag) || !floatWindow.isShow() || floatWindow.config.floatTag != tag) {
// 代理View初始化了才可以弹窗
mViewNotification?.let { notificationView ->
notificationView.setWarningIcon(EventTypeEnum.getWarningIcon(v2xType))
val warningContent = alertContent
?: EventTypeEnum.getWarningContent(v2xType)
if (warningContent.isEmpty()) {
CallerLogger.e("$M_HMI$TAG", "Show warningContent is null or empty!")
return@launchWhenResumed
} else {
notificationView.setWarningContent(warningContent)
}
if (floatWindow != null && floatWindow.isShow()) {
showWarning(WarningDirectionEnum.ALERT_WARNING_NON)
WarningFloat.dismiss(floatWindow.config.floatTag, true)
}
mWarningFloat = WarningFloat.with(it)
.setTag(tag)
.setLayout(notificationView)
.setSidePattern(notificationView.sidePattern)
.setCountDownTime(expireTime)
.setGravity(notificationView.layoutGravity, offsetX = notificationView.offsetX, offsetY = notificationView.offsetY)
.setImmersionStatusBar(true)
.isEnqueue(true)
.addWarningStatusListener(listenerIMoGo)
.addWarningStatusListener(object : IMoGoWarningStatusListener {
override fun onShow() {
// 创建弹窗成功才进行TTS播报
CallerLogger.d(
"$M_HMI$TAG",
"mWarningFloat = $mWarningFloat---ttsContent = $ttsContent"
)
if (mWarningFloat != null && !TextUtils.isEmpty(ttsContent) && playTTS) {
CallerLogger.d("$M_HMI$TAG", "---> ttsContent = $ttsContent")
AIAssist.getInstance(activity)
.speakTTSVoice(ttsContent)
}
}
override fun onDismiss() {
showWarning(WarningDirectionEnum.ALERT_WARNING_NON)
}
})
.setAnimator(object : DefaultAnimator() {
override fun enterAnim(
view: View,
params: LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator? =
super.enterAnim(view, params, windowManager, sidePattern)?.apply {
interpolator = OvershootInterpolator()
}
override fun exitAnim(
view: View,
params: LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator? =
super.exitAnim(view, params, windowManager, sidePattern)
?.setDuration(200)
})
.show()
}
} else {
val notification = floatWindow.config.layoutView as? V2XNotificationView
if (alertContent?.isNotEmpty() == true) {
notification?.setWarningContent(alertContent)
floatWindow.resetExpireTime(expireTime)
activity?.let {
val warningContent = alertContent
?: EventTypeEnum.getWarningContent(v2xType)
if (warningContent.isEmpty()) {
CallerLogger.e("$M_HMI$TAG", "Show warningContent is null or empty!")
return
}
speakJob?.safeCancel()
val content = mViewNotificationProvider?.getNotificationView() ?: return
content.setWarningIcon(EventTypeEnum.getWarningIcon(v2xType))
content.setWarningContent(warningContent)
var reminder: IReminder? = null
Reminder.enqueue(this@MoGoHmiFragment, object : PopupWindowReminder(PopupWindow(content, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).also { itx ->
itx.isTouchable = false
itx.isFocusable = false
itx.isClippingEnabled = false
itx.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val transition = Slide(Gravity.TOP).also { t ->
t.interpolator = AccelerateDecelerateInterpolator()
t.duration = 200
}
if (VERSION.SDK_INT >= VERSION_CODES.M) {
itx.enterTransition = transition
itx.exitTransition = transition
}
}) {
override fun show() {
val parent = it.window.decorView
parent.doOnAttach {
popupWindow.showAtLocation(parent, Gravity.TOP, 0, 0)
}
}
override fun isOverride(): Boolean {
return true
}
}.also { itx -> reminder = itx }, object : IStateChangeListener {
override fun onShow(reminder: IReminder) {
listener?.onShow()
if (ttsContent != null && !TextUtils.isEmpty(ttsContent) && playTTS) {
CallerLogger.d("$M_HMI$TAG", "---> ttsContent = $ttsContent")
lifecycleScope.launch {
speak(it, ttsContent)
}.also {
speakJob = it
}
}
}
override fun onHide(reminder: IReminder) {
listener?.onDismiss()
showWarning(WarningDirectionEnum.ALERT_WARNING_NON)
}
})
if (reminder == null) {
return
}
lifecycleScope.launch {
delay(expireTime)
reminder?.hide()
}
}
}
private suspend fun speak(ctx: Context, text: String) = suspendCancellableCoroutine<Unit> {
try {
val voiceCallback = object : IMogoVoiceCmdCallBack {
override fun onSpeakEnd(speakText: String?) {
super.onSpeakEnd(speakText)
it.resumeWith(Result.success(Unit))
}
override fun onSpeakError(speakText: String?, errorMsg: String?) {
super.onSpeakError(speakText, errorMsg)
it.resumeWith(Result.success(Unit))
}
}
it.invokeOnCancellation {
AIAssist.getInstance(ctx).stopSpeakTts(text)
}
AIAssist.getInstance(ctx).speakTTSVoice(text, voiceCallback)
} catch (t: Throwable) {
it.resumeWith(Result.success(Unit))
Logger.e(TAG, t.message)
}
}
@@ -861,6 +888,14 @@ import kotlin.collections.ArrayList
dismissToolsFloatView()
}
override fun showSmallFragment() {
// TODO:("展示全览模式地图")
}
override fun hideSmallFragment() {
// TODO:("隐藏全览模式地图")
}
private fun showCameraList(cameraList: List<CameraEntity>?) {
context?.let {
if (cameraViewFloat == null) {

View File

@@ -11,9 +11,12 @@ import android.text.Html
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.*
import androidx.annotation.RequiresApi
import androidx.appcompat.widget.PopupMenu
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import chassis.Chassis
import com.mogo.cloud.passport.MoGoAiCloudClient
@@ -52,6 +55,7 @@ import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.function.hmi.ui.logcatch.ILogViewListener
import com.mogo.eagle.core.function.hmi.ui.logcatch.LogInfoView
import com.mogo.eagle.core.function.hmi.ui.upgrade.UpgradeListAdapter
import com.mogo.eagle.core.network.*
import com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.LogLevel
@@ -66,6 +70,7 @@ import com.mogo.map.uicontroller.VisualAngleMode.*
import com.mogo.module.service.routeoverlay.*
import com.zhidao.easysocket.utils.L
import com.zhidao.support.adas.high.other.permission.BackgrounderPermission
import com.zhjt.mogo_core_function_devatools.env.*
import kotlinx.android.synthetic.main.view_debug_setting.view.*
import mogo.telematics.pad.MessagePad
import mogo_msg.MogoReportMsg
@@ -536,6 +541,10 @@ class DebugSettingView @JvmOverloads constructor(
// 演示模式
tbIsDemoMode.setOnCheckedChangeListener { _, isChecked ->
CallerAutoPilotManager.setDemoMode(isChecked)
if(!isChecked){
//关闭美化模式时,通知工控机
CallerAutoPilotManager.setIPCDemoMode(isChecked)
}
FunctionBuildConfig.isDemoMode = isChecked
tbIsDrawAutopilotTrajectoryData.isEnabled = !isChecked
FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = isChecked
@@ -765,7 +774,7 @@ class DebugSettingView @JvmOverloads constructor(
/**
* 设置鹰眼本地参数配置监听
*/
private fun setEagleEyeConfigListener() {
@SuppressLint("SetTextI18n") private fun setEagleEyeConfigListener() {
//初始化刹车加速度阈值信息
val brakeThreshold = SharedPrefsMgr.getInstance(context)
.getFloat(MoGoConfig.BRAKE_ACCELERATION_THRESHOLD, -2.5F)
@@ -810,6 +819,41 @@ class DebugSettingView @JvmOverloads constructor(
tbReportWarning.visibility = GONE
}
//切换环境
tvCurEnv.text = "当前环境:${EnvChangeManager.getCityName()}${EnvChangeManager.getNetMode()}"
btChangeEnv.onClick {
PopupMenu(context, btChangeEnv).also { p ->
p.menuInflater.inflate(R.menu.menu_env_pop, p.menu)
MenuCompat.setGroupDividerEnabled(p.menu, true)
p.setOnMenuItemClickListener { item ->
when(item.itemId) {
R.id.group_hy -> {
return@setOnMenuItemClickListener false
}
R.id.group_bj -> {
return@setOnMenuItemClickListener false
}
R.id.env_reset ->
EnvChangeManager.reset()
R.id.hy_product ->
EnvChangeManager.changeTo("0734", DebugConfig.NET_MODE_RELEASE)
R.id.hy_qa ->
EnvChangeManager.changeTo("0734", DebugConfig.NET_MODE_QA)
R.id.hy_demo ->
EnvChangeManager.changeTo("0734", DebugConfig.NET_MODE_DEMO)
R.id.bj_product ->
EnvChangeManager.changeTo("010", DebugConfig.NET_MODE_RELEASE)
R.id.bj_qa ->
EnvChangeManager.changeTo("010", DebugConfig.NET_MODE_QA)
R.id.bj_demo ->
EnvChangeManager.changeTo("010", DebugConfig.NET_MODE_DEMO)
else ->
throw AssertionError("invalid item: $item")
}
return@setOnMenuItemClickListener true
}
}.show()
}
}
/**

View File

@@ -30,6 +30,7 @@ import org.jetbrains.annotations.NotNull;
import chassis.Chassis;
import mogo.telematics.pad.MessagePad;
import mogo_msg.MogoReportMsg;
import system_master.SystemStatusInfo;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS_P;
@@ -142,13 +143,17 @@ public class SteeringWheelView extends ConstraintLayout {
}
}
});
}
@Override
public void onAutopilotSNRequest() {
}
@Override
public void onAutopilotStatusRespByQuery(@NonNull SystemStatusInfo.StatusInfo status) {
}
};
private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {

View File

@@ -32,8 +32,7 @@ class V2XNotificationView @JvmOverloads constructor(
sidePattern = SidePattern.RESULT_TOP
layoutGravity = Gravity.CENTER_HORIZONTAL
// 设置View的停留位置
offsetX = 0
offsetY = 110
setPadding(0, 110, 0, 0)
}
override fun setWarningIcon(@DrawableRes warningIcon: Int) {

View File

@@ -63,6 +63,7 @@ import java.util.Map;
import mogo.telematics.pad.MessagePad;
import mogo_msg.MogoReportMsg;
import system_master.SystemStatusInfo;
/**
* @author congtaowang
@@ -396,6 +397,11 @@ public class MainActivity extends MvpActivity<MainView, MainPresenter> implement
public void onAutopilotSNRequest() {
}
@Override
public void onAutopilotStatusRespByQuery(@NonNull SystemStatusInfo.StatusInfo status) {
}
private void updateConnectInfoView(@NonNull AutopilotStatusInfo autoPilotStatusInfo) {
if (!isFloatingLayerHidden) {// 遮罩层显示的时候
mConnAdapter.updateData(autoPilotStatusInfo);

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -109,16 +109,26 @@
<!--问题反馈-->
<ImageView
android:id="@+id/vsBadCaseToolsView"
android:layout_width="@dimen/module_hmi_check_size"
android:layout_height="@dimen/module_hmi_check_size"
android:layout_marginStart="25px"
android:layout_marginBottom="40px"
android:background="@drawable/icon_car_ap_badcase_entrance"
android:visibility="gone"
android:id="@+id/ivBadCaseTools"
android:layout_width="120px"
android:layout_height="120px"
android:src="@drawable/bad_case_selector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/ivToolsIcon"
app:layout_goneMarginStart="50px" />
app:layout_constraintStart_toEndOf="@id/ivToolsIcon"
android:layout_marginStart="50px"
android:layout_marginBottom="40px"
/>
<ImageView
android:id="@+id/ivAiCollectTools"
android:layout_width="120px"
android:layout_height="120px"
android:src="@drawable/ai_collect_selector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/ivBadCaseTools"
android:layout_marginStart="50px"
android:layout_marginBottom="40px"
/>
<View
android:id="@+id/viewUpgradeTips"

View File

@@ -1036,6 +1036,40 @@
android:visibility="gone"
tools:visibility="visible">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/llChangeEnv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_10"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@drawable/debug_setting_edit_bg"
android:gravity="center_vertical">
<TextView
android:id="@+id/tvCurEnv"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:textColor="#000"
android:gravity="start"
android:layout_marginStart="@dimen/dp_10"
android:textSize="@dimen/dp_24"
android:layout_weight="1"
tools:text="当前环境:"/>
<Button
android:id="@+id/btChangeEnv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/dp_8"
android:layout_marginEnd="@dimen/dp_10"
android:text="切换环境"
android:textSize="@dimen/dp_24"
android:textColor="#1A1A1A"/>
</androidx.appcompat.widget.LinearLayoutCompat>
<Button
android:id="@+id/btnBrakeThreshold"
android:layout_width="wrap_content"
@@ -1046,8 +1080,8 @@
android:paddingEnd="@dimen/dp_20"
android:text="设置刹车加速度阈值"
android:textSize="@dimen/dp_24"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@id/llChangeEnv"
app:layout_constraintLeft_toLeftOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="0dp"
@@ -1132,12 +1166,9 @@
android:textOff="开启异常上报提示"
android:textOn="关闭异常上报提示"
android:textSize="@dimen/dp_24"
app:layout_constraintTop_toBottomOf="@id/btnConnectServerIp"
/>
app:layout_constraintTop_toBottomOf="@id/btnConnectServerIp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ToggleButton
android:id="@+id/tbHmiController"
android:layout_width="match_parent"

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 Google Inc.
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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/group_hy"
android:title="衡阳">
<menu>
<item android:id="@+id/hy_product" android:title="生产环境"/>
<item android:id="@+id/hy_qa" android:title="测试环境"/>
<item android:id="@+id/hy_demo" android:title="演示环境"/>
</menu>
</item>
<item android:id="@+id/group_bj"
android:title="北京">
<menu>
<item android:id="@+id/bj_product" android:title="生产环境"/>
<item android:id="@+id/bj_qa" android:title="测试环境"/>
<item android:id="@+id/bj_demo" android:title="演示环境"/>
</menu>
</item>
<item android:id="@+id/env_reset" android:title="重置" />
</menu>

View File

@@ -21,7 +21,7 @@
<string name="check_vehicle_detection">车辆检测</string>
<string name="debug_panel">调试面板</string>
<string name="debug_panel_fb">反馈</string>
<string name="debug_panel_fb">录包设置</string>
<string name="check_vehicle_speed_setting">车速设置</string>
<string name="check_system_operation">系统运行</string>
<string name="check_system_shut_down">关机</string>