diff --git a/OCH/mogo-och-taxi/build.gradle b/OCH/mogo-och-taxi/build.gradle index 6fb54ece1f..b5779fdb5a 100644 --- a/OCH/mogo-och-taxi/build.gradle +++ b/OCH/mogo-och-taxi/build.gradle @@ -63,13 +63,15 @@ dependencies { implementation rootProject.ext.dependencies.mogo_core_data implementation rootProject.ext.dependencies.mogo_core_function_call implementation rootProject.ext.dependencies.mogo_core_function_smp + implementation rootProject.ext.dependencies.mogo_core_function_v2x }else { implementation project(":core:mogo-core-utils") implementation project(":foudations:mogo-commons") implementation project(':modules:mogo-module-common') implementation project(':core:mogo-core-data') implementation project(':core:mogo-core-function-call') - api project(':core:function-impl:mogo-core-function-smp') + implementation project(':core:function-impl:mogo-core-function-smp') + implementation project(':core:function-impl:mogo-core-function-v2x') } } diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/MogoOCHTaxi.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/MogoOCHTaxi.java index 5d45d9ce23..364e258dc1 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/MogoOCHTaxi.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/MogoOCHTaxi.java @@ -6,13 +6,13 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import com.alibaba.android.arouter.facade.annotation.Route; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; import com.mogo.module.common.MogoApisHandler; import com.mogo.och.taxi.constant.OCHTaxiConst; import com.mogo.och.taxi.ui.OCHTaxiFragment; import com.mogo.service.statusmanager.IMogoStatusChangedListener; import com.mogo.service.statusmanager.StatusDescriptor; -import com.mogo.utils.UiThreadHandler; -import com.mogo.utils.logger.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/OCHTaxiOverlayManager.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/OCHTaxiOverlayManager.java index bd59802434..95988abf48 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/OCHTaxiOverlayManager.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/OCHTaxiOverlayManager.java @@ -4,13 +4,12 @@ import android.content.Context; import com.mogo.eagle.core.data.map.MogoLatLng; import com.mogo.eagle.core.data.map.MogoLocation; +import com.mogo.eagle.core.function.v2x.events.utils.LocationUtils; +import com.mogo.eagle.core.utilcode.util.ColorUtils; import com.mogo.map.overlay.IMogoOverlayManager; import com.mogo.map.overlay.IMogoPolyline; import com.mogo.map.overlay.MogoPolylineOptions; import com.mogo.module.common.MogoApisHandler; -import com.mogo.module.common.utils.LocationUtils; -import com.mogo.utils.ColorUtils; - import java.util.ArrayList; import java.util.List; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/MogoOCHTaxiModelNew.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/MogoOCHTaxiModelNew.java index e08b00229d..18d4ecd99d 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/MogoOCHTaxiModelNew.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/MogoOCHTaxiModelNew.java @@ -24,7 +24,10 @@ import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager; import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager; import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotPlanningListenerManager; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr; import com.mogo.eagle.core.utilcode.mogo.toast.TipToast; +import com.mogo.eagle.core.utilcode.util.NetworkUtils; import com.mogo.map.navi.IMogoCarLocationChangedListener2; import com.mogo.module.common.MogoApisHandler; import com.mogo.och.taxi.callback.IOCHTaxiAutopilotPlanningCallback; @@ -53,9 +56,6 @@ import com.mogo.service.cloud.socket.IMogoLifecycleListener; import com.mogo.service.intent.IMogoIntentListener; import com.mogo.service.statusmanager.IMogoStatusChangedListener; import com.mogo.service.statusmanager.StatusDescriptor; -import com.mogo.utils.NetworkUtils; -import com.mogo.utils.logger.Logger; -import com.mogo.utils.storage.SharedPrefsMgr; import org.jetbrains.annotations.NotNull; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/NaviToDestinationModel.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/NaviToDestinationModel.java index 60d80526a6..1c7a0f692c 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/NaviToDestinationModel.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/NaviToDestinationModel.java @@ -24,9 +24,9 @@ import com.amap.api.navi.model.NaviInfo; import com.amap.api.navi.model.NaviLatLng; import com.autonavi.tbt.TrafficFacilityInfo; import com.mogo.eagle.core.utilcode.mogo.toast.TipToast; +import com.mogo.eagle.core.utilcode.util.NetworkUtils; import com.mogo.och.taxi.callback.IOCHTaxiNaviChangedCallback; import com.mogo.och.taxi.utils.PermissionUtil; -import com.mogo.utils.NetworkUtils; import java.util.ArrayList; import java.util.List; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/OCHTaxiModelLoopManager.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/OCHTaxiModelLoopManager.java index 6ef47a2125..f0bf44761a 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/OCHTaxiModelLoopManager.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/OCHTaxiModelLoopManager.java @@ -1,7 +1,7 @@ package com.mogo.och.taxi.model; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.och.taxi.constant.OCHTaxiConst; -import com.mogo.utils.logger.Logger; import java.util.concurrent.TimeUnit; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/network/OCHTaxiServiceManagerNew.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/network/OCHTaxiServiceManagerNew.java index 1f18f31792..8181065300 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/network/OCHTaxiServiceManagerNew.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/network/OCHTaxiServiceManagerNew.java @@ -6,6 +6,7 @@ import com.mogo.cloud.passport.MoGoAiCloudClientConfig; import com.mogo.eagle.core.data.BaseData; import com.mogo.eagle.core.network.RequestOptions; import com.mogo.eagle.core.network.SubscribeImpl; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.module.common.MogoApisHandler; import com.mogo.och.taxi.BuildConfig; import com.mogo.och.taxi.bean.CarHeartbeatReqBean; @@ -25,7 +26,6 @@ import com.mogo.och.taxi.bean.OrdersInServiceQueryRespBean; import com.mogo.och.taxi.bean.OrdersListQueryReqBean; import com.mogo.och.taxi.bean.OrdersListQueryRespBean; import com.mogo.och.taxi.bean.OrdersNewBookingQueryRespBean; -import com.mogo.utils.logger.Logger; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/OCHTaxiPresenter.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/OCHTaxiPresenter.java index 37b41c73e1..8a1242200d 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/OCHTaxiPresenter.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/OCHTaxiPresenter.java @@ -13,6 +13,8 @@ import com.mogo.commons.AbsMogoApplication; import com.mogo.commons.mvp.Presenter; import com.mogo.eagle.core.data.autopilot.AutopilotRouteInfo; import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; import com.mogo.och.taxi.callback.IOCHTaxiAutopilotPlanningCallback; import com.mogo.och.taxi.constant.OrderStatusEnum; import com.mogo.och.taxi.bean.OrderQueryRespBean; @@ -23,8 +25,6 @@ import com.mogo.och.taxi.callback.IOCHTaxiControllerStatusCallback; import com.mogo.och.taxi.callback.IOCHTaxiOrderStatusCallback; import com.mogo.och.taxi.model.MogoOCHTaxiModelNew; import com.mogo.och.taxi.ui.OCHTaxiFragment; -import com.mogo.utils.UiThreadHandler; -import com.mogo.utils.logger.Logger; import org.jetbrains.annotations.NotNull; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/BaseOchTaxiTabFragment.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/BaseOchTaxiTabFragment.java index 29213b6379..8055221bcd 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/BaseOchTaxiTabFragment.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/BaseOchTaxiTabFragment.java @@ -29,14 +29,14 @@ import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager; import com.mogo.eagle.core.function.call.hmi.CallerHmiManager; import com.mogo.eagle.core.function.call.map.CallerSmpManager; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.map.listener.IMogoMapListener; import com.mogo.map.uicontroller.VisualAngleMode; import com.mogo.module.common.MogoApisHandler; import com.mogo.module.common.constants.DataTypes; import com.mogo.module.common.view.OnPreventFastClickListener; import com.mogo.och.taxi.R; -import com.mogo.och.taxi.constant.OrderStatusEnum; -import com.mogo.utils.logger.Logger; + /** * 网约车基础Fragment,主要负责布局通用界面,处理站点面板和通话面板互斥情况 diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiBeingServerdOrdersFragment.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiBeingServerdOrdersFragment.java index e22499f2c0..28a0004ed0 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiBeingServerdOrdersFragment.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiBeingServerdOrdersFragment.java @@ -18,7 +18,10 @@ import androidx.constraintlayout.widget.ConstraintLayout; import com.amap.api.navi.model.NaviLatLng; import com.mogo.commons.debug.DebugConfig; import com.mogo.commons.voice.AIAssist; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.eagle.core.utilcode.mogo.toast.TipToast; +import com.mogo.eagle.core.utilcode.util.DateTimeUtils; +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; import com.mogo.och.taxi.callback.IOCHTaxiNaviChangedCallback; import com.mogo.och.taxi.constant.OrderStatusEnum; import com.mogo.och.taxi.R; @@ -27,9 +30,6 @@ import com.mogo.och.taxi.bean.OrderQueryRouteInfoRespBean; import com.mogo.och.taxi.model.MogoOCHTaxiModelNew; import com.mogo.och.taxi.model.NaviToDestinationModel; import com.mogo.och.taxi.utils.OchTaxiUtils; -import com.mogo.utils.DateTimeUtils; -import com.mogo.utils.UiThreadHandler; -import com.mogo.utils.logger.Logger; import java.text.DecimalFormat; import java.util.Calendar; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiFragment.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiFragment.java index 89844e8d71..7746b2e407 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiFragment.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiFragment.java @@ -11,6 +11,7 @@ import androidx.fragment.app.FragmentTransaction; import com.mogo.commons.debug.DebugConfig; import com.mogo.eagle.core.data.autopilot.AutopilotRouteInfo; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.module.common.MogoApisHandler; import com.mogo.och.taxi.R; import com.mogo.och.taxi.constant.OrderStatusEnum; @@ -19,7 +20,6 @@ import com.mogo.och.taxi.bean.OrderQueryRouteInfoRespBean; import com.mogo.och.taxi.model.MogoOCHTaxiModelNew; import com.mogo.och.taxi.presenter.OCHTaxiPresenter; import com.mogo.och.taxi.utils.PinYinUtil; -import com.mogo.utils.logger.Logger; import java.lang.ref.WeakReference; import java.util.List; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiGrabOrderFragment.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiGrabOrderFragment.java index 3047133243..f23cf81700 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiGrabOrderFragment.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiGrabOrderFragment.java @@ -9,10 +9,11 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; + +import com.mogo.eagle.core.utilcode.util.UiThreadHandler; import com.mogo.och.taxi.R; import com.mogo.och.taxi.bean.OrderQueryRespBean; import com.mogo.och.taxi.utils.OchTaxiUtils; -import com.mogo.utils.UiThreadHandler; import java.util.Calendar; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiServerOrdersFragment.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiServerOrdersFragment.java index d2aed0554e..70440978b4 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiServerOrdersFragment.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/OCHTaxiServerOrdersFragment.java @@ -18,10 +18,10 @@ import androidx.fragment.app.FragmentTransaction; import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; import com.mogo.och.taxi.R; import com.mogo.och.taxi.bean.OrderQueryRespBean; import com.mogo.och.taxi.bean.OrderQueryRouteInfoRespBean; -import com.mogo.utils.logger.Logger; import java.util.ArrayList; import java.util.List; diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/utils/OchTaxiUtils.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/utils/OchTaxiUtils.java index 155b1d4782..8c777d31e4 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/utils/OchTaxiUtils.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/utils/OchTaxiUtils.java @@ -1,6 +1,6 @@ package com.mogo.och.taxi.utils; -import com.mogo.utils.DateTimeUtils; +import com.mogo.eagle.core.utilcode.util.DateTimeUtils; import java.text.SimpleDateFormat; import java.util.Calendar; diff --git a/app/build.gradle b/app/build.gradle index 953649badb..8029fbfcb3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,16 +4,84 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'android-aspectjx' apply plugin: 'bugly' -apply plugin: 'apm-plugin' + +if (!isAndroidTestBuild()) { + apply plugin: 'apm-plugin' +} //apply ByteX宿主 -apply plugin: 'bytex' -ByteX { - enable true - enableInDebug true - logLevel "DEBUG" + +if (!isAndroidTestBuild()) { + apply plugin: 'bytex' + ByteX { + enable true + enableInDebug true + logLevel "DEBUG" + } } +if (!isAndroidTestBuild()) { + apply plugin: 'bytex.threadOpt' + thread_opt { + enable true + enableInDebug true + rxJavaIoReplacer 'com/mogo/eagle/core/utilcode/util/ThreadUtils@@getIoPool@@()Ljava/util/concurrent/ExecutorService;' + rxJavaComputationReplacer 'com/mogo/eagle/core/utilcode/util/ThreadUtils@@getCpuPool@@()Ljava/util/concurrent/ExecutorService;' + coroutineIoReplacer 'com/mogo/eagle/core/utilcode/util/ThreadUtils@@getIoPool@@()Ljava/util/concurrent/ExecutorService;' + coroutineDefaultReplacer 'com/mogo/eagle/core/utilcode/util/ThreadUtils@@getCpuPool@@()Ljava/util/concurrent/ExecutorService;' + } + + /** + * 方便使用systrace工具,在工程侧打点,便于分析工程侧性能问题 + */ + apply plugin: 'bytex.systrace' + systrace { + /** + * 交付时要关闭,会有性能损耗 + */ + enable false + enableInDebug false + /** + * - 是否使用[Trace.beginAsyncSection(String, int)/Trace.endAsyncSection(String, int)]进行打点 + * - 默认使用[Trace.beginSection(String)/Trace.endSection()]进行打点 + */ + isTraceAsync false + /** + * - 是否在运行时只针对主线程打点,其它线程不打 + */ + isOnlyMainThread false + + /** + * - 是否忽略对类的静态构造方法打点 + * - 默认不忽略 + */ + isIgnoreClinitMethod false + + /** + * - 是否忽略对类中的简单方法打点 + * 简单方法定义: + * - 空方法 + * - get/set 方法 + * - 单独的方法,方法体内没有调用其它方法 + * - 默认不忽略 + */ + isIgnoreSampleMethod false + + /** + * - 针对特定类集合,配置打点白名单,在此集合中的类中的所有方法不打点 + * - 支持正则表达式 + */ + whiteListForClass = [] + + /** + * - 针对特定包名集合,配置打点白名单,所有类以此包名为前缀的类不打点 + * - 支持正则表达式 + */ + whiteListForPackage = [] + } +} + + /*apply plugin: 'chain.log.hook' hooklog{ enableLoggerToServer true @@ -87,6 +155,10 @@ android { targetCompatibility 1.8 } + kotlinOptions { + jvmTarget = '1.8' + } + sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' @@ -140,6 +212,10 @@ android { packagingOptions { exclude 'META-INF/io.netty.versions.properties' } + + useLibrary 'android.test.runner' + useLibrary 'android.test.base' + useLibrary 'android.test.mock' } repositories { @@ -152,29 +228,7 @@ aspectjx { include "com.mogo.chat" } -ApmPlugin { - // 是否进行插桩 - enable true - // 是否在Debug包插桩,默认不插桩 - enableInDebug true - // DEBUG("DEBUG"), INFO("INFO"), WARN("WARN"), ERROR("ERROR"); - // INFO 级别Log会汇总所有被插桩处理的类供查看,路径 app/build/ByteX/ApmPlugin - logLevel "DEBUG" - // 启动分析开关:监控App启动耗时,需要同时开启pageLoadSwitch - startSwitch = true - // 页面响应开关:监控Activity的生命周期耗时 - pageLoadSwitch = true - // 网络监控开关:监控okhttp3的网络请求 - okHttp3Switch = true - // 白名单下的包进行插桩,需要填写要插装类所在的包名,支持前缀配置 - whiteList = [ - "com.mogo" - ] - // 黑名单包下类不进行插桩,可以配置包名和类名,没有可以填空 - blackList = [ - ] -} dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) @@ -184,9 +238,6 @@ dependencies { implementation rootProject.ext.dependencies.arouter implementation rootProject.ext.dependencies.boostmultidex - implementation 'com.volcengine:apm_insight:1.4.4.cn' - implementation 'com.volcengine:apm_insight_crash:1.4.2' - compileOnly rootProject.ext.dependencies.adasapi compileOnly rootProject.ext.dependencies.adasconfigapi @@ -202,21 +253,39 @@ dependencies { apply from: "./functions/tts.gradle" apply from: "./functions/och.gradle" -// implementation group: "com.tencent.matrix", name: "matrix-android-lib", version: '0.6.6', changing: true -// implementation group: "com.tencent.matrix", name: "matrix-android-commons", version: '0.6.6', changing: true -// implementation group: "com.tencent.matrix", name: "matrix-trace-canary", version:'0.6.6', changing: true -// implementation group: "com.tencent.matrix", name: "matrix-io-canary", version: '0.6.6', changing: true - + androidTestImplementation rootProject.ext.dependencies.androidx_test_core + androidTestImplementation rootProject.ext.dependencies.androidx_test_core_ktx + androidTestImplementation rootProject.ext.dependencies.androidx_unit_ext + androidTestImplementation rootProject.ext.dependencies.androidx_unit_ext_ktx + androidTestImplementation rootProject.ext.dependencies.androidx_runner + androidTestImplementation rootProject.ext.dependencies.androidx_espresso_core } -//apply plugin: 'com.tencent.matrix-plugin' -//matrix { -// trace { -// enable = true //if you don't want to use trace canary, set false -// baseMethodMapFile = "${project.projectDir}/matrixOutput/Debug.methodmap" -// blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt" -// } -//} +if (!isAndroidTestBuild()) { + ApmPlugin { + // 是否进行插桩 + enable true + // 是否在Debug包插桩,默认不插桩 + enableInDebug true + // DEBUG("DEBUG"), INFO("INFO"), WARN("WARN"), ERROR("ERROR"); + // INFO 级别Log会汇总所有被插桩处理的类供查看,路径 app/build/ByteX/ApmPlugin + logLevel "DEBUG" + // 启动分析开关:监控App启动耗时,需要同时开启pageLoadSwitch + startSwitch = true + // 页面响应开关:监控Activity的生命周期耗时 + pageLoadSwitch = true + // 网络监控开关:监控okhttp3的网络请求 + okHttp3Switch = true + // 白名单下的包进行插桩,需要填写要插装类所在的包名,支持前缀配置 + whiteList = [ + "com.mogo" + ] + // 黑名单包下类不进行插桩,可以配置包名和类名,没有可以填空 + blackList = [ + + ] + } +} android.applicationVariants.all { variant -> def buildTime = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08:00")) @@ -253,10 +322,20 @@ def getWorkingBranchName() { */ def getWorkingBranchHash() { def workingBranchHash = "" - def proc = "git log -n1 --format=format:\"%h\"".execute() + def proc = "git log -n1 --format=format:%h".execute() proc.in.eachLine { line -> workingBranchHash = line } proc.err.eachLine { line -> println line } proc.waitFor() println "Working branch hash: " + workingBranchHash - return workingBranchHash + return "\"${workingBranchHash}\"" +} + + +boolean isAndroidTestBuild() { + for (String s : gradle.startParameter.taskNames) { + if (s.contains("AndroidTest")) { + return true + } + } + return false } diff --git a/app/src/androidTest/java/com/mogo/functions/test/AutoPilotBadCaseTest.kt b/app/src/androidTest/java/com/mogo/functions/test/AutoPilotBadCaseTest.kt new file mode 100644 index 0000000000..8657b3107e --- /dev/null +++ b/app/src/androidTest/java/com/mogo/functions/test/AutoPilotBadCaseTest.kt @@ -0,0 +1,145 @@ +package com.mogo.functions.test + +import androidx.lifecycle.lifecycleScope +import androidx.test.core.app.ActivityScenario +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import com.mogo.eagle.core.data.autopilot.AutoPilotRecordResult +import com.mogo.eagle.core.function.hmi.ui.MoGoHmiFragment +import com.mogo.eagle.core.function.main.MainLauncherActivity +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import kotlin.random.Random + +@RunWith(AndroidJUnit4::class) +@LargeTest +class AutoPilotBadCaseTest { + + lateinit var launch: ActivityScenario + + @Before + fun launch() { + launch = ActivityScenario.launch(MainLauncherActivity::class.java) + } + + @ExperimentalCoroutinesApi @Test + fun showBadCaseEntrance1(): Unit = runBlocking(Dispatchers.Main) { + val f = ensureMoGoHmiFragmentShow() + var index = 0 + (1 until 50) + .map { it } + .asFlow() + .onEach { + delay(TimeUnit.SECONDS.toMillis(5)) + f.onAutopilotRecordResult(AutoPilotRecordResult().also { + it.diskFree = 100 + index + it.duration = 60.0 + it.fileName = "/user/general/record_$index.log" + it.id = 10 + index + it.key = "yyy_$index" + it.stat = 100 + it.type = 1 + it.timestamp = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Date()) + index++ + }) + } + .flowOn(Dispatchers.Default) + .collect() + delay(TimeUnit.HOURS.toMillis(2)) + } + + + @ExperimentalCoroutinesApi @Test + fun showBadCaseEntrance2():Unit = runBlocking(Dispatchers.Main) { + val f = ensureMoGoHmiFragmentShow() + var index = 0 + (1 until 50) + .map { it } + .asFlow() + .onEach { + if (index in 1..4) { + delay(TimeUnit.SECONDS.toMillis(15)) + } else { + delay(Random(20).nextLong()) + } + f.onAutopilotRecordResult(AutoPilotRecordResult().also { + it.diskFree = 100 + index + it.duration = 60.0 + it.fileName = "/user/general/record_$index.log" + it.id = 10 + index + it.key = "yyy_$index" + it.stat = 100 + it.type = 1 + it.timestamp = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Date()) + index++ + }) + + if (index == 5) { + f.lifecycleScope.cancel() + } + + } + .flowOn(Dispatchers.Default) + .collect() + delay(TimeUnit.HOURS.toMillis(2)) + } + + @ExperimentalCoroutinesApi @Test + fun showBadCaseEntrance3(): Unit = runBlocking(Dispatchers.Main) { + val f = ensureMoGoHmiFragmentShow() + var index = 0 + (1 until 50) + .map { it } + .asFlow() + .onEach { + delay(TimeUnit.SECONDS.toMillis(20)) + f.onAutopilotRecordResult(AutoPilotRecordResult().also { + it.diskFree = 100 + index + it.duration = 60.0 + it.fileName = "/user/general/record_$index.log" + it.id = 10 + index + it.key = "yyy_$index" + it.stat = 100 + it.type = 1 + it.timestamp = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Date()) + index++ + }) + } + .flowOn(Dispatchers.Default) + .collect() + delay(TimeUnit.HOURS.toMillis(2)) + } + + + private suspend fun ensureMoGoHmiFragmentShow(): MoGoHmiFragment = suspendCancellableCoroutine { + launch.onActivity { itx -> + 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/app/src/main/java/com/mogo/launcher/MogoApplication.java b/app/src/main/java/com/mogo/launcher/MogoApplication.java index 014984f49e..b16fa736cd 100644 --- a/app/src/main/java/com/mogo/launcher/MogoApplication.java +++ b/app/src/main/java/com/mogo/launcher/MogoApplication.java @@ -1,29 +1,16 @@ package com.mogo.launcher; -import com.apm.insight.AttachUserData; -import com.apm.insight.CrashType; -import com.apm.insight.MonitorCrash; -import com.apm.insight.log.VLog; import com.auto.zhidao.logsdk.CrashSystem; -import com.bytedance.apm.insight.ApmInsight; -import com.bytedance.apm.insight.ApmInsightInitConfig; -import com.mogo.cloud.passport.MoGoAiCloudClientConfig; import com.mogo.commons.debug.DebugConfig; import com.mogo.eagle.core.data.app.AppConfigInfo; import com.mogo.eagle.core.data.config.FunctionBuildConfig; import com.mogo.eagle.core.data.config.HdMapBuildConfig; import com.mogo.eagle.core.data.config.HmiBuildConfig; import com.mogo.eagle.core.function.main.MainMoGoApplication; -import com.mogo.module.v2x.utils.ObuConfig; +import com.mogo.eagle.core.utilcode.mogo.logger.LogLevel; +import com.mogo.eagle.core.utilcode.mogo.logger.Logger; +import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr; import com.mogo.test.crashreport.CrashReportConstants; -import com.mogo.utils.AppUtils; -import com.mogo.utils.CommonUtils; -import com.mogo.utils.logger.LogLevel; -import com.mogo.utils.logger.Logger; -import com.mogo.utils.storage.SharedPrefsMgr; - -import java.util.HashMap; -import java.util.Map; /** * @author congtaowang @@ -32,14 +19,12 @@ import java.util.Map; * Launcher application */ public class MogoApplication extends MainMoGoApplication { - private static final String BYTEAMP_APPID = "302368"; @Override protected void initCrashConfig() { CrashSystem crashSystem = CrashSystem.getInstance(this); crashSystem.init(); - initCrash(); - initApmInsight(); + //设置debug模式,日志不上传 crashSystem.setDebug(BuildConfig.DEBUG); } @@ -50,91 +35,6 @@ public class MogoApplication extends MainMoGoApplication { Logger.init(BuildConfig.DEBUG ? LogLevel.DEBUG : LogLevel.OFF); } - private void initCrash() { - - MonitorCrash crash = MonitorCrash.init(this, BYTEAMP_APPID, CommonUtils.getVersionCode(this), CommonUtils.getVersionName(this)) - .setCustomDataCallback(new AttachUserData() { - @Override - public Map getUserData(CrashType type) { - HashMap map = new HashMap<>(); -// map.put("app_custom", "app_value"); - //SN - map.put("serial", MoGoAiCloudClientConfig.getInstance().getSn()); - //地图版本 - String mapSDKVersion = AppUtils.getCustomMapSDKVersion(getApplicationContext()); - map.put("MAP_SDK_VERSION", mapSDKVersion); - return map; - } - }); - crash.config().setChannel("eagle"); -// crash.config().setDeviceId("did");//可选,可以设置自定义did,不设置会使用内部默认的 -// crash.setReportUrl("www.xxx.com"); // 私有化部署:私有化部署才配置上报地址 -// crash.addTags("key", "value"); // 自定义筛选tag, 按需添加、可多次覆盖 - } - - /** - * ApmInsight性能监控初始化 - */ - private void initApmInsight() { - - ApmInsightInitConfig.Builder builder = ApmInsightInitConfig.builder(); - //设置分配的appid - builder.aid(BYTEAMP_APPID); - //是否开启卡顿功能 - builder.blockDetect(true); - //是否开启严重卡顿功能 - builder.seriousBlockDetect(true); - //是否开启流畅性和丢帧 - builder.fpsMonitor(true); - //控制是否打开WebVeiw监控 - builder.enableWebViewMonitor(true); - //控制是否打开内存监控 - builder.memoryMonitor(true); - //控制是否打开电量监控 - builder.batteryMonitor(true); - //是否打印日志,注:线上release版本要配置为false - builder.debugMode(true); - //支持用户自定义user_id把平台数据和自己用户关联起来,可以不配置 -// builder.userId("user_id"); - //私有化部署:配置数据上报的域名 (私有化部署才需要配置,内部有默认域名),测试支持设置http://www.xxx.com 默认是https协议 -// builder.defaultReportDomain("www.xxx.com"); - //设置渠道。1.3.16版本增加接口 - builder.channel("local"); - //打开自定义日志回捞能力,1.4.1版本新增接口 - builder.enableLogRecovery(true); - //设置数据和Rangers Applog数据打通,设备标识did必填。1.3.16版本增加接口 -// builder.setDynamicParams(new IDynamicParams() { -// @Override -// public String getUserUniqueID() { -// //可选。依赖AppLog可以通过AppLog.getUserUniqueID()获取,否则可以返回null。 -// return null; -// } -// -// @Override -// public String getAbSdkVersion() { -// //可选。如果依赖AppLog可以通过AppLog.getAbSdkVersion()获取,否则可以返回null。 -// return null; -// } -// -// @Override -// public String getSsid() { -// //可选。依赖AppLog可以通过AppLog.getSsid()获取,否则可以返回null。 -// return null; -// } -// -// @Override -// public String getDid() { -// //1.4.0版本及以上,可选,其他版本必填。设备的唯一标识,如果依赖AppLog可以通过 AppLog.getDid() 获取,也可以自己生成。 -// return AppLog.getDid(); -// } -// }); - ApmInsight.getInstance().init(this, builder.build()); - - //初始化自定日志,配置自定义日志最大占用磁盘,内部一般配置20,代表最大20M磁盘占用。1.4.1版本开始存在这个api - VLog.init(this, 20); - - } - @Override protected void initCloudClientConfig() { // todo 使用旧Socket链路 true = 旧链路,false = 新链路 @@ -165,7 +65,6 @@ public class MogoApplication extends MainMoGoApplication { AppConfigInfo.INSTANCE.setWorkingBranchName(BuildConfig.WORKING_BRANCH_NAME); AppConfigInfo.INSTANCE.setWorkingBranchHash(BuildConfig.WORKING_BRANCH_HASH); - ObuConfig.useObuLocation = false; // 使用与渠道配置一样的gps提供者提供的数据,app/productFlavors/fPadLenovo.gradle GPS_PROVIDER 0-Android系统,1-工控机,2-OBU FunctionBuildConfig.gpsProvider = BuildConfig.GPS_PROVIDER; // 配置BuglyAppID diff --git a/build.gradle b/build.gradle index 8d71cf9739..95ee9b6c7f 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ apply from: "javadoc.gradle" buildscript { repositories { + maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } maven { url "https://artifact.bytedance.com/repository/byteX/" } maven { url 'http://nexus.zhidaoauto.com/repository/maven-releases/' } @@ -32,6 +33,9 @@ buildscript { classpath "com.bytedance.android.byteX:base-plugin:0.3.0" classpath "com.mogo.cloud:hook:${HOOK_LOG_VERSION}" classpath 'com.volcengine:apm_insight_plugin:1.4.1' + classpath 'com.mogo.cloud:thread_opt:1.0.0' + classpath 'com.mogo.cloud:systrace:1.0.1' + // classpath "com.bytedance.android.byteX:base-plugin:0.3.0" // classpath "com.mogo.cloud:hook:${HOOK_LOG_VERSION}" diff --git a/config.gradle b/config.gradle index 2d221db552..565bb8387b 100644 --- a/config.gradle +++ b/config.gradle @@ -114,7 +114,7 @@ ext { obusdk : "com.zhidao.enterprise.smartv2x:smartv2x:1.0.0.3", mogoobu : 'com.zhidao.support.obu:mogoobu:1.0.0.19', mogoami : 'com.zhidao.support.obu.ami:mogoami:1.0.0.10', - adasHigh : 'com.zhidao.support.adas:high:1.2.1.2', + adasHigh : 'com.zhidao.support.adas:high:1.2.1.2_bate11', // google googlezxing : "com.google.zxing:core:3.3.3", @@ -195,6 +195,9 @@ ext { skinsupportcardview : "com.mogo.skin:skin-support-cardview:${SKIN_SUPPORT_CARDVIEW_VERSION}", skinsupportconstraintlayout : "com.mogo.skin:skin-support-constraint-layout:${SKIN_SUPPORT_CONSTRAINT_LAYOUT_VERSION}", skinsupportdesign : "com.mogo.skin:skin-support-design:${SKIN_SUPPORT_DESIGN_VERSION}", + apm_insight : 'com.volcengine:apm_insight:1.4.4.cn', + apm_insight_crash : 'com.volcengine:apm_insight_crash:1.4.2', + //========================= TTS语音 Maven 版本管理 ========================= ttsbase : "com.mogo.tts:tts-base:${TTS_BASE_VERSION}", ttsdi : "com.mogo.tts:tts-di:${TTS_DI_VERSION}", @@ -238,6 +241,21 @@ ext { mogo_core_utils : "com.mogo.eagle.core:utils:${MOGO_CORE_UTILS_VERSION}", mogo_core_network : "com.mogo.eagle.core:network:${MOGO_CORE_NETWORK_VERSION}", + //========================= V2X SDK ========================= + mogo_v2x : "com.mogo.v2x:v2x:${MOGO_V2X_SDK_VERSION}", + + life_cycle_scope : "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0", + view_model_scope : "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0", + live_data_scope : "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0", + + + //========================== Unit Test ====================== + androidx_test_core : "androidx.test:core:1.2.1", + androidx_test_core_ktx : "androidx.test:core-ktx:1.2.0", + androidx_unit_ext : "androidx.test.ext:junit:1.1.2", + androidx_unit_ext_ktx : "androidx.test.ext:junit-ktx:1.1.2", + androidx_runner : "androidx.test:runner:1.3.0", + androidx_espresso_core : "androidx.test.espresso:espresso-core:3.3.0", ] } \ No newline at end of file diff --git a/core/README.md b/core/README.md index 034c05e8b2..ba2ca3c14f 100644 --- a/core/README.md +++ b/core/README.md @@ -2,13 +2,16 @@ 本模块用来编写鹰眼核型功能 - function-impl 目录下编写的都是对mogo-core-function-api定的功能实现, - - mogo-core-function-check 程序及车辆检测模块 - - mogo-core-function-hmi UI呈现及交互模块 - - mogo-core-function-map 地图相关的模块 - - mogo-core-function-notice 云端公告、调度相关模块 - - mogo-core-function-obu-mogo 自研OBU预警模块 - - mogo-core-function-smp 小地图模块 - - mogo-core-function-v2x 自车+云端预警模块 + - mogo-core-function-check 程序及车辆检测模块 + - mogo-core-function-devatools 开发工具模块 + - mogo-core-function-hmi UI呈现及交互模块 + - mogo-core-function-main 主入口 + - mogo-core-function-map 地图相关的模块 + - mogo-core-function-monitoring 远距离监控查看,路测摄像头、前车直播 + - mogo-core-function-notice 云端公告、调度相关模块 + - mogo-core-function-obu-mogo 自研OBU预警模块 + - mogo-core-function-smp 小地图模块 + - mogo-core-function-v2x 自车+云端预警模块 - mogo-core-data:定义基础业务所需要的数据结构 diff --git a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt index 0a59085289..9607b973e4 100644 --- a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt +++ b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/MoGoAutopilotProvider.kt @@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit */ @Route(path = MogoServicePaths.PATH_AUTO_PILOT) class MoGoAutopilotProvider : - IMoGoAutopilotProvider { + IMoGoAutopilotProvider { private val TAG = "MoGoAutoPilotProvider" override val functionName: String @@ -82,7 +82,8 @@ class MoGoAutopilotProvider : } override fun recordPackage(): Boolean { - return AdasManager.getInstance().recordPackage(1, (System.currentTimeMillis() / 1000).toInt()) + return AdasManager.getInstance() + .recordPackage(1, (System.currentTimeMillis() / 1000).toInt()) } override fun setEnableLog(isEnableLog: Boolean) { @@ -100,4 +101,16 @@ class MoGoAutopilotProvider : override fun setAutoPilotSpeed(speed: Int): Boolean { return AdasManager.getInstance().setSpeed(speed) } + + override fun setIPCShutDown() { + AdasManager.getInstance().shutdownIPC() + } + + override fun setIPCReboot() { + AdasManager.getInstance().rebootIPC() + } + + override fun recordCause(key: String?, name: String?, id: String?, reason: String?) { + AdasManager.getInstance().recordCause(key, name, id, reason) + } } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-check/src/main/java/com/mogo/eagle/core/function/check/VehicleMonitoringManager.kt b/core/function-impl/mogo-core-function-check/src/main/java/com/mogo/eagle/core/function/check/VehicleMonitoringManager.kt index e7c6518596..88eeed3a61 100644 --- a/core/function-impl/mogo-core-function-check/src/main/java/com/mogo/eagle/core/function/check/VehicleMonitoringManager.kt +++ b/core/function-impl/mogo-core-function-check/src/main/java/com/mogo/eagle/core/function/check/VehicleMonitoringManager.kt @@ -12,6 +12,7 @@ import com.mogo.eagle.core.function.check.net.CheckNetWork.checkNetWork import com.mogo.eagle.core.function.check.net.CheckResultData import com.mogo.eagle.core.function.check.view.CheckActivity import com.mogo.eagle.core.function.check.view.CheckDialog +import com.mogo.eagle.core.utilcode.util.ActivityLifecycleManager import com.mogo.eagle.core.utilcode.util.ActivityUtils import com.mogo.eagle.core.utilcode.util.AppUtils import com.mogo.eagle.core.utilcode.util.LogUtils @@ -19,7 +20,6 @@ import com.mogo.module.common.MogoApisHandler import com.mogo.module.service.receiver.MogoReceiver import com.mogo.service.statusmanager.IMogoStatusChangedListener import com.mogo.service.statusmanager.StatusDescriptor -import com.mogo.utils.ActivityLifecycleManager import java.util.concurrent.ConcurrentHashMap /** diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/logcatch/MogoLogCatchManager.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/logcatch/MogoLogCatchManager.kt index d9dfd1b9da..cdff9714ed 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/logcatch/MogoLogCatchManager.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/logcatch/MogoLogCatchManager.kt @@ -9,13 +9,13 @@ import com.mogo.commons.AbsMogoApplication import com.mogo.commons.debug.DebugConfig import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsListenerManager import com.mogo.eagle.core.network.NetConfig +import com.mogo.eagle.core.utilcode.mogo.logger.LogLevel +import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.eagle.core.utilcode.mogo.toast.TipToast import com.mogo.eagle.core.utilcode.util.ThreadUtils import com.mogo.eagle.core.utilcode.util.TimeUtils import com.mogo.module.common.MogoApisHandler import com.mogo.service.cloud.socket.IMogoOnMessageListener -import com.mogo.utils.logger.LogLevel -import com.mogo.utils.logger.Logger import com.zhidao.loglib.bean.RemoteLogPushContent import com.zhidao.loglib.call.LogInfoManagerFactory import com.zhidao.loglib.core.ILogListener @@ -47,7 +47,7 @@ object MogoLogCatchManager : IMogoOnMessageListener, Handl MogoApisHandler.getInstance().apis .getSocketManagerApi(AbsMogoApplication.getApp().applicationContext) .registerOnMessageListener(LOG_PUSH_TYPE, this) - manualContent.duration = 60 + manualContent.duration = 10 manualContent.pkgName = context.packageName } @@ -98,19 +98,23 @@ object MogoLogCatchManager : IMogoOnMessageListener, Handl private fun startCatchLog(content: RemoteLogPushContent) { catchingList.add(content.pkgName) - var delay = (content.duration * 60 * 1000).toLong() + var delay = (content.duration).toLong() handler.removeMessages(MSG_TRY_CLOSE_LOG) if (delay <= 0) { // 如果push 下来的delay小于等于0,那就给个默认最大值一小时 - delay = 60 * 60 * 1000L + delay = 10 } - handler.sendEmptyMessageDelayed(MSG_TRY_CLOSE_LOG, delay) + handler.sendEmptyMessageDelayed(MSG_TRY_CLOSE_LOG, delay * 1000L * 60) openLoggerLevel() logInfoManager = LogInfoManagerFactory.createPushLogInfoManager( mContext, MoGoAiCloudClientConfig.getInstance().sn + File.separator + TimeUtils.formatYMD(System.currentTimeMillis()), - content, this) + content, this + ) logInfoManager?.start() + logInfoManager?.registerLogOutListener { lineLog -> + CallerDevaToolsListenerManager.invokeDevaToolsLogCatchLines(lineLog) + } } private fun stopCatchLog(content: RemoteLogPushContent) { diff --git a/core/function-impl/mogo-core-function-hmi/src/main/AndroidManifest.xml b/core/function-impl/mogo-core-function-hmi/src/main/AndroidManifest.xml index 4e3fdff847..27c8e3db04 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/AndroidManifest.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/AndroidManifest.xml @@ -36,5 +36,13 @@ + + + + + + + + \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloat.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloat.kt index 18a97b553a..dd0750ac92 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloat.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloat.kt @@ -5,8 +5,8 @@ import android.view.View import com.mogo.eagle.core.function.hmi.notification.enums.SidePattern import com.mogo.eagle.core.function.hmi.notification.interfaces.OnFloatAnimator import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener -import com.mogo.utils.WindowUtils -import com.mogo.utils.logger.Logger +import com.mogo.eagle.core.utilcode.mogo.logger.Logger +import com.mogo.eagle.core.utilcode.util.WindowUtils /** * @author donghongyu @@ -147,6 +147,14 @@ class WarningFloat { } } + fun setWindowWidth(width: Int) = apply { + this.config.width = width + } + + fun setWindowHeight(height: Int) = apply { + this.config.height = height + } + /** * 创建浮窗,包括Activity浮窗和系统浮窗,如若系统浮窗无权限,先进行权限申请 */ diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloatWindowHelper.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloatWindowHelper.kt index fa8f7bedfc..639df0470b 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloatWindowHelper.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningFloatWindowHelper.kt @@ -12,12 +12,11 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.WindowManager -import com.mogo.eagle.core.function.hmi.R import com.mogo.eagle.core.function.hmi.notification.anim.AnimatorManager import com.mogo.eagle.core.function.hmi.notification.enums.ShowPattern import com.mogo.eagle.core.function.hmi.notification.widget.ParentFrameLayout -import com.mogo.utils.WindowUtils -import com.mogo.utils.logger.Logger +import com.mogo.eagle.core.utilcode.mogo.logger.Logger +import com.mogo.eagle.core.utilcode.util.WindowUtils /** * @author donghongyu @@ -66,8 +65,8 @@ internal class WarningFloatWindowHelper( // 没有边界限制,允许窗口扩展到屏幕外 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS else WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - width = WindowManager.LayoutParams.WRAP_CONTENT - height = WindowManager.LayoutParams.WRAP_CONTENT + width = config.width + height = config.height // 如若设置了固定坐标,直接定位 if (config.locationPair != Pair(0, 0)) { diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningNotificationConfig.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningNotificationConfig.kt index edb0f3e1d1..dcf1151adb 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningNotificationConfig.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/WarningNotificationConfig.kt @@ -1,6 +1,7 @@ package com.mogo.eagle.core.function.hmi.notification import android.view.View +import android.view.WindowManager import com.mogo.eagle.core.function.hmi.notification.anim.DefaultAnimator import com.mogo.eagle.core.function.hmi.notification.enums.ShowPattern import com.mogo.eagle.core.function.hmi.notification.enums.SidePattern @@ -59,4 +60,9 @@ data class WarningNotificationConfig( // Callbacks var callbacks: OnFloatCallbacks? = null, + // 窗口宽度 + var width: Int = WindowManager.LayoutParams.WRAP_CONTENT, + + // 窗口高度 + var height: Int = WindowManager.LayoutParams.WRAP_CONTENT ) \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/anim/DefaultAnimator.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/anim/DefaultAnimator.kt index f80831999c..675ed6ddda 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/anim/DefaultAnimator.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/notification/anim/DefaultAnimator.kt @@ -7,7 +7,7 @@ import android.view.View import android.view.WindowManager import com.mogo.eagle.core.function.hmi.notification.enums.SidePattern import com.mogo.eagle.core.function.hmi.notification.interfaces.OnFloatAnimator -import com.mogo.utils.WindowUtils +import com.mogo.eagle.core.utilcode.util.WindowUtils import kotlin.math.min /** diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/NoticeNormalBroadcastReceiver.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/NoticeNormalBroadcastReceiver.kt index 9f44cb8aa0..93fad68c28 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/NoticeNormalBroadcastReceiver.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/NoticeNormalBroadcastReceiver.kt @@ -4,15 +4,11 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import com.alibaba.android.arouter.launcher.ARouter -import com.mogo.module.common.enums.EventTypeEnum -import com.mogo.eagle.core.function.hmi.WaringConst import com.mogo.service.IMogoServiceApis import com.mogo.eagle.core.data.constants.MogoServicePaths import com.mogo.eagle.core.data.notice.NoticeNormalData -import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWaringProvider import com.mogo.eagle.core.function.call.hmi.CallerHmiManager import com.mogo.eagle.core.utilcode.util.SharedPrefs -import com.mogo.utils.logger.Logger /** * 用于普通云公告的测试 diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/TurnLightBroadcastReceiver.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/TurnLightBroadcastReceiver.kt new file mode 100644 index 0000000000..5fcdff1252 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/TurnLightBroadcastReceiver.kt @@ -0,0 +1,50 @@ +package com.mogo.eagle.core.function.hmi.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log +import com.alibaba.android.arouter.launcher.ARouter +import com.mogo.eagle.core.data.constants.MogoServicePaths +import com.mogo.eagle.core.data.notice.NoticeNormalData +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager.showBrakeLight +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager.showTurnLight +import com.mogo.eagle.core.function.hmi.WaringConst +import com.mogo.eagle.core.utilcode.mogo.logger.Logger +import com.mogo.eagle.core.utilcode.util.SharedPrefs +import com.mogo.service.IMogoServiceApis + +/** + * 转向灯,刹车 + * + * @author lixiaopeng + */ +class TurnLightBroadcastReceiver : BroadcastReceiver() { + + companion object { + private const val TAG = "TurnLightBroadcastReceiver" + } + + override fun onReceive(context: Context, intent: Intent) { + try { + val type = intent.getIntExtra("type", 0) + val lightInt = intent.getIntExtra("light", 0) + showTurnLight(type, lightInt) + } catch (e: Exception) { + e.printStackTrace() + } + } + + + private fun showTurnLight( //type 1,转向灯,2刹车 + type: Int, + lightInt: Int + ) { + if (type == 1) { + showTurnLight(lightInt) //设置转向灯 + } else if (type == 2) { + showBrakeLight(lightInt) //设置刹车信息 + } + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XLimitingVelocityBroadcastReceiver.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XLimitingVelocityBroadcastReceiver.kt index 03c9780f2b..554c398818 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XLimitingVelocityBroadcastReceiver.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XLimitingVelocityBroadcastReceiver.kt @@ -7,8 +7,8 @@ import com.alibaba.android.arouter.launcher.ARouter import com.mogo.eagle.core.data.constants.MogoServicePaths import com.mogo.eagle.core.function.call.hmi.CallerHmiManager import com.mogo.eagle.core.function.hmi.WaringConst +import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.service.IMogoServiceApis -import com.mogo.utils.logger.Logger /** * V2X 预警广播接收。用于跨应用,跨进程,内部也可以通过这种方式 控制限速标志 diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XTrafficLightBroadcastReceiver.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XTrafficLightBroadcastReceiver.kt index 3d6b064735..9cfd191f6c 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XTrafficLightBroadcastReceiver.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XTrafficLightBroadcastReceiver.kt @@ -7,8 +7,8 @@ import com.alibaba.android.arouter.launcher.ARouter import com.mogo.eagle.core.data.constants.MogoServicePaths import com.mogo.eagle.core.function.call.hmi.CallerHmiManager import com.mogo.eagle.core.function.hmi.WaringConst +import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.service.IMogoServiceApis -import com.mogo.utils.logger.Logger /** * V2X 预警广播接收。用于跨应用,跨进程,内部也可以通过这种方式 触发红绿灯场景 diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XWarningBroadcastReceiver.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XWarningBroadcastReceiver.kt index d5b6f7e4d3..49b3472569 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XWarningBroadcastReceiver.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/receiver/V2XWarningBroadcastReceiver.kt @@ -7,9 +7,9 @@ import com.alibaba.android.arouter.launcher.ARouter import com.mogo.eagle.core.data.constants.MogoServicePaths import com.mogo.eagle.core.function.call.hmi.CallerHmiManager import com.mogo.eagle.core.function.hmi.WaringConst +import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.module.common.enums.EventTypeEnum import com.mogo.service.IMogoServiceApis -import com.mogo.utils.logger.Logger /** * V2X 预警广播接收。用于跨应用,跨进程,内部也可以通过这种方式弹出预警提示框 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 fb28a0da14..63ceb9eb7c 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 @@ -1,23 +1,30 @@ 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.WindowManager +import android.view.* import android.view.animation.OvershootInterpolator +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.lifecycleScope 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.AutoPilotRecordResult import com.mogo.eagle.core.data.camera.CameraEntity import com.mogo.eagle.core.data.config.HmiBuildConfig import com.mogo.eagle.core.data.constants.MoGoFragmentPaths import com.mogo.eagle.core.data.enums.WarningDirectionEnum import com.mogo.eagle.core.data.notice.NoticeNormalData 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.monitor.CallerMonitorManager import com.mogo.eagle.core.function.hmi.R @@ -30,12 +37,21 @@ 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.post import com.mogo.eagle.core.function.hmi.ui.widget.V2XNotificationView +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.module.common.enums.EventTypeEnum -import com.mogo.utils.logger.Logger 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 @@ -45,7 +61,7 @@ import kotlinx.android.synthetic.main.fragment_hmi.* @Route(path = MoGoFragmentPaths.PATH_FRAGMENT_HMI) class MoGoHmiFragment : MvpFragment(), IMoGoWaringProvider, - MoGoWarningContract.View { + MoGoWarningContract.View, IMoGoAutopilotIdentifyListener { private val TAG = "MoGoHmiFragment" // DebugSettingView @@ -64,9 +80,107 @@ class MoGoHmiFragment : MvpFragment private var toolsView: AutoPilotAndCheckView? = null + private var autoPilotToolsFloat: WarningFloat.Builder? = null + // 检测、自动驾驶速度设置 private var toolsViewFloat: WarningFloat.Builder? = null + @Volatile + private var autoPilotBadCaseEntrance: View? = null + + private var autoPilotBadCaseView: AutoPilotBadCaseView? = null + + companion object { + private const val MSG_WHAT_DISMISS_BAD_CASE_ENTRY = 0x1010 + private val DURATION_FOR_DISMISS = 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) { + Logger.d("QQQ", "-- step -- 1 --") + var oldT = try { + old?.timestamp?.takeIf { it.isNotBlank() }?.let { + SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", 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("yyyy-MM-dd-HH-mm-ss", Locale.getDefault()).parse(it)?.time + ?: 0L + } ?: 0L + } catch (t: Throwable) { + t.printStackTrace() + 0L + } + + if (oldT == 0L || (newT > 0L && (newT - oldT > 0L) && (newT - oldT) < DURATION_FOR_DISMISS)) { + Logger.d("QQQ", "-- step -- 2 --") + record?.takeIf { it.key != old?.key && it.timestamp != old?.timestamp }?.also { + Logger.d("QQQ", "record: [$record] is displaying and consuming ~~~" ) + showBadCaseEntrance(it) + } + continue + } + + while (oldT != 0L && newT != 0L && (newT - oldT) >= DURATION_FOR_DISMISS) { + Logger.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("yyyy-MM-dd-HH-mm-ss", Locale.getDefault()).parse(it)?.time ?: 0L + } ?: 0L + } catch (t: Throwable) { + t.printStackTrace() + 0L + } + } + record?.takeIf { it.key != old?.key && it.timestamp != old?.timestamp }?.also { + Logger.d("QQQ", "record: [$record] is displaying for rest ..." ) + showBadCaseEntrance(it) + } + } else { + Logger.d("QQQ", "record: [$old] hasn't been consumed~~~~" ) + } + } finally { + delay(1000) + } + } + } + } + } + } + + private val handler by lazy { + Handler(Handler.Callback { + if (it.what == MSG_WHAT_DISMISS_BAD_CASE_ENTRY) { + val entrance = autoPilotBadCaseEntrance + if (entrance != null && entrance.visibility == View.VISIBLE) { + Logger.d(TAG, "${DURATION_FOR_DISMISS}毫秒后BadCase入口消失") + (entrance.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult)?.let { itx -> + itx.consumed = true + } + entrance.visibility = View.GONE + } + return@Callback true + } + return@Callback false + }) + } + override fun vipIdentification(visible: Boolean) { ThreadUtils.runOnUiThread { Logger.d(TAG, "vipIdentification") @@ -93,50 +207,156 @@ class MoGoHmiFragment : MvpFragment } viewShowDebugView.setOnLongClickListener { - Log.d(TAG, "长按显示状态工具栏") - context?.let { - if (mDebugSettingViewFloat != null) { - WarningFloat.dismiss(mDebugSettingViewFloat!!.config.floatTag, false) - mDebugSettingViewFloat = null - mDebugSettingView = null - } else { - if (mDebugSettingView == null) { - mDebugSettingView = DebugSettingView(it) - } - mDebugSettingViewFloat = WarningFloat.with(it) - .setTag("DebugSettingView") - .setLayout(mDebugSettingView!!) - .setSidePattern(SidePattern.RIGHT) - .setGravity(Gravity.RIGHT, offsetY = 70) - .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) - }) - .show() - } - } + toggleDebugView() true } } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + CallerAutopilotIdentifyListenerManager.addListener(TAG, this) + } + + @ExperimentalCoroutinesApi + override fun onAutopilotRecordResult(record: AutoPilotRecordResult?) { + record ?: return + Logger.d("QQQ", "onAutopilotRecordResult:$record") + if (record.type == 1 && record.stat == 100) { + lifecycleScope.launchWhenResumed { + channel.send(record) + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + CallerAutopilotIdentifyListenerManager.removeListener(TAG) + } + + @VisibleForTesting + fun showBadCaseEntrance(record: AutoPilotRecordResult) { + Logger.d("QQQ", "showBadCaseEntrance:$record") + lifecycleScope.launch { + if (vs_bad_case_entrance?.parent != null) { + val inflateView = vs_bad_case_entrance.inflate() + autoPilotBadCaseEntrance = inflateView + } + val entrance = autoPilotBadCaseEntrance + if (entrance != null) { + if (entrance.visibility != View.VISIBLE) { + entrance.visibility = View.VISIBLE + } + entrance.setTag(R.id.autopilot_badcase_record, record) + entrance.onClick { + showBadCasesFloat { + it.visibility = View.GONE + } + } + dismissBadCaseEntryAfterSomeTime() + } + } + } + + private fun showBadCasesFloat(dismiss: (() -> Unit)?) { + Logger.d("QQQ", "showBadCaseToolsFloat") + context?.let { it -> + if (autoPilotToolsFloat == null) { + if (autoPilotBadCaseView == null) { + autoPilotBadCaseView = AutoPilotBadCaseView(it).also { itx -> + itx.onDismiss { + dismissBadCaseFloatView() + } + itx.onSelect { + lifecycleScope.launch { + val record = + autoPilotBadCaseEntrance?.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult + 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) { + Logger.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?.consumed = true + return@launch + } + Logger.e("QQQ", "fail:${body}") + } + } catch (t: Throwable) { + t.printStackTrace() + ToastUtils.showShort("网络请求失败,请尝试联网~") + Logger.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, DURATION_FOR_DISMISS) + } + private fun showToolsFloat() { Logger.d(TAG, "showToolsFloat") context?.let { @@ -153,6 +373,10 @@ class MoGoHmiFragment : MvpFragment override fun onClose(v: View) { dismissToolsFloatView() } + + override fun showDebugPanelView() { + toggleDebugView() + } }) } toolsViewFloat = WarningFloat.with(it) @@ -258,6 +482,52 @@ class MoGoHmiFragment : MvpFragment ivToolsIcon?.visibility = visibility } + /** + * 开关DebugView + */ + override fun toggleDebugView() { + Log.d(TAG, "长按显示状态工具栏") + context?.let { + if (mDebugSettingViewFloat != null) { + WarningFloat.dismiss(mDebugSettingViewFloat!!.config.floatTag, false) + mDebugSettingViewFloat = null + mDebugSettingView = null + } else { + if (mDebugSettingView == null) { + mDebugSettingView = DebugSettingView(it) + } + mDebugSettingViewFloat = WarningFloat.with(it) + .setTag("DebugSettingView") + .setLayout(mDebugSettingView!!) + .setSidePattern(SidePattern.RIGHT) + .setGravity(Gravity.RIGHT, offsetY = 70) + .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) + }) + .show() + } + } + } + /** * 展示VR下V2X预警 * @@ -635,9 +905,78 @@ class MoGoHmiFragment : MvpFragment } } + /** + * 显示转向灯效果 + */ + override fun showTurnLight(light: Int) { +// turnLightView.setTurnLight(light) + + } + + /** + * 显示刹车效果 + */ + override fun showBrakeLight(light: Int) { +// brakeView.setBrakeLight(light) + + } + + /** + * 展示工控机下载状态信息 + * @param downloadVersion 下载版本 + * @param downloadStatus 下载状态(0:下载完成;1:正在下载;2:下载失败) + * @param downloadProgress 下载进度 + */ + override fun showAdDownloadStatus( + downloadVersion: String, + downloadStatus: Int, + downloadProgress: Int + ) { +// if (downloadProgress>0){ +// //新版工控机包处于下载中或已下载完成状态,展示工具箱提示角标 +// viewUpgradeTips.visibility = View.VISIBLE +// } + if(downloadStatus==0){ + //新版本工控机包下载完成,处于可升级状态,展示工具箱提示角标 + viewUpgradeTips.visibility = View.VISIBLE + }else if(downloadStatus==1){ + //新版本工控机包正在下载中,展示工具箱提示角标 + viewUpgradeTips.visibility = View.VISIBLE + }else if(downloadStatus==2){ + //新版本工控机包下载失败,隐藏工具箱提交角标 + viewUpgradeTips.visibility = View.GONE + } + + } + + /** + * 展示工控机升级状态信息 + * @param upgradeStatus 升级状态(true代表升级成功、false代表升级不成功) + */ + override fun showAdUpgradeStatus(upgradeStatus: Boolean) { + if(upgradeStatus){ + //工控机升级成功,隐藏工具箱提示角标 + viewUpgradeTips.visibility = View.GONE + }else{ + //工控机升级失败,展示工具箱提示角标 + viewUpgradeTips.visibility = View.VISIBLE + } + //TODO 给工具箱空间传递状态 +// toolsView?.setStatus(true) + } + + private fun dismissBadCaseFloatView() { + autoPilotToolsFloat?.let { + WarningFloat.dismiss(it.config.floatTag, false) + autoPilotToolsFloat = null + autoPilotBadCaseView = 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/camera/CameraListView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/camera/CameraListView.kt index 0850bb341d..66a91604f8 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/camera/CameraListView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/camera/CameraListView.kt @@ -23,8 +23,8 @@ import com.mogo.cloud.trafficlive.api.MoGoAiCloudTrafficLive import com.mogo.eagle.core.data.camera.CameraEntity import com.mogo.eagle.core.function.call.monitor.CallerMonitorManager import com.mogo.eagle.core.function.hmi.R +import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.eagle.core.widget.media.video.SimpleVideoPlayer -import com.mogo.utils.logger.Logger import com.shuyu.gsyvideoplayer.GSYVideoManager import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder import com.shuyu.gsyvideoplayer.model.VideoOptionModel diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsLogView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsLogView.kt new file mode 100644 index 0000000000..8af3873f7b --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsLogView.kt @@ -0,0 +1,496 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.res.Resources +import android.graphics.PixelFormat +import android.util.Log +import android.view.* +import android.widget.FrameLayout +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import androidx.core.view.GravityCompat +import com.mogo.commons.context.ContextHolderUtil +import com.mogo.eagle.core.utilcode.util.ScreenUtils +import com.mogo.eagle.core.utilcode.util.Utils + +abstract class AbsLogView : ILogView, TouchProxy.OnTouchEventListener { + + class ViewArgs { + var edgePinned = false + } + + private val mInnerReceiver = InnerReceiver() + + @JvmField + protected var mWindowManager = + ContextHolderUtil.getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager + + /** + * 创建FrameLayout#LayoutParams 系统悬浮窗调用 + */ + protected var systemLayoutParams: WindowManager.LayoutParams? = null + + /** + * 整个悬浮窗的View + */ + private var mRootView: FrameLayout? = null + + /** + * rootView的直接子View 一般是用户的xml布局 被添加到mRootView中 + */ + private var mChildView: View? = null + + val logView: View? + get() = mRootView + + /** + * 手势代理 + */ + @JvmField + var mTouchProxy = TouchProxy(this) + + private val viewProps = ViewArgs() + + /** + * 控件在布局边界发生大小变化被裁剪的原因 + */ + val parentView: LogFrameLayout? + get() = if (mRootView != null) { + mRootView!!.parent as LogFrameLayout + } else null + + fun show(context: Context) { + if (isShow) { + Log.d("EmArrow", "isShow : $isShow") + return + } + performCreate(context) + createView() + onResume() + } + + fun dismiss() { + removeView() + performDestroy() + } + + /** + * 执行floatPage create + * + * @param context 上下文环境 + */ + @SuppressLint("ClickableViewAccessibility") + private fun performCreate(context: Context) { + try { + //调用onCreate方法 + onCreate(context) + + //系统悬浮窗的返回按键监听 + mRootView = object : LogFrameLayout(context, LogFrameLayoutFlag_CHILD) { + override fun dispatchKeyEvent(event: KeyEvent): Boolean { + if (event.action == KeyEvent.ACTION_UP && shouldDealBackKey()) { + //监听返回键 + if (event.keyCode == KeyEvent.KEYCODE_BACK || event.keyCode == KeyEvent.KEYCODE_HOME) { + return onBackPressed() + } + } + return super.dispatchKeyEvent(event) + } + } + //添加根布局的layout回调 + addViewTreeObserverListener() + //调用onCreateView抽象方法 + mChildView = onCreateView(context, mRootView) + //将子View添加到rootView中 + mRootView?.addView(mChildView) + //设置根布局的手势拦截 + mRootView?.setOnTouchListener { v, event -> mTouchProxy.onTouchEvent(v, event) } + //调用onViewCreated回调 + onViewCreated(mRootView) + + mLogViewLayoutParams = LogViewLayoutParams() + //分别创建对应的LayoutParams + systemLayoutParams = WindowManager.LayoutParams() + //shouldDealBackKey : false 不自己收返回事件处理 + if (shouldDealBackKey()) { + //自己处理返回按键 + systemLayoutParams?.flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + mLogViewLayoutParams.flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or LogViewLayoutParams.FLAG_LAYOUT_NO_LIMITS + } else { + //设置WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE会导致RootView监听不到返回按键的监听失效 系统处理返回按键 + systemLayoutParams?.flags = + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + mLogViewLayoutParams.flags = + LogViewLayoutParams.FLAG_NOT_FOCUSABLE or LogViewLayoutParams.FLAG_LAYOUT_NO_LIMITS + } + systemLayoutParams?.apply { + format = PixelFormat.TRANSPARENT + gravity = GravityCompat.START or Gravity.TOP + } + mLogViewLayoutParams.gravity = GravityCompat.START or Gravity.TOP + //动态注册关闭系统弹窗的广播 + val intentFilter = IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + context.registerReceiver(mInnerReceiver, intentFilter) + initViewLayoutParams(mLogViewLayoutParams) + onSystemLayoutParamsCreated() + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun createView() { + mWindowManager.addView(logView, systemLayoutParams) + } + + override fun onResume() { + mRootView?.requestLayout() + } + + private fun removeView() { + mWindowManager.removeView(logView) + } + + private fun performDestroy() { + context?.unregisterReceiver(mInnerReceiver) + //移除布局监听 + removeViewTreeObserverListener() + mRootView = null + onDestroy() + } + + /** + * 用来保存rootView的LayoutParams + */ + private lateinit var mLogViewLayoutParams: LogViewLayoutParams + + /** + * 上一次LogView的位置信息 + */ + private val mLastLogViewPosInfo: LastLogViewPosInfo = LastLogViewPosInfo() + + /** + * 根布局的实际宽 + */ + private var mLogViewWidth = 0 + + /** + * 根布局的实际高 + */ + private var mLogViewHeight = 0 + + private var mViewTreeObserver: ViewTreeObserver? = null + + private val mOnGlobalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener = + ViewTreeObserver.OnGlobalLayoutListener { + //每次布局发生变动的时候重新赋值 + mRootView?.let { + mLogViewWidth = it.measuredWidth + mLogViewHeight = it.measuredHeight + mLastLogViewPosInfo.logViewWidth = mLogViewWidth + mLastLogViewPosInfo.logViewHeight = mLogViewHeight + } + } + + private fun addViewTreeObserverListener() { + if (mViewTreeObserver == null && mRootView != null) { + mViewTreeObserver = mRootView!!.viewTreeObserver + mViewTreeObserver?.addOnGlobalLayoutListener(mOnGlobalLayoutListener) + } + } + + private fun removeViewTreeObserverListener() { + mViewTreeObserver?.let { + if (it.isAlive) { + it.removeOnGlobalLayoutListener(mOnGlobalLayoutListener) + } + } + } + + override fun onDestroy() { + } + + /** + * 确定系统浮标的初始位置 + * LayoutParams创建完以后调用 + * 调用时建议放在实现下方 + */ + private fun onSystemLayoutParamsCreated() { + //如果有上一个页面的位置记录 这更新位置 + systemLayoutParams?.flags = mLogViewLayoutParams.flags + systemLayoutParams?.gravity = mLogViewLayoutParams.gravity + systemLayoutParams?.width = mLogViewLayoutParams.width + systemLayoutParams?.height = mLogViewLayoutParams.height + systemLayoutParams?.x = mLogViewLayoutParams.x + systemLayoutParams?.y = mLogViewLayoutParams.y + } + + /** + * 默认实现为true + * + * @return + */ + override fun canDrag(): Boolean { + return true + } + + /** + * 搭配shouldDealBackKey使用 自定义处理完以后需要返回true + * 默认模式的onBackPressed 拦截在NormViewManager#getRootContentView中被处理 + * 系统模式下的onBackPressed 在当前类的performCreate 初始化View时被处理 + * 返回false 表示交由系统处理 + * 返回 true 表示当前的返回事件已由自己处理 并拦截了改返回事件 + */ + override fun onBackPressed(): Boolean { + return false + } + + /** + * 默认不自己处理返回按键 + * + * @return + */ + override fun shouldDealBackKey(): Boolean { + return false + } + + override fun onEnterBackground() { + mRootView?.let { + it.visibility = View.GONE + } + } + + override fun onEnterForeground() { + mRootView?.let { + it.visibility = View.VISIBLE + } + } + + override fun onMove(x: Int, y: Int, dx: Int, dy: Int) { + if (!canDrag()) { + return + } + systemLayoutParams?.apply { + this.x += dx + this.y += dy + } + //限制布局边界 + resetBorderline(systemLayoutParams) + mWindowManager.updateViewLayout(mRootView, systemLayoutParams) + } + + /** + * 限制边界 调用的时候必须保证是在控件能获取到宽高德前提下 + */ + private fun resetBorderline( + windowLayoutParams: WindowManager.LayoutParams? + ) { + //如果是系统模式或者手动关闭动态限制边界 + if (!restrictBorderline()) { + return + } + + if (windowLayoutParams != null) { + + // 均是横向计算 + if (windowLayoutParams.y >= screenShortSideLength - mLogViewHeight) { + windowLayoutParams.y = screenShortSideLength - mLogViewHeight + } + // 均是横向计算 + if (windowLayoutParams.x >= screenLongSideLength - mLogViewWidth) { + windowLayoutParams.x = screenLongSideLength - mLogViewWidth + } + + //系统模式 + if (windowLayoutParams.y <= 0) { + windowLayoutParams.y = 0 + } + + if (windowLayoutParams.x <= 0) { + windowLayoutParams.x = 0 + } + } + } + + /** + * 手指弹起时保存当前浮标位置 + * + * @param x + * @param y + */ + override fun onUp(x: Int, y: Int) { + if (!canDrag()) { + return + } + if (!viewProps.edgePinned) { + endMoveAndRecord() + return + } + animatedMoveToEdge() + } + + private fun endMoveAndRecord() { + systemLayoutParams?.let { + mLastLogViewPosInfo.logViewWidth = it.x + mLastLogViewPosInfo.logViewHeight = it.y + } + } + + private fun animatedMoveToEdge() { + val viewSize = mRootView?.width ?: return + systemLayoutParams?.also { layoutAttrs -> + makeAnimator(layoutAttrs.x, viewSize, ViewGroup.LayoutParams.MATCH_PARENT) { + addUpdateListener { v -> + layoutAttrs.x = v.animatedValue as Int + mWindowManager.updateViewLayout(mRootView, layoutAttrs) + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + endMoveAndRecord() + } + }) + } + } + } + + private inline fun makeAnimator( + from: Int, + size: Int, + containerSize: Int, + setup: ValueAnimator.() -> Unit + ) { + if (size <= 0 || containerSize <= 0) return + ValueAnimator.ofInt( + from, + if (from <= (containerSize - size) / 2) 0 else (containerSize - size) + ) + .apply { + duration = 150L + setup() + } + .start() + } + + /** + * 手指按下时的操作 + * + * @param x + * @param y + */ + override fun onDown(x: Int, y: Int) { + if (!canDrag()) { + return + } + } + + /** + * home键被点击 只有系统悬浮窗控件才会被调用 + */ + open fun onHomeKeyPress() {} + + /** + * 菜单键被点击 只有系统悬浮窗控件才会被调用 + */ + open fun onRecentAppKeyPress() {} + + override fun onPause() {} + + /** + * 系统悬浮窗需要调用 + * + * @return + */ + val context: Context? + get() = if (mRootView != null) { + mRootView!!.context + } else { + null + } + + val resources: Resources? + get() = if (context == null) { + null + } else context!!.resources + + fun getString(@StringRes resId: Int): String? { + return if (context == null) { + null + } else context!!.getString(resId) + } + + private val isShow: Boolean + get() = mRootView?.isShown ?: false + + protected fun findViewById(@IdRes id: Int): T? { + if (mRootView == null) { + return null + } + return mRootView?.findViewById(id) + } + + /** + * 是否限制布局边界 + * + * @return + */ + open fun restrictBorderline(): Boolean { + return true + } + + /** + * 获取屏幕短边的长度(横屏) 不包含statusBar + * + * @return + */ + private val screenShortSideLength: Int + get() = ScreenUtils.getAppScreenHeight() + + /** + * 获取屏幕长边的长度(横屏) 不包含statusBar + * + * @return + */ + private val screenLongSideLength: Int + get() = ScreenUtils.getAppScreenWidth() + + /** + * 强制刷新当前view + */ + open fun immInvalidate() { + mRootView?.requestLayout() + } + + /** + * 广播接收器 系统悬浮窗需要调用 + */ + private inner class InnerReceiver : BroadcastReceiver() { + + private val SYSTEM_DIALOG_REASON_KEY = "reason" + private val SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps" + private val SYSTEM_DIALOG_REASON_HOME_KEY = "homekey" + + override fun onReceive(context: Context, intent: Intent) { + val action = intent.action + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS == action) { + val reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY) + if (reason != null) { + if (reason == SYSTEM_DIALOG_REASON_HOME_KEY) { + //点击home键 + onHomeKeyPress() + } else if (reason == SYSTEM_DIALOG_REASON_RECENT_APPS) { + //点击menu按钮 + onRecentAppKeyPress() + } + } + } + } + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsRecyclerAdapter.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsRecyclerAdapter.java new file mode 100644 index 0000000000..a3b5ebc955 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsRecyclerAdapter.java @@ -0,0 +1,148 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * 内置一个List的通用、简化的适用于RecyclerView的Adapter。 + */ +public abstract class AbsRecyclerAdapter extends RecyclerView.Adapter { + protected List mList; + private LayoutInflater mInflater; + protected Context mContext; + + public AbsRecyclerAdapter(Context context) { + if (context == null) { + return; + } + mContext = context; + mList = new ArrayList<>(); + mInflater = LayoutInflater.from(context); + } + + @NonNull + @Override + public final T onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = createView(mInflater, parent, viewType); + return createViewHolder(view, viewType); + } + + protected abstract T createViewHolder(View view, int viewType); + + /** + * 如果是通过LayoutInflater创建的View,不要绑定到父View,RecyclerView会负责添加。 + */ + protected abstract View createView(LayoutInflater inflater, ViewGroup parent, int viewType); + + @Override + public final void onBindViewHolder(T holder, int position) { + V data = mList.get(position); + holder.setData(data); + holder.bind(data, position); + } + + @Override + public int getItemCount() { + return mList.size(); + } + + /** + * 列表末尾追加一个元素 + */ + @SuppressLint("NotifyDataSetChanged") + public void append(V item) { + if (item == null) { + return; + } + mList.add(item); + notifyDataSetChanged(); + } + + /** + * 在特定位置增加一个元素 + */ + public void append(V item, int position) { + if (item == null) { + return; + } + if (position < 0) { + position = 0; + } else if (position > mList.size()) { + position = mList.size(); + } + mList.add(position, item); + notifyItemChanged(position, item); + } + + /** + * 追加一个集合 + */ + @SuppressLint("NotifyDataSetChanged") + public final void append(Collection items) { + if (items == null || items.size() == 0) { + return; + } + mList.addAll(items); + notifyDataSetChanged(); + } + + /** + * 清空集合 + */ + @SuppressLint("NotifyDataSetChanged") + public final void clear() { + if (mList.isEmpty()) { + return; + } + mList.clear(); + notifyDataSetChanged(); + } + + /** + * 删除一个元素 + */ + @SuppressLint("NotifyDataSetChanged") + public final void remove(V item) { + if (item == null) { + return; + } + if (mList.contains(item)) { + mList.remove(item); + notifyDataSetChanged(); + } + } + + /** + * 删除一个元素 + */ + public final void remove(int index) { + if (index < mList.size()) { + mList.remove(index); + notifyItemRemoved(index); + } + } + + /** + * 删除一个集合 + */ + @SuppressLint("NotifyDataSetChanged") + public final void remove(Collection items) { + if (items == null || items.size() == 0) { + return; + } + if (mList.removeAll(items)) { + notifyDataSetChanged(); + } + } + +} diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsViewBinder.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsViewBinder.java new file mode 100644 index 0000000000..c3c08f142e --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/AbsViewBinder.java @@ -0,0 +1,55 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch; + +import android.content.Context; +import android.view.View; + +import androidx.annotation.IdRes; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 简单封装的适用于RecyclerView的ViewHolder + */ +public abstract class AbsViewBinder extends RecyclerView.ViewHolder { + private T data; + + private View mView; + + public AbsViewBinder(final View view) { + super(view); + mView = view; + getViews(); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onViewClick(view, data); + } + }); + } + + protected final View getView() { + return mView; + } + + protected abstract void getViews(); + + public final V getView(@IdRes int id) { + return (V) mView.findViewById(id); + } + + public abstract void bind(T t); + + public void bind(T t, int position) { + bind(t); + } + + protected void onViewClick(View view, T data) { + } + + protected final void setData(T data) { + this.data = data; + } + + protected final Context getContext() { + return mView.getContext(); + } +} diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/ILogView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/ILogView.kt new file mode 100644 index 0000000000..4c49bd8610 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/ILogView.kt @@ -0,0 +1,82 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch + +import android.content.Context +import android.view.View +import android.widget.FrameLayout + +interface ILogView { + /** + * view 创建时调用 做一些变量的初始化 当还不能进行View的操作 + * + * @param context + */ + fun onCreate(context: Context?) + + /** + * 传入rootView 用于创建控件 + * + * @param context + * @param rootView + * @return 返回创建的childView + */ + fun onCreateView(context: Context?, rootView: FrameLayout?): View? + + /** + * 将xml中的控件添加到rootView以后调用,在当前方法中可以进行view的一些操作 + * + * @param rootView + */ + fun onViewCreated(rootView: FrameLayout?) + + /** + * 当前的View添加到根布局里时调用 + */ + fun onResume() + + /** + * 当前activity onPause时调用 + */ + fun onPause() + + /** + * 确定系统悬浮窗浮标的初始位置 + * LayoutParams创建完以后调用 + * + * @param params + */ + fun initViewLayoutParams(params: LogViewLayoutParams?) + + /** + * app进入后台时调用 内置View 不需要实现 + */ + fun onEnterBackground() + + /** + * app回到前台时调用 内置view 不需要实现 + */ + fun onEnterForeground() + + /** + * 浮标控件是否可以拖动 + * + * @return + */ + fun canDrag(): Boolean + + /** + * 是否需要自己处理返回键 + * + * @return + */ + fun shouldDealBackKey(): Boolean + + /** + * shouldDealBackKey == true 时调用 + */ + fun onBackPressed(): Boolean + + /** + * 悬浮窗主动销毁时调用 不能在当前生命周期回调函数中调用 detach自己 否则会出现死循环 + */ + fun onDestroy() +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/ILogViewListener.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/ILogViewListener.kt new file mode 100644 index 0000000000..16c65363b0 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/ILogViewListener.kt @@ -0,0 +1,6 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch + +interface ILogViewListener { + fun onAttach() + fun onDetach() +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LastLogViewPosInfo.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LastLogViewPosInfo.kt new file mode 100644 index 0000000000..3a6780a289 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LastLogViewPosInfo.kt @@ -0,0 +1,30 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch + +import com.mogo.eagle.core.utilcode.util.ScreenUtils + +/** + * 保存上一次LogView的位置信息 + */ +class LastLogViewPosInfo { + var logViewWidth = 0 + var logViewHeight = 0 + var leftMarginPercent = 0f + private set + var topMarginPercent = 0f + private set + + fun setLeftMargin(leftMargin: Int) { + leftMarginPercent = leftMargin.toFloat() / ScreenUtils.getAppScreenWidth().toFloat() + } + + fun setTopMargin(topMargin: Int) { + topMarginPercent = topMargin.toFloat() / ScreenUtils.getAppScreenHeight().toFloat() + } + + override fun toString(): String { + return "LastLogViewPosInfo{" + + ", leftMarginPercent=" + leftMarginPercent + + ", topMarginPercent=" + topMarginPercent + + '}' + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LogFrameLayout.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LogFrameLayout.kt new file mode 100644 index 0000000000..352ad9b2ea --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LogFrameLayout.kt @@ -0,0 +1,26 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout + +open class LogFrameLayout : FrameLayout { + private var mFlag = LogFrameLayoutFlag_ROOT + + constructor(context: Context, flag: Int) : super(context) { + mFlag = flag + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {} + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + } + + companion object { + const val LogFrameLayoutFlag_ROOT = 100 + const val LogFrameLayoutFlag_CHILD = 200 + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LogInfoView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LogInfoView.kt new file mode 100644 index 0000000000..6a8e8bf27c --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/logcatch/LogInfoView.kt @@ -0,0 +1,287 @@ +package com.mogo.eagle.core.function.hmi.ui.logcatch + +import android.annotation.SuppressLint +import android.content.Context +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.* +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.mogo.eagle.core.function.hmi.R +import java.util.* + +class LogInfoView : AbsLogView() { + + companion object { + const val MAX_LOG_LINE_NUM = 10000 + const val UPDATE_CHECK_INTERVAL = 200 + } + + private var logLines = LinkedList() + private var counter = 0 + private var mAutoScrollToBottom = true + private var mIsLoaded = false + + private var mLogRv: RecyclerView? = null + private var mLogItemAdapter: LogItemAdapter? = null + private var mLogFilter: EditText? = null + private var mRadioGroup: RadioGroup? = null + private var mLinearLayout: LinearLayout? = null + + /** + * 单行的log + */ + private var mLogHint: TextView? = null + private var mLogRvWrap: RelativeLayout? = null + + private var logViewListener: ILogViewListener? = null + + override fun onCreate(context: Context?) {} + override fun onCreateView(context: Context?, rootView: FrameLayout?): View? { + return LayoutInflater.from(context).inflate(R.layout.log_view, rootView, false) + } + + override fun onViewCreated(rootView: FrameLayout?) { + initView() + } + + private fun initView() { + mLogHint = findViewById(R.id.log_hint) + mLogRvWrap = findViewById(R.id.log_page) + mLogRv = findViewById(R.id.log_list) + mLogRv!!.layoutManager = LinearLayoutManager(context) + mLogItemAdapter = LogItemAdapter(context!!) + mLogRv!!.adapter = mLogItemAdapter + mLogFilter = findViewById(R.id.log_filter) + mLogFilter!!.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} + override fun afterTextChanged(s: Editable) { + mLogItemAdapter!!.filter.filter(s) + } + }) + val mTitleBar = findViewById(R.id.title_bar) + mTitleBar!!.setListener(object : LogTitleBar.OnTitleBarClickListener { + override fun onRightClick() { + if (logViewListener != null) { + logViewListener!!.onDetach() + } + } + + override fun onLeftClick() { + minimize() + } + }) + mLogHint!!.setOnClickListener { v: View? -> maximize() } + mRadioGroup = findViewById(R.id.radio_group) + mRadioGroup!!.setOnCheckedChangeListener { group: RadioGroup?, checkedId: Int -> + when (checkedId) { + R.id.verbose -> { + mLogItemAdapter!!.logLevelLimit = Log.VERBOSE + } + R.id.debug -> { + mLogItemAdapter!!.logLevelLimit = Log.DEBUG + } + R.id.info -> { + mLogItemAdapter!!.logLevelLimit = Log.INFO + } + R.id.warn -> { + mLogItemAdapter!!.logLevelLimit = Log.WARN + } + R.id.error -> { + mLogItemAdapter!!.logLevelLimit = Log.ERROR + } + } + mLogItemAdapter!!.filter.filter(mLogFilter!!.text) + } + mLogRv!!.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + } + + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + val layoutManager = recyclerView.layoutManager as LinearLayoutManager? + // if the bottom of the list isn't visible anymore, then stop autoscrolling + mAutoScrollToBottom = + layoutManager!!.findLastCompletelyVisibleItemPosition() == recyclerView.adapter!! + .itemCount - 1 + } + }) + mRadioGroup!!.check(R.id.verbose) + val mBtnTop = findViewById