You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

237 lines
8.2 KiB

package com.whitefish.ring
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.whitefish.app.bt.BleDevice
import com.whitefish.ring.bt.OnBleConnectionListener
import com.whitefish.ring.bt.OnBleScanCallback
import com.whitefish.ring.bean.ui.Device
import com.whitefish.ring.device.IDeviceManager
import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import lib.linktop.nexring.api.BATTERY_STATE_CHARGING
import lib.linktop.nexring.api.LOAD_DATA_EMPTY
import lib.linktop.nexring.api.LOAD_DATA_STATE_COMPLETED
import lib.linktop.nexring.api.LOAD_DATA_STATE_PROCESSING
import lib.linktop.nexring.api.LOAD_DATA_STATE_START
import lib.linktop.nexring.api.NexRingManager
import lib.linktop.nexring.api.OnSleepDataLoadListener
import lib.linktop.nexring.api.SleepData
class DeviceManager() : IDeviceManager(), OnBleConnectionListener, OnSleepDataLoadListener {
companion object{
const val STATE_DEVICE_CHARGING = 1
const val STATE_DEVICE_DISCHARGING = 0
const val STATE_DEVICE_DISCONNECTED = -3
const val STATE_DEVICE_CONNECTING = -2
const val STATE_DEVICE_CONNECTED = -1
}
private val app = Application.INSTANTS!!
private var isRegisterBattery = false
val batteryLevel = MutableLiveData(STATE_DEVICE_DISCONNECTED to 0)
private val sycProgress = MutableLiveData(0)
var isSyncingData: Boolean = false
private lateinit var context: Context
private val scope = CoroutineScope(Dispatchers.IO)
// var homeViewModel: demo.linktop.nexring.ui.HomeViewModel? = null
// var workoutDetailViewModel: demo.linktop.nexring.ui.workout.WorkoutDetailViewModel? = null
fun init(context: Context){
registerCb()
this.context = context
}
override fun onBleState(state: Int) {
bleStateListeners().forEach {
it.invoke(state)
}
when (state) {
BluetoothProfile.STATE_DISCONNECTED -> {
isRegisterBattery = false
batteryLevel.postValue(STATE_DEVICE_DISCONNECTED to 0)
}
BluetoothProfile.STATE_CONNECTED -> {
batteryLevel.postValue(STATE_DEVICE_CONNECTED to 0)
}
}
}
override fun onBleReady() {
bleReadyStateFlow.value = true
postDelay {
NexRingManager.get()
.deviceApi()
.getBatteryInfo {
if (it.state == BATTERY_STATE_CHARGING) {
batteryLevel.postValue(STATE_DEVICE_CHARGING to 0)
} else {
batteryLevel.postValue(STATE_DEVICE_DISCHARGING to it.level)
}
if (!isRegisterBattery) {
isRegisterBattery = true
postDelay {
NexRingManager.get()
.sleepApi()
.syncDataFromDev()
}
}
}
}
}
override fun onSyncDataFromDevice(state: Int, progress: Int) {
Napier.i(
"onSyncDataFromDevice state: $state, progress: $progress"
)
when (state) {
LOAD_DATA_EMPTY -> {
Napier.e("Empty data")
//TODO Callback when no data is received from the device.
}
LOAD_DATA_STATE_START -> {
isSyncingData = true
sycProgress.postValue(progress)
}
LOAD_DATA_STATE_PROCESSING -> sycProgress.postValue(progress)
LOAD_DATA_STATE_COMPLETED -> {
sycProgress.postValue(progress)
isSyncingData = false
//todo sync data complete
}
}
}
override fun onSyncDataError(errorCode: Int) {
context.cmdErrorTip(errorCode)
}
override fun onOutputNewSleepData(sleepData: ArrayList<SleepData>?) {
sleepData.also {
if (it.isNullOrEmpty()) {
Napier.i(
"onOutputNewSleepData NULL"
)
} else {
Napier.i(
"onOutputNewSleepData size ${it.size}"
)
it.forEachIndexed { index, data ->
Napier.i(
"onOutputNewSleepData $index sleep from ${data.startTs} to ${data.endTs}"
)
}
}
}
}
fun registerCb() {
app.bleManager.addOnBleConnectionListener(this)
NexRingManager.get().sleepApi().setOnSleepDataLoadListener(this)
}
fun unregisterCb() {
NexRingManager.get().sleepApi().setOnSleepDataLoadListener(null)
app.bleManager.removeOnBleConnectionListener(this)
}
override fun connect(address: String) {
with(app.bleManager) {
when (bleState.value) {
BluetoothProfile.STATE_DISCONNECTED -> {
batteryLevel.postValue(STATE_DEVICE_CONNECTING to 0)
if (!connect(address)) {
startScan(
20 * 1000L,
object : OnBleScanCallback {
override fun onScanning(result: BleDevice) {
if (result.device.address == address) {
connect(result.device)
}
}
override fun onScanFinished() {
}
})
}
}
BluetoothProfile.STATE_CONNECTED -> {
onBleState(bleState.value)
onBleReady()
}
}
}
}
override fun bind(onBound: () -> Unit) {
NexRingManager.get()
.deviceApi()
.getBindState {
if (it) {
//todo bind dialog
AlertDialog.Builder(context)
.setCancelable(false)
.setTitle(R.string.dialog_title_restricted_mode)
.setMessage(R.string.dialog_msg_restricted_mode)
.setNegativeButton(android.R.string.cancel) { _, _ ->
}.setPositiveButton(android.R.string.ok) { _, _ ->
onResetDeviceWhenBind.invoke()
NexRingManager.get()
.deviceApi()
.factoryReset()
}.create().show()
} else {
NexRingManager.get()
.deviceApi()
.bind {
onBound.invoke()
//todo bind result
}
}
}
}
override fun getCurrentMac(): String? {
return app.bleManager.connectedDevice?.address
}
override fun startScan() {
val bluetoothAdapter =
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
if (bluetoothAdapter.isEnabled) {
if (!app.bleManager.isScanning) {
app.bleManager.startScan(20 * 1000L,
object : OnBleScanCallback {
@SuppressLint("MissingPermission")
override fun onScanning(result: BleDevice) {
Napier.i("scanned device:${result}")
val newDevices = arrayListOf<Device>().apply {
addAll(_deviceList.value)
add(Device(result.device.name,result.device.address))
}
_deviceList.value = newDevices
}
override fun onScanFinished() {
}
})
}
}
}
override fun stopScan() {
}
}