Merge branch 'dev_robotaxi-d_231205_6.2.6' into dev_robotaxi-d_231218_6.2.6
# Conflicts: # OCH/bus/passenger/src/jinlvvan/java/com/mogo/och/bus/passenger/MogoOCHBusPassenger.java
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package com.mogo.och.common.module
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.mogo.och.common.module.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
14
OCH/common/common/src/debug/AndroidManifest.xml
Normal file
14
OCH/common/common/src/debug/AndroidManifest.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.och.common.module">
|
||||
|
||||
<application>
|
||||
<receiver android:name="com.mogo.och.common.module.debug.BizBroadcastReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.mogo.launcher.debug" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.mogo.och.common.module.debug
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
|
||||
class BizBroadcastReceiver: BroadcastReceiver() {
|
||||
|
||||
private var mContext: Context? = null
|
||||
|
||||
companion object {
|
||||
private const val TAG = "BizBroadcastReceiver"
|
||||
// 类型
|
||||
private const val type = "type"
|
||||
// 数据源
|
||||
private const val sourceFile = "path"
|
||||
// 数据频率 默认1s一次 -1 发送一次
|
||||
private const val frequencyKey = "fre"
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
try {
|
||||
mContext = context
|
||||
val type = intent.getStringExtra(type)
|
||||
val frequency = intent.getIntExtra(frequencyKey,1)
|
||||
val sourceFilePath = intent.getStringExtra(sourceFile)
|
||||
CallerLogger.d("${SceneConstant.M_OCHCOMMON}${TAG}",
|
||||
"类型:${type} 频率:${frequency} 命令所在文件:${sourceFilePath}"
|
||||
)
|
||||
DebugDataDispatch.disPathc(type,frequency,sourceFilePath,intent)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package com.mogo.och.common.module.debug
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Environment
|
||||
import android.os.SystemClock
|
||||
import chassis.Chassis
|
||||
import chassis.Chassis.DoorNumber
|
||||
import chassis.VehicleStateOuterClass
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mogo.eagle.core.data.enums.DataSourceType
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotStatisticsListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisDoorStateListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisGnssListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLamplightListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningActionsListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.ActivityUtils
|
||||
import com.mogo.eagle.core.utilcode.util.GsonUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.mogo.och.common.module.debug.location.MogoLocationExit
|
||||
import com.mogo.och.common.module.manager.distancemamager.TrajectoryAndDistanceManager
|
||||
import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil
|
||||
import com.mogo.och.common.module.view.DebugFloatWindow
|
||||
import com.zhjt.mogo.adas.data.bean.AutopilotStatistics
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import mogo_msg.MogoReportMsg
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
|
||||
object DebugDataDispatch {
|
||||
|
||||
const val TAG = "DebugDataDispatch"
|
||||
|
||||
const val globalPathMock = "globalPath"
|
||||
const val locationMock = "location"
|
||||
const val carDoorMock = "carDoor"
|
||||
const val carNeedTurnAround = "trunAroud"
|
||||
const val carLightSwitch = "lightSwitch"
|
||||
const val trajectoryStation = "trajectoryStation"
|
||||
const val showDebugView = "showDebugView"
|
||||
const val stateAutopilot = "stateAutopilot"
|
||||
const val stateAutopilotFail = "stateAutopilotFail"
|
||||
const val stopSite = "stopSite"
|
||||
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "location" --es path "1111/11111"
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "globalPath" --es path "sy73.json"
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "carDoor" --ei doorPostion 1 --ei doorStatus 1
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "trunAroud" --es code "IMAP_TRA_LOADED"
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "lightSwitch" --ei lightPostion 0
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "stateAutopilot" --ei autopilotMode 0 --ei autopilotState 0
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "stateAutopilotFail"
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "trajectoryStation" --ef startLon 116.74053643938474 --ef startLat 40.200487993233246 --ef endLon 116.73876977409685 --ef endLat 40.20179054129441 --el lineID 8
|
||||
// adb shell am broadcast -a com.mogo.launcher.debug -f 0x011000000 --es type "stopSite" --ei state 6 --ei action 1
|
||||
|
||||
|
||||
val ROOT_PATH =
|
||||
Environment.getExternalStorageDirectory().absolutePath + File.separator + "MLog" + File.separator + "APP_mock" + File.separator //程序外部存储跟目录
|
||||
|
||||
|
||||
fun disPathc(type: String?, frequency: Int, sourceFilePath: String?, intent: Intent) {
|
||||
val file = File(ROOT_PATH);
|
||||
if(file.exists()){
|
||||
|
||||
}
|
||||
when (type) {
|
||||
globalPathMock -> {
|
||||
sourceFilePath?.let {
|
||||
loadRawPoints(ROOT_PATH+it)
|
||||
}
|
||||
}
|
||||
locationMock -> {
|
||||
sourceFilePath?.let {
|
||||
getLocaitonByLog(ROOT_PATH+it)
|
||||
}
|
||||
}
|
||||
carDoorMock -> {
|
||||
// 1--5
|
||||
val intArrayExtra = intent.getIntExtra("doorPostion",0)
|
||||
// 0 -1
|
||||
val booleanArrayExtra = intent.getIntExtra("doorStatus",0)
|
||||
|
||||
val newBuilder = VehicleStateOuterClass.DoorStateV2.newBuilder()
|
||||
newBuilder.number = DoorNumber.forNumber(intArrayExtra)
|
||||
newBuilder.status = booleanArrayExtra
|
||||
val multiList = mutableListOf<VehicleStateOuterClass.DoorStateV2>()
|
||||
multiList.add(newBuilder.build())
|
||||
|
||||
CallerChassisDoorStateListenerManager.invokeAutopilotDoorState(multiList)
|
||||
}
|
||||
carNeedTurnAround -> {
|
||||
// 1--5
|
||||
val intArrayExtra = intent.getStringExtra("code")
|
||||
val newBuilder = MogoReportMsg.MogoReportMessage.newBuilder()
|
||||
newBuilder.code = intArrayExtra
|
||||
newBuilder.timestampBuilder.sec = 0
|
||||
newBuilder.timestampBuilder.nsec = 0
|
||||
newBuilder.src = "2"
|
||||
newBuilder.level = ""
|
||||
ThreadUtils.getSinglePool().execute {
|
||||
CallerAutoPilotStatusListenerManager.invokeAutopilotGuardian(newBuilder.build())
|
||||
}
|
||||
}
|
||||
carLightSwitch -> {
|
||||
//0-5
|
||||
// LIGHT_NONE = 0;
|
||||
// LIGHT_LEFT = 1;
|
||||
// LIGHT_RIGHT = 2;
|
||||
// LIGHT_FLASH = 3;
|
||||
// LIGHT_MANUAL = 4;
|
||||
// LIGHT_AUTO = 5;
|
||||
val lightPostion = intent.getIntExtra("lightPostion",0)
|
||||
CallerChassisLamplightListenerManager.invokeAutopilotLightSwitchData(Chassis.LightSwitch.forNumber(lightPostion))
|
||||
}
|
||||
trajectoryStation -> {
|
||||
val startLon = intent.getFloatExtra("startLon", -1.0f)
|
||||
val startLat = intent.getFloatExtra("startLat", -1.0f)
|
||||
val endLon = intent.getFloatExtra("endLon", -1.0f)
|
||||
val endLat = intent.getFloatExtra("endLat", -1.0f)
|
||||
val lineID = intent.getLongExtra("lineID", -1)
|
||||
setStation(startLon.toDouble(),startLat.toDouble(),endLon.toDouble(),endLat.toDouble(),lineID)
|
||||
}
|
||||
showDebugView -> {
|
||||
val debugFloatWindow = DebugFloatWindow(ActivityUtils.getTopActivity())
|
||||
debugFloatWindow.showFloatWindow()
|
||||
}
|
||||
stateAutopilot -> {
|
||||
val autopilotState = intent.getIntExtra("autopilotState", 0)
|
||||
val autopilotMode = intent.getIntExtra("autopilotMode", 0)
|
||||
CallerAutoPilotStatusListenerManager.updateAutoPilotStatus(autopilotState,autopilotMode)
|
||||
}
|
||||
stateAutopilotFail -> {
|
||||
val newBuilder = MogoReportMsg.MogoReportMessage.newBuilder()
|
||||
newBuilder.code = "100"
|
||||
newBuilder.msg = "adb 模拟指令"
|
||||
newBuilder.timestampBuilder.sec = 0
|
||||
newBuilder.timestampBuilder.nsec = 0
|
||||
newBuilder.src = "2"
|
||||
newBuilder.level = ""
|
||||
var autopilotStatistics =
|
||||
AutopilotStatistics(1, SystemClock.elapsedRealtime(), null, newBuilder.build())
|
||||
CallerAutopilotStatisticsListenerManager.invokeAutopilotStatistics(autopilotStatistics)
|
||||
}
|
||||
stopSite -> {
|
||||
val state = intent.getIntExtra("state", 0)
|
||||
val action = intent.getIntExtra("action", 0)
|
||||
val pncAction = MessagePad.PlanningActionMsg.newBuilder()
|
||||
val planningaction = MessagePad.ParkScenarioPlanningAction.newBuilder()
|
||||
val drivingAction = MessagePad.ParkScenarioDrivingAction.newBuilder()
|
||||
drivingAction.drivingState = MessagePad.ParkScenarioDrivingState.forNumber(state)
|
||||
drivingAction.drivingAction = MessagePad.DrivingAction.forNumber(action)
|
||||
planningaction.actionMsg = drivingAction.build()
|
||||
pncAction.parkScenarioAction = planningaction.build()
|
||||
CallerPlanningActionsListenerManager.invokePNCActions(pncAction.build())
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun setStation(startLon:Double,startLat:Double,endLon:Double,endLat:Double,lineID:Long){
|
||||
if(startLon<0||startLat<0||endLon<0||endLat<0||lineID<0){
|
||||
TrajectoryAndDistanceManager.setStationPoint(null,null,-1)
|
||||
}
|
||||
val startLocation = MogoLocation()
|
||||
startLocation.longitude = startLon
|
||||
startLocation.latitude = startLat
|
||||
val endLocation = MogoLocation()
|
||||
endLocation.longitude = endLon
|
||||
endLocation.latitude = endLat
|
||||
TrajectoryAndDistanceManager.setStationPoint(startLocation,endLocation,lineID)
|
||||
}
|
||||
|
||||
fun getLocaitonByLog(path:String) {
|
||||
ThreadUtils.getIoPool().execute {
|
||||
try {
|
||||
val inputStream = FileInputStream(path)
|
||||
val reader = BufferedReader(InputStreamReader(inputStream))
|
||||
var line: String? = ""
|
||||
while (reader.readLine().also { line = it } != null) {
|
||||
val list = GsonUtils.fromJson<MogoLocationExit>(
|
||||
line.toString(),
|
||||
object : TypeToken<MogoLocationExit>() {}.type
|
||||
)
|
||||
val newBuilder = MessagePad.GnssInfo.newBuilder()
|
||||
newBuilder.latitude = list.msg.GnssInfo.latitude
|
||||
newBuilder.longitude = list.msg.GnssInfo.longitude
|
||||
newBuilder.heading = list.msg.GnssInfo.heading
|
||||
newBuilder.gnssSpeed = list.msg.GnssInfo.gnssSpeed
|
||||
CallerChassisGnssListenerManager.invokeChassisGnssListener(newBuilder.build())
|
||||
Thread.sleep(100)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadRawPoints(path:String) {
|
||||
val inputStream = FileInputStream(path)
|
||||
val reader = BufferedReader(InputStreamReader(inputStream))
|
||||
val jsonStr = StringBuilder()
|
||||
var line: String? = ""
|
||||
try {
|
||||
while (reader.readLine().also { line = it } != null) {
|
||||
jsonStr.append(line)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
val list = GsonUtils.fromJson<List<LatLng>>(
|
||||
jsonStr.toString(),
|
||||
object : TypeToken<List<LatLng?>?>() {}.type
|
||||
)
|
||||
val newBuilder = MessagePad.GlobalPathResp.newBuilder()
|
||||
|
||||
for (latLng in list) {
|
||||
val locationBuilder = MessagePad.Location.newBuilder()
|
||||
locationBuilder.latitude = latLng.latitude
|
||||
locationBuilder.longitude = latLng.longitude
|
||||
newBuilder.addWayPoints(locationBuilder)
|
||||
}
|
||||
try {
|
||||
val file = File(path)
|
||||
newBuilder.lineId = file.name.toLong()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
val mogoLocation = MogoLocation()
|
||||
|
||||
mogoLocation.latitude = list[0].latitude
|
||||
mogoLocation.longitude = list[0].longitude
|
||||
|
||||
val mogoSecondLocation = MogoLocation()
|
||||
mogoSecondLocation.latitude = list[1].latitude
|
||||
mogoSecondLocation.longitude = list[1].longitude
|
||||
val angle = CoordinateCalculateRouteUtil.getHeadingAngle(
|
||||
mogoLocation,
|
||||
mogoSecondLocation
|
||||
)
|
||||
mogoLocation.heading = angle
|
||||
|
||||
CallerChassisLocationGCJ02ListenerManager.invokeChassisLocationGCJ02(
|
||||
mogoLocation,
|
||||
DataSourceType.OBU
|
||||
)
|
||||
CallerLogger.d(SceneConstant.M_OCHCOMMON + TAG,"轨迹点个数:${list.size}")
|
||||
// 发送轨迹
|
||||
CallerPlanningRottingListenerManager.invokeAutopilotRotting(newBuilder.build())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mogo.och.common.module.debug.location
|
||||
|
||||
data class MogoLocationExit(
|
||||
val localTime: Long,
|
||||
val msg: Msg
|
||||
)
|
||||
data class Msg(
|
||||
val GnssInfo: GnssInfo,
|
||||
val Header: Header,
|
||||
val stringDate0: String
|
||||
)
|
||||
|
||||
data class Header(
|
||||
val msgID: Int,
|
||||
val msgType: String,
|
||||
val sourceTimestamp: Double,
|
||||
val timestamp: Double
|
||||
)
|
||||
|
||||
data class GnssInfo(
|
||||
val acceleration: Double,
|
||||
val altitude: Double,
|
||||
val gnssSpeed: Double,
|
||||
val heading: Double,
|
||||
val latitude: Double,
|
||||
val longitude: Double,
|
||||
val satelliteTime: Double,
|
||||
val systemTime: Double,
|
||||
val yawRate: Double
|
||||
)
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import com.mogo.cloud.network.OkHttpFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class CollectionUtils {
|
||||
public static void setInterceptor(){
|
||||
OkHttpClient okHttpClient = OkHttpFactory.Companion.getOkHttpClient();
|
||||
List<Interceptor> interceptors = okHttpClient.interceptors();
|
||||
Field pro = getDeclaredField(interceptors, "list");
|
||||
if(pro != null){
|
||||
pro.setAccessible(true);
|
||||
List<Interceptor> modifierList;
|
||||
try {
|
||||
modifierList = (List<Interceptor>) pro.get(interceptors);
|
||||
if(modifierList != null){
|
||||
modifierList.add(new SimpleInterceptor());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获得名为field的字段
|
||||
* @Description:如果本身找不到去父类寻找
|
||||
* @param object
|
||||
* @param fieldName
|
||||
* @return Field
|
||||
* @author luhao
|
||||
* @since:2019年2月26日 下午4:06:16
|
||||
*/
|
||||
public static Field getDeclaredField(Object object, String fieldName){
|
||||
if(fieldName == null){
|
||||
return null;
|
||||
}
|
||||
Field field;
|
||||
Class<?> clazz = object.getClass() ;
|
||||
for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
|
||||
try {
|
||||
field = clazz.getDeclaredField(fieldName) ;
|
||||
return field ;
|
||||
} catch (Exception e) {
|
||||
//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
|
||||
//如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import android.util.Log
|
||||
import okhttp3.*
|
||||
|
||||
class SimpleInterceptor: Interceptor {
|
||||
var first = true;
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val original = chain.request()
|
||||
val encodedPath = original.url().encodedPath()
|
||||
Log.e("SimpleInterceptor",original.method()+ encodedPath+original.url().encodedQuery())
|
||||
when (encodedPath) {
|
||||
"/autopilot-car-hailing/cab/flow/v1/bus/driver/bus/startOperation" -> {
|
||||
val builder = Response.Builder()
|
||||
val create = ResponseBody.create(MediaType.parse("application/json"), "{\"code\":100006,\"msg\":\"\",\"data\":null}")
|
||||
builder.code(200)
|
||||
builder.request(original)
|
||||
builder.protocol(Protocol.HTTP_1_1)
|
||||
builder.message("")
|
||||
return builder.body(create).build()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
return chain.proceed(original)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.mogo.och.common.module.view
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.PixelFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.eagle.core.utilcode.util.BarUtils
|
||||
import com.mogo.och.common.module.R
|
||||
import mogo_msg.MogoReportMsg
|
||||
|
||||
/**
|
||||
* @author XuXinChao
|
||||
* @description 工控机上报列表面板
|
||||
* @since: 2022/4/13
|
||||
*/
|
||||
class DebugFloatWindow constructor(activity: Activity) : View.OnTouchListener{
|
||||
|
||||
private var mActivity: Activity = activity
|
||||
private var mWindowParams: WindowManager.LayoutParams? = null
|
||||
private var mWindowManager: WindowManager? = null
|
||||
|
||||
private lateinit var mFloatLayout: View
|
||||
private var mInViewX = 0f
|
||||
private var mInViewY = 0f
|
||||
private var mDownInScreenX = 0f
|
||||
private var mDownInScreenY = 0f
|
||||
private var mInScreenX = 0f
|
||||
private var mInScreenY = 0f
|
||||
|
||||
init {
|
||||
initFloatWindow();
|
||||
}
|
||||
|
||||
private fun initFloatWindow() {
|
||||
mFloatLayout = LayoutInflater.from(mActivity).inflate(R.layout.debug_view, null) as View
|
||||
mFloatLayout.setOnTouchListener(this)
|
||||
mWindowParams = WindowManager.LayoutParams()
|
||||
mWindowManager = mActivity.windowManager
|
||||
mWindowParams?.let {
|
||||
it.format = PixelFormat.RGBA_8888
|
||||
it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
it.gravity = Gravity.START or Gravity.TOP
|
||||
it.width = 800
|
||||
it.height = 1000
|
||||
it.alpha = 0.9f
|
||||
}
|
||||
mFloatLayout.findViewById<AppCompatImageView>(R.id.close_window).onClick {
|
||||
hideFloatWindow()
|
||||
}
|
||||
|
||||
mFloatLayout.findViewById<AppCompatButton>(R.id.acbtn_send_15_dir).onClick {
|
||||
val newBuilder = MogoReportMsg.MogoReportMessage.newBuilder()
|
||||
newBuilder.code = "EMAP_ATTITUDE_INIT_FAILED"
|
||||
newBuilder.timestampBuilder.sec = 0
|
||||
newBuilder.timestampBuilder.nsec = 0
|
||||
newBuilder.src = "2"
|
||||
newBuilder.level = ""
|
||||
CallerAutoPilotStatusListenerManager.invokeAutopilotGuardian(newBuilder.build())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTouch(v: View?, motionEvent: MotionEvent?): Boolean {
|
||||
when (motionEvent?.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
// 获取相对View的坐标,即以此View左上角为原点
|
||||
mInViewX = motionEvent.x
|
||||
mInViewY = motionEvent.y
|
||||
// 获取相对屏幕的坐标,即以屏幕左上角为原点
|
||||
mDownInScreenX = motionEvent.rawX
|
||||
mDownInScreenY = motionEvent.rawY
|
||||
mInScreenX = motionEvent.rawX
|
||||
mInScreenY = motionEvent.rawY
|
||||
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
// 更新浮动窗口位置参数
|
||||
mInScreenX = motionEvent.rawX
|
||||
mInScreenY = motionEvent.rawY
|
||||
mWindowParams!!.x = (mInScreenX - mInViewX).toInt()
|
||||
mWindowParams!!.y = (mInScreenY - mInViewY).toInt()
|
||||
// 手指移动的时候更新小悬浮窗的位置
|
||||
mWindowManager!!.updateViewLayout(mFloatLayout, mWindowParams)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun showFloatWindow() {
|
||||
if (mFloatLayout.parent == null) {
|
||||
val metrics = DisplayMetrics()
|
||||
// 默认固定位置,靠屏幕右边缘的中间
|
||||
mWindowManager!!.defaultDisplay.getMetrics(metrics)
|
||||
mWindowParams!!.x = metrics.widthPixels
|
||||
mWindowParams!!.y = metrics.heightPixels / 2 - BarUtils.getStatusBarHeight()
|
||||
mWindowManager!!.addView(mFloatLayout, mWindowParams)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideFloatWindow() {
|
||||
if (mFloatLayout.parent != null) mWindowManager!!.removeView(mFloatLayout)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#717B98"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/blue"/>
|
||||
</shape>
|
||||
29
OCH/common/common/src/debug/res/layout/debug_view.xml
Normal file
29
OCH/common/common/src/debug/res/layout/debug_view.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="@color/green"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/close_window"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:src="@drawable/baseline_close_24"
|
||||
android:background="@drawable/common_close"
|
||||
android:layout_marginTop="@dimen/dp_40"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginEnd="@dimen/dp_40"
|
||||
android:layout_width="@dimen/dp_50"
|
||||
android:layout_height="@dimen/dp_50"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/acbtn_send_15_dir"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginTop="@dimen/dp_40"
|
||||
android:layout_marginStart="@dimen/dp_40"
|
||||
android:text="15m/方向相反"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
18
OCH/common/common/src/main/AndroidManifest.xml
Normal file
18
OCH/common/common/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.och.common.module">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name=".wigets.video.VideoPlayerActivity"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:process=":video_ad"
|
||||
android:resizeableActivity="false"
|
||||
android:resumeWhilePausing="true"
|
||||
android:screenOrientation="landscape"
|
||||
android:stateNotNeeded="true"
|
||||
android:theme="@style/Main"
|
||||
android:windowSoftInputMode="adjustPan|stateHidden" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mogo.och.common.module
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/4/26
|
||||
*/
|
||||
class OchCommonApi private constructor(){
|
||||
companion object{
|
||||
private var instance: OchCommonApi? = null
|
||||
get() {
|
||||
if (field == null){
|
||||
field = OchCommonApi();
|
||||
}
|
||||
return field
|
||||
}
|
||||
@Synchronized
|
||||
fun get():OchCommonApi{
|
||||
return instance!!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.och.common.module.bean.dpmsg
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2023/2/24
|
||||
*/
|
||||
enum class DPMsgType(val type: Int) {
|
||||
TYPE_COMMON(0), //常规
|
||||
TYPE_CHANGE_DEST(1),// 变更目的地确认/到站
|
||||
TYPE_OPEN_CLOSE_DOOR(2),//开关门
|
||||
TYPE_ORDER_CLOSED(3), // 订单结束
|
||||
TYPE_TASK_DETAILS(4), //路线任务详情
|
||||
TYPE_LOGIN_STATUS(5), //login status
|
||||
TYPE_ARRIVEDEST_STATUS(6), //到站通知 status
|
||||
TYPE_ORDER_CLOSED_BY_M1_STATUS(7) //到站通知 status
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.mogo.och.common.module.bean.dpmsg
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2023/3/27
|
||||
*/
|
||||
|
||||
object BusCacheKey{
|
||||
const val BUS_LINE_CACHE = "bus_line_cache"
|
||||
const val BUS_LOGIN_STATUS_CACHE = "bus_login_status_cache"
|
||||
}
|
||||
|
||||
open class BaseDPMsg(open var type: Int){// 0: 常规 1:确认路线/站点 2:开/关车门 3:结束订单
|
||||
companion object{
|
||||
const val TAG = "BaseDPMsg"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class LoginCacheStatus(
|
||||
var loginStatus: Int,
|
||||
var updateTime: Long
|
||||
): BaseDPMsg(DPMsgType.TYPE_LOGIN_STATUS.type)
|
||||
|
||||
data class ChangeDestMsg(
|
||||
var orderNo: String,// 订单号
|
||||
var lineId: Int, //线路id
|
||||
var lineName: String = "", //线路名称
|
||||
var startSiteId: Int= 0, //当前站点
|
||||
var startSiteName: String = "",
|
||||
var destSiteId: Int= 0, //目的地
|
||||
var destSiteName: String = "",
|
||||
var isConfirmed: Boolean = false, //司机端是否同意
|
||||
var arriveStatus:Int?, //1:未到达 2:到达
|
||||
var writeVersion:Long?, //版本标记
|
||||
var lineSiteList: MutableList<LineSite>? = null
|
||||
): BaseDPMsg(DPMsgType.TYPE_CHANGE_DEST.type)
|
||||
|
||||
data class LineSite(
|
||||
val lineId: Long?,//线路Id
|
||||
val lineName: String?,//线路名称
|
||||
val siteId: Long?,//线路Id
|
||||
val siteName: String?,//站点名称
|
||||
val Wgs84Lon: Double?,//高精坐标
|
||||
val Wgs84Lat: Double?,//高精坐标
|
||||
val GcjLon: Double?,//高德坐标
|
||||
val GcjLat: Double?,//高德坐标
|
||||
val seq: Double?,
|
||||
val type: Int?,
|
||||
)
|
||||
|
||||
data class ArriveDestMsg(
|
||||
var orderNo: String, //订单id
|
||||
var lineId: Int, //线路id
|
||||
var lineName: String = "", //线路名称
|
||||
var startSiteId: Int= 0, //当前站点
|
||||
var startSiteName: String = "",
|
||||
var destSiteId: Int= 0, //目的地
|
||||
var destSiteName: String = "",
|
||||
var arriveStatus:Int?, //1:未到达 2:到达
|
||||
var writtenVersion:Long?, //版本标记
|
||||
): BaseDPMsg(DPMsgType.TYPE_ARRIVEDEST_STATUS.type)
|
||||
|
||||
data class EndOrderMsg(
|
||||
var orderNo: String, //订单id
|
||||
): BaseDPMsg(DPMsgType.TYPE_ORDER_CLOSED_BY_M1_STATUS.type)
|
||||
|
||||
data class DPCommonOperationMsg(
|
||||
var msg: String
|
||||
): BaseDPMsg(DPMsgType.TYPE_COMMON.type)
|
||||
|
||||
data class DPOperateDoorMsg(
|
||||
var open: Boolean = false // true: 开门, false: 关门
|
||||
): BaseDPMsg(DPMsgType.TYPE_OPEN_CLOSE_DOOR.type)
|
||||
|
||||
data class DPOrderClosedMsg(
|
||||
var closed: Boolean = true // true: 结束
|
||||
): BaseDPMsg(DPMsgType.TYPE_ORDER_CLOSED.type)
|
||||
|
||||
data class AppConnectMsg(
|
||||
var isViewShow: Boolean = true, var isPlay: Boolean = false, var msg: String,var boxType:Int=-1
|
||||
) : BaseDPMsg(DPMsgType.TYPE_COMMON.type)
|
||||
|
||||
data class TaskDetailsMsg(
|
||||
var msg: String?,
|
||||
): BaseDPMsg(DPMsgType.TYPE_TASK_DETAILS.type)
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.mogo.och.common.module.biz.bean;
|
||||
|
||||
import com.mogo.eagle.core.data.BaseData;
|
||||
|
||||
/**
|
||||
* Created by pangfan on 2021/8/19
|
||||
*
|
||||
* 状态查询返回数据结构
|
||||
*/
|
||||
public class DriverStatusQueryRespBean extends BaseData {
|
||||
public Result data;
|
||||
|
||||
public static class Result {
|
||||
public int servingStatus; //1接单,1暂停接单
|
||||
public int driverStatus; //1登录,0登出
|
||||
public String orderNo;
|
||||
public int purpose; // 1 运营, 2 测试, 3演示
|
||||
|
||||
public String sn;
|
||||
public String plateNumber;//车牌号
|
||||
public String phone;//手机号
|
||||
public Integer lineId;//线路id
|
||||
public Integer taskId;//任务id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mogo.och.common.module.biz.bean;
|
||||
|
||||
/**
|
||||
* Created by yangyakun on 2021/8/19
|
||||
* 通过手机号验证码登录
|
||||
*/
|
||||
public class TaxiLoginReqBean {
|
||||
|
||||
public String phone;
|
||||
public String captcha;
|
||||
public String sn;
|
||||
public Location4Login loc;
|
||||
|
||||
public TaxiLoginReqBean(String phone, String code, String sn,Location4Login location4Login) {
|
||||
this.phone = phone;
|
||||
this.captcha = code;
|
||||
this.sn = sn;
|
||||
this.loc = location4Login;
|
||||
}
|
||||
|
||||
public static class Location4Login{
|
||||
public double lat;
|
||||
public double lon;
|
||||
|
||||
public Location4Login(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.och.common.module.biz.bean;
|
||||
|
||||
import com.mogo.eagle.core.data.BaseData;
|
||||
|
||||
/**
|
||||
* Created by yangyakun on 2021/8/19
|
||||
* 通过验证码登录
|
||||
*/
|
||||
public class TaxiLoginRespBean extends BaseData {
|
||||
|
||||
public Result data;
|
||||
|
||||
public static class Result {
|
||||
public Double lat;
|
||||
public Double lon;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.mogo.och.common.module.biz.bean;
|
||||
|
||||
/**
|
||||
* Created by yyk on 2021/8/19
|
||||
* 获取验证码
|
||||
*/
|
||||
public class TaxiLoginSmsReqBean {
|
||||
|
||||
public String phone;
|
||||
|
||||
public TaxiLoginSmsReqBean(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.mogo.och.common.module.biz.bean;
|
||||
|
||||
/**
|
||||
* Created by yyk on 2021/8/19
|
||||
* 登出请求参数
|
||||
*/
|
||||
public class TaxiLogoutReqBean {
|
||||
public String sn;
|
||||
public Location4Login loc;
|
||||
|
||||
public TaxiLogoutReqBean(String sn, Location4Login location4Login) {
|
||||
this.sn = sn;
|
||||
this.loc = location4Login;
|
||||
}
|
||||
|
||||
public static class Location4Login{
|
||||
public double lat;
|
||||
public double lon;
|
||||
|
||||
public Location4Login(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.mogo.och.common.module.biz.callback;
|
||||
|
||||
import com.mogo.och.common.module.biz.bean.DriverStatusQueryRespBean;
|
||||
|
||||
public interface ILoginCallback {
|
||||
void loginSuccess(DriverStatusQueryRespBean data);
|
||||
|
||||
void loginFail(boolean isLogin);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.och.common.module.biz.callback
|
||||
|
||||
interface ILoginViewCallback {
|
||||
/**
|
||||
* 展示登录页面
|
||||
*/
|
||||
fun showLoginDialogFragment()
|
||||
|
||||
/**
|
||||
* 隐藏登录页面
|
||||
*/
|
||||
fun hideLoginDialogFragment()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.common.module.biz.callback;
|
||||
|
||||
/**
|
||||
* Created on 2021/9/8
|
||||
*
|
||||
* Model->Presenter回调:订单相关(进行中/待服务单变更,当前进行单状态变更,新到预约单,抢单,抢单结果状态等等)
|
||||
*/
|
||||
public interface ITaxiLoginCallback {
|
||||
void getPhoneCodeSuccess();
|
||||
void loginSuccess();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.mogo.och.common.module.biz.common.socketmessage
|
||||
|
||||
import com.mogo.aicloud.services.socket.IMogoOnMessageListener
|
||||
import com.mogo.aicloud.services.socket.MogoAiCloudSocketManager
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.OperationMsg
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
|
||||
|
||||
/**
|
||||
* 统一管理业务长链消息推送
|
||||
*/
|
||||
object OCHSocketMessageManager {
|
||||
const val msgMonitorType:Int = 6295553 //后台运营消息
|
||||
const val msgWriteOffPassengerType:Int = 6295554 //核销消息
|
||||
const val msgOperateDoorType = 6295556 // 开/关门消息
|
||||
const val msgOrderClosedType = 6295555 //订单结束消息
|
||||
|
||||
const val OPERATION_SYSTEM: Int = -1 // 运营消息 默认是次消息类型
|
||||
const val OPERATION_ORDER_TYPE: Int = 0 // 还车通知
|
||||
const val OPERATION_ROAD_SIDE_TYPE: Int = 1 //靠边停车通知
|
||||
|
||||
fun <T> registerSocketMessageListener(msgType:Int,
|
||||
mogoOnMessageListener :IMogoOnMessageListener<T>){
|
||||
MogoAiCloudSocketManager.getInstance(AbsMogoApplication.getApp().applicationContext)
|
||||
.registerOnMessageListener(msgType,mogoOnMessageListener)
|
||||
}
|
||||
|
||||
fun releaseSocketMessageListener(msgType:Int){
|
||||
MogoAiCloudSocketManager.getInstance(AbsMogoApplication.getApp().applicationContext)
|
||||
.unregisterLifecycleListener(msgType)
|
||||
}
|
||||
|
||||
fun pushAppOperationalMsgBox(time : Long,content : String,type: Int = -1){
|
||||
|
||||
CallerMsgBoxManager.saveMsgBox(MsgBoxBean(MsgBoxType.OPERATION,
|
||||
OperationMsg(time,content,type)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mogo.och.common.module.biz.common.socketmessage.data
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2023/2/25
|
||||
*/
|
||||
open class DataBaseMsg (var msgType: Int,var pushTimeStamp: Long = System.currentTimeMillis())
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.och.common.module.biz.common.socketmessage.data
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class OCHOperationalMessage(
|
||||
var message: String = "",//运营消息
|
||||
var messageType: Int = 0, // 运营消息类型,目前没有用处,后台也没返回
|
||||
// 运营消息类型,目前没有用处,后台也没返回
|
||||
var pushTimeStamp: Long = System.currentTimeMillis() // 消息下发时间戳
|
||||
): Serializable
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.och.common.module.biz.common.socketmessage.data
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2023/2/25
|
||||
*/
|
||||
data class OperateDoorMsg(
|
||||
var orderNo: String,
|
||||
var message: String,
|
||||
var pushTimeStamp: Long = System.currentTimeMillis() // 消息下发时间戳
|
||||
) //{"orderNo":"","message":""}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.och.common.module.biz.common.socketmessage.data
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2023/2/25
|
||||
*/
|
||||
data class OrderCloseMsg(
|
||||
var orderNo: String,
|
||||
var message: String,
|
||||
var pushTimeStamp: Long = System.currentTimeMillis() // 消息下发时间戳
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.common.module.biz.common.socketmessage.data
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2023/2/25
|
||||
*/
|
||||
data class SystemMsg(
|
||||
var context: String,
|
||||
var screenList: MutableList<Int>,//1:司机屏 2:乘客屏
|
||||
var pushTimeStamp: Long = System.currentTimeMillis() // 消息下发时间戳
|
||||
)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.mogo.och.common.module.biz.constant
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object LoginStatusManager {
|
||||
/**
|
||||
* 登录状态
|
||||
*/
|
||||
private var loginStatus: TaxiLoginStatusEnum = TaxiLoginStatusEnum.None
|
||||
private val mStatusChangeListener = ConcurrentHashMap<String, ILoginStatusChangeListener>()
|
||||
|
||||
@JvmStatic
|
||||
fun setLoginStatus(status: Int) {
|
||||
when (status) {
|
||||
0 -> {
|
||||
setLoginStatus(TaxiLoginStatusEnum.Logout)
|
||||
}
|
||||
1 -> {
|
||||
setLoginStatus(TaxiLoginStatusEnum.Login)
|
||||
}
|
||||
else -> {
|
||||
setLoginStatus(TaxiLoginStatusEnum.None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun setLoginStatus(loginStatus: TaxiLoginStatusEnum) {
|
||||
if(loginStatus!=this.loginStatus){
|
||||
this.loginStatus = loginStatus
|
||||
for (callback in mStatusChangeListener.values) {
|
||||
callback.onStatusChange(loginStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun getLoginStatus(): TaxiLoginStatusEnum {
|
||||
return loginStatus
|
||||
}
|
||||
@JvmStatic
|
||||
fun isLogin():Boolean {
|
||||
if(loginStatus== TaxiLoginStatusEnum.Login){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun setControllerStatusCallback(tag: String, callback: ILoginStatusChangeListener?) {
|
||||
if (tag.isBlank()) return
|
||||
if (callback == null) {
|
||||
mStatusChangeListener.remove(tag)
|
||||
return
|
||||
}
|
||||
mStatusChangeListener[tag] = callback
|
||||
}
|
||||
|
||||
interface ILoginStatusChangeListener{
|
||||
fun onStatusChange(currentStatus:TaxiLoginStatusEnum)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.mogo.och.common.module.biz.constant
|
||||
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
|
||||
/**
|
||||
* Created on 2021/12/6
|
||||
*/
|
||||
class OchCommonConst {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getBaseUrl(): String {
|
||||
return FunctionBuildConfig.urlJson.ochUrl
|
||||
}
|
||||
@JvmStatic
|
||||
fun getShuttleUrl(): String {
|
||||
return FunctionBuildConfig.urlJson.shuttleUrl
|
||||
}
|
||||
@JvmStatic
|
||||
fun getSweeperUrl(): String {
|
||||
return FunctionBuildConfig.urlJson.sweeperUrl
|
||||
}
|
||||
// token 失效 重新获取token
|
||||
const val WAIT_TAKEN = 100046
|
||||
|
||||
const val LOGINSERVICE = "/ochbiz/common/login"
|
||||
|
||||
const val BUSINESS_STRING = 100
|
||||
|
||||
// 自动驾驶自动规划的最大距离
|
||||
const val AUTOMATIC_PLANNING_MAX_DISTANCE = 15
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.och.common.module.biz.constant
|
||||
|
||||
/**
|
||||
* Created on 2022/08/19
|
||||
*
|
||||
*
|
||||
* 0 初始状态,
|
||||
* 10 已登录,
|
||||
* 20 已登出,
|
||||
*/
|
||||
enum class TaxiLoginStatusEnum(val code: Int) {
|
||||
None( 0 ),
|
||||
Login( 10),
|
||||
Logout( 20),;
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun valueOf(code: Int): TaxiLoginStatusEnum? {
|
||||
for (value in values()) {
|
||||
if (value.code == code) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.mogo.och.common.module.biz.model
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr
|
||||
import com.mogo.eagle.core.utilcode.util.NetworkUtils
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginReqBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginRespBean
|
||||
import com.mogo.och.common.module.biz.callback.ITaxiLoginCallback
|
||||
import com.mogo.och.common.module.biz.constant.LoginStatusManager
|
||||
import com.mogo.och.common.module.biz.constant.TaxiLoginStatusEnum
|
||||
import com.mogo.och.common.module.biz.network.OchCommonServiceCallback
|
||||
import com.mogo.och.common.module.biz.network.OchCommonServiceManager
|
||||
import com.mogo.och.common.module.utils.ToastUtilsOch
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils
|
||||
|
||||
/**
|
||||
* Created by pangfan on 2021/8/19
|
||||
*
|
||||
*
|
||||
* 网约车 - 出租车业务逻辑处理
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object OchCommonLoginModel {
|
||||
|
||||
private val TAG = "TaxiLoginModel"
|
||||
private var mContext: Context? = null
|
||||
var iTaxiLoginCallback: ITaxiLoginCallback? = null
|
||||
fun init(context: Context) {
|
||||
mContext = context.applicationContext
|
||||
}
|
||||
|
||||
fun hasInit(): Boolean {
|
||||
if (mContext == null && iTaxiLoginCallback == null) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun getiTaxiLoginCallback(): ITaxiLoginCallback? {
|
||||
return iTaxiLoginCallback
|
||||
}
|
||||
|
||||
fun setiTaxiLoginCallback(iTaxiLoginCallback: ITaxiLoginCallback?) {
|
||||
this.iTaxiLoginCallback = iTaxiLoginCallback
|
||||
}
|
||||
|
||||
fun release() {
|
||||
mContext = null
|
||||
iTaxiLoginCallback = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取手机验证码
|
||||
*/
|
||||
fun getPhoneCode(phone: String?) {
|
||||
mContext?.let {
|
||||
OchCommonServiceManager.getPhoneCode(it, phone,
|
||||
object : OchCommonServiceCallback<BaseData> {
|
||||
override fun onSuccess(data: BaseData?) {
|
||||
if (null != data && 0 == data.code) {
|
||||
// 获取验证码成功
|
||||
ToastCharterUtils.showToastShort(mContext?.getString(R.string.module_och_taxi_login_get_code_success))
|
||||
iTaxiLoginCallback?.getPhoneCodeSuccess()
|
||||
} else {
|
||||
if (data != null) {
|
||||
ToastCharterUtils.showToastShort(data.code.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
if (!NetworkUtils.isConnected(mContext)) {
|
||||
ToastCharterUtils.showToastShort(mContext?.getString(R.string.network_error_tip))
|
||||
} else {
|
||||
ToastCharterUtils.showToastShort(mContext?.getString(R.string.request_error_tip))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFail(code: Int, msg: String) {
|
||||
ToastUtilsOch.showWithCodeMessage(code, msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun gotoLogin(phone: String, code: String) {
|
||||
mContext?.let {
|
||||
val location = CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
val location4Login = TaxiLoginReqBean.Location4Login(location.latitude, location.longitude)
|
||||
OchCommonServiceManager.gotoLoginBycode(it, phone, code, location4Login,
|
||||
object : OchCommonServiceCallback<TaxiLoginRespBean> {
|
||||
override fun onSuccess(data: TaxiLoginRespBean?) {
|
||||
if (null != data && 0 == data.code) {
|
||||
// 获取验证码成功
|
||||
ToastCharterUtils.showToastShort(mContext?.getString(R.string.module_och_taxi_login_login_success))
|
||||
LoginStatusManager.setLoginStatus(TaxiLoginStatusEnum.Login)
|
||||
mContext?.let { c ->
|
||||
SharedPrefsMgr.getInstance(c).putString("och_account", phone)
|
||||
}
|
||||
iTaxiLoginCallback?.loginSuccess()
|
||||
} else {
|
||||
if (data != null) {
|
||||
ToastCharterUtils.showToastShort(data.code.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
if (!NetworkUtils.isConnected(mContext)) {
|
||||
ToastCharterUtils.showToastShort(mContext?.getString(R.string.network_error_tip))
|
||||
} else {
|
||||
ToastCharterUtils.showToastShort(mContext?.getString(R.string.request_error_tip))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFail(code: Int, msg: String) {
|
||||
ToastUtilsOch.showWithCodeMessage(code, msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.mogo.och.common.module.biz.model
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr
|
||||
import com.mogo.eagle.core.utilcode.util.GsonUtils
|
||||
import com.mogo.och.common.module.bean.dpmsg.BusCacheKey
|
||||
import com.mogo.och.common.module.bean.dpmsg.LoginCacheStatus
|
||||
import com.mogo.och.common.module.biz.bean.DriverStatusQueryRespBean
|
||||
import com.mogo.och.common.module.biz.callback.ILoginCallback
|
||||
import com.mogo.och.common.module.biz.callback.ILoginViewCallback
|
||||
import com.mogo.och.common.module.biz.constant.LoginStatusManager
|
||||
import com.mogo.och.common.module.utils.DateTimeUtil
|
||||
import com.mogo.och.data.manager.cache.CacheDataManager
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object OchCommonLoginStatusDefaultModel : OchCommonLoginStatusModel() {
|
||||
|
||||
|
||||
const val TAG = "OchCommonLoginStatusDefaultModel"
|
||||
|
||||
|
||||
var loginCallback: ILoginCallback? = null
|
||||
var loginViewCallback: ILoginViewCallback? = null
|
||||
|
||||
override fun loginSuccess(data: DriverStatusQueryRespBean?) {
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "loginSuccess:${LoginStatusManager.isLogin()}")
|
||||
if (LoginStatusManager.isLogin()) {
|
||||
SharedPrefsMgr.getInstance(mContext).putString("och_account", data?.data?.phone)
|
||||
loginViewCallback?.hideLoginDialogFragment()
|
||||
} else {
|
||||
SharedPrefsMgr.getInstance(mContext).putString("och_account", "")
|
||||
loginViewCallback?.showLoginDialogFragment()
|
||||
}
|
||||
loginCallback?.loginSuccess(data)
|
||||
|
||||
data?.data?.driverStatus?.let { updateLoginLocalStatus(it) }
|
||||
|
||||
}
|
||||
|
||||
private fun updateLoginLocalStatus(loginStatus: Int = 0) {
|
||||
val loginCacheStatus = LoginCacheStatus(loginStatus,DateTimeUtil.getCurrentTimeStamp())
|
||||
CacheDataManager.instance.putCacheData(mContext, BusCacheKey.BUS_LOGIN_STATUS_CACHE,
|
||||
GsonUtils.toJson(loginCacheStatus))
|
||||
}
|
||||
|
||||
override fun loginFail(isLogin: Boolean) {
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "loginFail:$isLogin")
|
||||
if (isLogin) {
|
||||
loginViewCallback?.hideLoginDialogFragment()
|
||||
} else {
|
||||
loginViewCallback?.showLoginDialogFragment()
|
||||
}
|
||||
loginCallback?.loginFail(isLogin)
|
||||
|
||||
updateLoginLocalStatus(0)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.mogo.och.common.module.biz.model;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_TAXI;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.eagle.core.data.BaseData;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.utilcode.util.NetworkUtils;
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils;
|
||||
import com.mogo.och.common.module.R;
|
||||
import com.mogo.och.common.module.biz.bean.DriverStatusQueryRespBean;
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLogoutReqBean;
|
||||
import com.mogo.och.common.module.biz.constant.LoginStatusManager;
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst;
|
||||
import com.mogo.och.common.module.biz.network.OchCommonServiceCallback;
|
||||
import com.mogo.och.common.module.biz.network.OchCommonServiceManager;
|
||||
import com.mogo.och.common.module.utils.ToastUtilsOch;
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
public abstract class OchCommonLoginStatusModel {
|
||||
|
||||
private static final String TAG = "OchCommonLoginStatusModel";
|
||||
|
||||
protected Context mContext;
|
||||
|
||||
private Disposable subscribe;
|
||||
|
||||
|
||||
public void init() {
|
||||
mContext = AbsMogoApplication.getApp();
|
||||
queryCarStatus();
|
||||
}
|
||||
|
||||
protected abstract void loginSuccess(DriverStatusQueryRespBean data);
|
||||
|
||||
protected abstract void loginFail(boolean isLogin);
|
||||
|
||||
/**
|
||||
* 接单状态和登录状态查询
|
||||
* 1、初始化查询
|
||||
* 2、错误重试
|
||||
* 3、错误重试
|
||||
* 4、登出后重试
|
||||
* 5、变更出车状态查下
|
||||
* 6、变更出车状态查下
|
||||
* 7、网络状态变更后查询
|
||||
* 8、登录页面关闭后查下状态
|
||||
*/
|
||||
public void queryCarStatus() {
|
||||
OchCommonServiceManager.queryDriverServiceStatus(mContext,
|
||||
new OchCommonServiceCallback<DriverStatusQueryRespBean>() {
|
||||
@Override
|
||||
public void onSuccess(DriverStatusQueryRespBean data) {
|
||||
if (null != data && 0 == data.code) {
|
||||
LoginStatusManager.setLoginStatus(data.data.driverStatus);
|
||||
CallerLogger.d(M_TAXI + TAG, "changeCarStatus:" + LoginStatusManager.getLoginStatus());
|
||||
loginSuccess(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
if (!NetworkUtils.isConnected(mContext)) {
|
||||
ToastCharterUtils.showToastShort(mContext.getString(R.string.network_error_tip));
|
||||
} else {
|
||||
ToastCharterUtils.showToastShort(mContext.getString(R.string.request_error_tip));
|
||||
}
|
||||
subscribe = Observable.timer(5, TimeUnit.SECONDS).subscribe(aLong -> {
|
||||
queryCarStatus();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(int code, String msg) {
|
||||
ToastUtilsOch.showWithCodeMessage(code,msg);
|
||||
if(code== OchCommonConst.WAIT_TAKEN){
|
||||
subscribe = Observable.timer(3, TimeUnit.SECONDS).subscribe(aLong -> {
|
||||
queryCarStatus();
|
||||
});
|
||||
}else {
|
||||
loginFail(LoginStatusManager.isLogin());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 登出
|
||||
public void logout(double mLatitude,double mLongitude) {
|
||||
TaxiLogoutReqBean.Location4Login location4Login = new TaxiLogoutReqBean.Location4Login(mLatitude, mLongitude);
|
||||
OchCommonServiceManager.logout(mContext,location4Login,
|
||||
new OchCommonServiceCallback<BaseData>() {
|
||||
@Override
|
||||
public void onSuccess(BaseData data) {
|
||||
if (null != data && 0 == data.code) {
|
||||
loginFail(false);
|
||||
queryCarStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
if (!NetworkUtils.isConnected(mContext)) {
|
||||
ToastCharterUtils.showToastShort(mContext.getString(R.string.network_error_tip));
|
||||
} else {
|
||||
ToastCharterUtils.showToastShort(mContext.getString(R.string.request_error_tip));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(int code, String msg) {
|
||||
ToastUtilsOch.showWithCodeMessage(code,msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if(subscribe!=null&&!subscribe.isDisposed()){
|
||||
subscribe.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mogo.och.common.module.biz.network
|
||||
|
||||
import android.content.Context
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.och.common.module.biz.bean.DriverStatusQueryRespBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginReqBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginRespBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLogoutReqBean
|
||||
|
||||
interface LoginDefaultManage {
|
||||
fun getPhoneCode(
|
||||
context: Context,
|
||||
phone: String?,
|
||||
callback: OchCommonServiceCallback<BaseData>?
|
||||
)
|
||||
fun gotoLoginBycode(
|
||||
context: Context, phone: String?, code: String?,
|
||||
location4Login: TaxiLoginReqBean.Location4Login?,
|
||||
callback: OchCommonServiceCallback<TaxiLoginRespBean>?
|
||||
)
|
||||
fun logout(
|
||||
context: Context,
|
||||
location4Login: TaxiLogoutReqBean.Location4Login?,
|
||||
callback: OchCommonServiceCallback<BaseData>?
|
||||
)
|
||||
fun queryDriverServiceStatus(
|
||||
context: Context,
|
||||
callback: OchCommonServiceCallback<DriverStatusQueryRespBean>?
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.och.common.module.biz.network;
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2021/1/15
|
||||
*
|
||||
* 修改订单状态回调接口
|
||||
*/
|
||||
public interface OchCommonServiceCallback< T > {
|
||||
|
||||
void onSuccess(T data);
|
||||
|
||||
void onFail(int code, String msg);
|
||||
|
||||
default void onError() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.mogo.och.common.module.biz.network
|
||||
|
||||
import android.content.Context
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst.Companion.getBaseUrl
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginSmsReqBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginReqBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginRespBean
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLogoutReqBean
|
||||
import com.mogo.och.common.module.biz.bean.DriverStatusQueryRespBean
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClient
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.och.common.module.biz.network.interceptor.transformTry
|
||||
import io.reactivex.Observable
|
||||
|
||||
/**
|
||||
* Created by pangfan on 2021/8/19
|
||||
*/
|
||||
object OchCommonServiceManager {
|
||||
|
||||
private const val TAG = "OchCommonServiceManager"
|
||||
|
||||
private var loginDefaultManage: LoginDefaultManage?=null
|
||||
|
||||
fun setLoginDefaultManage(loginDefaultManage: LoginDefaultManage?){
|
||||
this.loginDefaultManage = loginDefaultManage
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取手机验证码
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getPhoneCode(
|
||||
context: Context, phone: String?,
|
||||
callback: OchCommonServiceCallback<BaseData>?
|
||||
) {
|
||||
loginDefaultManage?.getPhoneCode(context,phone,callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过验证码登录
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
@JvmStatic
|
||||
fun gotoLoginBycode(
|
||||
context: Context, phone: String?, code: String?,
|
||||
location4Login: TaxiLoginReqBean.Location4Login?,
|
||||
callback: OchCommonServiceCallback<TaxiLoginRespBean>?
|
||||
) {
|
||||
loginDefaultManage?.gotoLoginBycode(context,phone,code,location4Login,callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logout(
|
||||
context: Context,
|
||||
location4Login: TaxiLogoutReqBean.Location4Login?,
|
||||
callback: OchCommonServiceCallback<BaseData>?
|
||||
) {
|
||||
loginDefaultManage?.logout(context,location4Login,callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 接单状态和登录状态查询
|
||||
*
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
@JvmStatic
|
||||
fun queryDriverServiceStatus(
|
||||
context: Context,
|
||||
callback: OchCommonServiceCallback<DriverStatusQueryRespBean>?
|
||||
) {
|
||||
loginDefaultManage?.queryDriverServiceStatus(context,callback)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.mogo.och.common.module.biz.network
|
||||
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.eagle.core.network.RequestOptions
|
||||
import com.mogo.eagle.core.network.SubscribeImpl
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.och.common.module.utils.CallerLoggerUtils.flavorTag
|
||||
|
||||
class OchCommonSubscribeImpl<T : BaseData>(
|
||||
val context: Any,
|
||||
val callback: OchCommonServiceCallback<T>?,
|
||||
val apiName: String
|
||||
) : SubscribeImpl<T>(RequestOptions.create(context)) {
|
||||
|
||||
companion object {
|
||||
const val TAG = "OchCommonSubscribeImpl"
|
||||
}
|
||||
|
||||
override fun onSuccess(o: T) {
|
||||
super.onSuccess(o)
|
||||
CallerLogger.d("$flavorTag$TAG", "$apiName: onSuccess() ${o.msg}")
|
||||
callback?.onSuccess(o)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
CallerLogger.e("$flavorTag$TAG", "$apiName: onError() ${e.message}")
|
||||
callback?.onError()
|
||||
}
|
||||
|
||||
override fun onError(message: String, code: Int) {
|
||||
super.onError(message, code)
|
||||
CallerLogger.e("$flavorTag$TAG", "$apiName: onError() code = $code; message = $message")
|
||||
callback?.onFail(code, message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mogo.och.common.module.biz.network.interceptor
|
||||
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClient
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.och.common.module.biz.constant.LoginStatusManager
|
||||
import com.mogo.och.common.module.biz.constant.TaxiLoginStatusEnum
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableSource
|
||||
import io.reactivex.functions.Function
|
||||
|
||||
class FRetryWithTime<T : BaseData> : Function<T, ObservableSource<T>> {
|
||||
|
||||
override fun apply(baseData: T): ObservableSource<T> {
|
||||
baseData.let {
|
||||
if (it.code == 100046 || it.code == 100045 || it.code == 100005 || it.code == 100006 || it.code == 520003) {
|
||||
MoGoAiCloudClient.getInstance().refreshToken()
|
||||
return Observable.error(OchCommonRetryException())
|
||||
}else if(it.code == 1003){
|
||||
LoginStatusManager.setLoginStatus(TaxiLoginStatusEnum.Logout)
|
||||
}
|
||||
}
|
||||
return Observable.just(baseData)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.mogo.och.common.module.biz.network.interceptor
|
||||
|
||||
import io.reactivex.Observable
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
fun <T : BaseData> Observable<T>.transformTry():Observable<T> {
|
||||
return flatMap(FRetryWithTime<T>())
|
||||
.retryWhen(RetryWithTime())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
fun <T : BaseData> Observable<T>.transformIoTry():Observable<T> {
|
||||
return flatMap(FRetryWithTime<T>())
|
||||
.retryWhen(RetryWithTime())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.mogo.och.common.module.biz.network.interceptor;
|
||||
|
||||
public class OchCommonRetryException extends RuntimeException{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mogo.och.common.module.biz.network.interceptor
|
||||
|
||||
import com.mogo.eagle.core.utilcode.constant.TimeConstants
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.util.TimeUtils
|
||||
import com.mogo.och.common.module.utils.CallerLoggerUtils.flavorTag
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableSource
|
||||
import io.reactivex.functions.Function
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class RetryWithTime : Function<Observable<Throwable?>, ObservableSource<Any?>> {
|
||||
companion object {
|
||||
private const val TAG = "RetryWithTime"
|
||||
}
|
||||
var current = -1
|
||||
private var timeDelys = intArrayOf(3, 1, 2)
|
||||
override fun apply(throwableObservable: Observable<Throwable?>): ObservableSource<Any?>? {
|
||||
return throwableObservable.flatMap {
|
||||
++current
|
||||
CallerLogger.e("${flavorTag}${TAG}", " 时间:${TimeUtils.getStringByNow(0, TimeConstants.SEC)}")
|
||||
if (it is OchCommonRetryException && current < timeDelys.size) {
|
||||
Observable.timer(timeDelys[current].toLong(), TimeUnit.SECONDS)
|
||||
} else {
|
||||
Observable.error(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.mogo.och.common.module.biz.presenter
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.mvp.Presenter
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.RegexUtils
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.common.module.biz.callback.ITaxiLoginCallback
|
||||
import com.mogo.och.common.module.biz.model.OchCommonLoginModel
|
||||
import com.mogo.och.common.module.biz.ui.TaxiLoginDialogFragment
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* @author congtaowang
|
||||
* @since 2021/1/18
|
||||
*
|
||||
* 描述
|
||||
*/
|
||||
class OchCommonLoginPresenter(view: TaxiLoginDialogFragment?) :
|
||||
Presenter<TaxiLoginDialogFragment?>(view), ITaxiLoginCallback {
|
||||
|
||||
private var countDownDisposable: Disposable? = null
|
||||
|
||||
init {
|
||||
initListeners()
|
||||
}
|
||||
|
||||
private fun initListeners() {
|
||||
OchCommonLoginModel.init(AbsMogoApplication.getApp())
|
||||
OchCommonLoginModel.setiTaxiLoginCallback(this)
|
||||
}
|
||||
|
||||
fun getPhoneCode(phone:String){
|
||||
if(!OchCommonLoginModel.hasInit()){
|
||||
initListeners()
|
||||
}
|
||||
if (!RegexUtils.isMobileExact(phone)) {
|
||||
ToastCharterUtils.showToastShort(R.string.module_och_taxi_login_phone_error)
|
||||
mView?.inputPhoneError()
|
||||
return
|
||||
}
|
||||
OchCommonLoginModel.getPhoneCode(phone)
|
||||
}
|
||||
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
super.onCreate(owner)
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "网约车-出租车登陆")
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
super.onDestroy(owner)
|
||||
OchCommonLoginModel.release()
|
||||
countDownDisposable?.let {
|
||||
if (!it.isDisposed) {
|
||||
it.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = OchCommonLoginPresenter::class.java.simpleName
|
||||
}
|
||||
|
||||
override fun getPhoneCodeSuccess() {
|
||||
val countDownSeconds = 60L;
|
||||
countDownDisposable = Observable.intervalRange(0, countDownSeconds, 0, 1, TimeUnit.SECONDS)
|
||||
.map { aLong -> countDownSeconds - aLong }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
mView?.setCountDownText("${it}s",false)
|
||||
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "倒计时:$it")
|
||||
}, {
|
||||
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "倒计时onError:${it}")
|
||||
it.printStackTrace()
|
||||
mView?.setCountDownText(AbsMogoApplication.getApp().getString(R.string.module_och_taxi_login_get_code),true)
|
||||
}, {
|
||||
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "倒计时onComplete")
|
||||
mView?.setCountDownText(AbsMogoApplication.getApp().getString(R.string.module_och_taxi_login_get_code),true)
|
||||
})
|
||||
}
|
||||
|
||||
override fun loginSuccess() {
|
||||
mView?.loginSuccess()
|
||||
}
|
||||
|
||||
fun gotoLogin(phone: String, code: String) {
|
||||
if(!OchCommonLoginModel.hasInit()){
|
||||
initListeners()
|
||||
}
|
||||
if (!RegexUtils.isMobileExact(phone)) {
|
||||
ToastCharterUtils.showToastShort(R.string.module_och_taxi_login_phone_error)
|
||||
mView?.inputPhoneError()
|
||||
return
|
||||
}
|
||||
if(code.isBlank()||code.length<4){
|
||||
ToastCharterUtils.showToastShort(R.string.module_och_taxi_login_code_error)
|
||||
return
|
||||
}
|
||||
mView?.closeSoftInput()
|
||||
OchCommonLoginModel.gotoLogin(phone,code)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.mogo.och.common.module.biz.presenter
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import com.mogo.och.common.module.biz.callback.ILoginCallback
|
||||
import com.mogo.och.common.module.biz.callback.ILoginViewCallback
|
||||
import com.mogo.och.common.module.biz.model.OchCommonLoginStatusDefaultModel
|
||||
|
||||
/**
|
||||
* @author yangyakun
|
||||
* @since 2020-09-19
|
||||
*/
|
||||
class OchCommonLoginStatusDefaultPresenter : LifecycleObserver {
|
||||
private var isFirstShow = true
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
|
||||
fun onCreate(owner: LifecycleOwner) {
|
||||
OchCommonLoginStatusDefaultModel.init()
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
fun onResume(owner: LifecycleOwner) {
|
||||
if (isFirstShow) {
|
||||
isFirstShow = false
|
||||
} else {
|
||||
queryLoginStatus()
|
||||
}
|
||||
}
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
fun onDestory(owner: LifecycleOwner) {
|
||||
OchCommonLoginStatusDefaultModel.release()
|
||||
}
|
||||
|
||||
fun queryLoginStatus() {
|
||||
OchCommonLoginStatusDefaultModel.queryCarStatus()
|
||||
}
|
||||
|
||||
fun logOut(mLatitude:Double,mLongitude:Double){
|
||||
OchCommonLoginStatusDefaultModel.logout(mLatitude, mLongitude)
|
||||
}
|
||||
|
||||
fun setLoginCallback(loginCallback: ILoginCallback?,loginViewCallback: ILoginViewCallback?){
|
||||
OchCommonLoginStatusDefaultModel.loginCallback = loginCallback
|
||||
OchCommonLoginStatusDefaultModel.loginViewCallback = loginViewCallback
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.mogo.och.common.module.biz.provider
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.alibaba.android.arouter.facade.template.IProvider
|
||||
import com.mogo.och.common.module.biz.callback.ILoginCallback
|
||||
import com.mogo.och.common.module.biz.network.LoginDefaultManage
|
||||
|
||||
interface LoginService : IProvider {
|
||||
/**
|
||||
* 注册页面
|
||||
* @param fragment 主页面
|
||||
* @param callback 回调
|
||||
*/
|
||||
fun registerFragment(fragment: Fragment?,loginCallback: ILoginCallback?,logindefaultmanage: LoginDefaultManage?)
|
||||
|
||||
fun unRegisterFragment()
|
||||
|
||||
/**
|
||||
* 查询登录状态
|
||||
*/
|
||||
fun queryLoginStatus():Boolean
|
||||
|
||||
fun queryLoginStatusByNet()
|
||||
|
||||
fun showUiModel(show:Boolean)
|
||||
|
||||
/**
|
||||
* 登出
|
||||
*/
|
||||
fun loginOut(mLatitude:Double,mLongitude:Double)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mogo.och.common.module.biz.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.AppStateManager.currentActivity
|
||||
import com.mogo.eagle.core.utilcode.util.ClickUtils
|
||||
import com.mogo.och.common.module.biz.callback.ILoginCallback
|
||||
import com.mogo.och.common.module.biz.callback.ILoginViewCallback
|
||||
import com.mogo.och.common.module.biz.constant.LoginStatusManager
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst
|
||||
import com.mogo.och.common.module.biz.network.LoginDefaultManage
|
||||
import com.mogo.och.common.module.biz.network.OchCommonServiceManager
|
||||
import com.mogo.och.common.module.biz.presenter.OchCommonLoginStatusDefaultPresenter
|
||||
import com.mogo.och.common.module.biz.ui.TaxiLoginDialogFragment
|
||||
import com.mogo.och.common.module.biz.ui.TaxiLoginDialogFragment.Companion.newInstance
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@Route(path = OchCommonConst.LOGINSERVICE)
|
||||
class LoginServiceImpl : LoginService,ILoginViewCallback {
|
||||
|
||||
companion object{
|
||||
const val TAG = "LoginServiceImpl"
|
||||
}
|
||||
|
||||
private var fragment: Fragment?=null
|
||||
private var taxiLoginDialogFragment: WeakReference<TaxiLoginDialogFragment>? = null
|
||||
private var presenter: OchCommonLoginStatusDefaultPresenter?=null
|
||||
private var uiModel = true
|
||||
|
||||
override fun init(context: Context) {
|
||||
|
||||
}
|
||||
|
||||
override fun registerFragment(fragment: Fragment?,loginCallback: ILoginCallback?,logindefaultmanage: LoginDefaultManage?) {
|
||||
OchCommonServiceManager.setLoginDefaultManage(logindefaultmanage)
|
||||
presenter = OchCommonLoginStatusDefaultPresenter()
|
||||
this.fragment = fragment
|
||||
presenter?.let {
|
||||
it.setLoginCallback(loginCallback, this)
|
||||
this.fragment?.lifecycle?.addObserver(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun unRegisterFragment() {
|
||||
this.presenter?.let {
|
||||
it.setLoginCallback(null,null)
|
||||
this.fragment?.lifecycle?.removeObserver(it)
|
||||
}
|
||||
this.fragment = null
|
||||
}
|
||||
|
||||
|
||||
override fun showLoginDialogFragment() {
|
||||
if(uiModel) {
|
||||
fragment?.let {
|
||||
CallerHmiManager.hideToolsView()
|
||||
CallerHmiManager.hideSOPSettingView()
|
||||
val parentFragmentManager = it.childFragmentManager
|
||||
val fragmentByTag: Fragment? = parentFragmentManager.findFragmentByTag(TAG)
|
||||
if (fragmentByTag is DialogFragment) {
|
||||
if (fragmentByTag.dialog != null && fragmentByTag.dialog!!.isShowing) {
|
||||
return
|
||||
}
|
||||
if (fragmentByTag.dialog != null && fragmentByTag.isAdded) {
|
||||
if (currentActivity() == null) { // 没有在当前应用内 在启动页面关闭应用
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "showLoginDialogFragment 权限验证")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (taxiLoginDialogFragment?.get() == null) {
|
||||
taxiLoginDialogFragment = WeakReference(newInstance())
|
||||
}
|
||||
val taxiLoginDialog = taxiLoginDialogFragment?.get()
|
||||
if (taxiLoginDialog != null) {
|
||||
if (taxiLoginDialog.dialog != null && taxiLoginDialog.dialog!!.isShowing) {
|
||||
return
|
||||
}
|
||||
if (taxiLoginDialog.isAdded) { //解决方法就是添加这行代码,如果已经添加了,就移除掉然后再show,就不会出现Fragment already added的错误了。
|
||||
parentFragmentManager.beginTransaction().remove(taxiLoginDialog)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
if (ClickUtils.isFastClick()) {
|
||||
taxiLoginDialog.show(parentFragmentManager, TAG)
|
||||
taxiLoginDialog.setOnDismissListener(DialogInterface.OnDismissListener { dialog: DialogInterface? ->
|
||||
taxiLoginDialogFragment?.clear()
|
||||
presenter?.queryLoginStatus()
|
||||
})
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "showLoginDialogFragment 展示登录界面")
|
||||
}else{
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "showLoginDialogFragment 展示登录界面 1s内执行一次")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun hideLoginDialogFragment() {
|
||||
CallerLogger.d(SceneConstant.M_TAXI + TAG, "hideLoginDialogFragment 隐藏登录界面")
|
||||
if (taxiLoginDialogFragment?.get() != null) {
|
||||
taxiLoginDialogFragment?.get()?.dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
override fun queryLoginStatus():Boolean {
|
||||
return LoginStatusManager.isLogin()
|
||||
}
|
||||
|
||||
override fun queryLoginStatusByNet() {
|
||||
presenter?.queryLoginStatus()
|
||||
}
|
||||
|
||||
override fun showUiModel(show:Boolean) {
|
||||
uiModel = show;
|
||||
}
|
||||
|
||||
override fun loginOut(mLatitude:Double,mLongitude:Double) {
|
||||
presenter?.logOut(mLatitude,mLongitude)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package com.mogo.och.common.module.biz.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.mogo.commons.mvp.MvpDialogFragment
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.KeyboardUtils
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.common.module.biz.bean.TaxiLoginReqBean
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst
|
||||
import com.mogo.och.common.module.biz.network.OchCommonServiceManager
|
||||
import com.mogo.och.common.module.biz.network.interceptor.transformTry
|
||||
import com.mogo.och.common.module.biz.presenter.OchCommonLoginPresenter
|
||||
import com.mogo.och.common.module.biz.provider.LoginService
|
||||
|
||||
|
||||
/**
|
||||
* @author: yangyakun
|
||||
* @date: 2022/8/15
|
||||
*/
|
||||
class TaxiLoginDialogFragment :
|
||||
MvpDialogFragment<TaxiLoginDialogFragment?, OchCommonLoginPresenter?>(),
|
||||
DialogInterface.OnKeyListener {
|
||||
|
||||
lateinit var clMain: ConstraintLayout
|
||||
lateinit var acbtnLogin: AppCompatButton
|
||||
lateinit var actvLoginGetCode: AppCompatTextView
|
||||
lateinit var actvLoginShowSn: AppCompatTextView
|
||||
lateinit var aceLoginPhoneValue: AppCompatEditText
|
||||
lateinit var acetPhoneCodeValue: AppCompatEditText
|
||||
lateinit var actvWelcomeLoginTitle: AppCompatTextView
|
||||
lateinit var acivLoginBg: AppCompatImageView
|
||||
private var mOnClickListener: DialogInterface.OnDismissListener? = null
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NO_TITLE, R.style.DialogFullScreen) //dialog全屏
|
||||
}
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
dialog?.setOnKeyListener(this)
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.taxi_login_view
|
||||
}
|
||||
|
||||
override fun initViews() {
|
||||
clMain = mRootView.findViewById(R.id.cl_main)
|
||||
acbtnLogin = mRootView.findViewById(R.id.acbtn_login)
|
||||
actvLoginGetCode = mRootView.findViewById(R.id.actv_login_get_code)
|
||||
aceLoginPhoneValue = mRootView.findViewById(R.id.ace_login_phone_value)
|
||||
acetPhoneCodeValue = mRootView.findViewById(R.id.acet_phone_code_value)
|
||||
actvWelcomeLoginTitle = mRootView.findViewById(R.id.actv_welcome_login_title)
|
||||
actvLoginShowSn = mRootView.findViewById(R.id.actv_login_show_sn)
|
||||
acivLoginBg = mRootView.findViewById(R.id.aciv_login_bg)
|
||||
inputPhoneNormal()
|
||||
initBg()
|
||||
initListener()
|
||||
dialog?.window?.let {
|
||||
context?.let { _ ->
|
||||
CallerHmiManager.setStatusBarDarkOrLight(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initBg() {
|
||||
if (AppIdentityModeUtils.isTaxi(FunctionBuildConfig.appIdentityMode) &&
|
||||
AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
|
||||
//出租车司机
|
||||
acivLoginBg.setImageResource(R.drawable.taxi_ic_login_bg)
|
||||
} else if ((AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)
|
||||
|| AppIdentityModeUtils.isShuttle(FunctionBuildConfig.appIdentityMode)
|
||||
|| AppIdentityModeUtils.isCharter(FunctionBuildConfig.appIdentityMode)) &&
|
||||
AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
|
||||
//小巴车司机
|
||||
acivLoginBg.setImageResource(R.drawable.bus_ic_login_bg)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun initListener() {
|
||||
mRootView.isFocusable = true
|
||||
mRootView.isFocusableInTouchMode = true
|
||||
mRootView.setOnTouchListener { _, event ->
|
||||
when (event?.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
closeSoftInput()
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
acbtnLogin.onClick {
|
||||
val phone = aceLoginPhoneValue.text.toString()
|
||||
val code = acetPhoneCodeValue.text.toString()
|
||||
mPresenter?.gotoLogin(phone, code)
|
||||
}
|
||||
actvWelcomeLoginTitle.setOnClickListener {
|
||||
continuousClick()
|
||||
}
|
||||
clMain.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
val rect = Rect()
|
||||
clMain.getWindowVisibleDisplayFrame(rect)
|
||||
val mainInvisibleHeight = clMain.rootView.height - rect.bottom
|
||||
if (mainInvisibleHeight > 100) {
|
||||
val outLocation = IntArray(2)
|
||||
acbtnLogin.getLocationInWindow(outLocation)
|
||||
val srollHeight = (outLocation[1] + acbtnLogin.height) - rect.bottom
|
||||
if (srollHeight > 0) {
|
||||
clMain.scrollTo(0, srollHeight)
|
||||
}
|
||||
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "滚动的距离:$srollHeight")
|
||||
} else {
|
||||
clMain.scrollTo(0, 0)
|
||||
}
|
||||
}
|
||||
actvLoginGetCode.onClick {
|
||||
mPresenter?.getPhoneCode(aceLoginPhoneValue.text.toString())
|
||||
}
|
||||
actvLoginShowSn.setOnLongClickListener {
|
||||
val loginService = ARouter.getInstance().build(OchCommonConst.LOGINSERVICE)
|
||||
.navigation() as LoginService
|
||||
loginService.showUiModel(false)
|
||||
dismissAllowingStateLoss()
|
||||
true
|
||||
}
|
||||
aceLoginPhoneValue.addTextChangedListener {
|
||||
it?.let { itEditable ->
|
||||
if (itEditable.isNotEmpty()) {
|
||||
inputPhoneNormal()
|
||||
}
|
||||
}
|
||||
}
|
||||
actvLoginShowSn.text = MoGoAiCloudClientConfig.getInstance().sn
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭键盘
|
||||
*/
|
||||
fun closeSoftInput() {
|
||||
mRootView.requestFocus()
|
||||
dialog?.window?.let {
|
||||
KeyboardUtils.hideSoftInput(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCountDownText(text: String, enable: Boolean) {
|
||||
if (enable) {
|
||||
actvLoginGetCode.setText(R.string.module_och_taxi_login_get_code)
|
||||
actvLoginGetCode.isEnabled = true
|
||||
} else {
|
||||
actvLoginGetCode.text = text
|
||||
actvLoginGetCode.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
fun inputPhoneError() {
|
||||
aceLoginPhoneValue.text?.clear()
|
||||
aceLoginPhoneValue.setHint(R.string.module_och_taxi_login_phone_error)
|
||||
context?.let {
|
||||
aceLoginPhoneValue.setHintTextColor(ContextCompat.getColor(it, R.color.taxi_EF262C))
|
||||
aceLoginPhoneValue.setBackgroundResource(R.drawable.taxi_login_phone_error)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inputPhoneNormal() {
|
||||
//aceLoginPhoneValue.setHint(R.string.module_och_taxi_login_phone_hint_text)
|
||||
context?.let {
|
||||
aceLoginPhoneValue.setHintTextColor(ContextCompat.getColor(it, R.color.taxi_878890))
|
||||
aceLoginPhoneValue.setBackgroundResource(R.drawable.taxi_login_phone_normal)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createPresenter(): OchCommonLoginPresenter {
|
||||
return OchCommonLoginPresenter(this)
|
||||
}
|
||||
|
||||
override fun getTagName(): String {
|
||||
return TAG
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val COUNTS = 4 // 点击次数
|
||||
private const val DURATION: Long = 1000 // 规定有效时间
|
||||
val TAG = TaxiLoginDialogFragment::class.java.simpleName
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): TaxiLoginDialogFragment {
|
||||
val args = Bundle()
|
||||
val fragment = TaxiLoginDialogFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
|
||||
private var mHits = LongArray(COUNTS)
|
||||
|
||||
private fun continuousClick() {
|
||||
//每次点击时,数组向前移动一位
|
||||
System.arraycopy(mHits, 1, mHits, 0, mHits.size - 1)
|
||||
//为数组最后一位赋值
|
||||
mHits[mHits.size - 1] = SystemClock.uptimeMillis()
|
||||
if (mHits[0] >= (SystemClock.uptimeMillis() - DURATION)) {
|
||||
mHits = LongArray(COUNTS) //重新初始化数组
|
||||
mPresenter?.gotoLogin("13288888888", "8888")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKey(dialog: DialogInterface, keyCode: Int, event: KeyEvent): Boolean {
|
||||
return keyCode == KeyEvent.KEYCODE_BACK
|
||||
}
|
||||
|
||||
fun loginSuccess() {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
fun setOnDismissListener(listener: DialogInterface.OnDismissListener?) {
|
||||
mOnClickListener = listener
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
mOnClickListener?.onDismiss(dialog)
|
||||
CallerHmiManager.setStatusBarDarkOrLight(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写父类show()方法
|
||||
* 避免出现java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
|
||||
*/
|
||||
override fun show(manager: FragmentManager, tag: String?) {
|
||||
try {
|
||||
var cls = this.javaClass.superclass ?: return
|
||||
while (cls != null) {
|
||||
if (cls.name == "java.lang.Object") {
|
||||
break
|
||||
}
|
||||
cls = cls.superclass!!
|
||||
if (cls == DialogFragment::class.java) {
|
||||
break
|
||||
}
|
||||
}
|
||||
val mDismissed = cls.getDeclaredField("mDismissed")
|
||||
val mShownByMe = cls.getDeclaredField("mShownByMe")
|
||||
mDismissed.isAccessible = true
|
||||
mShownByMe.isAccessible = true
|
||||
mDismissed.setBoolean(this, false)
|
||||
mShownByMe.setBoolean(this, true)
|
||||
if (isAdded) { //解决方法就是添加这行代码,如果已经添加了,就移除掉然后再show,就不会出现Fragment already added的错误了。
|
||||
return
|
||||
}
|
||||
val ft: FragmentTransaction = manager.beginTransaction()
|
||||
ft.add(this, tag)
|
||||
ft.commitAllowingStateLoss()
|
||||
} catch (e: Exception) {
|
||||
Log.e("DialogFragment", "show", e.fillInStackTrace())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.mogo.och.common.module.callback
|
||||
|
||||
import androidx.annotation.ColorRes
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/1/21
|
||||
*/
|
||||
interface IShadow {
|
||||
//设置阴影半径
|
||||
fun setShadowRadius(radius:Float): IShadow
|
||||
|
||||
//添加单位设置
|
||||
fun setShadowRadius(unit:Int,radius: Float): IShadow
|
||||
|
||||
//设置应用颜色
|
||||
fun setShadowColor(color:Int): IShadow
|
||||
|
||||
//设置阴影颜色资源文件id
|
||||
fun setShadowColorRes(@ColorRes color: Int): IShadow
|
||||
/**
|
||||
* 设置模糊半径
|
||||
* @param radius
|
||||
*/
|
||||
fun setBlurRadius(radius:Float): IShadow
|
||||
|
||||
/**
|
||||
*
|
||||
* @param unit @{@link android.util.TypedValue#TYPE_DIMENSION}
|
||||
* @param radius 模糊半径
|
||||
*/
|
||||
fun setBlurRadius(unit:Int,radius:Float): IShadow
|
||||
|
||||
/**
|
||||
* 设置水平方向的偏移量
|
||||
* @param offset x轴偏移
|
||||
*/
|
||||
fun setXOffset(offset:Float): IShadow
|
||||
|
||||
|
||||
/**
|
||||
* 设置x方向的偏移量,设置单位
|
||||
* @param unit @{@link android.util.TypedValue#TYPE_DIMENSION}
|
||||
* @param offset x轴偏移
|
||||
*/
|
||||
fun setXOffset(unit:Int,offset:Float): IShadow
|
||||
|
||||
/**
|
||||
* 设置竖直方向的偏移量
|
||||
* @param offset y轴偏移
|
||||
*/
|
||||
fun setYOffset(offset:Float): IShadow
|
||||
|
||||
/**
|
||||
* 设置竖直方向的偏移量,带单位
|
||||
* @param unit @{@link android.util.TypedValue#TYPE_DIMENSION}
|
||||
* @param offset y轴偏移
|
||||
*/
|
||||
fun setYOffset(unit:Int,offset:Float): IShadow
|
||||
|
||||
/**
|
||||
* 更新绘制
|
||||
*/
|
||||
fun commit();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.och.common.module.callback
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/11/9
|
||||
*/
|
||||
interface OchAdasStartFailureCallback {
|
||||
fun onStartAutopilotFailure(startFailedCode : String, startFailedMessage : String)
|
||||
|
||||
fun brakeStatusChanged(isBrakeAvailable: Boolean)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.mogo.och.common.module.manager
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import com.mogo.commons.module.status.IMogoStatusChangedListener
|
||||
import com.mogo.commons.module.status.MogoStatusManager
|
||||
import com.mogo.commons.module.status.StatusDescriptor
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.i
|
||||
import com.mogo.eagle.core.utilcode.util.NetworkUtils
|
||||
import com.mogo.och.common.module.utils.PermissionUtil
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/12/2
|
||||
*/
|
||||
object AbnormalFactorsLoopManager : IMogoStatusChangedListener {
|
||||
|
||||
const val TAG = "AbnormalFactorsLoopManager"
|
||||
|
||||
private const val LOOP_TIME = 10 * 1000L
|
||||
private const val LOOP_DELAY = 5 * 1000L
|
||||
private var socketStatus by Delegates.observable(false) { _, _, newValue ->
|
||||
if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
|
||||
return@observable
|
||||
}
|
||||
if (FunctionBuildConfig.isDemoMode) {
|
||||
return@observable
|
||||
}
|
||||
if (newValue) {
|
||||
ToastCharterUtils.showToastLong("长链接状态恢复")
|
||||
} else {
|
||||
ToastCharterUtils.showToastLong("长链接异常,请开启相应权限或者查看网络")
|
||||
}
|
||||
}
|
||||
|
||||
private var looperDisposable: Disposable? = null
|
||||
|
||||
fun startLoopAbnormalFactors(context: Context) {
|
||||
if (looperDisposable != null && !looperDisposable!!.isDisposed) {
|
||||
return
|
||||
}
|
||||
i(TAG, "startLoopAbnormalFactors()")
|
||||
looperDisposable = Observable.interval(LOOP_DELAY, LOOP_TIME, TimeUnit.MILLISECONDS)
|
||||
.map { aLong -> aLong + 1 }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { aLong -> checkAbnormalFactors(context) }
|
||||
|
||||
//长链接监听
|
||||
MogoStatusManager.getInstance().registerStatusChangedListener(
|
||||
TAG,
|
||||
StatusDescriptor.CLOUD_SOCKET, this
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkAbnormalFactors(context: Context) {
|
||||
|
||||
var locationStatusPermsStatus = false
|
||||
var networkStatus = false
|
||||
|
||||
//定位权限
|
||||
locationStatusPermsStatus =
|
||||
!(!PermissionUtil.isLocServiceEnable(context) || !PermissionUtil.checkPermission(
|
||||
context, *arrayOf(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
)
|
||||
))
|
||||
|
||||
//网络状态或者网络权限是否打开
|
||||
if (NetworkUtils.isConnected(context)) {
|
||||
networkStatus = true
|
||||
}
|
||||
//长链接状态 socketStatus
|
||||
|
||||
var toastStr = ""
|
||||
if (!locationStatusPermsStatus) toastStr += "定位服务异常 "
|
||||
if (!networkStatus) toastStr += " 网络异常 "
|
||||
|
||||
i(TAG, "abnormal_factors_Str = $toastStr")
|
||||
|
||||
if (!FunctionBuildConfig.isDemoMode && toastStr !== "") {
|
||||
ToastCharterUtils.showToastLong(toastStr + "请开启相应权限或者查看网络")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun stopLoopAbnormalFactors() {
|
||||
looperDisposable!!.dispose()
|
||||
looperDisposable == null
|
||||
|
||||
MogoStatusManager.getInstance().unregisterStatusChangedListener(
|
||||
TAG,
|
||||
StatusDescriptor.CLOUD_SOCKET, this
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStatusChanged(descriptor: StatusDescriptor?, isTrue: Boolean) {
|
||||
//长链接监听、
|
||||
if (StatusDescriptor.CLOUD_SOCKET == descriptor) {
|
||||
socketStatus = isTrue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.mogo.och.common.module.manager
|
||||
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
object CharterSendTripInfoManager{
|
||||
|
||||
const val START_TRIP = 1
|
||||
const val END_TRIP = 2
|
||||
const val LEAVE_STATION = 3
|
||||
const val ARRIVE_STATION = 4
|
||||
|
||||
/**
|
||||
* 行程信息
|
||||
* @param type 事件类型, 1:行程开始, 2:行程结束, 3:出站, 4:进站, 5:城市占道施工预警
|
||||
* @param lineName 路线名, for type 1, 2
|
||||
* @param departureStopName 出站站点名, for type 3, 4
|
||||
* @param arrivalStopName 下一站到达站点名, for type 3, 4
|
||||
* @param isLastStop 是否终点站(下一站或者要到达站)
|
||||
* @return
|
||||
*/
|
||||
fun sendCharterTripInfo(type: Int, lineName: String,
|
||||
departureStopName: String,
|
||||
arrivalStopName: String,
|
||||
isLastStop: Boolean) {
|
||||
d(SceneConstant.M_BUS + "CharterSendTripInfoManager", "type: "+ type
|
||||
+", lineName: "+ lineName +", departureStopName: "+ departureStopName
|
||||
+ ", arrivalStopName: "+arrivalStopName+", isLastStop: "+isLastStop)
|
||||
CallerAutoPilotControlManager.sendTripInfo(type,lineName,departureStopName, arrivalStopName, isLastStop)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.mogo.och.common.module.manager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager.sendOperatorSetAcceleratedSpeed
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager.sendOperatorSetHorn
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* 魔方连接状态和设备管理
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
class DriverMoFangFunctionManager private constructor() {
|
||||
|
||||
companion object {
|
||||
val driverMoFangFunctionManager: DriverMoFangFunctionManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
DriverMoFangFunctionManager()
|
||||
}
|
||||
}
|
||||
|
||||
private val TAG = "DriverMoFangFunctionManager"
|
||||
private var timerHorn: Timer? = null
|
||||
private var timerAcc: Timer? = null
|
||||
/**
|
||||
* 发送加速和减速,复位的时候,isSend为false,其他都是true,acc就是具体的值
|
||||
* acc -1 是减速, -2是刹停 0是复位时候传
|
||||
*/
|
||||
@Synchronized
|
||||
fun sendAcc(isSend: Boolean, acc: Double) {
|
||||
if (isSend) {
|
||||
if (timerAcc == null) {
|
||||
timerAcc = Timer()
|
||||
timerAcc!!.schedule(object : TimerTask() {
|
||||
override fun run() {
|
||||
d(SceneConstant.M_CHARTER_D + TAG,"sendOperatorSetAcceleratedSpeed $isSend $acc")
|
||||
sendOperatorSetAcceleratedSpeed(acc)
|
||||
}
|
||||
}, 0, 500)
|
||||
}
|
||||
} else {
|
||||
if (timerAcc != null) {
|
||||
timerAcc!!.cancel()
|
||||
timerAcc = null
|
||||
}
|
||||
d(SceneConstant.M_CHARTER_D + TAG,"sendOperatorSetAcceleratedSpeed $isSend $acc")
|
||||
sendOperatorSetAcceleratedSpeed(acc)
|
||||
}
|
||||
}
|
||||
|
||||
fun reset(){
|
||||
d(SceneConstant.M_CHARTER_D + TAG,"sendAcc false 0.0")
|
||||
sendAcc(false,0.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 鸣笛,鸣笛需要手动结束
|
||||
*/
|
||||
fun sendOperatorSetHornByDriver(){
|
||||
d(SceneConstant.M_CHARTER_D + TAG,"sendOperatorSetHorn(1.0)")
|
||||
sendOperatorSetHorn(1.0)
|
||||
if (timerHorn == null) {
|
||||
timerHorn = Timer()
|
||||
}
|
||||
timerHorn!!.schedule(object : TimerTask() {
|
||||
override fun run() {
|
||||
d(SceneConstant.M_CHARTER_D + TAG,"sendOperatorSetHorn(2.0)")
|
||||
sendOperatorSetHorn(2.0)
|
||||
timerHorn = null
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.mogo.och.common.module.manager
|
||||
|
||||
import com.mogo.eagle.core.function.call.telematic.CallerTelematicManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.GsonUtils
|
||||
import com.mogo.och.common.module.bean.dpmsg.BaseDPMsg
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst
|
||||
|
||||
object LanSocketManager {
|
||||
private const val TAG = "LanSocket"
|
||||
fun sendMsgToClient(msg: BaseDPMsg?) {
|
||||
CallerLogger.d(SceneConstant.M_CHARTER_D + TAG, "sendMsgToClient" + GsonUtils.toJson(msg))
|
||||
CallerTelematicManager.sendMsgToAllClients(
|
||||
OchCommonConst.BUSINESS_STRING,
|
||||
GsonUtils.toJson(msg).toByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
fun sendMsgToServer(msg: BaseDPMsg?) {
|
||||
CallerLogger.d(SceneConstant.M_CHARTER_D + TAG, "sendMsgToServer" + GsonUtils.toJson(msg))
|
||||
CallerTelematicManager.sendMsgToServer(
|
||||
OchCommonConst.BUSINESS_STRING,
|
||||
GsonUtils.toJson(msg).toByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.mogo.och.common.module.manager.autopilotmanager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotActionsListener;
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatisticsListener;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotActionsListenerManager;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotStatisticsListenerManager;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerParallelDrivingActionsListenerManager;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
|
||||
import com.mogo.eagle.core.utilcode.util.ParseVersionUtils;
|
||||
import com.mogo.och.common.module.callback.OchAdasStartFailureCallback;
|
||||
import com.zhjt.mogo.adas.data.bean.AutopilotStatistics;
|
||||
import com.zhjt.mogo.adas.data.bean.UnableLaunchData;
|
||||
import com.zhjt.mogo.adas.data.bean.UnableLaunchReason;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created on 2022/10/9
|
||||
* 工控机状态信息回调(判断是否能否启动自动驾驶的回调)
|
||||
* 目前定的是3秒回调一次
|
||||
*/
|
||||
public class OCHAdasAbilityManager implements IMoGoAutopilotActionsListener, IMoGoAutopilotStatisticsListener {
|
||||
|
||||
private static final String TAG = OCHAdasAbilityManager.class.getSimpleName();
|
||||
|
||||
private boolean isAutopilotAbility;
|
||||
private UnableLaunchData unableLaunchData;
|
||||
private ArrayList<UnableLaunchReason> unableAutopilotReasons;
|
||||
private String startFailedCode = "";
|
||||
private String startFailedMessage = "";
|
||||
|
||||
private OchAdasStartFailureCallback failureCallback = null;
|
||||
|
||||
private static final class SingletonHolder {
|
||||
private static final OCHAdasAbilityManager INSTANCE = new OCHAdasAbilityManager();
|
||||
}
|
||||
|
||||
public static OCHAdasAbilityManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public void init(Context context) {
|
||||
this.isAutopilotAbility = CallerAutopilotActionsListenerManager.INSTANCE.isAutopilotAbility();
|
||||
this.unableLaunchData = CallerAutopilotActionsListenerManager.INSTANCE.getUnableLaunchData();
|
||||
this.unableAutopilotReasons = CallerAutopilotActionsListenerManager.INSTANCE.getUnableAutopilotReasons();
|
||||
initListeners();
|
||||
}
|
||||
|
||||
public void setAdasStartFailureCallback(OchAdasStartFailureCallback callback){
|
||||
failureCallback = callback;
|
||||
}
|
||||
|
||||
public boolean getAutopilotAbilityStatus(){
|
||||
return isAutopilotAbility;
|
||||
}
|
||||
|
||||
public String getOriginalData() {
|
||||
return unableLaunchData == null ? "" : unableLaunchData.getJson();
|
||||
}
|
||||
public String getAutopilotUnAbilityReason(){
|
||||
try {
|
||||
if(unableAutopilotReasons==null||unableAutopilotReasons.isEmpty()){
|
||||
return "未知异常";
|
||||
}else {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < unableAutopilotReasons.size(); i++) {
|
||||
stringBuilder.append(unableAutopilotReasons.get(i));
|
||||
if(i<unableAutopilotReasons.size()-1){
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return "未知异常";
|
||||
}
|
||||
}
|
||||
|
||||
public String getStartFailedCode() {
|
||||
return startFailedCode;
|
||||
}
|
||||
|
||||
public String getStartFailedMessage() {
|
||||
return startFailedMessage;
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
//2022.10.9 工控机状态信息回调(判断是否能否启动自动驾驶的回调), 目前定的是3秒回调一次
|
||||
CallerAutopilotActionsListenerManager.INSTANCE.addListener(TAG, this);
|
||||
CallerAutopilotStatisticsListenerManager.INSTANCE.addListener(TAG,this);
|
||||
}
|
||||
|
||||
private void releaseListeners() {
|
||||
CallerAutopilotActionsListenerManager.INSTANCE.removeListener(this);
|
||||
CallerAutopilotStatisticsListenerManager.INSTANCE.removeListener(this);
|
||||
CallerParallelDrivingActionsListenerManager.INSTANCE.removeListener(TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutopilotAbility(boolean isAutopilotAbility,@Nullable UnableLaunchData unableLaunchData, @Nullable ArrayList<UnableLaunchReason> unableAutopilotReasons) {
|
||||
this.isAutopilotAbility = isAutopilotAbility;
|
||||
this.unableLaunchData = unableLaunchData;
|
||||
this.unableAutopilotReasons = unableAutopilotReasons;
|
||||
Logger.d(TAG, "是否可以启动自动驾驶=" + isAutopilotAbility + " 原因=" + (unableAutopilotReasons == null ? null : unableAutopilotReasons.toString()) + " 原始数据=" + (unableLaunchData == null ? null : unableLaunchData.getJson()));
|
||||
if (unableAutopilotReasons != null && getMapVersion() < 30600) {
|
||||
//刹车变化回调
|
||||
Logger.d(TAG,"onAutopilotAbility = " + isAutopilotAbility +
|
||||
" onAutopilotAbility =" + unableAutopilotReasons.toString());
|
||||
if (unableAutopilotReasons.toString().contains(UnableLaunchReason.SourceType.CHASSIS.name())
|
||||
&& unableAutopilotReasons.toString().contains(UnableLaunchReason.UnableType.BRAKE.name())) {
|
||||
failureCallback.brakeStatusChanged(isAutopilotAbility);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onAutopilotStatistics(@Nullable AutopilotStatistics statistics) {
|
||||
if (statistics == null) return;
|
||||
Logger.d(TAG, "AutopilotStatistics= " + statistics.status);
|
||||
if (failureCallback != null && 1 == statistics.status){
|
||||
startFailedCode = statistics.failedMessage.getCode();
|
||||
startFailedMessage = statistics.failedMessage.getMsg();
|
||||
failureCallback.onStartAutopilotFailure(startFailedCode, startFailedMessage);
|
||||
Logger.d(TAG, String.format("statistics-startFailedCode = s%; startFailedMessage = s%",
|
||||
startFailedCode, startFailedMessage));
|
||||
}
|
||||
}
|
||||
|
||||
private int getMapVersion(){
|
||||
return ParseVersionUtils.parseVersion(true, CallerAutoPilotStatusListenerManager.INSTANCE.getDockerVersion());
|
||||
}
|
||||
public void release() {
|
||||
releaseListeners();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.mogo.och.common.module.manager.beautifymode
|
||||
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.function.api.hmi.view.IViewControlListener
|
||||
import com.mogo.eagle.core.function.api.telematic.IReceivedMsgListener
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager
|
||||
import com.mogo.eagle.core.function.call.telematic.CallerTelematicListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object BeautifyManager : IViewControlListener, IReceivedMsgListener {
|
||||
|
||||
private val TAG = BeautifyManager::class.java.simpleName
|
||||
|
||||
enum class ChangeTypeEnum{
|
||||
BEAUTIFY_TYPE,// 美化模式变化
|
||||
ORDER_STATU_CHANGE,// 订单状态发生变化
|
||||
ARRIVED_DEST,// 到站
|
||||
STOPSITE_SUCCESS,// 靠边停车成功
|
||||
STOPSITE_SUCCESS_RUN// 靠边停车成功后恢复为正在驾驶
|
||||
}
|
||||
|
||||
private val orderStatusChangeListeners = ConcurrentHashMap<String, IBeautifyModeCallback>()
|
||||
|
||||
init {
|
||||
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
|
||||
CallerHmiViewControlListenerManager.addListener(TAG,this)
|
||||
} else if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
|
||||
CallerTelematicListenerManager.addListener(TAG,this)
|
||||
}
|
||||
}
|
||||
|
||||
fun setStatusChangeListener(tag: String, orderStatusChangeListener: IBeautifyModeCallback?) {
|
||||
if (tag.isBlank()) return
|
||||
if (orderStatusChangeListener == null) {
|
||||
orderStatusChangeListeners.remove(tag)
|
||||
return
|
||||
}
|
||||
orderStatusChangeListeners[tag] = orderStatusChangeListener
|
||||
}
|
||||
|
||||
|
||||
fun notifyViewChange(typeEnum: ChangeTypeEnum){
|
||||
CallerLogger.d(TAG,"美化模式变化原因:${typeEnum}")
|
||||
orderStatusChangeListeners.forEach {
|
||||
it.value.dispatchStatus(typeEnum)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReceivedMsg(type: Int, byteArray: ByteArray) {
|
||||
|
||||
}
|
||||
|
||||
override fun onDemoMode(isDemoMode: Boolean) {
|
||||
notifyViewChange(ChangeTypeEnum.BEAUTIFY_TYPE)
|
||||
}
|
||||
|
||||
override fun updateFuncMode(tag: String, boolean: Boolean) {
|
||||
if (tag == IViewControlListener.FUNC_MODE_DEMO) {
|
||||
notifyViewChange(ChangeTypeEnum.BEAUTIFY_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.mogo.och.common.module.manager.beautifymode
|
||||
|
||||
|
||||
interface IBeautifyModeCallback {
|
||||
fun dispatchStatus(typeEnum: BeautifyManager.ChangeTypeEnum)
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package com.mogo.och.common.module.manager.debug
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.mogo.commons.mvp.MvpDialogFragment
|
||||
import com.mogo.eagle.core.function.hmi.ui.setting.ToggleDebugView
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS_P
|
||||
import com.mogo.eagle.core.utilcode.util.AppStateManager
|
||||
import com.mogo.eagle.core.utilcode.util.BarUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ClickUtils
|
||||
import com.mogo.eagle.core.utilcode.util.KeyboardUtils
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils
|
||||
import kotlinx.android.synthetic.main.m1_debugview_pass.*
|
||||
|
||||
/**
|
||||
* @author: yangyakun
|
||||
* @date: 2023/1/28
|
||||
*/
|
||||
class DebugViewWatchDogFragment :
|
||||
MvpDialogFragment<DebugViewWatchDogFragment?, DebugWatchDogPresenter?>() {
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NO_TITLE, R.style.DialogFullScreen) //dialog全屏
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.m1_debugview_pass
|
||||
|
||||
override fun getTagName(): String = TAG
|
||||
|
||||
override fun initViews() {
|
||||
dialog?.setCancelable(false)
|
||||
actv_password_submit.setOnClickListener {
|
||||
val text = acet_close.text
|
||||
if(text==null||text.isEmpty()){
|
||||
ToastCharterUtils.showToastShort("请输入密码")
|
||||
}else{
|
||||
if(text.toString() == "123987"){
|
||||
dismissAllowingStateLoss()
|
||||
dialog?.window?.let {
|
||||
KeyboardUtils.hideSoftInput(it)
|
||||
}
|
||||
ToggleDebugView.toggleDebugView.toggle(requireContext())
|
||||
}else{
|
||||
ToastCharterUtils.showToastShort("请输入正确密码")
|
||||
}
|
||||
}
|
||||
}
|
||||
actv_cancle.setOnClickListener {
|
||||
dialog?.window?.let {
|
||||
KeyboardUtils.hideSoftInput(it)
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
acet_close.text?.clear()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
dialog?.window?.let {
|
||||
BarUtils.hideStatusBarAndSticky(it)
|
||||
it.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
|
||||
dialog?.setOnShowListener { _ ->
|
||||
it.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
|
||||
BarUtils.hideStatusBarAndSticky(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun createPresenter(): DebugWatchDogPresenter =
|
||||
DebugWatchDogPresenter(this)
|
||||
|
||||
/**
|
||||
* 重写父类show()方法
|
||||
* 避免出现java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
|
||||
*/
|
||||
override fun show(manager: FragmentManager, tag: String?) {
|
||||
try {
|
||||
var cls = this.javaClass.superclass ?: return
|
||||
while (true) {
|
||||
if (cls.name == "java.lang.Object") {
|
||||
break
|
||||
}
|
||||
cls = cls.superclass!!
|
||||
if (cls == DialogFragment::class.java) {
|
||||
break
|
||||
}
|
||||
}
|
||||
val mDismissed = cls.getDeclaredField("mDismissed")
|
||||
val mShownByMe = cls.getDeclaredField("mShownByMe")
|
||||
mDismissed.isAccessible = true
|
||||
mShownByMe.isAccessible = true
|
||||
mDismissed.setBoolean(this, false)
|
||||
mShownByMe.setBoolean(this, true)
|
||||
if (isAdded) { //解决方法就是添加这行代码,如果已经添加了,就移除掉然后再show,就不会出现Fragment already added的错误了。
|
||||
return
|
||||
}
|
||||
val ft: FragmentTransaction = manager.beginTransaction()
|
||||
ft.add(this, tag)
|
||||
ft.commitAllowingStateLoss()
|
||||
} catch (e: Exception) {
|
||||
Log.e("DialogFragment", "show", e.fillInStackTrace())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
CallerLogger.d(M_BUS_P+ TAG, "onViewStateRestored")
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "DebugViewWatchDogFragment"
|
||||
@JvmStatic
|
||||
fun newInstance(): DebugViewWatchDogFragment {
|
||||
val args = Bundle()
|
||||
val fragment = DebugViewWatchDogFragment()
|
||||
CallerLogger.d(M_BUS_P + TAG, "创建新的Fragment")
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
fun showDebugView(
|
||||
childFragmentManager: FragmentManager,
|
||||
parentFragmentManager: FragmentManager,
|
||||
debugViewWatchDogFragment: DebugViewWatchDogFragment?
|
||||
) {
|
||||
|
||||
val fragmentByTag: Fragment? = childFragmentManager.findFragmentByTag(TAG)
|
||||
if (fragmentByTag is DialogFragment) {
|
||||
if (fragmentByTag.dialog != null && fragmentByTag.dialog!!.isShowing) {
|
||||
CallerLogger.d(M_BUS_P + TAG, "正在展示")
|
||||
return
|
||||
}
|
||||
if (fragmentByTag.dialog != null && fragmentByTag.isAdded) {
|
||||
if (AppStateManager.currentActivity() == null) { // 没有在当前应用内 在启动页面关闭应用
|
||||
CallerLogger.d(M_BUS_P + TAG, "权限验证")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debugViewWatchDogFragment != null) {
|
||||
if (debugViewWatchDogFragment.dialog != null && debugViewWatchDogFragment.dialog!!.isShowing) {
|
||||
CallerLogger.d(M_BUS_P + TAG, "正在展示")
|
||||
return
|
||||
}
|
||||
if (ClickUtils.isFastClick()) {
|
||||
if (debugViewWatchDogFragment.isAdded) { //解决方法就是添加这行代码,如果已经添加了,就移除掉然后再show,就不会出现Fragment already added的错误了。
|
||||
parentFragmentManager.beginTransaction().remove(debugViewWatchDogFragment)
|
||||
.commitAllowingStateLoss()
|
||||
CallerLogger.d(M_BUS_P + TAG, "已经添加正在移除")
|
||||
}
|
||||
debugViewWatchDogFragment.show(parentFragmentManager, TAG)
|
||||
CallerLogger.d(M_BUS_P + TAG, "展示开关门")
|
||||
} else {
|
||||
CallerLogger.d(M_BUS_P + TAG, "dialog 1s内执行一次")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.och.common.module.manager.debug
|
||||
|
||||
import com.mogo.commons.mvp.Presenter
|
||||
|
||||
class DebugWatchDogPresenter(view: DebugViewWatchDogFragment?) :
|
||||
Presenter<DebugViewWatchDogFragment?>(view){
|
||||
companion object {
|
||||
private const val TAG = "BusPassengerFunctionPresenter"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage
|
||||
|
||||
import com.mogo.commons.voice.AIAssist
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.och.common.module.bean.dpmsg.AppConnectMsg
|
||||
import com.mogo.och.common.module.biz.common.socketmessage.OCHSocketMessageManager
|
||||
import com.mogo.och.common.module.manager.LanSocketManager
|
||||
import com.mogo.och.common.module.utils.DateTimeUtil
|
||||
import com.mogo.och.common.module.utils.RxUtils
|
||||
import com.mogo.och.common.module.voice.VoiceNotice
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
object LightAirconditionDoorManager {
|
||||
private const val TAG = "LightAirconditionDoorManager"
|
||||
|
||||
private var dooorSubscribe: Disposable? = null
|
||||
|
||||
fun go2OpenDoor(go2Open:Boolean){
|
||||
val canOpenOrCloseDoor = canOpenOrCloseDoor()
|
||||
if(!canOpenOrCloseDoor.isNullOrBlank()){
|
||||
ToastCharterUtils.showToastLong(canOpenOrCloseDoor)
|
||||
return
|
||||
}
|
||||
RxUtils.disposeSubscribe(dooorSubscribe)
|
||||
dooorSubscribe = RxUtils.createSubscribe(1000) {
|
||||
CallerAutoPilotControlManager.sendRoboBusJinlvM1FrontDoorCmd(0)
|
||||
}
|
||||
if(go2Open) {
|
||||
if (LightAirconditionDoorStatusManager.doorStatus.isOpen) {
|
||||
return
|
||||
}
|
||||
CallerAutoPilotControlManager.sendRoboBusJinlvM1FrontDoorCmd(1)
|
||||
}else{
|
||||
if (!LightAirconditionDoorStatusManager.doorStatus.isOpen) {
|
||||
return
|
||||
}
|
||||
CallerAutoPilotControlManager.sendRoboBusJinlvM1FrontDoorCmd(2)
|
||||
}
|
||||
}
|
||||
|
||||
private fun canOpenOrCloseDoor(): String? {
|
||||
val location = CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
return if(location.gnssSpeed<0.3){
|
||||
null
|
||||
}else{
|
||||
"车辆行驶中不可以开关门哦~"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage
|
||||
|
||||
import chassis.VehicleStateOuterClass
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoRoboBusJinlvM1StatesListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerRoboBusJinlvM1StatesListenerManager
|
||||
import com.mogo.och.common.module.manager.devicemanage.callback.LightAirconditionDoorCallback
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.AirconditionStatus
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.DoorStatus
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.HeaterStatue
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.LightStatus
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object LightAirconditionDoorStatusManager : IMoGoRoboBusJinlvM1StatesListener {
|
||||
private const val TAG = "OCHM1LightAirconditionDoorStatusManager"
|
||||
|
||||
init {
|
||||
CallerRoboBusJinlvM1StatesListenerManager.addListener(TAG, this)
|
||||
CallerRoboBusJinlvM1StatesListenerManager.setListenerHz(TAG,5)
|
||||
}
|
||||
|
||||
val M_LISTENERS: ConcurrentHashMap<String, LightAirconditionDoorCallback> =
|
||||
ConcurrentHashMap()
|
||||
|
||||
val airconditionStatus = AirconditionStatus(false, 0, 26, 2)
|
||||
val heaterStatue = HeaterStatue(false, 2)
|
||||
val doorStatus = DoorStatus(false)
|
||||
val lightStatus = LightStatus(false, false, false)
|
||||
|
||||
fun addListener(
|
||||
tag: String,
|
||||
listener: LightAirconditionDoorCallback
|
||||
) {
|
||||
if (M_LISTENERS.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS[tag] = listener
|
||||
listener.onLightTop1Callback(lightStatus,true)
|
||||
listener.onLightTop2Callback(lightStatus,true)
|
||||
listener.onLightAtmosphereCallback(lightStatus,true)
|
||||
listener.onAirconditionStatusCallback(heaterStatue.isOpen,airconditionStatus,true)
|
||||
listener.onHeaterStatusCallback(airconditionStatus.isOpen,heaterStatue,true)
|
||||
}
|
||||
|
||||
fun removeListener(tag: String) {
|
||||
if (!M_LISTENERS.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS.remove(tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除监听
|
||||
* @param listener 要删除的监听对象
|
||||
*/
|
||||
fun removeListener(listener: LightAirconditionDoorCallback) {
|
||||
if (!M_LISTENERS.containsValue(listener)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS.forEach {
|
||||
if (it.value == listener) {
|
||||
M_LISTENERS.remove(it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRoboBusJinlvM1States(states: VehicleStateOuterClass.RoboBusJinlvM1State) {
|
||||
val airConditionerState = states.airConditionerState
|
||||
val heaterState = states.heaterState
|
||||
if (airConditionerState.isOn != airconditionStatus.isOpen ||
|
||||
airConditionerState.mode != airconditionStatus.pattert ||
|
||||
airConditionerState.temperature != airconditionStatus.temperature ||
|
||||
airConditionerState.windSpeed != airconditionStatus.windSpeed
|
||||
) {
|
||||
airconditionStatus.isOpen = airConditionerState.isOn
|
||||
airconditionStatus.pattert = airConditionerState.mode
|
||||
airconditionStatus.temperature = airConditionerState.temperature
|
||||
airconditionStatus.windSpeed = airConditionerState.windSpeed
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onAirconditionStatusCallback(heaterState.isOn,airconditionStatus,false)
|
||||
}
|
||||
}
|
||||
if (heaterState.isOn != heaterStatue.isOpen ||
|
||||
heaterState.windSpeed != heaterStatue.windSpeed
|
||||
) {
|
||||
heaterStatue.isOpen = heaterState.isOn
|
||||
heaterStatue.windSpeed = heaterState.windSpeed
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onHeaterStatusCallback(airConditionerState.isOn,heaterStatue,false)
|
||||
}
|
||||
}
|
||||
if (states.frontDoorState.isOn != doorStatus.isOpen) {
|
||||
doorStatus.isOpen = states.frontDoorState.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onDoorStatusCallback(doorStatus.isOpen,false)
|
||||
}
|
||||
}
|
||||
if(states.mainLamp1State.isOn != lightStatus.isOpenLight1){
|
||||
lightStatus.isOpenLight1 = states.mainLamp1State.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onLightTop1Callback(lightStatus,false)
|
||||
}
|
||||
}
|
||||
if(states.mainLamp2State.isOn != lightStatus.isOpenLight2){
|
||||
lightStatus.isOpenLight2 = states.mainLamp2State.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onLightTop2Callback(lightStatus,false)
|
||||
}
|
||||
}
|
||||
if(states.smallLampState.isOn != lightStatus.isOpenatmosphere){
|
||||
lightStatus.isOpenatmosphere = states.smallLampState.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onLightAtmosphereCallback(lightStatus,false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage
|
||||
|
||||
import chassis.Chassis
|
||||
import chassis.VehicleStateOuterClass
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisDoorStateListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisDoorStateListenerManager
|
||||
import com.mogo.eagle.core.function.call.base.CallerBase
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.och.common.module.manager.devicemanage.callback.DoorStateCallback
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.DoorPosition
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.DoorState
|
||||
|
||||
object TaxiDoorStateManager : IMoGoChassisDoorStateListener,
|
||||
CallerBase<DoorStateCallback>() {
|
||||
private val TAG = TaxiDoorStateManager::class.java.simpleName
|
||||
|
||||
@Volatile
|
||||
private var haveOpenDoor: Boolean? = null
|
||||
|
||||
init {
|
||||
CallerChassisDoorStateListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
override fun doSomeAfterAddListener(tag: String, listener: DoorStateCallback) {
|
||||
val doorList = CallerChassisDoorStateListenerManager.getDoorList()
|
||||
if(doorList is MutableList<VehicleStateOuterClass.DoorStateV2>){
|
||||
doSomeAfterAddListenerInner(doorList)
|
||||
doorList.forEach {
|
||||
onAutopilotSingleDoorState(it.number,it.status)
|
||||
}
|
||||
}else{
|
||||
doSomeAfterAddListenerInner(mutableListOf())
|
||||
}
|
||||
}
|
||||
|
||||
private fun doSomeAfterAddListenerInner(doorList: MutableList<VehicleStateOuterClass.DoorStateV2>){
|
||||
var have = false
|
||||
doorList.forEach {
|
||||
if (it.status == 1) {//0关闭 1开着 2未知
|
||||
have = true
|
||||
}
|
||||
}
|
||||
haveOpenDoor = have
|
||||
invokeOpenState(have)
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要用来判断是否有门开着
|
||||
*/
|
||||
override fun onAutopilotDoorState(doorList: MutableList<VehicleStateOuterClass.DoorStateV2>) {
|
||||
var have = false
|
||||
doorList.forEach {
|
||||
if (it.status == 1) {//0关闭 1开着 2未知
|
||||
have = true
|
||||
}
|
||||
}
|
||||
if (have != haveOpenDoor) {
|
||||
haveOpenDoor = have
|
||||
invokeOpenState(have)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断单个车门是否开着
|
||||
*/
|
||||
override fun onAutopilotSingleDoorState(num: Chassis.DoorNumber, status: Int) {
|
||||
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "门太变化:${num}--${status}")
|
||||
when (status) {
|
||||
0 -> { exchangeEnum(num, DoorState.CLOSE)}
|
||||
1 -> {exchangeEnum(num, DoorState.OPEN)}
|
||||
2 -> {exchangeEnum(num, DoorState.UNKNOWN)}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun exchangeEnum(num: Chassis.DoorNumber, state: DoorState) {
|
||||
when (num) {
|
||||
Chassis.DoorNumber.FRONT_LEFT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.FRONT_LEFT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.FRONT_RIGHT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.FRONT_RIGHT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.REAR_LEFT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.REAR_LEFT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.REAR_RIGHT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.REAR_RIGHT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.MIDDLE -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.MIDDLE, state)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param have true 有车门开着
|
||||
* false 没有车门开着(可能开着可能未知)
|
||||
*/
|
||||
@Synchronized
|
||||
private fun invokeOpenState(have: Boolean) {
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.hasOpenDoor(have)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param doorPosition 车门位置
|
||||
* @param doorState 车门状态
|
||||
*/
|
||||
@Synchronized
|
||||
private fun invokeSingleDoorOpenState(doorPosition: DoorPosition,doorState: DoorState) {
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.doorStateChangeCallback(doorPosition,doorState)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage.callback
|
||||
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.DoorPosition
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.DoorState
|
||||
|
||||
interface DoorStateCallback {
|
||||
|
||||
/**
|
||||
* @param have true 有车门开着
|
||||
* false 没有车门开着(可能开着可能未知)
|
||||
*/
|
||||
fun hasOpenDoor(have:Boolean){}
|
||||
|
||||
/**
|
||||
* @param position 车门位置
|
||||
* @param state 当前车门状态
|
||||
*/
|
||||
fun doorStateChangeCallback(position: DoorPosition,state: DoorState){}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage.callback
|
||||
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.AirconditionStatus
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.HeaterStatue
|
||||
import com.mogo.och.common.module.manager.devicemanage.data.LightStatus
|
||||
|
||||
interface LightAirconditionDoorCallback {
|
||||
|
||||
fun onAirconditionStatusCallback(heaterIsOpen: Boolean, airconditionStatus: AirconditionStatus,
|
||||
isFirst: Boolean) {
|
||||
}
|
||||
|
||||
fun onHeaterStatusCallback(airconditionIsOpen: Boolean, heaterStatue: HeaterStatue,
|
||||
isFirst: Boolean) {
|
||||
}
|
||||
|
||||
fun onDoorStatusCallback(isOpen: Boolean, isFirst: Boolean) {}
|
||||
|
||||
fun onLightTop1Callback(lightStatus: LightStatus, isFirst: Boolean) {
|
||||
}
|
||||
|
||||
fun onLightTop2Callback(lightStatus: LightStatus, isFirst: Boolean) {}
|
||||
|
||||
fun onLightAtmosphereCallback(lightStatus: LightStatus, isFirst: Boolean) {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage.data
|
||||
|
||||
data class AirconditionStatus(
|
||||
var isOpen: Boolean,
|
||||
var pattert: Int,
|
||||
var temperature: Int,
|
||||
var windSpeed: Int
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage.data
|
||||
|
||||
data class DoorStatus(var isOpen: Boolean)
|
||||
|
||||
|
||||
enum class DoorPosition {
|
||||
FRONT_LEFT, FRONT_RIGHT, REAR_LEFT, REAR_RIGHT, MIDDLE
|
||||
}
|
||||
|
||||
enum class DoorState {
|
||||
OPEN,CLOSE,UNKNOWN
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage.data
|
||||
|
||||
data class HeaterStatue(var isOpen: Boolean, var windSpeed: Int)
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mogo.och.common.module.manager.devicemanage.data
|
||||
|
||||
data class LightStatus(
|
||||
var isOpenLight1: Boolean,
|
||||
var isOpenLight2: Boolean,
|
||||
var isOpenatmosphere: Boolean
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.mogo.och.common.module.manager.distancemamager
|
||||
|
||||
data class DistanceDegree(var distance: Float, var degree: Double?, var isNext: Boolean?) :
|
||||
Comparable<DistanceDegree> {
|
||||
override fun compareTo(other: DistanceDegree): Int {
|
||||
// 对比距离
|
||||
if (distance == other.distance) {
|
||||
return 0;
|
||||
} else if (distance < other.distance) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
var next: DistanceDegree? = null
|
||||
|
||||
fun recycle() {
|
||||
synchronized(sPoolSync) {
|
||||
if (sPoolSize < MAX_POOL_SIZE) {
|
||||
next = sPool
|
||||
sPool = this
|
||||
sPoolSize++
|
||||
}
|
||||
//Logger.d("DistanceDegree","缓存对象个数${sPoolSize}个")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var sPoolSync = Any()
|
||||
private var sPool: DistanceDegree? = null
|
||||
private var sPoolSize = 0
|
||||
private var MAX_POOL_SIZE = 20
|
||||
|
||||
|
||||
fun obtain(distance: Float, degree: Double?, isNext: Boolean?): DistanceDegree {
|
||||
synchronized(sPoolSync) {
|
||||
if (sPool != null) {
|
||||
val m: DistanceDegree = sPool!!
|
||||
sPool = m.next
|
||||
m.next = null
|
||||
m.distance = distance
|
||||
m.degree = degree
|
||||
m.isNext = isNext
|
||||
sPoolSize--
|
||||
//Logger.d("DistanceDegree","取出一个对象个数${sPoolSize}个")
|
||||
return m
|
||||
}
|
||||
//Logger.d("DistanceDegree","创建一个对象 ${sPoolSize}个")
|
||||
return DistanceDegree(distance, degree, isNext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.mogo.och.common.module.manager.distancemamager
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
|
||||
interface IDistanceListener {
|
||||
/**
|
||||
* @param distance 距离终点坐标的距离(终点坐标设置错误可能为负值)
|
||||
*/
|
||||
fun distanceCallback(distance: Float){}
|
||||
|
||||
/**
|
||||
* 两个站点之间的距离
|
||||
*/
|
||||
fun stationDistanceCallback(stationDistance:Float){}
|
||||
}
|
||||
|
||||
interface ITrajectoryListener{
|
||||
/**
|
||||
* @param routeArrivied 已经走过的坐标
|
||||
* @param routeArriving 没有走过的坐标
|
||||
* @param location 车的坐标
|
||||
* @return
|
||||
*/
|
||||
fun trajectoryCallback(
|
||||
routeArrivied: MutableList<MogoLocation>,
|
||||
routeArriving: MutableList<MogoLocation>,
|
||||
location: MogoLocation
|
||||
)
|
||||
}
|
||||
|
||||
interface ITrajectoryWithStationListener{
|
||||
/**
|
||||
* @param routeArrivied 已经走过的坐标 第一个是开始站点坐标
|
||||
* @param routeArriving 没有走过的坐标 最后一个是结束站点坐标
|
||||
* @param location 车的坐标
|
||||
* @return
|
||||
*/
|
||||
fun trajectoryWithStationCallback(
|
||||
routeArrivied: MutableList<MogoLocation>,
|
||||
routeArriving: MutableList<MogoLocation>,
|
||||
location: MogoLocation
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.common.module.manager.distancemamager
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
|
||||
data class StationAndIndex(
|
||||
var stationPoint: MogoLocation?,// 站点坐标
|
||||
var index: Int?,// 坐标对应轨迹中最近的点
|
||||
var distance: Float?,//轨迹中最近的点
|
||||
var isNext:Boolean?,// 最近的点在轨迹中是在站点的下一个还是上一个
|
||||
var lineId:Long?,// 站点所属轨迹 todo 未来轨迹线路id和站点线路id 分别存储
|
||||
)
|
||||
@@ -0,0 +1,775 @@
|
||||
package com.mogo.och.common.module.manager.distancemamager
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.e
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_OCHCOMMON
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.core.utilcode.util.LocationUtils
|
||||
import com.mogo.och.common.module.biz.constant.OchCommonConst
|
||||
import com.mogo.och.common.module.manager.loopmanager.BizLoopManager
|
||||
import com.mogo.och.common.module.manager.loopmanager.LoopInfo
|
||||
import com.mogo.och.common.module.utils.CoordinateCalculateRouteUtil
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
|
||||
/**
|
||||
* 计算当前位置距离站点距离和走过的和未走过的轨迹点
|
||||
*/
|
||||
object TrajectoryAndDistanceManager : IMoGoPlanningRottingListener {
|
||||
|
||||
private val distanceListeners: ConcurrentHashMap<String, IDistanceListener> =
|
||||
ConcurrentHashMap()
|
||||
private val trajectoryListeners: ConcurrentHashMap<String, ITrajectoryListener> =
|
||||
ConcurrentHashMap()
|
||||
private val trajectoryWithStationListeners: ConcurrentHashMap<String, ITrajectoryWithStationListener> =
|
||||
ConcurrentHashMap()
|
||||
|
||||
private const val TAG = "DistanceManager"
|
||||
private const val DISTANCE = "BusPassengerModelDistance"
|
||||
|
||||
|
||||
fun addDistanceListener(tag: String, listener: IDistanceListener) {
|
||||
if (distanceListeners.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
distanceListeners[tag] = listener
|
||||
}
|
||||
|
||||
fun addTrajectoryListener(tag: String, listener: ITrajectoryListener) {
|
||||
if (trajectoryListeners.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
trajectoryListeners[tag] = listener
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun addTrajectoryWithStationListener(tag: String, listener: ITrajectoryWithStationListener) {
|
||||
if (trajectoryWithStationListeners.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
trajectoryWithStationListeners[tag] = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除监听
|
||||
* @param tag 标记,用来注销监听使用
|
||||
*/
|
||||
fun removeListener(tag: String) {
|
||||
distanceListeners.remove(tag)
|
||||
trajectoryListeners.remove(tag)
|
||||
trajectoryWithStationListeners.remove(tag)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 所有轨迹点
|
||||
*/
|
||||
@Volatile
|
||||
private var mRoutePoints: MutableList<MogoLocation>? = ArrayList()
|
||||
|
||||
/**
|
||||
* 0-1 1-2 2-3 各个轨迹点的距离
|
||||
*/
|
||||
@Volatile
|
||||
private var mRoutePointsDistance: MutableList<Float>? = ArrayList()
|
||||
|
||||
/**
|
||||
* 所有轨迹点距离的和
|
||||
*/
|
||||
@Volatile
|
||||
private var maxDistanceAllPoint: Double = 0.0
|
||||
|
||||
/**
|
||||
* 线路Id
|
||||
*/
|
||||
@Volatile
|
||||
private var lineId: Long? = null
|
||||
|
||||
/**
|
||||
* 结束站点
|
||||
*/
|
||||
@Volatile
|
||||
private var endStationInfo: StationAndIndex = StationAndIndex(null, null, null, null, null)
|
||||
|
||||
/**
|
||||
* 开始站点
|
||||
*/
|
||||
@Volatile
|
||||
private var startStationInfo: StationAndIndex = StationAndIndex(null, null, null, null, null)
|
||||
|
||||
/**
|
||||
* startStationInfo endStationInfo 站点之间的距离
|
||||
*/
|
||||
private val stationDistance: ConcurrentHashMap<String, Float> = ConcurrentHashMap()
|
||||
|
||||
/**
|
||||
* 上一次(上一个tick)计算最近点的缓存
|
||||
*/
|
||||
private var preCarLocationIndexInTrajectory = 0
|
||||
|
||||
init {
|
||||
CallerPlanningRottingListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
override fun onAutopilotRotting(globalPathResp: MessagePad.GlobalPathResp?) {
|
||||
d(M_OCHCOMMON + TAG, "onAutopilotRotting: 收到轨迹")
|
||||
globalPathResp?.wayPointsList?.let {
|
||||
if (it.size > 0) {
|
||||
d(
|
||||
M_OCHCOMMON + TAG,
|
||||
"收到轨迹:轨迹个数${it.size}第一个点${it[0]}最后一个点:${it.last()} 轨迹id:${globalPathResp.lineId}"
|
||||
)
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (globalPathResp.lineId != null) {// 适配低版本不传递lineId
|
||||
if (globalPathResp.lineId == lineId && !mRoutePoints.isNullOrEmpty()) {
|
||||
d(M_OCHCOMMON + TAG, "重复轨迹")
|
||||
startCalculateDistanceLoop()
|
||||
return
|
||||
}else{
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
}
|
||||
this.lineId = globalPathResp.lineId
|
||||
}
|
||||
endCalculateDistanceLoop()
|
||||
updateRoutePoints(it)
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
startCalculateDistanceLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateRoutePoints(routePoints: List<MessagePad.Location>?) {
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
val latLngModels = CoordinateCalculateRouteUtil
|
||||
.coordinateConverterWgsToGcjLocations(AbsMogoApplication.getApp(), routePoints!!)
|
||||
mRoutePoints = latLngModels
|
||||
TrajectoryCache.writeLastTrajectory2jsonFile(latLngModels, lineId.toString())
|
||||
|
||||
mRoutePointsDistance = ArrayList()
|
||||
maxDistanceAllPoint = 0.0
|
||||
mRoutePoints?.forEachIndexed { index, current ->
|
||||
if (mRoutePoints!!.last() != current) {
|
||||
val next = mRoutePoints!![index + 1]
|
||||
val distanceItem = CoordinateUtils.calculateLineDistance(
|
||||
current.longitude,
|
||||
current.latitude,
|
||||
next.longitude,
|
||||
next.latitude
|
||||
)
|
||||
mRoutePointsDistance?.add(distanceItem)
|
||||
maxDistanceAllPoint += distanceItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置或清理站点坐标
|
||||
*/
|
||||
fun setStationPoint(
|
||||
startStationInfo: MogoLocation?,
|
||||
endStationInfo: MogoLocation?,
|
||||
lineId: Long?
|
||||
) {
|
||||
d(
|
||||
M_OCHCOMMON + TAG,
|
||||
"线路id:${lineId}设置站点:开始站点${startStationInfo}、结束站点:${endStationInfo}"
|
||||
)
|
||||
if (startStationInfo == null || endStationInfo == null || lineId == -1L) {
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.endStationInfo.lineId = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
this.startStationInfo.lineId = null
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
endCalculateDistanceLoop()
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
TrajectoryCache.deleteCatcheFile()
|
||||
this.endStationInfo.stationPoint = null
|
||||
this.startStationInfo.stationPoint = null
|
||||
this.lineId = null
|
||||
stationDistance.clear()
|
||||
} else {
|
||||
if (isSameStation(this.startStationInfo.stationPoint, startStationInfo) &&
|
||||
isSameStation(this.endStationInfo.stationPoint, endStationInfo)
|
||||
) {
|
||||
if (this.lineId != lineId) {
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.endStationInfo.lineId = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
this.startStationInfo.lineId = null
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
TrajectoryCache.deleteCatcheFile()
|
||||
stationDistance.clear()
|
||||
}
|
||||
} else {
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.endStationInfo.lineId = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
this.startStationInfo.lineId = null
|
||||
if (this.lineId == 0L || this.lineId == null) {
|
||||
// 兼容老MAP 不返回轨迹id lineID
|
||||
} else {
|
||||
if (this.lineId != lineId) {// bus 切换站点不会切线路
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
TrajectoryCache.deleteCatcheFile()
|
||||
}
|
||||
}
|
||||
stationDistance.clear()
|
||||
}
|
||||
this.endStationInfo.stationPoint = endStationInfo
|
||||
this.startStationInfo.stationPoint = startStationInfo
|
||||
this.lineId = lineId
|
||||
startCalculateDistanceLoop()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSameStation(stationOne: MogoLocation?, stationTwo: MogoLocation?): Boolean {
|
||||
if (stationOne == null || stationTwo == null) {
|
||||
return false
|
||||
}
|
||||
if (stationOne.longitude == stationTwo.longitude && stationOne.latitude == stationTwo.latitude) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据两点距离和轨迹距离来计算真实距离
|
||||
*/
|
||||
private fun calculateDistance() {
|
||||
//mLocation gcj坐标
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02().let {
|
||||
if (mRoutePoints.isNullOrEmpty() || endStationInfo.stationPoint == null) {
|
||||
d(M_OCHCOMMON + TAG, "没有轨迹或站点坐标停止计算")
|
||||
//结束距离计算
|
||||
endCalculateDistanceLoop()
|
||||
return
|
||||
}
|
||||
if (it.latitude == 0.0 && it.longitude == 0.0) {
|
||||
return
|
||||
}
|
||||
calculateRouteSumLength(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停路距计算
|
||||
*/
|
||||
fun suspendCalculate() {
|
||||
endCalculateDistanceLoop()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun reStartCalculate() {
|
||||
startCalculateDistanceLoop()
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动路距计算
|
||||
*/
|
||||
private fun startCalculateDistanceLoop() {
|
||||
BizLoopManager.setLoopFunction(
|
||||
DISTANCE,
|
||||
LoopInfo(
|
||||
1,
|
||||
::calculateDistance,
|
||||
scheduler = Schedulers.computation()
|
||||
)
|
||||
)
|
||||
d(M_OCHCOMMON + TAG, "开始路距计算")
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束启动路距计算
|
||||
*/
|
||||
private fun endCalculateDistanceLoop() {
|
||||
BizLoopManager.removeLoopFunction(DISTANCE)
|
||||
d(M_OCHCOMMON + TAG, "结束路距计算")
|
||||
}
|
||||
|
||||
|
||||
@Synchronized
|
||||
fun calculateRouteSumLength(
|
||||
location: MogoLocation,
|
||||
) {
|
||||
val autoPilotState = CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo().state
|
||||
val locationInfo =
|
||||
"自动驾驶状态:$autoPilotState line信息:${lineId}定位信息:${location.latitude},${location.longitude},${location.heading} 当前速度:${location.gnssSpeed}"
|
||||
if (mRoutePoints.isNullOrEmpty()) return
|
||||
// 计算起始站点在轨迹中的信息 这个是一个常量
|
||||
if (startStationInfo.stationPoint != null
|
||||
&& startStationInfo.isNext == null
|
||||
&& startStationInfo.index == null
|
||||
&& startStationInfo.distance == null
|
||||
) {
|
||||
//要前往的站在轨迹中对应的点的信息
|
||||
val startStationInfo = CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory,
|
||||
mRoutePoints!!.size,
|
||||
mRoutePoints!!,
|
||||
startStationInfo.stationPoint!!,
|
||||
1,
|
||||
useHeading = false
|
||||
)
|
||||
this.startStationInfo.isNext = startStationInfo.second
|
||||
this.startStationInfo.index = startStationInfo.first
|
||||
this.startStationInfo.distance = startStationInfo.third
|
||||
preCarLocationIndexInTrajectory = startStationInfo.first
|
||||
val calculateData =
|
||||
"距离起始站点最近的点:${startStationInfo.first} 点在站的后面:${startStationInfo.second} 距离点的距离:${startStationInfo.third}"
|
||||
writeLog(calculateData, locationInfo)
|
||||
}
|
||||
|
||||
// 计算结束站点在轨迹中的信息 这个是一个常量可以缓存
|
||||
if (endStationInfo.stationPoint != null
|
||||
&& endStationInfo.isNext == null
|
||||
&& endStationInfo.index == null
|
||||
&& endStationInfo.distance == null
|
||||
) {
|
||||
//要前往的站在轨迹中对应的点
|
||||
val endStationInfo = CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory,
|
||||
mRoutePoints!!.size,
|
||||
mRoutePoints!!,
|
||||
endStationInfo.stationPoint!!,
|
||||
3,
|
||||
useHeading = false
|
||||
)
|
||||
this.endStationInfo.isNext = endStationInfo.second
|
||||
this.endStationInfo.index = endStationInfo.first
|
||||
this.endStationInfo.distance = endStationInfo.third
|
||||
val calculateData =
|
||||
"距离结束站点最近的点:${endStationInfo.first} 点在站的后面:${endStationInfo.second} 距离点的距离:${endStationInfo.third}"
|
||||
writeLog(calculateData, locationInfo)
|
||||
}
|
||||
|
||||
try {
|
||||
if (endStationInfo.stationPoint != null
|
||||
&& endStationInfo.isNext != null
|
||||
&& endStationInfo.index != null
|
||||
&& endStationInfo.distance != null
|
||||
&& startStationInfo.stationPoint != null
|
||||
&& startStationInfo.isNext != null
|
||||
&& startStationInfo.index != null
|
||||
&& startStationInfo.distance != null
|
||||
) {
|
||||
calculateStationDistance()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "计算两个站点间的距离")
|
||||
}
|
||||
|
||||
val carLocationInfo: Triple<Int, Boolean?, Float> = if (endStationInfo.isNext == true) {
|
||||
// 计算车的位置在轨迹中的信息 这个是一个变量可以缓存
|
||||
CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory, endStationInfo.index!!, mRoutePoints!!, location, 2
|
||||
)
|
||||
} else {
|
||||
CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory,
|
||||
endStationInfo.index!! + 1,
|
||||
mRoutePoints!!,
|
||||
location,
|
||||
2
|
||||
)
|
||||
}
|
||||
val calculateData =
|
||||
"距离轨迹点最近的点:${carLocationInfo.first} 点在站的后面:${carLocationInfo.second} 距离点的距离:${carLocationInfo.third}"
|
||||
writeLog(calculateData, locationInfo)
|
||||
if (carLocationInfo.second == null || carLocationInfo.third > 1_000) {
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
return
|
||||
}
|
||||
|
||||
var maxDisatance = 0.0f
|
||||
if (carLocationInfo.second == true) {
|
||||
if (carLocationInfo.first > 0) {
|
||||
maxDisatance = mRoutePointsDistance?.get(carLocationInfo.first - 1) ?: 0f
|
||||
}
|
||||
} else {
|
||||
maxDisatance = mRoutePointsDistance?.get(carLocationInfo.first) ?: 0f
|
||||
}
|
||||
if (carLocationInfo.third > maxDisatance) {
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
writeLog("到点的距离${carLocationInfo.third},最大距离${maxDisatance}", locationInfo)
|
||||
return
|
||||
}
|
||||
|
||||
preCarLocationIndexInTrajectory = carLocationInfo.first
|
||||
|
||||
// 距离回调
|
||||
try {
|
||||
if (distanceListeners.size > 0) {
|
||||
invokeDistance(carLocationInfo, location, locationInfo)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "距离计算错误")
|
||||
}
|
||||
// 不带站点轨迹回调
|
||||
try {
|
||||
if (trajectoryListeners.size > 0) {
|
||||
invokeTrajectory(carLocationInfo, location)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "轨迹线(轨迹两头)计算错误")
|
||||
}
|
||||
|
||||
// 只展示站点之间轨迹
|
||||
try {
|
||||
if (trajectoryWithStationListeners.size > 0) {
|
||||
invokeTrajectoryWithStation(carLocationInfo, location)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "轨迹线(站点两头)计算错误")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算站点间距离
|
||||
*/
|
||||
private fun calculateStationDistance() {
|
||||
var lastSumLength: Float
|
||||
val key = getKey()
|
||||
if (stationDistance[key] != null) {
|
||||
return
|
||||
}
|
||||
|
||||
val stationIndex = endStationInfo.index ?: 0
|
||||
if (startStationInfo.index!! < stationIndex - 1) {
|
||||
// subList 是[) 需要的是[]
|
||||
val subList = mRoutePoints!!.subList(startStationInfo.index!!, stationIndex + 1)
|
||||
// 轨迹点所有的距离
|
||||
lastSumLength = CoordinateCalculateRouteUtil.calculateRouteSumLength(subList)
|
||||
val stationDistance = endStationInfo.distance ?: 0f
|
||||
if (endStationInfo.isNext == true) {// isNext = true
|
||||
lastSumLength -= stationDistance
|
||||
} else {// isNext = false
|
||||
lastSumLength += stationDistance
|
||||
}
|
||||
if (startStationInfo.isNext == true) {// 是否是下一个 true 下一个
|
||||
lastSumLength += startStationInfo.distance!!
|
||||
} else {
|
||||
lastSumLength -= startStationInfo.distance!!
|
||||
}
|
||||
} else {
|
||||
val lastPoints = endStationInfo.stationPoint
|
||||
lastSumLength = CoordinateUtils.calculateLineDistance(
|
||||
startStationInfo.stationPoint!!.longitude, startStationInfo.stationPoint!!.latitude,
|
||||
lastPoints!!.longitude, lastPoints.latitude
|
||||
)
|
||||
}
|
||||
d(M_OCHCOMMON + TAG, "两站点距离:$lastSumLength")
|
||||
stationDistance[key] = lastSumLength
|
||||
|
||||
if (distanceListeners.size > 0) {
|
||||
distanceListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.stationDistanceCallback(lastSumLength)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKey(): String {
|
||||
return "${startStationInfo.stationPoint!!.longitude}${startStationInfo.stationPoint!!.latitude}${endStationInfo.stationPoint!!.longitude}${endStationInfo.stationPoint!!.latitude}"
|
||||
}
|
||||
|
||||
/**
|
||||
* 到结束站点的距离 站点设置错误可能为负值
|
||||
*/
|
||||
private fun invokeDistance(
|
||||
carLocationInfo: Triple<Int, Boolean?, Float>,
|
||||
location: MogoLocation,
|
||||
locationInfo: String
|
||||
) {
|
||||
var lastSumLength: Float
|
||||
|
||||
val stationIndex = endStationInfo.index ?: 0
|
||||
if (carLocationInfo.first < stationIndex - 1) {
|
||||
// subList 是[) 需要的是[]
|
||||
val subList = mRoutePoints!!.subList(carLocationInfo.first, stationIndex + 1)
|
||||
// 轨迹点所有的距离
|
||||
lastSumLength = CoordinateCalculateRouteUtil.calculateRouteSumLength(subList)
|
||||
val stationDistance = endStationInfo.distance ?: 0f
|
||||
if (endStationInfo.isNext == true) {// isNext = true
|
||||
lastSumLength -= stationDistance
|
||||
} else {// isNext = false
|
||||
lastSumLength += stationDistance
|
||||
}
|
||||
if (carLocationInfo.second == true) {// 是否是下一个 true 下一个
|
||||
lastSumLength += carLocationInfo.third
|
||||
} else {
|
||||
lastSumLength -= carLocationInfo.third
|
||||
}
|
||||
} else {
|
||||
val lastPoints = endStationInfo.stationPoint
|
||||
lastSumLength = CoordinateUtils.calculateLineDistance(
|
||||
lastPoints!!.longitude, lastPoints.latitude,
|
||||
location.longitude, location.latitude
|
||||
)
|
||||
}
|
||||
d(M_OCHCOMMON + TAG, "距离终点:$lastSumLength")
|
||||
if (lastSumLength > maxDistanceAllPoint) {
|
||||
// 大于最大值需要需要删除此次计算
|
||||
writeLog("距离终点:$lastSumLength", locationInfo)
|
||||
return
|
||||
}
|
||||
if (distanceListeners.size > 0) {
|
||||
distanceListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.distanceCallback(lastSumLength)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算站点之间的轨迹(从轨迹起点算起到轨迹结束点结束)
|
||||
* routeArrivied 已经走过的轨迹点
|
||||
* routeArriving 还没有走过的轨迹
|
||||
* location 车的轨迹点
|
||||
*/
|
||||
private fun invokeTrajectory(
|
||||
carLocationInfo: Triple<Int, Boolean?, Float>,
|
||||
location: MogoLocation
|
||||
) {
|
||||
if (mRoutePoints.isNullOrEmpty()) return
|
||||
val routeArrivied = mutableListOf<MogoLocation>()
|
||||
val routeArriving = mutableListOf<MogoLocation>()
|
||||
if (carLocationInfo.second == true) {// isNext = true
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(0, carLocationInfo.first))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(carLocationInfo.first, mRoutePoints!!.size))
|
||||
} else {// isNext = false
|
||||
val indexNext = carLocationInfo.first + 1
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(0, indexNext))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(indexNext, mRoutePoints!!.size))
|
||||
}
|
||||
if (trajectoryListeners.size > 0) {
|
||||
trajectoryListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.trajectoryCallback(routeArrivied, routeArriving, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算站点之间的轨迹(从开始站点算起到结束站点)
|
||||
* routeArrivied 已经走过的轨迹点
|
||||
* routeArriving 还没有走过的轨迹
|
||||
* location 车的轨迹点
|
||||
*/
|
||||
private fun invokeTrajectoryWithStation(
|
||||
carLocationInfo: Triple<Int, Boolean?, Float>,
|
||||
location: MogoLocation
|
||||
) {
|
||||
if (mRoutePoints.isNullOrEmpty()) return
|
||||
val routeArrivied = mutableListOf<MogoLocation>()
|
||||
val routeArriving = mutableListOf<MogoLocation>()
|
||||
var fromCut = 0
|
||||
var endCut = mRoutePoints!!.size
|
||||
if (startStationInfo.stationPoint != null
|
||||
&& startStationInfo.isNext != null
|
||||
&& startStationInfo.index != null
|
||||
&& startStationInfo.distance != null
|
||||
) {
|
||||
if (startStationInfo.isNext == true) {
|
||||
fromCut = startStationInfo.index!!
|
||||
} else {
|
||||
fromCut = startStationInfo.index!! + 1
|
||||
}
|
||||
}
|
||||
|
||||
if (endStationInfo.stationPoint != null
|
||||
&& endStationInfo.isNext != null
|
||||
&& endStationInfo.index != null
|
||||
&& endStationInfo.distance != null
|
||||
) {
|
||||
if (endStationInfo.isNext == true) {
|
||||
endCut = endStationInfo.index!!
|
||||
} else {
|
||||
endCut = endStationInfo.index!! + 1
|
||||
}
|
||||
}
|
||||
d(M_OCHCOMMON + TAG, "根据站点切个:第一个点:$fromCut 最后一个点$endCut")
|
||||
if (carLocationInfo.second == true) {// isNext = true
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(fromCut, carLocationInfo.first))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(carLocationInfo.first, endCut))
|
||||
} else {// isNext = false
|
||||
val indexNext = carLocationInfo.first + 1
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(fromCut, indexNext))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(indexNext, endCut))
|
||||
}
|
||||
|
||||
routeArrivied.add(0, startStationInfo.stationPoint!!)
|
||||
routeArriving.add(endStationInfo.stationPoint!!)
|
||||
if (trajectoryWithStationListeners.size > 0) {
|
||||
trajectoryWithStationListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.trajectoryWithStationCallback(routeArrivied, routeArriving, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @ChainLog(
|
||||
// linkChainLog = ChainConstant.CHAIN_TYPE_OCH,
|
||||
// linkCode = ChainConstant.CHAIN_SOURCE_OCH,
|
||||
// nodeAliasCode = ChainConstant.CHAIN_CODE_OCH_COMMON_DISTANCE,
|
||||
// paramIndexes = [0,1]
|
||||
// )
|
||||
private fun writeLog(carLocationInfo: String, location: String) {
|
||||
d(M_OCHCOMMON + TAG, carLocationInfo)
|
||||
d(M_OCHCOMMON + TAG, location)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回空为可启动自驾
|
||||
* 返回其他不可启动自驾 返回为原因
|
||||
*/
|
||||
fun canStartAutopilot(lineId: Long?): String {
|
||||
if (lineId == null) {
|
||||
return "请确认线路ID"
|
||||
}
|
||||
|
||||
try {
|
||||
if (mRoutePoints.isNullOrEmpty()) {
|
||||
// 判断距离起始站的距离
|
||||
// 没有收到过轨迹
|
||||
// 收到过轨迹 且底盘没有在自动驾驶中(没办法申请轨迹) 自驾中重启底盘的形式
|
||||
val redCatche = TrajectoryCache.redCatche(lineId.toString())
|
||||
return if (redCatche.isNullOrEmpty()) {
|
||||
distanceWithStartStation()
|
||||
} else {
|
||||
val currentPoint =
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
distanceWithTrajectory(redCatche,currentPoint)
|
||||
}
|
||||
|
||||
} else {
|
||||
return if (this.lineId == 0L || this.lineId == null) {
|
||||
val currentPoint =
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
distanceWithTrajectory(mRoutePoints!!,currentPoint)
|
||||
} else {
|
||||
if (lineId != this.lineId) {
|
||||
// 判断距离起始站的距离
|
||||
distanceWithStartStation()
|
||||
} else {
|
||||
val currentPoint =
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
distanceWithTrajectory(mRoutePoints!!,currentPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 距离站点的距离
|
||||
*/
|
||||
private fun distanceWithStartStation(): String {
|
||||
if (startStationInfo.stationPoint == null) {
|
||||
return "请选择起始结束站点"
|
||||
}
|
||||
val currentPoint = CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
val distance = CoordinateUtils.calculateLineDistance(
|
||||
currentPoint.longitude,
|
||||
currentPoint.latitude,
|
||||
startStationInfo.stationPoint!!.longitude,
|
||||
startStationInfo.stationPoint!!.latitude
|
||||
)
|
||||
return if (distance <= OchCommonConst.AUTOMATIC_PLANNING_MAX_DISTANCE) {
|
||||
""
|
||||
} else {
|
||||
"距离起始站点过远:${distance}米"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 距离轨迹的距离
|
||||
*/
|
||||
fun distanceWithTrajectory(redCatche: MutableList<MogoLocation>,currentPoint:MogoLocation): String {
|
||||
// 判断距离轨迹的距离
|
||||
val carLocationInfo: Triple<Int, Boolean?, Float> =
|
||||
CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
0,
|
||||
redCatche.size - 1,
|
||||
redCatche,
|
||||
currentPoint,
|
||||
2
|
||||
)
|
||||
if (carLocationInfo.third <= OchCommonConst.AUTOMATIC_PLANNING_MAX_DISTANCE) {
|
||||
return ""// 可以启动自驾
|
||||
} else {
|
||||
// 判断距离线段的距离 垂足的距离
|
||||
val nextPoint: MogoLocation
|
||||
val prePoint: MogoLocation
|
||||
// isNext true 最近的点是在下一个
|
||||
// isNext false 最近的点是在上一个
|
||||
if (carLocationInfo.second == true) {
|
||||
if (carLocationInfo.first > 0) {
|
||||
nextPoint = redCatche[carLocationInfo.first]
|
||||
prePoint = redCatche[carLocationInfo.first - 1]
|
||||
} else {
|
||||
// 距离第一个点大于15m 过远
|
||||
return "距离轨迹线超过15m:${carLocationInfo.first}米,无法启动自驾"
|
||||
}
|
||||
} else {
|
||||
if (carLocationInfo.first + 1 < redCatche.size) {
|
||||
nextPoint = redCatche[carLocationInfo.first + 1]
|
||||
prePoint = redCatche[carLocationInfo.first]
|
||||
} else {
|
||||
nextPoint = redCatche[carLocationInfo.first]
|
||||
prePoint = redCatche[carLocationInfo.first - 1]
|
||||
}
|
||||
}
|
||||
val pointToLine = LocationUtils.pointToLine(
|
||||
prePoint.longitude,
|
||||
prePoint.latitude,
|
||||
nextPoint.longitude,
|
||||
nextPoint.latitude,
|
||||
currentPoint.longitude,
|
||||
currentPoint.latitude
|
||||
)
|
||||
return if (pointToLine <= OchCommonConst.AUTOMATIC_PLANNING_MAX_DISTANCE) {
|
||||
""
|
||||
} else {
|
||||
"距离轨迹线超过15m,无法启动自驾"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mogo.och.common.module.manager.distancemamager
|
||||
|
||||
import com.elegant.network.utils.GsonUtil
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_OCHCOMMON
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
|
||||
object TrajectoryCache {
|
||||
|
||||
private const val TAG = "TrajectoryCache"
|
||||
|
||||
private val dir = "${AbsMogoApplication.getApp().cacheDir}/trajectory/"
|
||||
|
||||
fun writeLastTrajectory2jsonFile(latLngModels: MutableList<MogoLocation>,name:String) {
|
||||
val jsonFromObject = GsonUtil.jsonFromObject(latLngModels)
|
||||
try {
|
||||
val path = File(dir)
|
||||
if(!path.exists()){
|
||||
path.mkdir()
|
||||
}else {
|
||||
path.deleteRecursively()
|
||||
CallerLogger.d(M_OCHCOMMON + TAG,"删除缓存")
|
||||
path.mkdir()
|
||||
}
|
||||
val writer = FileWriter("${path.path}/${name}")
|
||||
writer.write(jsonFromObject)
|
||||
writer.close()
|
||||
CallerLogger.d(M_OCHCOMMON + TAG,"写入缓存")
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCatcheFile(){
|
||||
try {
|
||||
val path = File(dir)
|
||||
if(path.exists()){
|
||||
path.deleteRecursively()
|
||||
CallerLogger.d(M_OCHCOMMON + TAG,"删除缓存")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun redCatche(name: String): MutableList<MogoLocation>? {
|
||||
try {
|
||||
val path = File(dir)
|
||||
if(!path.exists()){
|
||||
return null
|
||||
}
|
||||
val fileReader = FileReader("${path.path}/${name}")
|
||||
val readText = fileReader.readText()
|
||||
fileReader.close()
|
||||
return GsonUtil.arrayFromJson(readText, MogoLocation::class.java)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.mogo.och.common.module.manager.lightmanager
|
||||
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLamplightListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLamplightListenerManager
|
||||
|
||||
object BreakLightManager : IMoGoChassisLamplightListener {
|
||||
private const val TAG = "BreakLightManager"
|
||||
init {
|
||||
CallerChassisLamplightListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
// 刹车灯
|
||||
override fun onAutopilotBrakeLightData(brakeLight: Boolean) {
|
||||
super.onAutopilotBrakeLightData(brakeLight)
|
||||
}
|
||||
|
||||
enum class BreakLightStatus{
|
||||
BREAK_LIGHT,
|
||||
BREAK_NONE,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.mogo.och.common.module.manager.lightmanager
|
||||
|
||||
import chassis.Chassis
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLamplightListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLamplightListenerManager
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
object TurnLightManager : IMoGoChassisLamplightListener {
|
||||
private const val TAG = "TurnLightManager"
|
||||
|
||||
private val lightStatusChange: ConcurrentHashMap<String, TurnLightListener> =
|
||||
ConcurrentHashMap()
|
||||
|
||||
private var turnLightStatus:TurnLightStatus by Delegates.observable(TurnLightStatus.TURN_LIGHT_NONE) { _, oldValue, newValue ->
|
||||
if (oldValue != newValue) {
|
||||
if(lightStatusChange.size>0){
|
||||
lightStatusChange.forEach {
|
||||
it.value.statusChange(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
CallerChassisLamplightListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
fun addTurnLightStatusChangeListener(tag: String, listener: TurnLightListener) {
|
||||
if (lightStatusChange.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
lightStatusChange[tag] = listener
|
||||
listener.statusChange(turnLightStatus)
|
||||
}
|
||||
|
||||
|
||||
// 转向灯
|
||||
override fun onAutopilotLightSwitchData(lightSwitch: Chassis.LightSwitch?) {
|
||||
super.onAutopilotLightSwitchData(lightSwitch)
|
||||
lightSwitch?.let {
|
||||
when (it.number) {
|
||||
Chassis.LightSwitch.LIGHT_LEFT_VALUE -> {
|
||||
turnLightStatus = TurnLightStatus.TURN_LIGHT_LEFT
|
||||
}
|
||||
Chassis.LightSwitch.LIGHT_RIGHT_VALUE -> {
|
||||
turnLightStatus = TurnLightStatus.TURN_LIGHT_RIGHT
|
||||
}
|
||||
Chassis.LightSwitch.LIGHT_NONE_VALUE -> {
|
||||
turnLightStatus = TurnLightStatus.TURN_LIGHT_NONE
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface TurnLightListener{
|
||||
fun statusChange(newStatus: TurnLightStatus)
|
||||
}
|
||||
|
||||
enum class TurnLightStatus{
|
||||
TURN_LIGHT_LEFT,
|
||||
TURN_LIGHT_RIGHT,
|
||||
TURN_LIGHT_NONE,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.mogo.och.common.module.manager.loopmanager
|
||||
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS_P
|
||||
import com.mogo.och.common.module.utils.RxUtils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Created on 2021/11/22
|
||||
*
|
||||
* 管理轮询逻辑(订单轮询、新单轮询、新单抢单结果轮询等等)
|
||||
*/
|
||||
object BizLoopManager {
|
||||
|
||||
private val TAG = "BusPassengerModelLoopManager"
|
||||
|
||||
private val mControllerStatusCallbackMap = ConcurrentHashMap<String, LoopInfo>()
|
||||
|
||||
const val LOOP_LINE_2S = 2 * 1000L
|
||||
const val LOOP_LINE_1S = 1 * 1000L
|
||||
const val LOOP_DELAY = 100L
|
||||
|
||||
fun setLoopFunction(tag: String, function: LoopInfo) {
|
||||
if (tag.isBlank()) return
|
||||
if(mControllerStatusCallbackMap.contains(tag)){
|
||||
return
|
||||
}
|
||||
mControllerStatusCallbackMap[tag] = function
|
||||
if(function.immediately){
|
||||
function.function.invoke()
|
||||
}
|
||||
if (mControllerStatusCallbackMap.size > 0) {
|
||||
startLineLoop()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeLoopFunction(tag: String) {
|
||||
if (tag.isBlank()) return
|
||||
mControllerStatusCallbackMap.remove(tag)
|
||||
if (mControllerStatusCallbackMap.size == 0) {
|
||||
stopLineLoop()
|
||||
}
|
||||
}
|
||||
|
||||
// 订单 轮训
|
||||
// 订单时间轮训
|
||||
// 车辆状态轮训
|
||||
// 计算距离轮训
|
||||
private var mQueryLineDisposable: Disposable? = null
|
||||
|
||||
private fun startLineLoop() {
|
||||
if (mQueryLineDisposable != null && !mQueryLineDisposable!!.isDisposed) {
|
||||
return
|
||||
}
|
||||
CallerLogger.i(M_BUS_P + TAG, "startQueryDriverLineLoop()")
|
||||
mQueryLineDisposable = Observable.interval(LOOP_DELAY, LOOP_LINE_1S, TimeUnit.MILLISECONDS)
|
||||
.map { aLong: Long -> aLong + 1 }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe { aLong: Long? ->
|
||||
mControllerStatusCallbackMap.forEach { (tag, loopInfo) ->
|
||||
aLong?.let {
|
||||
if (it % loopInfo.interval == 0L) {
|
||||
try {
|
||||
if(loopInfo.scheduler!=null) {
|
||||
Observable.just(tag).observeOn(loopInfo.scheduler)
|
||||
.subscribe(object :Observer<String>{
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onError(e: Throwable) {}
|
||||
override fun onComplete() {
|
||||
try {
|
||||
loopInfo.function.invoke()
|
||||
}catch (e:Throwable){
|
||||
CallerLogger.e(TAG,"$tag:--$e")
|
||||
}
|
||||
CallerLogger.d(TAG, "${aLong}正在执行方法${tag}_${Thread.currentThread().name}")
|
||||
}
|
||||
override fun onNext(t: String) {}
|
||||
})
|
||||
}else{
|
||||
loopInfo.function.invoke()
|
||||
CallerLogger.d(TAG, "${aLong}正在执行方法${tag}_${Thread.currentThread().name}")
|
||||
}
|
||||
}catch (e:Throwable){
|
||||
e.printStackTrace()
|
||||
CallerLogger.e(TAG,"$tag:--$e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopLineLoop() {
|
||||
CallerLogger.i(M_BUS_P + TAG, "stopQueryDriverLineLoop()")
|
||||
RxUtils.disposeSubscribe(mQueryLineDisposable)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.common.module.manager.loopmanager
|
||||
|
||||
import io.reactivex.Scheduler
|
||||
|
||||
/**
|
||||
* interval 轮训间隔
|
||||
* function 轮询执行的方法
|
||||
* immediately 是否立刻执行
|
||||
* scheduler 轮训执行的线程
|
||||
*/
|
||||
data class LoopInfo(val interval:Long,val function: () -> Unit,val immediately:Boolean=false,var scheduler: Scheduler? = null)
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.mogo.och.common.module.manager.orderlogmanager
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.mogo.commons.utils.MogoAnalyticUtils
|
||||
import com.mogo.eagle.core.data.app.AppConfigInfo
|
||||
import com.mogo.eagle.core.data.deva.chain.ChainConstant
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.DateTimeUtils
|
||||
import com.zhjt.service.chain.ChainLog
|
||||
|
||||
object OchChainLogManager {
|
||||
|
||||
private val TAG = OchChainLogManager::class.java.simpleName
|
||||
|
||||
const val EVENT_KEY_INFE_WITH_CHANGE = "event_key_och_common_info_and_changeinfo"
|
||||
const val EVENT_KEY_INFE_WITH_TRAJECTORY = "event_key_och_trajectory_info"
|
||||
|
||||
/**
|
||||
* @param Info 订单详细信息
|
||||
* @param changeInfo 变化信息
|
||||
*/
|
||||
@ChainLog(
|
||||
linkChainLog = ChainConstant.CHAIN_TYPE_OCH,
|
||||
linkCode = ChainConstant.CHAIN_SOURCE_OCH,
|
||||
nodeAliasCode = ChainConstant.CHAIN_CODE_OCH_COMMON_DISTANCE,
|
||||
paramIndexes = [0,1]
|
||||
)
|
||||
@JvmStatic
|
||||
fun writeChainLog(Info: String, changeInfo: String,upload:Boolean = true,eventID:String=EVENT_KEY_INFE_WITH_CHANGE) {
|
||||
try {
|
||||
d(SceneConstant.M_OCHCOMMON + TAG, Info)
|
||||
d(SceneConstant.M_OCHCOMMON + TAG, changeInfo)
|
||||
if(upload) {
|
||||
val plateNum = AppConfigInfo.plateNumber
|
||||
val params = HashMap<String, Any>()
|
||||
params["sn"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
params["env"] = DebugConfig.getNetMode()
|
||||
params["plate_number"] = if (TextUtils.isEmpty(plateNum)) "" else plateNum
|
||||
params["time"] = DateTimeUtils.getTimeText(DateTimeUtils.yyyy_MM_dd_HH_mm_ss)
|
||||
params["info"] = Info
|
||||
params["changeInfo"] = changeInfo
|
||||
MogoAnalyticUtils.track(eventID, params)
|
||||
}
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.och.common.module.manager.orderlogmanager
|
||||
|
||||
import com.mogo.eagle.core.data.deva.chain.ChainConstant
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.zhjt.service.chain.ChainLog
|
||||
|
||||
object OrderChainLogManager {
|
||||
|
||||
private val TAG = OrderChainLogManager::class.java.simpleName
|
||||
|
||||
/**
|
||||
* @param orderInfo 订单详细信息
|
||||
* @param changeInfo 变化信息
|
||||
*/
|
||||
@ChainLog(
|
||||
linkChainLog = ChainConstant.CHAIN_TYPE_OCH,
|
||||
linkCode = ChainConstant.CHAIN_SOURCE_OCH,
|
||||
nodeAliasCode = ChainConstant.CHAIN_CODE_OCH_COMMON_DISTANCE,
|
||||
paramIndexes = [0,1]
|
||||
)
|
||||
fun writeChainLog(orderInfo: String, changeInfo: String) {
|
||||
d(SceneConstant.M_OCHCOMMON + TAG, orderInfo)
|
||||
d(SceneConstant.M_OCHCOMMON + TAG, changeInfo)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.mogo.och.common.module.manager.stopsidemanager
|
||||
|
||||
interface OCHPlanningActionsCallback {
|
||||
fun onStartAutopilotFailure(actionStatus: StopSideStatus, stopSideStatus : Boolean?, errorInfo : String?)
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.mogo.och.common.module.manager.stopsidemanager
|
||||
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotPlanningActionsListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningActionsListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object StopSideManager : IMoGoAutopilotPlanningActionsListener {
|
||||
private const val TAG = "OCHPlanningActionsManager"
|
||||
|
||||
init {
|
||||
CallerPlanningActionsListenerManager.addListener(TAG, this)
|
||||
CallerPlanningActionsListenerManager.setListenerHz(TAG,5)
|
||||
}
|
||||
|
||||
var stopSiteStatus = StopSideStatus.NOTHING
|
||||
|
||||
val M_LISTENERS: ConcurrentHashMap<String, OCHPlanningActionsCallback> = ConcurrentHashMap()
|
||||
|
||||
fun addListener(
|
||||
tag: String,
|
||||
listener: OCHPlanningActionsCallback
|
||||
) {
|
||||
if (M_LISTENERS.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS[tag] = listener
|
||||
}
|
||||
|
||||
fun removeListener(tag: String) {
|
||||
if (!M_LISTENERS.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS.remove(tag)
|
||||
}
|
||||
/**
|
||||
* 删除监听
|
||||
* @param listener 要删除的监听对象
|
||||
*/
|
||||
fun removeListener(listener: OCHPlanningActionsCallback) {
|
||||
if (!M_LISTENERS.containsValue(listener)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS.forEach {
|
||||
if (it.value == listener) {
|
||||
M_LISTENERS.remove(it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopSide(){
|
||||
// 靠边停车
|
||||
CallerAutoPilotControlManager.sendPlanningCmd(1)
|
||||
}
|
||||
|
||||
fun resetStopSide(){
|
||||
// 重新起步
|
||||
CallerAutoPilotControlManager.sendPlanningCmd(2)
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun pncActions(planningActionMsg: MessagePad.PlanningActionMsg) {
|
||||
val drivingState = planningActionMsg.parkScenarioAction.actionMsg.drivingState
|
||||
val drivingAction = planningActionMsg.parkScenarioAction.actionMsg.drivingAction
|
||||
when (drivingState) {
|
||||
MessagePad.ParkScenarioDrivingState.PARK_SENARIO_FORCE_PULL_OVER_ON -> {
|
||||
when (drivingAction) {
|
||||
MessagePad.DrivingAction.DRIVING_ACTION_STATE_ONE -> {
|
||||
// 表示开始靠边停车
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.START){
|
||||
// 靠边停车中
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车中")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.DOING,null,null)
|
||||
}else{
|
||||
// 开始靠边停车
|
||||
stopSiteStatus = StopSideStatus.START
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"开始靠边停车")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.START,null,null)
|
||||
}
|
||||
}
|
||||
}
|
||||
MessagePad.DrivingAction.DRIVING_ACTION_STATE_TWO -> {
|
||||
//表示靠边停车成功
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.EndingSuccess){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.EndingSuccess
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车成功")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.EndingSuccess,true,null)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
MessagePad.DrivingAction.DRIVING_ACTION_STATE_THREE -> {
|
||||
//靠边停车失败
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.EndingFaile){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.EndingFaile
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车失败")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.EndingFaile,false,null)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
MessagePad.ParkScenarioDrivingState.PARK_SENARIO_FORCE_PULL_OVER_OFF -> {
|
||||
when (drivingAction) {
|
||||
MessagePad.DrivingAction.DRIVING_ACTION_STATE_ONE -> {
|
||||
// 表示距离前方站点100m
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.NOSTART){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.NOSTART
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车失败_原因:距离前方站点100m")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.NOSTART,false,"距离前方站点100m,请稍后再试")
|
||||
}
|
||||
}
|
||||
}
|
||||
MessagePad.DrivingAction.DRIVING_ACTION_STATE_TWO -> {
|
||||
//表示距离路口100m
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车失败_原因:距离路口100m")
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.NOSTART){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.NOSTART
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车失败_原因:距离路口100m,请稍后再试")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.NOSTART,false,"距离路口100m,请稍后再试")
|
||||
}
|
||||
}
|
||||
}
|
||||
MessagePad.DrivingAction.DRIVING_ACTION_STATE_THREE -> {
|
||||
//正在变道
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.NOSTART){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.NOSTART
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车失败_原因:正在变道")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.NOSTART,false,"因车辆正在变道无法靠边停车,请稍后再试")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
//未知问题
|
||||
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
if(stopSiteStatus == StopSideStatus.NOSTART){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.NOSTART
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"靠边停车失败_原因:未知问题")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.NOSTART,false,"靠边停车失败,请稍后再试")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MessagePad.ParkScenarioDrivingState.PARK_SENARIO_LANKE_KEEP ->{
|
||||
if(stopSiteStatus == StopSideStatus.NOTHING){
|
||||
// 只响应第一次
|
||||
}else{
|
||||
stopSiteStatus = StopSideStatus.NOTHING
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
CallerLogger.d(SceneConstant.M_BUS+ TAG,"进入正常驾驶")
|
||||
listener.onStartAutopilotFailure(StopSideStatus.NOTHING,false,"进入正常行驶中")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.och.common.module.manager.stopsidemanager
|
||||
|
||||
enum class StopSideStatus {
|
||||
START(),// 开始靠边停车
|
||||
DOING(),// 正在靠边停车
|
||||
EndingSuccess(),// 靠边停车成功
|
||||
EndingFaile(),// 靠边停车失败
|
||||
NOSTART(),// 没有响应靠边停车
|
||||
NOTHING()// 默认状态
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
package com.mogo.och.common.module.map;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_TAXI;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.amap.api.navi.AMapNavi;
|
||||
import com.amap.api.navi.AMapNaviListener;
|
||||
import com.amap.api.navi.enums.NaviType;
|
||||
import com.amap.api.navi.model.AMapCalcRouteResult;
|
||||
import com.amap.api.navi.model.AMapLaneInfo;
|
||||
import com.amap.api.navi.model.AMapModelCross;
|
||||
import com.amap.api.navi.model.AMapNaviCameraInfo;
|
||||
import com.amap.api.navi.model.AMapNaviCross;
|
||||
import com.amap.api.navi.model.AMapNaviLocation;
|
||||
import com.amap.api.navi.model.AMapNaviRouteNotifyData;
|
||||
import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo;
|
||||
import com.amap.api.navi.model.AMapServiceAreaInfo;
|
||||
import com.amap.api.navi.model.AimLessModeCongestionInfo;
|
||||
import com.amap.api.navi.model.AimLessModeStat;
|
||||
import com.amap.api.navi.model.NaviInfo;
|
||||
import com.amap.api.navi.model.NaviLatLng;
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.utilcode.util.NetworkUtils;
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils;
|
||||
import com.mogo.och.common.module.utils.PermissionUtil;
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2021/12/6
|
||||
*/
|
||||
public class AmapNaviToDestinationModel implements AMapNaviListener {
|
||||
|
||||
public static final String TAG = "NaviToDestinationModel";
|
||||
|
||||
private AMapNavi mAMapNavi = null;
|
||||
protected final List<NaviLatLng> sList = new ArrayList<NaviLatLng>();
|
||||
protected final List<NaviLatLng> eList = new ArrayList<NaviLatLng>();
|
||||
protected List<NaviLatLng> mWayPointList = new ArrayList<NaviLatLng>();
|
||||
private volatile ICommonNaviChangedCallback mNaviChangedCallback;
|
||||
private final AtomicInteger errorCount = new AtomicInteger(0);
|
||||
private boolean isPlay;
|
||||
|
||||
public static AmapNaviToDestinationModel getInstance(Context context) {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class SingletonHolder {
|
||||
private static final AmapNaviToDestinationModel INSTANCE = new AmapNaviToDestinationModel();
|
||||
}
|
||||
|
||||
private AmapNaviToDestinationModel() {
|
||||
}
|
||||
|
||||
public void initAMapNavi(NaviLatLng startLatLng, NaviLatLng endLatLng) {
|
||||
ThreadUtils.getSinglePool().execute(() -> {
|
||||
try {
|
||||
CallerLogger.i(TAG, "initAMapNavi()");
|
||||
mAMapNavi = AMapNavi.getInstance(AbsMogoApplication.getApp());
|
||||
mAMapNavi.addAMapNaviListener(this);
|
||||
mAMapNavi.setUseInnerVoice(true, true);
|
||||
sList.add(startLatLng);
|
||||
eList.add(endLatLng);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setVoiceIsMute(boolean isPlay) {
|
||||
ThreadUtils.getSinglePool().execute(() -> {
|
||||
if (mAMapNavi == null) return;
|
||||
CallerLogger.i(TAG, "setVoiceIsMute()--" + isPlay);
|
||||
this.isPlay = isPlay;
|
||||
if (isPlay) {
|
||||
mAMapNavi.startSpeak();
|
||||
} else {
|
||||
mAMapNavi.stopSpeak();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public AMapNavi getmAMapNavi() {
|
||||
return mAMapNavi;
|
||||
}
|
||||
|
||||
public void destroyAmaNavi() {
|
||||
ThreadUtils.getSinglePool().execute(() -> {
|
||||
CallerLogger.i(TAG, "destroyAmaNavi()");
|
||||
if (mAMapNavi != null) {
|
||||
isPlay = false;
|
||||
sList.clear();
|
||||
eList.clear();
|
||||
mAMapNavi.stopNavi();
|
||||
mAMapNavi.destroy();
|
||||
mAMapNavi = null;
|
||||
mNaviChangedCallback = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTaxiNaviChangedCallback(ICommonNaviChangedCallback callback) {
|
||||
CallerLogger.i(TAG, "setTaxiNaviChangedCallback()");
|
||||
this.mNaviChangedCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitNaviFailure() {
|
||||
Toast.makeText(AbsMogoApplication.getApp(), "init navi Failed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitNaviSuccess() {
|
||||
//初始化成功
|
||||
/**
|
||||
* 方法: int strategy=mAMapNavi.strategyConvert(congestion, avoidhightspeed, cost, hightspeed, multipleroute); 参数:
|
||||
*
|
||||
* @congestion 躲避拥堵
|
||||
* @avoidhightspeed 不走高速
|
||||
* @cost 避免收费
|
||||
* @hightspeed 高速优先
|
||||
* @multipleroute 多路径
|
||||
*
|
||||
* 说明: 以上参数都是boolean类型,其中multipleroute参数表示是否多条路线,如果为true则此策略会算出多条路线。
|
||||
* 注意: 不走高速与高速优先不能同时为true 高速优先与避免收费不能同时为true
|
||||
*/
|
||||
ThreadUtils.getSinglePool().execute(() -> {
|
||||
int strategy = 0;
|
||||
try {
|
||||
//再次强调,最后一个参数为true时代表多路径,否则代表单路径
|
||||
strategy = mAMapNavi.strategyConvert(true, false, false, false, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mAMapNavi.calculateDriveRoute(sList, eList, mWayPointList, strategy);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculateRouteSuccess(int[] ints) {
|
||||
//多路径算路成功回调
|
||||
ThreadUtils.getSinglePool().execute(() -> mAMapNavi.startNavi(NaviType.GPS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNaviInfoUpdate(NaviInfo naviinfo) {
|
||||
//导航过程中的信息更新,请看NaviInfo的具体说明
|
||||
CallerLogger.i(TAG, "距离=" + naviinfo.getPathRetainDistance() + ", 剩余时间 " + naviinfo.getPathRetainTime());
|
||||
if (null != mNaviChangedCallback) {
|
||||
mNaviChangedCallback.onCurrentNaviDistAndTimeChanged(naviinfo.getPathRetainDistance(), naviinfo.getPathRetainTime());// 米、秒
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculateRouteSuccess(AMapCalcRouteResult aMapCalcRouteResult) {
|
||||
errorCount.set(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculateRouteFailure(AMapCalcRouteResult result) {
|
||||
//路线计算失败
|
||||
//多路径算路成功回调
|
||||
if (errorCount.get() < 5) {
|
||||
errorCount.getAndIncrement();
|
||||
if (mNaviChangedCallback != null) {
|
||||
mNaviChangedCallback.reInitNaviAmap(isPlay, true);
|
||||
}
|
||||
}
|
||||
if (!NetworkUtils.isConnected(AbsMogoApplication.getApp()) || result.getErrorCode() == 2) {
|
||||
ToastCharterUtils.showToastShort("网络异常,请重试");
|
||||
if (mNaviChangedCallback != null) {
|
||||
mNaviChangedCallback.reInitNaviAmap(isPlay, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!PermissionUtil.isLocServiceEnable(AbsMogoApplication.getApp()) || !PermissionUtil.checkPermission(AbsMogoApplication.getApp(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
|
||||
ToastCharterUtils.showToastShort("请开启车机定位后重试");
|
||||
if (mNaviChangedCallback != null) {
|
||||
mNaviChangedCallback.reInitNaviAmap(isPlay, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CallerLogger.i(M_TAXI + TAG, "路线计算失败:错误码=" + result.getErrorCode() + ",Error Message= " + result.getErrorDetail());
|
||||
CallerLogger.i(M_TAXI + TAG, "错误码详细链接见:http://lbs.amap.com/api/android-navi-sdk/guide/tools/errorcode/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartNavi(int type) {
|
||||
//开始导航回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrafficStatusUpdate() {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChange(AMapNaviLocation location) {
|
||||
//当前位置回调
|
||||
// CallerLogger.i( TAG, "AMapNaviLocation = NaviLatLng = "+
|
||||
// location.getCoord().getLatitude()+ ", "+ location.getCoord().getLongitude()
|
||||
// + ", bearing = " +location.getBearing()
|
||||
// +", time = " + DateTimeUtil.formatLongToString(location.getTime(),DateTimeUtil.HH_mm)
|
||||
// + ", locationType = "+ location.getLocationType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetNavigationText(int type, String text) {
|
||||
//播报类型和播报文字回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetNavigationText(String s) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEndEmulatorNavi() {
|
||||
//结束模拟导航
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArriveDestination() {
|
||||
//到达目的地
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculateRouteFailure(int errorInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReCalculateRouteForYaw() {
|
||||
//偏航后重新计算路线回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReCalculateRouteForTrafficJam() {
|
||||
//拥堵后重新计算路线回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onArrivedWayPoint(int wayID) {
|
||||
//到达途径点
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGpsOpenStatus(boolean enabled) {
|
||||
//GPS开关状态回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showModeCross(AMapModelCross aMapModelCross) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideModeCross() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIntervalCameraInfo(AMapNaviCameraInfo aMapNaviCameraInfo, AMapNaviCameraInfo aMapNaviCameraInfo1, int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showLaneInfo(AMapLaneInfo aMapLaneInfo) {
|
||||
//显示车道信息
|
||||
// StringBuffer sb = new StringBuffer();
|
||||
// sb.append("共" + aMapLaneInfo.frontLane.length + "车道");
|
||||
// for (int i = 0; i < aMapLaneInfo.frontLane.length; i++) {
|
||||
// //当前车道可以选择的动作
|
||||
// int background = aMapLaneInfo.backgroundLane[i];
|
||||
// //当前用户要执行的动作
|
||||
// int recommend = aMapLaneInfo.frontLane[i];
|
||||
//
|
||||
// CallerLogger.e(M_TAXI + "ggb", "---->>> background is " + background + " ; recommend is " + recommend);
|
||||
// //根据文档中每个动作对应的枚举类型,显示对应的图片
|
||||
// try {
|
||||
// sb.append(",第" + (i + 1) + "车道为" + array[background]);
|
||||
// if (recommend != 255) {
|
||||
// sb.append(",当前车道可 " + actions[recommend]);
|
||||
// }
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// CallerLogger.e(M_TAXI + "showLaneInfo", sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNaviRouteNotify(AMapNaviRouteNotifyData aMapNaviRouteNotifyData) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGpsSignalWeak(boolean b) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCameraInfo(AMapNaviCameraInfo[] aMapCameraInfos) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceAreaUpdate(AMapServiceAreaInfo[] amapServiceAreaInfos) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo aMapNaviTrafficFacilityInfo) {
|
||||
//已过时
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCross(AMapNaviCross aMapNaviCross) {
|
||||
//显示放大图回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideCross() {
|
||||
//隐藏放大图回调
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showLaneInfo(AMapLaneInfo[] laneInfos, byte[] laneBackgroundInfo, byte[] laneRecommendedInfo) {
|
||||
//过时
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideLaneInfo() {
|
||||
//隐藏车道信息
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyParallelRoad(int i) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo[] aMapNaviTrafficFacilityInfos) {
|
||||
//更新交通设施信息
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAimlessModeStatistics(AimLessModeStat aimLessModeStat) {
|
||||
//更新巡航模式的统计信息
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateAimlessModeCongestionInfo(AimLessModeCongestionInfo aimLessModeCongestionInfo) {
|
||||
//更新巡航模式的拥堵信息
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayRing(int i) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.mogo.och.common.module.map
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.RelativeLayout
|
||||
import com.amap.api.maps.AMap
|
||||
import com.amap.api.maps.model.CustomMapStyleOptions
|
||||
import com.amap.api.navi.AMapNaviView
|
||||
import com.amap.api.navi.AMapNaviViewListener
|
||||
import com.amap.api.navi.AMapNaviViewOptions
|
||||
import com.amap.api.navi.model.RouteOverlayOptions
|
||||
import com.mogo.eagle.core.utilcode.mogo.MapAssetStyleUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.och.common.module.R
|
||||
import kotlinx.android.synthetic.main.taxi_common_amap_navi_view.view.*
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/10/23
|
||||
*/
|
||||
class CommonAmapNaviVIew @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0)
|
||||
: RelativeLayout(context,attrs,defStyleAttr), AMapNaviViewListener {
|
||||
|
||||
private val TAG : String = "TaxiAmapNaviVIew"
|
||||
|
||||
var aMap : AMap? = null
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.taxi_common_amap_navi_view,this,true)
|
||||
initMapView()
|
||||
}
|
||||
|
||||
private fun initMapView(){
|
||||
|
||||
amapNaviView.setAMapNaviViewListener(this)
|
||||
//车头向上模式
|
||||
amapNaviView.naviMode = AMapNaviView.CAR_UP_MODE
|
||||
aMap = amapNaviView.map
|
||||
//关闭地图文字显示
|
||||
aMap!!.showMapText(false)
|
||||
// 设置导航地图模式,aMap是地图控制器对象。
|
||||
aMap!!.mapType = AMap.MAP_TYPE_NIGHT
|
||||
// 关闭显示实时路况图层,aMap是地图控制器对象。
|
||||
aMap!!.isTrafficEnabled = false
|
||||
setMapViewOptions()
|
||||
|
||||
thread(start = true){
|
||||
try {
|
||||
Thread.sleep(1000L)
|
||||
} catch (e : InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
if (null == context){
|
||||
return@thread
|
||||
}
|
||||
|
||||
aMap!!.setCustomMapStyle(
|
||||
CustomMapStyleOptions()
|
||||
.setEnable(true)
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(context, "over_view_style.data"))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(context, "over_view_style_extra.data"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMapViewOptions() {
|
||||
|
||||
val options = AMapNaviViewOptions()
|
||||
options.tilt = 0 //设置 2D 模式
|
||||
|
||||
options.isLayoutVisible = false //设置导航界面UI是否显示。
|
||||
|
||||
options.isTrafficBarEnabled = false //设置路况光柱条是否显示(只适用于驾车导航,需要联网)。
|
||||
|
||||
options.isAutoLockCar = true //设置6秒后是否自动锁车
|
||||
|
||||
options.isAutoDisplayOverview = true //设置是否自动全览模式,即在算路成功后自动进入全览模式
|
||||
|
||||
options.isTrafficLine = false
|
||||
options.setModeCrossDisplayShow(true) //设置是否显示路口放大图(路口模型图)
|
||||
|
||||
options.isAutoChangeZoom = true //自动缩放级别
|
||||
|
||||
options.carBitmap =
|
||||
BitmapFactory.decodeResource(context.resources, R.drawable.taxi_navi_arrow_icon)
|
||||
options.fourCornersBitmap =
|
||||
BitmapFactory.decodeResource(this.resources, R.drawable.taxi_navi_direction_icon)
|
||||
options.isAutoChangeZoom = true //设置是否开启动态比例尺 (锁车态下自动进行地图缩放变化)
|
||||
|
||||
// options.setZoom(18);//14-18
|
||||
// options.setTrafficInfoUpdateEnabled(false);
|
||||
// options.setTrafficLayerEnabled(false);//设置[实时交通图层开关按钮]是否显示(只适用于驾车导航,需要联网)。
|
||||
// options.setCameraInfoUpdateEnabled(false);
|
||||
// options.setCompassEnabled(false);//设置指南针图标否在导航界面显示,默认显示。
|
||||
// options.setLaneInfoShow(false);// 设置是否显示道路信息view
|
||||
// options.setNaviArrowVisible(false);//设置路线转向箭头隐藏和显示
|
||||
// options.setRealCrossDisplayShow(false);//设置是否显示路口放大图(实景图)
|
||||
// options.setRouteListButtonShow(true);//设置导航界面是否显示路线全览按钮。
|
||||
// options.setSettingMenuEnabled(false);//设置菜单按钮是否在导航界面显示。
|
||||
|
||||
// options.setZoom(18);//14-18
|
||||
// options.setTrafficInfoUpdateEnabled(false);
|
||||
// options.setTrafficLayerEnabled(false);//设置[实时交通图层开关按钮]是否显示(只适用于驾车导航,需要联网)。
|
||||
// options.setCameraInfoUpdateEnabled(false);
|
||||
// options.setCompassEnabled(false);//设置指南针图标否在导航界面显示,默认显示。
|
||||
// options.setLaneInfoShow(false);// 设置是否显示道路信息view
|
||||
// options.setNaviArrowVisible(false);//设置路线转向箭头隐藏和显示
|
||||
// options.setRealCrossDisplayShow(false);//设置是否显示路口放大图(实景图)
|
||||
// options.setRouteListButtonShow(true);//设置导航界面是否显示路线全览按钮。
|
||||
// options.setSettingMenuEnabled(false);//设置菜单按钮是否在导航界面显示。
|
||||
val routeOverlayOptions = RouteOverlayOptions()
|
||||
|
||||
// routeOverlayOptions.setArrowOnTrafficRoute(BitmapFactory.decodeResource(getResources(),R.drawable.custtexture_aolr));
|
||||
|
||||
// routeOverlayOptions.setArrowOnTrafficRoute(BitmapFactory.decodeResource(getResources(),R.drawable.custtexture_aolr));
|
||||
routeOverlayOptions.normalRoute =
|
||||
BitmapFactory.decodeResource(resources, R.drawable.taxi_navi_line_icon)
|
||||
options.routeOverlayOptions = routeOverlayOptions
|
||||
|
||||
amapNaviView.viewOptions = options
|
||||
}
|
||||
|
||||
override fun onNaviSetting() {
|
||||
//底部导航设置点击回调
|
||||
}
|
||||
|
||||
override fun onNaviCancel() {
|
||||
}
|
||||
|
||||
override fun onNaviBackClick(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onNaviMapMode(p0: Int) {
|
||||
//导航态车头模式,0:车头朝上状态;1:正北朝上模式。
|
||||
}
|
||||
|
||||
override fun onNaviTurnClick() {
|
||||
//转弯view的点击回调
|
||||
}
|
||||
|
||||
override fun onNextRoadClick() {
|
||||
//下一个道路View点击回调
|
||||
}
|
||||
|
||||
override fun onScanViewButtonClick() {
|
||||
//全览按钮点击回调
|
||||
}
|
||||
|
||||
override fun onLockMap(p0: Boolean) {
|
||||
//锁地图状态发生变化时回调
|
||||
}
|
||||
|
||||
override fun onNaviViewLoaded() {
|
||||
d(SceneConstant.M_TAXI + TAG, "导航页面加载成功")
|
||||
}
|
||||
|
||||
override fun onMapTypeChanged(p0: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onNaviViewShowMode(p0: Int) {
|
||||
|
||||
}
|
||||
|
||||
fun onCreate(savedInstanceState : Bundle?){
|
||||
amapNaviView.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
fun onResume(){
|
||||
amapNaviView.onResume()
|
||||
}
|
||||
|
||||
fun onPause(){
|
||||
amapNaviView.onPause()
|
||||
}
|
||||
|
||||
fun onDestroy(){
|
||||
amapNaviView.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.common.module.map;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2021/12/3
|
||||
*/
|
||||
public interface ICommonNaviChangedCallback {
|
||||
// 当前位置距离上车点的距离(米)、预估时间(秒)
|
||||
void onCurrentNaviDistAndTimeChanged(int meters, long timeInSecond);
|
||||
void reInitNaviAmap(boolean isPlay,boolean isRestart);
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/7/20
|
||||
*/
|
||||
public class AnimatorDrawableUtil {
|
||||
private static final int MSG_START = 0xf1;
|
||||
private static final int MSG_STOP = 0xf2;
|
||||
private static final int STATE_STOP = 0xf3;
|
||||
private static final int STATE_RUNNING = 0xf4;
|
||||
|
||||
//运行状态
|
||||
private int mState = STATE_RUNNING;
|
||||
//显示图片的View
|
||||
private ImageView mImageView = null;
|
||||
//图片资源的ID列表
|
||||
private List<Integer> mResourceIdList = null;
|
||||
//图片bitmap列表
|
||||
private List<Bitmap> mBitmapList = null;
|
||||
//定时任务器
|
||||
private final Timer mTimer = new Timer();
|
||||
//定时任务
|
||||
private AnimTimerTask mTimeTask = null;
|
||||
//记录播放位置
|
||||
private int mFrameIndex = 0;
|
||||
//播放形式
|
||||
private boolean isLooping = false;
|
||||
|
||||
public AnimatorDrawableUtil() {
|
||||
// mTimer = new Timer();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置动画播放资源
|
||||
*/
|
||||
public void setAnimation(ImageView imageview, List<Integer> resourceIdList) {
|
||||
mImageView = imageview;
|
||||
if(mResourceIdList==null){
|
||||
mResourceIdList = new ArrayList<Integer>();
|
||||
mBitmapList = new ArrayList<>();
|
||||
}else{
|
||||
mResourceIdList.clear();
|
||||
mBitmapList.clear();
|
||||
}
|
||||
mResourceIdList.addAll(resourceIdList);
|
||||
|
||||
//在初始化时候就将资源文件decode
|
||||
for (int i = 0; i <= resourceIdList.size()-1; i++){
|
||||
mBitmapList.add(readBitMap(mImageView.getContext(),resourceIdList.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置动画播放资源
|
||||
*/
|
||||
public void setAnimation(Context context, int resourceId, ImageView imageview) {
|
||||
this.mImageView = imageview;
|
||||
if(mResourceIdList==null){
|
||||
mResourceIdList = new ArrayList<Integer>();
|
||||
mBitmapList = new ArrayList<>();
|
||||
}else{
|
||||
mResourceIdList.clear();
|
||||
mBitmapList.clear();
|
||||
}
|
||||
|
||||
loadFromXml(context, resourceId, new OnParseListener() {
|
||||
@Override
|
||||
public void onParse(List<Integer> res) {
|
||||
mResourceIdList.addAll(res);
|
||||
for (int i = 0; i <= res.size()-1; i++){
|
||||
mBitmapList.add(readBitMap(mImageView.getContext(),res.get(i)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析xml
|
||||
*
|
||||
* @param context
|
||||
* @param resourceId 资源id
|
||||
*/
|
||||
private void loadFromXml(final Context context, final int resourceId,
|
||||
final OnParseListener onParseListener) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<Integer> res = new ArrayList<Integer>();
|
||||
XmlResourceParser parser = context.getResources().getXml(resourceId);
|
||||
|
||||
try {
|
||||
int eventType = parser.getEventType();
|
||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
if (eventType == XmlPullParser.START_DOCUMENT) {
|
||||
} else if (eventType == XmlPullParser.START_TAG) {
|
||||
if (parser.getName().equals("item")) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); i++) {
|
||||
if (parser.getAttributeName(i).equals("drawable")) {
|
||||
int resId = Integer.parseInt(parser.getAttributeValue(i).substring(1));
|
||||
res.add(resId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (eventType == XmlPullParser.END_TAG) {
|
||||
} else if (eventType == XmlPullParser.TEXT) {
|
||||
}
|
||||
|
||||
eventType = parser.next();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: handle exception
|
||||
e.printStackTrace();
|
||||
} catch (XmlPullParserException e2) {
|
||||
// TODO: handle exception
|
||||
e2.printStackTrace();
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
|
||||
if (onParseListener != null) {
|
||||
onParseListener.onParse(res);
|
||||
}
|
||||
}
|
||||
|
||||
private AnimationLisenter lisenter;
|
||||
|
||||
|
||||
/**
|
||||
* 开始播放动画
|
||||
*
|
||||
* @param loop 是否循环播放
|
||||
* @param duration 动画播放时间间隔
|
||||
*/
|
||||
public void start(boolean loop, int duration, AnimationLisenter lisenter) {
|
||||
this.lisenter = lisenter;
|
||||
// stop();
|
||||
if (mResourceIdList == null || mResourceIdList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
// if (mTimer == null) {
|
||||
// mTimer = new Timer();
|
||||
// }
|
||||
try {
|
||||
isLooping = loop;
|
||||
mFrameIndex = 0;
|
||||
mState = STATE_RUNNING;
|
||||
if (mTimeTask != null){
|
||||
return;
|
||||
}
|
||||
mTimeTask = new AnimTimerTask();
|
||||
mTimer.schedule(mTimeTask, 0, duration);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (lisenter != null){
|
||||
lisenter.startAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止动画播放
|
||||
*/
|
||||
public void stop() {
|
||||
if (mTimer != null) {
|
||||
mTimer.purge();
|
||||
mTimer.cancel();
|
||||
// mTimer = null;
|
||||
}
|
||||
if (mTimeTask != null) {
|
||||
mFrameIndex = 0;
|
||||
mState = STATE_STOP;
|
||||
mTimeTask.cancel();
|
||||
mTimeTask = null;
|
||||
}
|
||||
//移除Handler消息
|
||||
if (AnimHandler != null) {
|
||||
AnimHandler.removeMessages(MSG_START);
|
||||
AnimHandler.removeMessages(MSG_STOP);
|
||||
AnimHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时器任务
|
||||
*/
|
||||
class AnimTimerTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mFrameIndex < 0 || mState == STATE_STOP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFrameIndex < mResourceIdList.size()) {
|
||||
Message msg = AnimHandler.obtainMessage(MSG_START, 0, 0, null);
|
||||
msg.sendToTarget();
|
||||
} else {
|
||||
mFrameIndex = 0;
|
||||
if (!isLooping) {
|
||||
Message msg = AnimHandler.obtainMessage(MSG_STOP, 0, 0, null);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler
|
||||
*/
|
||||
private Handler AnimHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_START: {
|
||||
if (mFrameIndex >= 0 && mFrameIndex < mResourceIdList.size() && mState == STATE_RUNNING) {
|
||||
//这里不能使用image.setImageResource 因为源码中也是创建了bitmap 所以这里我们自己创建
|
||||
if (mBitmapList != null && mBitmapList.size()-1 >= mFrameIndex){
|
||||
Bitmap bitmap= mBitmapList.get(mFrameIndex);
|
||||
mImageView.setImageBitmap(bitmap);
|
||||
}else {
|
||||
Bitmap bitmap=readBitMap(mImageView.getContext(),mResourceIdList.get(mFrameIndex));
|
||||
mImageView.setImageBitmap(bitmap);
|
||||
}
|
||||
mFrameIndex++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MSG_STOP: {
|
||||
if (mTimeTask != null) {
|
||||
mFrameIndex = 0;
|
||||
mTimer.purge();
|
||||
mTimeTask.cancel();
|
||||
mState = STATE_STOP;
|
||||
mTimeTask = null;
|
||||
if (lisenter !=null){
|
||||
lisenter.endAnimation();
|
||||
}
|
||||
if (isLooping) {
|
||||
mImageView.setImageResource(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static Bitmap readBitMap(Context context, int resId) {
|
||||
BitmapFactory.Options opt = new BitmapFactory.Options();
|
||||
opt.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
opt.inPurgeable = true;
|
||||
opt.inInputShareable = true;
|
||||
InputStream is = context.getResources().openRawResource(resId);
|
||||
return BitmapFactory.decodeStream(is, null, opt);
|
||||
}
|
||||
|
||||
public interface OnParseListener {
|
||||
void onParse(List<Integer> res);
|
||||
}
|
||||
|
||||
public interface AnimationLisenter {
|
||||
void startAnimation();
|
||||
|
||||
void endAnimation();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.widget.ImageView
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import java.lang.ref.SoftReference
|
||||
import java.util.concurrent.ArrayBlockingQueue
|
||||
import java.util.concurrent.Future
|
||||
|
||||
class BigFrameAnimatorContainer (resId: Int,
|
||||
fps: Int,
|
||||
imageView: ImageView,
|
||||
isOnce: Boolean = false,// 一次性的 true 值播放一次 false 重复播放
|
||||
initFirstFrame:Boolean = true,
|
||||
width:Int = -1,
|
||||
height:Int = -1){
|
||||
private val TAG = "BigFrameAnimatorContainer"
|
||||
private lateinit var mFrames: IntArray // 帧数组
|
||||
private var mIndex = 0 // 当前帧
|
||||
private var mShouldRun = false // 开始/停止播放用
|
||||
private var mIsRunning = false // 动画是否正在播放,防止重复播放
|
||||
private var mSoftReferenceImageView: SoftReference<ImageView>? = null // 软引用ImageView,以便及时释放掉
|
||||
private var mHandler: Handler? = null
|
||||
private var mDelayMillis = 0
|
||||
private var mOnAnimationStoppedListener: OnAnimationStoppedListener? = null//播放停止监听
|
||||
var isOnce:Boolean = false
|
||||
|
||||
private val readQueue = ArrayBlockingQueue<Pair<Bitmap,BitmapFactory.Options>>(8,true)
|
||||
private val writeQueue = ArrayBlockingQueue<Pair<Bitmap,BitmapFactory.Options>>(8,true)
|
||||
|
||||
private var currentPoll:Pair<Bitmap,BitmapFactory.Options>?=null
|
||||
|
||||
private var decodeImage: Future<*>?=null
|
||||
|
||||
|
||||
init {
|
||||
createAnimation(imageView, getData(resId), fps,initFirstFrame,width,height)
|
||||
this.isOnce = isOnce
|
||||
}
|
||||
|
||||
private fun createAnimation(
|
||||
imageView: ImageView,
|
||||
frames: IntArray,
|
||||
fps: Int,
|
||||
initFirstFrame: Boolean,
|
||||
width: Int,
|
||||
height: Int
|
||||
) {
|
||||
mHandler = object: Handler(Looper.myLooper()!!){
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
CallerLogger.d(TAG,"消息类型:${msg.what}")
|
||||
if(msg.what==0){
|
||||
val imageView = mSoftReferenceImageView!!.get()
|
||||
if (!mShouldRun || imageView == null) {
|
||||
mIsRunning = false
|
||||
if (mOnAnimationStoppedListener != null) {
|
||||
mOnAnimationStoppedListener!!.AnimationStopped()
|
||||
}
|
||||
return
|
||||
}
|
||||
mIsRunning = true
|
||||
//新开线程去读下一帧
|
||||
if (imageView.isShown) {
|
||||
if (!mShouldRun) {
|
||||
mIsRunning = false
|
||||
CallerLogger.d(TAG,"暂停播放")
|
||||
if (mOnAnimationStoppedListener != null) {
|
||||
mOnAnimationStoppedListener!!.AnimationStopped()
|
||||
}
|
||||
return
|
||||
}
|
||||
mHandler?.sendEmptyMessageDelayed(0,mDelayMillis.toLong())
|
||||
if(currentPoll!=null){
|
||||
writeQueue.offer(currentPoll)
|
||||
currentPoll = null
|
||||
}
|
||||
currentPoll = readQueue.poll()
|
||||
if(currentPoll!=null){
|
||||
val bitmap = currentPoll!!.first
|
||||
imageView.setImageBitmap(bitmap)
|
||||
}else{
|
||||
CallerLogger.d(TAG,"加载过慢了")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mFrames = frames
|
||||
mIndex = -1
|
||||
mSoftReferenceImageView = SoftReference(imageView)
|
||||
mShouldRun = false
|
||||
mIsRunning = false
|
||||
mDelayMillis = 1000 / fps //帧动画时间间隔,毫秒
|
||||
CallerLogger.d(TAG,"两帧时间:${mDelayMillis}")
|
||||
if(initFirstFrame) {
|
||||
imageView.setImageResource(mFrames[0])
|
||||
}
|
||||
var widthImage = -1
|
||||
var heightImage = -1
|
||||
var config = Bitmap.Config.ARGB_8888
|
||||
if(width>0&&height>0){
|
||||
widthImage = width
|
||||
heightImage = height
|
||||
}else{
|
||||
try {
|
||||
val bmp = (imageView.drawable as BitmapDrawable).bitmap
|
||||
widthImage = bmp.width
|
||||
heightImage = bmp.height
|
||||
config = bmp.config
|
||||
}catch (e:Exception){
|
||||
throw RuntimeException("请设置图片或传递大小")
|
||||
}
|
||||
}
|
||||
// 当图片大小类型相同时进行复用,避免频繁GC
|
||||
|
||||
for (i in 0..7) {
|
||||
val mBitmap = Bitmap.createBitmap(widthImage, heightImage, config)
|
||||
val mBitmapOptions = BitmapFactory.Options()
|
||||
//设置Bitmap内存复用
|
||||
mBitmapOptions.inBitmap = mBitmap //Bitmap复用内存块,类似对象池,避免不必要的内存分配和回收
|
||||
mBitmapOptions.inMutable = true //解码时返回可变Bitmap
|
||||
mBitmapOptions.inSampleSize = 1 //缩放比例
|
||||
writeQueue.add(Pair(mBitmap,mBitmapOptions))
|
||||
}
|
||||
|
||||
decodeImage = ThreadUtils.getIoPool().submit {
|
||||
while (true) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val (bitmap1, options) = writeQueue.take()
|
||||
val index: Int = next
|
||||
val imageRes: Int = mFrames[index]
|
||||
var bitmap: Bitmap? = null
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeResource(
|
||||
imageView.resources,
|
||||
imageRes,
|
||||
options
|
||||
)
|
||||
options.inBitmap = bitmap
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (bitmap != null) {
|
||||
readQueue.put(Pair(bitmap, options))
|
||||
}
|
||||
val dexTime = System.currentTimeMillis() - startTime
|
||||
CallerLogger.d(TAG, "decode用时:${dexTime}ms index ${index}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//循环读取下一帧
|
||||
private val next: Int
|
||||
get() {
|
||||
mIndex++
|
||||
if (mIndex >= mFrames.size){
|
||||
mIndex = 0
|
||||
}
|
||||
return mIndex
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun reStart(){
|
||||
mIndex = 0
|
||||
mIsRunning = false
|
||||
start()
|
||||
}
|
||||
|
||||
fun release(){
|
||||
mShouldRun = false
|
||||
decodeImage?.cancel(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放动画,同步锁防止多线程读帧时,数据安全问题
|
||||
*/
|
||||
@Synchronized
|
||||
fun start() {
|
||||
mShouldRun = true
|
||||
if (mIsRunning) return
|
||||
mHandler?.removeCallbacksAndMessages(null)
|
||||
mHandler?.sendEmptyMessage(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放
|
||||
*/
|
||||
@Synchronized
|
||||
fun stop() {
|
||||
mShouldRun = false
|
||||
}
|
||||
|
||||
fun isPlaying():Boolean{
|
||||
return mShouldRun
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置停止播放监听
|
||||
* @param listener 设置监听
|
||||
*/
|
||||
fun setOnAnimStopListener(listener: OnAnimationStoppedListener?) {
|
||||
mOnAnimationStoppedListener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 从xml中读取帧数组
|
||||
* @param resId
|
||||
* @return
|
||||
*/
|
||||
fun getData(resId: Int): IntArray {
|
||||
val array = AbsMogoApplication.getApp().resources.obtainTypedArray(resId)
|
||||
val len = array.length()
|
||||
val intArray = IntArray(array.length())
|
||||
for (i in 0 until len) {
|
||||
intArray[i] = array.getResourceId(i, 0)
|
||||
}
|
||||
array.recycle()
|
||||
return intArray
|
||||
}
|
||||
|
||||
fun setData(mFrames: IntArray){
|
||||
this.mFrames = mFrames
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放监听
|
||||
*/
|
||||
interface OnAnimationStoppedListener {
|
||||
fun AnimationStopped()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/9/23
|
||||
*/
|
||||
public class BlinkAnimationUtil {
|
||||
|
||||
//实现图片闪烁效果
|
||||
public static void setAnimation(ImageView imageView) {
|
||||
Object animObject = imageView.getTag(imageView.getId());
|
||||
if (animObject instanceof AnimatorSet){
|
||||
AnimatorSet animatorSet = (AnimatorSet)animObject;
|
||||
animatorSet.start();
|
||||
return;
|
||||
}
|
||||
|
||||
AnimatorSet animationSet = new AnimatorSet();
|
||||
imageView.setTag(imageView.getId(),animationSet);
|
||||
|
||||
ObjectAnimator valueAnimator = ObjectAnimator.ofFloat(imageView, "alpha",0.3f, 1.0f);
|
||||
ObjectAnimator valueAnimatorDisappare = ObjectAnimator.ofFloat(imageView, "alpha",1.0f, 0.3f);
|
||||
valueAnimator.setDuration(1000);
|
||||
valueAnimatorDisappare.setDuration(800);
|
||||
|
||||
valueAnimator.setRepeatCount(-1);
|
||||
valueAnimatorDisappare.setRepeatCount(-1);
|
||||
|
||||
animationSet.playTogether(valueAnimatorDisappare, valueAnimator);
|
||||
animationSet.start();
|
||||
}
|
||||
|
||||
//消除动画
|
||||
public static void clearAnimation(ImageView imageView){
|
||||
Object animObject = imageView.getTag(imageView.getId());
|
||||
if (animObject instanceof AnimatorSet){
|
||||
AnimatorSet animatorSet = (AnimatorSet)animObject;
|
||||
animatorSet.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS_P
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_CHARTER_D
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_SWEEPER
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_TAXI
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_TAXI_P
|
||||
|
||||
object CallerLoggerUtils {
|
||||
var flavorTag =if (AppIdentityModeUtils.isTaxi(FunctionBuildConfig.appIdentityMode)&&
|
||||
AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)){
|
||||
//出租车司机
|
||||
M_TAXI
|
||||
}else if (AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode) &&
|
||||
AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)){
|
||||
//小巴车司机
|
||||
M_BUS
|
||||
}else if (AppIdentityModeUtils.isTaxi(FunctionBuildConfig.appIdentityMode)&&
|
||||
AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)){
|
||||
//出租车乘客
|
||||
M_TAXI_P
|
||||
}else if (AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)&&
|
||||
AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)){
|
||||
//小巴车乘客
|
||||
M_BUS_P
|
||||
}else if (AppIdentityModeUtils.isSweeper(FunctionBuildConfig.appIdentityMode)){
|
||||
//清扫车
|
||||
M_SWEEPER
|
||||
}else if (AppIdentityModeUtils.isCharter(FunctionBuildConfig.appIdentityMode) &&
|
||||
AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)){
|
||||
//M1司机端
|
||||
M_CHARTER_D
|
||||
}
|
||||
else{
|
||||
""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,856 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import com.amap.api.maps.CoordinateConverter
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils
|
||||
import com.mogo.och.common.module.manager.distancemamager.DistanceDegree
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import java.util.TreeMap
|
||||
import kotlin.math.acos
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/3/28
|
||||
*/
|
||||
object CoordinateCalculateRouteUtil {
|
||||
@JvmStatic
|
||||
fun <T> calculateRouteSumLength(points: List<T>?): Float {
|
||||
if (null == points || points.size == 0) return 0f
|
||||
var sumLength = 0f
|
||||
if (points[0] is MogoLocation) {
|
||||
//计算全路径总距离
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val locationPre = points[i] as MogoLocation
|
||||
val location = points[i + 1] as MogoLocation
|
||||
val preLat = locationPre.latitude
|
||||
val preLon = locationPre.longitude
|
||||
val laLat = location.latitude
|
||||
val laLon = location.longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
} else if (points[0] is Location) {
|
||||
//计算全路径总距离
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val locationPre = points[i] as Location
|
||||
val location = points[i + 1] as Location
|
||||
val preLat = locationPre.latitude
|
||||
val preLon = locationPre.longitude
|
||||
val laLat = location.latitude
|
||||
val laLon = location.longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
} else if (points[0] is LatLng) {
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val locationPre = points[i] as LatLng
|
||||
val location = points[i + 1] as LatLng
|
||||
val preLat = locationPre.latitude
|
||||
val preLon = locationPre.longitude
|
||||
val laLat = location.latitude
|
||||
val laLon = location.longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
}
|
||||
return sumLength
|
||||
}
|
||||
|
||||
fun calculateRouteSumLength(
|
||||
mRoutePoints: List<MogoLocation>?,
|
||||
location: MogoLocation,
|
||||
station: MogoLocation
|
||||
): Float {
|
||||
if (null == mRoutePoints || mRoutePoints.size == 0) return 0f
|
||||
var lastSumLength = 0f
|
||||
|
||||
//当前位置距离轨迹中最近的点
|
||||
val currentRouteIndex = getArrivedPointIndexNew(
|
||||
0, mRoutePoints, location.longitude, location.latitude
|
||||
)
|
||||
// 距离当前位置轨迹中最近的轨迹点坐标
|
||||
val currentPoint = mRoutePoints[currentRouteIndex]
|
||||
// 当前位置距离最近的点的距离
|
||||
val calculateCurrentdex = CoordinateUtils.calculateLineDistance(
|
||||
location.longitude, location.latitude,
|
||||
currentPoint.longitude, currentPoint.latitude
|
||||
)
|
||||
|
||||
|
||||
//要前往的站在轨迹中对应的点
|
||||
val stationPointInRouteIndex = getArrivedPointIndexNew(
|
||||
currentRouteIndex, mRoutePoints,
|
||||
station.longitude,
|
||||
station.latitude
|
||||
)
|
||||
// 距离站点最近的轨迹点
|
||||
val stationPointInRoute = mRoutePoints[stationPointInRouteIndex]
|
||||
// 站点距离轨迹中最近点的距离
|
||||
val calculateLineDistance = CoordinateUtils.calculateLineDistance(
|
||||
stationPointInRoute.longitude, stationPointInRoute.latitude,
|
||||
station.longitude, station.latitude
|
||||
)
|
||||
if (currentRouteIndex < stationPointInRouteIndex) {
|
||||
// subList 是[) 需要的是[]
|
||||
val subList = mRoutePoints.subList(currentRouteIndex, stationPointInRouteIndex + 1)
|
||||
// 轨迹点所有的距离
|
||||
lastSumLength = calculateRouteSumLength(subList)
|
||||
// region 站点坐标和 站点坐标对应轨迹点的坐标距离
|
||||
// 需要加距离 和下一个轨迹点成钝角
|
||||
if (stationPointInRouteIndex + 1 < mRoutePoints.size) {
|
||||
val lastPointsNext = mRoutePoints[stationPointInRouteIndex + 1]
|
||||
val degree = getDegree(
|
||||
station.longitude, station.latitude,
|
||||
stationPointInRoute.longitude, stationPointInRoute.latitude,
|
||||
lastPointsNext.longitude, lastPointsNext.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength + calculateLineDistance
|
||||
}
|
||||
}
|
||||
// 需要减距离 和上一个轨迹点成钝角
|
||||
if (stationPointInRouteIndex - 1 >= 0) {
|
||||
val lastPointsPre = mRoutePoints[stationPointInRouteIndex - 1]
|
||||
val degree = getDegree(
|
||||
station.longitude, station.latitude,
|
||||
stationPointInRoute.longitude, stationPointInRoute.latitude,
|
||||
lastPointsPre.longitude, lastPointsPre.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength - calculateLineDistance
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 当前位置和 对应轨迹点的坐标距离
|
||||
// 需要加距离 和下一个轨迹点成钝角
|
||||
if (currentRouteIndex + 1 < stationPointInRouteIndex) {
|
||||
val currentPointsNext = mRoutePoints[currentRouteIndex + 1]
|
||||
val degree = getDegree(
|
||||
location.longitude, location.latitude,
|
||||
currentPoint.longitude, currentPoint.latitude,
|
||||
currentPointsNext.longitude, currentPointsNext.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength - calculateCurrentdex
|
||||
}
|
||||
}
|
||||
|
||||
// 需要减距离 和上一个轨迹点成钝角
|
||||
if (currentRouteIndex - 1 >= 0) {
|
||||
val lastPointsPre = mRoutePoints[currentRouteIndex - 1]
|
||||
val degree = getDegree(
|
||||
location.longitude, location.latitude,
|
||||
currentPoint.longitude, currentPoint.latitude,
|
||||
lastPointsPre.longitude, lastPointsPre.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength + calculateCurrentdex
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
} else {
|
||||
val lastPoints = mRoutePoints[stationPointInRouteIndex]
|
||||
lastSumLength = CoordinateUtils.calculateLineDistance(
|
||||
lastPoints.longitude, lastPoints.latitude,
|
||||
location.longitude, location.latitude
|
||||
)
|
||||
}
|
||||
return lastSumLength
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcjListCommon(
|
||||
mContext: Context?,
|
||||
models: List<MessagePad.Location>
|
||||
): List<LatLng> {
|
||||
//转成MogoLatLng集合
|
||||
val list: MutableList<LatLng> = ArrayList()
|
||||
for (m in models) {
|
||||
val mogoLatLng = coordinateConverterWgsToGcj(mContext, m)
|
||||
list.add(mogoLatLng)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcj(
|
||||
mContext: Context?,
|
||||
mogoLatLng: MessagePad.Location
|
||||
): LatLng {
|
||||
val mCoordinateConverter =
|
||||
CoordinateConverter(mContext)
|
||||
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS)
|
||||
mCoordinateConverter.coord(
|
||||
LatLng(
|
||||
mogoLatLng.latitude,
|
||||
mogoLatLng.longitude
|
||||
)
|
||||
)
|
||||
return mCoordinateConverter.convert()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcj(
|
||||
mContext: Context?,
|
||||
lon: Double,
|
||||
lat: Double
|
||||
): LatLng {
|
||||
val mCoordinateConverter =
|
||||
CoordinateConverter(mContext)
|
||||
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS)
|
||||
mCoordinateConverter.coord(LatLng(lat, lon))
|
||||
return mCoordinateConverter.convert()
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单粗暴 直接比较 todo 需要优化
|
||||
* @param mRoutePoints
|
||||
* @param realLon
|
||||
* @param realLat
|
||||
* @return
|
||||
*/
|
||||
fun getRemainPointListByCompare(
|
||||
mRoutePoints: List<LatLng>,
|
||||
realLon: Double,
|
||||
realLat: Double
|
||||
): List<LatLng> {
|
||||
val latePoints: MutableList<LatLng> = ArrayList()
|
||||
var currentIndex = 0 //记录疑似点
|
||||
if (mRoutePoints.size > 0) {
|
||||
//基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
if (baseLatLng != null) {
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, baseLatLng.longitude, baseLatLng.latitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in 1 until mRoutePoints.size) {
|
||||
val latLng = mRoutePoints[i]
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff) {
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+i+"-------先记录点----- ");
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+currentIndex+"-------是最近的点------ ");
|
||||
if (currentIndex == mRoutePoints.size - 1) {
|
||||
latePoints.add(mRoutePoints[currentIndex])
|
||||
} else if (currentIndex < mRoutePoints.size - 1) {
|
||||
latePoints.addAll(mRoutePoints.subList(currentIndex, mRoutePoints.size))
|
||||
}
|
||||
return latePoints
|
||||
}
|
||||
}
|
||||
return latePoints
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单粗暴 直接比较 todo 需要优化
|
||||
* @param mRoutePoints
|
||||
* @param realLon
|
||||
* @param realLat
|
||||
* @return 返回已经到达点的index
|
||||
*/
|
||||
fun getArrivedPointIndex(mRoutePoints: List<LatLng>, realLon: Double, realLat: Double): Int {
|
||||
var currentIndex = 0 //记录疑似点
|
||||
if (mRoutePoints.size > 0) {
|
||||
//基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
if (baseLatLng != null) {
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, baseLatLng.longitude, baseLatLng.latitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in 1 until mRoutePoints.size) {
|
||||
val latLng = mRoutePoints[i]
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff) {
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+i+"-------先记录点----- ");
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
return currentIndex
|
||||
}
|
||||
}
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
fun calculateRouteSumLengthByLocation(points: List<Location>?): Float {
|
||||
if (points.isNullOrEmpty()) return 0f
|
||||
var sumLength = 0f
|
||||
|
||||
//计算全路径总距离
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val preLat = points[i].latitude
|
||||
val preLon = points[i].longitude
|
||||
val laLat = points[i + 1].latitude
|
||||
val laLon = points[i + 1].longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
return sumLength
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcjLocations(
|
||||
mContext: Context?,
|
||||
models: List<MessagePad.Location>
|
||||
): MutableList<MogoLocation> {
|
||||
//转成MogoLatLng集合
|
||||
val list = mutableListOf<MogoLocation>()
|
||||
for (m in models) {
|
||||
val mogoLatLng = coordinateConverterWgsToGcj(mContext, m)
|
||||
val location = MogoLocation()
|
||||
location.heading = m.heading.toFloat().toDouble()
|
||||
location.latitude = mogoLatLng.latitude
|
||||
location.longitude = mogoLatLng.longitude
|
||||
list.add(location)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterLatlngToLocation(models: List<LatLng>): List<MogoLocation> {
|
||||
//转成MogoLatLng集合
|
||||
val list: MutableList<MogoLocation> = ArrayList()
|
||||
for (m in models) {
|
||||
val location = MogoLocation()
|
||||
location.latitude = m.latitude
|
||||
location.longitude = m.longitude
|
||||
list.add(location)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterLocationToLatLng(
|
||||
mContext: Context?,
|
||||
models: List<MogoLocation>
|
||||
): List<LatLng> {
|
||||
//转成MogoLatLng集合
|
||||
val list: MutableList<LatLng> = ArrayList()
|
||||
for (m in models) {
|
||||
val mogoLatLng = LatLng(m.latitude, m.longitude)
|
||||
list.add(mogoLatLng)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据前一个index,经纬度航向角,确认剩余轨迹
|
||||
* @param preIndex
|
||||
* @param mRoutePoints
|
||||
* @param realLocation
|
||||
* @return
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRemainPointListByCompareNew(
|
||||
preIndex: Int,
|
||||
mRoutePoints: List<MogoLocation>,
|
||||
realLocation: MogoLocation
|
||||
): Map<Int, List<MogoLocation>> {
|
||||
val routePonits: MutableMap<Int, List<MogoLocation>> = HashMap()
|
||||
val latePoints: MutableList<MogoLocation> = ArrayList() // 剩余轨迹集合
|
||||
var currentIndex = 0 //记录疑似点
|
||||
if (mRoutePoints.size > 0) {
|
||||
//基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude, baseLatLng.longitude, baseLatLng.longitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in mRoutePoints.indices) {
|
||||
val latLng = mRoutePoints[i]
|
||||
//todo 先看index对应点的方向和realLocation方向是否一致, 方向角度不能过90度
|
||||
if (realLocation.heading == realLocation.heading - latLng.heading ||
|
||||
Math.abs(realLocation.heading - latLng.heading) <= 90
|
||||
) {
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude,
|
||||
latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff) {
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.d("calculateRouteSumLength", "点:$currentIndex-------是最近的点------ ")
|
||||
if (currentIndex == mRoutePoints.size - 1) {
|
||||
val location = mRoutePoints[currentIndex]
|
||||
// LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||
latePoints.add(location)
|
||||
} else {
|
||||
val locations = mRoutePoints.subList(currentIndex, mRoutePoints.size)
|
||||
for (location in locations) {
|
||||
// LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||
latePoints.add(location)
|
||||
}
|
||||
}
|
||||
routePonits[currentIndex] = latePoints
|
||||
return routePonits
|
||||
}
|
||||
return routePonits
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getArrivedPointIndexNew(
|
||||
preIndex: Int, mRoutePoints: List<MogoLocation>,
|
||||
realLocation: MogoLocation
|
||||
): Int {
|
||||
var currentIndex = 0 //记录疑似点 //基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude, baseLatLng.longitude, baseLatLng.longitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in mRoutePoints.indices) {
|
||||
val latLng = mRoutePoints[i]
|
||||
if (realLocation.heading == realLocation.heading - latLng.heading ||
|
||||
Math.abs(realLocation.heading - latLng.heading) <= 90
|
||||
) {
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude,
|
||||
latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff && i > currentIndex) {
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.d("calculateRouteSumLength", "点:$currentIndex-------是最近的点------ ")
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getArrivedPointIndexNew(
|
||||
preIndex: Int, mRoutePoints: List<MogoLocation>,
|
||||
realLon: Double, realLat: Double
|
||||
): Int {
|
||||
var currentIndex = preIndex //记录疑似点 //基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLon,
|
||||
realLat, baseLatLng.longitude, baseLatLng.longitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in preIndex until mRoutePoints.size) {
|
||||
val latLng = mRoutePoints[i]
|
||||
// if (realLocation.getBearing() == realLocation.getBearing() - latLng.getBearing() ||
|
||||
// Math.abs(realLocation.getBearing() - latLng.getBearing()) <= 90){
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLon,
|
||||
realLat,
|
||||
latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff && i > currentIndex) {
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+i+"-------先记录点----- ");
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
// }
|
||||
}
|
||||
Logger.d("calculateRouteSumLength", "点:$currentIndex-------是最近的点------ ")
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* https://blog.csdn.net/Jeanne_0523/article/details/106056255
|
||||
* @param vertexPointX
|
||||
* @param vertexPointY
|
||||
* @param point0X 角
|
||||
* @param point0Y 角
|
||||
* @param point1X
|
||||
* @param point1Y
|
||||
* @return
|
||||
*/
|
||||
fun getDegree(
|
||||
vertexPointX: Double,
|
||||
vertexPointY: Double,
|
||||
point0X: Double,
|
||||
point0Y: Double,
|
||||
point1X: Double,
|
||||
point1Y: Double
|
||||
): Int {
|
||||
//向量的点乘
|
||||
val vector =
|
||||
(point0X - vertexPointX) * (point1X - vertexPointX) + (point0Y - vertexPointY) * (point1Y - vertexPointY)
|
||||
//向量的模乘
|
||||
val sqrt = Math.sqrt(
|
||||
(Math.abs((point0X - vertexPointX) * (point0X - vertexPointX)) + Math.abs((point0Y - vertexPointY) * (point0Y - vertexPointY)))
|
||||
* (Math.abs((point1X - vertexPointX) * (point1X - vertexPointX)) + Math.abs((point1Y - vertexPointY) * (point1Y - vertexPointY)))
|
||||
)
|
||||
//反余弦计算弧度
|
||||
val radian = Math.acos(vector / sqrt)
|
||||
//弧度转角度制
|
||||
return (180 * radian / Math.PI).toInt()
|
||||
}
|
||||
|
||||
private fun ball2xyz(thera: Double, fie: Double, r: Double): Triple<Double, Double, Double> {
|
||||
val x = r * cos(thera) * cos(fie)
|
||||
val y = r * cos(thera) * sin(fie)
|
||||
val z = r * sin(thera)
|
||||
return Triple(x, y, z)
|
||||
}
|
||||
|
||||
/**
|
||||
* https://blog.csdn.net/reborn_lee/article/details/82497577
|
||||
* 将地理经纬度转换成笛卡尔坐标系
|
||||
*/
|
||||
private fun geo2xyz(lat: Double, lng: Double): Triple<Double, Double, Double> {
|
||||
val thera = Math.PI * lat / 180
|
||||
val fie = Math.PI * lng / 180
|
||||
return ball2xyz(thera, fie, 6400.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算3个地理坐标点之间的夹角
|
||||
* @param l1 顶点坐标
|
||||
* @param l2
|
||||
* @param l3
|
||||
* @return l1为顶点的角度 精度没有angleOflocation高
|
||||
*/
|
||||
fun getDegree(l2: MogoLocation, l1: MogoLocation, l3: MogoLocation): Double {
|
||||
val (x1, y1, z1) = geo2xyz(l1.latitude, l1.longitude)
|
||||
val (x2, y2, z2) = geo2xyz(l2.latitude, l2.longitude)
|
||||
val (x3, y3, z3) = geo2xyz(l3.latitude, l3.longitude)
|
||||
|
||||
// 计算向量 P2P1 和 P2P3 的夹角 https://www.zybang.com/question/3379a30c0dd3041b3ef966803f0bf758.html
|
||||
val p1P2 = sqrt((x2 - x1).pow(2.0) + (y2 - y1).pow(2.0) + (z2 - z1).pow(2.0))
|
||||
val p2p3 = sqrt((x3 - x2).pow(2.0) + (y3 - y2).pow(2.0) + (z3 - z2).pow(2.0))
|
||||
val p = (x1 - x2) * (x3 - x2) + (y1 - y2) * (y3 - y2) + (z1 - z2) * (z3 - z2) //P2P1*P2P3
|
||||
return acos(p / (p1P2 * p2p3)) / Math.PI * 180
|
||||
}
|
||||
|
||||
fun getHeadingAngle(location: MogoLocation, nextPoint: MogoLocation): Double {
|
||||
return getHeadingAngle(
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
nextPoint.longitude,
|
||||
nextPoint.latitude
|
||||
)
|
||||
}
|
||||
|
||||
fun getHeadingAngle(location: LatLng, nextPoint: LatLng): Double {
|
||||
return getHeadingAngle(
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
nextPoint.longitude,
|
||||
nextPoint.latitude
|
||||
)
|
||||
}
|
||||
fun getHeadingAngle(locationLongitude: Double, locationLatitude: Double,
|
||||
nextPointLongitude: Double, nextPointLatitude: Double): Double {
|
||||
val y = sin(nextPointLongitude - locationLongitude) * cos(nextPointLatitude)
|
||||
val x = cos(locationLatitude) * sin(nextPointLatitude) - sin(locationLatitude) *
|
||||
cos(nextPointLatitude) * cos(nextPointLongitude - locationLongitude)
|
||||
var bearing = atan2(y, x)
|
||||
bearing = Math.toDegrees(bearing)
|
||||
if (bearing < 0) {
|
||||
bearing += 360.0
|
||||
}
|
||||
return 360-bearing
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 支持带航行角的和不带航向角的
|
||||
* 带航向角的会删除 航向角差大于90°的点
|
||||
* @param preIndex 上次计算缓存
|
||||
* @param mRoutePoints 轨迹点
|
||||
* @param location 目标坐标
|
||||
* @param type 1 开始站点 2 定位点 3 结束站点
|
||||
* @return Triple<Int,Boolean?,Float>
|
||||
* 距离目标坐标最近的轨迹点下标、
|
||||
* 最近点坐标是目标坐标的上一个点还是下一个点
|
||||
* 目标到最近轨迹点的距离
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNearestPointInfo(
|
||||
preIndex: Int,
|
||||
endIndex: Int,
|
||||
mRoutePoints: List<MogoLocation>,
|
||||
location: MogoLocation,
|
||||
type:Int,
|
||||
size:Int = 4,
|
||||
useHeading:Boolean = true,
|
||||
): Triple<Int,Boolean?,Float> {
|
||||
val startTime = System.currentTimeMillis()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"参数:[$preIndex $endIndex) mRoutePoints:${mRoutePoints.size} type:$type size:$size" +
|
||||
" location:(${location.latitude},${location.longitude},${location.heading})")
|
||||
var currentIndex:Int = preIndex //记录疑似点 //基础点
|
||||
// 轨迹中的点和定位点的距离集合
|
||||
val distanceMap: TreeMap<DistanceDegree, Int> = TreeMap()
|
||||
for (index in preIndex until endIndex) {
|
||||
val latLngIndex = mRoutePoints[index]
|
||||
val distance = CoordinateUtils.calculateLineDistance(
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
latLngIndex.longitude,
|
||||
latLngIndex.latitude
|
||||
)
|
||||
distanceMap[DistanceDegree.obtain(distance, null,null)] = index
|
||||
if (distanceMap.size > size) {
|
||||
distanceMap.pollLastEntry()?.key?.recycle()
|
||||
}
|
||||
}
|
||||
distanceMap.forEach {
|
||||
val distanceDegree = it.key
|
||||
val pointIndex = it.value
|
||||
val currentPoint = mRoutePoints[pointIndex]// 疑似最近的点
|
||||
var nextDegree = 0.0
|
||||
var preDegree = 0.0
|
||||
|
||||
if (pointIndex + 1 < mRoutePoints.size) {
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
nextDegree = getDegree(location, currentPoint, nextPoint)
|
||||
}else{
|
||||
nextDegree = 135.0
|
||||
}
|
||||
// 需要减距离 和上一个轨迹点成钝角
|
||||
if (pointIndex - 1 >= 0) {
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
preDegree = getDegree(
|
||||
location,
|
||||
currentPoint,
|
||||
prePoint
|
||||
)
|
||||
}else{// 第一个个点处理
|
||||
preDegree = 135.0
|
||||
}
|
||||
fun getDegreeNext(){
|
||||
if (pointIndex + 1 < mRoutePoints.size) {
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
val headingAngle = getHeadingAngle(currentPoint, nextPoint)
|
||||
distanceDegree.degree = headingAngle
|
||||
distanceDegree.isNext = false
|
||||
}else{
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
val headingAngle = getHeadingAngle(prePoint,currentPoint)
|
||||
distanceDegree.degree = headingAngle
|
||||
distanceDegree.isNext = true
|
||||
}
|
||||
}
|
||||
fun getDegreePre(){
|
||||
if (pointIndex - 1 >= 0) {
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
val headingAngle = getHeadingAngle(prePoint, currentPoint)
|
||||
distanceDegree.degree = headingAngle;
|
||||
distanceDegree.isNext = true
|
||||
}else{
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
val headingAngle = getHeadingAngle(currentPoint,nextPoint)
|
||||
distanceDegree.degree = headingAngle
|
||||
distanceDegree.isNext = false
|
||||
}
|
||||
}
|
||||
if(nextDegree>90){
|
||||
getDegreeNext()
|
||||
}
|
||||
if(preDegree>90){
|
||||
getDegreePre()
|
||||
}
|
||||
if(preDegree<90&&nextDegree<90&&preDegree+nextDegree>90){
|
||||
if (pointIndex + 1 < mRoutePoints.size&&pointIndex - 1 >= 0) {
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
val degree = getDegree(currentPoint, prePoint, nextPoint)
|
||||
if(degree>90) {
|
||||
getDegreePre()
|
||||
// isNext 值无所谓了 就 ture和false都行
|
||||
// 通过航向角过滤一遍
|
||||
if(distanceDegree.degree!=null&&DrivingDirectionUtils.getAngleDiff(location.heading, distanceDegree.degree!!)<90){
|
||||
currentIndex = pointIndex
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
return Triple(currentIndex,distanceDegree.isNext,distanceDegree.distance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据角度来排除一些点
|
||||
val iterator = distanceMap.iterator()
|
||||
// 有航向角比较航向角
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
val key = next.key
|
||||
if (key.degree == null) {
|
||||
key.recycle()
|
||||
iterator.remove()
|
||||
} else {
|
||||
if (location.heading != 0.0 && useHeading) {
|
||||
key.degree?.let {
|
||||
val dexAngle = DrivingDirectionUtils.getAngleDiff(location.heading, it)
|
||||
if (dexAngle > 90) {
|
||||
key.recycle()
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(distanceMap.size==0&&size<16){
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return getNearestPointInfo(preIndex,endIndex,mRoutePoints,location,type,size+2)
|
||||
}
|
||||
|
||||
// 最近点中包含上次计算的点和上次计算的最近的一个点
|
||||
if(distanceMap.containsValue(preIndex)&&distanceMap.containsValue(preIndex+1)&&type==1){
|
||||
var preIndexDistance:DistanceDegree?=null
|
||||
var preIndexNextDistance:DistanceDegree?=null
|
||||
distanceMap.iterator().forEach { en ->
|
||||
val key = en.key
|
||||
val value = en.value
|
||||
if(value==preIndex){
|
||||
preIndexDistance = key
|
||||
}else if(value==preIndex+1){
|
||||
preIndexNextDistance = key
|
||||
}
|
||||
}
|
||||
if(preIndexDistance!=null&&preIndexNextDistance!=null){
|
||||
if(preIndexDistance!!.distance<preIndexNextDistance!!.distance){
|
||||
currentIndex = preIndex
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,preIndexDistance?.isNext,preIndexDistance!!.distance)
|
||||
}else{
|
||||
currentIndex = preIndex+1
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,preIndexNextDistance?.isNext,preIndexNextDistance!!.distance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var maxIndex = 0
|
||||
var minIndex = Int.MAX_VALUE
|
||||
|
||||
distanceMap.iterator().forEach { en ->
|
||||
val value = en.value
|
||||
if(value<minIndex){
|
||||
minIndex = value
|
||||
}
|
||||
if(value>maxIndex){
|
||||
maxIndex = value
|
||||
}
|
||||
}
|
||||
|
||||
val middleVale =minIndex + (maxIndex-minIndex)/2
|
||||
when (type) {
|
||||
1 -> {// 求开始站点
|
||||
val iteratorRemove = distanceMap.iterator()
|
||||
while (iteratorRemove.hasNext()) {
|
||||
val next = iteratorRemove.next()
|
||||
val key = next.key
|
||||
if(next.value>middleVale){
|
||||
key.recycle()
|
||||
iteratorRemove.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
3 -> {// 求结束站点
|
||||
val iteratorRemove = distanceMap.iterator()
|
||||
while (iteratorRemove.hasNext()) {
|
||||
val next = iteratorRemove.next()
|
||||
val key = next.key
|
||||
if(next.value<middleVale){
|
||||
key.recycle()
|
||||
iteratorRemove.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
// 根据距离来计算 最近的点 只有一个前面的点
|
||||
var tempDistance = Float.MAX_VALUE
|
||||
var isNext:Boolean? = null
|
||||
distanceMap.iterator().forEach { en ->
|
||||
val key = en.key
|
||||
val value = en.value
|
||||
// 排除没有第一个值0是
|
||||
if(value==preIndex+1&&preIndex!=0&&type==1){
|
||||
currentIndex = value
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,key.isNext,key.distance)
|
||||
}
|
||||
key.distance.let {
|
||||
if (it < tempDistance) {
|
||||
tempDistance = it
|
||||
currentIndex = value
|
||||
isNext = key.isNext
|
||||
}
|
||||
}
|
||||
}
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,isNext,tempDistance)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import com.mogo.eagle.core.utilcode.util.DateTimeUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/5/6
|
||||
*/
|
||||
public class DateTimeUtil {
|
||||
public static final String HH_mm = "HH:mm";
|
||||
public static final String MM_dd = "MM-dd";
|
||||
public static final String MM_dd_HH_mm = "MM-dd HH:mm";
|
||||
public static final String yyyy_MM_dd = "yyyy-MM-dd";
|
||||
public static final String yyyyMMdd = "yyyy-MM-dd";
|
||||
public static final String yy_MM_dd = "yy.MM.dd";
|
||||
public static final String yyyy_MM_dd_HH_mm = "yyyy-MM-dd HH:mm";
|
||||
public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static String formatCalendarToString(Calendar calendar, String format){
|
||||
if (calendar == null) return "";
|
||||
try {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||
return dateFormat.format(calendar.getTime());
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static boolean compareDateIsCurrentDay(Calendar targetCalendar){
|
||||
Calendar currentCale = DateTimeUtils.getCurrentDateTime();
|
||||
String currentDay = formatCalendarToString(currentCale, yyyy_MM_dd);
|
||||
return currentDay.equals(formatCalendarToString(targetCalendar, yyyy_MM_dd));
|
||||
}
|
||||
|
||||
public static Calendar formatLongToCalendar(long time){
|
||||
Calendar calendar = null;
|
||||
try {
|
||||
calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(time);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return calendar;
|
||||
}
|
||||
public static String formatLongToString(long time, String format){
|
||||
try {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||
return dateFormat.format(time);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public static String getYMDTime(long time){//格式为 2021.8.21
|
||||
try {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(time);
|
||||
int month = calendar.get(Calendar.MONTH) + 1;
|
||||
return calendar.get(Calendar.YEAR)+"."+month+"."+ calendar.get(Calendar.DAY_OF_MONTH);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param seconds 60
|
||||
* @return 1 时
|
||||
*/
|
||||
public static String secondsToHourStr(long seconds){//秒数转成相应的 小时分钟数
|
||||
if (seconds >= 3600){
|
||||
int hours = (int)seconds/3600;
|
||||
return String.valueOf(hours);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param seconds 60
|
||||
* @return 1 时
|
||||
*/
|
||||
public static String secondsToMinuteStr(long seconds){//秒数转成相应的 小时分钟数
|
||||
int minute = (int)(seconds % 3600)/60;
|
||||
return String.valueOf(minute);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回当前时间
|
||||
* @return
|
||||
*/
|
||||
public static long getCurrentTimeStamp(){
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static long getTodayStartTime(){
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
|
||||
calendar.set(Calendar.HOUR_OF_DAY,0);
|
||||
calendar.set(Calendar.MINUTE,0);
|
||||
calendar.set(Calendar.SECOND,0);
|
||||
return calendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
public static String getAfterSecondTime(int timeInSecond,String formate){
|
||||
Calendar beforeTime = Calendar.getInstance();
|
||||
beforeTime.add(Calendar.SECOND, timeInSecond);
|
||||
return formatCalendarToString(beforeTime, formate);
|
||||
}
|
||||
public static String getAfterSecondTime(int timeInSecond){
|
||||
Calendar beforeTime = Calendar.getInstance();
|
||||
beforeTime.add(Calendar.SECOND, timeInSecond);
|
||||
return formatCalendarToString(beforeTime, DateTimeUtil.HH_mm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param second 秒
|
||||
* @description: 秒转换为时分秒 HH:mm:ss 格式 仅当小时数大于0时 展示HH
|
||||
*/
|
||||
public static String second2Time(Long second) {
|
||||
if (second == null || second < 0) {
|
||||
return "00:00";
|
||||
}
|
||||
|
||||
long h = second / 3600;
|
||||
long m = (long) Math.ceil((second % 3600) / 60.0);// 向上取整
|
||||
long s = second % 60;
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
if(m==60){
|
||||
m=0;
|
||||
h = h+1;
|
||||
}
|
||||
if (h > 0) {
|
||||
stringBuffer.append(h < 10 ? ("0" + h) : h).append(":");
|
||||
}else {
|
||||
stringBuffer.append("00:");
|
||||
}
|
||||
stringBuffer.append(m < 10 ? ("0" + m) : m);
|
||||
//str += (s < 10 ? ("0" + s) : s);
|
||||
return stringBuffer.toString();
|
||||
|
||||
}
|
||||
|
||||
public static String second2MMSS(Long second) {
|
||||
if (second == null || second < 0) {
|
||||
return "00:00";
|
||||
}
|
||||
long m = (long) Math.floor((second % 3600) / 60.0);// 向上取整
|
||||
long s = second % 60;
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
if (m > 0) {
|
||||
stringBuffer.append(m < 10 ? ("0" + m) : m).append(":");
|
||||
}else {
|
||||
stringBuffer.append("00:");
|
||||
}
|
||||
stringBuffer.append(s < 10 ? ("0" + s) : s);
|
||||
return stringBuffer.toString();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import android.content.res.Resources
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/1/21
|
||||
*/
|
||||
object DimenUtil{
|
||||
fun dp2px(value:Float):Float{
|
||||
return (0.5f + value * Resources.getSystem().displayMetrics.density)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public class FieldUtils {
|
||||
|
||||
public static Field getDeclaredField(final Class<?> cls, final String fieldName, final
|
||||
boolean forceAccess) {
|
||||
if (cls == null || TextUtils.isEmpty(fieldName)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// only consider the specified class by using getDeclaredField()
|
||||
final Field field = cls.getDeclaredField(fieldName);
|
||||
if (!isAccessible(field)) {
|
||||
if (forceAccess) {
|
||||
field.setAccessible(true);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return field;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isAccessible(final Member m) {
|
||||
return m != null && Modifier.isPublic(m.getModifiers()) && !m.isSynthetic();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
/**
|
||||
* @author aibingbing
|
||||
* @date: 2023/9/13
|
||||
* @desc Flow Bus
|
||||
*/
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* FlowBus消息总线
|
||||
*/
|
||||
object FlowBus {
|
||||
private const val TAG = "FlowBus"
|
||||
private val busMap = mutableMapOf<String, EventBus<*>>()
|
||||
private val busStickMap = mutableMapOf<String, StickEventBus<*>>()
|
||||
|
||||
@Synchronized
|
||||
fun <T> with(key: String): EventBus<T> {
|
||||
var eventBus = busMap[key]
|
||||
if (eventBus == null) {
|
||||
eventBus = EventBus<T>(key)
|
||||
busMap[key] = eventBus
|
||||
}
|
||||
return eventBus as EventBus<T>
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun <T> withStick(key: String): StickEventBus<T> {
|
||||
var eventBus = busStickMap[key]
|
||||
if (eventBus == null) {
|
||||
eventBus = StickEventBus<T>(key)
|
||||
busStickMap[key] = eventBus
|
||||
}
|
||||
return eventBus as StickEventBus<T>
|
||||
}
|
||||
|
||||
//真正实现类
|
||||
open class EventBus<T>(private val key: String) : LifecycleObserver {
|
||||
|
||||
//私有对象用于发送消息
|
||||
private val _events: MutableSharedFlow<T> by lazy {
|
||||
obtainEvent()
|
||||
}
|
||||
|
||||
//暴露的公有对象用于接收消息
|
||||
private val events = _events.asSharedFlow()
|
||||
|
||||
open fun obtainEvent(): MutableSharedFlow<T> =
|
||||
MutableSharedFlow(0, 1, BufferOverflow.DROP_OLDEST)
|
||||
|
||||
//主线程接收数据
|
||||
fun register(lifecycleOwner: LifecycleOwner, action: (t: T) -> Unit) {
|
||||
lifecycleOwner.lifecycle.addObserver(this)
|
||||
lifecycleOwner.lifecycleScope.launch {
|
||||
events.collect {
|
||||
try {
|
||||
action(it)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Log.e(TAG, "FlowBus - Error:$e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//协程中发送数据
|
||||
suspend fun post(event: T) {
|
||||
_events.emit(event)
|
||||
}
|
||||
|
||||
//主线程发送数据
|
||||
fun post(scope: CoroutineScope, event: T) {
|
||||
scope.launch {
|
||||
_events.emit(event)
|
||||
}
|
||||
}
|
||||
|
||||
//自动销毁
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
fun onDestroy() {
|
||||
Log.w(TAG, "FlowBus - 自动onDestroy")
|
||||
val subscriptCount = _events.subscriptionCount.value
|
||||
if (subscriptCount <= 0)
|
||||
busMap.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
class StickEventBus<T>(key: String) : EventBus<T>(key) {
|
||||
override fun obtainEvent(): MutableSharedFlow<T> =
|
||||
MutableSharedFlow(1, 1, BufferOverflow.DROP_OLDEST)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.widget.ImageView
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import java.lang.RuntimeException
|
||||
import java.lang.ref.SoftReference
|
||||
|
||||
class FrameAnimatorContainer (resId: Int,
|
||||
fps: Int,
|
||||
imageView: ImageView,
|
||||
sequence: Boolean = true,// 播放顺序 true 正序 false 倒序
|
||||
isOnce: Boolean = false,// 一次性的 true 值播放一次 false 重复播放
|
||||
initFirstFrame:Boolean = true,
|
||||
width:Int = -1,
|
||||
height:Int = -1){
|
||||
private val TAG = "FrameAnimatorContainer"
|
||||
private lateinit var mFrames: IntArray // 帧数组
|
||||
private var mIndex = 0 // 当前帧
|
||||
private var mShouldRun = false // 开始/停止播放用
|
||||
private var mIsRunning = false // 动画是否正在播放,防止重复播放
|
||||
private var mSoftReferenceImageView: SoftReference<ImageView>? = null // 软引用ImageView,以便及时释放掉
|
||||
private var mHandler: Handler? = null
|
||||
private var mDelayMillis = 0
|
||||
private var mOnAnimationStoppedListener: OnAnimationStoppedListener? = null//播放停止监听
|
||||
private var mBitmap: Bitmap? = null
|
||||
private var mBitmapOptions: BitmapFactory.Options? = null //Bitmap管理类,可有效减少Bitmap的OOM问题
|
||||
var isOnce:Boolean = false
|
||||
var sequence:Boolean = true
|
||||
|
||||
init {
|
||||
createAnimation(imageView, getData(resId), fps,initFirstFrame,width,height)
|
||||
this.isOnce = isOnce
|
||||
this.sequence = sequence
|
||||
}
|
||||
|
||||
private fun createAnimation(
|
||||
imageView: ImageView,
|
||||
frames: IntArray,
|
||||
fps: Int,
|
||||
initFirstFrame: Boolean,
|
||||
width: Int,
|
||||
height: Int
|
||||
) {
|
||||
mHandler = Handler(Looper.myLooper()!!)
|
||||
mFrames = frames
|
||||
mIndex = -1
|
||||
mSoftReferenceImageView = SoftReference(imageView)
|
||||
mShouldRun = false
|
||||
mIsRunning = false
|
||||
mDelayMillis = 1000 / fps //帧动画时间间隔,毫秒
|
||||
if(initFirstFrame) {
|
||||
imageView.setImageResource(mFrames[0])
|
||||
}
|
||||
var widthImage = -1
|
||||
var heightImage = -1
|
||||
var config = Bitmap.Config.ARGB_8888
|
||||
if(width>0&&height>0){
|
||||
widthImage = width
|
||||
heightImage = height
|
||||
}else{
|
||||
try {
|
||||
val bmp = (imageView.drawable as BitmapDrawable).bitmap
|
||||
widthImage = bmp.width
|
||||
heightImage = bmp.height
|
||||
config = bmp.config
|
||||
}catch (e:Exception){
|
||||
throw RuntimeException("请设置图片或传递大小")
|
||||
}
|
||||
}
|
||||
// 当图片大小类型相同时进行复用,避免频繁GC
|
||||
|
||||
mBitmap = Bitmap.createBitmap(widthImage, heightImage, config)
|
||||
mBitmapOptions = BitmapFactory.Options()
|
||||
//设置Bitmap内存复用
|
||||
mBitmapOptions!!.inBitmap = mBitmap //Bitmap复用内存块,类似对象池,避免不必要的内存分配和回收
|
||||
mBitmapOptions!!.inMutable = true //解码时返回可变Bitmap
|
||||
mBitmapOptions!!.inSampleSize = 1 //缩放比例
|
||||
}
|
||||
|
||||
//循环读取下一帧
|
||||
private val next: Int
|
||||
get() {
|
||||
mIndex++
|
||||
if (mIndex >= mFrames.size){
|
||||
mIndex = 0
|
||||
if(isOnce){// 一次性动画 播放完毕后直接结束
|
||||
stop()
|
||||
}
|
||||
}
|
||||
if(!sequence){// 倒叙
|
||||
return mFrames[mFrames.size-1-mIndex]
|
||||
}
|
||||
return mFrames[mIndex]
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun reStart(){
|
||||
mIndex = -1
|
||||
mIsRunning = false
|
||||
start()
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放动画,同步锁防止多线程读帧时,数据安全问题
|
||||
*/
|
||||
@Synchronized
|
||||
fun start() {
|
||||
mShouldRun = true
|
||||
if (mIsRunning) return
|
||||
mHandler?.removeCallbacksAndMessages(null)
|
||||
val runnable: Runnable = object : Runnable {
|
||||
override fun run() {
|
||||
val imageView = mSoftReferenceImageView!!.get()
|
||||
if (!mShouldRun || imageView == null) {
|
||||
mIsRunning = false
|
||||
if (mOnAnimationStoppedListener != null) {
|
||||
mOnAnimationStoppedListener!!.AnimationStopped()
|
||||
}
|
||||
return
|
||||
}
|
||||
mIsRunning = true
|
||||
//新开线程去读下一帧
|
||||
if (imageView.isShown) {
|
||||
val imageRes: Int = next
|
||||
if (!mShouldRun || imageView == null) {
|
||||
mIsRunning = false
|
||||
if (mOnAnimationStoppedListener != null) {
|
||||
mOnAnimationStoppedListener!!.AnimationStopped()
|
||||
}
|
||||
return
|
||||
}
|
||||
mHandler?.postDelayed(this, mDelayMillis.toLong())
|
||||
if (mBitmap != null) { // so Build.VERSION.SDK_INT >= 11
|
||||
var bitmap: Bitmap? = null
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeResource(
|
||||
imageView.resources,
|
||||
imageRes,
|
||||
mBitmapOptions
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (bitmap != null) {
|
||||
imageView.setImageBitmap(bitmap)
|
||||
} else {
|
||||
imageView.setImageResource(imageRes)
|
||||
mBitmap!!.recycle()
|
||||
mBitmap = null
|
||||
}
|
||||
} else {
|
||||
imageView.setImageResource(imageRes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mHandler!!.post(runnable)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放
|
||||
*/
|
||||
@Synchronized
|
||||
fun stop() {
|
||||
mShouldRun = false
|
||||
}
|
||||
|
||||
fun isPlaying():Boolean{
|
||||
return mShouldRun
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置停止播放监听
|
||||
* @param listener 设置监听
|
||||
*/
|
||||
fun setOnAnimStopListener(listener: OnAnimationStoppedListener?) {
|
||||
mOnAnimationStoppedListener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 从xml中读取帧数组
|
||||
* @param resId
|
||||
* @return
|
||||
*/
|
||||
fun getData(resId: Int): IntArray {
|
||||
val array = AbsMogoApplication.getApp().resources.obtainTypedArray(resId)
|
||||
val len = array.length()
|
||||
val intArray = IntArray(array.length())
|
||||
for (i in 0 until len) {
|
||||
intArray[i] = array.getResourceId(i, 0)
|
||||
}
|
||||
array.recycle()
|
||||
return intArray
|
||||
}
|
||||
|
||||
fun setData(mFrames: IntArray){
|
||||
this.mFrames = mFrames
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放监听
|
||||
*/
|
||||
interface OnAnimationStoppedListener {
|
||||
fun AnimationStopped()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/5/6
|
||||
*/
|
||||
public class NumberFormatUtil {
|
||||
/**
|
||||
* 有小数1位, 没有小数保留整数
|
||||
* @param d
|
||||
* @return
|
||||
*/
|
||||
public static String formatLong(double d) {
|
||||
BigDecimal bg = BigDecimal.valueOf(d).setScale(1, RoundingMode.HALF_UP);
|
||||
double num = bg.doubleValue();
|
||||
if (Math.ceil(num) - num == 0) {
|
||||
return String.valueOf((long) num);
|
||||
}
|
||||
return String.valueOf(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取小数点后cutNum位, 不进行四舍五入
|
||||
* @param num
|
||||
* @param cutNum
|
||||
* @return
|
||||
*/
|
||||
public static String cutOutNumber(double num,int cutNum){
|
||||
try{
|
||||
//注:将double类型转成String类型再处理截取。 使用double部分数据截取有问题
|
||||
BigDecimal bg = new BigDecimal(String.valueOf(num)).setScale(cutNum, RoundingMode.DOWN);
|
||||
return String.valueOf(bg.doubleValue());
|
||||
}catch (Exception e){
|
||||
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class OCHThreadPoolManager<T> {
|
||||
|
||||
/**
|
||||
* 根据cpu的数量动态的配置核心线程数和最大线程数
|
||||
*/
|
||||
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
|
||||
/**
|
||||
* 核心线程数 = CPU核心数 + 1
|
||||
*/
|
||||
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
|
||||
/**
|
||||
* 线程池最大线程数 = CPU核心数 * 2 + 1
|
||||
*/
|
||||
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
|
||||
/**
|
||||
* 非核心线程闲置时超时1s
|
||||
*/
|
||||
private static final int KEEP_ALIVE = 1;
|
||||
/**
|
||||
* 线程池的对象
|
||||
*/
|
||||
private ThreadPoolExecutor executor;
|
||||
|
||||
/**
|
||||
* 要确保该类只有一个实例对象,避免产生过多对象消费资源,所以采用单例模式
|
||||
*/
|
||||
private OCHThreadPoolManager() {
|
||||
}
|
||||
|
||||
private volatile static OCHThreadPoolManager INSTANCE;
|
||||
private static final byte[] obj = new byte[0];
|
||||
|
||||
public static OCHThreadPoolManager getsInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (obj) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new OCHThreadPoolManager();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启一个无返回结果的线程
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
if (executor == null) {
|
||||
/*
|
||||
* corePoolSize:核心线程数
|
||||
* maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
|
||||
* keepAliveTime:非核心线程闲置时间超时时长
|
||||
* unit:keepAliveTime的单位
|
||||
* workQueue:等待队列,存储还未执行的任务
|
||||
* threadFactory:线程创建的工厂
|
||||
* handler:异常处理机制
|
||||
*
|
||||
*/
|
||||
executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
|
||||
KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<>(200),
|
||||
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
|
||||
}
|
||||
// 把一个任务丢到了线程池中
|
||||
try {
|
||||
executor.execute(r);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启一个有返回结果的线程
|
||||
*/
|
||||
public Future<T> submit(Callable<T> r) {
|
||||
if (executor == null) {
|
||||
/*
|
||||
* corePoolSize:核心线程数
|
||||
* maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
|
||||
* keepAliveTime:非核心线程闲置时间超时时长
|
||||
* unit:keepAliveTime的单位
|
||||
* workQueue:等待队列,存储还未执行的任务
|
||||
* threadFactory:线程创建的工厂
|
||||
* handler:异常处理机制
|
||||
*
|
||||
*/
|
||||
executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
|
||||
KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20),
|
||||
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
|
||||
}
|
||||
// 把一个任务丢到了线程池中
|
||||
return executor.submit(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启一个无返回结果的线程
|
||||
*/
|
||||
public Future submit(Runnable r) {
|
||||
if (executor == null) {
|
||||
/*
|
||||
* corePoolSize:核心线程数
|
||||
* maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
|
||||
* keepAliveTime:非核心线程闲置时间超时时长
|
||||
* unit:keepAliveTime的单位
|
||||
* workQueue:等待队列,存储还未执行的任务
|
||||
* threadFactory:线程创建的工厂
|
||||
* handler:异常处理机制
|
||||
*
|
||||
*/
|
||||
executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
|
||||
KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<>(200),
|
||||
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
|
||||
}
|
||||
return executor.submit(r);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 把任务移除等待队列
|
||||
*/
|
||||
public void cancel(Runnable r) {
|
||||
if (r != null) {
|
||||
executor.getQueue().remove(r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.LocationManager;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2021/12/7
|
||||
*/
|
||||
public class PermissionUtil {
|
||||
|
||||
public static boolean checkPermission(Context context,String... permissons) {
|
||||
|
||||
for (String permisson : permissons) {
|
||||
if ((ContextCompat.checkSelfPermission(context,
|
||||
permisson) != PackageManager.PERMISSION_GRANTED)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isLocServiceEnable(Context context) {
|
||||
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
|
||||
if (gps || network) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.och.common.module.utils;
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2021/11/26
|
||||
*/
|
||||
public class PinYinUtil {
|
||||
/**
|
||||
* 得到中文字符串首字母
|
||||
* @param str 需要转化的中文字符串
|
||||
* @return 大写首字母缩写的字符串
|
||||
*/
|
||||
public static String getPinYinHeadChar(String str) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.mogo.och.common.module.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.EncodeHintType
|
||||
import com.google.zxing.common.BitMatrix
|
||||
import com.google.zxing.qrcode.QRCodeWriter
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* isDeleteWhite 是否删除白边
|
||||
*/
|
||||
fun createQRCode(address: String, width: Int, height: Int,isDeleteWhite: Boolean): Bitmap? {
|
||||
val hints = Hashtable<EncodeHintType, Any>()
|
||||
hints[EncodeHintType.CHARACTER_SET] = "utf-8"
|
||||
hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
|
||||
hints[EncodeHintType.MARGIN] = if (isDeleteWhite) 1 else 0
|
||||
var bitMatrix = QRCodeWriter().encode(
|
||||
address,
|
||||
BarcodeFormat.QR_CODE, width, height, hints
|
||||
)
|
||||
|
||||
if (isDeleteWhite) {
|
||||
//删除白边
|
||||
bitMatrix = deleteWhite(bitMatrix)
|
||||
}
|
||||
val widthNew = bitMatrix.width
|
||||
val heightNew = bitMatrix.height
|
||||
|
||||
val pixels = IntArray(widthNew * heightNew)
|
||||
//下面这里按照二维码的算法,逐个生成二维码的图片,
|
||||
//两个for循环是图片横列扫描的结果
|
||||
for (y in 0 until heightNew) {
|
||||
for (x in 0 until widthNew) {
|
||||
if (bitMatrix.get(x, y)) {
|
||||
pixels[y * widthNew + x] = -0x1000000
|
||||
} else {
|
||||
pixels[y * widthNew + x] = -0x1
|
||||
}
|
||||
}
|
||||
}
|
||||
//生成二维码图片的格式,使用ARGB_8888
|
||||
var bitmap = Bitmap.createBitmap(widthNew, heightNew, Bitmap.Config.ARGB_8888)
|
||||
bitmap.setPixels(pixels, 0, widthNew, 0, 0, widthNew, heightNew)
|
||||
return bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除白色边框
|
||||
*
|
||||
* @param matrix matrix
|
||||
* @return BitMatrix
|
||||
*/
|
||||
private fun deleteWhite(matrix: BitMatrix): BitMatrix? {
|
||||
val rec = matrix.enclosingRectangle
|
||||
val resWidth = rec[2] + 1
|
||||
val resHeight = rec[3] + 1
|
||||
val resMatrix = BitMatrix(resWidth, resHeight)
|
||||
resMatrix.clear()
|
||||
for (i in 0 until resWidth) {
|
||||
for (j in 0 until resHeight) {
|
||||
if (matrix[i + rec[0], j + rec[1]]) resMatrix[i] = j
|
||||
}
|
||||
}
|
||||
return resMatrix
|
||||
}
|
||||
|
||||
fun createQRCodeWithPicture(bmCenter: Bitmap,address: String, width: Int, height: Int,isDeleteWhite: Boolean): Bitmap?{
|
||||
var qrCode = createQRCode(address,width,height,isDeleteWhite)
|
||||
//8,创建一个bitmap对象用于作为其图标
|
||||
qrCode?.let {
|
||||
val resultBitmap = addLogo(it,bmCenter)
|
||||
if (resultBitmap != null){
|
||||
return resultBitmap
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于向创建的二维码中添加一个logo
|
||||
* @param bmQr
|
||||
* @param bmCenter
|
||||
* @return
|
||||
*/
|
||||
fun addLogo(bmQr: Bitmap, bmCenter:Bitmap) :Bitmap?{
|
||||
if (bmQr == null) {
|
||||
return null
|
||||
}
|
||||
if (bmCenter == null) {
|
||||
return bmQr
|
||||
}
|
||||
|
||||
//获取图片的宽高
|
||||
val bmQrWidth = bmQr.width
|
||||
val bmQrHeight = bmQr.height
|
||||
val bmCenterWidth = bmCenter.width
|
||||
val bmCenterHeight = bmCenter.height
|
||||
|
||||
var bitmap = Bitmap.createBitmap(bmQrWidth, bmQrHeight, Bitmap.Config.ARGB_8888)
|
||||
try {
|
||||
var canvas = Canvas(bitmap)
|
||||
canvas.drawBitmap(bmQr, 0f, 0f, null)
|
||||
canvas.drawBitmap(bmCenter, ((bmQrWidth-bmCenterWidth)/2-bmCenterWidth/2).toFloat(),
|
||||
((bmQrHeight-bmCenterHeight)/2-bmCenterHeight/2).toFloat(), null)
|
||||
|
||||
canvas.save()
|
||||
canvas.restore()
|
||||
} catch (e: Exception) {
|
||||
bitmap = null
|
||||
e.stackTrace
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user