1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-15 21:24:10 +02:00

Refactor ScaleFactory and BluetoothScannerManager to use ScannedDeviceInfo

This commit is contained in:
oliexdev
2025-08-13 09:08:12 +02:00
parent b9203c8d5d
commit e5e670835a
3 changed files with 41 additions and 51 deletions

View File

@@ -17,6 +17,8 @@
*/ */
package com.health.openscale.core.bluetooth package com.health.openscale.core.bluetooth
import android.R.attr.identifier
import android.R.attr.name
import android.content.Context import android.content.Context
import android.util.SparseArray import android.util.SparseArray
import com.health.openscale.core.bluetooth.scales.DummyScaleHandler import com.health.openscale.core.bluetooth.scales.DummyScaleHandler
@@ -77,9 +79,7 @@ class ScaleFactory(
// List of modern Kotlin-based device handlers. // List of modern Kotlin-based device handlers.
// These are checked first for device compatibility. // These are checked first for device compatibility.
private val modernKotlinHandlers: List<ScaleDeviceHandler> = listOf( private val modernKotlinHandlers: List<ScaleDeviceHandler> = listOf(
DummyScaleHandler("Mi Scale"), // Recognizes devices with "Mi Scale" in their name DummyScaleHandler("Test") // Recognizes devices with "Test" in their name
DummyScaleHandler("Beurer"), // Recognizes devices with "Beurer" in their name
DummyScaleHandler("BF700") // Recognizes devices with "BF700" in their name
) )
/** /**
@@ -87,11 +87,20 @@ class ScaleFactory(
* This method contains the logic to map device names to specific Java driver classes. * This method contains the logic to map device names to specific Java driver classes.
* *
* @param context The application context. * @param context The application context.
* @param deviceName The name of the Bluetooth device. * @param deviceInfo Information about the scanned Bluetooth device.
* @return A [BluetoothCommunication] instance if a matching driver is found, otherwise null. * @return A [BluetoothCommunication] instance if a matching driver is found, otherwise null.
*/ */
private fun createLegacyJavaDriver(context: Context?, deviceName: String): BluetoothCommunication? { private fun createLegacyJavaDriver(context: Context?, deviceInfo: ScannedDeviceInfo): BluetoothCommunication? {
val name = deviceName.lowercase() val deviceName : String
val name : String
if (deviceInfo.name != null) {
deviceName = deviceInfo.name
name = deviceInfo.name.lowercase()
} else {
deviceName = deviceInfo.determinedHandlerDisplayName ?: "UnknownDevice"
name = deviceInfo.determinedHandlerDisplayName?.lowercase() ?: "UnknownDevice"
}
if (name.startsWith("BEURER BF700".lowercase()) if (name.startsWith("BEURER BF700".lowercase())
|| name.startsWith("BEURER BF800".lowercase()) || name.startsWith("BEURER BF800".lowercase())
@@ -256,11 +265,11 @@ class ScaleFactory(
* Creates a [ScaleCommunicator] using the legacy Java driver approach. * Creates a [ScaleCommunicator] using the legacy Java driver approach.
* It wraps a [BluetoothCommunication] instance (Java driver) in a [LegacyScaleAdapter]. * It wraps a [BluetoothCommunication] instance (Java driver) in a [LegacyScaleAdapter].
* *
* @param identifier The device name or other identifier used to find a legacy Java driver. * @param deviceInfo The device information used to find a legacy Java driver.
* @return A [LegacyScaleAdapter] instance if a suitable Java driver is found, otherwise null. * @return A [LegacyScaleAdapter] instance if a suitable Java driver is found, otherwise null.
*/ */
private fun createLegacyCommunicator(identifier: String): ScaleCommunicator? { private fun createLegacyCommunicator(deviceInfo: ScannedDeviceInfo): ScaleCommunicator? {
val javaDriverInstance = createLegacyJavaDriver(applicationContext, identifier) val javaDriverInstance = createLegacyJavaDriver(applicationContext, deviceInfo)
return if (javaDriverInstance != null) { return if (javaDriverInstance != null) {
LogManager.i(TAG, "Creating LegacyScaleAdapter with Java driver '${javaDriverInstance.javaClass.simpleName}'.") LogManager.i(TAG, "Creating LegacyScaleAdapter with Java driver '${javaDriverInstance.javaClass.simpleName}'.")
LegacyScaleAdapter( LegacyScaleAdapter(
@@ -269,7 +278,7 @@ class ScaleFactory(
databaseRepository = databaseRepository databaseRepository = databaseRepository
) )
} else { } else {
LogManager.w(TAG, "Could not create LegacyScaleAdapter: No Java driver found for '$identifier'.") LogManager.w(TAG, "Could not create LegacyScaleAdapter: No Java driver found for '${deviceInfo.name}'.")
null null
} }
} }
@@ -332,12 +341,10 @@ class ScaleFactory(
LogManager.d(TAG, "No modern Kotlin handler actively claimed '${primaryIdentifier}' or could create a communicator.") LogManager.d(TAG, "No modern Kotlin handler actively claimed '${primaryIdentifier}' or could create a communicator.")
// 2. Fallback to legacy adapter if no modern handler matched or created a communicator. // 2. Fallback to legacy adapter if no modern handler matched or created a communicator.
// The device name (or a specific legacy handler name, if known from `determinedHandlerDisplayName`) is used. LogManager.i(TAG, "Attempting fallback to legacy adapter for identifier '${deviceInfo.name}'.")
val identifierForLegacy = deviceInfo.determinedHandlerDisplayName ?: primaryIdentifier val legacyCommunicator = createLegacyCommunicator(deviceInfo)
LogManager.i(TAG, "Attempting fallback to legacy adapter for identifier '${identifierForLegacy}'.")
val legacyCommunicator = createLegacyCommunicator(identifierForLegacy)
if (legacyCommunicator != null) { if (legacyCommunicator != null) {
LogManager.i(TAG, "Legacy communicator '${legacyCommunicator.javaClass.simpleName}' created for device (identifier: '${identifierForLegacy}').") LogManager.i(TAG, "Legacy communicator '${legacyCommunicator.javaClass.simpleName}' created for device ('${deviceInfo.name}').")
return legacyCommunicator return legacyCommunicator
} }
@@ -349,39 +356,26 @@ class ScaleFactory(
* Checks if any known handler (modern Kotlin or legacy Java-based) can theoretically support the given device. * Checks if any known handler (modern Kotlin or legacy Java-based) can theoretically support the given device.
* This can be used by the UI to indicate if a device is potentially recognizable. * This can be used by the UI to indicate if a device is potentially recognizable.
* *
* @param deviceName The name of the Bluetooth device. * @param deviceInfo Information about the scanned Bluetooth device.
* @param deviceAddress The MAC address of the device.
* @param serviceUuids A list of advertised service UUIDs.
* @param manufacturerData Manufacturer-specific data from the advertisement.
* @return A Pair where `first` is true if a handler is found, and `second` is the name of the handler/driver, or null. * @return A Pair where `first` is true if a handler is found, and `second` is the name of the handler/driver, or null.
*/ */
fun getSupportingHandlerInfo( fun getSupportingHandlerInfo(deviceInfo : ScannedDeviceInfo): Pair<Boolean, String?> {
deviceName: String?,
deviceAddress: String,
serviceUuids: List<UUID>,
manufacturerData: SparseArray<ByteArray>?
): Pair<Boolean, String?> {
val primaryIdentifier = deviceName ?: "UnknownDevice"
// LogManager.d(TAG, "getSupportingHandlerInfo for: '$primaryIdentifier', Addr: $deviceAddress, UUIDs: ${serviceUuids.size}, ManuData: ${manufacturerData != null}")
// Check modern handlers first // Check modern handlers first
for (handler in modernKotlinHandlers) { for (handler in modernKotlinHandlers) {
if (handler.canHandleDevice(deviceName, deviceAddress, serviceUuids, manufacturerData)) { if (handler.canHandleDevice(deviceInfo.name, deviceInfo.address, deviceInfo.serviceUuids, deviceInfo.manufacturerData)) {
// LogManager.d(TAG, "getSupportingHandlerInfo: Modern handler '${handler.getDriverName()}' matches '$primaryIdentifier'.")
return true to handler.getDriverName() // The "driver name" of the modern handler return true to handler.getDriverName() // The "driver name" of the modern handler
} }
} }
// Then check if a legacy driver would exist based on the name // Then check if a legacy driver would exist based on the name
if (deviceName != null) { if (deviceInfo.name != null) {
val legacyJavaDriver = createLegacyJavaDriver(applicationContext, deviceName) val legacyJavaDriver = createLegacyJavaDriver(applicationContext, deviceInfo)
if (legacyJavaDriver != null) { if (legacyJavaDriver != null) {
// LogManager.d(TAG, "getSupportingHandlerInfo: Legacy driver '${legacyJavaDriver.javaClass.simpleName}' matches '$deviceName'.")
// Return the driver name from the BluetoothCommunication interface if available and meaningful. // Return the driver name from the BluetoothCommunication interface if available and meaningful.
return true to legacyJavaDriver.driverName() // Assumes BluetoothCommunication has a driverName() method. return true to legacyJavaDriver.driverName() // Assumes BluetoothCommunication has a driverName() method.
} }
} }
LogManager.d(TAG, "getSupportingHandlerInfo: No supporting handler found for '$primaryIdentifier'.") LogManager.d(TAG, "getSupportingHandlerInfo: No supporting handler found for ${deviceInfo.name}.")
return false to null return false to null
} }
} }

View File

@@ -250,23 +250,21 @@ class BluetoothScannerManager(
val serviceUuids: List<UUID> = scanResult.scanRecord?.serviceUuids?.mapNotNull { it?.uuid } ?: emptyList() val serviceUuids: List<UUID> = scanResult.scanRecord?.serviceUuids?.mapNotNull { it?.uuid } ?: emptyList()
val manufacturerData: SparseArray<ByteArray>? = scanResult.scanRecord?.manufacturerSpecificData val manufacturerData: SparseArray<ByteArray>? = scanResult.scanRecord?.manufacturerSpecificData
val (isSupported, handlerName) = scaleFactory.getSupportingHandlerInfo(
deviceName = deviceName,
deviceAddress = deviceAddress,
serviceUuids = serviceUuids,
manufacturerData = manufacturerData
)
val newDevice = ScannedDeviceInfo( val newDevice = ScannedDeviceInfo(
name = deviceName, name = deviceName,
address = deviceAddress, address = deviceAddress,
rssi = rssi, rssi = rssi,
serviceUuids = serviceUuids, serviceUuids = serviceUuids,
manufacturerData = manufacturerData, manufacturerData = manufacturerData,
isSupported = isSupported, isSupported = false, // will be determined in the next getSupportingHandlerInfo
determinedHandlerDisplayName = handlerName determinedHandlerDisplayName = null // // will be determined in the next getSupportingHandlerInfo
) )
val (isSupported, handlerName) = scaleFactory.getSupportingHandlerInfo(newDevice)
newDevice.isSupported = isSupported
newDevice.determinedHandlerDisplayName = handlerName
val existingDevice = deviceMap[newDevice.address] val existingDevice = deviceMap[newDevice.address]
var listShouldBeUpdated = false var listShouldBeUpdated = false

View File

@@ -344,12 +344,6 @@ class BluetoothViewModel(
// For a saved device, we need to re-evaluate its support status using ScaleFactory, // For a saved device, we need to re-evaluate its support status using ScaleFactory,
// as supported handlers might change with app updates. // as supported handlers might change with app updates.
LogManager.d(TAG, "Re-evaluating support for saved device '$name' ($address) using ScaleFactory.") LogManager.d(TAG, "Re-evaluating support for saved device '$name' ($address) using ScaleFactory.")
val (isPotentiallySupported, handlerNameFromFactory) = scaleFactory.getSupportingHandlerInfo(
deviceName = name,
deviceAddress = address,
serviceUuids = emptyList(), // Service UUIDs are unknown without a fresh scan.
manufacturerData = null // Manufacturer data is unknown without a fresh scan.
)
val deviceInfoForConnect = ScannedDeviceInfo( val deviceInfoForConnect = ScannedDeviceInfo(
name = name, name = name,
@@ -357,10 +351,14 @@ class BluetoothViewModel(
rssi = 0, // RSSI is not relevant for a direct connection attempt to a saved device. rssi = 0, // RSSI is not relevant for a direct connection attempt to a saved device.
serviceUuids = emptyList(), serviceUuids = emptyList(),
manufacturerData = null, manufacturerData = null,
isSupported = isPotentiallySupported, // Use current support assessment. isSupported = false, // will be determined by getSupportingHandlerInfo
determinedHandlerDisplayName = handlerNameFromFactory determinedHandlerDisplayName = null // will be determined by getSupportingHandlerInfo
) )
val (isPotentiallySupported, handlerNameFromFactory) = scaleFactory.getSupportingHandlerInfo(deviceInfoForConnect)
deviceInfoForConnect.isSupported = isPotentiallySupported
deviceInfoForConnect.determinedHandlerDisplayName = handlerNameFromFactory
if (!deviceInfoForConnect.isSupported) { if (!deviceInfoForConnect.isSupported) {
LogManager.w(TAG, "Saved device '$name' ($address) is currently not supported by ScaleFactory. Connection aborted.") LogManager.w(TAG, "Saved device '$name' ($address) is currently not supported by ScaleFactory. Connection aborted.")
// This error is specific to connecting to a *saved* device that's no longer supported. // This error is specific to connecting to a *saved* device that's no longer supported.