Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
id("com.android.application")
id("com.google.dagger.hilt.android")
Expand Down Expand Up @@ -52,7 +54,7 @@ android {

kotlin {
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
jvmTarget.set(JvmTarget.JVM_17)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import kotlinx.coroutines.flow.asStateFlow
class BluetoothDiscoveryManager
@Inject
constructor(
@ApplicationContext private val appContext: Context,
@param:ApplicationContext private val appContext: Context,
private val logManager: LogManager,
) {
private val discoveredDevices = linkedMapOf<String, DeviceInfo>()
Expand Down Expand Up @@ -128,14 +128,13 @@ class BluetoothDiscoveryManager
}
}

fun isBluetoothEnabled(): Boolean {
return try {
fun isBluetoothEnabled(): Boolean =
try {
@Suppress("DEPRECATION")
BluetoothAdapter.getDefaultAdapter()?.isEnabled == true
} catch (_: SecurityException) {
false
}
}

fun isLocationServicesEnabledForDiscovery(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Expand Down Expand Up @@ -165,11 +164,12 @@ class BluetoothDiscoveryManager
return Result.failure(error)
}

val adapter = BluetoothAdapter.getDefaultAdapter() ?: run {
val error = Exception("Bluetooth not available")
_discoveryState.value = DiscoveryState.Error(error.message ?: "Bluetooth not available")
return Result.failure(error)
}
val adapter =
BluetoothAdapter.getDefaultAdapter() ?: run {
val error = Exception("Bluetooth not available")
_discoveryState.value = DiscoveryState.Error(error.message ?: "Bluetooth not available")
return Result.failure(error)
}

if (!adapter.isEnabled) {
val error = Exception("Bluetooth is disabled")
Expand Down Expand Up @@ -243,8 +243,9 @@ class BluetoothDiscoveryManager
return Result.failure(error)
}

val adapter = BluetoothAdapter.getDefaultAdapter()
?: return Result.failure(Exception("Bluetooth not available"))
val adapter =
BluetoothAdapter.getDefaultAdapter()
?: return Result.failure(Exception("Bluetooth not available"))

if (!adapter.isEnabled) {
return Result.failure(Exception("Bluetooth is disabled"))
Expand Down Expand Up @@ -366,29 +367,26 @@ class BluetoothDiscoveryManager
unregisterReceiverIfNeeded()
}

private fun hasDiscoveryPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
private fun hasDiscoveryPermission(): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
hasBluetoothScanPermission() && hasBluetoothConnectPermission()
} else {
hasLocationPermission()
}
}

private fun hasBluetoothScanPermission(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
private fun hasBluetoothScanPermission(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
ContextCompat.checkSelfPermission(
appContext,
Manifest.permission.BLUETOOTH_SCAN,
) == PackageManager.PERMISSION_GRANTED
}

private fun hasBluetoothConnectPermission(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
private fun hasBluetoothConnectPermission(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
ContextCompat.checkSelfPermission(
appContext,
Manifest.permission.BLUETOOTH_CONNECT,
) == PackageManager.PERMISSION_GRANTED
}

private fun hasLocationPermission(): Boolean {
val fineLocationGranted =
Expand All @@ -406,11 +404,10 @@ class BluetoothDiscoveryManager
}

@Suppress("DEPRECATION")
private fun Intent.extractBluetoothDevice(): BluetoothDevice? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
private fun Intent.extractBluetoothDevice(): BluetoothDevice? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice::class.java)
} else {
getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import kotlinx.coroutines.withContext
class BluetoothTransport
@Inject
constructor(
@ApplicationContext private val appContext: Context,
@param:ApplicationContext private val appContext: Context,
) : ObdTransport {
private var socket: BluetoothSocket? = null
private var inputStream: InputStream? = null
Expand Down Expand Up @@ -79,25 +79,21 @@ class BluetoothTransport
}
}

private fun hasBluetoothConnectPermission(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
private fun hasBluetoothConnectPermission(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
ContextCompat.checkSelfPermission(
appContext,
Manifest.permission.BLUETOOTH_CONNECT,
) == PackageManager.PERMISSION_GRANTED
}

private fun hasBluetoothScanPermission(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
private fun hasBluetoothScanPermission(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
ContextCompat.checkSelfPermission(
appContext,
Manifest.permission.BLUETOOTH_SCAN,
) == PackageManager.PERMISSION_GRANTED
}

override fun isConnected(): Boolean {
return socket?.isConnected == true
}
override fun isConnected(): Boolean = socket?.isConnected == true

override fun getInputStream(): InputStream? = inputStream

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ class DtcParser
} else {
decodeFromHex(chunk)
}
}
.distinct()
}.distinct()
}

fun descriptionFor(code: String): String = "Diagnostic Trouble Code $code"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,24 +72,16 @@ class LogExportFormatter
}
}

fun buildDefaultFileName(nowMillis: Long = System.currentTimeMillis()): String {
return "obd-debug-log-${formatFileNameDate(nowMillis)}.txt"
}
fun buildDefaultFileName(nowMillis: Long = System.currentTimeMillis()): String = "obd-debug-log-${formatFileNameDate(nowMillis)}.txt"

private fun formatExportDate(timestampMillis: Long): String {
return exportDateFormat.get()?.format(Date(timestampMillis)).orEmpty()
}
private fun formatExportDate(timestampMillis: Long): String = exportDateFormat.get()?.format(Date(timestampMillis)).orEmpty()

private fun formatFileNameDate(timestampMillis: Long): String {
return fileNameDateFormat.get()?.format(Date(timestampMillis)).orEmpty()
}
private fun formatFileNameDate(timestampMillis: Long): String = fileNameDateFormat.get()?.format(Date(timestampMillis)).orEmpty()

private fun formatEventTime(timestampMillis: Long): String {
return eventTimeFormat.get()?.format(Date(timestampMillis)).orEmpty()
}
private fun formatEventTime(timestampMillis: Long): String = eventTimeFormat.get()?.format(Date(timestampMillis)).orEmpty()

private fun formatTelemetryEvent(event: TelemetryEvent): String {
return when (event) {
private fun formatTelemetryEvent(event: TelemetryEvent): String =
when (event) {
is CommandTelemetry ->
buildString {
append(formatEventTime(event.finishedAtMs))
Expand Down Expand Up @@ -124,9 +116,6 @@ class LogExportFormatter
append(" value=${sanitizeMessage(event.value)}")
}
}
}

private fun sanitizeMessage(message: String): String {
return message.replace("\n", "\\n")
}
private fun sanitizeMessage(message: String): String = message.replace("\n", "\\n")
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,12 @@ class LogExportRepositoryImpl
logs: List<DebugLogEntry>,
telemetryEvents: List<TelemetryEvent>,
exportedAtMillis: Long,
): String {
return formatter.buildExportText(logs, telemetryEvents, exportedAtMillis)
}
): String = formatter.buildExportText(logs, telemetryEvents, exportedAtMillis)

override fun buildDefaultFileName(nowMillis: Long): String {
return formatter.buildDefaultFileName(nowMillis)
}
override fun buildDefaultFileName(nowMillis: Long): String = formatter.buildDefaultFileName(nowMillis)

override suspend fun export(
destination: String,
content: String,
): Result<Unit> {
return exporter.export(Uri.parse(destination), content)
}
): Result<Unit> = exporter.export(Uri.parse(destination), content)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import kotlinx.coroutines.withContext
class LogExporter
@Inject
constructor(
@ApplicationContext private val context: Context,
@param:ApplicationContext private val context: Context,
) {
suspend fun export(
uri: Uri,
content: String,
): Result<Unit> {
return runCatching {
): Result<Unit> =
runCatching {
withContext(Dispatchers.IO) {
val writer =
context.contentResolver
Expand All @@ -32,5 +32,4 @@ class LogExporter
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class DashboardMetricsStore
private fun updateDashboardSnapshot(
metricId: DashboardMetricId,
value: String,
): DashboardMetricsSnapshot {
return when (metricId) {
): DashboardMetricsSnapshot =
when (metricId) {
DashboardMetricId.SPEED -> dashboardState.value.copy(speed = value)
DashboardMetricId.RPM -> dashboardState.value.copy(rpm = value)
DashboardMetricId.THROTTLE -> dashboardState.value.copy(throttle = value)
Expand All @@ -68,10 +68,9 @@ class DashboardMetricsStore
DashboardMetricId.INTAKE -> dashboardState.value.copy(intakeTemp = value)
DashboardMetricId.FUEL -> dashboardState.value.copy(fuel = value)
}
}

private fun metricDisplayName(metricId: DashboardMetricId): String {
return when (metricId) {
private fun metricDisplayName(metricId: DashboardMetricId): String =
when (metricId) {
DashboardMetricId.SPEED -> "Speed"
DashboardMetricId.RPM -> "RPM"
DashboardMetricId.THROTTLE -> "Throttle"
Expand All @@ -80,13 +79,11 @@ class DashboardMetricsStore
DashboardMetricId.INTAKE -> "Intake"
DashboardMetricId.FUEL -> "Fuel"
}
}

private fun String.previewValue(): String? {
return replace('\n', ' ')
private fun String.previewValue(): String? =
replace('\n', ' ')
.replace('\r', ' ')
.trim()
.take(40)
.takeIf { it.isNotBlank() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ class DashboardPollingCoordinator
connection: ObdDeviceConnection,
cycleId: Long,
metricId: DashboardMetricId,
): Boolean {
return when (metricId) {
): Boolean =
when (metricId) {
DashboardMetricId.SPEED ->
pollTypedMetric(
cycleId = cycleId,
Expand Down Expand Up @@ -332,7 +332,6 @@ class DashboardPollingCoordinator
maxValue = 100f,
)
}
}

private suspend fun <T> pollTypedMetric(
cycleId: Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ internal class DashboardPollingScheduler(
.associateWith { startAtMs }
.toMutableMap()

fun dueMetrics(nowMs: Long): List<DashboardMetricId> {
return ORDERED_METRICS.filter { metricId ->
fun dueMetrics(nowMs: Long): List<DashboardMetricId> =
ORDERED_METRICS.filter { metricId ->
nextDueAtMs.getValue(metricId) <= nowMs
}
}

fun markExecuted(
metricId: DashboardMetricId,
Expand All @@ -52,13 +51,12 @@ internal class DashboardPollingScheduler(
return (nextDueAt - nowMs).coerceAtLeast(0L)
}

private fun intervalFor(metricId: DashboardMetricId): Long {
return when (TIER_BY_METRIC.getValue(metricId)) {
private fun intervalFor(metricId: DashboardMetricId): Long =
when (TIER_BY_METRIC.getValue(metricId)) {
MetricPollingTier.FAST -> baseIntervalMs.coerceAtLeast(MIN_FAST_INTERVAL_MS)
MetricPollingTier.MEDIUM -> maxOf(baseIntervalMs * MEDIUM_INTERVAL_MULTIPLIER, MIN_MEDIUM_INTERVAL_MS)
MetricPollingTier.SLOW -> maxOf(baseIntervalMs * SLOW_INTERVAL_MULTIPLIER, MIN_SLOW_INTERVAL_MS)
}
}

companion object {
val ORDERED_METRICS: List<DashboardMetricId> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ class DiscoveryRepositoryImpl

override fun isBluetoothEnabled(): Boolean = discoveryManager.isBluetoothEnabled()

override fun isLocationServicesEnabledForDiscovery(): Boolean =
discoveryManager.isLocationServicesEnabledForDiscovery()
override fun isLocationServicesEnabledForDiscovery(): Boolean = discoveryManager.isLocationServicesEnabledForDiscovery()

override fun startDiscovery(): Result<Unit> = discoveryManager.startDiscovery()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,10 @@ class ObdCommandExecutor
}
}

fun previewValue(value: String?): String? {
return value
fun previewValue(value: String?): String? =
value
?.replace('\n', ' ')
?.replace('\r', ' ')
?.trim()
?.take(40)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,10 @@ class ObdSessionManager

fun isTransportConnected(): Boolean = transport.isConnected()

suspend fun <T> withConnectionAccess(block: suspend () -> T): T {
return connectionAccessMutex.withLock {
suspend fun <T> withConnectionAccess(block: suspend () -> T): T =
connectionAccessMutex.withLock {
block()
}
}

private suspend fun cleanupConnection() {
withConnectionAccess {
Expand All @@ -161,11 +160,10 @@ class ObdSessionManager
}
}

private fun hasBluetoothConnectPermission(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
private fun hasBluetoothConnectPermission(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
ContextCompat.checkSelfPermission(
appContext,
Manifest.permission.BLUETOOTH_CONNECT,
) == PackageManager.PERMISSION_GRANTED
}
}
Loading
Loading