[fea]
[核销、未通知小程序]
This commit is contained in:
yangyakun
2024-11-19 14:20:21 +08:00
parent da414503b9
commit 7db12ccbe7
15 changed files with 624 additions and 20 deletions

View File

@@ -1,6 +1,29 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.och.common.module">
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!--查找蓝牙设备-->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!--使当前设备可被其他蓝牙设备检测到-->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!--与已配对的蓝牙设备进行通讯-->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!--使用蓝牙扫描结果来推导物理位置-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application>
<activity
android:name=".wigets.media.MediaPlayerActivity"

View File

@@ -0,0 +1,87 @@
package com.mogo.och.common.module.manager.bluetooth
import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.ActivityCompat
import com.mogo.commons.AbsMogoApplication
import com.mogo.eagle.core.function.main.MainPresenter
import com.mogo.eagle.core.utilcode.mogo.permissions.PermissionsDialogUtils
import com.mogo.eagle.core.utilcode.util.ActivityUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.common.module.utils.PermissionUtil
open class BaseBluetoothManager {
protected var bluetoothAdapter: BluetoothAdapter? = null
protected var bluetoothManager: BluetoothManager? = null
private val REQUEST_ENABLE_BT = 10001
private val TAG = "OchBluetoothManager"
private var permissionlist = arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
)
enum class BluetoothState {
NONE, ON, OFF
}
init {
bluetoothManager = AbsMogoApplication.getApp().getSystemService(BluetoothManager::class.java)
bluetoothAdapter = bluetoothManager?.adapter
}
fun isEnable(): BluetoothState {
bluetoothAdapter?.let {
if (it.isEnabled) {
return BluetoothState.ON
} else {
return BluetoothState.OFF
}
}
ToastUtils.showShort("设备无蓝牙硬件")
return BluetoothState.NONE
}
fun requestPermission(){
if (PermissionUtil.checkPermission(AbsMogoApplication.getApp(), *permissionlist)) {
}else{
//申请悬浮窗权限
val shouldShowRequestPermissionRationale = ActivityUtils.getTopActivity()
.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
if(shouldShowRequestPermissionRationale){// 可以弹窗系统权限框
ActivityCompat.requestPermissions(
ActivityUtils.getTopActivity(),
permissionlist, MainPresenter.MOGO_PERMISSION_REQUEST_CODE
)
}else{// 不会弹系统弹窗
PermissionsDialogUtils.openAppDetails(ActivityUtils.getTopActivity(), "蓝牙", 100)
}
}
}
fun checkPermission():Boolean{
AbsMogoApplication.getApp()?.let {
permissionlist.forEach { permission->
val checkSelfPermission = ActivityCompat.checkSelfPermission(it, permission)
if (PackageManager.PERMISSION_GRANTED!=checkSelfPermission) {
return false
}
}
}
return true
}
}

View File

@@ -0,0 +1,19 @@
package com.mogo.och.common.module.manager.bluetooth
import android.bluetooth.BluetoothDevice
import android.bluetooth.le.ScanResult
data class BleDevItem(val dev: BluetoothDevice,val scanResult: ScanResult,val gattcallback:OchBluetoothGattCallback){
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BleDevItem
return dev.address == other.dev.address
}
override fun hashCode(): Int {
return dev.hashCode()
}
}

View File

@@ -0,0 +1,127 @@
package com.mogo.och.common.module.manager.bluetooth
import android.annotation.SuppressLint
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import com.mogo.och.common.module.manager.loop.BizLoopManager
import java.util.UUID
object BleManager : BaseBluetoothManager() {
val UUID_SERVICE: UUID = UUID.fromString("000018F0-0000-1000-8000-00805F9BDDFB") //自定义UUID
val UUID_CHAR_READ_NOTIFY: UUID = UUID.fromString("00002AF0-0000-1000-8000-00805F9BEEFB")
val UUID_DESC_NOTITY: UUID = UUID.fromString("00002AF1-0000-1000-8000-00805F9BCCFB")
val UUID_CHAR_WRITE: UUID = UUID.fromString("00002AF1-0000-1000-8000-00805F9BFFFB")
private var scanning = false
private val handler = Handler(Looper.getMainLooper())
private var bluetoothLeScanner: BluetoothLeScanner? = null
private val SCAN_PERIOD = 10000L
private const val TAG = "BleManager"
private val scanList = mutableListOf<BleDevItem>()
var listener: BleDevListener? = null
private val leScanCallback = object : ScanCallback(){
@SuppressLint("MissingPermission")
override fun onScanResult(callbackType: Int, result: ScanResult?) {
result?.let {
val device = it.device
it.rssi// 信号强度
it.scanRecord?.advertiseFlags
it.scanRecord?.serviceUuids
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
it.scanRecord?.serviceSolicitationUuids
}
it.scanRecord?.manufacturerSpecificData
it.scanRecord?.serviceData
it.scanRecord?.txPowerLevel
it.scanRecord?.deviceName
it.scanRecord?.manufacturerSpecificData
it.timestampNanos//
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
it.isLegacy
} else {
TODO("VERSION.SDK_INT < O")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
it.isLegacy//是否传统蓝牙
} else {
TODO("VERSION.SDK_INT < O")
}
it.primaryPhy
it.secondaryPhy
it.advertisingSid
it.txPower
it.periodicAdvertisingInterval
if(!it.device.name.isNullOrEmpty()){
val bleDevItem = BleDevItem(result.device, result,OchBluetoothGattCallback(result.device))
if(!scanList.contains(bleDevItem)){
scanList.add(bleDevItem)
}
Log.d(TAG, "callbackType:${callbackType}_____result:${result}")
listener?.dataChange(scanList)
}
}
}
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
Log.d(TAG, "results:${results}")
}
override fun onScanFailed(errorCode: Int) {
Log.d(TAG, "errorCode:${errorCode}")
}
}
fun scanLeDevice() {
when (isEnable()) {
BluetoothState.ON -> {}
else -> {
return
}
}
if(bluetoothLeScanner ==null){
bluetoothLeScanner = bluetoothAdapter?.bluetoothLeScanner
}
try {
if (!scanning) { // Stops scanning after a pre-defined scan period.
handler.postDelayed({
scanning = false
bluetoothLeScanner?.stopScan(leScanCallback)
}, SCAN_PERIOD)
scanning = true
bluetoothLeScanner?.startScan(leScanCallback)
scanList.clear()
listener?.dataChange(scanList)
} else {
scanning = false
bluetoothLeScanner?.stopScan(leScanCallback)
}
}catch (e:SecurityException){
e.printStackTrace()
}
}
interface BleDevListener{
fun dataChange(scanList:MutableList<BleDevItem>)
}
}

View File

@@ -0,0 +1,227 @@
package com.mogo.och.common.module.manager.bluetooth
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothProfile
import android.util.Log
import com.mogo.commons.AbsMogoApplication
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import java.util.UUID
import kotlin.properties.Delegates
@SuppressLint("MissingPermission")
class OchBluetoothGattCallback(device: BluetoothDevice) : BluetoothGattCallback() {
private val device = device
private var mBluetoothGatt: BluetoothGatt? = null
var connectListener: ConnectListener?=null
private val waitSendData = mutableMapOf<String,UUID>()
var isConnected:Boolean by Delegates.observable(false) { _, oldValue, newValue ->
if (oldValue != newValue) {
Log.i(TAG,"链接状态发生变化")
connectListener?.connectChangeListener()
}
}
private val TAG = "GattCallback"
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
val dev = gatt.device
Log.i(TAG, "onConnectionStateChange:${dev.name},${dev.address},${status},${newState},${dev.type}")
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
isConnected = true
gatt.discoverServices() //启动服务发现
} else {
isConnected = false
closeConn()
}
if(status==0){
if(newState==2){
Log.i(TAG,"与[${dev}]连接成功")
}else{
Log.i(TAG,"与[${dev}]连接断开")
}
}else{
Log.i(TAG,"与[${dev}]连接出错,错误码:$status")
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
Log.i(TAG,"onServicesDiscovered:${gatt.device.name},${gatt.device.address},${status}")
if (status == BluetoothGatt.GATT_SUCCESS) { //BLE服务发现成功
// 遍历获取BLE服务Services/Characteristics/Descriptors的全部UUID
for (service in gatt.services) {
val allUUIDs = StringBuilder(
"UUIDs={\n S=${service.uuid}".trimIndent()
)
for (characteristic in service.characteristics) {
allUUIDs.append(",\nC=").append(characteristic.uuid)
for (descriptor in characteristic.descriptors) {
allUUIDs.append(",\nD=").append(descriptor.uuid)
}
}
allUUIDs.append("}")
Log.i(TAG, "onServicesDiscovered:$allUUIDs")
}
// 链接成功 服务发现也成功后
waitSendData.forEach {
writeData2UUID(it.key,it.value)
}
}
}
override fun onCharacteristicRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
val uuid = characteristic.uuid
val valueStr = String(characteristic.value)
Log.i(TAG,"onCharacteristicRead:${gatt.device.name},${gatt.device.address},$uuid,$valueStr,$status")
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
val uuid = characteristic.uuid
val valueStr = String(characteristic.value)
Log.i(
TAG,
"onCharacteristicWrite:${gatt.device.name},${gatt.device.address},$uuid,$valueStr,$status"
)
if(status==BluetoothGatt.GATT_SUCCESS){
waitSendData.remove(valueStr)
closeConn()
connectListener?.sendDataSuccessAndCloseListener(device)
}
}
override fun onCharacteristicChanged(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
val uuid = characteristic.uuid
val valueStr = String(characteristic.value)
Log.i(TAG,"onCharacteristicChanged:${gatt.device.name},${ gatt.device.address},$uuid,$valueStr")
}
override fun onDescriptorRead(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
) {
val uuid = descriptor.uuid
val valueStr = descriptor.value.contentToString()
Log.i(TAG,"onDescriptorRead:${gatt.device.name},${gatt.device.address},$uuid,$valueStr,$status")
}
override fun onDescriptorWrite(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
) {
val uuid = descriptor.uuid
val valueStr = descriptor.value.contentToString()
Log.i(TAG,"onDescriptorWrite:${gatt.device.name},${gatt.device.address},$uuid,$valueStr,$status")
}
private fun refreshDeviceCache(mBluetoothGatt: BluetoothGatt?): Boolean {
if (mBluetoothGatt != null) {
try {
val refresh = mBluetoothGatt.javaClass.getMethod("refresh")
if (refresh != null) {
return refresh.invoke(mBluetoothGatt) as Boolean
}
} catch (e: Exception) {
e.printStackTrace()
}
}
return false
}
// BLE中心设备连接外围设备的数量有限(大概2~7个)在建立新连接之前必须释放旧连接资源否则容易出现连接错误133
fun closeConn() {
if (mBluetoothGatt != null) {
mBluetoothGatt!!.disconnect()
mBluetoothGatt!!.close()
refreshDeviceCache(mBluetoothGatt)
mBluetoothGatt = null
isConnected = false
}
}
// 获取Gatt服务
private fun getGattService(uuid: UUID): BluetoothGattService? {
if (!isConnected) {
return null
}
val service = mBluetoothGatt!!.getService(uuid)
if (service == null) ToastUtils.showShort("没有找到服务UUID=$uuid")
return service
}
// 注意连续频繁读写数据容易失败读写操作间隔最好200ms以上或等待上次回调完成后再进行下次读写操作
// 写入数据成功会回调->onCharacteristicWrite()
fun writeData2UUID(text:String,uuid: UUID){
OchChainLogManager.writeChainLogWriteOff("司机端核销成功","发送数据${text}")
val service = getGattService(BleManager.UUID_SERVICE)
if (service != null) {
val characteristic = service.getCharacteristic(uuid) //通过UUID获取可写的Characteristic
characteristic.setValue(text.toByteArray()) //单次最多20个字节
mBluetoothGatt!!.writeCharacteristic(characteristic)
}
}
// 注意连续频繁读写数据容易失败读写操作间隔最好200ms以上或等待上次回调完成后再进行下次读写操作
// 读取数据成功会回调->onCharacteristicChanged()
fun readDataByUUId(uuid: UUID){
val service = getGattService(BleManager.UUID_SERVICE)
if (service != null) {
val characteristic =
service.getCharacteristic(uuid) //通过UUID获取可读的Characteristic
mBluetoothGatt!!.readCharacteristic(characteristic)
}
}
fun notifyByUUID(uuid: UUID,notify:UUID){
// 设置通知Characteristic变化会回调->onCharacteristicChanged()
val service = getGattService(BleManager.UUID_SERVICE)
if (service != null) {
// 设置Characteristic通知
val characteristic =
service.getCharacteristic(BleManager.UUID_CHAR_READ_NOTIFY) //通过UUID获取可通知的Characteristic
mBluetoothGatt!!.setCharacteristicNotification(characteristic, true)
// 向Characteristic的Descriptor属性写入通知开关使蓝牙设备主动向手机发送数据
val descriptor = characteristic.getDescriptor(BleManager.UUID_DESC_NOTITY)
// descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);//和通知类似,但服务端不主动发数据,只指示客户端读取数据
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
mBluetoothGatt!!.writeDescriptor(descriptor)
}
}
fun connectGatt() {
if(isConnected){
ToastUtils.showShort("已连接成功")
writeData2UUID("1",BleManager.UUID_CHAR_WRITE)
}else {
mBluetoothGatt = device.connectGatt(AbsMogoApplication.getApp(), false, this)
waitSendData.put("1",BleManager.UUID_CHAR_WRITE)
}
}
interface ConnectListener{
fun connectChangeListener(){}
fun sendDataSuccessAndCloseListener(device: BluetoothDevice)
}
}

View File

@@ -26,6 +26,14 @@ object CheckVinManager : IMoGoAutopilotCarConfigListener {
checkVin()
}
fun getVin(): String {
var delineVin = CallerAutoPilotControlManager.getVIN()
if(delineVin.isEmpty()){
delineVin = LoginStatusManager.getLoginInfo()?.vin?:""
}
return delineVin
}
private fun checkVin() {
LoginStatusManager.getLoginInfo()?.let {loginInfo ->
val serverVin = loginInfo.vin

View File

@@ -58,10 +58,16 @@ object OchChainLogManager {
const val EVENT_KEY_INFO_DB = "analytics_event_och_db"
const val EVENT_KEY_INFO_WRITEOFF = "analytics_event_och_writeoff"
fun writeChainLogDb(title: String, info: String) {
writeChainLog(title, info, true, EVENT_KEY_INFO_DB)
}
fun writeChainLogWriteOff(title: String, info: String) {
writeChainLog(title, info, true, EVENT_KEY_INFO_WRITEOFF)
}
fun writeChainLogNet(mustUpdate: Boolean, title: String, info: String) {

View File

@@ -77,7 +77,7 @@ data class WriteOffDetialMsg(
val bookingTime: Long?=null,
val businessType: Int?=null,
val lineId: Long?=null,
val remainingTimes: Int?=null,//剩余票数
val availableTimes: Int?=null,//剩余票数
val orderNo: String?=null,
val uid: String?=null,
val phone: String?=null,