[fix]
[蓝牙广播]
This commit is contained in:
yangyakun
2024-11-28 14:08:26 +08:00
parent ed91f30f39
commit f31d410610
7 changed files with 313 additions and 28 deletions

View File

@@ -0,0 +1,225 @@
package com.mogo.och.common.module.manager.bluetooth
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.bluetooth.le.BluetoothLeAdvertiser
import android.os.ParcelUuid
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.och.common.module.manager.bluetooth.bean.BleBroadCastData
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.utils.RxUtils
import io.reactivex.disposables.Disposable
import java.util.UUID
import kotlin.properties.Delegates
object AdvertisManager {
const val TAG ="AdvertisManager"
private var mBluetoothLeAdvertiser: BluetoothLeAdvertiser? = null // BLE广播
private var callbackListUsing = mutableListOf<AdvertiseCallbackWithData>() // BLE广播
private var callbackListUnUse = mutableListOf<AdvertiseCallbackWithData>() // BLE广播
private val waitBroadData = mutableListOf<BleBroadCastData>()
private var broadCastSite:Long by Delegates.observable(0) { _, oldValue, newValue ->
if (oldValue != newValue) {
// 停止广播
CallerLogger.d(TAG,"停止广播:站点切换停止广播")
closeAllBroadCast()
}
}
@SuppressLint("MissingPermission")
fun closeAllBroadCast(){
if (callbackListUsing.isEmpty()) {
return
}
callbackListUsing.forEach {
stopBroadCast(it)
}
callbackListUnUse.addAll(callbackListUsing)
callbackListUsing.clear()
}
@Synchronized
fun setBroadCastSites(broadCastSite:Long){
CallerLogger.d(TAG,"设置新的站点old:${this.broadCastSite}_new:$broadCastSite")
this.broadCastSite = broadCastSite
}
@SuppressLint("MissingPermission")
@Synchronized
fun startOneAd(data: BleBroadCastData?=null){
val tempData:BleBroadCastData
// data 为null 是上一个播放5s后要播放下一个等待播放的
if(data==null){
if(waitBroadData.isEmpty()){
return
}
val last = waitBroadData.last()
tempData = last
}else{
tempData = data
// 查找订单一样的广播替换数据
val sameData = findSampleOrderAndReplace(tempData)
if(sameData!=null){
CallerLogger.d(TAG,"停止广播:${tempData}")
if (sameData is BleBroadCastData) {
// 移除旧的离开播放新的
waitBroadData.remove(sameData)
CallerLogger.d(TAG,"移除待广播:有新的结果${tempData}")
}else if(sameData is AdvertiseCallbackWithData){
// 离开结束播放
sameData.close(false)
CallerLogger.d(TAG,"停止广播:有新的结果来进行广播${tempData}")
}
}
}
// 站点不一样 关闭所有的广播并设置新的站点id
if(tempData.siteId!= broadCastSite){
CallerLogger.d(TAG,"停止广播:站点切换停止广播_通过广播内容检测")
closeAllBroadCast()
waitBroadData.clear()
this.broadCastSite = tempData.siteId
}
// 来了新的广播 关闭播放时间最长的一个广播 并放入未使用列表
if(callbackListUsing.size>=5){
// 停止播放 播放时间最长的callback
val currentTime = System.currentTimeMillis()
var maxTime = 0L
var maxBroadCallback:AdvertiseCallbackWithData?=null
callbackListUsing.forEach {
val dex = currentTime - it.startTime
if(dex>maxTime){
maxBroadCallback = it
maxTime = dex
}
}
if(maxBroadCallback!=null){
// 添加到当前站点的待播放数据
maxBroadCallback?.close()
CallerLogger.d(TAG,"停止广播:有新的核销切当前广播数大于5${tempData}")
}else{
// 放到最后一位
waitBroadData.add(tempData)
return
}
}
var tempCallback:AdvertiseCallbackWithData?=null
// 未使用为空 创建一个新的callback
if (callbackListUnUse.isEmpty()) {
tempCallback = AdvertiseCallbackWithData(tempData)
} else {// 未使用不为空取出一个
tempCallback = callbackListUnUse.removeFirst()
tempCallback.dataInnser = tempData
}
//广播设置(必须)
val settings = AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) //广播模式: 低功耗,平衡,低延迟
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) //发射功率级别: 极低,低,中,高
.setConnectable(true) //能否连接,广播分为可连接广播和不可连接广播
.build()
//广播数据(必须,广播启动就会发送)
val advertiseData = AdvertiseData.Builder()
.setIncludeDeviceName(true) //包含蓝牙名称
.setIncludeTxPowerLevel(true) //包含发射功率级别
.build()
//扫描响应数据(可选,当客户端扫描时才发送)
val scanResponse = AdvertiseData.Builder()
.addServiceData(ParcelUuid(tempData.uuid), tempData.data.toByteArray()) //服务数据,自定义
.build()
if(mBluetoothLeAdvertiser == null) {
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
mBluetoothLeAdvertiser = bluetoothAdapter.bluetoothLeAdvertiser
}
mBluetoothLeAdvertiser?.startAdvertising(settings, advertiseData,scanResponse, tempCallback)
CallerLogger.d(TAG,"开始广播:广播数据${tempData}")
}
private fun findSampleOrderAndReplace(tempData: BleBroadCastData):Any? {
// 正在广播的
callbackListUsing.forEach {
if(isSampleOrder(it.dataInnser.uuid,tempData.uuid)){
return it
}
}
// 等待广播的
waitBroadData.forEach {
if(isSampleOrder(it.uuid,tempData.uuid)){
return it
}
}
return null
}
// 是否是同一个UU
fun isSampleOrder(oleUuid:UUID,newUUID: UUID): Boolean {
val oldOrderId = oleUuid.toString().substring(0,22)
val newOrderId = newUUID.toString().substring(0,22)
return oldOrderId==newOrderId
}
class AdvertiseCallbackWithData(val data:BleBroadCastData): AdvertiseCallback() {
var dataInnser = data
var broadCastDate: Disposable?=null
var startTime:Long = 0
@SuppressLint("MissingPermission")
override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
super.onStartSuccess(settingsInEffect)
callbackListUsing.add(this)
startTime = System.currentTimeMillis()
RxUtils.disposeSubscribe(broadCastDate)
broadCastDate = RxUtils.createSubscribe {
CallerLogger.d(TAG,"停止广播:${data}_播放了2s")
close()
startOneAd()
}
}
/**
* @param reUse 是否放入待播放中
*/
fun close(reUse: Boolean=true) {
RxUtils.disposeSubscribe(broadCastDate)
startTime = 0
callbackListUsing.remove(this)
if(callbackListUnUse.size + callbackListUsing.size<5) {
callbackListUnUse.add(this)
}
if(reUse) {
waitBroadData.add(0, dataInnser)
}
stopBroadCast(this)
}
override fun onStartFailure(errorCode: Int) {
super.onStartFailure(errorCode)
if(callbackListUnUse.size+ callbackListUsing.size<5) {
callbackListUnUse.add(this)
}
RxUtils.disposeSubscribe(broadCastDate)
OchChainLogManager.writeChainLogBluetooth("广播内容","广播失败")
}
}
@SuppressLint("MissingPermission")
fun stopBroadCast(callback:AdvertiseCallbackWithData){
if(mBluetoothLeAdvertiser == null) {
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
mBluetoothLeAdvertiser = bluetoothAdapter.bluetoothLeAdvertiser
}
mBluetoothLeAdvertiser?.stopAdvertising(callback)
CallerLogger.d(TAG,"停止广播:${callback.data}")
}
}

View File

@@ -8,6 +8,7 @@ import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.os.ParcelUuid
import android.util.Log
import com.mogo.och.common.module.manager.bluetooth.bean.BleBroadCastData
import com.mogo.och.common.module.utils.RxUtils
import java.util.UUID
@@ -143,4 +144,23 @@ object BleManager : BaseBluetoothManager() {
Log.d(TAG1, "链接超次 $ochBluetoothGattCallback scanList个数:${scanList}___sendDataIntDev个数:${sendDataIntDev}")
}
fun broadcast(data: String, businessTime: Long, orderNo: String, siteId: Long) {
val uuidStringNoSplit = "$orderNo${businessTime/100}$data"
val uuidString = uuidStringNoSplit.padEnd(32,'F')
val uuidWithDashes = uuidString.substring(0, 8) + "-" +
uuidString.substring(8, 12) + "-" +
uuidString.substring(12, 16) + "-" +
uuidString.substring(16, 20) + "-" +
uuidString.substring(20, 32) // 构造一个标准的 UUID 字符串
val uuid = UUID.fromString(uuidWithDashes)
AdvertisManager.startOneAd(BleBroadCastData(data,uuid,siteId))
}
fun setSiteId(siteId: Long){
AdvertisManager.setBroadCastSites(siteId)
}
}

View File

@@ -0,0 +1,6 @@
package com.mogo.och.common.module.manager.bluetooth.bean
import java.util.UUID
data class BleBroadCastData(val data:String, val uuid: UUID,val siteId: Long)

View File

@@ -97,7 +97,10 @@ data class WriteOffDetialMsg(
data class WriteOffResultMsg(
val code:Int,// 1成功 其他失败
val phone:String,// 手机号
val businessTime:Long
val orderNo: String,
val businessTime:Long,
val lineId:Long,
val siteId: Long
) : BaseDPMsg(DPMsgType.TYPE_WRITEOFF_INFO_RESULT.type)
data class WriteOffDevicesMsg(

View File

@@ -20,6 +20,8 @@ import com.mogo.och.common.module.biz.login.LoginStatusManager
import com.mogo.och.common.module.manager.autopilot.line.LineManager
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.manager.socket.lan.LanSocketManager
import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffResultMsg
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.common.module.utils.DateTimeUtil
import com.mogo.och.common.module.utils.ResourcesUtils
@@ -34,6 +36,7 @@ import com.mogo.och.weaknet.repository.db.bean.TaskDataBean
import com.mogo.och.weaknet.repository.db.bean.TaskSiteDataBean
import com.mogo.och.weaknet.repository.db.repository.EventDb
import com.mogo.och.weaknet.repository.RepositoryManager
import com.mogo.och.weaknet.repository.db.repository.SiteDb
import com.mogo.och.weaknet.repository.exception.DataException
import com.mogo.och.weaknet.util.ShuttleVoiceManager
import io.reactivex.Observer
@@ -253,6 +256,15 @@ object LineModel {
if (data) {
EventDb.saveEventTaskStart(taskId, lineId, taskTime, lineName)
OrderModel.queryBusRoutes()
BizLoopManager.runInIoThread{
val querySiteByLineId = SiteDb.querySiteByLineId(lineId)
querySiteByLineId?.forEach {
if (it.seq==1) {
LanSocketManager.sendMsgToClient(WriteOffResultMsg(-99, "","", System.currentTimeMillis(),LineManager.lineInfos?.lineId?:0,it.siteId?:0L))
}
return@forEach
}
}
mBusLinesCallbackMap.forEach {
it.value.onChangeLineIdSuccess()
}
@@ -283,6 +295,7 @@ object LineModel {
}
fun arrivedStationSuccess(){
LanSocketManager.sendMsgToClient(WriteOffResultMsg(-99, "","", System.currentTimeMillis(),LineManager.lineInfos?.lineId?:0,LineManager.getStations()?.first?.siteId?.toLong()?:0L))
mBusLinesCallbackMap.forEach {callback->
callback.value.onArriveStationSuccess()
}
@@ -332,6 +345,7 @@ object LineModel {
currentTask = null
LineManager.setLineInfo(null)
LineManager.setStartAndEndStation(null, null)
LanSocketManager.sendMsgToClient(WriteOffResultMsg(-99, "","", System.currentTimeMillis(),LineManager.lineInfos?.lineId?:0,LineManager.getStations()?.first?.siteId?.toLong()?:0L))
LineModel.callEyeMap(true)
stationList = mutableListOf()
startStationIndex = 0
@@ -366,6 +380,7 @@ object LineModel {
currentTask = null
LineManager.setLineInfo(null)
LineManager.setStartAndEndStation(null, null)
LanSocketManager.sendMsgToClient(WriteOffResultMsg(-99, "","", System.currentTimeMillis(),LineManager.lineInfos?.lineId?:0,LineManager.getStations()?.first?.siteId?.toLong()?:0L))
LineModel.callEyeMap(true)
stationList = mutableListOf()
startStationIndex = 0

View File

@@ -72,6 +72,7 @@ object TicketModel {
writeOffSuccess(
passenger.passengerSize,
passenger.phone ?: "",
"",
passenger.ticketName?:"",
0
)
@@ -160,7 +161,8 @@ object TicketModel {
sendMessage2Driver(
writeOffDetialMsg.msg ?: "",
writeOffDetialMsg.phone ?: "",
writeOffDetialMsg.code
writeOffDetialMsg.code,
writeOffDetialMsg.orderNo?:"",
)
} else {
RepositoryManager.writeOff(writeOffDetialMsg)
@@ -175,7 +177,7 @@ object TicketModel {
d(TAG, "receiveWrteOffDefailtInfo onError${e.printStackTrace()}")
if (e is DataException) {
CallerLogger.d(M_BUS_P + TAG, "核销失败 ${e.code}-----${e.msg}")
parseData(e.code,e.msg?:"",writeOffDetialMsg.phone?:"")
parseData(e.code,e.msg?:"",writeOffDetialMsg.phone?:"",writeOffDetialMsg.orderNo?:"")
}
}
@@ -188,6 +190,7 @@ object TicketModel {
writeOffSuccess(
data.ticketSize ?: 0,
data.phone ?: "",
writeOffDetialMsg.orderNo?:"",
data.ticketName ?: "",
data.businessTime?:System.currentTimeMillis(),
)
@@ -200,22 +203,22 @@ object TicketModel {
/**
* 解析错误原因
*/
private fun parseData(code:Int,msg:String,phone: String){
private fun parseData(code:Int,msg:String,phone: String,orderNo: String){
when (code) {
6002 -> sendMessage2Driver("同一订单核销间隔时间需大于2分钟", phone,6002)
1009 -> sendMessage2Driver("车票所选乘车日期非今日", phone,1009)
1005 -> sendMessage2Driver("车辆未登录、或没有任务", phone,1005)
1006 -> sendMessage2Driver("车票路线信息与当前车辆执行任务的路线信息不符合", phone,1006)
1008 -> sendMessage2Driver("车票剩余可用次数为0", phone,99)
6001 -> sendMessage2Driver("二维码已过期", phone,6001)
6003 -> sendMessage2Driver("车票站点信息与当前车辆执行任务的站点信息不符合", phone,6003)
1012 -> sendMessage2Driver("当前用户下单路线非当前的车辆所属公司", phone,1012)
6002 -> sendMessage2Driver("同一订单核销间隔时间需大于2分钟", phone,6002,orderNo)
1009 -> sendMessage2Driver("车票所选乘车日期非今日", phone,1009,orderNo)
1005 -> sendMessage2Driver("车辆未登录、或没有任务", phone,1005,orderNo)
1006 -> sendMessage2Driver("车票路线信息与当前车辆执行任务的路线信息不符合", phone,1006,orderNo)
1008 -> sendMessage2Driver("车票剩余可用次数为0", phone,99,orderNo)
6001 -> sendMessage2Driver("二维码已过期", phone,6001,orderNo)
6003 -> sendMessage2Driver("车票站点信息与当前车辆执行任务的站点信息不符合", phone,6003,orderNo)
1012 -> sendMessage2Driver("当前用户下单路线非当前的车辆所属公司", phone,1012,orderNo)
else -> {
try {
val tempcode=msg.toInt()
parseData(tempcode,msg,phone)
parseData(tempcode,msg,phone,orderNo)
}catch (e:Exception){
sendMessage2Driver(msg, phone,3002)
sendMessage2Driver(msg, phone,3002,orderNo)
}
}
}
@@ -227,9 +230,9 @@ object TicketModel {
* code 3002 司机屏校验失败原因未知
* code 99 小程序缓存丢失Android 缓存存在
*/
private fun sendMessage2Driver(message:String,phone:String,code:Int){
private fun sendMessage2Driver(message:String,phone:String,code:Int,orderNo: String){
// 发送乘客屏 通过蓝牙告知小程序
LanSocketManager.sendMsgToClient(WriteOffResultMsg(code = code, phone = phone, System.currentTimeMillis()))
LanSocketManager.sendMsgToClient(WriteOffResultMsg(code, phone,orderNo, System.currentTimeMillis(),LineManager.lineInfos?.lineId?:0,LineManager.getStations()?.first?.siteId?.toLong()?:0L))
val failedReason = "验票失败,${message}"
ShuttleVoiceManager.writeOffFaile(failedReason)
var tempPhone = phone
@@ -264,7 +267,7 @@ object TicketModel {
* 1、本地核销
* 2、云端核销
*/
private fun writeOffSuccess(ticketSize: Int, phone:String, ticketName:String,businessTime:Long) {
private fun writeOffSuccess(ticketSize: Int, phone:String,orderNo:String, ticketName:String,businessTime:Long) {
// 发送乘客屏 通过蓝牙告知小程序 为0时是 安全员小程序核销的
if(businessTime>0) {
@@ -272,7 +275,10 @@ object TicketModel {
WriteOffResultMsg(
code = 0,// 00成功
phone = phone,
businessTime = businessTime
orderNo = orderNo,
businessTime = businessTime,
LineManager.lineInfos?.lineId?:0L,
LineManager.getStations()?.first?.siteId?.toLong()?:0L
)
)
}

View File

@@ -1,7 +1,6 @@
package com.mogo.och.shuttle.weaknet.passenger.model
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
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.GsonUtils
@@ -36,15 +35,26 @@ object TicketModel : StateChangeListener {
// 收到核销结果扫描蓝牙并写会核销结果
obj?.phone?.let {phone->
val findDev = when (obj.code) {
99 -> {
BleManager.sendData2Wx(getBleName(phone),"99,${obj.businessTime}")
}
0 -> {
BleManager.sendData2Wx(getBleName(phone),"00,${obj.businessTime}")
}
else -> {
BleManager.sendData2Wx(getBleName(phone),"01,${obj.businessTime}")
}
99 -> {
BleManager.broadcast("99", obj.businessTime, obj.orderNo, obj.siteId)
BleManager.sendData2Wx(getBleName(phone), "99,${obj.businessTime}")
}
0 -> {
BleManager.broadcast("00", obj.businessTime, obj.orderNo, obj.siteId)
BleManager.sendData2Wx(getBleName(phone), "00,${obj.businessTime}")
}
-99 -> {
// 设置站点Id
BleManager.setSiteId(obj.siteId)
true
}
else -> {
BleManager.broadcast("01", obj.businessTime, obj.orderNo, obj.siteId)
BleManager.sendData2Wx(getBleName(phone), "01,${obj.businessTime}")
}
}
if(!findDev&&count<6){