Merge branch 'dev_MogoAP_eagle-220_211207_8.0.17_merge' into dev_robotaxi-p-app_254_220228_2.5.4

# Conflicts:
#	core/function-impl/mogo-core-function-hmi/build.gradle
#	core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt
#	core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/carcorder/CarcorderPreviewView.kt
#	core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_carcorder_preview.xml
#	libraries/map-usbcamera/build.gradle
#	libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/UVCCameraHelper.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/Size.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandler.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandlerMultiSurface.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IAudioEncoder.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IVideoEncoder.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaAudioEncoder.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaSurfaceEncoder.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoBufferEncoder.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/AACEncodeConsumer.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/H264EncodeConsumer.java
#	libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java
#	libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUVCCamera.so
#	libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libjpeg-turbo1500.so
#	libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libusb100.so
#	libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libuvc.so
#	libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so
#	libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so
#	libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so
#	libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so
#	libraries/map-usbcamera/src/main/jniLibs/x86/libUVCCamera.so
#	libraries/map-usbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so
#	libraries/map-usbcamera/src/main/jniLibs/x86/libusb100.so
#	libraries/map-usbcamera/src/main/jniLibs/x86/libuvc.so
#	libraries/map-usbcamera/src/main/jniLibs/x86_64/libUVCCamera.so
#	libraries/map-usbcamera/src/main/jniLibs/x86_64/libjpeg-turbo1500.so
#	libraries/map-usbcamera/src/main/jniLibs/x86_64/libusb100.so
#	libraries/map-usbcamera/src/main/jniLibs/x86_64/libuvc.so
This commit is contained in:
donghongyu
2022-03-01 16:12:57 +08:00
257 changed files with 19058 additions and 1047 deletions

View File

@@ -24,6 +24,7 @@ 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.AppIdentityModeUtils;
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;
@@ -134,7 +135,7 @@ public class MogoOCHTaxiModelNew {
if (NetworkUtils.isConnected(mContext)) {
// startOrStopOrderLoop(mOCHCarStatus == 1);
if (FunctionBuildConfig.appIdentityMode == 0x00) {
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
queryCarStatus();
}
}
@@ -821,7 +822,7 @@ public class MogoOCHTaxiModelNew {
Logger.d( TAG, "onIntentReceived = %s", intentStr );
if ( ConnectivityManager.CONNECTIVITY_ACTION.equals( intentStr ) ) {
if ( NetworkUtils.isConnected( mContext ) ) {
if (FunctionBuildConfig.appIdentityMode == 0x00) {
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
startOrStopOrderLoop(mOCHCarStatus == 1);
queryCarStatus();
}
@@ -941,7 +942,7 @@ public class MogoOCHTaxiModelNew {
mPrevAPStatus = state;
if (FunctionBuildConfig.isDemoMode
&& FunctionBuildConfig.appIdentityMode == 0x01) {
&& AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
// 当美化模式演示模式开启时且是乘客app、且未到终点时维持自动驾驶icon开启状态
if (!arriveAtEnd) {
return;
@@ -955,7 +956,7 @@ public class MogoOCHTaxiModelNew {
mPrevAPStatus = state;
if (FunctionBuildConfig.isDemoMode
&& FunctionBuildConfig.appIdentityMode == 0x01) {
&& AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
// 当美化模式演示模式开启时且是乘客app、且未到终点时维持自动驾驶icon开启状态
if (!arriveAtEnd) {
return;
@@ -981,7 +982,7 @@ public class MogoOCHTaxiModelNew {
@Override
public void onAutopilotArriveAtStation(@Nullable AutopilotStationInfo data) {
if (FunctionBuildConfig.isDemoMode
&& FunctionBuildConfig.appIdentityMode == 0x01) {
&& AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
arriveAtEnd = true;
}

View File

@@ -30,6 +30,7 @@ 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.hmi.CallerHmiManager;
import com.mogo.eagle.core.function.call.map.CallerSmpManager;
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.map.listener.IMogoMapListener;
import com.mogo.map.uicontroller.VisualAngleMode;
@@ -133,7 +134,7 @@ public abstract class BaseOchTaxiTabFragment<V extends IView, P extends Presente
@Override
public void onClickImpl(View v) {
// 如果能自动驾驶,就自动驾驶,不能就提示
if (FunctionBuildConfig.appIdentityMode == 0x00) {
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
restartAutopilot();
}
// TODO: 2021/11/27 通过开启结果更新ui
@@ -220,7 +221,7 @@ public abstract class BaseOchTaxiTabFragment<V extends IView, P extends Presente
showNaviToStartStationFragment(false);
});
if (FunctionBuildConfig.appIdentityMode == 0x01) {
if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
flStationPanelContainer.setVisibility(View.GONE);
tvOperationStatus.setVisibility(View.GONE);
mSettingBtn.setVisibility(View.GONE);

View File

@@ -12,6 +12,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.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
import com.mogo.module.common.MogoApisHandler;
import com.mogo.och.taxi.passenger.R;
@@ -85,7 +86,7 @@ public class OCHTaxiFragment extends BaseOchTaxiTabFragment<OCHTaxiFragment, OCH
switchVRFlatMode(false);
}
if (FunctionBuildConfig.appIdentityMode == 0x00) {
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
tvOperationStatus.setVisibility(View.VISIBLE);
} else {
tvOperationStatus.setVisibility(View.GONE);

21
ZD_README/README_Utils.md Normal file
View File

@@ -0,0 +1,21 @@
### 项目说明
* ### 应用身份 相关 -> [AppIdentityModeUtils.java][AppIdentityModeUtils.java] -> [Demo][AppIdentityModeUtils.java]
```
// 判断是否是 司机身份
AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)
// 判断是否是 乘客身份
AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)
// 判断是否是 小巴车
AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)
// 判断是否是 出租车
AppIdentityModeUtils.isTaxi(FunctionBuildConfig.appIdentityMode)
```

View File

@@ -5,9 +5,6 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'android-aspectjx'
apply plugin: 'bugly'
if (!isAndroidTestBuild()) {
apply plugin: 'apm-plugin'
}
//apply ByteX宿主
if (!isAndroidTestBuild()) {
@@ -18,73 +15,78 @@ if (!isAndroidTestBuild()) {
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
}
}
//if (!isAndroidTestBuild()) {
// apply plugin: 'apm-plugin'
//}
//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
}*/
bugly {
appId = 'ac71228f85' // 注册时分配的App ID
appKey = '3c736249-d6be-4066-b577-b7a6dc975cf7' // 注册时分配的App Key
@@ -254,31 +256,31 @@ dependencies {
androidTestImplementation rootProject.ext.dependencies.androidx_espresso_core
}
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 = [
]
}
}
//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"))

View File

@@ -29,7 +29,7 @@ project.android.productFlavors {
// 构建的应用身份类型,司机|乘客
buildConfigField 'int', 'APP_IDENTITY_MODE', "0x02"
// 连接的工控机IP地址
buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.1.102\""
buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.1.104\""
// 构建的是否是演示(美化)模式
buildConfigField 'boolean', 'IS_DEMO_MODE', 'true'
}

View File

@@ -28,8 +28,8 @@ project.android.productFlavors {
// GPS数据提供源 0-Android系统1-工控机2-OBU
buildConfigField 'int', 'GPS_PROVIDER', "1"
// 构建的应用身份类型,司机|乘客
buildConfigField 'int', 'APP_IDENTITY_MODE', "0x00"
// 构建的应用身份类型,出租车0|小巴A-司机|乘客
buildConfigField 'int', 'APP_IDENTITY_MODE', "0xA0"
// 连接的工控机IP地址
buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.8.102\""
// 构建的是否是演示(美化)模式

View File

@@ -26,8 +26,8 @@ project.android.productFlavors {
// GPS数据提供源 0-Android系统1-工控机2-OBU
buildConfigField 'int', 'GPS_PROVIDER', "1"
// 构建的应用身份类型司机0乘客1
buildConfigField 'int', 'APP_IDENTITY_MODE', "0x01"
// 构建的应用身份类型,出租车0|小巴A-司机0乘客1
buildConfigField 'int', 'APP_IDENTITY_MODE', "0xA1"
// 连接的工控机IP地址
buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.8.103\""
// 构建的是否是演示(美化)模式

View File

@@ -29,7 +29,7 @@ project.android.productFlavors {
// GPS数据提供源 0-Android系统1-工控机2-OBU
buildConfigField 'int', 'GPS_PROVIDER', "1"
// 构建的应用身份类型,司机|乘客
// 构建的应用身份类型,出租车0|小巴A-司机|乘客
buildConfigField 'int', 'APP_IDENTITY_MODE', "0x00"
// 连接的工控机IP地址
buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.1.102\""

View File

@@ -28,7 +28,7 @@ project.android.productFlavors {
// GPS数据提供源 0-Android系统1-工控机2-OBU
buildConfigField 'int', 'GPS_PROVIDER', "1"
// 构建的应用身份类型司机0乘客1
// 构建的应用身份类型,出租车0|小巴A-司机0乘客1
buildConfigField 'int', 'APP_IDENTITY_MODE', "0x01"
// 连接的工控机IP地址
buildConfigField 'String', 'ADAS_CONNECT_IP', "\"192.168.1.103\""

View File

@@ -0,0 +1,71 @@
package com.mogo.functions.test
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.mogo.eagle.core.function.hmi.ui.MoGoHmiFragment
import com.mogo.eagle.core.function.main.MainLauncherActivity
import com.mogo.eagle.core.utilcode.mogo.toast.TipToast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.MILLISECONDS
@RunWith(AndroidJUnit4::class)
@LargeTest
class TipToastLeakTest {
lateinit var launch: ActivityScenario<MainLauncherActivity>
@Before
fun before() {
launch = ActivityScenario.launch(MainLauncherActivity::class.java)
}
@Test
fun test() = runBlocking(Dispatchers.Main) {
val f = ensureMoGoHmiFragmentShow()
var index = 0
while (index < 50) {
delay(TimeUnit.SECONDS.toMillis(4))
TipToast.shortTip("toast-> $index" )
index ++
}
delay(TimeUnit.SECONDS.toMillis(1))
f.activity?.finish()
delay(TimeUnit.SECONDS.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, MILLISECONDS)
}
}
}

View File

@@ -89,6 +89,7 @@ public class MogoApplication extends MainMoGoApplication {
HmiBuildConfig.isShowPerspectiveSwitchView = false;
HmiBuildConfig.isShowToolsView = false;
HmiBuildConfig.isShowBadCaseView = false;
HmiBuildConfig.isShowUpgradeTipsView = false;
//业务端可以根据需要控制是否展示刹车和转向灯的ui
// HmiBuildConfig.isShowBrakeLightView = false;
// HmiBuildConfig.isShowTurnLightView = false;

View File

@@ -35,9 +35,7 @@ buildscript {
classpath 'com.volcengine:apm_insight_plugin:1.4.1'
classpath 'com.mogo.cloud:thread_opt:1.0.1'
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}"
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
// classpath ("com.tencent.matrix:matrix-gradle-plugin:0.6.6") { changing = true }
}

View File

@@ -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_bate21',
adasHigh : 'com.zhidao.support.adas:high:1.2.1.2_bate25',
// google
googlezxing : "com.google.zxing:core:3.3.3",
@@ -222,6 +222,7 @@ ext {
mogoaicloudtanlu : "com.mogo.cloud:tanlu:${MOGO_TANLU_VERSION}",
mogoaicloudtrafficlive : "com.mogo.cloud:trafficlive:${MOGO_TRAFFICLIVE_VERSION}",
mogoaicloudlocation : "com.mogo.cloud:location:${MOGO_LOCATION_VERSION}",
mogoaicloudtelematic : "com.mogo.cloud:telematic:${MOGO_TELEMATIC_VERSION}",
//========================= 新架构的 Maven 版本管理 =========================
mogo_core_function_autopilot : "com.mogo.eagle.core.function.impl:autopilot:${MOGO_CORE_FUNCTION_AUTOPILOT_VERSION}",
@@ -237,13 +238,14 @@ ext {
mogo_core_function_v2x : "com.mogo.eagle.core.function.impl:v2x:${MOGO_CORE_FUNCTION_V2X_VERSION}",
mogo_core_function_api : "com.mogo.eagle.core.function:api:${MOGO_CORE_FUNCTION_API_VERSION}",
mogo_core_function_call : "com.mogo.eagle.core.function:call:${MOGO_CORE_FUNCTION_CALL_VERSION}",
mogo_core_function_carcorder : "com.mogo.eagle.core.function:carcorder:${MOGO_CORE_FUNCTION_CARCORDER_VERSION}",
mogo_core_data : "com.mogo.eagle.core:data:${MOGO_CORE_DATA_VERSION}",
mogo_core_res : "com.mogo.eagle.core:res:${MOGO_CORE_RES_VERSION}",
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}",
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",

View File

@@ -2,25 +2,25 @@
本模块用来编写鹰眼核型功能
- function-impl 目录下编写的都是对mogo-core-function-api定的功能实现,
- 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 自车+云端预警模块
- check 程序及车辆检测模块
- devatools 开发工具模块日志采集、BadCase、
- hmi UI呈现及交互模块
- main 主入口(模块加载、后台服务启动、多进程启动等)
- map 地图相关的模块
- monitoring 行车超视距模块,路测摄像头、前车直播
- notice 云端公告、调度相关模块
- obu-mogo 自研OBU预警模块
- smp 小地图模块
- v2x 自车+云端预警模块
- mogo-core-data定义基础业务所需要的数据结构
- mogo-core-function-res这里只存放公共资源图片布局动画等
- mogo-core-network公共网络请求
- mogo-core-function-api定义基础业务功能的接口
- mogo-core-function-call定义基础业务暴露给外部调用的接口,对function-impl的二次封装,只将能对外调用的功能进行封装
- mogo-core-res程序中涉及到的图片及布局资源同一管理并通过设置不同的目录指定是那个模块的资源
- mogo-core-res程序中涉及到的图片及布局资源同一管理并通过设置不同的目录指定是那个模块的资源,这里只存放公共资源,图片,布局,动画等
- mogo-core-utils基于成熟的工具类开源框架下沉的这里可以增添针对我们业务上的一些工具类

View File

@@ -51,18 +51,20 @@ dependencies {
kapt rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.adasHigh
implementation rootProject.ext.dependencies.mogochainbase
implementation rootProject.ext.dependencies.mogoami
implementation rootProject.ext.dependencies.mogoaicloudtelematic
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation rootProject.ext.dependencies.mogo_core_data
implementation rootProject.ext.dependencies.modulecommon
implementation rootProject.ext.dependencies.moduleservice
implementation rootProject.ext.dependencies.mogo_core_data
implementation rootProject.ext.dependencies.mogo_core_utils
implementation rootProject.ext.dependencies.mogo_core_network
implementation rootProject.ext.dependencies.mogo_core_function_api
implementation rootProject.ext.dependencies.mogo_core_function_call
implementation rootProject.ext.dependencies.adasHigh
} else {
implementation project(':modules:mogo-module-common')
implementation project(':modules:mogo-module-service')
@@ -72,6 +74,7 @@ dependencies {
implementation project(':core:mogo-core-network')
implementation project(':core:mogo-core-function-api')
implementation project(':core:mogo-core-function-call')
implementation project(':libraries:mogo-adas')
}
}

View File

@@ -4,6 +4,7 @@ import android.Manifest.permission
import android.content.Context
import androidx.annotation.RequiresPermission
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.eagle.core.data.autopilot.AutopilotControlCmdParameter
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
import com.mogo.eagle.core.data.config.FunctionBuildConfig
@@ -21,10 +22,12 @@ import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr
import com.mogo.eagle.core.utilcode.util.GsonUtils
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.zhidao.support.adas.high.AdasManager
import com.zhidao.support.adas.high.AdasOptions
import com.zhidao.support.adas.high.bean.IPCUpgradeInfo
import com.zhidao.support.adas.high.common.CupidLogUtils
import java.util.concurrent.TimeUnit
/**
* @author xiaoyuzhou
* @date 2021/9/22 8:43 下午
@@ -32,7 +35,7 @@ import java.util.concurrent.TimeUnit
*/
@Route(path = MogoServicePaths.PATH_AUTO_PILOT)
class MoGoAutopilotProvider :
IMoGoAutopilotProvider, IMoGoMapDataCollectProvider.OnMapCollectCmdListener {
IMoGoAutopilotProvider, IMoGoMapDataCollectProvider.OnMapCollectCmdListener {
private val TAG = "MoGoAutoPilotProvider"
private var mContext: Context? = null
@@ -50,24 +53,121 @@ class MoGoAutopilotProvider :
when (FunctionBuildConfig.appIdentityMode) {
0x00 -> // 司机
{
// 注册地图采集功能
CallerMapDataCollectorManager.registerOnMapCollectTaskListener(this)
AdasManager.getInstance().create(context, FunctionBuildConfig.adasConnectIP)
// "192.168.1.102"
val options = AdasOptions.Builder()
.setIPCIp(FunctionBuildConfig.adasConnectIP)
.setClient(false)
.build()
AdasManager.getInstance().create(context, options)
// NSDNettyManager.getInstance().startNSDNettyServer(context, object : NettyServerListener<MogoProtocolMsg> {
// override fun onMessageResponseServer(msg: MogoProtocolMsg?, channel: Channel?) {
// Logger.d(TAG, "Receive client data is:${msg?.toString()}")
// }
//
// override fun onStartServer() {
// ToastUtils.showShort("司机端服务启动成功!")
// Logger.d(TAG, "onStartServer")
// }
//
// override fun onStopServer() {
// ToastUtils.showLong("司机端服务停止!")
// Logger.d(TAG, "onStopServer")
// }
//
// override fun onChannelConnect(channel: Channel?) {
// NSDNettyManager.getInstance().selectChannel(channel)
// val socketAddress = channel?.remoteAddress().toString()
// Logger.d(TAG, "Client ip is:${socketAddress}")
// }
//
// override fun onChannelDisConnect(channel: Channel?) {
// Logger.d(TAG, "onChannelDisConnect")
// }
// })
}
0x01 -> // 乘客
{
// 乘客端默认接收绘制全局路径+引导线
//FunctionBuildConfig.isDemoMode = true
//FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData = true
AdasManager.getInstance().create(context, FunctionBuildConfig.adasConnectIP)
// "192.168.1.102"
val options = AdasOptions
.Builder()
.setClient(true)
.build()
AdasManager.getInstance().create(context, options)
// NSDNettyManager.getInstance().searchAndConnectServer(context, MoGoAiCloudClientConfig.getInstance().sn, object : NettyClientListener<MogoProtocolMsg> {
// override fun onMessageResponseClient(msg: MogoProtocolMsg?, sign: String?) {
// Logger.d(TAG, "收到司机端的数据!")
// // 乘客端收到adas数据直接解析后续分发解析后的数据流程同司机端
// msg?.let {
// AdasManager.getInstance().parseIPCData(it.body)
// Logger.d(TAG, "解析司机端数据完毕!")
// }
// }
//
// override fun onClientStatusConnectChanged(statusCode: Int, sign: String?) {
// when (statusCode) {
// ConnectState.STATUS_CONNECT_SUCCESS -> Logger.d(TAG, "乘客端连接司机端服务成功! sign is:${sign}")
// else -> {
// ToastUtils.showLong("和司机端连接异常!")
// Logger.d(TAG, "client statusCode is:${statusCode}")
// }
// }
// }
// })
}
//
else -> // 默认采用UDP寻址方式
AdasManager.getInstance().create(context)
{
val options = AdasOptions.Builder()
.setClient(false)
.setIPCIp(FunctionBuildConfig.adasConnectIP)
.build()
AdasManager.getInstance().create(context, options)
}
}
//////////////////////////////////注意先后顺序AdasManager.getInstance().create后才可以设置监听/////////////////////////////////////////////
// 监听 adas 连接状态
AdasManager.getInstance().setOnAdasConnectStatusListener(MoGoAdasMsgConnectStatusListenerImpl())
// 监听ADAS-SDK获取到的工控机数据
AdasManager.getInstance()
.setOnAdasConnectStatusListener(MoGoAdasMsgConnectStatusListenerImpl())
// 监听ADAS-SDK获取到的工控机数据(乘客也需注册)
AdasManager.getInstance().setOnAdasListener(MoGoAdasListenerImpl())
// // 司机端监听
// if (FunctionBuildConfig.appIdentityMode == 0) {
// AdasManager.getInstance().setOnMultiDeviceListener { bytes ->
// Logger.d(
// TAG,
// "司机端接收到工控机吐出来的数据为:${Arrays.toString(bytes)}"
// )
// // 发送数据给乘客端
// if (NSDNettyManager.getInstance().isServerStart) {
// Logger.d(
// TAG,
// "司机端透传数据给乘客端!"
// )
// NSDNettyManager.getInstance().sendMsgToAllClients(MogoProtocolMsg(NORMAL_DATA, bytes.size, bytes))
//// NSDNettyManager.getInstance().sendMogoProtocolMsgToClient(MogoProtocolMsg(NORMAL_DATA, bytes.size, bytes)) { channelFuture: ChannelFuture ->
//// if (channelFuture.isSuccess) {
//// Logger.d(
//// TAG,
//// "Send data to client is success."
//// )
//// } else {
//// Logger.d(
//// TAG,
//// "Send data to client is failure."
//// )
//// }
//// }
// } else {
// Logger.d(TAG, "司机端Server未启动")
// }
// }
// }
// 同步数据给工控机的服务
AsyncDataToAutopilotServer.INSTANCE.initServer()
// 同步是否开启美化模式
@@ -87,7 +187,9 @@ class MoGoAutopilotProvider :
@RequiresPermission(permission.INTERNET)
override fun doInBackground(): String {
// 保存本地 AutoPilot IP地址
mContext?.let { SharedPrefsMgr.getInstance(it).putString(MoGoConfig.AUTOPILOT_IP, autoPilotIp) }
mContext?.let {
SharedPrefsMgr.getInstance(it).putString(MoGoConfig.AUTOPILOT_IP, autoPilotIp)
}
// 设置IP地址
AdasManager.getInstance().setIPCIp(autoPilotIp)
// 打开通讯连接
@@ -134,7 +236,7 @@ class MoGoAutopilotProvider :
override fun recordPackage(): Boolean {
return AdasManager.getInstance()
.recordPackage(1, (System.currentTimeMillis() / 1000).toInt())
.recordPackage(1, (System.currentTimeMillis() / 1000).toInt())
}
override fun recordPackage(type: Int, id: Int): Boolean {

View File

@@ -1,5 +1,17 @@
package com.mogo.eagle.core.function.autopilot.adapter;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_ARRIVE;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_GUARDIAN;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_RECORD;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_ROUTE;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_STATUS;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_TRAJECTORY;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_WARN;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_CAR_STATE;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_ALIAS_CODE_ADAS_MESSAGE_RECT_DATA;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_LINK_ADAS;
import static com.mogo.eagle.core.data.chain.ChainConstant.CHAIN_LINK_LOG_WEB_SOCKET_DATA;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -42,6 +54,8 @@ import com.zhidao.support.adas.high.bean.WarnMessageInfo;
import com.zhidao.support.adas.high.bean.guardian.AutopilotGuardianInfo;
import com.zhidao.support.adas.high.bean.record.AutopilotRecordResult;
import com.zhidao.support.obu.ami.AmiClientManager;
import com.zhjt.service.chain.ChainLog;
import com.zhjt.service.chain.TracingConstants;
import org.json.JSONObject;
@@ -57,7 +71,12 @@ import java.util.List;
public class MoGoAdasListenerImpl implements OnAdasListener {
private final String TAG = "OnAdasListenerAdapter";
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_RECT_DATA,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onRectData(RectInfo rectInfo) {
if (HdMapBuildConfig.isMapLoaded) {
@@ -66,6 +85,12 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
}
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_CAR_STATE,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onCarStateData(CarStateInfo carStateInfo) {
if (HdMapBuildConfig.isMapLoaded) {
@@ -145,6 +170,12 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
}
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_STATUS,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void autopilotStatus(AutopilotStatus autopilotStatus) {
if (HdMapBuildConfig.isMapLoaded) {
@@ -177,10 +208,16 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
}
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_ARRIVE,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void autopilotArrive(AutopilotWayArrive autopilotWayArrive) {
if (HdMapBuildConfig.isMapLoaded) {
Logger.d(TAG, "autopilotArrive : " + autopilotWayArrive);
// Logger.d(TAG, "autopilotArrive : " + autopilotWayArrive);
if (autopilotWayArrive != null) {
AutopilotWayArrive.ResultBean result = autopilotWayArrive.getResult();
if (result != null) {
@@ -195,19 +232,30 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
}
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_ROUTE,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onAutopilotRoute(AutopilotRoute route) {
if (HdMapBuildConfig.isMapLoaded) {
Logger.d(TAG, "onAutopilotRoute : " + route.toString());
// Logger.d(TAG, "onAutopilotRoute : " + route.toString());
AutopilotRouteInfo autopilotRoute = AdasObjectConvertUtils.INSTANCE.fromAdasAutopilotRoute(route);
CallerAutopilotPlanningListenerManager.INSTANCE.invokeAutopilotRotting(autopilotRoute);
}
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_TRAJECTORY,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onAutopilotTrajectory(List<TrajectoryInfo> trajectoryList) {
if (HdMapBuildConfig.isMapLoaded) {
Logger.d(TAG, "onAutopilotTrajectory : " + trajectoryList);
// Logger.d(TAG, "onAutopilotTrajectory : " + trajectoryList);
ArrayList<ADASTrajectoryInfo> trajectoryInfoArrayList = new ArrayList<>();
if (trajectoryList != null && trajectoryList.size() > 0) {
for (TrajectoryInfo trajectory : trajectoryList) {
@@ -223,7 +271,7 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
adasTrajectoryInfo.setTheta(trajectory.getTheta());
trajectoryInfoArrayList.add(adasTrajectoryInfo);
}
Log.e(TAG, "time:" + System.currentTimeMillis() + "trajectoryInfoArrayList:" + trajectoryInfoArrayList);
// Log.e(TAG, "time:" + System.currentTimeMillis() + "trajectoryInfoArrayList:" + trajectoryInfoArrayList);
}
CallerAutopilotPlanningListenerManager.INSTANCE.invokeAutopilotTrajectory(trajectoryInfoArrayList);
}
@@ -234,6 +282,12 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
CallerAutoPilotStatusListenerManager.INSTANCE.invokeAutopilotSNRequest();
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_GUARDIAN,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onAutopilotGuardian(AutopilotGuardianInfo guardianInfo) {
if (HdMapBuildConfig.isMapLoaded) {
@@ -242,6 +296,12 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
}
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_RECORD,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onAutopilotRecord(AutopilotRecordResult result) {
if (result != null) {
@@ -276,7 +336,12 @@ public class MoGoAdasListenerImpl implements OnAdasListener {
}
// @ChainLog(linkCode = CHAIN_LINK_ADAS,
// linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_DATA,
// endpoint = TracingConstants.Endpoint.PAD,
// nodeAliasCode = CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_WARN,
// paramIndexes = {0},
// clientPkFileName = "sn")
@Override
public void onWarnMessage(WarnMessageInfo warnMessageInfo) {
final AutopilotWarnMessage warnMessage = AdasObjectConvertUtils.INSTANCE.fromAdasObject(warnMessageInfo);

View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,75 @@
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-android-extensions'
id 'kotlin-kapt'
id 'com.alibaba.arouter'
}
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
//ARouter apt 参数
kapt {
useBuildCache = false
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.kotlinstdlibjdk7
implementation rootProject.ext.dependencies.coroutinescore
implementation rootProject.ext.dependencies.arouter
kapt rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.mogologlib
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation rootProject.ext.dependencies.mogoserviceapi
implementation rootProject.ext.dependencies.modulecommon
implementation project(':libraries:map-usbcamera')
implementation rootProject.ext.dependencies.mogo_core_utils
implementation rootProject.ext.dependencies.mogo_core_function_api
implementation rootProject.ext.dependencies.mogo_core_function_call
implementation rootProject.ext.dependencies.mogo_core_data
}else {
implementation project(':services:mogo-service-api')
implementation project(':modules:mogo-module-common')
implementation project(':libraries:map-usbcamera')
implementation project(':core:mogo-core-utils')
implementation project(':core:mogo-core-function-api')
implementation project(':core:mogo-core-function-call')
implementation project(':core:mogo-core-data')
}
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

@@ -0,0 +1,3 @@
GROUP=com.mogo.eagle.core.function.impl
POM_ARTIFACT_ID=carcorder
VERSION_CODE=1

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.eagle.core.function.carcorder">
<application>
<service
android:name=".service.CarcorderService"
android:enabled="true"
android:exported="true"
android:process=":uvcservice">
<intent-filter>
<action android:name="com.mogo.launcher.action.CARCORDER_SERVICE" />
</intent-filter>
</service>
</application>
</manifest>

View File

@@ -0,0 +1,162 @@
package com.mogo.eagle.core.function.carcorder.service
import android.content.Intent
import android.hardware.usb.UsbDevice
import android.os.IBinder
import android.util.Log
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
import com.mogo.usbcamera.UVCCameraHelper
import com.serenegiant.usb.IFrameCallback
import com.serenegiant.usb.USBMonitor
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener
import com.serenegiant.usb.USBMonitor.UsbControlBlock
import com.serenegiant.usb.UVCCamera
import com.serenegiant.usb.common.BaseService
import com.serenegiant.usb.encoder.MediaVideoBufferEncoder
/**
* 行车记录仪服务
* @author donghongyu
*/
class CarcorderService : BaseService() {
private val DEBUG = true
val TAG = CarcorderService::class.java.name
// 挂载的USB设备集合
private var mDeviceList: List<UsbDevice>? = null
// USB 设备连接工具
private var mUSBMonitor: USBMonitor? = null
// 用于接入UVC摄像机
private var mUVCCamera: UVCCamera? = null
// 相机控制
private var mCtrlBlock: UsbControlBlock? = null
/**
* 配置相机基本按书
*/
private val previewWidth = 640
private val previewHeight = 480
// Default using MJPEG
// if your device is connected,but have no images
// please try to change it to FRAME_FORMAT_YUYV
val FRAME_FORMAT_MJPEG: Int = UVCCamera.FRAME_FORMAT_MJPEG
val MODE_BRIGHTNESS = UVCCamera.PU_BRIGHTNESS
val MODE_CONTRAST = UVCCamera.PU_CONTRAST
private val mFrameFormat = UVCCameraHelper.FRAME_FORMAT_MJPEG
override fun onCreate() {
super.onCreate()
if (DEBUG) {
Logger.d(TAG, "onCreate……")
}
if (mUSBMonitor == null) {
mUSBMonitor = USBMonitor(applicationContext, mOnDeviceConnectListener)
mUSBMonitor!!.register()
mDeviceList = mUSBMonitor!!.deviceList
}
}
override fun onDestroy() {
super.onDestroy()
if (DEBUG) Log.d(TAG, "onDestroy:")
if (mUSBMonitor != null) {
mUSBMonitor!!.unregister()
mUSBMonitor = null
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onRebind(intent: Intent) {
if (DEBUG) Log.d(TAG, "onRebind:$intent")
}
override fun onUnbind(intent: Intent): Boolean {
if (DEBUG) Log.d(TAG, "onUnbind:$intent")
if (DEBUG) Log.d(TAG, "onUnbind:finished")
return true
}
//**********************************************************************************************************************************
private val mSync: Any = Any()
private val mVideoEncoder: MediaVideoBufferEncoder? = null
/**
* USB 设备连接监听
*/
private val mOnDeviceConnectListener: OnDeviceConnectListener = object : OnDeviceConnectListener {
override fun onAttach(device: UsbDevice) {
if (DEBUG) Log.d(TAG, "OnDeviceConnectListener#onAttach:${device.deviceName}---mDeviceList:${mDeviceList?.size}")
mUSBMonitor!!.requestPermission(device)
}
override fun onConnect(device: UsbDevice, ctrlBlock: UsbControlBlock, createNew: Boolean) {
if (DEBUG) Log.d(TAG, "OnDeviceConnectListener#onConnect:${device.deviceName}")
openCamera(device, ctrlBlock, createNew)
}
override fun onDisconnect(device: UsbDevice, ctrlBlock: UsbControlBlock) {
if (DEBUG) Log.d(TAG, "OnDeviceConnectListener#onDisconnect:${device.deviceName}")
}
override fun onDettach(device: UsbDevice) {
if (DEBUG) Log.d(TAG, "OnDeviceConnectListener#onDettach:${device.deviceName}")
}
override fun onCancel(device: UsbDevice) {
if (DEBUG) Log.d(TAG, "OnDeviceConnectListener#onCancel:${device.deviceName}")
}
}
/**
* 连接相机
*/
private fun openCamera(device: UsbDevice, ctrlBlock: UsbControlBlock, createNew: Boolean) {
if (mUVCCamera == null) {
mUVCCamera = UVCCamera()
mUVCCamera!!.open(ctrlBlock)
mUVCCamera!!.setStatusCallback { statusClass, event, selector, statusAttribute, data ->
if (DEBUG) Log.d(TAG, "IStatusCallback#onStatus(statusClass=${statusClass},event=${event},selector=${selector},statusAttribute=${statusAttribute},data=${data})")
}
try {
mUVCCamera!!.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG)
} catch (e: Exception) {
e.printStackTrace()
try {
mUVCCamera!!.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE)
} catch (e: Exception) {
e.printStackTrace()
mUVCCamera!!.destroy()
}
}
mUVCCamera!!.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP)
mUVCCamera!!.startPreview()
}
}
/**
* 视频帧回掉
*/
private val mIFrameCallback = IFrameCallback { frame ->
if (DEBUG) Log.d(TAG, "IFrameCallback#onFrame:${frame}")
}
}

View File

@@ -0,0 +1,53 @@
package com.mogo.eagle.core.function.carcorder.service
import android.content.Intent
import android.os.IBinder
import android.util.Log
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
import com.serenegiant.usb.common.BaseService
/**
* 行车记录仪服务
* @author donghongyu
*/
class LivePushService : BaseService() {
private val DEBUG = true
val TAG = LivePushService::class.java.name
override fun onCreate() {
super.onCreate()
if (DEBUG) {
Logger.d(TAG, "onCreate……")
}
}
override fun onDestroy() {
super.onDestroy()
if (DEBUG) Log.d(TAG, "onDestroy:")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onRebind(intent: Intent) {
if (DEBUG) Log.d(TAG, "onRebind:$intent")
}
override fun onUnbind(intent: Intent): Boolean {
if (DEBUG) Log.d(TAG, "onUnbind:$intent")
if (DEBUG) Log.d(TAG, "onUnbind:finished")
return true
}
}

View File

@@ -48,6 +48,7 @@ dependencies {
implementation rootProject.ext.dependencies.arouter
kapt rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.mogologlib
implementation rootProject.ext.dependencies.mogochainbase
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation rootProject.ext.dependencies.mogoserviceapi

View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zhjt.mogo_core_function_devatools">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
</manifest>

View File

@@ -1,29 +1,105 @@
package com.zhjt.mogo_core_function_devatools
import android.annotation.SuppressLint
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_ADAS_INIT
import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_ADAS_MSG
import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_CONNECT_STATUS
import com.mogo.eagle.core.data.chain.ChainConstant.Companion.CHAIN_LINK_LOG_WEB_SOCKET_DATA
import com.mogo.eagle.core.data.chain.ChainLogParam
import com.mogo.eagle.core.data.constants.MoGoConfig
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr
import com.mogo.eagle.core.utilcode.util.DeviceUtils
import com.mogo.eagle.core.utilcode.util.Utils
import com.zhidao.loglib.fw.FileWriteManager
import com.zhidao.loglib.fw.FwBuild
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchManager
import com.zhjt.service.chain.core.ChainTraceStarter
@Route(path = MogoServicePaths.PATH_DEVA_TOOLS)
class DevaToolsProvider : IDevaToolsProvider {
private val traceInfoCache = hashMapOf<Int, ChainLogParam>()
private val fwBuildMap: MutableMap<Int, FwBuild> = HashMap()
override val functionName: String
get() = "DevaToolsProvider"
override fun init(context: Context) {
MogoLogCatchManager.init(context)
logCheck(context)
initTrace(context)
}
private fun logCheck(context: Context) {
val logger = SharedPrefsMgr.getInstance(context).getBoolean(MoGoConfig.CATCH_LOG, false)
val loggerTime = SharedPrefsMgr.getInstance(context).getLong(MoGoConfig.CATCH_LOG_TIME, 0)
val logCatchDuration = (System.currentTimeMillis() - loggerTime) / 1000 / 60
if (logger && loggerTime > 0) {
val logTime: Int = if (10 - logCatchDuration < 1) {
1
} else {
10 - logCatchDuration.toInt()
}
MogoLogCatchManager.startCatchLog(logTime)
} else {
Logger.d(
functionName,
"logCheck logger : $logger , logCatchDuration : $logCatchDuration"
)
}
}
override fun startLogCatch() {
MogoLogCatchManager.startCatchLog()
}
override fun startLogCatch(duration: Int) {
MogoLogCatchManager.startCatchLog(duration)
}
override fun stopLogCatch() {
MogoLogCatchManager.stopCatchLog()
}
private fun initTrace(context: Context) {
// 初始化Trace抓取服务
val pkgName = Utils.getApp().packageName
ChainTraceStarter.start(pkgName, DeviceUtils.getMacAddress(), BuildConfig.DEBUG)
// Trace过程中进行日志抓取对日志进行配置
fwBuildMap[CHAIN_LINK_LOG_CONNECT_STATUS] =
FwBuild(true, pkgName + CHAIN_LINK_LOG_ADAS_INIT, 5_000)
fwBuildMap[CHAIN_LINK_LOG_WEB_SOCKET_DATA] =
FwBuild(false, pkgName + CHAIN_LINK_LOG_ADAS_MSG, 500)
traceInfoCache[CHAIN_LINK_LOG_CONNECT_STATUS] = ChainLogParam(true, "ADAS连接状态")
traceInfoCache[CHAIN_LINK_LOG_WEB_SOCKET_DATA] = ChainLogParam(false, "ADAS长链数据")
FileWriteManager.getInstance()
.init(context, MoGoAiCloudClientConfig.getInstance().sn, pkgName, fwBuildMap)
}
override fun getTraceInfo(): HashMap<Int, ChainLogParam> {
return traceInfoCache
}
@SuppressLint("NewApi")
override fun refreshTraceInfo(map: HashMap<Int, ChainLogParam>) {
map.forEach { (type, param) ->
val fwBuild = this.fwBuildMap[type]
fwBuild?.let {
Logger.d(functionName, "param : ${param.des} , record : ${param.record}")
it.isRecord = param.record
}
}
FileWriteManager.getInstance().operateChainMap(fwBuildMap)
}
override fun onDestroy() {
MogoLogCatchManager.onDestroy()
}

View File

@@ -7,13 +7,14 @@ import android.os.Message
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.debug.DebugConfig
import com.mogo.eagle.core.data.constants.MoGoConfig
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.storage.SharedPrefsMgr
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.zhidao.loglib.bean.RemoteLogPushContent
@@ -25,7 +26,6 @@ import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchConst.Companio
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchConst.Companion.LOG_PUSH_TYPE
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchConst.Companion.START_CATCH_LOG
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchConst.Companion.STOP_CATCH_LOG
import java.io.File
@SuppressLint("StaticFieldLeak")
object MogoLogCatchManager : IMogoOnMessageListener<RemoteLogPushContent>, Handler.Callback,
@@ -47,7 +47,6 @@ object MogoLogCatchManager : IMogoOnMessageListener<RemoteLogPushContent>, Handl
MogoApisHandler.getInstance().apis
.getSocketManagerApi(AbsMogoApplication.getApp().applicationContext)
.registerOnMessageListener(LOG_PUSH_TYPE, this)
manualContent.duration = 10
manualContent.pkgName = context.packageName
}
@@ -80,12 +79,13 @@ object MogoLogCatchManager : IMogoOnMessageListener<RemoteLogPushContent>, Handl
return false
}
fun startCatchLog() {
fun startCatchLog(duration:Int = 10) {
if (catchingList.contains(MANUAL_CATCH_PKG_NAME)) {
TipToast.shortTip("已经在抓取日志了,请稍后再试")
} else {
Logger.d(TAG, "开始抓取日志====")
Logger.d(TAG, "开始抓取日志==== duration : $duration")
manualContent.type = START_CATCH_LOG
manualContent.duration = duration
startCatchLog(manualContent)
}
}
@@ -101,20 +101,28 @@ object MogoLogCatchManager : IMogoOnMessageListener<RemoteLogPushContent>, Handl
var delay = (content.duration).toLong()
handler.removeMessages(MSG_TRY_CLOSE_LOG)
if (delay <= 0) {
// 如果push 下来的delay小于等于0那就给个默认最大值一小时
// 如果push 下来的delay小于等于0那就给个默认
delay = 10
}
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
MoGoAiCloudClientConfig.getInstance().sn,
content,
this
)
logInfoManager?.start()
logInfoManager?.registerLogOutListener { lineLog ->
CallerDevaToolsListenerManager.invokeDevaToolsLogCatchLines(lineLog)
}
SharedPrefsMgr.getInstance(mContext!!).putBoolean(MoGoConfig.CATCH_LOG, true)
SharedPrefsMgr.getInstance(mContext!!)
.putLong(MoGoConfig.CATCH_LOG_TIME, System.currentTimeMillis())
}
private fun stopCatchLog(content: RemoteLogPushContent) {
@@ -125,6 +133,9 @@ object MogoLogCatchManager : IMogoOnMessageListener<RemoteLogPushContent>, Handl
logInfoManager?.stop()
logInfoManager = null
closeLoggerLevel()
SharedPrefsMgr.getInstance(mContext!!).putBoolean(MoGoConfig.CATCH_LOG, false)
SharedPrefsMgr.getInstance(mContext!!).putLong(MoGoConfig.CATCH_LOG_TIME, 0)
}
/**
@@ -152,6 +163,10 @@ object MogoLogCatchManager : IMogoOnMessageListener<RemoteLogPushContent>, Handl
override fun onClose(pkgName: String?) {
ThreadUtils.runOnUiThread {
SharedPrefsMgr.getInstance(mContext!!).putBoolean(MoGoConfig.CATCH_LOG, false)
SharedPrefsMgr.getInstance(mContext!!).putLong(MoGoConfig.CATCH_LOG_TIME, 0)
CallerDevaToolsListenerManager.invokeDevaToolsLogCatchClose()
TipToast.shortTip("日志抓取默认计时结束")
}

View File

@@ -59,8 +59,8 @@ dependencies {
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation rootProject.ext.dependencies.androidxrecyclerview
implementation rootProject.ext.dependencies.modulecommon
compileOnly rootProject.ext.dependencies.mogoserviceapi
implementation project(':libraries:map-usbcamera')
implementation rootProject.ext.dependencies.mogo_core_res
@@ -76,7 +76,7 @@ dependencies {
implementation project(':core:mogo-core-res')
implementation project(':core:mogo-core-data')
implementation project(':core:mogo-core-utils')
implementation project(':core:mogo-core-res')
implementation project(':core:mogo-core-network')
implementation project(':core:mogo-core-function-api')
implementation project(':core:mogo-core-function-call')
}

View File

@@ -5,12 +5,16 @@ import android.os.Bundle
import android.os.Handler
import android.text.TextUtils
import android.util.Log
import android.view.*
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.animation.OvershootInterpolator
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.lifecycleScope
import androidx.transition.*
import androidx.transition.AutoTransition
import androidx.transition.TransitionManager
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.commons.mvp.MvpFragment
@@ -37,7 +41,6 @@ import com.mogo.eagle.core.function.hmi.notification.WarningFloat
import com.mogo.eagle.core.function.hmi.notification.anim.DefaultAnimator
import com.mogo.eagle.core.function.hmi.notification.enums.SidePattern
import com.mogo.eagle.core.function.hmi.ui.camera.CameraListView
import com.mogo.eagle.core.function.hmi.ui.carcorder.CarcorderPreviewView
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
@@ -99,6 +102,8 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
private var onBadCaseShow: (() -> View)? = null
private var onBadCaseHide: (() -> Unit)? = null
private var upgradeTipsView: (() -> View)? = null
companion object {
private const val MSG_WHAT_DISMISS_BAD_CASE_ENTRY = 0x1010
private val CASE_EXPIRE_DURATION = TimeUnit.HOURS.toMillis(4)
@@ -117,7 +122,8 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
Log.d("QQQ", "-- step -- 1 --")
var oldT = try {
old?.timestamp?.takeIf { it.isNotBlank() }?.let {
SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time ?: 0L
SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time
?: 0L
} ?: 0L
} catch (t: Throwable) {
t.printStackTrace()
@@ -127,30 +133,31 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
var newT = try {
it.receive()?.also { record = it }?.timestamp?.takeIf { it.isNotBlank() }?.let {
SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time
?: 0L
?: 0L
} ?: 0L
} catch (t: Throwable) {
t.printStackTrace()
0L
}
if (oldT == 0L || (newT > 0L && (newT - oldT > 0L) && (newT - oldT) < CASE_EXPIRE_DURATION)) {
if (oldT == 0L || (newT > 0L && (newT - oldT > 0L) && (newT - oldT) < CASE_EXPIRE_DURATION)) {
Log.d("QQQ", "-- step -- 2 --")
record?.takeIf { it.key != old?.key && it.timestamp != old?.timestamp }?.also {
Log.d("QQQ", "record: [$record] is displaying and consuming ~~~" )
Log.d("QQQ", "record: [$record] is displaying and consuming ~~~")
showBadCaseEntrance(it)
}
continue
}
while (oldT != 0L && newT != 0L && (newT - oldT) >= CASE_EXPIRE_DURATION) {
Log.d("QQQ", "record: [$record] has been discarded, because it has been timeout." )
Log.d("QQQ", "record: [$record] has been discarded, because it has been timeout.")
oldT = newT
newT = try {
it.receive()?.also {
record = it
}?.timestamp?.takeIf { it.isNotBlank() }?.let {
SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time ?: 0L
SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).parse(it)?.time
?: 0L
} ?: 0L
} catch (t: Throwable) {
t.printStackTrace()
@@ -158,7 +165,7 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
}
}
record?.takeIf { it.key != old?.key && it.timestamp != old?.timestamp }?.also {
Log.d("QQQ", "record: [$record] is displaying for rest ..." )
Log.d("QQQ", "record: [$record] is displaying for rest ...")
showBadCaseEntrance(it)
}
} else {
@@ -170,7 +177,7 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
it.visibility = View.VISIBLE
}
}
Log.d("QQQ", "record: [$old] hasn't been consumed~~~~" )
Log.d("QQQ", "record: [$old] hasn't been consumed~~~~")
}
} finally {
delay(1000)
@@ -232,10 +239,10 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
}
}
ivCameraIcon?.setOnLongClickListener {
/*ivCameraIcon?.setOnLongClickListener {
activity?.let { it1 -> CarcorderPreviewView.show(it1) }
true
}
}*/
ivToolsIcon?.setOnClickListener {
if (toolsViewFloat == null) {
@@ -265,6 +272,11 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
}
}
}
/*// TODO 这里后面需要改成独立进程通讯后台获取YUV
view.postDelayed({
activity?.let { CarcorderPreviewView.show(it) }
}, 1000)*/
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -352,21 +364,29 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
onBadCaseHide = onHide
}
/**
*注册工控机升级提示圆点View的回调
* @param 提示圆点View
*/
override fun registerUpgradeTipsCallback(tipsView: () -> View) {
upgradeTipsView = tipsView
}
/**
* 工控机重启返回结果
* @param code
* @param msg
*/
override fun showDockerRebootResult(code: Int, msg: String) {
ThreadUtils.runOnUiThread{
if(code>=-1){
ThreadUtils.runOnUiThread {
if (code >= -1) {
//重启成功
ToastUtils.showShort("重启成功")
}else{
} else {
//重启失败
msg?.let {
ToastUtils.showShort(it)
}
}
}
}
}
@@ -378,7 +398,7 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
if (autoPilotBadCaseView == null) {
autoPilotBadCaseView = AutoPilotBadCaseView(it).also { itx ->
val record =
autoPilotBadCaseEntrance?.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult
autoPilotBadCaseEntrance?.getTag(R.id.autopilot_badcase_record) as? AutoPilotRecordResult
itx.tag = record
itx.onDismiss {
dismissBadCaseFloatView()
@@ -389,12 +409,13 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
val params = mutableMapOf<String, String>()
autoPilotBadCaseEntrance?.apply {
params["carLicense"] =
MoGoAiCloudClientConfig.getInstance().sn
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["duration"] = record?.duration?.toInt()?.toString()
?: ""
params["timestamp"] = record?.timestamp ?: ""
}
val response = post(params)
@@ -409,9 +430,9 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
dismissBadCaseFloatView()
dismiss?.invoke()
CallerAutoPilotManager.recordCause(
record?.key,
record?.fileName,
it.id, it.reason)
record?.key,
record?.fileName,
it.id, it.reason)
ToastUtils.showShort("接管反馈成功~")
record?.also {
it.consumed = true
@@ -437,39 +458,39 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
}
}
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()
}
.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()
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()
}
@@ -669,7 +690,8 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
if (floatWindow == null || TextUtils.isEmpty(showTag) || !floatWindow.isShow() || floatWindow.config.floatTag != tag) {
val notificationView = V2XNotificationView(it)
notificationView.setWarningIcon(EventTypeEnum.getWarningIcon(v2xType.toString()))
val warningContent = alertContent ?: EventTypeEnum.getWarningContent(v2xType.toString())
val warningContent = alertContent
?: EventTypeEnum.getWarningContent(v2xType.toString())
if (warningContent.isEmpty()) {
Logger.e(TAG, "Show warningContent is null or empty!")
return@launchWhenResumed
@@ -680,48 +702,48 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
WarningFloat.dismiss(floatWindow.config.floatTag, true)
}
mWarningFloat = WarningFloat.with(it)
.setTag(tag)
.setLayout(notificationView)
.setSidePattern(SidePattern.RESULT_TOP)
.setCountDownTime(expireTime)
.setGravity(Gravity.CENTER_HORIZONTAL, offsetY = 110)
.setImmersionStatusBar(true)
.isEnqueue(true)
.addWarningStatusListener(listenerIMoGo)
.addWarningStatusListener(object : IMoGoWarningStatusListener {
override fun onShow() {
// 创建弹窗成功才进行TTS播报
Logger.d(
"MoGoWarningFragment",
"mWarningFloat = $mWarningFloat---ttsContent = $ttsContent"
)
if (mWarningFloat != null && !TextUtils.isEmpty(ttsContent) && playTts) {
Logger.d("MoGoWarningFragment", "---> ttsContent = $ttsContent")
AIAssist.getInstance(activity)
.speakTTSVoice(ttsContent)
}
}
})
.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()
.setTag(tag)
.setLayout(notificationView)
.setSidePattern(SidePattern.RESULT_TOP)
.setCountDownTime(expireTime)
.setGravity(Gravity.CENTER_HORIZONTAL, offsetY = 110)
.setImmersionStatusBar(true)
.isEnqueue(true)
.addWarningStatusListener(listenerIMoGo)
.addWarningStatusListener(object : IMoGoWarningStatusListener {
override fun onShow() {
// 创建弹窗成功才进行TTS播报
Logger.d(
"MoGoWarningFragment",
"mWarningFloat = $mWarningFloat---ttsContent = $ttsContent"
)
if (mWarningFloat != null && !TextUtils.isEmpty(ttsContent) && playTts) {
Logger.d("MoGoWarningFragment", "---> ttsContent = $ttsContent")
AIAssist.getInstance(activity)
.speakTTSVoice(ttsContent)
}
}
})
.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()
override fun exitAnim(
view: View,
params: WindowManager.LayoutParams,
windowManager: WindowManager,
sidePattern: SidePattern
): Animator? =
super.exitAnim(view, params, windowManager, sidePattern)?.setDuration(200)
})
.show()
} else {
val notification = floatWindow.config.layoutView as? V2XNotificationView
if (alertContent?.isNotEmpty() == true) {
@@ -1073,22 +1095,32 @@ class MoGoHmiFragment : MvpFragment<MoGoWarningContract.View?, WaringPresenter?>
* @param upgradeStatus 升级状态
*/
override fun showAdUpgradeStatus(
upgradeMode: Int,
downloadStatus: Int,
currentProgress: Int,
totalProgress: Int,
downloadVersion: String,
upgradeStatus: Int
upgradeMode: Int,
downloadStatus: Int,
currentProgress: Int,
totalProgress: Int,
downloadVersion: String,
upgradeStatus: Int
) {
ThreadUtils.runOnUiThread{
ThreadUtils.runOnUiThread {
val tipsView = upgradeTipsView?.invoke()
//如果工控机处于“下载中”、“可升级(下载完成)”、“升级中”、“升级失败”状态时,工具箱入口显示红色角标
if(AdUpgradeStateHelper.showUpgradeTips(downloadStatus, upgradeStatus)){
viewUpgradeTips.visibility = View.VISIBLE
}else{
viewUpgradeTips.visibility = View.GONE
if (AdUpgradeStateHelper.showUpgradeTips(downloadStatus, upgradeStatus)) {
if (HmiBuildConfig.isShowUpgradeTipsView){
viewUpgradeTips?.visibility = View.VISIBLE
}else{
tipsView?.let {
it.visibility = View.VISIBLE
}
}
} else {
viewUpgradeTips?.visibility = View.GONE
tipsView?.let {
it.visibility = View.GONE
}
}
//将状态同步到工具箱
toolsView?.showAdUpgradeStatus(upgradeMode,downloadStatus, currentProgress, totalProgress, downloadVersion, upgradeStatus)
toolsView?.showAdUpgradeStatus(upgradeMode, downloadStatus, currentProgress, totalProgress, downloadVersion, upgradeStatus)
}
}

View File

@@ -8,7 +8,9 @@ import android.os.Looper
import android.util.Log
import android.view.*
import android.view.animation.OvershootInterpolator
import android.widget.Toast
import com.mogo.cloud.live.manager.ILiveStreamManager
import com.mogo.cloud.live.manager.LiveStreamManagerImpl
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.function.hmi.notification.WarningFloat
import com.mogo.eagle.core.function.hmi.notification.anim.DefaultAnimator
@@ -39,6 +41,8 @@ class CarcorderPreviewView private constructor(
private var isRequest = false
private var isPreview = false
private var liveStreamManager: ILiveStreamManager? = null
init {
LayoutInflater.from(context).inflate(R.layout.view_carcorder_preview, this, true)
}
@@ -70,7 +74,7 @@ class CarcorderPreviewView private constructor(
.setTag("CarcorderPreviewView")
.setLayout(carcorderPreviewVie)
.setSidePattern(SidePattern.RIGHT)
.setGravity(Gravity.RIGHT, offsetY = 200)
.setGravity(Gravity.RIGHT, offsetY = 250)
.setImmersionStatusBar(true)
.setAnimator(object : DefaultAnimator() {
override fun enterAnim(
@@ -160,6 +164,10 @@ class CarcorderPreviewView private constructor(
Log.d(TAG, "onDisConnectDev")
showShortMsg("相机断开连接")
}
override fun onCancelDev(device: UsbDevice?) {
Log.d(TAG, "onCancelDev" + device?.deviceName)
}
}
@@ -174,7 +182,14 @@ class CarcorderPreviewView private constructor(
mCameraHelper?.setDefaultFrameFormat(UVCCameraHelper.FRAME_FORMAT_MJPEG)
mCameraHelper?.initUSBMonitor(context as Activity, carcorderPreview, listener)
mCameraHelper?.setOnPreviewFrameListener { nv21Yuv -> Log.d(TAG, "onPreviewResult: " + nv21Yuv.size) }
mCameraHelper?.setOnPreviewFrameListener { nv21Yuv ->
Log.d(TAG, "onPreviewResult: " + nv21Yuv.size)
//Log.i(TAG, "onVideoFrame byte length: " + bytesLength);
if (liveStreamManager != null) {
// 将摄像头采集的YUV数据推送到ZEGO
liveStreamManager!!.notifyYUVData(nv21Yuv, 640, 480, 2)
}
}
}
@@ -185,6 +200,19 @@ class CarcorderPreviewView private constructor(
if (mCameraHelper != null) {
mCameraHelper!!.registerUSB()
}
// 初始化直播流管理
// 初始化直播流管理
liveStreamManager = LiveStreamManagerImpl.getInstance((context as Activity).application,
MoGoAiCloudClientConfig.getInstance().sn, true)
// 设置状态回调
liveStreamManager!!.setLiveStatusChangeCallback { status ->
if (status == 0) {
Logger.d(TAG, "直播中……")
} else {
Logger.d(TAG, "直播结束……")
}
}
}
override fun onDetachedFromWindow() {
@@ -193,6 +221,13 @@ class CarcorderPreviewView private constructor(
if (mCameraHelper != null) {
mCameraHelper!!.unregisterUSB()
}
if (liveStreamManager != null) {
// 停止
liveStreamManager!!.stopLiveStream()
// 释放资源
liveStreamManager!!.release()
}
}
override fun onSurfaceCreated(view: CameraViewInterface?, surface: Surface?) {

View File

@@ -68,7 +68,6 @@ abstract class AbsLogView : ILogView, TouchProxy.OnTouchEventListener {
fun show(context: Context) {
if (isShow) {
Log.d("EmArrow", "isShow : $isShow")
return
}
performCreate(context)

View File

@@ -244,7 +244,6 @@ class LogInfoView : AbsLogView() {
mLogHint!!.visibility = View.VISIBLE
mLogRvWrap!!.visibility = View.GONE
val layoutParams = systemLayoutParams ?: return
Log.d("EmArrow", "minimize , layoutParams is not null")
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT

View File

@@ -11,6 +11,7 @@ import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.debug.DebugConfig
import com.mogo.eagle.core.data.app.AppConfigInfo
import com.mogo.eagle.core.data.autopilot.*
import com.mogo.eagle.core.data.chain.ChainConstant
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.constants.MoGoConfig
import com.mogo.eagle.core.data.map.MogoLocation
@@ -35,11 +36,20 @@ import com.mogo.eagle.core.function.call.obu.CallerObuListenerManager
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.function.hmi.ui.logcatch.ILogViewListener
import com.mogo.eagle.core.function.hmi.ui.logcatch.LogInfoView
import com.mogo.eagle.core.utilcode.kotlin.onClick
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.eagle.core.utilcode.util.*
import com.mogo.map.MogoMap
import com.mogo.map.uicontroller.VisualAngleMode
import com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_300
import com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_CROSS
import com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_TOP
import com.mogo.map.uicontroller.VisualAngleMode.MODE_CLOSE_SIGHT
import com.mogo.map.uicontroller.VisualAngleMode.MODE_LONG_SIGHT
import com.mogo.map.uicontroller.VisualAngleMode.MODE_MEDIUM_SIGHT
import com.mogo.module.common.MogoApisHandler
import kotlinx.android.synthetic.main.view_debug_setting.view.*
import java.util.*
@@ -50,13 +60,13 @@ import java.util.*
* 展示 本机、网络、工控机、OBU等状态信息支持设置IP等参数进行调试
*/
class DebugSettingView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), IMoGoObuStatusListener,
IMoGoAutopilotStatusListener, IMoGoAutopilotCarStateListener,
IMoGoMapLocationListener, IMoGoAutopilotIdentifyListener,
IMoGoAutopilotPlanningListener {
IMoGoAutopilotStatusListener, IMoGoAutopilotCarStateListener,
IMoGoMapLocationListener, IMoGoAutopilotIdentifyListener,
IMoGoAutopilotPlanningListener {
private val TAG = "DebugSettingView"
@@ -75,6 +85,12 @@ class DebugSettingView @JvmOverloads constructor(
// 全局路径规划点个数
private var mRouteInfoSize = 0
private val mapUiController by lazy {
MogoApisHandler.getInstance().apis?.mapServiceApi?.mapUIController
}
private var lastVisualAngleMode: VisualAngleMode? = null
init {
LayoutInflater.from(context).inflate(R.layout.view_debug_setting, this, true)
initView()
@@ -204,21 +220,40 @@ class DebugSettingView @JvmOverloads constructor(
}
}
changesight_top_btn.setOnClickListener {
CallerHDMapManager.setMapDAngle(0);
lastVisualAngleMode = mapUiController?.currentMapVisualAngle
changesight_top_btn.onClick {
mapUiController?.changeMapVisualAngle(MAP_STYLE_VR_ANGLE_TOP, null)
}
changesight_back_btn?.onClick {
mapUiController?.changeMapVisualAngle(MAP_STYLE_VR_ANGLE_300, null)
}
changesight_cross_btn?.onClick {
mapUiController?.changeMapVisualAngle(MAP_STYLE_VR_ANGLE_CROSS, null)
}
changesight_far_btn?.onClick {
mapUiController?.changeMapVisualAngle(MODE_LONG_SIGHT, null)
}
reset_changesight?.onClick {
lastVisualAngleMode?.let {
mapUiController?.changeMapVisualAngle(it, null)
}
}
tvObuInfo.text = CallerObuListenerManager.getObuStatusInfoJsonString()
tvAutopilotInfo.text =
CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfoJsonString()
CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfoJsonString()
// 绘制应用基本信息
drawAppInfo()
// 初始化OBU IP信息
val ipAddress =
SharedPrefsMgr.getInstance(context).getString(MoGoConfig.OBU_IP, "192.168.1.199")
SharedPrefsMgr.getInstance(context).getString(MoGoConfig.OBU_IP, "192.168.1.199")
etObuIP.setText(ipAddress)
etObuIP.text?.let { etObuIP.setSelection(it.length) }
@@ -255,18 +290,18 @@ class DebugSettingView @JvmOverloads constructor(
// 初始化 GSP数据源 数据
rgGpsProvider.check(
when (FunctionBuildConfig.gpsProvider) {
0 -> {
R.id.rbGpsProviderAndroid
}
1 -> {
R.id.rbGpsProviderRTK
}
2 -> {
R.id.rbGpsProviderOBU
}
else -> R.id.rbGpsProviderAndroid
when (FunctionBuildConfig.gpsProvider) {
0 -> {
R.id.rbGpsProviderAndroid
}
1 -> {
R.id.rbGpsProviderRTK
}
2 -> {
R.id.rbGpsProviderOBU
}
else -> R.id.rbGpsProviderAndroid
}
)
rgGpsProvider.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
@@ -350,31 +385,29 @@ class DebugSettingView @JvmOverloads constructor(
}
tbLogCatch.isChecked =
SharedPrefsMgr.getInstance(context).getBoolean(MoGoConfig.CATCH_LOG, false)
SharedPrefsMgr.getInstance(context).getBoolean(MoGoConfig.CATCH_LOG, false)
tbLogCatch.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
CallerDevaToolsManager.startCatchLog()
SharedPrefsMgr.getInstance(context).putBoolean(MoGoConfig.CATCH_LOG, true)
} else {
CallerDevaToolsManager.stopCatchLog()
SharedPrefsMgr.getInstance(context).putBoolean(MoGoConfig.CATCH_LOG, false)
}
}
CallerDevaToolsListenerManager.registerDevaToolsLogCatchListener(TAG,
object : IMoGoDevaToolsListener {
override fun onLogCatchClose() {
super.onLogCatchClose()
tbLogCatch.isChecked = false
}
object : IMoGoDevaToolsListener {
override fun onLogCatchClose() {
super.onLogCatchClose()
tbLogCatch.isChecked = false
}
override fun onLogCatch(lineLog: String) {
logInfoView?.let {
if (logViewAttach) {
it.onLogCatch(lineLog)
}
override fun onLogCatch(lineLog: String) {
logInfoView?.let {
if (logViewAttach) {
it.onLogCatch(lineLog)
}
}
})
}
})
tbLogDebugView.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
logInfoView = LogInfoView()
@@ -394,6 +427,15 @@ class DebugSettingView @JvmOverloads constructor(
logViewDestroy()
}
}
tbLogTraceView.setOnCheckedChangeListener { _, isChecked ->
val traceInfoMap = CallerDevaToolsManager.getTraceInfo()
val chainLogParam = traceInfoMap[ChainConstant.CHAIN_LINK_LOG_WEB_SOCKET_DATA]
chainLogParam?.let {
it.record = isChecked
traceInfoMap[ChainConstant.CHAIN_LINK_LOG_WEB_SOCKET_DATA] = chainLogParam
CallerDevaToolsManager.refreshTraceInfo(traceInfoMap)
}
}
}
private fun logViewDestroy() {
@@ -428,15 +470,15 @@ class DebugSettingView @JvmOverloads constructor(
tvAutopilotInfo.text = GsonUtils.toJson(mAutoPilotStatusInfo)
tvCarInfo.text =
"GPS时间${mAutoPilotCarStateInfo?.values?.satelliteTime}\n" +
"自车经纬度:\n${mAutoPilotCarStateInfo?.values?.lon}\n${mAutoPilotCarStateInfo?.values?.lat}\n"
"GPS时间${mAutoPilotCarStateInfo?.values?.satelliteTime}\n" +
"自车经纬度:\n${mAutoPilotCarStateInfo?.values?.lon}\n${mAutoPilotCarStateInfo?.values?.lat}\n"
tvIdentifyInfo.text =
"感知数据个数:${mIdentifyDataSize}"
"感知数据个数:${mIdentifyDataSize}"
tvTrajectoryInfoSize.text =
"引导线点个数:${mTrajectoryInfoSize}"
"引导线点个数:${mTrajectoryInfoSize}"
tvRouteInfoSize.text =
"全局路径规划点个数:${mRouteInfoSize}"
"全局路径规划点个数:${mRouteInfoSize}"
// 用完之后重制为0防止节点回掉突然没数据导致页面显示还是之前的数据情况
mIdentifyDataSize = 0

View File

@@ -8,11 +8,13 @@ import android.view.View
import android.widget.FrameLayout
import com.mogo.eagle.core.data.autopilot.AutopilotGuardianStatusInfo
import com.mogo.eagle.core.data.autopilot.AutopilotStatusInfo
import com.mogo.eagle.core.data.config.FunctionBuildConfig
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.hmi.R
import com.mogo.eagle.core.function.hmi.ui.utils.KeyBoardUtil
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import kotlinx.android.synthetic.main.view_auto_pilot_check.view.*
import kotlinx.android.synthetic.main.view_check_system.view.*
@@ -102,6 +104,7 @@ class AutoPilotAndCheckView @JvmOverloads constructor(
return@setOnTouchListener false
}
}
updateSpeedSettingViews()
// // 比如需要设置默认速度
// val speed = "30"
// etInputSpeed.setText(speed)
@@ -112,6 +115,22 @@ class AutoPilotAndCheckView @JvmOverloads constructor(
this.clickListener = clickListener
}
/**
* Bus不可设置自动驾驶速度而Taxi可以
*/
private fun updateSpeedSettingViews() {
when {
AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode) -> {
tvSpeedTitle.visibility = View.GONE
llSpeedPosition.visibility = View.GONE
}
else -> {
tvSpeedTitle.visibility = View.VISIBLE
llSpeedPosition.visibility = View.VISIBLE
}
}
}
/**
* 展示工控机下载、升级状态信息
* @param upgradeMode 升级模式(提示升级、静默升级)

View File

@@ -71,6 +71,12 @@ class SystemVersionView @JvmOverloads constructor(
if(AdUpgradeStateHelper.isDownloading(downloadStatus)){
//点击Toast提示下载剩余时间
ToastUtils.showShort("预计"+AdUpgradeStateHelper.getRemainingTime(totalProgress,previousProgress,currentProgress)+"下载完成")
}else if(AdUpgradeStateHelper.getUpgradeStatus()){
//工控机状态为“升级中”
ToastUtils.showShort("新版本升级中预计5分钟升级完成")
}else if(AdUpgradeStateHelper.isUpgradeFailed(upgradeStatus)){
//如果升级失败则Toast提示升级失败请联系运维人员
ToastUtils.showShort("升级失败,请联系运维人员")
}else if(AdUpgradeStateHelper.isHintUpgradeMode(upgradeMode) && AdUpgradeStateHelper.isDownloadFinish(downloadStatus,upgradeStatus)){
//如果升级模式为“提示升级”,并且下载状态为已经下载完成,点击弹出升级确认弹窗
if(adUpgradeDialog == null){
@@ -86,6 +92,10 @@ class SystemVersionView @JvmOverloads constructor(
//设置当前状态为“升级中”
AdUpgradeStateHelper.setUpgradeStatus(true)
CallerAutoPilotManager.setIPCUpgradeAffirm()
//将角标设为升级中
ivAdStatus?.setImageResource(R.drawable.icon_upgrading)
adCircularProgressView?.visibility = View.GONE
ivAdVersion?.setBackgroundResource(R.drawable.version_latest_background)
}
}
@@ -99,12 +109,6 @@ class SystemVersionView @JvmOverloads constructor(
})
}
adUpgradeDialog?.showUpgradeDialog()
}else if(AdUpgradeStateHelper.getUpgradeStatus()){
//工控机状态为“升级中”
ToastUtils.showShort("新版本升级中预计5分钟升级完成")
}else if(AdUpgradeStateHelper.isUpgradeFailed(upgradeStatus)){
//如果升级失败则Toast提示升级失败请联系运维人员
ToastUtils.showShort("升级失败,请联系运维人员")
}
}

View File

@@ -112,8 +112,8 @@
<View
android:id="@+id/viewUpgradeTips"
android:layout_width="20px"
android:layout_height="20px"
android:layout_width="22px"
android:layout_height="22px"
app:layout_constraintCircle="@id/ivToolsIcon"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="60px"

View File

@@ -2,14 +2,13 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/dp_768"
android:layout_height="@dimen/dp_432"
android:background="#FFFFFF">
android:layout_height="@dimen/dp_432">
<com.serenegiant.usb.widget.UVCCameraTextureView
android:id="@+id/carcorderPreview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"

View File

@@ -413,6 +413,16 @@
android:textOn="关闭日志过滤面板"
android:textSize="@dimen/dp_24" />
<ToggleButton
android:id="@+id/tbLogTraceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:gravity="center"
android:textOff="ADAS长链数据未写入"
android:textOn="ADAS长链数据写入中..."
android:textSize="@dimen/dp_24" />
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
<!--域控制器(工控机)配置信息-->

View File

@@ -68,7 +68,6 @@ dependencies {
api rootProject.ext.dependencies.mogocommons
api rootProject.ext.dependencies.modulecommon
api rootProject.ext.dependencies.mogoservice
api rootProject.ext.dependencies.moduleshare
api rootProject.ext.dependencies.moduleextensions
api rootProject.ext.dependencies.callchat
api rootProject.ext.dependencies.callchatprovider

View File

@@ -61,7 +61,6 @@ public abstract class MainMoGoApplication extends AbsMogoApplication {
return;
}
start = System.currentTimeMillis();
ChainTraceStarter.start("com.mogo.launcher.f", DeviceUtils.getMacAddress());
// Crash 日志收集
initCrashConfig();
initLogConfig();
@@ -153,7 +152,7 @@ public abstract class MainMoGoApplication extends AbsMogoApplication {
// 设置是否输出日志
clientConfig.setShowDebugLog(true);
// 设置是否是直播推流的主播
clientConfig.setAnchor(false);
clientConfig.setAnchor(true);
// 设置从蘑菇AI开放平台获取的APPKey
switch (DebugConfig.getCarMachineType()) {
// 比亚迪
@@ -178,8 +177,8 @@ public abstract class MainMoGoApplication extends AbsMogoApplication {
// 设置AI云平台分配给三方应用的签名密钥需要从AI云平台申请
// 设置车机设备的唯一标识(这些表识必须是通过后台录入的设备)
clientConfig.setThirdPartyDeviceId(Utils.getDevicesId());
// 设置循环检测间隔时间
clientConfig.setLoopCheckDelay(60 * 60 * 24 * 1000);
// 设置循环检测间隔时间每隔2小时loop一次httpDnsConfig
clientConfig.setLoopCheckDelay(60 * 60 * 2 * 1000);
//连接ami
connectAmiIp();
@@ -249,7 +248,7 @@ public abstract class MainMoGoApplication extends AbsMogoApplication {
*/
private void connectAmiIp() {
String ipAddress = SharedPrefsMgr.getInstance(AbsMogoApplication.getApp().getBaseContext()).getString(MoGoConfig.OBU_IP, "192.168.1.199");
Logger.d("OnAdasListenerAdapter", "application --ipAddress = " + ipAddress);
//Logger.d("OnAdasListenerAdapter", "application --ipAddress = " + ipAddress);
AmiClientManager.getInstance().setObuIp(ipAddress);
}
@@ -302,7 +301,8 @@ public abstract class MainMoGoApplication extends AbsMogoApplication {
private void initModules() {
Logger.d(TAG, "initModules");
//mogo deva tools
MogoModulePaths.addModuleFunctionServer(new MogoModule(MogoServicePaths.PATH_DEVA_TOOLS, "IMoGoDevaToolsProvider"));
// 初始化 bugly 升级
MogoModulePaths.addBaseModule(new MogoModule(UpgradeReportConstants.PATH, UpgradeReportConstants.NAME));
// 初始化 apm 日志采集
@@ -312,9 +312,8 @@ public abstract class MainMoGoApplication extends AbsMogoApplication {
MogoModulePaths.addBaseModule(new MogoModule(MapApiPath.PATH, "CustomMapApiBuilder"));
MogoModulePaths.addBaseModule(new MogoModule(ServiceConst.PATH_REFRESH_STRATEGY, ServiceConst.PATH_REFRESH_STRATEGY));
// MogoModulePaths.addBaseModule(new MogoModule(V2XConst.PATH_V2X_UI, V2XConst.MODULE_NAME));
//mogo deva tools
MogoModulePaths.addModuleFunctionServer(new MogoModule(MogoServicePaths.PATH_DEVA_TOOLS, "IMoGoDevaToolsProvider"));
// MogoModulePaths.addBaseModule(new MogoModule(V2XConst.PATH_V2X_UI, V2XConst.MODULE_NAME));
// 域控制器模块(新)
MogoModulePaths.addModuleFunctionServer(new MogoModule(MogoServicePaths.PATH_AUTO_PILOT, "IMoGoAutoPilotProvider"));
// OBU 模块

View File

@@ -50,7 +50,7 @@ dependencies {
implementation rootProject.ext.dependencies.rxandroid
kapt rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.adasHigh
//implementation rootProject.ext.dependencies.adasHigh
implementation rootProject.ext.dependencies.mogocustommapoperational
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
implementation rootProject.ext.dependencies.mogoserviceapi
@@ -74,6 +74,8 @@ dependencies {
implementation project(":libraries:mogo-map")
implementation project(":libraries:mogo-map-api")
implementation project(':libraries:mogo-adas')
}
}

View File

@@ -53,7 +53,7 @@ dependencies {
implementation rootProject.ext.dependencies.flexbox
kapt rootProject.ext.dependencies.aroutercompiler
implementation rootProject.ext.dependencies.adasHigh
// implementation rootProject.ext.dependencies.adasHigh
implementation rootProject.ext.dependencies.mogo_v2x
implementation rootProject.ext.dependencies.mogoaicloudtrafficlive
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
@@ -75,6 +75,8 @@ dependencies {
implementation project(':modules:mogo-module-carchattingprovider')
implementation project(':core:mogo-core-res')
implementation project(':libraries:mogo-adas')
}
}

View File

@@ -1,16 +0,0 @@
package com.mogo.eagle.core.function.v2x.events.widgets;
import com.mogo.commons.mvp.IView;
import com.mogo.module.common.entity.MarkerExploreWay;
import java.util.List;
/**
* @author lixiaopeng
* @description
* @since 2020/7/29
*/
public interface SurroundingEventView extends IView {
void showSurroudingData(List<MarkerExploreWay> exploreWayList);
}

View File

@@ -1,36 +0,0 @@
package com.mogo.eagle.core.function.v2x.events.widgets;
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
/**
* @author lixiaopeng
* @description
* @since 2020/8/11
*/
public class SurroundingMarginDecoration extends RecyclerView.ItemDecoration {
private int margin ;
private int marginLeft ;
public SurroundingMarginDecoration(int space, int left) {
margin = space;
marginLeft = left;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.bottom = margin;
//由于每行都只有2个所以第一个都是2的倍数
if (parent.getChildLayoutPosition(view) % 2 == 0) {
outRect.left = marginLeft;
outRect.right = margin / 2;
} else {
outRect.left = margin / 2;
outRect.right = marginLeft;
}
}
}

View File

@@ -1,25 +1,10 @@
package com.mogo.eagle.core.function.v2x.trafficlight
import com.mogo.commons.debug.DebugConfig
class TrafficLightConst {
companion object {
const val MODULE_NAME = "MODULE_V2X_TRAFFIC_LIGHT"
private const val HOST_DEV = "http://dzt-test.zhidaozhixing.com"
private const val HOST_TEST = "http://dzt-test.zhidaozhixing.com"
private const val HOST_DEMO = "http://dzt-show.zhidaozhixing.com"
private const val HOST_PRODUCT = "http://dzt.zhidaozhixing.com"
fun getNetHost(): String {
return when (DebugConfig.getNetMode()) {
DebugConfig.NET_MODE_DEV -> HOST_DEV
DebugConfig.NET_MODE_QA -> HOST_TEST
DebugConfig.NET_MODE_DEMO -> HOST_DEMO
else -> HOST_PRODUCT
}
}
}
}

View File

@@ -1,8 +1,5 @@
package com.mogo.eagle.core.data.autopilot
import android.util.Log
import java.util.logging.Logger
/**
* @author XuXinChao
* @description 工控机升级状态实体类
@@ -32,6 +29,7 @@ class AdUpgradeStateHelper {
* @param downloadStatus 下载状态
* @param upgradeStatus 升级状态
*/
@JvmStatic
fun showUpgradeTips(downloadStatus: Int,upgradeStatus: Int) : Boolean{
return isDownloading(downloadStatus) || isDownloadFinish(downloadStatus,upgradeStatus) || getUpgradeStatus() || isUpgradeFailed(upgradeStatus)
}
@@ -41,6 +39,7 @@ class AdUpgradeStateHelper {
* @param downloadStatus 下载状态
* @param upgradeStatus 升级状态
*/
@JvmStatic
fun showCannotReboot(downloadStatus: Int,upgradeStatus: Int): Boolean{
return isDownloading(downloadStatus)|| isDownloadFinish(downloadStatus,upgradeStatus) || getUpgradeStatus()
}
@@ -49,6 +48,7 @@ class AdUpgradeStateHelper {
* 工控机是否处于“下载中”状态
* @param downloadStatus 下载状态
*/
@JvmStatic
fun isDownloading(downloadStatus: Int) : Boolean{
return downloadStatus == DOWNLOAD_START
}
@@ -58,6 +58,7 @@ class AdUpgradeStateHelper {
* @param downloadStatus 下载状态
* @param upgradeStatus 升级状态
*/
@JvmStatic
fun isDownloadFinish(downloadStatus: Int,upgradeStatus: Int) : Boolean{
return downloadStatus == DOWNLOAD_FINISH && upgradeStatus == USER_AFFIRM
}
@@ -66,6 +67,7 @@ class AdUpgradeStateHelper {
* 工控机是否处于“下载失败”状态
* @param downloadStatus 下载状态
*/
@JvmStatic
fun isDownloadFailed(downloadStatus: Int) : Boolean{
return downloadStatus == DOWNLOAD_FAILED
}
@@ -74,6 +76,7 @@ class AdUpgradeStateHelper {
* 工控机是否处于“升级成功”状态
* @param upgradeStatus 升级状态
*/
@JvmStatic
fun isUpgradeSuccess(upgradeStatus: Int) : Boolean{
return upgradeStatus == UPGRADE_SUCCEED
}
@@ -82,6 +85,7 @@ class AdUpgradeStateHelper {
* 工控机是否处于“升级失败”状态
* @param upgradeStatus 升级状态
*/
@JvmStatic
fun isUpgradeFailed(upgradeStatus: Int) : Boolean{
return upgradeStatus == UPGRADE_FAILED
}
@@ -91,6 +95,7 @@ class AdUpgradeStateHelper {
* @param currentProgress 当前已下载包体大小
* @param totalProgress 包体总大小
*/
@JvmStatic
fun downloadProgress(currentProgress: Int,totalProgress: Int) : Int{
return (currentProgress.toDouble()/totalProgress.toDouble()*100).toInt()
}
@@ -99,6 +104,7 @@ class AdUpgradeStateHelper {
* 工控机升级模式是否是静默升级
* @param upgradeMode 升级模式
*/
@JvmStatic
fun isQuietUpgradeMode(upgradeMode: Int) : Boolean{
return upgradeMode == UPGRADE_QUIET
}
@@ -107,6 +113,7 @@ class AdUpgradeStateHelper {
* 工控机升级模式是否是提示升级
* @param upgradeMode 升级模式
*/
@JvmStatic
fun isHintUpgradeMode(upgradeMode: Int) : Boolean{
return upgradeMode == UPGRADE_HINT
}
@@ -114,6 +121,7 @@ class AdUpgradeStateHelper {
/**
* 获取是否处于“升级中”状态
*/
@JvmStatic
fun getUpgradeStatus() : Boolean{
return UPGRADING
}
@@ -122,6 +130,7 @@ class AdUpgradeStateHelper {
* 设置是否处于“升级中”状态
* @param upgrading 是否是升级中
*/
@JvmStatic
fun setUpgradeStatus(upgrading: Boolean){
UPGRADING = upgrading
}
@@ -129,6 +138,7 @@ class AdUpgradeStateHelper {
/**
* 获取工控机包体下载剩余时间
*/
@JvmStatic
fun getRemainingTime(totalProgress: Int,previousProgress: Int,currentProgress: Int) : String{
//剩余包体大小
val remainingSize = totalProgress - currentProgress
@@ -139,14 +149,14 @@ class AdUpgradeStateHelper {
//转换为分秒格式返回
val minute = time/60
val second = time%60
if(minute>0 && second>0){
return minute.toString()+"分钟"+second+""
return if(minute>0 && second>0){
minute.toString()+"分钟"+second+""
}else if(minute>0){
return minute.toString()+"分钟"
minute.toString()+"分钟"
}else if(second>0){
return second.toString()+""
second.toString()+""
}else{
return ""
""
}
}

View File

@@ -0,0 +1,31 @@
package com.mogo.eagle.core.data.chain
class ChainConstant {
companion object{
const val CHAIN_LINK_CLOUD_SHOW = 0
const val CHAIN_LINK_ADAS = 1
const val CHAIN_LINK_LOG_CONNECT_STATUS = 0
const val CHAIN_LINK_LOG_WEB_SOCKET_DATA = 1
const val CHAIN_LINK_LOG_ADAS_INIT = "-adasInitStatus"
const val CHAIN_LINK_LOG_ADAS_MSG = "-adasWsMsg"
const val CHAIN_ALIAS_CODE_UDP_INIT = "PAD_ADAS_UDP_INIT"
const val CHAIN_ALIAS_CODE_UDP_CONNECT_ADDRESS = "PAD_ADAS_UDP_CONNECT_ADDRESS"
const val CHAIN_ALIAS_CODE_WEB_SOCKET_OPEN = "PAD_ADAS_WEB_SOCKET_OPEN"
const val CHAIN_ALIAS_CODE_WEB_SOCKET_MESSAGE_JSON = "PAD_ADAS_WEB_SOCKET_MESSAGE_JSON"
const val CHAIN_ALIAS_CODE_WEB_SOCKET_MESSAGE_BYTE = "PAD_ADAS_WEB_SOCKET_MESSAGE_BYTE"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_RECT_DATA = "PAD_ADAS_MESSAGE_AUTOPILOT_RECT_DATA"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_CAR_STATE = "PAD_ADAS_MESSAGE_AUTOPILOT_CAR_STATE"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_STATUS = "PAD_ADAS_MESSAGE_AUTOPILOT_STATUS"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_ARRIVE = "PAD_ADAS_MESSAGE_AUTOPILOT_ARRIVE"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_ROUTE = "PAD_ADAS_MESSAGE_AUTOPILOT_ROUTE"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_TRAJECTORY = "PAD_ADAS_MESSAGE_AUTOPILOT_TRAJECTORY"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_GUARDIAN = "PAD_ADAS_MESSAGE_AUTOPILOT_GUARDIAN"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_RECORD = "PAD_ADAS_MESSAGE_AUTOPILOT_RECORD"
const val CHAIN_ALIAS_CODE_ADAS_MESSAGE_AUTOPILOT_WARN = "PAD_ADAS_MESSAGE_AUTOPILOT_WARN"
}
}

View File

@@ -0,0 +1,13 @@
package com.mogo.eagle.core.data.chain
class ChainLogParam {
var record: Boolean = false
var des: String? = null
constructor(record: Boolean, des: String) {
this.record = record
this.des = des
}
}

View File

@@ -36,6 +36,12 @@ object HmiBuildConfig {
@JvmField
var isShowBadCaseView = true
/**
* 是否展示工控机升级提示UI
*/
@JvmField
var isShowUpgradeTipsView = true
/**
* 是否展示转向灯ui
*/

View File

@@ -14,6 +14,8 @@ object MoGoConfig {
// CMD全量日志抓取
const val CATCH_LOG = "CATCH_LOG"
// CMD全量日志抓取当时时间
const val CATCH_LOG_TIME = "CATCH_LOG_TIME"
// 是否是演示美化模式会存在SP中方便做现场恢复
const val IS_DEMO_MODE = "IS_DEMO_MODE"

View File

@@ -1,5 +1,6 @@
package com.mogo.eagle.core.function.api.devatools
import com.mogo.eagle.core.data.chain.ChainLogParam
import com.mogo.eagle.core.function.api.base.IMoGoFunctionServerProvider
/**
@@ -9,5 +10,12 @@ interface IDevaToolsProvider : IMoGoFunctionServerProvider {
fun startLogCatch()
fun startLogCatch(duration: Int)
fun stopLogCatch()
fun getTraceInfo():HashMap<Int, ChainLogParam>
fun refreshTraceInfo(map: HashMap<Int, ChainLogParam>)
}

View File

@@ -193,6 +193,12 @@ interface IMoGoWaringProvider {
*/
fun registerBadCaseCallback(onShow:() -> View, onHide: (() -> Unit)?)
/**
*注册工控机升级提示圆点View的回调
* @param 提示圆点View
*/
fun registerUpgradeTipsCallback(tipsView:() -> View)
/**
* 工控机重启返回结果
* @param code

View File

@@ -1,8 +1,10 @@
package com.mogo.eagle.core.function.call.devatools
import com.alibaba.android.arouter.launcher.ARouter
import com.mogo.eagle.core.data.chain.ChainLogParam
import com.mogo.eagle.core.data.constants.MogoServicePaths.PATH_DEVA_TOOLS
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
import com.mogo.eagle.core.utilcode.util.SnackbarUtils
object CallerDevaToolsManager {
@@ -17,10 +19,32 @@ object CallerDevaToolsManager {
devaToolsProviderApi.startLogCatch()
}
/**
* 开始抓取全量日志
* duration 分钟数
*/
fun startCatchLog(duration: Int){
devaToolsProviderApi.startLogCatch(duration)
}
/**
* 停止抓取全量日志
*/
fun stopCatchLog() {
devaToolsProviderApi.stopLogCatch()
}
/**
* 更新链路节点信息,是否写入
*/
fun refreshTraceInfo(map: HashMap<Int, ChainLogParam>) {
devaToolsProviderApi.refreshTraceInfo(map)
}
/**
* 获取链路节点信息
*/
fun getTraceInfo():HashMap<Int, ChainLogParam>{
return devaToolsProviderApi.getTraceInfo()
}
}

View File

@@ -273,6 +273,14 @@ object CallerHmiManager : CallerBase() {
waringProviderApi?.registerBadCaseCallback(onShow, onHide)
}
/**
*注册工控机升级提示圆点View的回调
* @param 提示圆点View
*/
fun registerUpgradeTipsCallback(tipsView:() -> View){
waringProviderApi?.registerUpgradeTipsCallback(tipsView)
}
/**
* 工控机重启返回结果
* @param code

View File

@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.eagle.core.utilcode.util">
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application>
<activity

View File

@@ -17,6 +17,13 @@ import android.view.Gravity;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.eagle.core.utilcode.kotlin.ExtensionsKt;
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
@@ -34,7 +41,7 @@ public final class TipToast {
private static ToastViewGenerator sGenerator;
public static void init( Context context, ToastViewGenerator generator ) {
TipToast.sContext = context;
TipToast.sContext = context.getApplicationContext();
sHandler = new Handler( context.getMainLooper() );
sGenerator = generator;
}
@@ -165,20 +172,21 @@ public final class TipToast {
sHandler.post(() -> {
synchronized ( sSyncObject ) {
if ( context == null ) {
return;
}
if ( sToast != null ) {
sToast.cancel();
if ( sToast != null) {
View view = sToast.getView();
if (view != null && ViewCompat.isAttachedToWindow(view)) {
sToast.cancel();
}
}
if ( sGenerator == null ) {
sToast = Toast.makeText( context, msg, duration );
} else {
sToast = new Toast( context );
final View view = sGenerator.make( context, msg, tipDrawable );
if ( view != null ) {
sToast.setView( view );
sToast.setGravity( sGenerator.gravity(), sGenerator.xOffset(), sGenerator.yOffset() );
@@ -187,6 +195,15 @@ public final class TipToast {
sToast = Toast.makeText( context, msg, duration );
}
}
View view = sToast.getView();
if (view != null) {
LifecycleOwner lifecycleOwner = ExtensionsKt.getLifecycleOwner(view);
lifecycleOwner.getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> {
if (event == Lifecycle.Event.ON_DESTROY) {
sToast = null;
}
});
}
if ( sToast != null ) {
sToast.show();
}

View File

@@ -3,38 +3,40 @@ package com.mogo.eagle.core.utilcode.util;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.MediaDrm;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.elegant.utils.storage.SharedPrefsMgr;
import androidx.core.content.ContextCompat;
import com.elegant.utils.storage.SharedPrefsMgr;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
public final class DeviceIdUtils {
public static final String KEY_DEVICE_ID = "deviceId";
private DeviceIdUtils() {}
private DeviceIdUtils() {
}
private static void saveDeviceId( Context context, String deviceId){
private static void saveDeviceId(Context context, String deviceId) {
SharedPrefsMgr.getInstance(context).putString(KEY_DEVICE_ID, deviceId);
}
public static String getDeviceId( Context context) {
if(context == null){
public static String getDeviceId(Context context) {
if (context == null) {
throw new NullPointerException("context must not be null.");
}
final Context appContext = context.getApplicationContext();
String deviceId = SharedPrefsMgr.getInstance( context ).getString( KEY_DEVICE_ID );
String deviceId = SharedPrefsMgr.getInstance(context).getString(KEY_DEVICE_ID);
if ( TextUtils.isEmpty( deviceId )) {
if (TextUtils.isEmpty(deviceId)) {
deviceId = getDeviceIdInternal(appContext);
if (TextUtils.isEmpty(deviceId)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -54,35 +56,37 @@ public final class DeviceIdUtils {
}
}
}
saveDeviceId(appContext,deviceId);
saveDeviceId(appContext, deviceId);
}
return deviceId;
}
private static String getDeviceIdInternal( Context context) {
private static String getDeviceIdInternal(Context context) {
String id = "";
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
if ( ContextCompat.checkSelfPermission( context, Manifest.permission.READ_PHONE_STATE ) != PackageManager.PERMISSION_GRANTED ) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return id;
}
}
TelephonyManager telephonymanager = ( TelephonyManager ) context.getSystemService( Context.TELEPHONY_SERVICE);
TelephonyManager telephonymanager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonymanager != null) {
id = telephonymanager.getDeviceId();
if ( TextUtils.isEmpty(id))
if (TextUtils.isEmpty(id)) {
id = "";
}
}
return id;
}
private static String getAndroidId( Context context) {
private static String getAndroidId(Context context) {
String s = "";
s = Settings.Secure.getString(context.getContentResolver(), "android_id");
if ( TextUtils.isEmpty(s))
if (TextUtils.isEmpty(s)) {
s = "";
}
return s;
}
@@ -95,16 +99,63 @@ public final class DeviceIdUtils {
if (!method.isAccessible()) {
method.setAccessible(true);
}
serial = ( String ) method.invoke(new Build(), "ro.serialno");
} catch ( ClassNotFoundException e) {
serial = (String) method.invoke(new Build(), "ro.serialno");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch ( NoSuchMethodException e) {
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch ( InvocationTargetException e) {
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch ( IllegalAccessException e) {
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return serial;
}
/**
* 获取数字版权管理设备ID
*
* @return WidevineID可能为空
*/
public static String getWidevineID(Context context) {
try {
//See https://stackoverflow.com/questions/16369818/how-to-get-crypto-scheme-uuid
//You can find some UUIDs in the https://github.com/google/ExoPlayer source code
final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
byte[] widevineId = mediaDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID);
if (widevineId == null) {
return "";
}
StringBuilder sb = new StringBuilder();
for (byte aByte : widevineId) {
sb.append(String.format("%02x", aByte));
}
return sb.toString();
} catch (Exception | Error e) {
e.printStackTrace();
}
return "";
}
/**
* 获取数字版权管理设备ID,进行MD5加密获取32位的唯一标记给后台生成SN
*
* @return WidevineID可能为空
*/
public static String getWidevineIDWithMd5(Context context) {
try {
String widevineId = getWidevineID(context);
if (!TextUtils.isEmpty(widevineId)) {
widevineId = EncryptUtils.encryptHmacMD5ToString(widevineId, "MoGoAuto");
return widevineId;
} else {
return getDeviceId(context);
}
} catch (Exception | Error e) {
e.printStackTrace();
}
return getDeviceId(context);
}
}

View File

@@ -55,14 +55,6 @@ public final class TimeUtils {
throw new UnsupportedOperationException("u can't instantiate me...");
}
@SuppressLint("SimpleDateFormat")
public static String formatYMD(long time){
Date date = new Date(time);
String strDateFormat = "yyyy-MM-dd";
SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);
return sdf.format(date);
}
/**
* Milliseconds to the formatted time string.
* <p>The pattern is {@code yyyy-MM-dd HH:mm:ss}.</p>
@@ -1532,8 +1524,8 @@ public final class TimeUtils {
return CHINESE_ZODIAC[year % 12];
}
private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22};
private static final String[] ZODIAC = {
private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22};
private static final String[] ZODIAC = {
"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座",
"狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"
};

View File

@@ -179,13 +179,12 @@ public abstract class AbsMogoApplication extends Application {
*/
protected void registerSocketHttpDnsTTL(String host) {
sApis.addressChangedListener(map -> {
Logger.d("TEST-SOCKET", "ttl callBack ,ready to getCache Dns IP");
String dnsCacheIp = sApis.getCachedHttpDnsIps(host, HTTP_DNS_ADDRESS_TYPE_HTTP);
if (dnsCacheIp == null) {
return;
}
Logger.d("TEST-SOCKET", "获取缓存Dns IP : " + dnsCacheIp + " , 原缓存 IP " + cacheIp);
if (!dnsCacheIp.equals(cacheIp)) {
Logger.d("TEST-SOCKET", "获取缓存Dns IP : " + dnsCacheIp + " , 原缓存 IP " + cacheIp);
socketTTL();
this.cacheIp = dnsCacheIp;
}

View File

@@ -32,12 +32,12 @@ kapt.include.compile.classpath=false
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# Android operating system, and which are packaged with your app'protoc_platforms APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
android.jetifier.blacklist=module-service-2.1.16.8.aar
android.jetifier.blacklist=module-service-2.1.16.10.aar
## maven 配置
RELEASE_REPOSITORY_URL=http://nexus.zhidaoauto.com/repository/maven-releases/
SNAPSHOT_REPOSITORY_URL=http://nexus.zhidaoauto.com/repository/maven-snapshots/
@@ -56,28 +56,30 @@ bytex.forbidUseLenientMutationDuringGetArtifact=true
bytex.verifyProguardConfigurationChanged=false
bytex.ASM_API=ASM7
HOOK_LOG_VERSION=1.4.109
SERVICE_CHAIN_VERSION=1.0.43
HOOK_LOG_VERSION=1.5.17
SERVICE_CHAIN_VERSION=1.0.53
################ 外部依赖引用 ################
# loglib
LOGLIB_VERSION=1.1.18
LOGLIB_VERSION=1.2.8
######## MogoAiCloudSDK Version ########
# 网络请求
MOGO_NETWORK_VERSION=1.3.18
MOGO_NETWORK_VERSION=1.3.30
# 鉴权
MOGO_PASSPORT_VERSION=1.3.18
MOGO_PASSPORT_VERSION=1.3.30
# 常链接
MOGO_SOCKET_VERSION=1.3.18
MOGO_SOCKET_VERSION=1.3.30
# 数据采集
MOGO_REALTIME_VERSION=1.3.18
MOGO_REALTIME_VERSION=1.3.30
# 探路,道路事件发布,获取
MOGO_TANLU_VERSION=1.3.18
MOGO_TANLU_VERSION=1.3.30
# 直播推流
MOGO_LIVE_VERSION=1.3.18
MOGO_LIVE_VERSION=1.3.30
# 直播拉流
MOGO_TRAFFICLIVE_VERSION=1.3.18
MOGO_TRAFFICLIVE_VERSION=1.3.30
# 定位服务
MOGO_LOCATION_VERSION=1.3.18
MOGO_LOCATION_VERSION=1.3.30
# 远程通讯模块
MOGO_TELEMATIC_VERSION=1.3.30
######## MogoAiCloudSDK Version ########
# 自研地图
MAP_SDK_VERSION=2.0.5.1
@@ -92,105 +94,107 @@ versionCode=80008
versionName=2.5.1
################# 新架构模块Maven版本管理 #################
MOGO_CORE_FUNCTION_AUTOPILOT_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_CHECK_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_HMI_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_MAIN_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_MAP_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_MONITORING_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_NOTICE_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_OBU_MOGO_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_SMP_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_V2X_VERSION=0.0.58.8
MOGO_CORE_DATA_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_API_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_CALL_VERSION=0.0.58.8
MOGO_CORE_RES_VERSION=0.0.58.8
MOGO_CORE_UTILS_VERSION=0.0.58.8
MOGO_CORE_NETWORK_VERSION=0.0.58.8
MOGO_CORE_FUNCTION_AUTOPILOT_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_CHECK_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_HMI_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_MAIN_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_MAP_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_MONITORING_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_NOTICE_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_OBU_MOGO_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_SMP_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_V2X_VERSION=0.0.58.10
MOGO_CORE_DATA_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_API_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_CALL_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_CARCORDER_VERSION=0.0.58.10
MOGO_CORE_FUNCTION_DEVATOOLS_VERSION=0.0.58.10
MOGO_CORE_RES_VERSION=0.0.58.10
MOGO_CORE_UTILS_VERSION=0.0.58.10
MOGO_CORE_NETWORK_VERSION=0.0.58.10
################# 旧版本架构模块版本 #################
## 工程内模块
MOGO_COMMONS_VERSION=2.1.16.8
MOGO_UTILS_VERSION=2.1.16.8
MAP_AMAP_VERSION=2.1.16.8
MAP_AUTONAVI_VERSION=2.1.16.8
MOGO_MAP_VERSION=2.1.16.8
MOGO_MAP_API_VERSION=2.1.16.8
MOGO_SERVICE_VERSION=2.1.16.8
MOGO_SERVICE_API_VERSION=2.1.16.8
MOGO_CONNECTION_VERSION=2.1.16.8
MOGO_MODULE_APPS_VERSION=2.1.16.8
MOGO_MODULE_NAVI_VERSION=2.1.16.8
MOGO_MODULE_SHARE_VERSION=2.1.16.8
MOGO_MODULE_COMMON_VERSION=2.1.16.8
MOGO_MODULE_MAIN_VERSION=2.1.16.8
MOGO_MODULE_MAP_VERSION=2.1.16.8
MOGO_MODULE_SERVICE_VERSION=2.1.16.8
MOGO_MODULE_EXTENSIONS_VERSION=2.1.16.8
MOGO_MODULE_SEARCH_VERSION=2.1.16.8
MOGO_MODULE_BACK_VERSION=2.1.16.8
MOGO_MODULE_V2X_VERSION=2.1.16.8
MOGO_COMMONS_VERSION=2.1.16.10
MOGO_UTILS_VERSION=2.1.16.10
MAP_AMAP_VERSION=2.1.16.10
MAP_AUTONAVI_VERSION=2.1.16.10
MOGO_MAP_VERSION=2.1.16.10
MOGO_MAP_API_VERSION=2.1.16.10
MOGO_SERVICE_VERSION=2.1.16.10
MOGO_SERVICE_API_VERSION=2.1.16.10
MOGO_CONNECTION_VERSION=2.1.16.10
MOGO_MODULE_APPS_VERSION=2.1.16.10
MOGO_MODULE_NAVI_VERSION=2.1.16.10
MOGO_MODULE_SHARE_VERSION=2.1.16.10
MOGO_MODULE_COMMON_VERSION=2.1.16.10
MOGO_MODULE_MAIN_VERSION=2.1.16.10
MOGO_MODULE_MAP_VERSION=2.1.16.10
MOGO_MODULE_SERVICE_VERSION=2.1.16.10
MOGO_MODULE_EXTENSIONS_VERSION=2.1.16.10
MOGO_MODULE_SEARCH_VERSION=2.1.16.10
MOGO_MODULE_BACK_VERSION=2.1.16.10
MOGO_MODULE_V2X_VERSION=2.1.16.10
# 探路
MOGO_MODULE_TANLU_VERSION=2.1.16.8
MOGO_MODULE_TANLU_VERSION=2.1.16.10
# 推送
MOGO_MODULE_PUSH_VERSION=2.1.16.8
MOGO_MODULE_PUSH_BASE_VERSION=2.1.16.8
MOGO_MODULE_PUSH_NOOP_VERSION=2.1.16.8
MOGO_MODULE_PUSH_VERSION=2.1.16.10
MOGO_MODULE_PUSH_BASE_VERSION=2.1.16.10
MOGO_MODULE_PUSH_NOOP_VERSION=2.1.16.10
# 探路上报和分享模块
TANLULIB_VERSION=2.1.16.8
MOGO_TANLU_API_VERSION=2.1.16.8
TANLULIB_VERSION=2.1.16.10
MOGO_TANLU_API_VERSION=2.1.16.10
#左侧面板模块
MOGO_MODULE_LEFT_PANEL_VERSION=2.1.16.8
MOGO_MODULE_LEFT_PANEL_NOOP_VERSION=2.1.16.8
MOGO_MODULE_LEFT_PANEL_VERSION=2.1.16.10
MOGO_MODULE_LEFT_PANEL_NOOP_VERSION=2.1.16.10
# 小控件
MOGO_MODULE_WIDGETS_VERSION=2.1.16.8
MOGO_MODULE_WIDGETS_VERSION=2.1.16.10
# obu
MOGO_MODULE_OBU_VERSION=2.1.16.8
MOGO_MODULE_OBU_MOGO_VERSION=2.1.16.8
MOGO_MODULE_OBU_VERSION=2.1.16.10
MOGO_MODULE_OBU_MOGO_VERSION=2.1.16.10
# monitor
MOGO_MODULE_MONITOR_VERSION=2.1.16.8
MOGO_MODULE_MONITOR_VERSION=2.1.16.10
# bugly
CRASHREPORT_VERSION=2.1.16.8
CRASHREPORT_BUGLY_VERSION=2.1.16.8
CRASHREPORT_NOOP_VERSION=2.1.16.8
CRASHREPORT_APMBYTE_VERSION=2.1.16.8
CRASHREPORT_UPGRADE_VERSION=2.1.16.8
CRASHREPORT_VERSION=2.1.16.10
CRASHREPORT_BUGLY_VERSION=2.1.16.10
CRASHREPORT_NOOP_VERSION=2.1.16.10
CRASHREPORT_APMBYTE_VERSION=2.1.16.10
CRASHREPORT_UPGRADE_VERSION=2.1.16.10
## tts
TTS_BASE_VERSION=2.1.16.8
TTS_DI_VERSION=2.1.16.8
TTS_ZHI_VERSION=2.1.16.8
TTS_PAD_VERSION=2.1.16.8
TTS_NOOP_VERSION=2.1.16.8
TTS_BASE_VERSION=2.1.16.10
TTS_DI_VERSION=2.1.16.10
TTS_ZHI_VERSION=2.1.16.10
TTS_PAD_VERSION=2.1.16.10
TTS_NOOP_VERSION=2.1.16.10
# 自研地图
MAP_CUSTOM_VERSION=2.1.16.8
MOGO_MODULE_ADAS_VERSION=2.1.16.8
MAP_CUSTOM_VERSION=2.1.16.10
MOGO_MODULE_ADAS_VERSION=2.1.16.10
# 基础服务实现passport、socket、location
MOGO_BASE_WEBSOCKET_SDK_VERSION=2.1.16.8
MOGO_BASE_SERVICES_APK_VERSION=2.1.16.8
MOGO_BASE_SERVICES_SDK_VERSION=2.1.16.8
MOGO_MODULE_CHAT_VERSION=2.1.16.8
MOGO_BASE_WEBSOCKET_SDK_VERSION=2.1.16.10
MOGO_BASE_SERVICES_APK_VERSION=2.1.16.10
MOGO_BASE_SERVICES_SDK_VERSION=2.1.16.10
MOGO_MODULE_CHAT_VERSION=2.1.16.10
# 车聊聊
MOGO_MODULE_CARCHATTING_VERSION=2.1.16.8
MOGO_MODULE_CARCHATTING_VERSION=2.1.16.10
# 车聊聊接口
MOGO_MODULE_CARCHATTINGPROVIDER_VERSION=2.1.16.8
MOGO_MODULE_CARCHATTINGPROVIDER_VERSION=2.1.16.10
# 皮肤
MOGO_SKIN_SUPPORT_VERSION=2.1.16.8
MOGO_SKIN_LIGHT_VERSION=2.1.16.8
MOGO_SKIN_SUPPORT_IMPL_VERSION=2.1.16.8
MOGO_SKIN_SUPPORT_NOOP_VERSION=2.1.16.8
SKIN_SUPPORT_VERSION=2.1.16.8
SKIN_SUPPORT_APPCOMPAT_VERSION=2.1.16.8
SKIN_SUPPORT_CARDVIEW_VERSION=2.1.16.8
SKIN_SUPPORT_CONSTRAINT_LAYOUT_VERSION=2.1.16.8
SKIN_SUPPORT_DESIGN_VERSION=2.1.16.8
MOGO_SKIN_SUPPORT_VERSION=2.1.16.10
MOGO_SKIN_LIGHT_VERSION=2.1.16.10
MOGO_SKIN_SUPPORT_IMPL_VERSION=2.1.16.10
MOGO_SKIN_SUPPORT_NOOP_VERSION=2.1.16.10
SKIN_SUPPORT_VERSION=2.1.16.10
SKIN_SUPPORT_APPCOMPAT_VERSION=2.1.16.10
SKIN_SUPPORT_CARDVIEW_VERSION=2.1.16.10
SKIN_SUPPORT_CONSTRAINT_LAYOUT_VERSION=2.1.16.10
SKIN_SUPPORT_DESIGN_VERSION=2.1.16.10
# OCH
MOGO_OCH_VERSION=2.1.16.8-test
MOGO_OCH_VERSION=2.1.16.10-test
MOGO_OCH_BUS_VERSION=2.0.66
MOGO_OCH_NOOP_VERSION=2.0.66
MOGO_OCH_TAXI_VERSION=2.0.66
# mogoAiCloud sdk services
MOGO_AICLOUD_SERVICES_SDK_VERSION=2.1.16.8
MOGO_AICLOUD_SERVICES_SDK_VERSION=2.1.16.10
# v2x-sdk
MOGO_V2X_SDK_VERSION=1.0.1
MOGO_V2X_SDK_VERSION=1.3.30
################# 旧版本架构模块版本 #################

View File

@@ -1,5 +1,8 @@
package com.mogo.map.impl.custom;
import static com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_300;
import static com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_CROSS;
import static com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_TOP;
import static com.mogo.map.uicontroller.VisualAngleMode.MODE_CLOSE_SIGHT;
import static com.mogo.map.uicontroller.VisualAngleMode.MODE_LONG_SIGHT;
import static com.mogo.map.uicontroller.VisualAngleMode.MODE_MEDIUM_SIGHT;
@@ -767,6 +770,12 @@ public class AMapViewWrapper implements IMogoMapView,
return MODE_MEDIUM_SIGHT;
case 2:
return MODE_LONG_SIGHT;
case 3:
return MAP_STYLE_VR_ANGLE_300;
case 4:
return MAP_STYLE_VR_ANGLE_TOP;
case 5:
return MAP_STYLE_VR_ANGLE_CROSS;
default:
throw new IllegalStateException("mode is unCorrect");
}

View File

@@ -62,7 +62,6 @@ dependencies {
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation rootProject.ext.dependencies.arouter
kapt rootProject.ext.dependencies.aroutercompiler
//implementation(name: 'common-4.1.1', ext: 'aar')
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {

View File

@@ -0,0 +1,39 @@
package com.mogo.usbcamera;
import com.serenegiant.usb.USBMonitor;
/**
* @author donghongyu
* USB摄像头方案获取权限、获取YUV数据
*/
public class USBCameraHelper {
private static USBCameraHelper mCameraHelper;
/**
* USB Manager
*/
private USBMonitor mUSBMonitor;
private USBCameraHelper() {
}
public static USBCameraHelper getInstance() {
if (mCameraHelper == null) {
mCameraHelper = new USBCameraHelper();
}
return mCameraHelper;
}
public void registerUSB() {
if (mUSBMonitor != null) {
mUSBMonitor.register();
}
}
public void unregisterUSB() {
if (mUSBMonitor != null) {
mUSBMonitor.unregister();
}
}
}

View File

@@ -22,10 +22,7 @@ import java.util.Objects;
/**
* UVCCamera Helper class
* <p>
* Created by jiangdongguo on 2017/9/30.
*/
public class UVCCameraHelper {
public static final String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator;
@@ -77,6 +74,9 @@ public class UVCCameraHelper {
void onConnectDev(UsbDevice device, boolean isConnected);
void onDisConnectDev(UsbDevice device);
void onCancelDev(UsbDevice device);
}
public void initUSBMonitor(Activity activity, CameraViewInterface cameraView, final OnMyDevConnectListener listener) {
@@ -109,18 +109,15 @@ public class UVCCameraHelper {
public void onConnect(final UsbDevice device, USBMonitor.UsbControlBlock ctrlBlock, boolean createNew) {
mCtrlBlock = ctrlBlock;
openCamera(ctrlBlock);
new Thread(new Runnable() {
@Override
public void run() {
// wait for camera created
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// start previewing
startPreview(mCamView);
new Thread(() -> {
// wait for camera created
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// start previewing
startPreview(mCamView);
}).start();
if (listener != null) {
listener.onConnectDev(device, true);
@@ -138,6 +135,9 @@ public class UVCCameraHelper {
@Override
public void onCancel(UsbDevice device) {
if (listener != null) {
listener.onCancelDev(device);
}
}
});
@@ -252,7 +252,6 @@ public class UVCCameraHelper {
public void capturePicture(String savePath, AbstractUVCCameraHandler.OnCaptureListener listener) {
if (mCameraHandler != null && mCameraHandler.isOpened()) {
File file = new File(savePath);
if (!Objects.requireNonNull(file.getParentFile()).exists()) {
file.getParentFile().mkdirs();

View File

@@ -0,0 +1,23 @@
package com.serenegiant.dialog;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
public abstract class DialogFragmentEx extends DialogFragment {
protected static final String ARGS_KEY_REQUEST_CODE = "requestCode";
protected static final String ARGS_KEY_ID_TITLE = "title";
protected static final String ARGS_KEY_ID_MESSAGE = "message";
protected static final String ARGS_KEY_TAG = "tag";
@Override
public void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
final Bundle args = getArguments();
if (args != null) {
outState.putAll(args);
}
}
}

View File

@@ -0,0 +1,136 @@
package com.serenegiant.dialog;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import com.serenegiant.utils.BuildCheck;
/**
* パーミッション要求前に説明用のダイアログを表示するためのDialogFragment
*/
@SuppressWarnings("deprecation")
@Deprecated
public class MessageDialogFragment extends DialogFragment {
// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること
private static final String TAG = MessageDialogFragment.class.getSimpleName();
public static interface MessageDialogListener {
public void onMessageDialogResult(final MessageDialogFragment dialog, final int requestCode, final String[] permissions, final boolean result);
}
public static MessageDialogFragment showDialog(final Activity parent, final int requestCode, final int id_title, final int id_message, final String[] permissions) {
final MessageDialogFragment dialog = newInstance(requestCode, id_title, id_message, permissions);
dialog.show(parent.getFragmentManager(), TAG);
return dialog;
}
public static MessageDialogFragment showDialog(final Fragment parent, final int requestCode, final int id_title, final int id_message, final String[] permissions) {
final MessageDialogFragment dialog = newInstance(requestCode, id_title, id_message, permissions);
dialog.setTargetFragment(parent, parent.getId());
dialog.show(parent.getFragmentManager(), TAG);
return dialog;
}
public static MessageDialogFragment newInstance(final int requestCode, final int id_title, final int id_message, final String[] permissions) {
final MessageDialogFragment fragment = new MessageDialogFragment();
final Bundle args = new Bundle();
// ここでパラメータをセットする
args.putInt("requestCode", requestCode);
args.putInt("title", id_title);
args.putInt("message", id_message);
args.putStringArray("permissions", permissions != null ? permissions : new String[]{});
fragment.setArguments(args);
return fragment;
}
private MessageDialogListener mDialogListener;
public MessageDialogFragment() {
super();
// デフォルトコンストラクタが必要
}
@SuppressLint("NewApi")
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
// コールバックインターフェースを取得
if (activity instanceof MessageDialogListener) {
mDialogListener = (MessageDialogListener)activity;
}
if (mDialogListener == null) {
final Fragment fragment = getTargetFragment();
if (fragment instanceof MessageDialogListener) {
mDialogListener = (MessageDialogListener)fragment;
}
}
if (mDialogListener == null) {
if (BuildCheck.isAndroid4_2()) {
final Fragment target = getParentFragment();
if (target instanceof MessageDialogListener) {
mDialogListener = (MessageDialogListener)target;
}
}
}
if (mDialogListener == null) {
// Log.w(TAG, "caller activity/fragment must implement PermissionDetailDialogFragmentListener");
throw new ClassCastException(activity.toString());
}
}
// @Override
// public void onCreate(final Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// final Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
// }
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
final int requestCode = getArguments().getInt("requestCode");
final int id_title = getArguments().getInt("title");
final int id_message = getArguments().getInt("message");
final String[] permissions = args.getStringArray("permissions");
return new AlertDialog.Builder(getActivity())
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(id_title)
.setMessage(id_message)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int whichButton) {
// 本当はここでパーミッション要求をしたいだけどこのダイアログがdismissしてしまって結果を受け取れないので
// 呼び出し側へ返してそこでパーミッション要求する。なのでこのダイアログは単にメッセージを表示するだけ
try {
mDialogListener.onMessageDialogResult(MessageDialogFragment.this, requestCode, permissions, true);
} catch (final Exception e) {
Log.w(TAG, e);
}
}
}
)
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, int whichButton) {
try {
mDialogListener.onMessageDialogResult(MessageDialogFragment.this, requestCode, permissions, false);
} catch (final Exception e) {
Log.w(TAG, e);
}
}
}
)
.create();
}
}

View File

@@ -0,0 +1,213 @@
package com.serenegiant.dialog;
/*
* libcommon
* utility/helper classes for myself
*
* Copyright (c) 2014-2018 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.serenegiant.utils.BuildCheck;
public class MessageDialogFragmentV4 extends DialogFragmentEx {
// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること
private static final String TAG = MessageDialogFragmentV4.class.getSimpleName();
private static final String ARGS_KEY_PERMISSIONS = "permissions";
/**
* ダイアログの表示結果を受け取るためのコールバックリスナー
*/
public static interface MessageDialogListener {
public void onMessageDialogResult(
@NonNull final MessageDialogFragmentV4 dialog, final int requestCode,
@NonNull final String[] permissions, final boolean result);
}
/**
* ダイアログ表示のためのヘルパーメソッド
* @param parent
* @param requestCode
* @param id_title
* @param id_message
* @param permissions
* @return
* @throws IllegalStateException
*/
public static MessageDialogFragmentV4 showDialog(
@NonNull final FragmentActivity parent, final int requestCode,
@StringRes final int id_title, @StringRes final int id_message,
@NonNull final String[] permissions) throws IllegalStateException {
final MessageDialogFragmentV4 dialog
= newInstance(requestCode, id_title, id_message, permissions);
dialog.show(parent.getSupportFragmentManager(), TAG);
return dialog;
}
/**
* ダイアログ表示のためのヘルパーメソッド
* @param parent
* @param requestCode
* @param id_title
* @param id_message
* @param permissions
* @return
* @throws IllegalStateException
*/
public static MessageDialogFragmentV4 showDialog(
@NonNull final Fragment parent, final int requestCode,
@StringRes final int id_title, @StringRes final int id_message,
@NonNull final String[] permissions) throws IllegalStateException {
final MessageDialogFragmentV4 dialog
= newInstance(requestCode, id_title, id_message, permissions);
dialog.setTargetFragment(parent, parent.getId());
dialog.show(parent.requireFragmentManager(), TAG);
return dialog;
}
/**
* ダイアログ生成のためのヘルパーメソッド
* ダイアログ自体を直接生成せずにこのメソッドを呼び出すこと
* @param requestCode
* @param id_title
* @param id_message
* @param permissions
* @return
*/
public static MessageDialogFragmentV4 newInstance(
final int requestCode,
@StringRes final int id_title, @StringRes final int id_message,
@NonNull final String[] permissions) {
final MessageDialogFragmentV4 fragment = new MessageDialogFragmentV4();
final Bundle args = new Bundle();
// ここでパラメータをセットする
args.putInt(ARGS_KEY_REQUEST_CODE, requestCode);
args.putInt(ARGS_KEY_ID_TITLE, id_title);
args.putInt(ARGS_KEY_ID_MESSAGE, id_message);
args.putStringArray(ARGS_KEY_PERMISSIONS, permissions);
fragment.setArguments(args);
return fragment;
}
private MessageDialogListener mDialogListener;
/**
* コンストラクタ, 直接生成せずに#newInstanceを使うこと
*/
public MessageDialogFragmentV4() {
super();
// デフォルトコンストラクタが必要
}
@Override
public void onAttach(final Context context) {
super.onAttach(context);
// コールバックインターフェースを取得
if (context instanceof MessageDialogListener) {
mDialogListener = (MessageDialogListener)context;
}
if (mDialogListener == null) {
final Fragment fragment = getTargetFragment();
if (fragment instanceof MessageDialogListener) {
mDialogListener = (MessageDialogListener)fragment;
}
}
if (mDialogListener == null) {
if (BuildCheck.isAndroid4_2()) {
final Fragment target = getParentFragment();
if (target instanceof MessageDialogListener) {
mDialogListener = (MessageDialogListener)target;
}
}
}
if (mDialogListener == null) {
// Log.w(TAG, "caller activity/fragment must implement PermissionDetailDialogFragmentListener");
throw new ClassCastException(context.toString());
}
}
// @Override
// public void onCreate(final Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// final Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
// }
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = savedInstanceState != null ? savedInstanceState : requireArguments();
final int id_title = args.getInt(ARGS_KEY_ID_TITLE);
final int id_message = args.getInt(ARGS_KEY_ID_MESSAGE);
final Activity activity = requireActivity();
return new AlertDialog.Builder(activity)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(id_title)
.setMessage(id_message)
.setPositiveButton(android.R.string.ok, mOnClickListener)
.setNegativeButton(android.R.string.cancel, mOnClickListener)
.create();
}
private final DialogInterface.OnClickListener mOnClickListener
= new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
// 本当はここでパーミッション要求をしたいだけどこのダイアログがdismissしてしまって結果を受け取れないので
// 呼び出し側へ返してそこでパーミッション要求する。なのでこのダイアログは単にメッセージを表示するだけ
callOnMessageDialogResult(which == DialogInterface.BUTTON_POSITIVE);
}
};
@Override
public void onCancel(final DialogInterface dialog) {
super.onCancel(dialog);
callOnMessageDialogResult(false);
}
/**
* コールバックリスナー呼び出しのためのヘルパーメソッド
* @param result
*/
private void callOnMessageDialogResult(final boolean result)
throws IllegalStateException {
final Bundle args = requireArguments();
final int requestCode = args.getInt(ARGS_KEY_REQUEST_CODE);
final String[] permissions = args.getStringArray(ARGS_KEY_PERMISSIONS);
try {
mDialogListener.onMessageDialogResult(
MessageDialogFragmentV4.this,
requestCode, permissions, result);
} catch (final Exception e) {
Log.w(TAG, e);
}
}
}

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.app.Activity;
@@ -24,199 +47,192 @@ import java.util.ArrayList;
import java.util.List;
public class CameraDialog extends DialogFragment {
private static final String TAG = CameraDialog.class.getSimpleName();
private static final String TAG = CameraDialog.class.getSimpleName();
public interface CameraDialogParent {
public USBMonitor getUSBMonitor();
public interface CameraDialogParent {
public USBMonitor getUSBMonitor();
public void onDialogResult(boolean canceled);
}
/**
* Helper method
* @param parent FragmentActivity
* @return
*/
public static CameraDialog showDialog(final Activity parent/* add parameters here if you need */) {
CameraDialog dialog = newInstance(/* add parameters here if you need */);
try {
dialog.show(parent.getFragmentManager(), TAG);
} catch (final IllegalStateException e) {
dialog = null;
}
return dialog;
}
public void onDialogResult(boolean canceled);
}
public static CameraDialog newInstance(/* add parameters here if you need */) {
final CameraDialog dialog = new CameraDialog();
final Bundle args = new Bundle();
// add parameters here if you need
dialog.setArguments(args);
return dialog;
}
/**
* Helper method
*
* @param parent FragmentActivity
* @return
*/
public static CameraDialog showDialog(final Activity parent/* add parameters here if you need */) {
CameraDialog dialog = newInstance(/* add parameters here if you need */);
protected USBMonitor mUSBMonitor;
private Spinner mSpinner;
private DeviceListAdapter mDeviceListAdapter;
public CameraDialog(/* no arguments */) {
// Fragment need default constructor
}
@SuppressWarnings("deprecation")
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
if (mUSBMonitor == null)
try {
dialog.show(parent.getFragmentManager(), TAG);
} catch (final IllegalStateException e) {
dialog = null;
mUSBMonitor = ((CameraDialogParent)activity).getUSBMonitor();
} catch (final ClassCastException e) {
} catch (final NullPointerException e) {
}
return dialog;
}
if (mUSBMonitor == null) {
throw new ClassCastException(activity.toString() + " must implement CameraDialogParent#getUSBController");
}
}
public static CameraDialog newInstance(/* add parameters here if you need */) {
final CameraDialog dialog = new CameraDialog();
final Bundle args = new Bundle();
// add parameters here if you need
dialog.setArguments(args);
return dialog;
}
protected USBMonitor mUSBMonitor;
private Spinner mSpinner;
private DeviceListAdapter mDeviceListAdapter;
public CameraDialog(/* no arguments */) {
// Fragment need default constructor
}
@SuppressWarnings("deprecation")
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
if (mUSBMonitor == null) {
try {
mUSBMonitor = ((CameraDialogParent) activity).getUSBMonitor();
} catch (final NullPointerException | ClassCastException e) {
e.printStackTrace();
}
}
if (mUSBMonitor == null) {
throw new ClassCastException(activity.toString() + " must implement CameraDialogParent#getUSBController");
}
}
@Override
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
savedInstanceState = getArguments();
}
}
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
savedInstanceState = getArguments();
}
@Override
public void onSaveInstanceState(final Bundle saveInstanceState) {
final Bundle args = getArguments();
if (args != null) {
saveInstanceState.putAll(args);
}
super.onSaveInstanceState(saveInstanceState);
}
@Override
public void onSaveInstanceState(final Bundle saveInstanceState) {
final Bundle args = getArguments();
if (args != null)
saveInstanceState.putAll(args);
super.onSaveInstanceState(saveInstanceState);
}
@Override
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(initView());
builder.setTitle(R.string.select);
builder.setPositiveButton(android.R.string.ok, mOnDialogClickListener);
builder.setNegativeButton(android.R.string.cancel, mOnDialogClickListener);
builder.setNeutralButton(R.string.refresh, null);
final Dialog dialog = builder.create();
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(initView());
builder.setTitle(R.string.select);
builder.setPositiveButton(android.R.string.ok, mOnDialogClickListener);
builder.setNegativeButton(android.R.string.cancel , mOnDialogClickListener);
builder.setNeutralButton(R.string.refresh, null);
final Dialog dialog = builder.create();
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
}
/**
* create view that this fragment shows
*
* @return
*/
private final View initView() {
final View rootView = getActivity().getLayoutInflater().inflate(R.layout.dialog_camera, null);
mSpinner = (Spinner) rootView.findViewById(R.id.spinner1);
final View empty = rootView.findViewById(android.R.id.empty);
mSpinner.setEmptyView(empty);
return rootView;
}
/**
* create view that this fragment shows
* @return
*/
private final View initView() {
final View rootView = getActivity().getLayoutInflater().inflate(R.layout.dialog_camera, null);
mSpinner = (Spinner)rootView.findViewById(R.id.spinner1);
final View empty = rootView.findViewById(android.R.id.empty);
mSpinner.setEmptyView(empty);
return rootView;
}
@Override
public void onResume() {
super.onResume();
updateDevices();
final Button button = (Button) getDialog().findViewById(android.R.id.button3);
if (button != null) {
button.setOnClickListener(mOnClickListener);
}
}
@Override
public void onResume() {
super.onResume();
updateDevices();
final Button button = (Button)getDialog().findViewById(android.R.id.button3);
if (button != null) {
button.setOnClickListener(mOnClickListener);
}
}
private final OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
switch (v.getId()) {
case android.R.id.button3:
updateDevices();
break;
}
}
};
private final OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
switch (v.getId()) {
case android.R.id.button3:
updateDevices();
break;
}
}
};
private final DialogInterface.OnClickListener mOnDialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final Object item = mSpinner.getSelectedItem();
if (item instanceof UsbDevice) {
mUSBMonitor.requestPermission((UsbDevice) item);
((CameraDialogParent) getActivity()).onDialogResult(false);
}
break;
case DialogInterface.BUTTON_NEGATIVE:
((CameraDialogParent) getActivity()).onDialogResult(true);
break;
}
}
};
private final DialogInterface.OnClickListener mOnDialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final Object item = mSpinner.getSelectedItem();
if (item instanceof UsbDevice) {
mUSBMonitor.requestPermission((UsbDevice)item);
((CameraDialogParent)getActivity()).onDialogResult(false);
}
break;
case DialogInterface.BUTTON_NEGATIVE:
((CameraDialogParent)getActivity()).onDialogResult(true);
break;
}
}
};
@Override
public void onCancel(final DialogInterface dialog) {
((CameraDialogParent) getActivity()).onDialogResult(true);
super.onCancel(dialog);
}
@Override
public void onCancel(final DialogInterface dialog) {
((CameraDialogParent)getActivity()).onDialogResult(true);
super.onCancel(dialog);
}
public void updateDevices() {
public void updateDevices() {
// mUSBMonitor.dumpDevices();
final List<DeviceFilter> filter = DeviceFilter.getDeviceFilters(getActivity(), R.xml.device_filter);
mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0)));
mSpinner.setAdapter(mDeviceListAdapter);
}
final List<DeviceFilter> filter = DeviceFilter.getDeviceFilters(getActivity(), R.xml.device_filter);
mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0)));
mSpinner.setAdapter(mDeviceListAdapter);
}
private static final class DeviceListAdapter extends BaseAdapter {
private static final class DeviceListAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private final List<UsbDevice> mList;
private final LayoutInflater mInflater;
private final List<UsbDevice> mList;
public DeviceListAdapter(final Context context, final List<UsbDevice> list) {
mInflater = LayoutInflater.from(context);
mList = list != null ? list : new ArrayList<UsbDevice>();
}
public DeviceListAdapter(final Context context, final List<UsbDevice>list) {
mInflater = LayoutInflater.from(context);
mList = list != null ? list : new ArrayList<UsbDevice>();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public UsbDevice getItem(final int position) {
if ((position >= 0) && (position < mList.size())) {
return mList.get(position);
} else {
return null;
}
}
@Override
public UsbDevice getItem(final int position) {
if ((position >= 0) && (position < mList.size()))
return mList.get(position);
else
return null;
}
@Override
public long getItemId(final int position) {
return position;
}
@Override
public long getItemId(final int position) {
return position;
}
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem_device, parent, false);
}
if (convertView instanceof CheckedTextView) {
final UsbDevice device = getItem(position);
((CheckedTextView) convertView).setText(
String.format("UVC Camera:(%x:%x:%s)", device.getVendorId(), device.getProductId(), device.getDeviceName()));
}
return convertView;
}
}
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem_device, parent, false);
}
if (convertView instanceof CheckedTextView) {
final UsbDevice device = getItem(position);
((CheckedTextView)convertView).setText(
String.format("UVC Camera:(%x:%x:%s)", device.getVendorId(), device.getProductId(), device.getDeviceName()));
}
return convertView;
}
}
}

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.content.Context;

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import java.nio.ByteBuffer;

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.os.Parcel;

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.annotation.SuppressLint;
@@ -97,20 +120,15 @@ public final class USBMonitor {
}
public USBMonitor(final Context context, final OnDeviceConnectListener listener) {
if (DEBUG) {
Log.v(TAG, "USBMonitor:Constructor");
}
if (listener == null) {
if (DEBUG) Log.v(TAG, "USBMonitor:Constructor");
if (listener == null)
throw new IllegalArgumentException("OnDeviceConnectListener should not null.");
}
mWeakContext = new WeakReference<Context>(context);
mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
mOnDeviceConnectListener = listener;
mAsyncHandler = HandlerThreadHandler.createHandler(TAG);
destroyed = false;
if (DEBUG) {
Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager);
}
if (DEBUG) Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager);
}
/**
@@ -118,9 +136,7 @@ public final class USBMonitor {
* never reuse again
*/
public void destroy() {
if (DEBUG) {
Log.i(TAG, "destroy:");
}
if (DEBUG) Log.i(TAG, "destroy:");
unregister();
if (!destroyed) {
destroyed = true;
@@ -153,13 +169,9 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public synchronized void register() throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
if (mPermissionIntent == null) {
if (DEBUG) {
Log.i(TAG, "register:");
}
if (DEBUG) Log.i(TAG, "register:");
final Context context = mWeakContext.get();
if (context != null) {
mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
@@ -209,9 +221,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public void setDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.clear();
mDeviceFilters.add(filter);
}
@@ -222,9 +232,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public void addDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.add(filter);
}
@@ -234,9 +242,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public void removeDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.remove(filter);
}
@@ -246,9 +252,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public void setDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.clear();
mDeviceFilters.addAll(filters);
}
@@ -259,9 +263,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public void addDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.addAll(filters);
}
@@ -270,9 +272,7 @@ public final class USBMonitor {
* @param filters
*/
public void removeDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.removeAll(filters);
}
@@ -282,9 +282,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public int getDeviceCount() throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
return getDeviceList().size();
}
@@ -294,9 +292,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public List<UsbDevice> getDeviceList() throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
return getDeviceList(mDeviceFilters);
}
@@ -307,9 +303,7 @@ public final class USBMonitor {
* @throws IllegalStateException
*/
public List<UsbDevice> getDeviceList(final List<DeviceFilter> filters) throws IllegalStateException {
if (destroyed) {
throw new IllegalStateException("already destroyed");
}
if (destroyed) throw new IllegalStateException("already destroyed");
// get detected devices
final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
// store those devices info before matching filter xml file
@@ -353,8 +347,8 @@ public final class USBMonitor {
break;
} else {
// collection failed dev's class and subclass
String devModel = android.os.Build.MODEL;
String devSystemVersion = android.os.Build.VERSION.RELEASE;
String devModel = Build.MODEL;
String devSystemVersion = Build.VERSION.RELEASE;
String devClass = String.valueOf(device.getDeviceClass());
String subClass = String.valueOf(device.getDeviceSubclass());
try{

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.util.SparseArray;

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.graphics.SurfaceTexture;

View File

@@ -2,9 +2,7 @@ package com.serenegiant.usb.common;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
@@ -22,7 +20,6 @@ import android.view.Surface;
import android.view.SurfaceHolder;
import com.serenegiant.usb.IFrameCallback;
import com.serenegiant.usb.ParentPreviewConstraintLayout;
import com.serenegiant.usb.Size;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.UVCCamera;
@@ -52,7 +49,6 @@ import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -68,19 +64,19 @@ public abstract class AbstractUVCCameraHandler extends Handler {
// 对外回调接口
public interface CameraCallback {
void onOpen();
public void onOpen();
void onClose();
public void onClose();
void onStartPreview();
public void onStartPreview();
void onStopPreview();
public void onStopPreview();
void onStartRecording();
public void onStartRecording();
void onStopRecording();
public void onStopRecording();
void onError(final Exception e);
public void onError(final Exception e);
}
public static OnEncodeResultListener mListener;
@@ -180,16 +176,12 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
public void close() {
if (DEBUG) {
Log.v(TAG, "close:");
}
if (DEBUG) Log.v(TAG, "close:");
if (isOpened()) {
stopPreview();
sendEmptyMessage(MSG_CLOSE);
}
if (DEBUG) {
Log.v(TAG, "close:finished");
}
if (DEBUG) Log.v(TAG, "close:finished");
}
// 切换分辨率
@@ -214,18 +206,14 @@ public abstract class AbstractUVCCameraHandler extends Handler {
// 关闭Camera预览
public void stopPreview() {
if (DEBUG) {
Log.v(TAG, "stopPreview:");
}
if (DEBUG) Log.v(TAG, "stopPreview:");
removeMessages(MSG_PREVIEW_START);
if (isRecording()) {
stopRecording();
}
if (isPreviewing()) {
final CameraThread thread = mWeakThread.get();
if (thread == null) {
return;
}
if (thread == null) return;
synchronized (thread.mSync) {
sendEmptyMessage(MSG_PREVIEW_STOP);
if (!isCameraThread()) {
@@ -239,12 +227,10 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
}
}
if (DEBUG) {
Log.v(TAG, "stopPreview:finished");
}
if (DEBUG) Log.v(TAG, "stopPreview:finished");
}
public void captureStill(final String path, AbstractUVCCameraHandler.OnCaptureListener listener) {
public void captureStill(final String path, OnCaptureListener listener) {
AbstractUVCCameraHandler.mCaptureListener = listener;
checkReleased();
sendMessage(obtainMessage(MSG_CAPTURE_STILL, path));
@@ -366,9 +352,7 @@ public abstract class AbstractUVCCameraHandler extends Handler {
@Override
public void handleMessage(final Message msg) {
final CameraThread thread = mWeakThread.get();
if (thread == null) {
return;
}
if (thread == null) return;
switch (msg.what) {
case MSG_OPEN:
thread.handleOpen((USBMonitor.UsbControlBlock) msg.obj);
@@ -472,17 +456,13 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
public AbstractUVCCameraHandler getHandler() {
if (DEBUG) {
Log.v(TAG_THREAD, "getHandler:");
}
if (DEBUG) Log.v(TAG_THREAD, "getHandler:");
synchronized (mSync) {
if (mHandler == null) {
if (mHandler == null)
try {
mSync.wait();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
return mHandler;
}
@@ -528,9 +508,7 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
public void handleOpen(final USBMonitor.UsbControlBlock ctrlBlock) {
if (DEBUG) {
Log.v(TAG_THREAD, "handleOpen:");
}
if (DEBUG) Log.v(TAG_THREAD, "handleOpen:");
handleClose();
try {
final UVCCamera camera = new UVCCamera();
@@ -542,15 +520,12 @@ public abstract class AbstractUVCCameraHandler extends Handler {
} catch (final Exception e) {
callOnError(e);
}
if (DEBUG) {
if (DEBUG)
Log.i(TAG, "supportedSize:" + (mUVCCamera != null ? mUVCCamera.getSupportedSize() : null));
}
}
public void handleClose() {
if (DEBUG) {
Log.v(TAG_THREAD, "handleClose:");
}
if (DEBUG) Log.v(TAG_THREAD, "handleClose:");
handleStopPusher();
final UVCCamera camera;
synchronized (mSync) {
@@ -565,12 +540,8 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
public void handleStartPreview(final Object surface) {
if (DEBUG) {
Log.v(TAG_THREAD, "handleStartPreview:");
}
if ((mUVCCamera == null) || mIsPreviewing) {
return;
}
if (DEBUG) Log.v(TAG_THREAD, "handleStartPreview:");
if ((mUVCCamera == null) || mIsPreviewing) return;
try {
mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, mPreviewMode, mBandwidthFactor);
// 获取USB Camera预览数据使用NV21颜色会失真
@@ -603,9 +574,7 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
public void handleStopPreview() {
if (DEBUG) {
Log.v(TAG_THREAD, "handleStopPreview:");
}
if (DEBUG) Log.v(TAG_THREAD, "handleStopPreview:");
if (mIsPreviewing) {
if (mUVCCamera != null) {
mUVCCamera.stopPreview();
@@ -617,20 +586,14 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
callOnStopPreview();
}
if (DEBUG) {
Log.v(TAG_THREAD, "handleStopPreview:finished");
}
if (DEBUG) Log.v(TAG_THREAD, "handleStopPreview:finished");
}
// 捕获静态图片
public void handleCaptureStill(final String path) {
if (DEBUG) {
Log.v(TAG_THREAD, "handleCaptureStill:");
}
if (DEBUG) Log.v(TAG_THREAD, "handleCaptureStill:");
final Activity parent = mWeakParent.get();
if (parent == null) {
return;
}
if (parent == null) return;
// mSoundPool.play(mSoundId, 0.2f, 0.2f, 0, 0, 1.0f); // play shutter sound
try {
final Bitmap bitmap = mWeakCameraView.get().captureStillImage(mWidth, mHeight);
@@ -647,7 +610,6 @@ public abstract class AbstractUVCCameraHandler extends Handler {
os.flush();
mHandler.sendMessage(mHandler.obtainMessage(MSG_MEDIA_UPDATE, outputFile.getPath()));
} catch (final IOException e) {
e.printStackTrace();
}
} finally {
os.close();
@@ -706,9 +668,8 @@ public abstract class AbstractUVCCameraHandler extends Handler {
private H264EncodeConsumer mH264Consumer;
public void handleStartPusher(RecordParams params) {
if ((mUVCCamera == null) || (mH264Consumer != null)) {
if ((mUVCCamera == null) || (mH264Consumer != null))
return;
}
// // 获取USB Camera预览数据
// mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21);
@@ -747,9 +708,8 @@ public abstract class AbstractUVCCameraHandler extends Handler {
// 停止音视频编码线程
stopAudioRecord();
stopVideoRecord();
if(isSupportOverlay) {
if(isSupportOverlay)
TxtOverlay.getInstance().release();
}
// // 停止捕获视频数据
// if (mUVCCamera != null) {
// mUVCCamera.stopCapture();
@@ -915,23 +875,18 @@ public abstract class AbstractUVCCameraHandler extends Handler {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public void handleUpdateMedia(final String path) {
if (DEBUG) {
Log.v(TAG_THREAD, "handleUpdateMedia:path=" + path);
}
if (DEBUG) Log.v(TAG_THREAD, "handleUpdateMedia:path=" + path);
final Activity parent = mWeakParent.get();
final boolean released = (mHandler == null) || mHandler.mReleased;
if (parent != null && parent.getApplicationContext() != null) {
try {
if (DEBUG) {
Log.i(TAG, "MediaScannerConnection#scanFile");
}
if (DEBUG) Log.i(TAG, "MediaScannerConnection#scanFile");
MediaScannerConnection.scanFile(parent.getApplicationContext(), new String[]{path}, null, null);
} catch (final Exception e) {
Log.e(TAG, "handleUpdateMedia:", e);
}
if (released || parent.isDestroyed()) {
if (released || parent.isDestroyed())
handleRelease();
}
} else {
Log.w(TAG, "MainActivity already destroyed");
// give up to add this movie to MediaStore now.
@@ -941,71 +896,57 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
public void handleRelease() {
if (DEBUG) {
Log.v(TAG_THREAD, "handleRelease:mIsRecording=" + mIsRecording);
}
if (DEBUG) Log.v(TAG_THREAD, "handleRelease:mIsRecording=" + mIsRecording);
handleClose();
mCallbacks.clear();
if (!mIsRecording) {
mHandler.mReleased = true;
Looper.myLooper().quit();
}
if (DEBUG) {
Log.v(TAG_THREAD, "handleRelease:finished");
}
if (DEBUG) Log.v(TAG_THREAD, "handleRelease:finished");
}
// 自动对焦
public void handleCameraFoucs() {
if (DEBUG) {
Log.v(TAG_THREAD, "handleStartPreview:");
}
if ((mUVCCamera == null) || !mIsPreviewing) {
if (DEBUG) Log.v(TAG_THREAD, "handleStartPreview:");
if ((mUVCCamera == null) || !mIsPreviewing)
return;
}
mUVCCamera.setAutoFocus(true);
}
// 获取支持的分辨率
public List<Size> getSupportedSizes() {
if ((mUVCCamera == null) || !mIsPreviewing) {
if ((mUVCCamera == null) || !mIsPreviewing)
return null;
}
return mUVCCamera.getSupportedSizeList();
}
private final MediaEncoder.MediaEncoderListener mMediaEncoderListener = new MediaEncoder.MediaEncoderListener() {
@Override
public void onPrepared(final MediaEncoder encoder) {
if (DEBUG) {
Log.v(TAG, "onPrepared:encoder=" + encoder);
}
if (DEBUG) Log.v(TAG, "onPrepared:encoder=" + encoder);
mIsRecording = true;
if (encoder instanceof MediaVideoEncoder) {
if (encoder instanceof MediaVideoEncoder)
try {
mWeakCameraView.get().setVideoEncoder((MediaVideoEncoder) encoder);
} catch (final Exception e) {
Log.e(TAG, "onPrepared:", e);
}
}
if (encoder instanceof MediaSurfaceEncoder) {
if (encoder instanceof MediaSurfaceEncoder)
try {
mWeakCameraView.get().setVideoEncoder((MediaSurfaceEncoder) encoder);
mUVCCamera.startCapture(((MediaSurfaceEncoder) encoder).getInputSurface());
} catch (final Exception e) {
Log.e(TAG, "onPrepared:", e);
}
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onStopped(final MediaEncoder encoder) {
if (DEBUG) {
Log.v(TAG_THREAD, "onStopped:encoder=" + encoder);
}
if (DEBUG) Log.v(TAG_THREAD, "onStopped:encoder=" + encoder);
if ((encoder instanceof MediaVideoEncoder)
|| (encoder instanceof MediaSurfaceEncoder)) {
|| (encoder instanceof MediaSurfaceEncoder))
try {
mIsRecording = false;
final Activity parent = mWeakParent.get();
@@ -1027,7 +968,6 @@ public abstract class AbstractUVCCameraHandler extends Handler {
} catch (final Exception e) {
Log.e(TAG, "onPrepared:", e);
}
}
}
@Override

View File

@@ -0,0 +1,321 @@
package com.serenegiant.usb.common;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import com.mogo.usbcamera.R;
import com.serenegiant.dialog.MessageDialogFragmentV4;
import com.serenegiant.utils.BuildCheck;
import com.serenegiant.utils.HandlerThreadHandler;
import com.serenegiant.utils.PermissionCheck;
/**
* Created by saki on 2016/11/18.
*
*/
public class BaseActivity extends AppCompatActivity
implements MessageDialogFragmentV4.MessageDialogListener {
private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること
private static final String TAG = BaseActivity.class.getSimpleName();
/** UI操作のためのHandler */
private final Handler mUIHandler = new Handler(Looper.getMainLooper());
private final Thread mUiThread = mUIHandler.getLooper().getThread();
/** ワーカースレッド上で処理するためのHandler */
private Handler mWorkerHandler;
private long mWorkerThreadID = -1;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ワーカースレッドを生成
if (mWorkerHandler == null) {
mWorkerHandler = HandlerThreadHandler.createHandler(TAG);
mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId();
}
}
@Override
protected void onPause() {
clearToast();
super.onPause();
}
@Override
protected synchronized void onDestroy() {
// ワーカースレッドを破棄
if (mWorkerHandler != null) {
try {
mWorkerHandler.getLooper().quit();
} catch (final Exception e) {
//
}
mWorkerHandler = null;
}
super.onDestroy();
}
//================================================================================
/**
* UIスレッドでRunnableを実行するためのヘルパーメソッド
* @param task
* @param duration
*/
public final void runOnUiThread(final Runnable task, final long duration) {
if (task == null) {
return;
}
mUIHandler.removeCallbacks(task);
if ((duration > 0) || Thread.currentThread() != mUiThread) {
mUIHandler.postDelayed(task, duration);
} else {
try {
task.run();
} catch (final Exception e) {
Log.w(TAG, e);
}
}
}
/**
* UIスレッド上で指定したRunnableが実行待ちしていれば実行待ちを解除する
* @param task
*/
public final void removeFromUiThread(final Runnable task) {
if (task == null) {
return;
}
mUIHandler.removeCallbacks(task);
}
/**
* ワーカースレッド上で指定したRunnableを実行する
* 未実行の同じRunnableがあればキャンセルされる(後から指定した方のみ実行される)
* @param task
* @param delayMillis
*/
protected final synchronized void queueEvent(final Runnable task, final long delayMillis) {
if ((task == null) || (mWorkerHandler == null)) {
return;
}
try {
mWorkerHandler.removeCallbacks(task);
if (delayMillis > 0) {
mWorkerHandler.postDelayed(task, delayMillis);
} else if (mWorkerThreadID == Thread.currentThread().getId()) {
task.run();
} else {
mWorkerHandler.post(task);
}
} catch (final Exception e) {
// ignore
}
}
/**
* 指定したRunnableをワーカースレッド上で実行予定であればキャンセルする
* @param task
*/
protected final synchronized void removeEvent(final Runnable task) {
if (task == null) {
return;
}
try {
mWorkerHandler.removeCallbacks(task);
} catch (final Exception e) {
// ignore
}
}
//================================================================================
private Toast mToast;
/**
* Toastでメッセージを表示
* @param msg
*/
protected void showToast(@StringRes final int msg, final Object... args) {
removeFromUiThread(mShowToastTask);
mShowToastTask = new ShowToastTask(msg, args);
runOnUiThread(mShowToastTask, 0);
}
/**
* Toastが表示されていればキャンセルする
*/
protected void clearToast() {
removeFromUiThread(mShowToastTask);
mShowToastTask = null;
try {
if (mToast != null) {
mToast.cancel();
mToast = null;
}
} catch (final Exception e) {
// ignore
}
}
private ShowToastTask mShowToastTask;
private final class ShowToastTask implements Runnable {
final int msg;
final Object args;
private ShowToastTask(@StringRes final int msg, final Object... args) {
this.msg = msg;
this.args = args;
}
@Override
public void run() {
try {
if (mToast != null) {
mToast.cancel();
mToast = null;
}
final String _msg = (args != null) ? getString(msg, args) : getString(msg);
mToast = Toast.makeText(BaseActivity.this, _msg, Toast.LENGTH_SHORT);
mToast.show();
} catch (final Exception e) {
// ignore
}
}
}
//================================================================================
/**
* MessageDialogFragmentメッセージダイアログからのコールバックリスナー
* @param dialog
* @param requestCode
* @param permissions
* @param result
*/
@SuppressLint("NewApi")
@Override
public void onMessageDialogResult(final MessageDialogFragmentV4 dialog, final int requestCode, final String[] permissions, final boolean result) {
if (result) {
// メッセージダイアログでOKを押された時はパーミッション要求する
if (BuildCheck.isMarshmallow()) {
requestPermissions(permissions, requestCode);
return;
}
}
// メッセージダイアログでキャンセルされた時とAndroid6でない時は自前でチェックして#checkPermissionResultを呼び出す
for (final String permission: permissions) {
checkPermissionResult(requestCode, permission, PermissionCheck.hasPermission(this, permission));
}
}
/**
* パーミッション要求結果を受け取るためのメソッド
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 何もしてないけど一応呼んどく
final int n = Math.min(permissions.length, grantResults.length);
for (int i = 0; i < n; i++) {
checkPermissionResult(requestCode, permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED);
}
}
/**
* パーミッション要求の結果をチェック
* ここではパーミッションを取得できなかった時にToastでメッセージ表示するだけ
* @param requestCode
* @param permission
* @param result
*/
protected void checkPermissionResult(final int requestCode, final String permission, final boolean result) {
// パーミッションがないときにはメッセージを表示する
if (!result && (permission != null)) {
if (Manifest.permission.RECORD_AUDIO.equals(permission)) {
showToast(R.string.permission_audio);
}
if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) {
showToast(R.string.permission_ext_storage);
}
if (Manifest.permission.INTERNET.equals(permission)) {
showToast(R.string.permission_network);
}
}
}
// 動的パーミッション要求時の要求コード
protected static final int REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE = 0x12345;
protected static final int REQUEST_PERMISSION_AUDIO_RECORDING = 0x234567;
protected static final int REQUEST_PERMISSION_NETWORK = 0x345678;
protected static final int REQUEST_PERMISSION_CAMERA = 0x537642;
/**
* 外部ストレージへの書き込みパーミッションが有るかどうかをチェック
* なければ説明ダイアログを表示する
* @return true 外部ストレージへの書き込みパーミッションが有る
*/
protected boolean checkPermissionWriteExternalStorage() {
if (!PermissionCheck.hasWriteExternalStorage(this)) {
MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE,
R.string.permission_title, R.string.permission_ext_storage_request,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE});
return false;
}
return true;
}
/**
* 録音のパーミッションが有るかどうかをチェック
* なければ説明ダイアログを表示する
* @return true 録音のパーミッションが有る
*/
protected boolean checkPermissionAudio() {
if (!PermissionCheck.hasAudio(this)) {
MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING,
R.string.permission_title, R.string.permission_audio_recording_request,
new String[]{Manifest.permission.RECORD_AUDIO});
return false;
}
return true;
}
/**
* ネットワークアクセスのパーミッションが有るかどうかをチェック
* なければ説明ダイアログを表示する
* @return true ネットワークアクセスのパーミッションが有る
*/
protected boolean checkPermissionNetwork() {
if (!PermissionCheck.hasNetwork(this)) {
MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_NETWORK,
R.string.permission_title, R.string.permission_network_request,
new String[]{Manifest.permission.INTERNET});
return false;
}
return true;
}
/**
* カメラアクセスのパーミッションがあるかどうかをチェック
* なければ説明ダイアログを表示する
* @return true カメラアクセスのパーミッションが有る
*/
protected boolean checkPermissionCamera() {
if (!PermissionCheck.hasCamera(this)) {
MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_CAMERA,
R.string.permission_title, R.string.permission_camera_request,
new String[]{Manifest.permission.CAMERA});
return false;
}
return true;
}
}

View File

@@ -0,0 +1,348 @@
package com.serenegiant.usb.common;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Fragment;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import com.mogo.usbcamera.R;
import com.serenegiant.dialog.MessageDialogFragment;
import com.serenegiant.utils.BuildCheck;
import com.serenegiant.utils.HandlerThreadHandler;
import com.serenegiant.utils.PermissionCheck;
/**
* Created by saki on 2016/11/19.
*/
public class BaseFragment extends Fragment
implements MessageDialogFragment.MessageDialogListener {
private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること
private static final String TAG = BaseFragment.class.getSimpleName();
/**
* UI操作のためのHandler
*/
private final Handler mUIHandler = new Handler(Looper.getMainLooper());
private final Thread mUiThread = mUIHandler.getLooper().getThread();
/**
* ワーカースレッド上で処理するためのHandler
*/
private Handler mWorkerHandler;
private long mWorkerThreadID = -1;
public BaseFragment() {
super();
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ワーカースレッドを生成
if (mWorkerHandler == null) {
mWorkerHandler = HandlerThreadHandler.createHandler(TAG);
mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId();
}
}
@Override
public void onPause() {
clearToast();
super.onPause();
}
@Override
public synchronized void onDestroy() {
// ワーカースレッドを破棄
if (mWorkerHandler != null) {
try {
mWorkerHandler.getLooper().quit();
} catch (final Exception e) {
//
}
mWorkerHandler = null;
}
super.onDestroy();
}
//================================================================================
/**
* UIスレッドでRunnableを実行するためのヘルパーメソッド
*
* @param task
* @param duration
*/
public final void runOnUiThread(final Runnable task, final long duration) {
if (task == null) {
return;
}
mUIHandler.removeCallbacks(task);
if ((duration > 0) || Thread.currentThread() != mUiThread) {
mUIHandler.postDelayed(task, duration);
} else {
try {
task.run();
} catch (final Exception e) {
Log.w(TAG, e);
}
}
}
/**
* UIスレッド上で指定したRunnableが実行待ちしていれば実行待ちを解除する
*
* @param task
*/
public final void removeFromUiThread(final Runnable task) {
if (task == null) {
return;
}
mUIHandler.removeCallbacks(task);
}
/**
* ワーカースレッド上で指定したRunnableを実行する
* 未実行の同じRunnableがあればキャンセルされる(後から指定した方のみ実行される)
*
* @param task
* @param delayMillis
*/
protected final synchronized void queueEvent(final Runnable task, final long delayMillis) {
if ((task == null) || (mWorkerHandler == null)) {
return;
}
try {
mWorkerHandler.removeCallbacks(task);
if (delayMillis > 0) {
mWorkerHandler.postDelayed(task, delayMillis);
} else if (mWorkerThreadID == Thread.currentThread().getId()) {
task.run();
} else {
mWorkerHandler.post(task);
}
} catch (final Exception e) {
// ignore
}
}
/**
* 指定したRunnableをワーカースレッド上で実行予定であればキャンセルする
*
* @param task
*/
protected final synchronized void removeEvent(final Runnable task) {
if (task == null) {
return;
}
try {
mWorkerHandler.removeCallbacks(task);
} catch (final Exception e) {
// ignore
}
}
//================================================================================
private Toast mToast;
/**
* Toastでメッセージを表示
*
* @param msg
*/
protected void showToast(@StringRes final int msg, final Object... args) {
removeFromUiThread(mShowToastTask);
mShowToastTask = new ShowToastTask(msg, args);
runOnUiThread(mShowToastTask, 0);
}
/**
* Toastが表示されていればキャンセルする
*/
protected void clearToast() {
removeFromUiThread(mShowToastTask);
mShowToastTask = null;
try {
if (mToast != null) {
mToast.cancel();
mToast = null;
}
} catch (final Exception e) {
// ignore
}
}
private ShowToastTask mShowToastTask;
private final class ShowToastTask implements Runnable {
final int msg;
final Object args;
private ShowToastTask(@StringRes final int msg, final Object... args) {
this.msg = msg;
this.args = args;
}
@Override
public void run() {
try {
if (mToast != null) {
mToast.cancel();
mToast = null;
}
if (args != null) {
final String _msg = getString(msg, args);
mToast = Toast.makeText(getActivity(), _msg, Toast.LENGTH_SHORT);
} else {
mToast = Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT);
}
mToast.show();
} catch (final Exception e) {
// ignore
}
}
}
//================================================================================
/**
* MessageDialogFragmentメッセージダイアログからのコールバックリスナー
*
* @param dialog
* @param requestCode
* @param permissions
* @param result
*/
@SuppressLint("NewApi")
@Override
public void onMessageDialogResult(final MessageDialogFragment dialog, final int requestCode, final String[] permissions, final boolean result) {
if (result) {
// メッセージダイアログでOKを押された時はパーミッション要求する
if (BuildCheck.isMarshmallow()) {
requestPermissions(permissions, requestCode);
return;
}
}
// メッセージダイアログでキャンセルされた時とAndroid6でない時は自前でチェックして#checkPermissionResultを呼び出す
for (final String permission : permissions) {
checkPermissionResult(requestCode, permission, PermissionCheck.hasPermission(getActivity(), permission));
}
}
/**
* パーミッション要求結果を受け取るためのメソッド
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 何もしてないけど一応呼んどく
final int n = Math.min(permissions.length, grantResults.length);
for (int i = 0; i < n; i++) {
checkPermissionResult(requestCode, permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED);
}
}
/**
* パーミッション要求の結果をチェック
* ここではパーミッションを取得できなかった時にToastでメッセージ表示するだけ
*
* @param requestCode
* @param permission
* @param result
*/
protected void checkPermissionResult(final int requestCode, final String permission, final boolean result) {
// パーミッションがないときにはメッセージを表示する
if (!result && (permission != null)) {
if (Manifest.permission.RECORD_AUDIO.equals(permission)) {
showToast(R.string.permission_audio);
}
if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) {
showToast(R.string.permission_ext_storage);
}
if (Manifest.permission.INTERNET.equals(permission)) {
showToast(R.string.permission_network);
}
}
}
// 動的パーミッション要求時の要求コード
protected static final int REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE = 0x12345;
protected static final int REQUEST_PERMISSION_AUDIO_RECORDING = 0x234567;
protected static final int REQUEST_PERMISSION_NETWORK = 0x345678;
protected static final int REQUEST_PERMISSION_CAMERA = 0x537642;
/**
* 外部ストレージへの書き込みパーミッションが有るかどうかをチェック
* なければ説明ダイアログを表示する
*
* @return true 外部ストレージへの書き込みパーミッションが有る
*/
protected boolean checkPermissionWriteExternalStorage() {
if (!PermissionCheck.hasWriteExternalStorage(getActivity())) {
MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE,
R.string.permission_title, R.string.permission_ext_storage_request,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE});
return false;
}
return true;
}
/**
* 録音のパーミッションが有るかどうかをチェック
* なければ説明ダイアログを表示する
*
* @return true 録音のパーミッションが有る
*/
protected boolean checkPermissionAudio() {
if (!PermissionCheck.hasAudio(getActivity())) {
MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING,
R.string.permission_title, R.string.permission_audio_recording_request,
new String[]{Manifest.permission.RECORD_AUDIO});
return false;
}
return true;
}
/**
* ネットワークアクセスのパーミッションが有るかどうかをチェック
* なければ説明ダイアログを表示する
*
* @return true ネットワークアクセスのパーミッションが有る
*/
protected boolean checkPermissionNetwork() {
if (!PermissionCheck.hasNetwork(getActivity())) {
MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_NETWORK,
R.string.permission_title, R.string.permission_network_request,
new String[]{Manifest.permission.INTERNET});
return false;
}
return true;
}
/**
* カメラアクセスのパーミッションがあるかどうかをチェック
* なければ説明ダイアログを表示する
*
* @return true カメラアクセスのパーミッションが有る
*/
protected boolean checkPermissionCamera() {
if (!PermissionCheck.hasCamera(getActivity())) {
MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_CAMERA,
R.string.permission_title, R.string.permission_camera_request,
new String[]{Manifest.permission.CAMERA});
return false;
}
return true;
}
}

View File

@@ -0,0 +1,108 @@
package com.serenegiant.usb.common;
import android.app.Service;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.serenegiant.utils.HandlerThreadHandler;
public abstract class BaseService extends Service {
private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること
private static final String TAG = BaseService.class.getSimpleName();
/** UI操作のためのHandler */
private final Handler mUIHandler = new Handler(Looper.getMainLooper());
private final Thread mUiThread = mUIHandler.getLooper().getThread();
/** ワーカースレッド上で処理するためのHandler */
private Handler mWorkerHandler;
private long mWorkerThreadID = -1;
@Override
public void onCreate() {
super.onCreate();
// ワーカースレッドを生成
if (mWorkerHandler == null) {
mWorkerHandler = HandlerThreadHandler.createHandler(TAG);
mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId();
}
}
@Override
public synchronized void onDestroy() {
// ワーカースレッドを破棄
if (mWorkerHandler != null) {
try {
mWorkerHandler.getLooper().quit();
} catch (final Exception e) {
//
}
mWorkerHandler = null;
}
super.onDestroy();
}
//================================================================================
/**
* UIスレッドでRunnableを実行するためのヘルパーメソッド
* @param task
* @param duration
*/
public final void runOnUiThread(final Runnable task, final long duration) {
if (task == null) return;
mUIHandler.removeCallbacks(task);
if ((duration > 0) || Thread.currentThread() != mUiThread) {
mUIHandler.postDelayed(task, duration);
} else {
try {
task.run();
} catch (final Exception e) {
Log.w(TAG, e);
}
}
}
/**
* UIスレッド上で指定したRunnableが実行待ちしていれば実行待ちを解除する
* @param task
*/
public final void removeFromUiThread(final Runnable task) {
if (task == null) return;
mUIHandler.removeCallbacks(task);
}
/**
* ワーカースレッド上で指定したRunnableを実行する
* 未実行の同じRunnableがあればキャンセルされる(後から指定した方のみ実行される)
* @param task
* @param delayMillis
*/
protected final synchronized void queueEvent(final Runnable task, final long delayMillis) {
if ((task == null) || (mWorkerHandler == null)) return;
try {
mWorkerHandler.removeCallbacks(task);
if (delayMillis > 0) {
mWorkerHandler.postDelayed(task, delayMillis);
} else if (mWorkerThreadID == Thread.currentThread().getId()) {
task.run();
} else {
mWorkerHandler.post(task);
}
} catch (final Exception e) {
// ignore
}
}
/**
* 指定したRunnableをワーカースレッド上で実行予定であればキャンセルする
* @param task
*/
protected final synchronized void removeEvent(final Runnable task) {
if (task == null) return;
try {
mWorkerHandler.removeCallbacks(task);
} catch (final Exception e) {
// ignore
}
}
}

View File

@@ -1,9 +1,30 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.common;
import android.app.Activity;
import android.content.Context;
import com.serenegiant.usb.ParentPreviewConstraintLayout;
import com.serenegiant.usb.UVCCamera;
import com.serenegiant.usb.widget.CameraViewInterface;

View File

@@ -1,10 +1,32 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.common;
import android.app.Activity;
import android.view.Surface;
import com.serenegiant.glutils.RendererHolder;
import com.serenegiant.usb.ParentPreviewConstraintLayout;
import com.serenegiant.usb.UVCCamera;
import com.serenegiant.usb.widget.CameraViewInterface;
@@ -101,7 +123,6 @@ public class UVCCameraHandlerMultiSurface extends AbstractUVCCameraHandler {
mRendererHolder = new RendererHolder(thread.getWidth(), thread.getHeight(), null);
}
@Override
public synchronized void release() {
if (mRendererHolder != null) {
mRendererHolder.release();
@@ -110,8 +131,7 @@ public class UVCCameraHandlerMultiSurface extends AbstractUVCCameraHandler {
super.release();
}
@Override
public synchronized void resize(final int width, final int height) {
public synchronized void resize(final int width, final int height) {
super.resize(width, height);
if (mRendererHolder != null) {
mRendererHolder.resize(width, height);

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.encoder;
public interface IAudioEncoder {

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.encoder;
public interface IVideoEncoder {

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.encoder;
import android.media.AudioFormat;

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.encoder;
import android.media.MediaCodec;

View File

@@ -1,3 +1,26 @@
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb.encoder;
import android.media.MediaCodec;

View File

@@ -1,8 +1,10 @@
package com.serenegiant.usb.encoder;
/**
* 录制参数
/** 录制参数
*
* Created by jiangdongguo on 2017/10/19.
*/
public class RecordParams {
private String recordPath;
private int recordDuration;

View File

@@ -19,10 +19,12 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
/**
* 将PCM编码为AAC
/**将PCM编码为AAC
*
* Created by jianddongguo on 2017/7/21.
*/
public class AACEncodeConsumer extends Thread {
public class AACEncodeConsumer extends Thread{
private static final boolean DEBUG = false;
private static final String TAG = "TMPU";
private static final String MIME_TYPE = "audio/mp4a-latm";
@@ -38,7 +40,7 @@ public class AACEncodeConsumer extends Thread {
private AudioRecord mAudioRecord; // 音频采集
private MediaCodec mAudioEncoder; // 音频编码
private OnAACEncodeResultListener listener;
private int mSamplingRateIndex = 0;//ADTS
private int mSamplingRateIndex = 0;//ADTS
private boolean isEncoderStart = false;
private boolean isRecMp3 = false;
private boolean isExit = false;
@@ -46,7 +48,7 @@ public class AACEncodeConsumer extends Thread {
private WeakReference<Mp4MediaMuxer> mMuxerRef;
private MediaFormat newFormat;
private static final int[] AUDIO_SOURCES = new int[]{
private static final int[] AUDIO_SOURCES = new int[] {
MediaRecorder.AudioSource.DEFAULT,
MediaRecorder.AudioSource.MIC,
MediaRecorder.AudioSource.CAMCORDER,
@@ -54,7 +56,7 @@ public class AACEncodeConsumer extends Thread {
/**
* There are 13 supported frequencies by ADTS.
**/
public static final int[] AUDIO_SAMPLING_RATES = {96000, // 0
public static final int[] AUDIO_SAMPLING_RATES = { 96000, // 0
88200, // 1
64000, // 2
48000, // 3
@@ -75,13 +77,13 @@ public class AACEncodeConsumer extends Thread {
private FileOutputStream fops;
// 编码流结果回调接口
public interface OnAACEncodeResultListener {
public interface OnAACEncodeResultListener{
void onEncodeResult(byte[] data, int offset,
int length, long timestamp);
}
public AACEncodeConsumer() {
for (int i = 0; i < AUDIO_SAMPLING_RATES.length; i++) {
public AACEncodeConsumer(){
for (int i=0;i < AUDIO_SAMPLING_RATES.length; i++) {
if (AUDIO_SAMPLING_RATES[i] == SAMPLE_RATE) {
mSamplingRateIndex = i;
break;
@@ -89,16 +91,16 @@ public class AACEncodeConsumer extends Thread {
}
}
public void setOnAACEncodeResultListener(OnAACEncodeResultListener listener) {
public void setOnAACEncodeResultListener(OnAACEncodeResultListener listener){
this.listener = listener;
}
public void exit() {
public void exit(){
isExit = true;
}
public synchronized void setTmpuMuxer(Mp4MediaMuxer mMuxer) {
this.mMuxerRef = new WeakReference<>(mMuxer);
public synchronized void setTmpuMuxer(Mp4MediaMuxer mMuxer){
this.mMuxerRef = new WeakReference<>(mMuxer);
Mp4MediaMuxer muxer = mMuxerRef.get();
if (muxer != null && newFormat != null) {
muxer.addTrack(newFormat, false);
@@ -108,7 +110,7 @@ public class AACEncodeConsumer extends Thread {
@Override
public void run() {
// 开启音频采集、编码
if (!isEncoderStart) {
if(! isEncoderStart){
initAudioRecord();
initMediaCodec();
}
@@ -116,16 +118,16 @@ public class AACEncodeConsumer extends Thread {
byte[] mp3Buffer = new byte[1024];
// 这里有问题,当本地录制结束后,没有写入
while (!isExit) {
while(! isExit){
byte[] audioBuffer = new byte[2048];
// 采集音频
int readBytes = mAudioRecord.read(audioBuffer, 0, BUFFER_SIZE);
int readBytes = mAudioRecord.read(audioBuffer,0,BUFFER_SIZE);
if (DEBUG)
Log.i(TAG, "采集音频readBytes = " + readBytes);
if(DEBUG)
Log.i(TAG,"采集音频readBytes = "+readBytes);
// 编码音频
if (readBytes > 0) {
encodeBytes(audioBuffer, readBytes);
if(readBytes > 0){
encodeBytes(audioBuffer,readBytes);
}
}
// 停止音频采集、编码
@@ -140,81 +142,81 @@ public class AACEncodeConsumer extends Thread {
ByteBuffer[] outputBuffers = mAudioEncoder.getOutputBuffers();
//返回编码器的一个输入缓存区句柄,-1表示当前没有可用的输入缓存区
int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(TIMES_OUT);
if (inputBufferIndex >= 0) {
if(inputBufferIndex >= 0){
// 绑定一个被空的、可写的输入缓存区inputBuffer到客户端
ByteBuffer inputBuffer = null;
if (!isLollipop()) {
ByteBuffer inputBuffer = null;
if(!isLollipop()){
inputBuffer = inputBuffers[inputBufferIndex];
} else {
}else{
inputBuffer = mAudioEncoder.getInputBuffer(inputBufferIndex);
}
// 向输入缓存区写入有效原始数据,并提交到编码器中进行编码处理
if (audioBuf == null || readBytes <= 0) {
mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, 0, getPTSUs(), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
if(audioBuf==null || readBytes<=0){
mAudioEncoder.queueInputBuffer(inputBufferIndex,0,0,getPTSUs(),MediaCodec.BUFFER_FLAG_END_OF_STREAM);
}else{
inputBuffer.clear();
inputBuffer.put(audioBuf);
mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, readBytes, getPTSUs(), 0);
mAudioEncoder.queueInputBuffer(inputBufferIndex,0,readBytes,getPTSUs(),0);
}
}
// 返回一个输出缓存区句柄,当为-1时表示当前没有可用的输出缓存区
// mBufferInfo参数包含被编码好的数据timesOut参数为超时等待的时间
MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = -1;
do {
outputBufferIndex = mAudioEncoder.dequeueOutputBuffer(mBufferInfo, TIMES_OUT);
if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
if (DEBUG)
Log.i(TAG, "获得编码器输出缓存区超时");
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
do{
outputBufferIndex = mAudioEncoder.dequeueOutputBuffer(mBufferInfo,TIMES_OUT);
if(outputBufferIndex == MediaCodec. INFO_TRY_AGAIN_LATER){
if(DEBUG)
Log.i(TAG,"获得编码器输出缓存区超时");
}else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED){
// 如果API小于21APP需要重新绑定编码器的输入缓存区
// 如果API大于21则无需处理INFO_OUTPUT_BUFFERS_CHANGED
if (!isLollipop()) {
if(!isLollipop()){
outputBuffers = mAudioEncoder.getOutputBuffers();
}
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
}else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){
// 编码器输出缓存区格式改变,通常在存储数据之前且只会改变一次
// 这里设置混合器视频轨道,如果音频已经添加则启动混合器(保证音视频同步)
if (DEBUG)
Log.i(TAG, "编码器输出缓存区格式改变,添加视频轨道到混合器");
if(DEBUG)
Log.i(TAG,"编码器输出缓存区格式改变,添加视频轨道到混合器");
synchronized (AACEncodeConsumer.this) {
newFormat = mAudioEncoder.getOutputFormat();
if (mMuxerRef != null) {
if(mMuxerRef != null){
Mp4MediaMuxer muxer = mMuxerRef.get();
if (muxer != null) {
muxer.addTrack(newFormat, false);
}
}
}
} else {
}else{
// 当flag属性置为BUFFER_FLAG_CODEC_CONFIG后说明输出缓存区的数据已经被消费了
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
if (DEBUG)
Log.i(TAG, "编码数据被消费BufferInfo的size属性置0");
if((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0){
if(DEBUG)
Log.i(TAG,"编码数据被消费BufferInfo的size属性置0");
mBufferInfo.size = 0;
}
// 数据流结束标志,结束本次循环
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
if (DEBUG)
Log.i(TAG, "数据流结束,退出循环");
if((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0){
if(DEBUG)
Log.i(TAG,"数据流结束,退出循环");
break;
}
// 获取一个只读的输出缓存区inputBuffer ,它包含被编码好的数据
ByteBuffer mBuffer = ByteBuffer.allocate(10240);
ByteBuffer outputBuffer = null;
if (!isLollipop()) {
outputBuffer = outputBuffers[outputBufferIndex];
} else {
outputBuffer = mAudioEncoder.getOutputBuffer(outputBufferIndex);
if(!isLollipop()){
outputBuffer = outputBuffers[outputBufferIndex];
}else{
outputBuffer = mAudioEncoder.getOutputBuffer(outputBufferIndex);
}
if (mBufferInfo.size != 0) {
if(mBufferInfo.size != 0){
// 获取输出缓存区失败,抛出异常
if (outputBuffer == null) {
throw new RuntimeException("encodecOutputBuffer" + outputBufferIndex + "was null");
if(outputBuffer == null){
throw new RuntimeException("encodecOutputBuffer"+outputBufferIndex+"was null");
}
// 添加视频流到混合器
if (mMuxerRef != null) {
if(mMuxerRef != null){
Mp4MediaMuxer muxer = mMuxerRef.get();
if (muxer != null) {
muxer.pumpStream(outputBuffer, mBufferInfo, false);
@@ -228,25 +230,25 @@ public class AACEncodeConsumer extends Thread {
addADTStoPacket(mBuffer.array(), mBufferInfo.size + 7);
mBuffer.flip();
// 将AAC回调给MainModelImpl进行push
if (listener != null) {
Log.i(TAG, "----->得到aac数据流<-----");
listener.onEncodeResult(mBuffer.array(), 0, mBufferInfo.size + 7, mBufferInfo.presentationTimeUs / 1000);
if(listener != null){
Log.i(TAG,"----->得到aac数据流<-----");
listener.onEncodeResult(mBuffer.array(),0, mBufferInfo.size + 7, mBufferInfo.presentationTimeUs / 1000);
}
}
// 处理结束,释放输出缓存区资源
mAudioEncoder.releaseOutputBuffer(outputBufferIndex, false);
mAudioEncoder.releaseOutputBuffer(outputBufferIndex,false);
}
} while (outputBufferIndex >= 0);
}while (outputBufferIndex >= 0);
}
private void initAudioRecord() {
if (DEBUG)
Log.d(TAG, "AACEncodeConsumer-->开始采集音频");
private void initAudioRecord(){
if(DEBUG)
Log.d(TAG,"AACEncodeConsumer-->开始采集音频");
// 设置进程优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
for (final int src : AUDIO_SOURCES) {
for (final int src: AUDIO_SOURCES) {
try {
mAudioRecord = new AudioRecord(src,
SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
@@ -266,18 +268,18 @@ public class AACEncodeConsumer extends Thread {
mAudioRecord.startRecording();
}
private void initMediaCodec() {
if (DEBUG)
Log.d(TAG, "AACEncodeConsumer-->开始编码音频");
private void initMediaCodec(){
if(DEBUG)
Log.d(TAG,"AACEncodeConsumer-->开始编码音频");
MediaCodecInfo mCodecInfo = selectSupportCodec(MIME_TYPE);
if (mCodecInfo == null) {
Log.e(TAG, "编码器不支持" + MIME_TYPE + "类型");
if(mCodecInfo == null){
Log.e(TAG,"编码器不支持"+MIME_TYPE+"类型");
return;
}
try {
try{
mAudioEncoder = MediaCodec.createByCodecName(mCodecInfo.getName());
} catch (IOException e) {
Log.e(TAG, "创建编码器失败" + e.getMessage());
}catch(IOException e){
Log.e(TAG,"创建编码器失败"+e.getMessage());
e.printStackTrace();
}
MediaFormat format = new MediaFormat();
@@ -293,9 +295,9 @@ public class AACEncodeConsumer extends Thread {
}
private void stopAudioRecord() {
if (DEBUG)
Log.d(TAG, "AACEncodeConsumer-->停止采集音频");
if (mAudioRecord != null) {
if(DEBUG)
Log.d(TAG,"AACEncodeConsumer-->停止采集音频");
if(mAudioRecord != null){
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
@@ -303,9 +305,9 @@ public class AACEncodeConsumer extends Thread {
}
private void stopMediaCodec() {
if (DEBUG)
Log.d(TAG, "AACEncodeConsumer-->停止编码音频");
if (mAudioEncoder != null) {
if(DEBUG)
Log.d(TAG,"AACEncodeConsumer-->停止编码音频");
if(mAudioEncoder != null){
mAudioEncoder.stop();
mAudioEncoder.release();
mAudioEncoder = null;
@@ -314,28 +316,28 @@ public class AACEncodeConsumer extends Thread {
}
// API>=21
private boolean isLollipop() {
private boolean isLollipop(){
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
// API<=19
private boolean isKITKAT() {
private boolean isKITKAT(){
return Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT;
}
private long getPTSUs() {
long result = System.nanoTime() / 1000;
if (result < prevPresentationTimes) {
result = (prevPresentationTimes - result) + result;
private long getPTSUs(){
long result = System.nanoTime()/1000;
if(result < prevPresentationTimes){
result = (prevPresentationTimes - result ) + result;
}
return result;
}
/**
* 遍历所有编解码器返回第一个与指定MIME类型匹配的编码器
* 判断是否有支持指定mime类型的编码器
*/
private MediaCodecInfo selectSupportCodec(String mimeType) {
* 判断是否有支持指定mime类型的编码器
* */
private MediaCodecInfo selectSupportCodec(String mimeType){
int numCodecs = MediaCodecList.getCodecCount();
for (int i = 0; i < numCodecs; i++) {
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
@@ -365,7 +367,7 @@ public class AACEncodeConsumer extends Thread {
}
private short[] transferByte2Short(byte[] data, int readBytes) {
private short[] transferByte2Short(byte[] data,int readBytes){
// byte[] 转 short[],数组长度缩减一半
int shortLen = readBytes / 2;
// 将byte[]数组装如ByteBuffer缓冲区

View File

@@ -17,7 +17,9 @@ import java.nio.ByteBuffer;
/**
* 对YUV视频流进行编码
* Created by jiangdongguo on 2017/5/6.
*/
@SuppressWarnings("deprecation")
public class H264EncodeConsumer extends Thread {
private static final boolean DEBUG = false;

View File

@@ -10,9 +10,11 @@ import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Mp4封装混合器
/**Mp4封装混合器
*
* Created by jianddongguo on 2017/7/28.
*/
public class Mp4MediaMuxer {
private static final boolean VERBOSE = false;
private static final String TAG = Mp4MediaMuxer.class.getSimpleName();

View File

@@ -0,0 +1,186 @@
package com.serenegiant.utils;
import android.Manifest.permission;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.net.Uri;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class PermissionCheck {
public static final void dumpPermissions(@Nullable final Context context) {
if (context == null) return;
try {
final PackageManager pm = context.getPackageManager();
final List<PermissionGroupInfo> list = pm.getAllPermissionGroups(PackageManager.GET_META_DATA);
for (final PermissionGroupInfo info : list) {
Log.d("PermissionCheck", info.name);
}
} catch (final Exception e) {
Log.w("", e);
}
}
/**
* パーミッションを確認
* @param context
* @param permissionName
* @return 指定したパーミッションがあればtrue
*/
@SuppressLint("NewApi")
public static boolean hasPermission(@Nullable final Context context, final String permissionName) {
if (context == null) return false;
boolean result = false;
try {
final int check;
if (BuildCheck.isMarshmallow()) {
check = context.checkSelfPermission(permissionName);
} else {
final PackageManager pm = context.getPackageManager();
check = pm.checkPermission(permissionName, context.getPackageName());
}
switch (check) {
case PackageManager.PERMISSION_DENIED:
break;
case PackageManager.PERMISSION_GRANTED:
result = true;
break;
}
} catch (final Exception e) {
Log.w("", e);
}
return result;
}
/**
* 録音のミッションがあるかどうかを確認
* @param context
* @return 録音のパーミッションがあればtrue
*/
public static boolean hasAudio(@Nullable final Context context) {
return hasPermission(context, permission.RECORD_AUDIO);
}
/**
* ネットワークへのアクセスパーミッションがあるかどうかを確認
* @param context
* @return ネットワークへのアクセスパーミッションがあればtrue
*/
public static boolean hasNetwork(@Nullable final Context context) {
return hasPermission(context, permission.INTERNET);
}
/**
* 外部ストレージへの書き込みパーミッションがあるかどうかを確認
* @param context
* @return 外部ストレージへの書き込みパーミッションがあればtrue
*/
public static boolean hasWriteExternalStorage(@Nullable final Context context) {
return hasPermission(context, permission.WRITE_EXTERNAL_STORAGE);
}
/**
* 外部ストレージからの読み込みパーミッションがあるかどうかを確認
* @param context
* @return 外部ストレージへの読み込みパーミッションがあればtrue
*/
@SuppressLint("InlinedApi")
public static boolean hasReadExternalStorage(@Nullable final Context context) {
if (BuildCheck.isAndroid4())
return hasPermission(context, permission.READ_EXTERNAL_STORAGE);
else
return hasPermission(context, permission.WRITE_EXTERNAL_STORAGE);
}
/**
* 位置情報アクセスのパーミッションが有るかどうかを確認
* @param context
* @return
*/
public static boolean hasAccessLocation(@Nullable final Context context) {
return hasPermission(context, permission.ACCESS_COARSE_LOCATION)
&& hasPermission(context, permission.ACCESS_FINE_LOCATION);
}
/**
* 低精度位置情報アクセスのパーミッションが有るかどうかを確認
* @param context
* @return
*/
public static boolean hasAccessCoarseLocation(@Nullable final Context context) {
return hasPermission(context, permission.ACCESS_COARSE_LOCATION);
}
/**
* 高精度位置情報アクセスのパーミッションが有るかどうかを確認
* @param context
* @return
*/
public static boolean hasAccessFineLocation(@Nullable final Context context) {
return hasPermission(context, permission.ACCESS_FINE_LOCATION);
}
/**
* カメラへアクセス可能かどうか
* @param context
* @return
*/
public static boolean hasCamera(@Nullable final Context context) {
return hasPermission(context, permission.CAMERA);
}
/**
* アプリの詳細設定へ遷移させる(パーミッションを取得できなかった時など)
* @param context
*/
public static void openSettings(@NonNull final Context context) {
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
final Uri uri = Uri.fromParts("package", context.getPackageName(), null);
intent.setData(uri);
context.startActivity(intent);
}
/**
* AndroidManifest.xmlに設定されているはずのパーミッションをチェックする
* @param context
* @param expectations
* @return 空リストなら全てのパーミッションが入っていた,
* @throws IllegalArgumentException
* @throws PackageManager.NameNotFoundException
*/
public static List<String> missingPermissions(@NonNull final Context context, @NonNull final String[] expectations) throws IllegalArgumentException, PackageManager.NameNotFoundException {
return missingPermissions(context, new ArrayList<String>(Arrays.asList(expectations)));
}
/**
* AndroidManifest.xmlに設定されているはずのパーミッションをチェックする
* @param context
* @param expectations
* @return 空リストなら全てのパーミッションが入っていた,
* @throws IllegalArgumentException
* @throws PackageManager.NameNotFoundException
*/
public static List<String> missingPermissions(@NonNull final Context context, @NonNull final List<String> expectations) throws IllegalArgumentException, PackageManager.NameNotFoundException {
final PackageManager pm = context.getPackageManager();
final PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
final String[] info = pi.requestedPermissions;
if (info != null) {
for (String i : info) {
expectations.remove(i);
}
}
return expectations;
}
}

Some files were not shown because too many files have changed in this diff Show More