From 180bdfd50a4acbe5caa8cfc529d0fe52e85f71cd Mon Sep 17 00:00:00 2001 From: zhongchao Date: Fri, 11 Mar 2022 19:41:19 +0800 Subject: [PATCH] rebase --- .../bus/fragment/BaseOchBusTabFragment.java | 57 ++- .../och/taxi/ui/BaseOchTaxiTabFragment.java | 58 ++- app/build.gradle | 9 +- .../functions/test/AutoPilotBadCaseTest.kt | 46 +- .../mogo-core-function-devatools/build.gradle | 31 +- .../DevaToolsProvider.kt | 11 + .../badcase/BadCaseManager.kt | 281 ++++++++++++ .../badcase/api/BadCaseApi.kt | 19 + .../badcase/api/entity/BadCaseResponse.kt | 28 ++ .../badcase/api/entity/UploadResult.kt | 15 + .../badcase/consts/BadCaseHost.kt | 8 + .../badcase/mvp/BadCasePresenter.kt | 54 +++ .../badcase/mvp/BadCaseView.kt | 176 ++++++++ .../badcase/mvp/biz/IBadCasePresenter.kt | 24 ++ .../badcase/repository/Repository.kt | 93 ++++ .../badcase/repository/db/BadCaseDb.kt | 16 + .../badcase/repository/db/BadCaseDbModel.kt | 12 + .../repository/db/dao/IBadCaseRecordDao.kt | 19 + .../repository/db/entity/AutoPilotRecord.kt | 89 ++++ .../badcase/repository/net/BadCaseNetModel.kt | 44 ++ .../badcase/repository/store/BadCaseStore.kt | 109 +++++ .../src/main/proto/badcase.proto | 17 + .../drawable-xxhdpi/icon_ap_badcase_check.png | Bin .../icon_ap_badcase_default.png | Bin .../res/layout/layout_badcase_collect.xml | 0 .../main/res/layout/layout_badcase_item.xml | 0 .../mogo-core-function-hmi/build.gradle | 4 + .../core/function/hmi/ui/MoGoHmiFragment.kt | 389 +++-------------- .../function/hmi/ui/tools/AutoPilotBadCase.kt | 404 ------------------ .../src/main/res/layout/fragment_hmi.xml | 6 +- core/mogo-core-function-api/build.gradle | 3 + .../api/devatools/IDevaToolsProvider.kt | 15 + .../api/hmi/warning/IMoGoWaringProvider.kt | 14 +- .../call/devatools/CallerDevaToolsManager.kt | 28 +- .../function/call/hmi/CallerHmiManager.kt | 15 +- 35 files changed, 1260 insertions(+), 834 deletions(-) create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/BadCaseApi.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/BadCaseResponse.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/UploadResult.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/consts/BadCaseHost.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCasePresenter.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCaseView.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/biz/IBadCasePresenter.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/Repository.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDb.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDbModel.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/dao/IBadCaseRecordDao.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/entity/AutoPilotRecord.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/net/BadCaseNetModel.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/store/BadCaseStore.kt create mode 100644 core/function-impl/mogo-core-function-devatools/src/main/proto/badcase.proto rename core/function-impl/{mogo-core-function-hmi => mogo-core-function-devatools}/src/main/res/drawable-xxhdpi/icon_ap_badcase_check.png (100%) rename core/function-impl/{mogo-core-function-hmi => mogo-core-function-devatools}/src/main/res/drawable-xxhdpi/icon_ap_badcase_default.png (100%) rename core/function-impl/{mogo-core-function-hmi => mogo-core-function-devatools}/src/main/res/layout/layout_badcase_collect.xml (100%) rename core/function-impl/{mogo-core-function-hmi => mogo-core-function-devatools}/src/main/res/layout/layout_badcase_item.xml (100%) delete mode 100644 core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/tools/AutoPilotBadCase.kt diff --git a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java index fe02bfef81..c881ebcc7d 100644 --- a/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java +++ b/OCH/mogo-och-bus/src/main/java/com/mogo/och/bus/fragment/BaseOchBusTabFragment.java @@ -3,6 +3,7 @@ package com.mogo.och.bus.fragment; import android.animation.ObjectAnimator; import android.content.Intent; import android.graphics.Color; +import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -13,6 +14,8 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.constraintlayout.widget.Group; import com.mogo.commons.AbsMogoApplication; @@ -21,8 +24,15 @@ import com.mogo.commons.mvp.IView; import com.mogo.commons.mvp.MvpFragment; import com.mogo.commons.mvp.Presenter; import com.mogo.commons.voice.AIAssist; +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult; +import com.mogo.eagle.core.data.autopilot.AutopilotWarnMessage; +import com.mogo.eagle.core.data.config.HmiBuildConfig; +import com.mogo.eagle.core.data.traffic.TrafficData; +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener; import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; +import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager; +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager; import com.mogo.eagle.core.function.call.hmi.CallerHmiManager; import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.eagle.core.utilcode.util.UiThreadHandler; @@ -35,6 +45,8 @@ import com.mogo.och.bus.R; import com.mogo.och.bus.view.BusArcView; import com.mogo.och.bus.view.SlidePanelView; +import java.util.ArrayList; + /** * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况 *

@@ -42,7 +54,7 @@ import com.mogo.och.bus.view.SlidePanelView; * * @author tongchenfei */ -public abstract class BaseOchBusTabFragment> extends MvpFragment implements IMogoMapListener { +public abstract class BaseOchBusTabFragment> extends MvpFragment implements IMogoMapListener, IMoGoAutopilotIdentifyListener { private static final String TAG = "BaseOchFragment"; @@ -200,17 +212,45 @@ public abstract class BaseOchBusTabFragment { // onShow() - return mBadcaseBtn; }, - () -> { // onHide() - return null; }); +// CallerHmiManager.INSTANCE.registerBadCaseCallback( +// () -> { // onShow() +// return mBadcaseBtn; }, +// () -> { // onHide() +// return null; }); + if (mBadcaseBtn != null) { + CallerDevaToolsManager.INSTANCE.initBadCase(mBadcaseBtn, null, null); + if (!HmiBuildConfig.isShowBadCaseView) { + CallerAutopilotIdentifyListenerManager.INSTANCE.addListener(TAG, this); + } + } //设置升级小红点提示 默认隐藏 mUpgradeTipIv = findViewById(R.id.module_och_bus_upgrade_red_tip); CallerHmiManager.INSTANCE.registerUpgradeTipsCallback(() -> mUpgradeTipIv); } + @Override + public void onDestroyView() { + super.onDestroyView(); + if (!HmiBuildConfig.isShowBadCaseView) { + CallerAutopilotIdentifyListenerManager.INSTANCE.removeListener(TAG); + } + } + + + @Override + public void onAutopilotRecordResult(@Nullable AutoPilotRecordResult record) { + if (!HmiBuildConfig.isShowBadCaseView && record != null && record.getType() == 1 && record.getStat() == 100) { + CallerDevaToolsManager.INSTANCE.onReceiveBadCaseRecord(record); + } + } + + @Override + public void onAutopilotIdentifyDataUpdate(@Nullable ArrayList trafficData) { } + + @Override + public void onAutopilotWarnMessage(@Nullable AutopilotWarnMessage autopilotWarnMessage) { } + /** * 测试到站 */ @@ -367,11 +407,6 @@ public abstract class BaseOchBusTabFragment> extends MvpFragment implements IMogoMapListener { +public abstract class BaseOchTaxiTabFragment> extends MvpFragment implements IMogoMapListener, IMoGoAutopilotIdentifyListener { private static final String TAG = "BaseOchFragment"; private LinearLayout ctvAutopilotStatus; @@ -133,12 +145,18 @@ public abstract class BaseOchTaxiTabFragment { // onShow() - return mBadcaseBtn; }, - () -> { // onHide() - return null; }); +// CallerHmiManager.INSTANCE.registerBadCaseCallback( +// () -> { // onShow() +// return mBadcaseBtn; }, +// () -> { // onHide() +// return null; }); + if (mBadcaseBtn != null) { + CallerDevaToolsManager.INSTANCE.initBadCase(mBadcaseBtn, null, null); + if (!HmiBuildConfig.isShowBadCaseView) { + CallerAutopilotIdentifyListenerManager.INSTANCE.addListener(TAG, this); + } + } //设置升级小红点提示 默认隐藏 mUpgradeTipIv = findViewById(R.id.module_och_taxi_upgrade_red_tip); CallerHmiManager.INSTANCE.registerUpgradeTipsCallback(() -> mUpgradeTipIv); @@ -240,6 +258,29 @@ public abstract class BaseOchTaxiTabFragment trafficData) { } + + @Override + public void onAutopilotRecordResult(@Nullable AutoPilotRecordResult record) { + if (!HmiBuildConfig.isShowBadCaseView && record != null && record.getType() == 1 && record.getStat() == 100) { + CallerDevaToolsManager.INSTANCE.onReceiveBadCaseRecord(record); + } + } + + @Override + public void onAutopilotWarnMessage(@Nullable AutopilotWarnMessage autopilotWarnMessage) { } + public void showNotice(String notice) { getActivity().runOnUiThread(() -> { AIAssist.getInstance(getContext()).speakTTSVoice(notice); @@ -409,11 +450,6 @@ public abstract class BaseOchTaxiTabFragment - val executor = Executors.newSingleThreadScheduledExecutor() - executor.scheduleAtFixedRate({ - var find = - itx.supportFragmentManager.fragments.find { it is MoGoHmiFragment } as? MoGoHmiFragment - while (find == null) { - find = - itx.supportFragmentManager.fragments.find { it is MoGoHmiFragment } as? MoGoHmiFragment - - } - while (!find.isResumed) { - Thread.sleep(500) - } - it.resumeWith(Result.success(find)) - try { - Thread.sleep(500) - executor.shutdownNow() - } catch (e: Throwable) { - e.printStackTrace() - } - }, 50, 500, TimeUnit.MILLISECONDS) - } - } } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/build.gradle b/core/function-impl/mogo-core-function-devatools/build.gradle index 56c8d2e062..9874e99d32 100644 --- a/core/function-impl/mogo-core-function-devatools/build.gradle +++ b/core/function-impl/mogo-core-function-devatools/build.gradle @@ -4,6 +4,7 @@ plugins { id 'kotlin-android-extensions' id 'kotlin-kapt' id 'com.alibaba.arouter' + id 'com.google.protobuf' } android { @@ -39,21 +40,45 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs += [ + "-Xopt-in=kotlin.RequiresOptIn" + ] + } + protobuf { + protoc { + artifact = rootProject.ext.dependencies.google_protoc + } + generateProtoTasks { + all().each { task -> + task.builtins { + java {} + } + } + } + } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation rootProject.ext.dependencies.kotlinstdlibjdk7 - implementation rootProject.ext.dependencies.coroutinescore implementation rootProject.ext.dependencies.arouter kapt rootProject.ext.dependencies.aroutercompiler implementation rootProject.ext.dependencies.mogologlib implementation rootProject.ext.dependencies.mogochainbase + kapt rootProject.ext.dependencies.androidxroomcompiler + implementation rootProject.ext.dependencies.androidxroomruntime + implementation rootProject.ext.dependencies.androidxroomktx + implementation rootProject.ext.dependencies.androidx_datastore + implementation rootProject.ext.dependencies.google_proto_java + implementation rootProject.ext.dependencies.androidxappcompat + implementation rootProject.ext.dependencies.androidxconstraintlayout + implementation rootProject.ext.dependencies.androidxrecyclerview + if (Boolean.valueOf(USE_MAVEN_PACKAGE)) { implementation rootProject.ext.dependencies.mogoserviceapi implementation rootProject.ext.dependencies.modulecommon - implementation rootProject.ext.dependencies.mogo_core_utils implementation rootProject.ext.dependencies.mogo_core_function_api implementation rootProject.ext.dependencies.mogo_core_function_call diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/DevaToolsProvider.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/DevaToolsProvider.kt index faa6260712..6b2c12162b 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/DevaToolsProvider.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/DevaToolsProvider.kt @@ -2,8 +2,10 @@ package com.zhjt.mogo_core_function_devatools import android.annotation.SuppressLint import android.content.Context +import android.view.View import com.alibaba.android.arouter.facade.annotation.Route import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_ADAS_INIT import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_ADAS_MSG import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_CONNECT_STATUS @@ -18,6 +20,7 @@ import com.mogo.eagle.core.utilcode.util.DeviceUtils import com.mogo.eagle.core.utilcode.util.Utils import com.zhidao.loglib.fw.FileWriteManager import com.zhidao.loglib.fw.FwBuild +import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchManager import com.zhjt.service.chain.core.ChainTraceStarter @@ -100,6 +103,14 @@ class DevaToolsProvider : IDevaToolsProvider { FileWriteManager.getInstance().operateChainMap(fwBuildMap) } + override fun initBadCase(view: View, onShow: (() -> Unit)?, onHide: (() -> Unit)?) { + BadCaseManager.init(view, onShow, onHide) + } + + override fun onReceiveBadCaseRecord(record: AutoPilotRecordResult) { + BadCaseManager.onReceiveBadCaseRecord(record) + } + override fun onDestroy() { MogoLogCatchManager.onDestroy() } diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt new file mode 100644 index 0000000000..922bf86078 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt @@ -0,0 +1,281 @@ +package com.zhjt.mogo_core_function_devatools.badcase + +import android.transition.AutoTransition +import android.transition.TransitionManager +import android.util.Log +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.Lifecycle.Event +import androidx.lifecycle.Lifecycle.Event.ON_DESTROY +import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager +import com.mogo.eagle.core.utilcode.kotlin.lifecycleOwner +import com.mogo.eagle.core.utilcode.kotlin.onClick +import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.eagle.core.utilcode.util.Utils +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason +import com.zhjt.mogo_core_function_devatools.badcase.mvp.BadCasePresenter +import com.zhjt.mogo_core_function_devatools.badcase.mvp.BadCaseView +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.Channel +import java.lang.ref.WeakReference +import java.util.concurrent.TimeUnit + +internal object BadCaseManager : LifecycleEventObserver { + + const val TAG = "BadCase" + + /** + * 超过此时间,case入口自动消失 + */ + + private val CASE_EXPIRE_DURATION: Long = TimeUnit.HOURS.toMillis(4)/* TimeUnit.SECONDS.toMillis(10) */ + + private var onShow: (() -> Unit)? = null + private var onHide: (() -> Unit)? = null + + private var hideFloat: (() -> Unit)? = null + + @Volatile + private var record: AutoPilotRecord? = null + + @Volatile + private var viewHolder : WeakReference? = null + + @Volatile + private var dismissJob: Job? = null + + @OptIn(ExperimentalCoroutinesApi::class) + private var channel: Channel = Channel(Channel.RENDEZVOUS) + get() = if (field.isClosedForReceive || field.isClosedForSend) { + field = Channel(Channel.RENDEZVOUS) + field + } else { + field + } + + private val presenter by lazy { + BadCasePresenter() + } + + @Volatile + private var scope: LifecycleCoroutineScope? = null + get() = if (field == null) { + field = viewHolder?.get()?.lifecycleOwner?.lifecycleScope + field + } else { + field + } + + fun init(view: View, onShow: (() -> Unit)?, onHide: (() -> Unit)?) { + this.viewHolder = WeakReference(view) + view.lifecycleOwner.lifecycle.addObserver(this) + this.onShow = onShow + this.onHide = onHide + register() + recoverBadCase() + } + + @OptIn(ExperimentalCoroutinesApi::class) + private fun register() { + scope?.launch(Dispatchers.Default) { + while (true) { + Log.d(TAG, "---- 开始监听BadCase事件 ----") + val old = record + if (old == null || old.consumed) { + Log.d(TAG, "---- 当前事件已消费 -- value: $old") + var receive = channel.receive() + var oldT = record?.toLongTime() ?: 0L + var newT = receive.toLongTime() + if (isValid(oldT, newT)) { + record = receive + Log.d(TAG, "---- 时间有效,开始展示入口 ---") + withContext(Dispatchers.Main) { + showBadCaseInternal(receive) + } + continue + } + Log.d(TAG, "---- 时间无效,移除管道中无用数据 ---") + presenter.deleteRecord(receive) + while (oldT != 0L && newT != 0L && (newT - oldT) >= CASE_EXPIRE_DURATION) { + oldT = newT + receive = channel.receive() + newT = receive.toLongTime() + presenter.deleteRecord(receive) + } + receive.takeIf { it.key != old?.key }?.also { + Log.d(TAG, "record: [$record] is displaying for rest ...") + record = receive + withContext(Dispatchers.Main) { + showBadCaseInternal(it) + } + } + } else { + Log.d(TAG, "record: [$old] hasn't been consumed~~~~") + withContext(Dispatchers.Main) { + showEntry() + } + delay(1000) + } + } + } + } + + + private fun recoverBadCase() { + scope?.launchWhenCreated { + val lastModified = presenter.getLastModified() + val list = withContext(Dispatchers.IO) { + try { + Log.d(TAG, " --- 1 ----") + Log.d(TAG, "恢复持久化的数据 - 最后修改时间:$lastModified") + presenter.getUnConsumedRecords().fold(mutableListOf()) { + acc, record -> + if (isValid(lastModified, record.toLongTime())) { + acc.add(record) + } else { + presenter.deleteRecord(record) + } + acc + } + } catch (t: Throwable) { + emptyList() + } + } + if (list.isEmpty()) { + Log.d(TAG, "没有要恢复的数据") + } else { + list.forEach { + Log.d(TAG, "恢复的接管数据:$it") + channel.send(it) + } + } + + } + } + + private fun isValid(oldT: Long, newT: Long): Boolean { + return oldT == 0L || newT == 0L || (newT - oldT >= 0 && (newT - oldT) < CASE_EXPIRE_DURATION) + } + + fun onReceiveBadCaseRecord(record: AutoPilotRecordResult) { + scope?.launch { + val newRecord = record.toRecord() + withContext(Dispatchers.IO) { + presenter.insertRecord(newRecord) + channel.send(newRecord) + } + } + } + + private fun CoroutineScope.showBadCaseInternal(record: AutoPilotRecord) = launch { + viewHolder?.get()?.also { + presenter.updateLastModified(record.toLongTime()) + showEntry() + it.onClick { + showBadCaseFloat( + onDismiss = { + hideFloat?.invoke() + hideFloat = null + }, + onSelect = { reason -> + val uploadResult = presenter.upload(mutableMapOf().also { itx -> + itx["carLicense"] = MoGoAiCloudClientConfig.getInstance().sn + itx["filename"] = record.fileName ?: "" + itx["filesize"] = record.total.toString() + itx["key"] = record.key ?: "" + itx["reason"] = reason.reason ?: "" + itx["duration"] = record.duration.toInt().toString() + itx["timestamp"] = record.timestamp + }) + if (uploadResult == null || uploadResult.code != 200) { + ToastUtils.showShort("接管反馈失败") + } else { + ToastUtils.showShort("接管反馈成功") + record.consumed = true + withContext(Dispatchers.IO) { + presenter.deleteRecord(record) + } + hideEntry() + hideFloat?.invoke() + hideFloat = null + } + }) + } + dismissAfterDelay()?.also { dismissJob = it } + } + } + + private fun dismissAfterDelay(): Job? { + dismissJob?.takeIf { it.isActive }?.cancel() + return scope?.launch { + delay(CASE_EXPIRE_DURATION) + hideEntry() + record?.also { + it.consumed = true + withContext(Dispatchers.IO) { + presenter.deleteRecord(it) + } + } + } + } + + private fun showEntry() { + viewHolder?.get()?.takeIf { it.visibility != View.VISIBLE }?.also { + it.toggle(true) + onShow?.invoke() + } + } + + private fun hideEntry() { + viewHolder?.get()?.takeIf { it.visibility == View.VISIBLE }?.also { + it.toggle(false) + onHide?.invoke() + } + } + + private fun showBadCaseFloat(onDismiss: () -> Unit, onSelect:suspend (reason: Reason) -> Unit) { + val context = viewHolder?.get()?.context ?: Utils.getApp() + BadCaseView(context).also { + it.register(record, onDismiss, onSelect) + hideFloat = CallerHmiManager.showBadCaseFloat(floatView = it) + } + } + + override fun onStateChanged(source: LifecycleOwner, event: Event) { + if (event == ON_DESTROY) { + dismissJob?.takeIf { it.isActive }?.cancel() + onHide = null + onShow = null + hideFloat = null + } + } +} + +fun T.toggle(show: Boolean) { + val group = (parent as? ViewGroup) ?: return + val target = if (show) View.VISIBLE else View.GONE + takeIf { it.visibility != target }?.also { + TransitionManager.beginDelayedTransition(group, AutoTransition()) + it.visibility = target + } +} + +internal fun AutoPilotRecordResult.toRecord(): AutoPilotRecord = AutoPilotRecord().also { + it.id = this.id + it.stat = this.stat + it.key = this.key + it.note = this.note + it.type = this.type + it.total = this.total + it.fileName = this.fileName + it.duration = this.duration + it.diskFree = this.diskFree + it.consumed = false +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/BadCaseApi.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/BadCaseApi.kt new file mode 100644 index 0000000000..07350f1355 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/BadCaseApi.kt @@ -0,0 +1,19 @@ +package com.zhjt.mogo_core_function_devatools.badcase.api + +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult +import retrofit2.Response +import retrofit2.http.FieldMap +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.POST + +internal interface BadCaseApi { + + @FormUrlEncoded + @POST("/yycp-vehicle-management-service/tool/badcase/add") + suspend fun post(@FieldMap map: Map): Response + + @GET("/yycp-vehicle-management-service/tool/badcase/reasons") + suspend fun get(): Response +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/BadCaseResponse.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/BadCaseResponse.kt new file mode 100644 index 0000000000..e4d4382e7e --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/BadCaseResponse.kt @@ -0,0 +1,28 @@ +package com.zhjt.mogo_core_function_devatools.badcase.api.entity + +import androidx.annotation.Keep +import com.google.gson.annotations.Expose + +@Keep +internal class BadCaseResponse { + var code: Int = -1 + var data: List? = null + var msg: String? = null + var success: Boolean = false + var total: Int = -1 + + @Expose(serialize = false, deserialize = false) + var isBuildIn: Boolean = false + + @Keep + class Reason { + var id: String? = null + var reason: String? = null + + /** + * 业务字段,不参与序列化和反序列化 + */ + @Expose(deserialize = false, serialize = false) + var isChecked: Boolean = false + } +} diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/UploadResult.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/UploadResult.kt new file mode 100644 index 0000000000..8661560732 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/api/entity/UploadResult.kt @@ -0,0 +1,15 @@ +package com.zhjt.mogo_core_function_devatools.badcase.api.entity + +import androidx.annotation.Keep + +@Keep +internal class UploadResult { + var code: Int = -1 + var msg: String? = null + var data: Array? = null + var success: Boolean = false + + override fun toString(): String { + return "UploadResult(code=$code, msg=$msg, data=${data?.contentToString()}, success=$success)" + } +} diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/consts/BadCaseHost.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/consts/BadCaseHost.kt new file mode 100644 index 0000000000..2a7e072aa0 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/consts/BadCaseHost.kt @@ -0,0 +1,8 @@ +package com.zhjt.mogo_core_function_devatools.badcase.consts + +import com.mogo.commons.debug.DebugConfig + +internal object BadCaseHost { + + fun getHost(): String = if (DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE) "http://dzt.zhidaozhixing.com" else "http://front.zdjs-private-test.myghost.zhidaoauto.com" +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCasePresenter.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCasePresenter.kt new file mode 100644 index 0000000000..cc70f3ab1d --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCasePresenter.kt @@ -0,0 +1,54 @@ +package com.zhjt.mogo_core_function_devatools.badcase.mvp + +import android.util.Log +import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult +import com.zhjt.mogo_core_function_devatools.badcase.mvp.biz.IBadCasePresenter +import com.zhjt.mogo_core_function_devatools.badcase.repository.Repository +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord +import kotlinx.coroutines.flow.Flow + +internal class BadCasePresenter: IBadCasePresenter { + + private val repository by lazy { + Repository() + } + + override suspend fun loadBadCases() = repository.loadBadCases() + + override suspend fun insertRecord(record: AutoPilotRecord) { + try { + repository.insert(record) + } catch (t: Throwable) { + Log.d(BadCaseManager.TAG, "-- 插入数据失败 -- msg: $t") + } + } + + override suspend fun getUnConsumedRecords(): List { + return try { + repository.getAllUnConsumedRecord() ?: emptyList() + } catch (t: Throwable) { + Log.d(BadCaseManager.TAG, "-- 获取所有未消费的数据失败 -- msg: $t") + emptyList() + } + } + + override suspend fun deleteRecord(record: AutoPilotRecord) { + try { + repository.deleteRecord(record) + } catch (t: Throwable) { + Log.d(BadCaseManager.TAG, "-- 删除某条记录失败 -- msg: $t") + } + } + + override suspend fun upload(map: Map): UploadResult? = repository.upload(map) + + override suspend fun updateLastModified(timestamp: Long) { + repository.uploadLastModified(timestamp) + } + + override suspend fun getLastModified(): Long { + Log.d(BadCaseManager.TAG, " --- 2 ----") + return repository.getLastModified() + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCaseView.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCaseView.kt new file mode 100644 index 0000000000..435605a055 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/BadCaseView.kt @@ -0,0 +1,176 @@ +package com.zhjt.mogo_core_function_devatools.badcase.mvp + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.GradientDrawable +import android.graphics.drawable.StateListDrawable +import android.util.AttributeSet +import android.util.StateSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult +import com.mogo.eagle.core.utilcode.kotlin.* +import com.zhjt.mogo_core_function_devatools.R +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord +import kotlinx.android.synthetic.main.layout_badcase_collect.view.* +import kotlinx.coroutines.launch +import java.text.SimpleDateFormat +import java.util.* + +internal class BadCaseView: ConstraintLayout { + + @Volatile + private var selectCase: Reason? = null + + @Volatile + private var cases: List? = null + + private val presenter by lazy { + BadCasePresenter() + } + + private var onDismiss: (() -> Unit)? = null + private var onSelect:(suspend (reason: Reason) -> Unit)? = null + + private val scope by lazy { + lifecycleOwner.lifecycleScope + } + + private var record: AutoPilotRecord? = null + + constructor(context: Context) : this(context, null) + + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + + @SuppressLint("SetTextI18n") constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + LayoutInflater.from(context).inflate(R.layout.layout_badcase_collect, this, true) + background = ColorDrawable(Color.parseColor("#F0151D41")) + isClickable = true + layoutParams = ViewGroup.LayoutParams(960.toPixels().toInt(), 1528.toPixels().toInt()) + close?.onClick { + onDismiss?.invoke() + } + cancel?.also { + it.background = shape(solid = Color.parseColor("#3B4577"), radius = 16) + it.onClick { + onDismiss?.invoke() + } + } + ok?.also { + val enabled = gradient(radius = 16.toPixels().toInt(), orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252)) + val disabled = gradient(radius = 16.toPixels().toInt(), orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(24, 71, 129), endColor = Color.rgb(21, 46, 129)) + it.background = object : StateListDrawable() {}.also { itx -> + itx.addState(intArrayOf(android.R.attr.state_enabled), enabled) + itx.addState(StateSet.WILD_CARD, disabled) + } + it.onClick { + selectCase?.run { + scope.launch { + onSelect?.invoke(this@run) + } + } + } + } + scope.launchWhenCreated { + time_of_take_over?.text = "接管时间:${SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.getDefault()).format(record?.toLongTime() ?: System.currentTimeMillis())}" + showLoading() + presenter.loadBadCases().also { + cases = it + refresh(it) + } + hideLoading() + } + } + + private fun refresh(causes: List) { + cases = causes + rv_take_over?.let { + it.layoutManager = LinearLayoutManager(it.context, LinearLayoutManager.VERTICAL, false) + it.adapter = object : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BadCaseViewHolder = BadCaseViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_badcase_item, parent, false)) + override fun onBindViewHolder(holder: BadCaseViewHolder, position: Int) { + val cases = cases + if (cases == null || cases.isEmpty()) { + return + } + if (position >= cases.size) { + return + } + val case = cases[position] + holder.bindData(case) + } + override fun getItemCount(): Int = cases?.size ?: 0 + } + } + } + + private fun showLoading() { + pb?.let { + it.visibility = View.VISIBLE + } + } + + private fun hideLoading() { + pb?.let { + it.visibility = View.INVISIBLE + } + } + + private inner class BadCaseViewHolder(item: View) : RecyclerView.ViewHolder(item) { + + private val check: ImageView = item.findViewById(R.id.check) + private val reason: TextView = item.findViewById(R.id.reason) + + init { + check.background = StateListDrawable().also { + it.addState(intArrayOf(android.R.attr.state_selected), ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_check)) + it.addState(StateSet.WILD_CARD, ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_default)) + } + } + + @SuppressLint("NotifyDataSetChanged") + fun bindData(case: Reason) { + check.isSelected = case.isChecked + reason.text = case.reason ?: "" + if (case.isChecked) { + ok?.isSelected = true + } + itemView.onClick { + case.isChecked = !case.isChecked + selectCase = case + cancelOtherChecked(case) + ok?.isEnabled = hasCheckedItem() + rv_take_over?.adapter?.notifyDataSetChanged() + } + } + + private fun hasCheckedItem(): Boolean = cases?.find { it.isChecked } != null + + private fun cancelOtherChecked(case: Reason) { + val cases = cases + if (cases == null || cases.isEmpty()) { + return + } + cases.filterNot { it == case }.forEach { + it.isChecked = false + } + } + } + + fun register(record: AutoPilotRecord?, onDismiss: () -> Unit, onSelect:suspend (reason: Reason) -> Unit) { + this.record = record + this.onDismiss = onDismiss + this.onSelect = onSelect + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/biz/IBadCasePresenter.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/biz/IBadCasePresenter.kt new file mode 100644 index 0000000000..4652dc9f60 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/mvp/biz/IBadCasePresenter.kt @@ -0,0 +1,24 @@ +package com.zhjt.mogo_core_function_devatools.badcase.mvp.biz + +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord +import kotlinx.coroutines.flow.Flow + + +internal interface IBadCasePresenter { + + suspend fun loadBadCases(): List + + suspend fun updateLastModified(timestamp: Long) + + suspend fun getLastModified(): Long + + suspend fun upload(map: Map): UploadResult? + + suspend fun insertRecord(record: AutoPilotRecord) + + suspend fun getUnConsumedRecords(): List + + suspend fun deleteRecord(record: AutoPilotRecord) +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/Repository.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/Repository.kt new file mode 100644 index 0000000000..db0456fc37 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/Repository.kt @@ -0,0 +1,93 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository + +import android.util.Log +import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.BadCaseDbModel +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord +import com.zhjt.mogo_core_function_devatools.badcase.repository.net.BadCaseNetModel +import com.zhjt.mogo_core_function_devatools.badcase.repository.store.BadCaseStore +import kotlinx.coroutines.flow.Flow + +internal class Repository { + + private val net by lazy { + BadCaseNetModel() + } + + private val db by lazy { + BadCaseDbModel() + } + + private val store by lazy { + BadCaseStore + } + + suspend fun loadBadCases(): List { + return net.get()?.data?.takeIf { it.isNotEmpty() }?.also { store.updateRecords(it) } ?: store.records().takeIf { it.isNotEmpty() } ?: getBuildIn() + } + + suspend fun uploadLastModified(timestamp: Long) { + store.updateLastModified(timestamp) + } + + suspend fun getLastModified(): Long { + Log.d(BadCaseManager.TAG, " --- 3 ----") + return store.getLastModified() + } + + private fun getBuildIn(): List { + Log.d(BadCaseManager.TAG, "-- load cases from buildin -- 1 --") + val data = mutableListOf() + data += Reason().also { + it.id = "1" + it.reason = "变道有干扰" + } + data += Reason().also { + it.id = "2" + it.reason = "遇红绿灯未停车" + } + data += Reason().also { + it.id = "3" + it.reason = "遇障碍物未停车" + } + data += Reason().also { + it.id = "4" + it.reason = "无法绕行" + } + data += Reason().also { + it.id = "5" + it.reason = "画龙" + } + data += Reason().also { + it.id = "6" + it.reason = "转弯过于靠近路侧" + } + data += Reason().also { + it.id = "7" + it.reason = "无故退出自动驾驶" + } + data += Reason().also { + it.id = "8" + it.reason = "其它" + } + return data + } + + suspend fun upload(map: Map): UploadResult? { + return net.upload(map) + } + + suspend fun insert(record: AutoPilotRecord) { + db.dao().insertRecord(record) + } + + suspend fun deleteRecord(record: AutoPilotRecord) { + db.dao().deleteRecord(record) + } + + suspend fun getAllUnConsumedRecord(): List? { + return db.dao().getAllUnConsumedRecords() + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDb.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDb.kt new file mode 100644 index 0000000000..ec4dd92965 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDb.kt @@ -0,0 +1,16 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository.db + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.dao.IBadCaseRecordDao +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord + +@Database(entities = [ + AutoPilotRecord::class + ], + version = 1, + exportSchema = false) +internal abstract class BadCaseDb : RoomDatabase() { + + abstract fun dao(): IBadCaseRecordDao +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDbModel.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDbModel.kt new file mode 100644 index 0000000000..360a8b0658 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/BadCaseDbModel.kt @@ -0,0 +1,12 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository.db + +import androidx.room.Room +import com.mogo.eagle.core.utilcode.util.Utils +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.dao.IBadCaseRecordDao + +internal class BadCaseDbModel { + + fun dao(): IBadCaseRecordDao { + return Room.databaseBuilder(Utils.getApp(), BadCaseDb::class.java, "bad-cases").build().dao() + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/dao/IBadCaseRecordDao.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/dao/IBadCaseRecordDao.kt new file mode 100644 index 0000000000..c40d2e22bb --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/dao/IBadCaseRecordDao.kt @@ -0,0 +1,19 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository.db.dao + +import androidx.room.* +import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord + +@Dao +internal interface IBadCaseRecordDao { + + @Transaction + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertRecord(record: AutoPilotRecord): Long + + @Transaction + @Delete + suspend fun deleteRecord(record: AutoPilotRecord): Int + + @Query("SELECT * FROM record ORDER BY timestamp ASC") + suspend fun getAllUnConsumedRecords(): List? +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/entity/AutoPilotRecord.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/entity/AutoPilotRecord.kt new file mode 100644 index 0000000000..2a55730795 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/db/entity/AutoPilotRecord.kt @@ -0,0 +1,89 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.text.SimpleDateFormat +import java.util.* +@Entity(tableName = "record") +internal class AutoPilotRecord { + + /** + * 磁盘可用空间(M) + */ + @ColumnInfo(name = "disk_free") + var diskFree: Long = 0 + + /** + * 采集时长 + */ + var duration: Double = 0.0 + + + /** + * 保存的文件名 + */ + @ColumnInfo(name = "file_name") + var fileName: String? = "" + + + /** + * 其他信息,包含错误信息等 + */ + var note: String? = "" + + /** + * 域控制器定义的bag key + */ + var key: String? = "" + + /** + * 采集状态: + * 100 - 采集成功,自动结束 + * 101 - 采集成功,收到结束指令 + * 200 - 采集失败 + * 201 - 采集中 + * 300 - 开始采集 + */ + var stat: Int = 0 + + + /** + * 任务类型:1-badcase采集任务,2-地图数据采集任务 + */ + var type: Int = 0 + + /** + * 任务ID + */ + var id: Int = 0 + + /** + * 时间戳,格式:YYYY-MM-DD-hh-mm-ss + */ + @PrimaryKey + var timestamp: String = SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(Date()) + + /** + * 此次采集数据总大小(M) + */ + var total: Long? = 0 + + /** + * 记录此条数据是否已消费 + */ + @Volatile + var consumed: Boolean = false + + + override fun toString(): String { + return "AutoPilotRecord(diskFree=$diskFree, duration=$duration, fileName=$fileName, note=$note, key=$key, stat=$stat, type=$type, id=$id, timestamp='$timestamp', total=$total, consumed=$consumed)" + } + + fun toLongTime(): Long = try { + SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(this.timestamp)?.time ?: 0L + } catch (t: Throwable) { + 0L + } +} + diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/net/BadCaseNetModel.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/net/BadCaseNetModel.kt new file mode 100644 index 0000000000..6388faa7f3 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/net/BadCaseNetModel.kt @@ -0,0 +1,44 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository.net + +import android.util.Log +import com.mogo.eagle.core.network.MoGoRetrofitFactory +import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager +import com.zhjt.mogo_core_function_devatools.badcase.api.BadCaseApi +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.UploadResult +import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseHost + +internal class BadCaseNetModel { + + suspend fun get(): BadCaseResponse? = try { + Log.d(BadCaseManager.TAG, "-- load cases from net -- 1 --") + MoGoRetrofitFactory + .getInstance(BadCaseHost.getHost()) + .create(BadCaseApi::class.java) + .get() + .takeIf { + val body = it.body() + it.isSuccessful && body != null && (body.code == 0 || body.code == 200) + } + ?.body()?.also { + Log.d(BadCaseManager.TAG, "-- load cases from net -- 2 --") + } + } catch (t: Throwable) { + Log.d(BadCaseManager.TAG, "-- load cases from net -- 3 --") + null + } + + suspend fun upload(map: Map): UploadResult? = try { + MoGoRetrofitFactory + .getInstance(BadCaseHost.getHost()) + .create(BadCaseApi::class.java) + .post(map) + .takeIf { + val body = it.body() + return@takeIf it.isSuccessful && (body != null) && (body.code == 0 || body.code == 200) + } + ?.body() + } catch (t: Throwable) { + null + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/store/BadCaseStore.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/store/BadCaseStore.kt new file mode 100644 index 0000000000..3d906b63c8 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/repository/store/BadCaseStore.kt @@ -0,0 +1,109 @@ +package com.zhjt.mogo_core_function_devatools.badcase.repository.store + +import android.util.Log +import androidx.datastore.core.DataStore +import androidx.datastore.core.DataStoreFactory +import androidx.datastore.core.Serializer +import com.mogo.eagle.core.utilcode.util.Utils +import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse +import com.zhjt.mogo_core_function_devatools.badcase.api.entity.BadCaseResponse.Reason +import com.zhjt.mogo_core_function_devatools.badcase.generated.BadCauses +import com.zhjt.mogo_core_function_devatools.badcase.generated.Cause +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import java.io.File +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import kotlin.math.log + +internal object BadCaseStore { + + private val serializer = object : Serializer { + + override val defaultValue: BadCauses + get() = BadCauses.getDefaultInstance() + + override suspend fun readFrom(input: InputStream): BadCauses = suspendCancellableCoroutine { + Log.d(BadCaseManager.TAG, "--- readFrom ---") + it.invokeOnCancellation { + Thread.currentThread().interrupt() + } + try { + it.resumeWith(Result.success(BadCauses.parseFrom(input))) + } catch (t: Throwable) { + it.resumeWith(Result.failure(t)) + } + } + + override suspend fun writeTo(t: BadCauses, output: OutputStream) = suspendCancellableCoroutine { + it.invokeOnCancellation { + Thread.currentThread().interrupt() + } + try { + t.writeTo(output) + it.resumeWith(Result.success(Unit)) + } catch (t: Throwable) { + it.resumeWith(Result.failure(t)) + } + } + } + + + private val store: DataStore by lazy { + DataStoreFactory.create(serializer = serializer) { File(Utils.getApp().filesDir, "bad_cases.pb") } + } + + suspend fun updateRecords(reasons: List): BadCauses { + Log.d(BadCaseManager.TAG, "--- updateRecords ---") + val data = mutableListOf() + reasons.forEach { itx -> + data += Cause.newBuilder().let { + it.id = itx.id + it.reason = itx.reason + it.build() + } + } + return store.updateData { itx -> + itx.toBuilder().clearData().addAllData(data).build() + } + } + + suspend fun updateLastModified(timestamp: Long): BadCauses { + Log.d(BadCaseManager.TAG, "--- updateLastModified ---") + return store.updateData { itx -> + itx.toBuilder().setLastModified(timestamp).build() + } + } + + suspend fun getLastModified(): Long { + Log.d(BadCaseManager.TAG, " --- 4 ----") + return store + .data + .catch { + if (it is IOException) { + emit(BadCauses.getDefaultInstance()) + } + } + .map { + it.lastModified + }.firstOrNull() ?: 0L + + } + + @OptIn(FlowPreview::class) + suspend fun records(): List { + Log.d(BadCaseManager.TAG, "-- load cases from pb -- 1 -- ") + val causes = store.data.firstOrNull() + return causes?.dataList?.map { + Reason().also { itx -> + itx.id = it.id + itx.reason = it.reason + } + }?.fold(mutableListOf()) { acc, reason -> + acc += reason + acc + } ?: emptyList() + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-devatools/src/main/proto/badcase.proto b/core/function-impl/mogo-core-function-devatools/src/main/proto/badcase.proto new file mode 100644 index 0000000000..d76f5ad9a0 --- /dev/null +++ b/core/function-impl/mogo-core-function-devatools/src/main/proto/badcase.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "com.zhjt.mogo_core_function_devatools.badcase.generated"; +option java_outer_classname = "BadCausesProto"; + +message BadCauses { + int64 lastModified = 1; + repeated Cause data = 2 ; +} + +message Cause { + string id = 1; + string reason = 2; +} + + diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_ap_badcase_check.png b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable-xxhdpi/icon_ap_badcase_check.png similarity index 100% rename from core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_ap_badcase_check.png rename to core/function-impl/mogo-core-function-devatools/src/main/res/drawable-xxhdpi/icon_ap_badcase_check.png diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_ap_badcase_default.png b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable-xxhdpi/icon_ap_badcase_default.png similarity index 100% rename from core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_ap_badcase_default.png rename to core/function-impl/mogo-core-function-devatools/src/main/res/drawable-xxhdpi/icon_ap_badcase_default.png diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/layout_badcase_collect.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/layout/layout_badcase_collect.xml similarity index 100% rename from core/function-impl/mogo-core-function-hmi/src/main/res/layout/layout_badcase_collect.xml rename to core/function-impl/mogo-core-function-devatools/src/main/res/layout/layout_badcase_collect.xml diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/layout_badcase_item.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/layout/layout_badcase_item.xml similarity index 100% rename from core/function-impl/mogo-core-function-hmi/src/main/res/layout/layout_badcase_item.xml rename to core/function-impl/mogo-core-function-devatools/src/main/res/layout/layout_badcase_item.xml diff --git a/core/function-impl/mogo-core-function-hmi/build.gradle b/core/function-impl/mogo-core-function-hmi/build.gradle index eacd9256cd..5fba5dc7e4 100644 --- a/core/function-impl/mogo-core-function-hmi/build.gradle +++ b/core/function-impl/mogo-core-function-hmi/build.gradle @@ -38,6 +38,10 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = "1.8" + } + } dependencies { diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt index bcd0564a1d..ab6032e8cb 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt @@ -2,21 +2,14 @@ package com.mogo.eagle.core.function.hmi.ui import android.animation.Animator import android.os.Bundle -import android.os.Handler import android.text.TextUtils import android.util.Log import android.view.Gravity import android.view.View -import android.view.ViewGroup import android.view.WindowManager import android.view.animation.OvershootInterpolator -import androidx.lifecycle.Lifecycle.Event.ON_DESTROY -import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.lifecycleScope -import androidx.transition.AutoTransition -import androidx.transition.TransitionManager import com.alibaba.android.arouter.facade.annotation.Route -import com.mogo.cloud.passport.MoGoAiCloudClientConfig import com.mogo.commons.mvp.MvpFragment import com.mogo.commons.voice.AIAssist import com.mogo.eagle.core.data.autopilot.AdUpgradeStateHelper @@ -30,9 +23,9 @@ import com.mogo.eagle.core.data.notice.NoticeTrafficStylePushData import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWaringProvider import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener -import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager import com.mogo.eagle.core.function.call.check.CallerCheckManager +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager import com.mogo.eagle.core.function.call.map.CallerMapDataCollectorManager import com.mogo.eagle.core.function.call.monitor.CallerMonitorManager import com.mogo.eagle.core.function.hmi.R @@ -45,23 +38,15 @@ import com.mogo.eagle.core.function.hmi.ui.notice.NoticeBannerView import com.mogo.eagle.core.function.hmi.ui.notice.NoticeNormalBannerView import com.mogo.eagle.core.function.hmi.ui.setting.DebugSettingView import com.mogo.eagle.core.function.hmi.ui.tools.AutoPilotAndCheckView -import com.mogo.eagle.core.function.hmi.ui.tools.AutoPilotBadCaseView -import com.mogo.eagle.core.function.hmi.ui.tools.Repository -import com.mogo.eagle.core.function.hmi.ui.tools.post import com.mogo.eagle.core.function.hmi.ui.widget.V2XNotificationView -import com.mogo.eagle.core.utilcode.kotlin.lifecycleOwner -import com.mogo.eagle.core.utilcode.kotlin.onClick import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.eagle.core.utilcode.util.ThreadUtils import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.eagle.core.utilcode.util.Utils import com.mogo.module.common.enums.EventTypeEnum import kotlinx.android.synthetic.main.fragment_hmi.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED -import java.text.SimpleDateFormat import java.util.* -import java.util.concurrent.TimeUnit /** * @author xiaoyuzhou @@ -94,132 +79,8 @@ class MoGoHmiFragment : MvpFragment // 检测、自动驾驶速度设置 private var toolsViewFloat: WarningFloat.Builder? = null - @Volatile - private var autoPilotBadCaseEntrance: View? = null - - private var autoPilotBadCaseView: AutoPilotBadCaseView? = null - - private var onBadCaseShow: (() -> View)? = null - private var onBadCaseHide: (() -> Unit)? = null - private var upgradeTipsView: (() -> View)? = null - companion object { - private const val MSG_WHAT_DISMISS_BAD_CASE_ENTRY = 0x1010 - private val CASE_EXPIRE_DURATION = TimeUnit.HOURS.toMillis(4) - } - - @ExperimentalCoroutinesApi - private val channel by lazy { - Channel(UNLIMITED).also { - lifecycleScope.launchWhenResumed { - withContext(Dispatchers.Default) { - while (!it.isClosedForReceive) { - try { - val entrance = autoPilotBadCaseEntrance - val old = entrance?.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult - if (entrance == null || old == null || old.consumed) { - Log.d("QQQ", "-- step -- 1 --") - var oldT = try { - old?.timestamp?.takeIf { it.isNotBlank() }?.let { - SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time - ?: 0L - } ?: 0L - } catch (t: Throwable) { - t.printStackTrace() - 0L - } - var record: AutoPilotRecordResult? = null - var newT = try { - it.receive()?.also { record = it }?.timestamp?.takeIf { it.isNotBlank() }?.let { - SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time - ?: 0L - } ?: 0L - } catch (t: Throwable) { - t.printStackTrace() - 0L - } - - if (oldT == 0L || (newT > 0L && (newT - oldT > 0L) && (newT - oldT) < CASE_EXPIRE_DURATION)) { - Log.d("QQQ", "-- step -- 2 --") - record?.takeIf { it.key != old?.key && it.timestamp != old?.timestamp }?.also { - Log.d("QQQ", "record: [$record] is displaying and consuming ~~~") - showBadCaseEntrance(it) - } - continue - } - - while (oldT != 0L && newT != 0L && (newT - oldT) >= CASE_EXPIRE_DURATION) { - Log.d("QQQ", "record: [$record] has been discarded, because it has been timeout.") - oldT = newT - newT = try { - it.receive()?.also { - record = it - }?.timestamp?.takeIf { it.isNotBlank() }?.let { - SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time - ?: 0L - } ?: 0L - } catch (t: Throwable) { - t.printStackTrace() - 0L - } - } - record?.takeIf { it.key != old?.key && it.timestamp != old?.timestamp }?.also { - Log.d("QQQ", "record: [$record] is displaying for rest ...") - showBadCaseEntrance(it) - } - } else { - withContext(Dispatchers.Main) { - entrance.takeIf { it.visibility != View.VISIBLE }?.also { - (entrance.parent as? ViewGroup)?.let { g -> - TransitionManager.beginDelayedTransition(g, AutoTransition()) - } - it.visibility = View.VISIBLE - } - } - Log.d("QQQ", "record: [$old] hasn't been consumed~~~~") - } - } finally { - delay(1000) - } - } - } - } - } - } - - private val handler by lazy { - Handler(Handler.Callback { it -> - if (it.what == MSG_WHAT_DISMISS_BAD_CASE_ENTRY) { - val entrance = autoPilotBadCaseEntrance - if (entrance != null && entrance.visibility == View.VISIBLE) { - val record = entrance.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult - record?.consumed = true - record?.let { itx -> - lifecycleScope.launch(Dispatchers.IO) { - try { - val i = Repository.dao().deleteRecord(itx) - Log.d("QQQ", "delete result: $i") - } catch (t: Throwable) { - Log.d("QQQ", "---- delete error: ${t.message}") - } - } - } - dismissBadCaseFloatView() - if (entrance.visibility != View.GONE) { - (entrance.parent as? ViewGroup)?.let { g -> - TransitionManager.beginDelayedTransition(g, AutoTransition()) - } - entrance.visibility = View.GONE - onBadCaseHide?.invoke() - } - } - return@Callback true - } - return@Callback false - }) - } - override fun vipIdentification(visible: Boolean) { ThreadUtils.runOnUiThread { Logger.d(TAG, "vipIdentification") @@ -260,18 +121,6 @@ class MoGoHmiFragment : MvpFragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) CallerAutopilotIdentifyListenerManager.addListener(TAG, this) - lifecycleScope.launchWhenResumed { - withContext(Dispatchers.IO) { - val dao = Repository.dao() - try { - dao.getAllUnConsumedRecords()?.forEach { - channel.send(it) - } - } catch (t: Throwable) { - t.printStackTrace() - } - } - } /*// TODO 这里后面需要改成独立进程通讯后台获取YUV view.postDelayed({ @@ -282,21 +131,8 @@ class MoGoHmiFragment : MvpFragment @OptIn(ExperimentalCoroutinesApi::class) override fun onAutopilotRecordResult(record: AutoPilotRecordResult?) { record ?: return - Log.d("QQQ", "onAutopilotRecordResult:$record") - if (record.type == 1 && record.stat == 100) { - lifecycleScope.launchWhenResumed { - withContext(Dispatchers.IO) { - val dao = Repository.dao() - try { - dao.insertRecord(record) - } catch (t: Throwable) { - t.printStackTrace() - } - record.also { - channel.send(it) - } - } - } + if (HmiBuildConfig.isShowBadCaseView && record.type == 1 && record.stat == 100) { + CallerDevaToolsManager.onReceiveBadCaseRecord(record) } if (record.type == 2 && (record.stat == 101 || record.stat == 100)) { CallerMapDataCollectorManager.finish(record.id, record.stat, "", record.fileName ?: "", record.note ?: "") @@ -308,61 +144,6 @@ class MoGoHmiFragment : MvpFragment CallerAutopilotIdentifyListenerManager.removeListener(TAG) } - private fun showBadCaseEntrance(record: AutoPilotRecordResult) { - Log.d("QQQ", "showBadCaseEntrance:$record") - lifecycleScope.launch { - if (HmiBuildConfig.isShowBadCaseView) { - if (vsBadCaseToolsView?.parent != null) { - val inflateView = vsBadCaseToolsView.inflate() - autoPilotBadCaseEntrance = inflateView - } - } - val entrance = autoPilotBadCaseEntrance - Log.d("QQQ", "show --- 1 ----") - if (entrance != null) { - if (entrance.visibility != View.VISIBLE) { - (entrance.parent as? ViewGroup)?.let { g -> - TransitionManager.beginDelayedTransition(g, AutoTransition()) - } - entrance.visibility = View.VISIBLE - } - entrance.setTag(R.id.autopilot_badcase_record, record) - entrance.onClick { - showBadCasesFloat { - if (it.visibility != View.GONE) { - (entrance.parent as? ViewGroup)?.let { g -> - TransitionManager.beginDelayedTransition(g, AutoTransition()) - } - it.visibility = View.GONE - onBadCaseHide?.invoke() - } - } - } - dismissBadCaseEntryAfterSomeTime() - } else { - val view = onBadCaseShow?.invoke() - if (view != null) { - view.lifecycleOwner.lifecycle.addObserver(badCaseEntranceObserver) - view.visibility = View.GONE - autoPilotBadCaseEntrance = view - showBadCaseEntrance(record) - } - } - } - } - - private val badCaseEntranceObserver = LifecycleEventObserver { _, event -> - if (event == ON_DESTROY) { - onBadCaseShow = null - onBadCaseHide = null - autoPilotBadCaseEntrance = null - } - } - - override fun registerBadCaseCallback(onShow: () -> View, onHide: (() -> Unit)?) { - onBadCaseShow = onShow - onBadCaseHide = onHide - } /** *注册工控机升级提示圆点View的回调 @@ -391,116 +172,6 @@ class MoGoHmiFragment : MvpFragment } } - private fun showBadCasesFloat(dismiss: (() -> Unit)?) { - Log.d("QQQ", "showBadCaseToolsFloat") - context?.let { it -> - if (autoPilotToolsFloat == null) { - if (autoPilotBadCaseView == null) { - autoPilotBadCaseView = AutoPilotBadCaseView(it).also { itx -> - val record = - autoPilotBadCaseEntrance?.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult - itx.tag = record - itx.onDismiss { - dismissBadCaseFloatView() - } - itx.onSelect { - lifecycleScope.launch { - try { - val params = mutableMapOf() - autoPilotBadCaseEntrance?.apply { - params["carLicense"] = - MoGoAiCloudClientConfig.getInstance().sn - params["filename"] = record?.fileName ?: "" - params["filesize"] = record?.total.toString() - params["key"] = record?.key ?: "" - params["reason"] = it.reason ?: "" - params["duration"] = record?.duration?.toInt()?.toString() - ?: "" - params["timestamp"] = record?.timestamp ?: "" - } - val response = post(params) - if (response.isSuccessful) { - val body = response.body() - if (body == null) { - Log.e("QQQ", "返回的body是空的~~~") - return@launch - } - if (body.code == 200) { - Logger.i(TAG, "ok:${body}") - dismissBadCaseFloatView() - dismiss?.invoke() - CallerAutoPilotManager.recordCause( - record?.key, - record?.fileName, - it.id, it.reason) - ToastUtils.showShort("接管反馈成功~") - record?.also { - it.consumed = true - withContext(Dispatchers.IO) { - try { - Repository.dao().deleteRecord(record) - } catch (t: Throwable) { - Log.d("QQQ", "---- delete error 2: ${t.message}") - } - } - } - return@launch - } - Log.e("QQQ", "fail:${body}") - } - } catch (t: Throwable) { - t.printStackTrace() - ToastUtils.showShort("网络请求失败,请尝试联网~") - Log.e("QQQ", "exception:${t.message}") - } - } - } - } - } - autoPilotToolsFloat = WarningFloat.with(it) - .setTag("BadCaseCollectFloat") - .setLayout(autoPilotBadCaseView!!) - .setSidePattern(SidePattern.LEFT) - .setGravity(Gravity.LEFT, offsetY = 72) - .setImmersionStatusBar(true) - .setAnimator(object : DefaultAnimator() { - override fun enterAnim( - view: View, - params: WindowManager.LayoutParams, - windowManager: WindowManager, - sidePattern: SidePattern - ): Animator? = - super.enterAnim(view, params, windowManager, sidePattern) - ?.apply { - interpolator = OvershootInterpolator() - } - - override fun exitAnim( - view: View, - params: WindowManager.LayoutParams, - windowManager: WindowManager, - sidePattern: SidePattern - ): Animator? = - super.exitAnim(view, params, windowManager, sidePattern) - ?.setDuration(200) - }) - .addWarningStatusListener(object : IMoGoWarningStatusListener { - override fun onDismiss() { - autoPilotToolsFloat = null - autoPilotBadCaseView = null - } - }) - .show() - } else { - autoPilotToolsFloat?.show() - } - } - } - - private fun dismissBadCaseEntryAfterSomeTime() { - handler.removeMessages(MSG_WHAT_DISMISS_BAD_CASE_ENTRY) - handler.sendEmptyMessageDelayed(MSG_WHAT_DISMISS_BAD_CASE_ENTRY, CASE_EXPIRE_DURATION) - } private fun showToolsFloat() { Logger.d(TAG, "showToolsFloat") @@ -597,6 +268,10 @@ class MoGoHmiFragment : MvpFragment } else { setToolsViewVisibility(View.GONE) } + + if (HmiBuildConfig.isShowBadCaseView) { + CallerDevaToolsManager.initBadCase(vsBadCaseToolsView) + } } override fun getLayoutId(): Int { @@ -1125,18 +800,54 @@ class MoGoHmiFragment : MvpFragment } - private fun dismissBadCaseFloatView() { - autoPilotToolsFloat?.let { - WarningFloat.dismiss(it.config.floatTag, false) - autoPilotToolsFloat = null - autoPilotBadCaseView = null + override fun showBadCaseFloat(tag: String, floatView: View): () -> Unit { + WarningFloat.with(context ?: Utils.getApp()) + .setTag(tag) + .setLayout(floatView) + .setSidePattern(SidePattern.LEFT) + .setGravity(Gravity.START, offsetY = 72) + .setImmersionStatusBar(true) + .setAnimator(object : DefaultAnimator() { + override fun enterAnim( + view: View, + params: WindowManager.LayoutParams, + windowManager: WindowManager, + sidePattern: SidePattern + ): Animator? = + super.enterAnim(view, params, windowManager, sidePattern) + ?.apply { + interpolator = OvershootInterpolator() + } + + override fun exitAnim( + view: View, + params: WindowManager.LayoutParams, + windowManager: WindowManager, + sidePattern: SidePattern + ): Animator? = + super.exitAnim(view, params, windowManager, sidePattern) + ?.setDuration(200) + }) + .addWarningStatusListener(object : IMoGoWarningStatusListener { + override fun onDismiss() { + autoPilotToolsFloat = null + } + }) + .also { + autoPilotToolsFloat = it + } + .show() + return { + autoPilotToolsFloat?.let { + WarningFloat.dismiss(it.config.floatTag, false) + autoPilotToolsFloat = null + } } } override fun onDestroy() { super.onDestroy() Log.d(TAG, "onDestroy") - handler.removeCallbacksAndMessages(null) } diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/tools/AutoPilotBadCase.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/tools/AutoPilotBadCase.kt deleted file mode 100644 index 28e6ce710c..0000000000 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/tools/AutoPilotBadCase.kt +++ /dev/null @@ -1,404 +0,0 @@ -package com.mogo.eagle.core.function.hmi.ui.tools - -import android.annotation.SuppressLint -import android.content.Context -import android.content.Context.MODE_PRIVATE -import android.graphics.Color -import android.graphics.drawable.ColorDrawable -import android.graphics.drawable.GradientDrawable -import android.graphics.drawable.StateListDrawable -import android.os.Handler -import android.util.AttributeSet -import android.util.StateSet -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.annotation.Keep -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.room.* -import com.google.gson.annotations.Expose -import com.mogo.commons.debug.DebugConfig -import com.mogo.commons.debug.DebugConfig.getNetMode -import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult -import com.mogo.eagle.core.function.hmi.R -import com.mogo.eagle.core.function.hmi.ui.tools.BadCaseEntity.Reason -import com.mogo.eagle.core.network.MoGoRetrofitFactory -import com.mogo.eagle.core.network.utils.GsonUtil -import com.mogo.eagle.core.utilcode.kotlin.* -import com.mogo.eagle.core.utilcode.util.ThreadUtils -import com.mogo.eagle.core.utilcode.util.Utils -import kotlinx.android.synthetic.main.layout_badcase_collect.view.* -import kotlinx.coroutines.* -import kotlinx.coroutines.android.asCoroutineDispatcher -import retrofit2.Response -import retrofit2.http.FieldMap -import retrofit2.http.FormUrlEncoded -import retrofit2.http.GET -import retrofit2.http.POST -import java.text.SimpleDateFormat -import java.util.* -import kotlin.Result.Companion.failure -import kotlin.Result.Companion.success - -private typealias OnDismissCallback = () -> Unit -private typealias OnSelectCallback = (Reason) -> Unit - - -object Repository { - - fun dao(): Dao { - return Room.databaseBuilder(Utils.getApp(), RecordDb::class.java, "bad-cases").build().dao() - } - - @Database(entities = [ - AutoPilotRecordResult::class - ], - version = 1, - exportSchema = false) - abstract class RecordDb : RoomDatabase() { - abstract fun dao(): Dao - } - - @androidx.room.Dao - interface Dao { - - @Transaction - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertRecord(record: AutoPilotRecordResult): Long - - @Transaction - @Delete - suspend fun deleteRecord(record: AutoPilotRecordResult): Int - - @Query("SELECT * FROM record ORDER BY timestamp ASC") - suspend fun getAllUnConsumedRecords(): List? - } -} - -interface BadCaseApi { - - @FormUrlEncoded - @POST("/yycp-vehicle-management-service/tool/badcase/add") - suspend fun post(@FieldMap map: Map): Response - - @GET("/yycp-vehicle-management-service/tool/badcase/reasons") - suspend fun get(): Response -} - -@Keep -class BadCaseEntity { - var code: Int = -1 - var data: List? = null - var msg: String? = null - var success: Boolean = false - var total: Int = -1 - - @Expose(serialize = false, deserialize = false) - var isBuildIn: Boolean = false - - @Keep - class Reason { - var id: String? = null - var reason: String? = null - - /** - * 业务字段,不参与序列化和反序列化 - */ - @Expose(deserialize = false, serialize = false) - var isChecked: Boolean = false - } -} - -@Keep -class PostResult { - var code: Int = -1 - var msg: String? = null - var data: Array? = null - var success: Boolean = false - - override fun toString(): String { - return "Result(code=$code, msg=$msg, data=${data?.contentToString()}, success=$success)" - } -} - -private fun getHost(): String = if (getNetMode() == DebugConfig.NET_MODE_RELEASE) "http://dzt.zhidaozhixing.com" else "http://front.zdjs-private-test.myghost.zhidaoauto.com" - -internal suspend fun post(map: Map): Response { - return MoGoRetrofitFactory.getInstance(getHost()).create(BadCaseApi::class.java).post(map) -} - -private suspend fun get(): Response? { - return try { MoGoRetrofitFactory.getInstance(getHost()).create(BadCaseApi::class.java).get() } catch (t: Throwable) { t.printStackTrace(); null} -} - -private suspend fun updateCache(entity: BadCaseEntity) = suspendCancellableCoroutine { - try { - val future = ThreadUtils.getIoPool().submit { - try { - val gson = GsonUtil.jsonFromObject(entity) - Sp.saveBody(gson) - it.resumeWith(success(Unit)) - } catch (t: Throwable) { - it.resumeWith(failure(t)) - } - } - it.invokeOnCancellation { - future.cancel(true) - } - } catch (e: Throwable) { - it.resumeWith(failure(e)) - } -} - -private suspend fun getCache(): BadCaseEntity? = suspendCancellableCoroutine { - try { - val body = Sp.getBody() - if (body != null && body.isNotEmpty()) { - val future = ThreadUtils.getIoPool().submit { - try { - val result = GsonUtil.objectFromJson(body, BadCaseEntity::class.java) - it.resumeWith(success(result)) - } catch (t: Throwable) { - it.resumeWith(success(null)) - } - } - it.invokeOnCancellation { - future.cancel(true) - } - } - } catch (t: Throwable) { - it.resumeWith(success(null)) - } -} - -private fun getBuildIn(): BadCaseEntity = BadCaseEntity().also { itx -> - val data = mutableListOf() - data += Reason().also { - it.id = "1" - it.reason = "变道有干扰" - } - data += Reason().also { - it.id = "2" - it.reason = "遇红绿灯未停车" - } - data += Reason().also { - it.id = "3" - it.reason = "遇障碍物未停车" - } - data += Reason().also { - it.id = "4" - it.reason = "无法绕行" - } - data += Reason().also { - it.id = "5" - it.reason = "画龙" - } - data += Reason().also { - it.id = "6" - it.reason = "转弯过于靠近路侧" - } - data += Reason().also { - it.id = "7" - it.reason = "无故退出自动驾驶" - } - data += Reason().also { - it.id = "8" - it.reason = "其它" - } - itx.data = data - itx.isBuildIn = true -} - -internal object Sp { - - private val sp by lazy { - Utils.getApp().getSharedPreferences("bad_case_prefs", MODE_PRIVATE) - } - - @SuppressLint("ApplySharedPref") - fun saveBody(body: String) { - sp.edit().putString("prefs", body).commit() - } - - fun getBody(): String? { - return sp.getString("prefs", null) - } -} - -class AutoPilotBadCaseView: ConstraintLayout { - - private var dismiss: OnDismissCallback? = null - private var select: OnSelectCallback? = null - private var cases: List? = null - - private var selectCase: Reason? = null - - private val scope = CoroutineScope(Handler().asCoroutineDispatcher() + SupervisorJob()) - - constructor(context: Context) : this(context, null) - - constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - LayoutInflater.from(context).inflate(R.layout.layout_badcase_collect, this, true) - background = ColorDrawable(Color.parseColor("#F0151D41")) - isClickable = true - layoutParams = ViewGroup.LayoutParams(960.toPixels().toInt(), 1528.toPixels().toInt()) - close?.onClick { - dismiss?.invoke() - } - cancel?.also { - it.background = shape(solid = Color.parseColor("#3B4577"), radius = 16) - it.onClick { - dismiss?.invoke() - } - } - ok?.also { - val enabled = gradient(radius = 16.toPixels().toInt(), orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252)) - val disabled = gradient(radius = 16.toPixels().toInt(), orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(24, 71, 129), endColor = Color.rgb(21, 46, 129)) - it.background = object : StateListDrawable() {}.also { itx -> - itx.addState(intArrayOf(android.R.attr.state_enabled), enabled) - itx.addState(StateSet.WILD_CARD, disabled) - } - it.onClick { - val case = selectCase - if (case != null) { - select?.invoke(case) - } - } - } - } - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - val adapter = rv_take_over?.adapter - if (adapter != null && adapter.itemCount > 0) { - return - } - time_of_take_over?.text = "接管时间: ${(tag as? AutoPilotRecordResult)?.timestamp?.let { - try { - SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.let { itx -> - SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.getDefault()).format(itx) - } - } catch (e: Throwable) { - null - } ?: SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.getDefault()).format(Date())}}" - - scope.launch { - showLoading() - try { - get()?.takeIf { it.isSuccessful && it.body() != null && it.body()?.code == 200 }?.let { - val entity = it.body()!! - try { - updateCache(entity) - } catch (t: Throwable) { - t.printStackTrace() - } finally { - updateBadCaseList(entity) - } - } - ?: - getCache()?.also { - updateBadCaseList(it) - } - ?: - updateBadCaseList(getBuildIn()) - } finally { - hideLoading() - } - } - } - - private fun updateBadCaseList(body: BadCaseEntity) { - cases = body.data - rv_take_over?.let { - it.layoutManager = LinearLayoutManager(it.context, LinearLayoutManager.VERTICAL, false) - it.adapter = object : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BadCaseViewHolder = BadCaseViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_badcase_item, parent, false)) - override fun onBindViewHolder(holder: BadCaseViewHolder, position: Int) { - val cases = cases - if (cases == null || cases.isEmpty()) { - return - } - if (position >= cases.size) { - return - } - val case = cases[position] - holder.bindData(case) - } - override fun getItemCount(): Int = cases?.size ?: 0 - } - } - } - - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - scope.cancel("Cancel all for AutoPilotBadCaseView#onDetachedFromWindow") - } - - private fun showLoading() { - pb?.let { - it.visibility = View.VISIBLE - } - } - - private fun hideLoading() { - pb?.let { - it.visibility = View.INVISIBLE - } - } - - private inner class BadCaseViewHolder(item: View) : RecyclerView.ViewHolder(item) { - - private val check: ImageView = item.findViewById(R.id.check) - private val reason: TextView = item.findViewById(R.id.reason) - - init { - check.background = StateListDrawable().also { - it.addState(intArrayOf(android.R.attr.state_selected), ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_check)) - it.addState(StateSet.WILD_CARD, ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_default)) - } - } - - @SuppressLint("NotifyDataSetChanged") - fun bindData(case: Reason) { - check.isSelected = case.isChecked - reason.text = case.reason ?: "" - if (case.isChecked) { - ok?.isSelected = true - } - itemView.onClick { - case.isChecked = !case.isChecked - selectCase = case - cancelOtherChecked(case) - ok?.isEnabled = hasCheckedItem() - rv_take_over?.adapter?.notifyDataSetChanged() - } - } - - private fun hasCheckedItem(): Boolean = cases?.find { it.isChecked } != null - - private fun cancelOtherChecked(case: Reason) { - val cases = cases - if (cases == null || cases.isEmpty()) { - return - } - cases.filterNot { it == case }.forEach { - it.isChecked = false - } - } - } - - fun onDismiss(dismiss:() -> Unit) { - this.dismiss = dismiss - } - - fun onSelect(cb:(Reason) -> Unit) { - this.select = cb - } -} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/fragment_hmi.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/fragment_hmi.xml index fbbc1af7f3..e88f74560e 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/fragment_hmi.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/fragment_hmi.xml @@ -98,14 +98,14 @@ app:layout_constraintStart_toEndOf="@+id/viewPerspectiveSwitch" app:layout_goneMarginStart="50px" /> - diff --git a/core/mogo-core-function-api/build.gradle b/core/mogo-core-function-api/build.gradle index a9303fa9ca..56faa70676 100644 --- a/core/mogo-core-function-api/build.gradle +++ b/core/mogo-core-function-api/build.gradle @@ -44,13 +44,16 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation rootProject.ext.dependencies.kotlinstdlibjdk7 implementation rootProject.ext.dependencies.arouter + implementation project(path: ':libraries:mogo-adas') kapt rootProject.ext.dependencies.aroutercompiler implementation rootProject.ext.dependencies.coroutinescore implementation rootProject.ext.dependencies.coroutinesandroid if (Boolean.valueOf(USE_MAVEN_PACKAGE)) { implementation rootProject.ext.dependencies.mogo_core_data + compileOnly rootProject.ext.dependencies.adasHigh } else { implementation project(':core:mogo-core-data') + compileOnly project(':libraries:mogo-adas') } } diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/IDevaToolsProvider.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/IDevaToolsProvider.kt index 18d9f6b400..c14aa1283f 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/IDevaToolsProvider.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/IDevaToolsProvider.kt @@ -1,5 +1,7 @@ package com.mogo.eagle.core.function.api.devatools +import android.view.View +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult import com.mogo.eagle.core.data.chain.ChainLogParam import com.mogo.eagle.core.function.api.base.IMoGoFunctionServerProvider @@ -18,4 +20,17 @@ interface IDevaToolsProvider : IMoGoFunctionServerProvider { fun refreshTraceInfo(map: HashMap) + /** + * 初始化BadCase入口 + * @param view: 展示入口 + * @param onShow: BadCase入口展示时回调 + * @param onHide: BadCase入口隐藏时回调 + * 注: 此方法必须在[recoverBadCase]和[onReceiveBadCaseRecord]之前调用 + */ + fun initBadCase(view: View, onShow: (() -> Unit)? = null, onHide: (() -> Unit)? = null) + + /** + * 当工控机回调时调用 + */ + fun onReceiveBadCaseRecord(record: AutoPilotRecordResult) } \ No newline at end of file diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/hmi/warning/IMoGoWaringProvider.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/hmi/warning/IMoGoWaringProvider.kt index 3f0f3304a4..343015d06f 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/hmi/warning/IMoGoWaringProvider.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/hmi/warning/IMoGoWaringProvider.kt @@ -186,13 +186,6 @@ interface IMoGoWaringProvider { fun showAdUpgradeStatus(upgradeMode : Int,downloadStatus : Int,currentProgress : Int,totalProgress : Int ,downloadVersion : String,upgradeStatus : Int) - /** - * 注册badcase入口展示和隐藏的回调 - * 当[onShow]被调用时,调用[showBadCaseEntrance] - * [onHide]回调不用关心,可以不注册 - */ - fun registerBadCaseCallback(onShow:() -> View, onHide: (() -> Unit)?) - /** *注册工控机升级提示圆点View的回调 * @param 提示圆点View @@ -205,4 +198,11 @@ interface IMoGoWaringProvider { * @param msg */ fun showDockerRebootResult(code: Int,msg: String) + + /** + * @param floatView: 要展示的View + * @param tag: 唯一标识 + * @return 触发消失时回调 + */ + fun showBadCaseFloat(tag: String = "BadCaseFloat", floatView: View): () -> Unit } \ No newline at end of file diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/devatools/CallerDevaToolsManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/devatools/CallerDevaToolsManager.kt index 115f9ac4cf..0b8b83a655 100644 --- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/devatools/CallerDevaToolsManager.kt +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/devatools/CallerDevaToolsManager.kt @@ -1,5 +1,7 @@ package com.mogo.eagle.core.function.call.devatools +import android.view.View +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult import com.mogo.eagle.core.data.chain.ChainLogParam import com.mogo.eagle.core.data.constants.MogoServicePaths import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider @@ -7,7 +9,7 @@ import com.mogo.eagle.core.function.call.base.CallerBase object CallerDevaToolsManager { - private val devaToolsProviderApi: IDevaToolsProvider + private val devaToolsProviderApi: IDevaToolsProvider? get() = CallerBase.getApiInstance( IDevaToolsProvider::class.java, MogoServicePaths.PATH_DEVA_TOOLS @@ -17,7 +19,7 @@ object CallerDevaToolsManager { * 开始抓取全量日志 */ fun startCatchLog() { - devaToolsProviderApi.startLogCatch() + devaToolsProviderApi?.startLogCatch() } /** @@ -25,27 +27,41 @@ object CallerDevaToolsManager { * duration 分钟数 */ fun startCatchLog(duration: Int) { - devaToolsProviderApi.startLogCatch(duration) + devaToolsProviderApi?.startLogCatch(duration) } /** * 停止抓取全量日志 */ fun stopCatchLog() { - devaToolsProviderApi.stopLogCatch() + devaToolsProviderApi?.stopLogCatch() } /** * 更新链路节点信息,是否写入 */ fun refreshTraceInfo(map: HashMap) { - devaToolsProviderApi.refreshTraceInfo(map) + devaToolsProviderApi?.refreshTraceInfo(map) } /** * 获取链路节点信息 */ fun getTraceInfo(): HashMap { - return devaToolsProviderApi.getTraceInfo() + return devaToolsProviderApi?.getTraceInfo() ?: HashMap() + } + + /** + * 初始化BadCase相关配置 + */ + fun initBadCase(view: View, onShow: (() -> Unit)? = null, onHide: (() -> Unit)? = null) { + devaToolsProviderApi?.initBadCase(view, onShow, onHide) + } + + /** + * 收到工控机回调时触发 + */ + fun onReceiveBadCaseRecord(record: AutoPilotRecordResult) { + devaToolsProviderApi?.onReceiveBadCaseRecord(record) } } \ No newline at end of file diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/hmi/CallerHmiManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/hmi/CallerHmiManager.kt index a7f5173590..14d166e65f 100644 --- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/hmi/CallerHmiManager.kt +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/hmi/CallerHmiManager.kt @@ -264,15 +264,6 @@ object CallerHmiManager : CallerBase() { waringProviderApi?.showAdUpgradeStatus(upgradeMode,downloadStatus, currentProgress, totalProgress, downloadVersion, upgradeStatus) } - /** - * 注册badcase入口展示和隐藏的回调 - * 当[onShow]被调用时, 表示达到展示条件,返回展示的入口控件 - * [onHide]回调不用关心,可以不注册 - */ - fun registerBadCaseCallback(onShow:() -> View, onHide: (() -> Unit)?) { - waringProviderApi?.registerBadCaseCallback(onShow, onHide) - } - /** *注册工控机升级提示圆点View的回调 * @param 提示圆点View @@ -290,4 +281,10 @@ object CallerHmiManager : CallerBase() { waringProviderApi?.showDockerRebootResult(code, msg) } + /** + * 展示BadCase浮层 + */ + fun showBadCaseFloat(tag: String = "BadCaseFloat", floatView: View): (() -> Unit)? { + return waringProviderApi?.showBadCaseFloat(tag, floatView) + } } \ No newline at end of file