From b3bd0b83e4894a7186fed3933f0e1a233ed45c3d Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 19:14:29 +0100 Subject: [PATCH 01/26] feat: implement bound service --- .../org/obd/graphs/PowerBroadcastReceiver.kt | 11 +-- .../org/obd/graphs/activity/MainActivity.kt | 49 +++++++++- .../org/obd/graphs/activity/Navigation.kt | 6 +- .../java/org/obd/graphs/activity/Receivers.kt | 24 +++-- .../graphs/preferences/PreferencesFragment.kt | 4 +- .../PidDefinitionPreferenceDialogFragment.kt | 14 +-- .../java/org/obd/graphs/ui/BaseFragment.kt | 89 ++++++++++++++++++ .../obd/graphs/ui/common/FloatingButton.kt | 49 ---------- .../graphs/ui/dashboard/DashboardFragment.kt | 24 ++--- .../ui/drag_racing/DragRacingFragment.kt | 28 +++--- .../org/obd/graphs/ui/gauge/GaugeAdapter.kt | 4 +- .../org/obd/graphs/ui/gauge/GaugeFragment.kt | 13 +-- .../obd/graphs/ui/giulia/GiuliaFragment.kt | 19 ++-- .../org/obd/graphs/ui/graph/GraphFragment.kt | 30 +++--- .../org/obd/graphs/ui/graph/MarkerWindow.kt | 4 +- .../graphs/ui/graph/TripDetailsViewAdapter.kt | 4 +- .../ui/performance/PerformanceFragment.kt | 28 +++--- .../graphs/ui/recycler/RefreshableFragment.kt | 14 +-- .../graphs/ui/trip_info/TripInfoFragment.kt | 28 +++--- .../org/obd/graphs/aa/screen/CarScreen.kt | 54 +++++++++-- .../aa/screen/iot/IotTemplateCarScreen.kt | 10 +- .../aa/screen/nav/AvailableFeaturesScreen.kt | 2 +- .../aa/screen/nav/NavTemplateCarScreen.kt | 10 +- .../graphs/aa/screen/nav/RoutinesScreen.kt | 14 +-- .../aa/screen/nav/SurfaceRendererScreen.kt | 26 +++--- .../collector/InMemoryCarMetricsCollector.kt | 6 +- .../obd/graphs/bl/collector/MetricsBuilder.kt | 8 +- .../obd/graphs/bl/datalogger/DataLogger.kt | 49 ---------- .../bl/datalogger/DataLoggerConstants.kt | 4 +- .../bl/datalogger/DataLoggerJobScheduler.kt | 2 +- .../graphs/bl/datalogger/DataLoggerService.kt | 92 +++++++++---------- .../datalogger/VehicleCapabilitiesManager.kt | 2 +- .../bl/generator/MetricGeneratorDefinition.kt | 2 +- .../graphs/bl/generator/MetricsGenerator.kt | 8 +- .../obd/graphs/bl/gps/GpsMetricsEmitter.kt | 4 +- .../obd/graphs/bl/trip/DefaultTripManager.kt | 6 +- .../org/obd/graphs/bl/trip/TripManager.kt | 4 +- .../gcp/gdrive/DefaultTripLogDriveManager.kt | 5 +- .../org/obd/graphs/renderer/AbstractDrawer.kt | 6 +- 39 files changed, 421 insertions(+), 335 deletions(-) create mode 100644 app/src/main/java/org/obd/graphs/ui/BaseFragment.kt delete mode 100644 app/src/main/java/org/obd/graphs/ui/common/FloatingButton.kt delete mode 100644 datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLogger.kt diff --git a/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt b/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt index f94733b1..4aed49bd 100644 --- a/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt +++ b/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -25,7 +25,7 @@ import android.util.Log import org.obd.graphs.activity.LOG_TAG import org.obd.graphs.activity.MainActivity import org.obd.graphs.bl.datalogger.DATA_LOGGER_SCHEDULED_START_EVENT -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DATA_LOGGER_SCHEDULED_STOP_EVENT const val SCREEN_OFF_EVENT = "power.screen.off" const val SCREEN_ON_EVENT = "power.screen.on" @@ -65,12 +65,7 @@ internal class PowerBroadcastReceiver : BroadcastReceiver() { } if (powerPreferences.connectOnPower) { - Log.d( - LOG_TAG, - "Stop data logging", - ) - dataLogger.stop() - dataLogger.scheduledStop() + sendBroadcastEvent(DATA_LOGGER_SCHEDULED_STOP_EVENT) } if (powerPreferences.screenOnOff) { diff --git a/app/src/main/java/org/obd/graphs/activity/MainActivity.kt b/app/src/main/java/org/obd/graphs/activity/MainActivity.kt index 9b485f68..888b345e 100644 --- a/app/src/main/java/org/obd/graphs/activity/MainActivity.kt +++ b/app/src/main/java/org/obd/graphs/activity/MainActivity.kt @@ -17,13 +17,17 @@ package org.obd.graphs.activity import android.content.BroadcastReceiver +import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.ServiceConnection import android.content.res.Configuration import android.os.Bundle +import android.os.IBinder import android.os.StrictMode import android.os.StrictMode.ThreadPolicy import android.os.StrictMode.VmPolicy +import android.util.Log import android.view.View import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity @@ -38,7 +42,8 @@ import org.obd.graphs.MAIN_ACTIVITY_EVENT_DESTROYED import org.obd.graphs.MAIN_ACTIVITY_EVENT_PAUSE import org.obd.graphs.Permissions import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerService +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.drag.dragRacingMetricsProcessor import org.obd.graphs.bl.extra.vehicleStatusMetricsProcessor import org.obd.graphs.bl.generator.MetricsGenerator @@ -62,6 +67,26 @@ class MainActivity : lateinit var lockScreenDialog: AlertDialog internal lateinit var backupManager: BackupManager + var dataLogger: DataLoggerService? = null + private var isBound = false + + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(className: ComponentName, service: IBinder) { + val binder = service as DataLoggerService.LocalBinder + dataLogger = binder.getService() + isBound = true + Log.i("ServiceConnection", "Service Connected! Ready to send commands.") + } + + override fun onServiceDisconnected(className: ComponentName) { + Log.e("ServiceConnection", "Service Disconnected unexpectedly.") + isBound = false + dataLogger = null + } + } + + internal var activityBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive( @@ -118,6 +143,23 @@ class MainActivity : fun getDrawer() = findViewById(R.id.drawer_layout) as DrawerLayout + + override fun onStart() { + super.onStart() + Intent(this, DataLoggerService::class.java).also { intent -> + bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } + } + + override fun onStop() { + super.onStop() + if (isBound) { + unbindService(serviceConnection) + isBound = false + dataLogger = null + } + } + override fun onPause() { super.onPause() sendBroadcastEvent(MAIN_ACTIVITY_EVENT_PAUSE) @@ -244,14 +286,13 @@ class MainActivity : } private fun setupMetricsProcessors() { - dataLogger - .observe(dragRacingMetricsProcessor) + DataLoggerRepository.observe(dragRacingMetricsProcessor) .observe(tripManager) .observe(vehicleStatusMetricsProcessor) .observe(gpsMetricsEmitter) if (BuildConfig.DEBUG) { - dataLogger.observe(MetricsGenerator(BuildConfig.DEBUG)) + DataLoggerRepository.observe(MetricsGenerator(BuildConfig.DEBUG)) } } diff --git a/app/src/main/java/org/obd/graphs/activity/Navigation.kt b/app/src/main/java/org/obd/graphs/activity/Navigation.kt index c1023455..c7ad511f 100644 --- a/app/src/main/java/org/obd/graphs/activity/Navigation.kt +++ b/app/src/main/java/org/obd/graphs/activity/Navigation.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -23,7 +23,7 @@ import androidx.core.os.bundleOf import androidx.core.view.GravityCompat import androidx.navigation.ui.NavigationUI import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.getContext import org.obd.graphs.preferences.PREFERENCE_SCREEN_KEY import org.obd.graphs.preferences.Prefs @@ -99,7 +99,7 @@ internal fun MainActivity.setupNavigationBar() { navController.addOnDestinationChangedListener { _, destination, _ -> bottomAppBar { - it.menu.findItem(R.id.ctx_menu_dtc).isVisible = dataLogger.isDTCEnabled() + it.menu.findItem(R.id.ctx_menu_dtc).isVisible = DataLoggerRepository.isDTCEnabled() ?: false it.menu.findItem(R.id.ctx_menu_android_auto)?.let { if (NavigationRouter.isAndroidAutoEnabled(this)) { val spanString = SpannableString(it.title.toString()) diff --git a/app/src/main/java/org/obd/graphs/activity/Receivers.kt b/app/src/main/java/org/obd/graphs/activity/Receivers.kt index 10d87e81..2c868f03 100644 --- a/app/src/main/java/org/obd/graphs/activity/Receivers.kt +++ b/app/src/main/java/org/obd/graphs/activity/Receivers.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -60,10 +60,11 @@ import org.obd.graphs.bl.datalogger.DATA_LOGGER_DTC_AVAILABLE import org.obd.graphs.bl.datalogger.DATA_LOGGER_ERROR_CONNECT_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_ERROR_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_NO_NETWORK_EVENT +import org.obd.graphs.bl.datalogger.DATA_LOGGER_SCHEDULED_STOP_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_WIFI_INCORRECT import org.obd.graphs.bl.datalogger.DATA_LOGGER_WIFI_NOT_CONNECTED -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.dataLoggerSettings import org.obd.graphs.bl.extra.EVENT_VEHICLE_STATUS_IGNITION_OFF import org.obd.graphs.bl.extra.EVENT_VEHICLE_STATUS_IGNITION_ON @@ -96,6 +97,14 @@ private const val EVENT_VEHICLE_STATUS_CHANGED = "event.vehicle.status.CHANGED" internal fun MainActivity.receive(intent: Intent?) { when (intent?.action) { + DATA_LOGGER_SCHEDULED_STOP_EVENT -> { + Log.d( + LOG_TAG, + "Stop data logging", + ) + dataLogger?.stop() + dataLogger?.scheduledStop() + } NAVIGATION_BUTTONS_VISIBILITY_CHANGED -> setupNavigationBar() GOOGLE_SIGN_IN_NO_CREDENTIAL_FAILURE -> toast(org.obd.graphs.commons.R.string.main_activity_toast_google_signin_failed) @@ -150,7 +159,7 @@ internal fun MainActivity.receive(intent: Intent?) { UsbManager.ACTION_USB_DEVICE_DETACHED -> { val usbDevice: UsbDevice = intent.extras?.get(UsbManager.EXTRA_DEVICE) as UsbDevice toast(R.string.pref_usb_device_detached, usbDevice.productName!!) - dataLogger.stop() + dataLogger?.stop() } USB_DEVICE_ATTACHED_EVENT -> { @@ -211,7 +220,7 @@ internal fun MainActivity.receive(intent: Intent?) { ContextCompat.getColorStateList(applicationContext, org.obd.graphs.commons.R.color.cardinal) it.setOnClickListener { Log.i(LOG_TAG, "Stop data logging ") - dataLogger.stop() + dataLogger?.stop() } it.refreshDrawableState() } @@ -264,7 +273,7 @@ internal fun MainActivity.receive(intent: Intent?) { updateVehicleStatus("Key off") if (dataLoggerSettings.instance().vehicleStatusDisconnectWhenOff) { Log.i(LOG_TAG, "Received vehicle status OFF event. Closing the session.") - dataLogger.stop() + dataLogger?.stop() } } } @@ -301,7 +310,7 @@ internal fun MainActivity.toggleNavigationItem( internal fun MainActivity.unregisterReceiver() { unregisterReceiver(activityBroadcastReceiver) unregisterReceiver(powerReceiver) - unregisterReceiver(dataLogger.eventsReceiver) + unregisterReceiver(DataLoggerRepository.eventsReceiver) } internal fun MainActivity.registerReceiver() { @@ -359,6 +368,7 @@ internal fun MainActivity.registerReceiver() { it.addAction(REQUEST_NOTIFICATION_PERMISSIONS) it.addAction(LOCATION_IS_DISABLED) it.addAction(NAVIGATION_BUTTONS_VISIBILITY_CHANGED) + it.addAction(DATA_LOGGER_SCHEDULED_STOP_EVENT) } registerReceiver(this, powerReceiver) { @@ -366,7 +376,7 @@ internal fun MainActivity.registerReceiver() { it.addAction("android.intent.action.ACTION_POWER_DISCONNECTED") } - registerReceiver(this, dataLogger.eventsReceiver) { + registerReceiver(this,DataLoggerRepository.eventsReceiver) { it.addAction(MODULES_LIST_CHANGED_EVENT) it.addAction(PROFILE_CHANGED_EVENT) } diff --git a/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt b/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt index b432d54f..7e09390a 100644 --- a/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt +++ b/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt @@ -27,7 +27,7 @@ import android.view.ViewGroup import androidx.preference.* import org.obd.graphs.R import org.obd.graphs.activity.* -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.trip.tripVirtualScreenManager import org.obd.graphs.preferences.dtc.DiagnosticTroubleCodeListPreferences import org.obd.graphs.preferences.dtc.DiagnosticTroubleCodePreferenceDialogFragment @@ -191,7 +191,7 @@ class PreferencesFragment : PreferenceFragmentCompat() { private fun hidePreferences() { findPreference("pref.dtc.category")?.isVisible = - dataLogger.isDTCEnabled() + DataLoggerRepository.isDTCEnabled() } private fun registerListeners() { diff --git a/app/src/main/java/org/obd/graphs/preferences/pid/PidDefinitionPreferenceDialogFragment.kt b/app/src/main/java/org/obd/graphs/preferences/pid/PidDefinitionPreferenceDialogFragment.kt index c5459322..07dc4f4c 100644 --- a/app/src/main/java/org/obd/graphs/preferences/pid/PidDefinitionPreferenceDialogFragment.kt +++ b/app/src/main/java/org/obd/graphs/preferences/pid/PidDefinitionPreferenceDialogFragment.kt @@ -35,7 +35,7 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import org.obd.graphs.R import org.obd.graphs.ViewPreferencesSerializer -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.dataLoggerSettings import org.obd.graphs.bl.datalogger.serialize import org.obd.graphs.bl.datalogger.vehicleCapabilitiesManager @@ -317,12 +317,12 @@ open class PidDefinitionPreferenceDialogFragment( private fun getAdapter() = (getRecyclerView(root).adapter as PidViewAdapter) private fun sourceList(): MutableList { - val all = dataLogger.getPidDefinitionRegistry().findAll() + val all = DataLoggerRepository.getPidDefinitionRegistry().findAll() val individualQuery = dataLoggerSettings.instance().adapter.individualQueryStrategyEnabled val sourceList: List = if (source == PREFERENCE_SCREEN_SOURCE_TRIP_INFO) { - val pidRegistry = dataLogger.getPidDefinitionRegistry() + val pidRegistry = DataLoggerRepository.getPidDefinitionRegistry() val list = Query .instance(QueryStrategyType.TRIP_INFO_QUERY) @@ -331,7 +331,7 @@ open class PidDefinitionPreferenceDialogFragment( .toMutableList() list.map { PidDefinitionDetails(it, checked = false, supported = true) } } else if (source == PREFERENCE_SCREEN_SOURCE_PERFORMANCE) { - val pidRegistry = dataLogger.getPidDefinitionRegistry() + val pidRegistry = DataLoggerRepository.getPidDefinitionRegistry() val list = Query .instance(QueryStrategyType.PERFORMANCE_QUERY) @@ -340,18 +340,18 @@ open class PidDefinitionPreferenceDialogFragment( .toMutableList() list.map { PidDefinitionDetails(it, checked = false, supported = true) } } else if (individualQuery) { - findPidDefinitionByPriority(dataLogger.getPidDefinitionRegistry().findAll()) { true } + findPidDefinitionByPriority(DataLoggerRepository.getPidDefinitionRegistry().findAll()) { true } } else { when (source) { "low" -> findPidDefinitionByPriority(all) { pidDefinition -> pidDefinition.priority > 0 } "high" -> findPidDefinitionByPriority(all) { pidDefinition -> pidDefinition.priority == 0 } - "edit" -> findPidDefinitionByPriority(dataLogger.getPidDefinitionRegistry().findAll()) { true } + "edit" -> findPidDefinitionByPriority(DataLoggerRepository.getPidDefinitionRegistry().findAll()) { true } "dashboard" -> map(all) "graph" -> map(all) "gauge" -> map(all) "giulia" -> map(all) "aa" -> map(all) - else -> findPidDefinitionByPriority(dataLogger.getPidDefinitionRegistry().findAll()) { true } + else -> findPidDefinitionByPriority(DataLoggerRepository.getPidDefinitionRegistry().findAll()) { true } } } diff --git a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt new file mode 100644 index 00000000..0ee8f43c --- /dev/null +++ b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt @@ -0,0 +1,89 @@ +/** + * Copyright 2019-2026, Tomasz Żebrowski + * + *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.obd.graphs.ui + +import android.app.Activity +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import android.util.Log +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.google.android.material.floatingactionbutton.FloatingActionButton +import org.obd.graphs.R +import org.obd.graphs.bl.datalogger.DataLoggerService +import org.obd.graphs.bl.datalogger.DataLoggerRepository +import org.obd.graphs.bl.query.Query + +abstract class BaseFragment : Fragment() { + + protected var dataLogger: DataLoggerService? = null + private var isBound = false + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(className: ComponentName, service: IBinder) { + val binder = service as DataLoggerService.LocalBinder + dataLogger = binder.getService() + isBound = true + } + + override fun onServiceDisconnected(className: ComponentName) { + dataLogger = null + isBound = false + } + } + + override fun onStart() { + super.onStart() + val intent = Intent(requireContext(), DataLoggerService::class.java) + requireContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } + + override fun onStop() { + super.onStop() + if (isBound) { + requireContext().unbindService(serviceConnection) + isBound = false + } + dataLogger = null + } + + protected fun attachToFloatingButton( + activity: Activity?, + query: Query + ) { + activity?.let { + val btn = activity.findViewById(R.id.connect_btn) + btn?.setOnClickListener { + + if (DataLoggerRepository.isRunning()) { + Log.i("BaseFragment", "DragRacingFragment: Start data logging") + dataLogger?.stop() + } else { + Log.i("BaseFragment", "Start data logging") + dataLogger?.start(query) + } + } + + btn?.backgroundTintList = + ContextCompat.getColorStateList(activity, if (DataLoggerRepository.isRunning()) org.obd.graphs.commons.R.color.cardinal + else org.obd.graphs.commons.R.color.philippine_green) + } + } +} diff --git a/app/src/main/java/org/obd/graphs/ui/common/FloatingButton.kt b/app/src/main/java/org/obd/graphs/ui/common/FloatingButton.kt deleted file mode 100644 index adfd79b4..00000000 --- a/app/src/main/java/org/obd/graphs/ui/common/FloatingButton.kt +++ /dev/null @@ -1,49 +0,0 @@ - /** - * Copyright 2019-2026, Tomasz Żebrowski - * - *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - *

http://www.apache.org/licenses/LICENSE-2.0 - * - *

Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.obd.graphs.ui.common - -import android.app.Activity -import android.util.Log -import androidx.core.content.ContextCompat -import com.google.android.material.floatingactionbutton.FloatingActionButton -import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.dataLogger -import org.obd.graphs.bl.query.Query - -private const val LOG_TAG = "FloatingButton" - -fun attachToFloatingButton( - activity: Activity?, - query: Query, -) { - activity?.let { - val btn = activity.findViewById(R.id.connect_btn) - btn?.setOnClickListener { - if (dataLogger.isRunning()) { - Log.i(org.obd.graphs.activity.LOG_TAG, "DragRacingFragment: Start data logging") - dataLogger.stop() - } else { - Log.i(LOG_TAG, "Start data logging") - dataLogger.start(query) - } - } - - btn?.backgroundTintList = - ContextCompat.getColorStateList(activity, if (dataLogger.isRunning()) org.obd.graphs.commons.R.color.cardinal - else org.obd.graphs.commons.R.color.philippine_green) - } -} diff --git a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt index e5d6a8b8..d4fc156c 100644 --- a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -26,20 +26,22 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import org.obd.graphs.bl.collector.Metric -import org.obd.graphs.bl.collector.MetricsCollector import org.obd.graphs.R import org.obd.graphs.RenderingThread -import org.obd.graphs.bl.datalogger.* +import org.obd.graphs.bl.collector.Metric +import org.obd.graphs.bl.collector.MetricsCollector +import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT +import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.preferences.Prefs import org.obd.graphs.preferences.getLongSet import org.obd.graphs.preferences.getS import org.obd.graphs.registerReceiver -import org.obd.graphs.ui.common.attachToFloatingButton -import org.obd.graphs.ui.recycler.RefreshableFragment import org.obd.graphs.ui.gauge.AdapterContext +import org.obd.graphs.ui.recycler.RefreshableFragment private const val CONFIGURATION_CHANGE_EVENT_DASH = "recycler.view.change.configuration.event.dash_id" + class DashboardFragment : RefreshableFragment() { private val metricsCollector = MetricsCollector.instance() @@ -103,14 +105,14 @@ class DashboardFragment : RefreshableFragment() { root = inflater.inflate(R.layout.fragment_dashboard, container, false) setupDashboardRecyclerView(true) - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { it.run { metricsCollector.append(it) } } - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query()) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query()) renderingThread.start() } @@ -124,7 +126,7 @@ class DashboardFragment : RefreshableFragment() { private fun setupDashboardRecyclerView(enableOnTouchListener: Boolean) { configureView( configureChangeEventId = CONFIGURATION_CHANGE_EVENT_DASH, - recyclerView = root.findViewById(R.id.dashboard_recycler_view) as RecyclerView, + recyclerView = root.findViewById(R.id.dashboard_recycler_view)!!, metricsIdsPref = dashboardPreferences.dashboardSelectedMetrics.first, adapterContext = AdapterContext( layoutId = R.layout.item_dashboard, @@ -154,7 +156,7 @@ class DashboardFragment : RefreshableFragment() { } private fun calculateSpanCount(): Int { - val numberOfItems = Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size + val numberOfItems = Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size return if (numberOfItems <= 3) { 1 } else { diff --git a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt index d9d0e8c6..55d38bf1 100644 --- a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -21,25 +21,27 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.view.* -import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.SurfaceView +import android.view.View +import android.view.ViewGroup import org.obd.graphs.R import org.obd.graphs.RenderingThread import org.obd.graphs.bl.collector.MetricsCollector -import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT +import org.obd.graphs.bl.datalogger.DataLoggerRepository +import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.query.QueryStrategyType -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.registerReceiver import org.obd.graphs.renderer.Fps import org.obd.graphs.renderer.SurfaceRenderer import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings +import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.common.attachToFloatingButton -open class DragRacingFragment : Fragment() { +open class DragRacingFragment : BaseFragment() { private lateinit var root: View private val query = Query.instance(QueryStrategyType.DRAG_RACING_QUERY) @@ -63,7 +65,7 @@ open class DragRacingFragment : Fragment() { when (intent?.action) { DATA_LOGGER_CONNECTED_EVENT -> { - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) renderingThread.start() } @@ -83,7 +85,7 @@ open class DragRacingFragment : Fragment() { override fun onAttach(context: Context) { super.onAttach(context) - registerReceiver(activity, broadcastReceiver){ + registerReceiver(activity, broadcastReceiver) { it.addAction(DATA_LOGGER_CONNECTED_EVENT) it.addAction(DATA_LOGGER_STOPPED_EVENT) } @@ -106,7 +108,7 @@ open class DragRacingFragment : Fragment() { savedInstanceState: Bundle? ): View { - root = inflater.inflate(R.layout.fragment_drag_racing, container, false) + root = inflater.inflate(R.layout.fragment_drag_racing, container, false) val surfaceView = root.findViewById(R.id.surface_view) val renderer = SurfaceRenderer.allocate( @@ -121,14 +123,14 @@ open class DragRacingFragment : Fragment() { enabled = query.getIDs() ) - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { it.run { metricsCollector.append(it) } } - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query) renderingThread.start() } diff --git a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeAdapter.kt b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeAdapter.kt index 19d3a9cf..d22f9d59 100644 --- a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeAdapter.kt +++ b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeAdapter.kt @@ -33,7 +33,7 @@ import androidx.recyclerview.widget.RecyclerView import org.obd.graphs.PREF_ALERTING_ENABLED import org.obd.graphs.R import org.obd.graphs.bl.collector.Metric -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.format import org.obd.graphs.mapRange import org.obd.graphs.modules @@ -212,7 +212,7 @@ class GaugeAdapter( if (preferences.commandRateEnabled) { this.visibility = View.VISIBLE val rate = - dataLogger + DataLoggerRepository .getDiagnostics() .rate() .findBy(RateType.MEAN, pid) diff --git a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt index f9668862..295a88dd 100644 --- a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt @@ -61,6 +61,7 @@ class GaugeFragment : RefreshableFragment() { } ) + @SuppressLint("NotifyDataSetChanged") private var broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -68,7 +69,7 @@ class GaugeFragment : RefreshableFragment() { DATA_LOGGER_SCHEDULED_START_EVENT -> { if (isAdded && isVisible) { Log.i(org.obd.graphs.activity.LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + dataLogger?.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) } } @@ -122,7 +123,7 @@ class GaugeFragment : RefreshableFragment() { ): View { root = inflater.inflate(R.layout.fragment_gauge, container, false) - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { it.run { metricsCollector.append(it) } @@ -131,8 +132,8 @@ class GaugeFragment : RefreshableFragment() { configureView(true) setupVirtualViewPanel() - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query()) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query()) renderingThread.start() } @@ -236,8 +237,8 @@ class GaugeFragment : RefreshableFragment() { it.setOnClickListener { gaugeVirtualScreen.updateVirtualScreen(viewId) - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query()) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query()) } configureView(true) diff --git a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt index 14ade280..3c7ecd5a 100644 --- a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -27,7 +27,6 @@ import android.view.SurfaceView import android.view.View import android.view.ViewGroup import android.widget.Button -import androidx.fragment.app.Fragment import org.obd.graphs.R import org.obd.graphs.RenderingThread import org.obd.graphs.activity.LOG_TAG @@ -35,7 +34,7 @@ import org.obd.graphs.bl.collector.MetricsCollector import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_SCHEDULED_START_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.query.Query import org.obd.graphs.getPowerPreferences import org.obd.graphs.registerReceiver @@ -43,12 +42,12 @@ import org.obd.graphs.renderer.Fps import org.obd.graphs.renderer.SurfaceRenderer import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings +import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.common.attachToFloatingButton -open class GiuliaFragment : Fragment() { +open class GiuliaFragment : BaseFragment() { private lateinit var root: View private val query = Query.instance() @@ -81,7 +80,7 @@ open class GiuliaFragment : Fragment() { DATA_LOGGER_SCHEDULED_START_EVENT -> { if (isAdded && isVisible) { Log.i(LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + dataLogger?.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) } } @@ -146,14 +145,14 @@ open class GiuliaFragment : Fragment() { applyFilter() - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { it.run { metricsCollector.append(it, forceAppend = false) } } - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query()) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query()) renderingThread.start() } @@ -177,7 +176,7 @@ open class GiuliaFragment : Fragment() { it.setOnClickListener { giuliaVirtualScreen.updateVirtualScreen(viewId) - dataLogger.updateQuery(query()) + dataLogger?.updateQuery(query()) applyFilter() setupVirtualViewPanel() surfaceController.renderFrame() diff --git a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt index 38dc4dcb..57631cd3 100644 --- a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -30,7 +30,6 @@ import android.view.ViewGroup import android.widget.Button import android.widget.LinearLayout import androidx.core.view.isVisible -import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.mikephil.charting.charts.LineChart @@ -51,7 +50,7 @@ import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTING_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_SCHEDULED_START_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.scaleToRange import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.query.QueryStrategyType @@ -61,10 +60,10 @@ import org.obd.graphs.bl.trip.tripVirtualScreenManager import org.obd.graphs.getPowerPreferences import org.obd.graphs.preferences.Prefs import org.obd.graphs.registerReceiver +import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.Colors -import org.obd.graphs.ui.common.attachToFloatingButton import org.obd.graphs.ui.common.onDoubleClickListener import org.obd.metrics.api.model.ObdMetric import org.obd.metrics.pid.PidDefinition @@ -75,7 +74,7 @@ import java.util.Locale private const val LOG_TAG = "Graph" -class GraphFragment : Fragment() { +class GraphFragment : BaseFragment() { private var broadcastReceiver = object : BroadcastReceiver() { override fun onReceive( @@ -86,7 +85,7 @@ class GraphFragment : Fragment() { DATA_LOGGER_SCHEDULED_START_EVENT -> { if (isAdded && isVisible) { Log.i(org.obd.graphs.activity.LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + dataLogger?.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) } } @@ -133,7 +132,8 @@ class GraphFragment : Fragment() { override fun onChartGestureStart( me: MotionEvent, lastPerformedGesture: ChartGesture, - ) {} + ) { + } override fun onChartGestureEnd( me: MotionEvent, @@ -162,13 +162,15 @@ class GraphFragment : Fragment() { me: MotionEvent, scaleX: Float, scaleY: Float, - ) {} + ) { + } override fun onChartTranslate( me: MotionEvent, dX: Float, dY: Float, - ) {} + ) { + } } private val simpleDateFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) @@ -223,7 +225,7 @@ class GraphFragment : Fragment() { } private fun registerMetricsObserver() { - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { if (preferences.metrics.contains(it.command.pid.id)) { addEntry(it) } @@ -238,8 +240,8 @@ class GraphFragment : Fragment() { recyclerView.layoutManager = GridLayoutManager(root.context, 1) recyclerView.adapter = adapter - dataLogger.observe(viewLifecycleOwner) { - dataLogger.findHistogramFor(it).let { hist -> + DataLoggerRepository.observe(viewLifecycleOwner) { + DataLoggerRepository.findHistogramFor(it).let { hist -> val sensorData = SensorData( id = it.command.pid.id, @@ -264,7 +266,7 @@ class GraphFragment : Fragment() { val colors = Colors().get() chart = buildChart(root).apply { - val pidRegistry: PidDefinitionRegistry = dataLogger.getPidDefinitionRegistry() + val pidRegistry: PidDefinitionRegistry = DataLoggerRepository.getPidDefinitionRegistry() val metrics = preferences.metrics .mapNotNull { @@ -300,7 +302,7 @@ class GraphFragment : Fragment() { private fun loadCurrentTrip() { if (preferences.cacheEnabled) { val trip = tripManager.getCurrentTrip() - val registry = dataLogger.getPidDefinitionRegistry() + val registry = DataLoggerRepository.getPidDefinitionRegistry() tripStartTs = trip.startTs val recyclerView: RecyclerView = root.findViewById(R.id.recycler_view) diff --git a/app/src/main/java/org/obd/graphs/ui/graph/MarkerWindow.kt b/app/src/main/java/org/obd/graphs/ui/graph/MarkerWindow.kt index 40f98690..b893ea83 100644 --- a/app/src/main/java/org/obd/graphs/ui/graph/MarkerWindow.kt +++ b/app/src/main/java/org/obd/graphs/ui/graph/MarkerWindow.kt @@ -26,7 +26,7 @@ import com.github.mikephil.charting.data.Entry import com.github.mikephil.charting.highlight.Highlight import com.github.mikephil.charting.utils.MPPointF import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.scaleToRange import org.obd.metrics.api.model.ObdMetric import org.obd.metrics.command.obd.ObdCommand @@ -111,7 +111,7 @@ class MarkerWindow( id: Long, v: Float, ): ObdMetric { - val pidRegistry: PidDefinitionRegistry = dataLogger.getPidDefinitionRegistry() + val pidRegistry: PidDefinitionRegistry = DataLoggerRepository.getPidDefinitionRegistry() val pid = pidRegistry.findBy(id) val value = pid.scaleToRange(v) return ObdMetric diff --git a/app/src/main/java/org/obd/graphs/ui/graph/TripDetailsViewAdapter.kt b/app/src/main/java/org/obd/graphs/ui/graph/TripDetailsViewAdapter.kt index fce9c76c..be285570 100644 --- a/app/src/main/java/org/obd/graphs/ui/graph/TripDetailsViewAdapter.kt +++ b/app/src/main/java/org/obd/graphs/ui/graph/TripDetailsViewAdapter.kt @@ -24,7 +24,7 @@ import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.trip.SensorData import org.obd.graphs.format import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN @@ -47,7 +47,7 @@ class TripDetailsViewAdapter internal constructor( position: Int, ) { mData.elementAt(position).let { metric -> - val pid = dataLogger.getPidDefinitionRegistry().findBy(metric.id) + val pid = DataLoggerRepository.getPidDefinitionRegistry().findBy(metric.id) holder.metricName.setText(pid.description, COLOR_PHILIPPINE_GREEN, 1.0f) metric.run { holder.metricMaxValue.setText( diff --git a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt index 9dd9e6d0..035beef1 100644 --- a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -22,25 +22,27 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.view.* -import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.SurfaceView +import android.view.View +import android.view.ViewGroup import org.obd.graphs.R import org.obd.graphs.RenderingThread import org.obd.graphs.bl.collector.MetricsCollector -import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT +import org.obd.graphs.bl.datalogger.DataLoggerRepository +import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.query.QueryStrategyType -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.registerReceiver import org.obd.graphs.renderer.Fps import org.obd.graphs.renderer.SurfaceRenderer import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings +import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.common.attachToFloatingButton -open class PerformanceFragment : Fragment() { +open class PerformanceFragment : BaseFragment() { private lateinit var root: View private val query = Query.instance(QueryStrategyType.PERFORMANCE_QUERY) @@ -65,7 +67,7 @@ open class PerformanceFragment : Fragment() { when (intent?.action) { DATA_LOGGER_CONNECTED_EVENT -> { - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) renderingThread.start() } @@ -86,7 +88,7 @@ open class PerformanceFragment : Fragment() { override fun onAttach(context: Context) { super.onAttach(context) - registerReceiver(activity, broadcastReceiver){ + registerReceiver(activity, broadcastReceiver) { it.addAction(DATA_LOGGER_CONNECTED_EVENT) it.addAction(DATA_LOGGER_STOPPED_EVENT) } @@ -110,7 +112,7 @@ open class PerformanceFragment : Fragment() { savedInstanceState: Bundle? ): View { - root = inflater.inflate(R.layout.fragment_drag_racing, container, false) + root = inflater.inflate(R.layout.fragment_drag_racing, container, false) val surfaceView = root.findViewById(R.id.surface_view) val renderer = SurfaceRenderer.allocate( @@ -125,14 +127,14 @@ open class PerformanceFragment : Fragment() { enabled = query.getIDs() ) - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { it.run { metricsCollector.append(it) } } - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query) renderingThread.start() } diff --git a/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt b/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt index 17993ea4..0f753e1e 100644 --- a/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -19,29 +19,31 @@ package org.obd.graphs.ui.recycler import android.annotation.SuppressLint import android.content.Context import android.view.View -import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import org.obd.graphs.ViewPreferencesSerializer -import org.obd.graphs.bl.collector.* +import org.obd.graphs.bl.collector.Metric +import org.obd.graphs.bl.collector.MetricsBuilder +import org.obd.graphs.bl.collector.MetricsCollector import org.obd.graphs.bl.query.Query import org.obd.graphs.preferences.Prefs import org.obd.graphs.preferences.updateLongSet import org.obd.graphs.sendBroadcastEvent +import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.DragManageAdapter import org.obd.graphs.ui.common.SwappableAdapter import org.obd.graphs.ui.common.ToggleToolbarDoubleClickListener import org.obd.graphs.ui.gauge.AdapterContext -open class RefreshableFragment : Fragment() { +open class RefreshableFragment : BaseFragment() { protected val query: Query = Query.instance() protected lateinit var root: View protected fun refreshRecyclerView(metricsCollector: MetricsCollector, recyclerViewId: Int) { - if (::root.isInitialized){ - val adapter = ((root.findViewById(recyclerViewId) as RecyclerView).adapter) as RecyclerViewAdapter + if (::root.isInitialized) { + val adapter = ((root.findViewById(recyclerViewId)!!).adapter) as RecyclerViewAdapter val data = adapter.data metricsCollector.getMetrics().forEach { it.run { diff --git a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt index 63ffd40d..99eeb6a7 100644 --- a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -22,25 +22,27 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.view.* -import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.SurfaceView +import android.view.View +import android.view.ViewGroup import org.obd.graphs.R import org.obd.graphs.RenderingThread import org.obd.graphs.bl.collector.MetricsCollector -import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT +import org.obd.graphs.bl.datalogger.DataLoggerRepository +import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.query.QueryStrategyType -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.registerReceiver import org.obd.graphs.renderer.Fps import org.obd.graphs.renderer.SurfaceRenderer import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings +import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.common.attachToFloatingButton -open class TripInfoFragment : Fragment() { +open class TripInfoFragment : BaseFragment() { private lateinit var root: View private val query = Query.instance(QueryStrategyType.TRIP_INFO_QUERY) @@ -65,7 +67,7 @@ open class TripInfoFragment : Fragment() { when (intent?.action) { DATA_LOGGER_CONNECTED_EVENT -> { - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) renderingThread.start() } @@ -86,7 +88,7 @@ open class TripInfoFragment : Fragment() { override fun onAttach(context: Context) { super.onAttach(context) - registerReceiver(activity, broadcastReceiver){ + registerReceiver(activity, broadcastReceiver) { it.addAction(DATA_LOGGER_CONNECTED_EVENT) it.addAction(DATA_LOGGER_STOPPED_EVENT) } @@ -110,7 +112,7 @@ open class TripInfoFragment : Fragment() { savedInstanceState: Bundle? ): View { - root = inflater.inflate(R.layout.fragment_drag_racing, container, false) + root = inflater.inflate(R.layout.fragment_drag_racing, container, false) val surfaceView = root.findViewById(R.id.surface_view) val renderer = SurfaceRenderer.allocate( @@ -125,14 +127,14 @@ open class TripInfoFragment : Fragment() { enabled = query.getIDs() ) - dataLogger.observe(viewLifecycleOwner) { + DataLoggerRepository.observe(viewLifecycleOwner) { it.run { metricsCollector.append(it) } } - if (dataLogger.isRunning()) { - dataLogger.updateQuery(query) + if (DataLoggerRepository.isRunning()) { + dataLogger?.updateQuery(query) renderingThread.start() } diff --git a/automotive/src/main/java/org/obd/graphs/aa/screen/CarScreen.kt b/automotive/src/main/java/org/obd/graphs/aa/screen/CarScreen.kt index ad489e47..b4b09f6b 100644 --- a/automotive/src/main/java/org/obd/graphs/aa/screen/CarScreen.kt +++ b/automotive/src/main/java/org/obd/graphs/aa/screen/CarScreen.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -16,6 +16,11 @@ */ package org.obd.graphs.aa.screen +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder import android.util.Log import androidx.car.app.CarContext import androidx.car.app.Screen @@ -23,6 +28,7 @@ import androidx.car.app.connection.CarConnection import androidx.car.app.model.ActionStrip import androidx.car.app.model.CarColor import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner import org.obd.graphs.AA_EDIT_PREF_SCREEN import org.obd.graphs.RenderingThread import org.obd.graphs.aa.CarSettings @@ -32,8 +38,9 @@ import org.obd.graphs.aa.screen.nav.CHANGE_SCREEN_EVENT import org.obd.graphs.aa.screen.nav.FeatureDescription import org.obd.graphs.aa.toast import org.obd.graphs.bl.collector.MetricsCollector +import org.obd.graphs.bl.datalogger.DataLoggerService +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.WorkflowStatus -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.renderer.Fps import org.obd.graphs.renderer.Identity import org.obd.graphs.sendBroadcastEvent @@ -66,6 +73,24 @@ internal abstract class CarScreen( open fun onCarConfigurationChanged() {} + protected var dataLogger: DataLoggerService? = null + private var isBound = false + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName, service: IBinder) { + val binder = service as DataLoggerService.LocalBinder + dataLogger = binder.getService() + isBound = true + invalidate() + } + + override fun onServiceDisconnected(name: ComponentName) { + dataLogger = null + isBound = false + } + } + + protected val renderingThread: RenderingThread = RenderingThread( id = "CarScreenRenderingThread", renderAction = { @@ -80,10 +105,23 @@ internal abstract class CarScreen( CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated) } + override fun onStart(owner: LifecycleOwner) { + super.onStart(owner) + val intent = Intent(carContext, DataLoggerService::class.java) + carContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } + + override fun onStop(owner: LifecycleOwner) { + super.onStop(owner) + if (isBound) { + carContext.unbindService(serviceConnection) + isBound = false + } + } protected fun actionStopDataLogging() { Log.i(LOG_TAG, "Stopping data logging process") - dataLogger.stop() + dataLogger?.stop() cancelRenderingTask() } @@ -94,7 +132,7 @@ internal abstract class CarScreen( ): ActionStrip { var builder = ActionStrip.Builder() - builder = if (dataLogger.status() == WorkflowStatus.Connecting || dataLogger.status() == WorkflowStatus.Connected) { + builder = if (DataLoggerRepository.status() == WorkflowStatus.Connecting || DataLoggerRepository.status() == WorkflowStatus.Connected) { builder.addAction( createAction( carContext, @@ -148,7 +186,7 @@ internal abstract class CarScreen( } protected fun submitRenderingTask() { - if (!renderingThread.isRunning() && dataLogger.status() == WorkflowStatus.Connected) { + if (!renderingThread.isRunning() && DataLoggerRepository.status() == WorkflowStatus.Connected) { renderingThread.start() fps.start() } @@ -158,12 +196,12 @@ internal abstract class CarScreen( when (connectionState) { CarConnection.CONNECTION_TYPE_PROJECTION -> { if (settings.isLoadLastVisitedScreenEnabled()) { - Log.i(LOG_TAG,"Load last visited screen flag is enabled. Loading last visited screen....") + Log.i(LOG_TAG, "Load last visited screen flag is enabled. Loading last visited screen....") gotoScreen(settings.getLastVisitedScreen()) } - if (settings.isAutomaticConnectEnabled() && !dataLogger.isRunning()) { - Log.i(LOG_TAG,"Auto connection enabled. Auto start data logging.....") + if (settings.isAutomaticConnectEnabled() && !DataLoggerRepository.isRunning()) { + Log.i(LOG_TAG, "Auto connection enabled. Auto start data logging.....") actionStartDataLogging() } } diff --git a/automotive/src/main/java/org/obd/graphs/aa/screen/iot/IotTemplateCarScreen.kt b/automotive/src/main/java/org/obd/graphs/aa/screen/iot/IotTemplateCarScreen.kt index 11bb122f..5236250f 100644 --- a/automotive/src/main/java/org/obd/graphs/aa/screen/iot/IotTemplateCarScreen.kt +++ b/automotive/src/main/java/org/obd/graphs/aa/screen/iot/IotTemplateCarScreen.kt @@ -182,7 +182,7 @@ internal class IotTemplateCarScreen( } else { query.setStrategy(QueryStrategyType.SHARED_QUERY) } - dataLogger.start(query) + dataLogger?.start(query) } override fun renderAction() { invalidate() @@ -194,7 +194,7 @@ internal class IotTemplateCarScreen( } override fun onGetTemplate(): Template = - if (dataLogger.status() == WorkflowStatus.Connecting) { + if (DataLoggerRepository.status() == WorkflowStatus.Connecting) { GridTemplate.Builder() .setTitle(carContext.resources.getString(R.string.app_name)) .setLoading(true) @@ -248,7 +248,7 @@ internal class IotTemplateCarScreen( if (dataLoggerSettings.instance().adapter.individualQueryStrategyEnabled) { query.update(metricsCollector.getMetrics().map { p-> p.source.command.pid.id }.toSet()) - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) } } @@ -264,10 +264,10 @@ internal class IotTemplateCarScreen( init { Log.i(LOG_TAG, "IotTemplate Screen Init") lifecycle.addObserver(this) - dataLogger.observe(this) { + DataLoggerRepository.observe(this) { metricsCollector.append(it) } - dataLogger.observe(dynamicSelectorModeEventBroadcaster) + DataLoggerRepository.observe(dynamicSelectorModeEventBroadcaster) submitRenderingTask() registerConnectionStateReceiver() } diff --git a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/AvailableFeaturesScreen.kt b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/AvailableFeaturesScreen.kt index 25b29b7f..01f04afb 100644 --- a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/AvailableFeaturesScreen.kt +++ b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/AvailableFeaturesScreen.kt @@ -36,7 +36,7 @@ internal class AvailableFeaturesScreen( ) : Screen(carContext) { override fun onGetTemplate(): Template = try { - if (dataLogger.status() == WorkflowStatus.Connecting) { + if (DataLoggerRepository.status() == WorkflowStatus.Connecting) { ListTemplate.Builder() .setHeaderAction(Action.BACK) .setActionStrip(getHorizontalActionStrip()) diff --git a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/NavTemplateCarScreen.kt b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/NavTemplateCarScreen.kt index 84fe9c16..0cd5d19b 100644 --- a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/NavTemplateCarScreen.kt +++ b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/NavTemplateCarScreen.kt @@ -188,7 +188,7 @@ internal class NavTemplateCarScreen( EVENT_VEHICLE_STATUS_IGNITION_OFF -> { if (dataLoggerSettings.instance().vehicleStatusDisconnectWhenOff){ Log.i(LOG_TAG,"Received vehicle status OFF event. Closing the session.") - dataLogger.stop() + dataLogger?.stop() } } } @@ -284,7 +284,7 @@ internal class NavTemplateCarScreen( override fun onGetTemplate(): Template = try { settings.initItemsSortOrder() - if (settings.isConnectionDialogEnabled() && dataLogger.status() == WorkflowStatus.Connecting) { + if (settings.isConnectionDialogEnabled() && DataLoggerRepository.status() == WorkflowStatus.Connecting) { NavigationTemplate.Builder() .setNavigationInfo(RoutingInfo.Builder().setLoading(true).build()) .setActionStrip(getHorizontalActionStrip()) @@ -311,13 +311,13 @@ internal class NavTemplateCarScreen( lifecycle.addObserver(surfaceRendererScreen.getLifecycleObserver()) - dataLogger.observe(this) { + DataLoggerRepository.observe(this) { metricsCollector.append(it, forceAppend = false) } - dataLogger.observe(dynamicSelectorModeEventBroadcaster) + DataLoggerRepository.observe(dynamicSelectorModeEventBroadcaster) - dataLogger + DataLoggerRepository .observe(dragRacingMetricsProcessor) .observe(tripManager) .observe(vehicleStatusMetricsProcessor) diff --git a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/RoutinesScreen.kt b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/RoutinesScreen.kt index 2b826499..b122fea5 100644 --- a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/RoutinesScreen.kt +++ b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/RoutinesScreen.kt @@ -166,7 +166,7 @@ internal class RoutinesScreen( } override fun actionStartDataLogging(){ - dataLogger.start(query) + dataLogger?.start(query) } @@ -176,14 +176,14 @@ internal class RoutinesScreen( .setLoading(true) .setTitle(carContext.getString(R.string.routine_execution_start)) .setActionStrip(getHorizontalActionStrip()).build() - } else if (dataLogger.status() == WorkflowStatus.Connecting) { + } else if (DataLoggerRepository.status() == WorkflowStatus.Connecting) { ListTemplate.Builder() .setLoading(true) .setTitle(carContext.getString(R.string.routine_page_connecting)) .setActionStrip(getHorizontalActionStrip()).build() } else { var items = ItemList.Builder() - dataLogger.getPidDefinitionRegistry().findBy(PIDsGroup.ROUTINE) + DataLoggerRepository.getPidDefinitionRegistry().findBy(PIDsGroup.ROUTINE) .sortedBy { it.description } .sortedBy { it.id != routineId } .forEach { @@ -211,14 +211,14 @@ internal class RoutinesScreen( .setOnClickListener { Log.i(LOG_TAG, "Executing routine ${data.description}") - if (dataLogger.isRunning()) { + if (DataLoggerRepository.isRunning()) { routineExecuting = true routineId = data.id } else { routineId = -1L } invalidate() - dataLogger.executeRoutine(Query.instance(QueryStrategyType.ROUTINES_QUERY).update(setOf(data.id))) + dataLogger?.executeRoutine(Query.instance(QueryStrategyType.ROUTINES_QUERY).update(setOf(data.id))) } .setBrowsable(false) @@ -250,7 +250,7 @@ internal class RoutinesScreen( private fun getHorizontalActionStrip(): ActionStrip { var builder = ActionStrip.Builder() - builder = if (dataLogger.isRunning()) { + builder = if (DataLoggerRepository.isRunning()) { builder.addAction( createAction( carContext, @@ -262,7 +262,7 @@ internal class RoutinesScreen( }) } else { builder.addAction(createAction(carContext, R.drawable.actions_connect, mapColor(settings.getColorTheme().actionsBtnConnectColor)) { - dataLogger.start(query) + dataLogger?.start(query) }) } diff --git a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/SurfaceRendererScreen.kt b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/SurfaceRendererScreen.kt index b27d2873..9114b853 100644 --- a/automotive/src/main/java/org/obd/graphs/aa/screen/nav/SurfaceRendererScreen.kt +++ b/automotive/src/main/java/org/obd/graphs/aa/screen/nav/SurfaceRendererScreen.kt @@ -30,7 +30,6 @@ import org.obd.graphs.* import org.obd.graphs.aa.* import org.obd.graphs.aa.screen.* import org.obd.graphs.bl.collector.MetricsCollector -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.bl.datalogger.dataLoggerSettings import org.obd.graphs.bl.query.Query import org.obd.graphs.bl.query.QueryStrategyType @@ -150,20 +149,19 @@ internal class SurfaceRendererScreen( query.setStrategy(QueryStrategyType.SHARED_QUERY) } - dataLogger.updateQuery(query = query) + dataLogger?.updateQuery(query = query) surfaceRendererController.allocateSurfaceRenderer(screenId as SurfaceRendererType) } SurfaceRendererType.DRAG_RACING -> { - dataLogger.updateQuery(query = query.apply { + dataLogger?.updateQuery(query = query.apply { setStrategy(QueryStrategyType.DRAG_RACING_QUERY) }) surfaceRendererController.allocateSurfaceRenderer(surfaceRendererType = SurfaceRendererType.DRAG_RACING) } SurfaceRendererType.TRIP_INFO -> { - - dataLogger.updateQuery(query = query.apply { + dataLogger?.updateQuery(query = query.apply { setStrategy(QueryStrategyType.TRIP_INFO_QUERY) }) surfaceRendererController.allocateSurfaceRenderer(surfaceRendererType = SurfaceRendererType.TRIP_INFO) @@ -171,7 +169,7 @@ internal class SurfaceRendererScreen( SurfaceRendererType.PERFORMANCE -> { - dataLogger.updateQuery(query = query.apply { + dataLogger?.updateQuery(query = query.apply { setStrategy(QueryStrategyType.PERFORMANCE_QUERY) }) surfaceRendererController.allocateSurfaceRenderer(surfaceRendererType = SurfaceRendererType.PERFORMANCE) @@ -190,21 +188,21 @@ internal class SurfaceRendererScreen( } else { query.setStrategy(QueryStrategyType.SHARED_QUERY) } - dataLogger.start(query) + dataLogger?.start(query) } SurfaceRendererType.DRAG_RACING -> - dataLogger.start(query.apply{ + dataLogger?.start(query.apply{ setStrategy(QueryStrategyType.DRAG_RACING_QUERY) }) SurfaceRendererType.TRIP_INFO -> - dataLogger.start(query.apply{ + dataLogger?.start(query.apply{ setStrategy(QueryStrategyType.TRIP_INFO_QUERY) }) SurfaceRendererType.PERFORMANCE -> - dataLogger.start(query.apply{ + dataLogger?.start(query.apply{ setStrategy(QueryStrategyType.PERFORMANCE_QUERY) }) } @@ -298,7 +296,7 @@ internal class SurfaceRendererScreen( query.setStrategy(QueryStrategyType.DRAG_RACING_QUERY) metricsCollector.applyFilter(enabled = query.getIDs()) Log.i(LOG_TAG, "User selection PIDs=${query.getIDs()}") - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) } else if (screenId == SurfaceRendererType.TRIP_INFO) { Log.i(LOG_TAG, "Updating query for TRIP_INFO_SCREEN_ID screen") @@ -306,7 +304,7 @@ internal class SurfaceRendererScreen( query.setStrategy(QueryStrategyType.TRIP_INFO_QUERY) metricsCollector.applyFilter(enabled = query.getIDs()) Log.i(LOG_TAG, "User selection PIDs=${query.getIDs()}") - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) } else if (screenId == SurfaceRendererType.PERFORMANCE) { Log.i(LOG_TAG, "Updating query for DYNAMIC_SCREEN_ID screen") @@ -314,7 +312,7 @@ internal class SurfaceRendererScreen( query.setStrategy(QueryStrategyType.PERFORMANCE_QUERY) metricsCollector.applyFilter(enabled = query.getIDs()) Log.i(LOG_TAG, "User selection PIDs=${query.getIDs()}") - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) } else if (dataLoggerSettings.instance().adapter.individualQueryStrategyEnabled) { Log.i(LOG_TAG, "Updating query for individualQueryStrategyEnabled") @@ -325,7 +323,7 @@ internal class SurfaceRendererScreen( query.update(metricsCollector.getMetrics().map { p -> p.source.command.pid.id }.toSet()) Log.i(LOG_TAG, "User selection PIDs=${selectedPIDs}") - dataLogger.updateQuery(query) + dataLogger?.updateQuery(query) } else { Log.i(LOG_TAG, "Updating query to SHARED_QUERY strategy") diff --git a/datalogger/src/main/java/org/obd/graphs/bl/collector/InMemoryCarMetricsCollector.kt b/datalogger/src/main/java/org/obd/graphs/bl/collector/InMemoryCarMetricsCollector.kt index 9a813065..a47d1c0d 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/collector/InMemoryCarMetricsCollector.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/collector/InMemoryCarMetricsCollector.kt @@ -17,7 +17,7 @@ package org.obd.graphs.bl.collector import android.util.Log -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.Pid import org.obd.metrics.api.model.ObdMetric import java.util.* @@ -91,8 +91,8 @@ internal class InMemoryCarMetricsCollector : MetricsCollector { it.source = metric it.value = metric.value - val hist = dataLogger.findHistogramFor(metric) - val rate = dataLogger.findRateFor(metric) + val hist = DataLoggerRepository.findHistogramFor(metric) + val rate = DataLoggerRepository.findRateFor(metric) if (metric.isLowerAlert) { it.inLowerAlertRisedHist = metric.isLowerAlert diff --git a/datalogger/src/main/java/org/obd/graphs/bl/collector/MetricsBuilder.kt b/datalogger/src/main/java/org/obd/graphs/bl/collector/MetricsBuilder.kt index 55949fcb..5126d669 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/collector/MetricsBuilder.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/collector/MetricsBuilder.kt @@ -17,7 +17,7 @@ package org.obd.graphs.bl.collector -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.metrics.api.model.ObdMetric import org.obd.metrics.command.obd.ObdCommand import org.obd.metrics.pid.PidDefinitionRegistry @@ -39,7 +39,7 @@ class MetricsBuilder { fun buildFor(obdMetric: ObdMetric): Metric { - val histogramSupplier = dataLogger.getDiagnostics().histogram() + val histogramSupplier = DataLoggerRepository.getDiagnostics().histogram() val histogram = histogramSupplier.findBy(obdMetric.command.pid) return Metric .newInstance( @@ -74,8 +74,8 @@ class MetricsBuilder { private fun buildMetrics(ids: Set): MutableList { - val pidRegistry: PidDefinitionRegistry = dataLogger.getPidDefinitionRegistry() - val histogramSupplier = dataLogger.getDiagnostics().histogram() + val pidRegistry: PidDefinitionRegistry = DataLoggerRepository.getPidDefinitionRegistry() + val histogramSupplier = DataLoggerRepository.getDiagnostics().histogram() return ids.mapNotNull { pidRegistry.findBy(it)?.let { pid -> diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLogger.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLogger.kt deleted file mode 100644 index 15714012..00000000 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLogger.kt +++ /dev/null @@ -1,49 +0,0 @@ - /** - * Copyright 2019-2026, Tomasz Żebrowski - * - *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - *

http://www.apache.org/licenses/LICENSE-2.0 - * - *

Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.obd.graphs.bl.datalogger - -import android.content.BroadcastReceiver -import androidx.lifecycle.LifecycleOwner -import org.obd.graphs.bl.query.Query -import org.obd.metrics.alert.Alert -import org.obd.metrics.api.model.ObdMetric -import org.obd.metrics.diagnostic.Diagnostics -import org.obd.metrics.diagnostic.Histogram -import org.obd.metrics.diagnostic.Rate -import org.obd.metrics.pid.PidDefinitionRegistry -import java.util.* - -interface DataLogger { - val eventsReceiver: BroadcastReceiver - fun status(): WorkflowStatus - fun observe(lifecycleOwner: LifecycleOwner, observer: (metric: ObdMetric) -> Unit) - fun observe(metricsProcessor: MetricsProcessor): DataLogger - fun isRunning(): Boolean - fun getDiagnostics(): Diagnostics - fun findHistogramFor(metric: ObdMetric): Histogram - fun findRateFor(metric: ObdMetric): Optional - fun getPidDefinitionRegistry(): PidDefinitionRegistry - fun isDTCEnabled(): Boolean - fun scheduleStart(delay: Long, query: Query) - fun scheduledStop() - fun executeRoutine(query: Query) - fun start(query: Query) - fun updateQuery(query: Query) - fun stop() - fun getCurrentQuery(): Query? - fun findAlertFor(metric: ObdMetric): List -} diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt index 849db693..20571acc 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -23,6 +23,8 @@ const val DATA_LOGGER_WIFI_INCORRECT = "data.logger.error.wifi.incorrect" const val DATA_LOGGER_WIFI_NOT_CONNECTED = "data.logger.error.wifi.not.connected" const val DATA_LOGGER_CONNECTED_EVENT = "data.logger.connected" const val DATA_LOGGER_SCHEDULED_START_EVENT = "data.logger.scheduled.start" +const val DATA_LOGGER_SCHEDULED_STOP_EVENT = "data.logger.scheduled.stop" + const val DATA_LOGGER_DTC_AVAILABLE = "data.logger.dtc.available" const val DATA_LOGGER_CONNECTING_EVENT = "data.logger.connecting" const val DATA_LOGGER_STOPPED_EVENT = "data.logger.stopped" diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerJobScheduler.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerJobScheduler.kt index 8062c1ec..8030000e 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerJobScheduler.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerJobScheduler.kt @@ -23,7 +23,7 @@ import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit -internal class DataLoggerJobScheduler { +internal class DataLoggerJobScheduler(private val dataLogger: DataLoggerService) { private val scheduleService: ScheduledExecutorService = Executors.newScheduledThreadPool(1) private var future: ScheduledFuture<*>? = null diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt index 314b7aeb..9a9510ca 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -58,33 +58,53 @@ private const val EXECUTE_ROUTINE = "org.obd.graphs.logger.EXECUTE_ROUTINE" private const val NOTIFICATION_CHANNEL_ID = "data_logger_channel_v2" private const val NOTIFICATION_ID = 12345 -// Thread-safe Singleton Management -private var _workflowOrchestrator: WorkflowOrchestrator? = null -private val orchestratorLock = Any() +object DataLoggerRepository { + private var _workflowOrchestrator: WorkflowOrchestrator? = null -internal val workflowOrchestrator: WorkflowOrchestrator - get() { - synchronized(orchestratorLock) { + internal val workflowOrchestrator: WorkflowOrchestrator + get() { if (_workflowOrchestrator == null) { Log.i(LOG_TAG, "Initializing WorkflowOrchestrator") _workflowOrchestrator = WorkflowOrchestrator() } return _workflowOrchestrator!! } - } -@VisibleForTesting -internal fun setWorkflowOrchestrator(mock: WorkflowOrchestrator) { - synchronized(orchestratorLock) { + @VisibleForTesting + internal fun setWorkflowOrchestrator(mock: WorkflowOrchestrator) { _workflowOrchestrator = mock } + + fun getCurrentQuery(): Query? = workflowOrchestrator.getCurrentQuery() + fun findAlertFor(metric: ObdMetric): List = workflowOrchestrator.findAlertFor(metric) + fun isRunning(): Boolean = workflowOrchestrator.isRunning() + fun getDiagnostics(): Diagnostics = workflowOrchestrator.diagnostics() + fun findHistogramFor(metric: ObdMetric): Histogram = workflowOrchestrator.findHistogramFor(metric) + fun findRateFor(metric: ObdMetric): Optional = workflowOrchestrator.findRateFor(metric) + fun getPidDefinitionRegistry(): PidDefinitionRegistry = workflowOrchestrator.pidDefinitionRegistry() + fun isDTCEnabled(): Boolean = workflowOrchestrator.isDTCEnabled() + fun status(): WorkflowStatus = workflowOrchestrator.status() + + fun observe(lifecycleOwner: LifecycleOwner, observer: (metric: ObdMetric) -> Unit) { + workflowOrchestrator.observe(lifecycleOwner, observer) + } + + fun observe(metricsProcessor: MetricsProcessor): DataLoggerRepository { + workflowOrchestrator.observe(metricsProcessor) + return this + } + + + val eventsReceiver: BroadcastReceiver + get() = workflowOrchestrator.eventsReceiver } -val dataLogger: DataLogger = DataLoggerService() -internal class DataLoggerService : Service(), DataLogger { +class DataLoggerService : Service() { - private val jobScheduler = DataLoggerJobScheduler() + private val workflowOrchestrator = DataLoggerRepository.workflowOrchestrator + + private val jobScheduler = DataLoggerJobScheduler(this) private val binder = LocalBinder() inner class LocalBinder : Binder() { @@ -98,8 +118,6 @@ internal class DataLoggerService : Service(), DataLogger { override fun onDestroy() { super.onDestroy() Log.i(LOG_TAG, "Destroying DataLoggerService") - // Check for null to avoid initializing it just to stop it - _workflowOrchestrator?.stop() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -138,18 +156,22 @@ internal class DataLoggerService : Service(), DataLogger { val query = intent.extras?.get(QUERY) as? Query query?.let { workflowOrchestrator.updateQuery(query = it) } } + ACTION_START -> { val query = intent.extras?.get(QUERY) as? Query query?.let { workflowOrchestrator.start(it) } } + EXECUTE_ROUTINE -> { val query = intent.extras?.get(QUERY) as? Query query?.let { workflowOrchestrator.executeRoutine(it) } } + ACTION_STOP -> { workflowOrchestrator.stop() serviceStop() } + SCHEDULED_ACTION_STOP -> jobScheduler.stop() SCHEDULED_ACTION_START -> { val delay = intent.extras?.getLong(SCHEDULED_START_DELAY) ?: 0L @@ -161,62 +183,40 @@ internal class DataLoggerService : Service(), DataLogger { return START_STICKY } - override fun updateQuery(query: Query) { - isRunning() + fun updateQuery(query: Query) { Log.i(LOG_TAG, "Updating query for strategy=${query.getStrategy()}. PIDs=${query.getIDs()}") - if (isRunning()) { + if (DataLoggerRepository.isRunning()) { enqueueWork(UPDATE_QUERY) { it.putExtra(QUERY, query) } } else { Log.w(LOG_TAG, "No workflow is currently running. Query won't be updated.") } } - override fun status(): WorkflowStatus = workflowOrchestrator.status() - override fun scheduleStart(delay: Long, query: Query) { + + fun scheduleStart(delay: Long, query: Query) { enqueueWork(SCHEDULED_ACTION_START) { it.putExtra(SCHEDULED_START_DELAY, delay) it.putExtra(QUERY, query) } } - override fun scheduledStop() { + fun scheduledStop() { enqueueWork(SCHEDULED_ACTION_STOP) } - override fun executeRoutine(query: Query) { + fun executeRoutine(query: Query) { enqueueWork(EXECUTE_ROUTINE) { it.putExtra(QUERY, query) } } - override fun start(query: Query) { + fun start(query: Query) { enqueueWork(ACTION_START) { it.putExtra(QUERY, query) } } - override fun stop() { + fun stop() { enqueueWork(ACTION_STOP) } - override val eventsReceiver: BroadcastReceiver - get() = workflowOrchestrator.eventsReceiver - - override fun observe(lifecycleOwner: LifecycleOwner, observer: (metric: ObdMetric) -> Unit) { - workflowOrchestrator.observe(lifecycleOwner, observer) - } - - override fun observe(metricsProcessor: MetricsProcessor): DataLogger { - workflowOrchestrator.observe(metricsProcessor) - return this - } - - override fun getCurrentQuery(): Query? = workflowOrchestrator.getCurrentQuery() - override fun findAlertFor(metric: ObdMetric): List = workflowOrchestrator.findAlertFor(metric) - override fun isRunning(): Boolean = workflowOrchestrator.isRunning() - override fun getDiagnostics(): Diagnostics = workflowOrchestrator.diagnostics() - override fun findHistogramFor(metric: ObdMetric): Histogram = workflowOrchestrator.findHistogramFor(metric) - override fun findRateFor(metric: ObdMetric): Optional = workflowOrchestrator.findRateFor(metric) - override fun getPidDefinitionRegistry(): PidDefinitionRegistry = workflowOrchestrator.pidDefinitionRegistry() - override fun isDTCEnabled(): Boolean = workflowOrchestrator.isDTCEnabled() - // --- Helper Methods --- private fun enqueueWork(intentAction: String, func: (p: Intent) -> Unit = {}) { diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/VehicleCapabilitiesManager.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/VehicleCapabilitiesManager.kt index 7aefecb8..3da309b0 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/VehicleCapabilitiesManager.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/VehicleCapabilitiesManager.kt @@ -63,7 +63,7 @@ class VehicleCapabilitiesManager { } fun getCapabilities(): MutableList { - val pidList = dataLogger.getPidDefinitionRegistry().findAll() + val pidList = DataLoggerRepository.getPidDefinitionRegistry().findAll() return Prefs.getStringSet(PREF_VEHICLE_CAPABILITIES, emptySet())!!.toMutableList() .sortedWith(compareBy { t -> pidList.firstOrNull { a -> a.pid == t.uppercase() } }).toMutableList() } diff --git a/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricGeneratorDefinition.kt b/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricGeneratorDefinition.kt index c4a864a3..c6961bac 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricGeneratorDefinition.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricGeneratorDefinition.kt @@ -16,7 +16,7 @@ */ package org.obd.graphs.bl.generator -import org.obd.graphs.bl.datalogger.dataLogger + import org.obd.graphs.bl.datalogger.Pid import org.obd.metrics.pid.PidDefinition import org.obd.metrics.pid.PidDefinitionRegistry diff --git a/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricsGenerator.kt b/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricsGenerator.kt index bb65a7a2..a2db76bf 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricsGenerator.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/generator/MetricsGenerator.kt @@ -18,8 +18,8 @@ package org.obd.graphs.bl.generator import android.os.Handler import android.os.Looper +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.MetricsProcessor -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.bl.query.Query import org.obd.graphs.preferences.Prefs import org.obd.metrics.api.model.ObdMetric @@ -59,8 +59,8 @@ class MetricsGenerator(private val debugBuild: Boolean) : MetricsProcessor { override fun onRunning(vehicleCapabilities: VehicleCapabilities?) { if (isGeneratorEnabled()) { - val metrics = generateMetricsFor(dataLogger.getPidDefinitionRegistry(), - dataLogger.getCurrentQuery()) + val metrics = generateMetricsFor(DataLoggerRepository.getPidDefinitionRegistry(), + DataLoggerRepository.getCurrentQuery()) if (!broadcasterLaunched) { broadcasterLaunched = true @@ -93,7 +93,7 @@ class MetricsGenerator(private val debugBuild: Boolean) : MetricsProcessor { if (metrics.containsKey(id)) { add(metrics[id]!!) } else { - val pid = dataLogger.getPidDefinitionRegistry().findBy(id) + val pid = DataLoggerRepository.getPidDefinitionRegistry().findBy(id) val metric = MetricGeneratorDefinition( pid = pid, data = generateSequenceFor(pid) diff --git a/datalogger/src/main/java/org/obd/graphs/bl/gps/GpsMetricsEmitter.kt b/datalogger/src/main/java/org/obd/graphs/bl/gps/GpsMetricsEmitter.kt index 74ff10fd..3d230550 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/gps/GpsMetricsEmitter.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/gps/GpsMetricsEmitter.kt @@ -30,9 +30,9 @@ import android.os.Looper import android.util.Log import org.obd.graphs.LOCATION_IS_DISABLED import org.obd.graphs.Permissions +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.MetricsProcessor import org.obd.graphs.bl.datalogger.Pid -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.bl.datalogger.dataLoggerSettings import org.obd.graphs.getContext import org.obd.graphs.sendBroadcastEvent @@ -72,7 +72,7 @@ internal class GpsMetricsEmitter : MetricsProcessor { override fun init(replyObserver: ReplyObserver>) { this.replyObserver = replyObserver - val registry = dataLogger.getPidDefinitionRegistry() + val registry = DataLoggerRepository.getPidDefinitionRegistry() locationCommand = ObdCommand(registry.findBy(Pid.GPS_LOCATION_PID_ID.id)) } diff --git a/datalogger/src/main/java/org/obd/graphs/bl/trip/DefaultTripManager.kt b/datalogger/src/main/java/org/obd/graphs/bl/trip/DefaultTripManager.kt index c1cadb24..b8e2968a 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/trip/DefaultTripManager.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/trip/DefaultTripManager.kt @@ -18,8 +18,8 @@ package org.obd.graphs.bl.trip import android.content.Context import android.util.Log +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.MetricsProcessor -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.bl.datalogger.scaleToRange import org.obd.graphs.getContext import org.obd.graphs.isNumber @@ -125,8 +125,8 @@ internal class DefaultTripManager : } else { try { f() - val histogram = dataLogger.getDiagnostics().histogram() - val pidDefinitionRegistry = dataLogger.getPidDefinitionRegistry() + val histogram = DataLoggerRepository.getDiagnostics().histogram() + val pidDefinitionRegistry = DataLoggerRepository.getPidDefinitionRegistry() trip.entries.forEach { (t, u) -> val p = pidDefinitionRegistry.findBy(t) diff --git a/datalogger/src/main/java/org/obd/graphs/bl/trip/TripManager.kt b/datalogger/src/main/java/org/obd/graphs/bl/trip/TripManager.kt index 2a11ded4..1c512bf2 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/trip/TripManager.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/trip/TripManager.kt @@ -19,8 +19,8 @@ package org.obd.graphs.bl.trip import android.content.Context import android.util.Log import org.obd.graphs.* +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.MetricsProcessor -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.commons.R private const val LOG_TAG = "TripManager" @@ -48,7 +48,7 @@ interface TripManager : MetricsProcessor { fun deleteTrip(trip: TripFileDesc) fun loadTrip(tripName: String) fun loadTripAsync(tripName: String){ - if (!dataLogger.isRunning()) { + if (!DataLoggerRepository.isRunning()) { sendBroadcastEvent(SCREEN_LOCK_PROGRESS_EVENT, getContext()?.getText(R.string.dialog_screen_lock_trip_load_message) as String) runAsync (wait = false) { try { diff --git a/integrations/src/main/java/org/obd/graphs.integrations/gcp/gdrive/DefaultTripLogDriveManager.kt b/integrations/src/main/java/org/obd/graphs.integrations/gcp/gdrive/DefaultTripLogDriveManager.kt index 53af82df..9eb52017 100644 --- a/integrations/src/main/java/org/obd/graphs.integrations/gcp/gdrive/DefaultTripLogDriveManager.kt +++ b/integrations/src/main/java/org/obd/graphs.integrations/gcp/gdrive/DefaultTripLogDriveManager.kt @@ -17,13 +17,12 @@ package org.obd.graphs.integrations.gcp.gdrive import android.app.Activity -import android.util.Log import androidx.fragment.app.Fragment import org.obd.graphs.SCREEN_UNLOCK_PROGRESS_EVENT import org.obd.graphs.TRIPS_UPLOAD_FAILED import org.obd.graphs.TRIPS_UPLOAD_NO_FILES_SELECTED import org.obd.graphs.TRIPS_UPLOAD_SUCCESSFUL -import org.obd.graphs.bl.datalogger.dataLogger +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.scaleToRange import org.obd.graphs.bl.trip.TripDescParser import org.obd.graphs.integrations.log.OutputType @@ -48,7 +47,7 @@ internal open class DefaultTripLogDriveManager( sendBroadcastEvent(TRIPS_UPLOAD_NO_FILES_SELECTED) } else { val folderId = drive.findFolderIdRecursive("mygiulia/trips") - val definitions = dataLogger.getPidDefinitionRegistry().findAll() + val definitions = DataLoggerRepository.getPidDefinitionRegistry().findAll() val signalsMapper = definitions.associate { it.id.toInt() to it.description.replace("\n", " ") } val pidMap = definitions.associateBy { it.id.toInt() } val transformer = diff --git a/screen_renderer/src/main/java/org/obd/graphs/renderer/AbstractDrawer.kt b/screen_renderer/src/main/java/org/obd/graphs/renderer/AbstractDrawer.kt index d7d3d766..3f8cba4f 100644 --- a/screen_renderer/src/main/java/org/obd/graphs/renderer/AbstractDrawer.kt +++ b/screen_renderer/src/main/java/org/obd/graphs/renderer/AbstractDrawer.kt @@ -26,9 +26,9 @@ import android.graphics.Rect import android.graphics.Typeface import org.obd.graphs.bl.collector.Metric import org.obd.graphs.bl.collector.MetricsCollector +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.datalogger.Pid import org.obd.graphs.bl.datalogger.WorkflowStatus -import org.obd.graphs.bl.datalogger.dataLogger import org.obd.graphs.commons.R import org.obd.graphs.format import org.obd.graphs.mapRange @@ -195,7 +195,7 @@ internal abstract class AbstractDrawer( val color: Int val colorTheme = settings.getColorTheme() - text = dataLogger.status().name.lowercase() + text = DataLoggerRepository.status().name.lowercase() color = mapColor(colorTheme) @@ -316,7 +316,7 @@ internal abstract class AbstractDrawer( } private fun mapColor(colorTheme: ColorTheme) = - when (dataLogger.status()) { + when (DataLoggerRepository.status()) { WorkflowStatus.Disconnected -> { colorTheme.statusDisconnectedColor } From 1a7f48374b5e5062257ebb3a6a90c58415c28771 Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 20:55:55 +0100 Subject: [PATCH 02/26] feat: Introduce withDataLogger Fragment/Activity extensions --- .../org/obd/graphs/activity/MainActivity.kt | 67 ++--------- .../java/org/obd/graphs/activity/Receivers.kt | 23 ++-- .../java/org/obd/graphs/ui/BaseFragment.kt | 66 +++-------- .../org/obd/graphs/ui/DataLoggerConnector.kt | 78 ++++++++++++ .../graphs/ui/dashboard/DashboardFragment.kt | 79 ++++++------ .../ui/drag_racing/DragRacingFragment.kt | 11 +- .../org/obd/graphs/ui/gauge/GaugeFragment.kt | 15 ++- .../obd/graphs/ui/giulia/GiuliaFragment.kt | 15 ++- .../org/obd/graphs/ui/graph/GraphFragment.kt | 7 +- .../ui/performance/PerformanceFragment.kt | 76 +++++++----- .../graphs/ui/recycler/RefreshableFragment.kt | 112 ++++++++++-------- .../graphs/ui/trip_info/TripInfoFragment.kt | 12 +- 12 files changed, 318 insertions(+), 243 deletions(-) create mode 100644 app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt diff --git a/app/src/main/java/org/obd/graphs/activity/MainActivity.kt b/app/src/main/java/org/obd/graphs/activity/MainActivity.kt index 888b345e..304b1307 100644 --- a/app/src/main/java/org/obd/graphs/activity/MainActivity.kt +++ b/app/src/main/java/org/obd/graphs/activity/MainActivity.kt @@ -17,17 +17,13 @@ package org.obd.graphs.activity import android.content.BroadcastReceiver -import android.content.ComponentName import android.content.Context import android.content.Intent -import android.content.ServiceConnection import android.content.res.Configuration import android.os.Bundle -import android.os.IBinder import android.os.StrictMode import android.os.StrictMode.ThreadPolicy import android.os.StrictMode.VmPolicy -import android.util.Log import android.view.View import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity @@ -42,7 +38,6 @@ import org.obd.graphs.MAIN_ACTIVITY_EVENT_DESTROYED import org.obd.graphs.MAIN_ACTIVITY_EVENT_PAUSE import org.obd.graphs.Permissions import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.DataLoggerService import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.drag.dragRacingMetricsProcessor import org.obd.graphs.bl.extra.vehicleStatusMetricsProcessor @@ -63,30 +58,9 @@ const val LOG_TAG = "MainActivity" class MainActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks { - lateinit var lockScreenDialog: AlertDialog internal lateinit var backupManager: BackupManager - var dataLogger: DataLoggerService? = null - private var isBound = false - - - private val serviceConnection = object : ServiceConnection { - override fun onServiceConnected(className: ComponentName, service: IBinder) { - val binder = service as DataLoggerService.LocalBinder - dataLogger = binder.getService() - isBound = true - Log.i("ServiceConnection", "Service Connected! Ready to send commands.") - } - - override fun onServiceDisconnected(className: ComponentName) { - Log.e("ServiceConnection", "Service Disconnected unexpectedly.") - isBound = false - dataLogger = null - } - } - - internal var activityBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive( @@ -143,23 +117,6 @@ class MainActivity : fun getDrawer() = findViewById(R.id.drawer_layout) as DrawerLayout - - override fun onStart() { - super.onStart() - Intent(this, DataLoggerService::class.java).also { intent -> - bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) - } - } - - override fun onStop() { - super.onStop() - if (isBound) { - unbindService(serviceConnection) - isBound = false - dataLogger = null - } - } - override fun onPause() { super.onPause() sendBroadcastEvent(MAIN_ACTIVITY_EVENT_PAUSE) @@ -167,7 +124,7 @@ class MainActivity : override fun onSupportNavigateUp(): Boolean { val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController - return NavigationUI.navigateUp(navController,appBarConfiguration) || super.onSupportNavigateUp() + return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp() } override fun onCreate(savedInstanceState: Bundle?) { @@ -206,7 +163,6 @@ class MainActivity : validatePermissions() } - override fun onResume() { super.onResume() screen.setupWindowManager(this) @@ -230,15 +186,15 @@ class MainActivity : Thread.setDefaultUncaughtExceptionHandler(ExceptionHandler()) } - - fun getAppBarConfiguration(): AppBarConfiguration = AppBarConfiguration( - setOf( - R.id.nav_giulia, - R.id.nav_graph, - R.id.nav_gauge, - ), - findViewById(R.id.drawer_layout) - ) + fun getAppBarConfiguration(): AppBarConfiguration = + AppBarConfiguration( + setOf( + R.id.nav_giulia, + R.id.nav_graph, + R.id.nav_gauge, + ), + findViewById(R.id.drawer_layout), + ) private fun initCache() { cacheManager.initCache(cache) @@ -286,7 +242,8 @@ class MainActivity : } private fun setupMetricsProcessors() { - DataLoggerRepository.observe(dragRacingMetricsProcessor) + DataLoggerRepository + .observe(dragRacingMetricsProcessor) .observe(tripManager) .observe(vehicleStatusMetricsProcessor) .observe(gpsMetricsEmitter) diff --git a/app/src/main/java/org/obd/graphs/activity/Receivers.kt b/app/src/main/java/org/obd/graphs/activity/Receivers.kt index 2c868f03..2a644c0e 100644 --- a/app/src/main/java/org/obd/graphs/activity/Receivers.kt +++ b/app/src/main/java/org/obd/graphs/activity/Receivers.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -82,6 +82,7 @@ import org.obd.graphs.registerReceiver import org.obd.graphs.ui.common.COLOR_CARDINAL import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.toast +import org.obd.graphs.ui.withDataLogger internal val powerReceiver = PowerBroadcastReceiver() const val NOTIFICATION_GRAPH_VIEW_TOGGLE = "view.graph.toggle" @@ -102,8 +103,10 @@ internal fun MainActivity.receive(intent: Intent?) { LOG_TAG, "Stop data logging", ) - dataLogger?.stop() - dataLogger?.scheduledStop() + withDataLogger { dataLogger -> + dataLogger.stop() + dataLogger.scheduledStop() + } } NAVIGATION_BUTTONS_VISIBILITY_CHANGED -> setupNavigationBar() @@ -159,7 +162,9 @@ internal fun MainActivity.receive(intent: Intent?) { UsbManager.ACTION_USB_DEVICE_DETACHED -> { val usbDevice: UsbDevice = intent.extras?.get(UsbManager.EXTRA_DEVICE) as UsbDevice toast(R.string.pref_usb_device_detached, usbDevice.productName!!) - dataLogger?.stop() + withDataLogger { dataLogger -> + dataLogger.stop() + } } USB_DEVICE_ATTACHED_EVENT -> { @@ -220,7 +225,9 @@ internal fun MainActivity.receive(intent: Intent?) { ContextCompat.getColorStateList(applicationContext, org.obd.graphs.commons.R.color.cardinal) it.setOnClickListener { Log.i(LOG_TAG, "Stop data logging ") - dataLogger?.stop() + withDataLogger { dataLogger -> + dataLogger.stop() + } } it.refreshDrawableState() } @@ -273,7 +280,9 @@ internal fun MainActivity.receive(intent: Intent?) { updateVehicleStatus("Key off") if (dataLoggerSettings.instance().vehicleStatusDisconnectWhenOff) { Log.i(LOG_TAG, "Received vehicle status OFF event. Closing the session.") - dataLogger?.stop() + withDataLogger { dataLogger -> + dataLogger.stop() + } } } } @@ -376,7 +385,7 @@ internal fun MainActivity.registerReceiver() { it.addAction("android.intent.action.ACTION_POWER_DISCONNECTED") } - registerReceiver(this,DataLoggerRepository.eventsReceiver) { + registerReceiver(this, DataLoggerRepository.eventsReceiver) { it.addAction(MODULES_LIST_CHANGED_EVENT) it.addAction(PROFILE_CHANGED_EVENT) } diff --git a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt index 0ee8f43c..406ab4cc 100644 --- a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -17,73 +17,45 @@ package org.obd.graphs.ui import android.app.Activity -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.ServiceConnection -import android.os.IBinder import android.util.Log import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import com.google.android.material.floatingactionbutton.FloatingActionButton import org.obd.graphs.R -import org.obd.graphs.bl.datalogger.DataLoggerService import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.query.Query abstract class BaseFragment : Fragment() { - - protected var dataLogger: DataLoggerService? = null - private var isBound = false - - private val serviceConnection = object : ServiceConnection { - override fun onServiceConnected(className: ComponentName, service: IBinder) { - val binder = service as DataLoggerService.LocalBinder - dataLogger = binder.getService() - isBound = true - } - - override fun onServiceDisconnected(className: ComponentName) { - dataLogger = null - isBound = false - } - } - - override fun onStart() { - super.onStart() - val intent = Intent(requireContext(), DataLoggerService::class.java) - requireContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) - } - - override fun onStop() { - super.onStop() - if (isBound) { - requireContext().unbindService(serviceConnection) - isBound = false - } - dataLogger = null - } - protected fun attachToFloatingButton( activity: Activity?, - query: Query + query: Query, ) { activity?.let { val btn = activity.findViewById(R.id.connect_btn) - btn?.setOnClickListener { + btn?.setOnClickListener { if (DataLoggerRepository.isRunning()) { - Log.i("BaseFragment", "DragRacingFragment: Start data logging") - dataLogger?.stop() + withDataLogger { dataLogger -> + Log.i("BaseFragment", "DragRacingFragment: Start data logging") + dataLogger.stop() + } } else { - Log.i("BaseFragment", "Start data logging") - dataLogger?.start(query) + withDataLogger { dataLogger -> + Log.i("BaseFragment", "Start data logging") + dataLogger.start(query) + } } } btn?.backgroundTintList = - ContextCompat.getColorStateList(activity, if (DataLoggerRepository.isRunning()) org.obd.graphs.commons.R.color.cardinal - else org.obd.graphs.commons.R.color.philippine_green) + ContextCompat.getColorStateList( + activity, + if (DataLoggerRepository.isRunning()) { + org.obd.graphs.commons.R.color.cardinal + } else { + org.obd.graphs.commons.R.color.philippine_green + }, + ) } } } diff --git a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt b/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt new file mode 100644 index 00000000..aac2948b --- /dev/null +++ b/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt @@ -0,0 +1,78 @@ + /** + * Copyright 2019-2026, Tomasz Żebrowski + * + *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.obd.graphs.ui + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import androidx.activity.ComponentActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import org.obd.graphs.bl.datalogger.DataLoggerService + +fun Fragment.withDataLogger(onConnected: (DataLoggerService) -> Unit) { + val connector = DataLoggerConnector(requireContext(), onConnected) + this.lifecycle.addObserver(connector) +} + +fun ComponentActivity.withDataLogger(onConnected: (DataLoggerService) -> Unit) { + val connector = DataLoggerConnector(this, onConnected) + this.lifecycle.addObserver(connector) +} + +class DataLoggerConnector( + private val context: Context, + private val onServiceConnected: (DataLoggerService) -> Unit, +) : DefaultLifecycleObserver { + private var dataLogger: DataLoggerService? = null + private var isBound = false + + private val serviceConnection = + object : ServiceConnection { + override fun onServiceConnected( + className: ComponentName, + service: IBinder, + ) { + val binder = service as DataLoggerService.LocalBinder + val logger = binder.getService() + dataLogger = logger + isBound = true + onServiceConnected(logger) + } + + override fun onServiceDisconnected(className: ComponentName) { + dataLogger = null + isBound = false + } + } + + override fun onStart(owner: LifecycleOwner) { + val intent = Intent(context, DataLoggerService::class.java) + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } + + override fun onStop(owner: LifecycleOwner) { + if (isBound) { + context.unbindService(serviceConnection) + isBound = false + } + dataLogger = null + } +} diff --git a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt index d4fc156c..6274e744 100644 --- a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -39,38 +39,44 @@ import org.obd.graphs.preferences.getS import org.obd.graphs.registerReceiver import org.obd.graphs.ui.gauge.AdapterContext import org.obd.graphs.ui.recycler.RefreshableFragment +import org.obd.graphs.ui.withDataLogger private const val CONFIGURATION_CHANGE_EVENT_DASH = "recycler.view.change.configuration.event.dash_id" class DashboardFragment : RefreshableFragment() { private val metricsCollector = MetricsCollector.instance() - private val renderingThread: RenderingThread = RenderingThread( - renderAction = { - refreshRecyclerView(metricsCollector, R.id.dashboard_recycler_view) - }, - perfFrameRate = { - Prefs.getS("pref.dashboard.fps", "10").toInt() - } - ) + private val renderingThread: RenderingThread = + RenderingThread( + renderAction = { + refreshRecyclerView(metricsCollector, R.id.dashboard_recycler_view) + }, + perfFrameRate = { + Prefs.getS("pref.dashboard.fps", "10").toInt() + }, + ) private val dashboardPreferences: DashboardPreferences by lazy { getDashboardPreferences() } - private var broadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - when (intent?.action) { - CONFIGURATION_CHANGE_EVENT_DASH -> setupDashboardRecyclerView(false) - - DATA_LOGGER_CONNECTED_EVENT -> { - renderingThread.start() - } - - DATA_LOGGER_STOPPED_EVENT -> { - renderingThread.stop() - attachToFloatingButton(activity, query()) + private var broadcastReceiver = + object : BroadcastReceiver() { + override fun onReceive( + context: Context?, + intent: Intent?, + ) { + when (intent?.action) { + CONFIGURATION_CHANGE_EVENT_DASH -> setupDashboardRecyclerView(false) + + DATA_LOGGER_CONNECTED_EVENT -> { + renderingThread.start() + } + + DATA_LOGGER_STOPPED_EVENT -> { + renderingThread.stop() + attachToFloatingButton(activity, query()) + } } } } - } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) @@ -100,7 +106,7 @@ class DashboardFragment : RefreshableFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { root = inflater.inflate(R.layout.fragment_dashboard, container, false) setupDashboardRecyclerView(true) @@ -112,7 +118,9 @@ class DashboardFragment : RefreshableFragment() { } if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query()) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query()) + } renderingThread.start() } @@ -128,21 +136,24 @@ class DashboardFragment : RefreshableFragment() { configureChangeEventId = CONFIGURATION_CHANGE_EVENT_DASH, recyclerView = root.findViewById(R.id.dashboard_recycler_view)!!, metricsIdsPref = dashboardPreferences.dashboardSelectedMetrics.first, - adapterContext = AdapterContext( - layoutId = R.layout.item_dashboard, - spanCount = calculateSpanCount(), - height = calculateHeight(Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size) - ), + adapterContext = + AdapterContext( + layoutId = R.layout.item_dashboard, + spanCount = calculateSpanCount(), + height = calculateHeight(Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size), + ), enableDragManager = dashboardPreferences.dragAndDropEnabled, enableOnTouchListener = enableOnTouchListener, enableSwipeToDelete = dashboardPreferences.swipeToDeleteEnabled, - adapter = { context: Context, - data: MutableList, - resourceId: Int, - height: Int? -> + adapter = { + context: Context, + data: MutableList, + resourceId: Int, + height: Int?, + -> DashboardViewAdapter(context, data, resourceId, height) }, - metricsSerializerPref = "prefs.dash.pids.settings" + metricsSerializerPref = "prefs.dash.pids.settings", ) metricsCollector.applyFilter(dashboardPreferences.dashboardSelectedMetrics.second) diff --git a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt index 55d38bf1..bd55dd68 100644 --- a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -40,6 +40,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController +import org.obd.graphs.ui.withDataLogger open class DragRacingFragment : BaseFragment() { @@ -65,7 +66,9 @@ open class DragRacingFragment : BaseFragment() { when (intent?.action) { DATA_LOGGER_CONNECTED_EVENT -> { - dataLogger?.updateQuery(query) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query) + } renderingThread.start() } @@ -130,7 +133,9 @@ open class DragRacingFragment : BaseFragment() { } if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query) + } renderingThread.start() } diff --git a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt index 295a88dd..03a4d732 100644 --- a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt @@ -42,6 +42,7 @@ import org.obd.graphs.registerReceiver import org.obd.graphs.ui.common.* import org.obd.graphs.ui.recycler.RecyclerViewAdapter import org.obd.graphs.ui.recycler.RefreshableFragment +import org.obd.graphs.ui.withDataLogger import kotlin.math.roundToInt private const val ENABLE_DRAG_AND_DROP_PREF = "pref.gauge_enable_drag_and_drop" @@ -61,7 +62,6 @@ class GaugeFragment : RefreshableFragment() { } ) - @SuppressLint("NotifyDataSetChanged") private var broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -69,7 +69,9 @@ class GaugeFragment : RefreshableFragment() { DATA_LOGGER_SCHEDULED_START_EVENT -> { if (isAdded && isVisible) { Log.i(org.obd.graphs.activity.LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - dataLogger?.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + withDataLogger { dataLogger -> + dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + } } } @@ -133,7 +135,10 @@ class GaugeFragment : RefreshableFragment() { setupVirtualViewPanel() if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query()) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query()) + } + renderingThread.start() } @@ -238,7 +243,9 @@ class GaugeFragment : RefreshableFragment() { gaugeVirtualScreen.updateVirtualScreen(viewId) if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query()) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query()) + } } configureView(true) diff --git a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt index 3c7ecd5a..6bb8f55d 100644 --- a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -46,6 +46,7 @@ import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.SurfaceController +import org.obd.graphs.ui.withDataLogger open class GiuliaFragment : BaseFragment() { private lateinit var root: View @@ -80,7 +81,9 @@ open class GiuliaFragment : BaseFragment() { DATA_LOGGER_SCHEDULED_START_EVENT -> { if (isAdded && isVisible) { Log.i(LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - dataLogger?.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + withDataLogger { dataLogger -> + dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + } } } @@ -152,7 +155,9 @@ open class GiuliaFragment : BaseFragment() { } if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query()) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query()) + } renderingThread.start() } @@ -175,8 +180,10 @@ open class GiuliaFragment : BaseFragment() { it.setOnClickListener { giuliaVirtualScreen.updateVirtualScreen(viewId) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query()) + } - dataLogger?.updateQuery(query()) applyFilter() setupVirtualViewPanel() surfaceController.renderFrame() diff --git a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt index 57631cd3..2129845c 100644 --- a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -65,6 +65,7 @@ import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.Colors import org.obd.graphs.ui.common.onDoubleClickListener +import org.obd.graphs.ui.withDataLogger import org.obd.metrics.api.model.ObdMetric import org.obd.metrics.pid.PidDefinition import org.obd.metrics.pid.PidDefinitionRegistry @@ -85,7 +86,9 @@ class GraphFragment : BaseFragment() { DATA_LOGGER_SCHEDULED_START_EVENT -> { if (isAdded && isVisible) { Log.i(org.obd.graphs.activity.LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - dataLogger?.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + withDataLogger { dataLogger -> + dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + } } } diff --git a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt index 035beef1..b4ce0522 100644 --- a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -41,6 +41,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController +import org.obd.graphs.ui.withDataLogger open class PerformanceFragment : BaseFragment() { private lateinit var root: View @@ -52,37 +53,42 @@ open class PerformanceFragment : BaseFragment() { private val settings = PerformanceSettings() private lateinit var surfaceController: SurfaceController - private val renderingThread: RenderingThread = RenderingThread( - id = "DragRacingRenderingThread", - renderAction = { - surfaceController.renderFrame() - }, - perfFrameRate = { - settings.getSurfaceFrameRate() - } - ) - - private var broadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - when (intent?.action) { - - DATA_LOGGER_CONNECTED_EVENT -> { - dataLogger?.updateQuery(query) - renderingThread.start() - } + private val renderingThread: RenderingThread = + RenderingThread( + id = "DragRacingRenderingThread", + renderAction = { + surfaceController.renderFrame() + }, + perfFrameRate = { + settings.getSurfaceFrameRate() + }, + ) - DATA_LOGGER_STOPPED_EVENT -> { - renderingThread.stop() - attachToFloatingButton(activity, query) + private var broadcastReceiver = + object : BroadcastReceiver() { + override fun onReceive( + context: Context?, + intent: Intent?, + ) { + when (intent?.action) { + DATA_LOGGER_CONNECTED_EVENT -> { + withDataLogger { dataLogger -> + dataLogger.updateQuery(query) + } + renderingThread.start() + } + + DATA_LOGGER_STOPPED_EVENT -> { + renderingThread.stop() + attachToFloatingButton(activity, query) + } } } } - } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) surfaceController.renderFrame() - } override fun onAttach(context: Context) { @@ -109,22 +115,26 @@ open class PerformanceFragment : BaseFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { - root = inflater.inflate(R.layout.fragment_drag_racing, container, false) val surfaceView = root.findViewById(R.id.surface_view) - val renderer = SurfaceRenderer.allocate( - requireContext(), settings, metricsCollector, fps, - surfaceRendererType = SurfaceRendererType.PERFORMANCE, viewSettings = ViewSettings(marginTop = 20) - ) + val renderer = + SurfaceRenderer.allocate( + requireContext(), + settings, + metricsCollector, + fps, + surfaceRendererType = SurfaceRendererType.PERFORMANCE, + viewSettings = ViewSettings(marginTop = 20), + ) surfaceController = SurfaceController(renderer) surfaceView.holder.addCallback(surfaceController) metricsCollector.applyFilter( - enabled = query.getIDs() + enabled = query.getIDs(), ) DataLoggerRepository.observe(viewLifecycleOwner) { @@ -134,7 +144,9 @@ open class PerformanceFragment : BaseFragment() { } if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query) + } renderingThread.start() } diff --git a/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt b/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt index 0f753e1e..25048b94 100644 --- a/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/recycler/RefreshableFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -37,11 +37,13 @@ import org.obd.graphs.ui.common.ToggleToolbarDoubleClickListener import org.obd.graphs.ui.gauge.AdapterContext open class RefreshableFragment : BaseFragment() { - protected val query: Query = Query.instance() protected lateinit var root: View - protected fun refreshRecyclerView(metricsCollector: MetricsCollector, recyclerViewId: Int) { + protected fun refreshRecyclerView( + metricsCollector: MetricsCollector, + recyclerViewId: Int, + ) { if (::root.isInitialized) { val adapter = ((root.findViewById(recyclerViewId)!!).adapter) as RecyclerViewAdapter val data = adapter.data @@ -59,7 +61,7 @@ open class RefreshableFragment : BaseFragment() { protected fun prepareMetrics( metricsIdsPref: String, - metricsSerializerPref: String + metricsSerializerPref: String, ): MutableList { val viewPreferences = ViewPreferencesSerializer(metricsSerializerPref) val metricsIds = query.filterBy(metricsIdsPref) @@ -79,20 +81,20 @@ open class RefreshableFragment : BaseFragment() { context: Context, data: MutableList, resourceId: Int, - height: Int? + height: Int?, ) -> RecyclerViewAdapter<*>, - metricsSerializerPref: String + metricsSerializerPref: String, ) { - val viewPreferences = ViewPreferencesSerializer(metricsSerializerPref) val metricsIds = query.filterBy(metricsIdsPref) val metrics = MetricsBuilder().buildFor(metricsIds, viewPreferences.getItemsSortOrder()) recyclerView.layoutManager = GridLayoutManager(requireContext(), adapterContext.spanCount) - recyclerView.adapter = adapter(requireContext(), metrics, adapterContext.layoutId, adapterContext.height).apply { - setHasStableIds(true) - notifyDataSetChanged() - } + recyclerView.adapter = + adapter(requireContext(), metrics, adapterContext.layoutId, adapterContext.height).apply { + setHasStableIds(true) + notifyDataSetChanged() + } attachDragManager( configureChangeEventId = configureChangeEventId, @@ -100,7 +102,7 @@ open class RefreshableFragment : BaseFragment() { enableDragManager = enableDragManager, recyclerView = recyclerView, metricsIdsPref = metricsIdsPref, - viewPreferences = viewPreferences + viewPreferences = viewPreferences, ) attachOnTouchListener(enableOnTouchListener, recyclerView) @@ -112,41 +114,45 @@ open class RefreshableFragment : BaseFragment() { configureChangeEventId: String, recyclerView: RecyclerView, metricsIdsPref: String, - viewSerializer: ViewPreferencesSerializer - ): SwappableAdapter = object : SwappableAdapter { - override fun swapItems(fromPosition: Int, toPosition: Int) { - adapter(recyclerView).swapItems( - fromPosition, - toPosition - ) - } + viewSerializer: ViewPreferencesSerializer, + ): SwappableAdapter = + object : SwappableAdapter { + override fun swapItems( + fromPosition: Int, + toPosition: Int, + ) { + adapter(recyclerView).swapItems( + fromPosition, + toPosition, + ) + } - override fun storePreferences(context: Context) { - viewSerializer.store(adapter(recyclerView).data.map { it.source.command.pid.id }) - } + override fun storePreferences(context: Context) { + viewSerializer.store(adapter(recyclerView).data.map { it.source.command.pid.id }) + } - override fun deleteItems(fromPosition: Int) { - val data = adapter(recyclerView).data - val itemId: Metric = data[fromPosition] - data.remove(itemId) + override fun deleteItems(fromPosition: Int) { + val data = adapter(recyclerView).data + val itemId: Metric = data[fromPosition] + data.remove(itemId) - Prefs.updateLongSet( - metricsIdsPref, - data.map { obdMetric -> obdMetric.source.command.pid.id }.toList() - ) - sendBroadcastEvent(configureChangeEventId) + Prefs.updateLongSet( + metricsIdsPref, + data.map { obdMetric -> obdMetric.source.command.pid.id }.toList(), + ) + sendBroadcastEvent(configureChangeEventId) + } } - } private fun attachOnTouchListener( enableOnTouchListener: Boolean, - recyclerView: RecyclerView + recyclerView: RecyclerView, ) { if (enableOnTouchListener) { recyclerView.addOnItemTouchListener( ToggleToolbarDoubleClickListener( - requireContext() - ) + requireContext(), + ), ) } } @@ -157,29 +163,31 @@ open class RefreshableFragment : BaseFragment() { enableSwipeToDelete: Boolean = false, recyclerView: RecyclerView, metricsIdsPref: String, - viewPreferences: ViewPreferencesSerializer + viewPreferences: ViewPreferencesSerializer, ) { if (enableDragManager) { val swappableAdapter = createSwappableAdapter(configureChangeEventId, recyclerView, metricsIdsPref, viewPreferences) - val callback = if (enableSwipeToDelete) - DragManageAdapter( - requireContext(), - ItemTouchHelper.UP or ItemTouchHelper.DOWN, - ItemTouchHelper.START or ItemTouchHelper.END, swappableAdapter - ) - else - DragManageAdapter( - requireContext(), - ItemTouchHelper.UP or ItemTouchHelper.DOWN, - ItemTouchHelper.ACTION_STATE_DRAG, swappableAdapter - ) + val callback = + if (enableSwipeToDelete) { + DragManageAdapter( + requireContext(), + ItemTouchHelper.UP or ItemTouchHelper.DOWN, + ItemTouchHelper.START or ItemTouchHelper.END, + swappableAdapter, + ) + } else { + DragManageAdapter( + requireContext(), + ItemTouchHelper.UP or ItemTouchHelper.DOWN, + ItemTouchHelper.ACTION_STATE_DRAG, + swappableAdapter, + ) + } ItemTouchHelper(callback).attachToRecyclerView(recyclerView) } } - private fun adapter(recyclerView: RecyclerView) = - (recyclerView.adapter as RecyclerViewAdapter) - + private fun adapter(recyclerView: RecyclerView) = (recyclerView.adapter as RecyclerViewAdapter) } diff --git a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt index 99eeb6a7..ed6ecb79 100644 --- a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -41,6 +41,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController +import org.obd.graphs.ui.withDataLogger open class TripInfoFragment : BaseFragment() { private lateinit var root: View @@ -67,7 +68,9 @@ open class TripInfoFragment : BaseFragment() { when (intent?.action) { DATA_LOGGER_CONNECTED_EVENT -> { - dataLogger?.updateQuery(query) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query) + } renderingThread.start() } @@ -134,7 +137,10 @@ open class TripInfoFragment : BaseFragment() { } if (DataLoggerRepository.isRunning()) { - dataLogger?.updateQuery(query) + withDataLogger { dataLogger -> + dataLogger.updateQuery(query) + } + renderingThread.start() } From a74e7328067e753a406291933dcd809a6b3a4c19 Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 21:02:43 +0100 Subject: [PATCH 03/26] fix: apply spotless fixes --- .../org/obd/graphs/PowerBroadcastReceiver.kt | 2 +- .../org/obd/graphs/activity/Navigation.kt | 2 +- .../java/org/obd/graphs/ui/BaseFragment.kt | 2 +- .../org/obd/graphs/ui/DataLoggerConnector.kt | 2 + .../bl/datalogger/DataLoggerConstants.kt | 2 +- .../graphs/bl/datalogger/DataLoggerService.kt | 2 +- .../bl/query/QueryStrategyOrchestrator.kt | 57 +++++++++++-------- 7 files changed, 40 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt b/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt index 4aed49bd..5e212a64 100644 --- a/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt +++ b/app/src/main/java/org/obd/graphs/PowerBroadcastReceiver.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license diff --git a/app/src/main/java/org/obd/graphs/activity/Navigation.kt b/app/src/main/java/org/obd/graphs/activity/Navigation.kt index c7ad511f..51ff0aa4 100644 --- a/app/src/main/java/org/obd/graphs/activity/Navigation.kt +++ b/app/src/main/java/org/obd/graphs/activity/Navigation.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license diff --git a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt index 406ab4cc..caaf7855 100644 --- a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt @@ -36,7 +36,7 @@ abstract class BaseFragment : Fragment() { btn?.setOnClickListener { if (DataLoggerRepository.isRunning()) { withDataLogger { dataLogger -> - Log.i("BaseFragment", "DragRacingFragment: Start data logging") + Log.i("BaseFragment", "Stop data logging") dataLogger.stop() } } else { diff --git a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt b/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt index aac2948b..63df5646 100644 --- a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt +++ b/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder +import android.util.Log import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment import androidx.lifecycle.DefaultLifecycleObserver @@ -69,6 +70,7 @@ class DataLoggerConnector( } override fun onStop(owner: LifecycleOwner) { + if (isBound) { context.unbindService(serviceConnection) isBound = false diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt index 20571acc..e2b028f3 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConstants.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt index 9a9510ca..16f4d087 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license diff --git a/datalogger/src/main/java/org/obd/graphs/bl/query/QueryStrategyOrchestrator.kt b/datalogger/src/main/java/org/obd/graphs/bl/query/QueryStrategyOrchestrator.kt index 5e60e6c5..3c61178c 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/query/QueryStrategyOrchestrator.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/query/QueryStrategyOrchestrator.kt @@ -23,41 +23,46 @@ import org.obd.graphs.preferences.Prefs import org.obd.graphs.preferences.getLongSet import org.obd.graphs.runAsync -private const val LOG_KEY = "QueryStrategyOrchestrator" - -internal class QueryStrategyOrchestrator : java.io.Serializable, Query { - - private val strategies: Map = mutableMapOf().apply { - runAsync { - this[QueryStrategyType.SHARED_QUERY] = SharedQueryStrategy() - this[QueryStrategyType.DRAG_RACING_QUERY] = DragRacingQueryStrategy() - this[QueryStrategyType.INDIVIDUAL_QUERY] = IndividualQueryStrategy() - this[QueryStrategyType.ROUTINES_QUERY] = RoutinesQueryStrategy() - this[QueryStrategyType.TRIP_INFO_QUERY] = TripInfoQueryStrategy() - this[QueryStrategyType.PERFORMANCE_QUERY] = PerformanceQueryStrategy() +private const val LOG_KEY = "QueryOrchestrator" + +internal class QueryStrategyOrchestrator : + java.io.Serializable, + Query { + private val strategies: Map = + mutableMapOf().apply { + runAsync { + this[QueryStrategyType.SHARED_QUERY] = SharedQueryStrategy() + this[QueryStrategyType.DRAG_RACING_QUERY] = DragRacingQueryStrategy() + this[QueryStrategyType.INDIVIDUAL_QUERY] = IndividualQueryStrategy() + this[QueryStrategyType.ROUTINES_QUERY] = RoutinesQueryStrategy() + this[QueryStrategyType.TRIP_INFO_QUERY] = TripInfoQueryStrategy() + this[QueryStrategyType.PERFORMANCE_QUERY] = PerformanceQueryStrategy() + } } - } private var strategy: QueryStrategyType = QueryStrategyType.SHARED_QUERY + override fun getDefaults(): Set = strategies[strategy]?.getDefaults() ?: emptySet() - override fun getIDs(): MutableSet { + override fun getIDs(): MutableSet { val pids = strategies[strategy]?.getPIDs() ?: mutableSetOf() - //decorate with Vehicle Status PID + // decorate with Vehicle Status PID if (dataLoggerSettings.instance().vehicleStatusPanelEnabled || - dataLoggerSettings.instance().vehicleStatusDisconnectWhenOff){ + dataLoggerSettings.instance().vehicleStatusDisconnectWhenOff + ) { pids.add(Pid.VEHICLE_STATUS_PID_ID.id) } - - Log.d(LOG_KEY,"Gets PIDs '$pids' for current strategy $strategy") + if (Log.isLoggable(LOG_KEY, Log.DEBUG)) { + Log.d(LOG_KEY, "Gets PIDs '$pids' for current strategy $strategy") + } return pids } override fun getStrategy(): QueryStrategyType = strategy override fun setStrategy(queryStrategyType: QueryStrategyType): Query { - Log.d(LOG_KEY,"Sets new strategy $queryStrategyType") + Log.d(LOG_KEY, "Sets new strategy $queryStrategyType") this.strategy = queryStrategyType return this } @@ -70,19 +75,23 @@ internal class QueryStrategyOrchestrator : java.io.Serializable, Query { override fun filterBy(filter: String): Set { val query = getIDs() val selection = Prefs.getLongSet(filter) - val intersection = selection.filter { query.contains(it) }.toSet() + val intersection = selection.filter { query.contains(it) }.toSet() - Log.i(LOG_KEY,"Individual query enabled:${isIndividualQuerySelected()}, " + - " key:$filter, query=$query,selection=$selection, intersection=$intersection") + Log.i( + LOG_KEY, + "Individual query enabled:${isIndividualQuerySelected()}, " + + " key:$filter, query=$query,selection=$selection, intersection=$intersection", + ) return if (isIndividualQuerySelected()) { - Log.i(LOG_KEY,"Returning selection=$selection") + Log.i(LOG_KEY, "Returning selection=$selection") selection } else { - Log.i(LOG_KEY,"Returning intersection=$intersection") + Log.i(LOG_KEY, "Returning intersection=$intersection") intersection } } + override fun apply(filter: String): Query = if (isIndividualQuerySelected()) { setStrategy(QueryStrategyType.INDIVIDUAL_QUERY) From 757cfbf34f22c878728ccef2bb395be0168158ee Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 21:06:15 +0100 Subject: [PATCH 04/26] refactor: Move DataLoggerRepository to separate cass --- .../org/obd/graphs/ui/DataLoggerConnector.kt | 1 - .../bl/datalogger/DataLoggerRepository.kt | 71 +++++++++++ .../graphs/bl/datalogger/DataLoggerService.kt | 118 ++++++------------ 3 files changed, 108 insertions(+), 82 deletions(-) create mode 100644 datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerRepository.kt diff --git a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt b/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt index 63df5646..1526297f 100644 --- a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt +++ b/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt @@ -21,7 +21,6 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder -import android.util.Log import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment import androidx.lifecycle.DefaultLifecycleObserver diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerRepository.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerRepository.kt new file mode 100644 index 00000000..95fe9c0c --- /dev/null +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerRepository.kt @@ -0,0 +1,71 @@ + /** + * Copyright 2019-2026, Tomasz Żebrowski + * + *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.obd.graphs.bl.datalogger + +import android.content.BroadcastReceiver +import android.util.Log +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.LifecycleOwner +import org.obd.graphs.bl.query.Query +import org.obd.metrics.alert.Alert +import org.obd.metrics.api.model.ObdMetric +import org.obd.metrics.diagnostic.Diagnostics +import org.obd.metrics.diagnostic.Histogram +import org.obd.metrics.diagnostic.Rate +import org.obd.metrics.pid.PidDefinitionRegistry +import java.util.Optional + +object DataLoggerRepository { + private var _workflowOrchestrator: WorkflowOrchestrator? = null + + internal val workflowOrchestrator: WorkflowOrchestrator + get() { + if (_workflowOrchestrator == null) { + Log.i(LOG_TAG, "Initializing WorkflowOrchestrator") + _workflowOrchestrator = WorkflowOrchestrator() + } + return _workflowOrchestrator!! + } + + @VisibleForTesting + internal fun setWorkflowOrchestrator(mock: WorkflowOrchestrator) { + _workflowOrchestrator = mock + } + + fun getCurrentQuery(): Query? = workflowOrchestrator.getCurrentQuery() + fun findAlertFor(metric: ObdMetric): List = workflowOrchestrator.findAlertFor(metric) + fun isRunning(): Boolean = workflowOrchestrator.isRunning() + fun getDiagnostics(): Diagnostics = workflowOrchestrator.diagnostics() + fun findHistogramFor(metric: ObdMetric): Histogram = workflowOrchestrator.findHistogramFor(metric) + fun findRateFor(metric: ObdMetric): Optional = workflowOrchestrator.findRateFor(metric) + fun getPidDefinitionRegistry(): PidDefinitionRegistry = workflowOrchestrator.pidDefinitionRegistry() + fun isDTCEnabled(): Boolean = workflowOrchestrator.isDTCEnabled() + fun status(): WorkflowStatus = workflowOrchestrator.status() + + fun observe(lifecycleOwner: LifecycleOwner, observer: (metric: ObdMetric) -> Unit) { + workflowOrchestrator.observe(lifecycleOwner, observer) + } + + fun observe(metricsProcessor: MetricsProcessor): DataLoggerRepository { + workflowOrchestrator.observe(metricsProcessor) + return this + } + + + val eventsReceiver: BroadcastReceiver + get() = workflowOrchestrator.eventsReceiver +} diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt index 16f4d087..9ebe18ab 100644 --- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerService.kt @@ -22,28 +22,18 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.app.Service -import android.content.BroadcastReceiver import android.content.Intent import android.os.Binder import android.os.Build import android.os.IBinder import android.util.Log -import androidx.annotation.VisibleForTesting import androidx.core.app.NotificationCompat -import androidx.lifecycle.LifecycleOwner import org.obd.graphs.Permissions import org.obd.graphs.REQUEST_NOTIFICATION_PERMISSIONS import org.obd.graphs.bl.query.Query import org.obd.graphs.datalogger.R import org.obd.graphs.getContext import org.obd.graphs.sendBroadcastEvent -import org.obd.metrics.alert.Alert -import org.obd.metrics.api.model.ObdMetric -import org.obd.metrics.diagnostic.Diagnostics -import org.obd.metrics.diagnostic.Histogram -import org.obd.metrics.diagnostic.Rate -import org.obd.metrics.pid.PidDefinitionRegistry -import java.util.Optional private const val SCHEDULED_ACTION_START = "org.obd.graphs.logger.scheduled.START" private const val SCHEDULED_ACTION_STOP = "org.obd.graphs.logger.scheduled.STOP" @@ -58,50 +48,7 @@ private const val EXECUTE_ROUTINE = "org.obd.graphs.logger.EXECUTE_ROUTINE" private const val NOTIFICATION_CHANNEL_ID = "data_logger_channel_v2" private const val NOTIFICATION_ID = 12345 -object DataLoggerRepository { - private var _workflowOrchestrator: WorkflowOrchestrator? = null - - internal val workflowOrchestrator: WorkflowOrchestrator - get() { - if (_workflowOrchestrator == null) { - Log.i(LOG_TAG, "Initializing WorkflowOrchestrator") - _workflowOrchestrator = WorkflowOrchestrator() - } - return _workflowOrchestrator!! - } - - @VisibleForTesting - internal fun setWorkflowOrchestrator(mock: WorkflowOrchestrator) { - _workflowOrchestrator = mock - } - - fun getCurrentQuery(): Query? = workflowOrchestrator.getCurrentQuery() - fun findAlertFor(metric: ObdMetric): List = workflowOrchestrator.findAlertFor(metric) - fun isRunning(): Boolean = workflowOrchestrator.isRunning() - fun getDiagnostics(): Diagnostics = workflowOrchestrator.diagnostics() - fun findHistogramFor(metric: ObdMetric): Histogram = workflowOrchestrator.findHistogramFor(metric) - fun findRateFor(metric: ObdMetric): Optional = workflowOrchestrator.findRateFor(metric) - fun getPidDefinitionRegistry(): PidDefinitionRegistry = workflowOrchestrator.pidDefinitionRegistry() - fun isDTCEnabled(): Boolean = workflowOrchestrator.isDTCEnabled() - fun status(): WorkflowStatus = workflowOrchestrator.status() - - fun observe(lifecycleOwner: LifecycleOwner, observer: (metric: ObdMetric) -> Unit) { - workflowOrchestrator.observe(lifecycleOwner, observer) - } - - fun observe(metricsProcessor: MetricsProcessor): DataLoggerRepository { - workflowOrchestrator.observe(metricsProcessor) - return this - } - - - val eventsReceiver: BroadcastReceiver - get() = workflowOrchestrator.eventsReceiver -} - - class DataLoggerService : Service() { - private val workflowOrchestrator = DataLoggerRepository.workflowOrchestrator private val jobScheduler = DataLoggerJobScheduler(this) @@ -111,16 +58,18 @@ class DataLoggerService : Service() { fun getService(): DataLoggerService = this@DataLoggerService } - override fun onBind(intent: Intent?): IBinder { - return binder - } + override fun onBind(intent: Intent?): IBinder = binder override fun onDestroy() { super.onDestroy() Log.i(LOG_TAG, "Destroying DataLoggerService") } - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + override fun onStartCommand( + intent: Intent?, + flags: Int, + startId: Int, + ): Int { Log.i(LOG_TAG, "Starting DataLoggerService in the Foreground Mode") createNotificationChannel() @@ -192,9 +141,10 @@ class DataLoggerService : Service() { } } - - - fun scheduleStart(delay: Long, query: Query) { + fun scheduleStart( + delay: Long, + query: Query, + ) { enqueueWork(SCHEDULED_ACTION_START) { it.putExtra(SCHEDULED_START_DELAY, delay) it.putExtra(QUERY, query) @@ -219,13 +169,17 @@ class DataLoggerService : Service() { // --- Helper Methods --- - private fun enqueueWork(intentAction: String, func: (p: Intent) -> Unit = {}) { + private fun enqueueWork( + intentAction: String, + func: (p: Intent) -> Unit = {}, + ) { try { getContext()?.let { context -> - val intent = Intent(context, DataLoggerService::class.java).apply { - action = intentAction - putExtra("init", 1) - } + val intent = + Intent(context, DataLoggerService::class.java).apply { + action = intentAction + putExtra("init", 1) + } func(intent) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -241,33 +195,35 @@ class DataLoggerService : Service() { private fun createNotification(): Notification { // Fix for NullPointerException in tests/edge cases where LaunchIntent is null - val contentIntent = packageManager.getLaunchIntentForPackage(packageName)?.let { - PendingIntent.getActivity( - this, - 0, - it, - PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT - ) - } + val contentIntent = + packageManager.getLaunchIntentForPackage(packageName)?.let { + PendingIntent.getActivity( + this, + 0, + it, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT, + ) + } - return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) + return NotificationCompat + .Builder(this, NOTIFICATION_CHANNEL_ID) .setContentTitle("Vehicle Telemetry Service") .setContentText("Logging OBD & GPS data in background...") .setSmallIcon(R.drawable.ic_mygiulia_logo) .apply { contentIntent?.let { setContentIntent(it) } - } - .setOngoing(true) + }.setOngoing(true) .build() } private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val serviceChannel = NotificationChannel( - NOTIFICATION_CHANNEL_ID, - "OBD Logger Service", - NotificationManager.IMPORTANCE_LOW - ) + val serviceChannel = + NotificationChannel( + NOTIFICATION_CHANNEL_ID, + "OBD Logger Service", + NotificationManager.IMPORTANCE_LOW, + ) val manager = getSystemService(NotificationManager::class.java) manager.createNotificationChannel(serviceChannel) } From ea8d54777805d42587b28119c4f8c42a20433233 Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 21:15:28 +0100 Subject: [PATCH 05/26] refactor: move DataLoggerConnector to base package --- .../main/java/org/obd/graphs/{ui => }/DataLoggerConnector.kt | 2 +- app/src/main/java/org/obd/graphs/activity/Receivers.kt | 2 +- app/src/main/java/org/obd/graphs/ui/BaseFragment.kt | 3 ++- .../main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt | 2 +- .../java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt | 2 +- app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt | 2 +- app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt | 2 +- app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt | 2 +- .../java/org/obd/graphs/ui/performance/PerformanceFragment.kt | 2 +- .../main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) rename app/src/main/java/org/obd/graphs/{ui => }/DataLoggerConnector.kt (99%) diff --git a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt b/app/src/main/java/org/obd/graphs/DataLoggerConnector.kt similarity index 99% rename from app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt rename to app/src/main/java/org/obd/graphs/DataLoggerConnector.kt index 1526297f..38973f79 100644 --- a/app/src/main/java/org/obd/graphs/ui/DataLoggerConnector.kt +++ b/app/src/main/java/org/obd/graphs/DataLoggerConnector.kt @@ -14,7 +14,7 @@ * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ -package org.obd.graphs.ui +package org.obd.graphs import android.content.ComponentName import android.content.Context diff --git a/app/src/main/java/org/obd/graphs/activity/Receivers.kt b/app/src/main/java/org/obd/graphs/activity/Receivers.kt index 2a644c0e..e9442a6a 100644 --- a/app/src/main/java/org/obd/graphs/activity/Receivers.kt +++ b/app/src/main/java/org/obd/graphs/activity/Receivers.kt @@ -82,7 +82,7 @@ import org.obd.graphs.registerReceiver import org.obd.graphs.ui.common.COLOR_CARDINAL import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.toast -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger internal val powerReceiver = PowerBroadcastReceiver() const val NOTIFICATION_GRAPH_VIEW_TOGGLE = "view.graph.toggle" diff --git a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt index caaf7855..298d6f9d 100644 --- a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt @@ -24,8 +24,9 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton import org.obd.graphs.R import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.query.Query +import org.obd.graphs.withDataLogger -abstract class BaseFragment : Fragment() { + abstract class BaseFragment : Fragment() { protected fun attachToFloatingButton( activity: Activity?, query: Query, diff --git a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt index 6274e744..a494a85c 100644 --- a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt @@ -39,7 +39,7 @@ import org.obd.graphs.preferences.getS import org.obd.graphs.registerReceiver import org.obd.graphs.ui.gauge.AdapterContext import org.obd.graphs.ui.recycler.RefreshableFragment -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger private const val CONFIGURATION_CHANGE_EVENT_DASH = "recycler.view.change.configuration.event.dash_id" diff --git a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt index bd55dd68..ea778287 100644 --- a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt @@ -40,7 +40,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger open class DragRacingFragment : BaseFragment() { diff --git a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt index 03a4d732..ff5b2017 100644 --- a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt @@ -42,7 +42,7 @@ import org.obd.graphs.registerReceiver import org.obd.graphs.ui.common.* import org.obd.graphs.ui.recycler.RecyclerViewAdapter import org.obd.graphs.ui.recycler.RefreshableFragment -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger import kotlin.math.roundToInt private const val ENABLE_DRAG_AND_DROP_PREF = "pref.gauge_enable_drag_and_drop" diff --git a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt index 6bb8f55d..7978129d 100644 --- a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt @@ -46,7 +46,7 @@ import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger open class GiuliaFragment : BaseFragment() { private lateinit var root: View diff --git a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt index 2129845c..ebfc6768 100644 --- a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt @@ -65,7 +65,7 @@ import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.Colors import org.obd.graphs.ui.common.onDoubleClickListener -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger import org.obd.metrics.api.model.ObdMetric import org.obd.metrics.pid.PidDefinition import org.obd.metrics.pid.PidDefinitionRegistry diff --git a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt index b4ce0522..5bfdb334 100644 --- a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt @@ -41,7 +41,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger open class PerformanceFragment : BaseFragment() { private lateinit var root: View diff --git a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt index ed6ecb79..b8fb1a85 100644 --- a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt @@ -41,7 +41,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.ui.withDataLogger +import org.obd.graphs.withDataLogger open class TripInfoFragment : BaseFragment() { private lateinit var root: View From c84bb795323e82ce77a1053a137b10121cfdaa8e Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 21:29:43 +0100 Subject: [PATCH 06/26] refactor: separate DataLoggerConnector from UI extensions --- .../java/org/obd/graphs/activity/Receivers.kt | 2 +- .../java/org/obd/graphs/ui/BaseFragment.kt | 5 ++-- .../main/java/org/obd/graphs/ui/Extensions.kt | 16 +++++++++++ .../graphs/ui/dashboard/DashboardFragment.kt | 22 +++++++-------- .../ui/drag_racing/DragRacingFragment.kt | 4 +-- .../org/obd/graphs/ui/gauge/GaugeFragment.kt | 28 +++++++++++++------ .../obd/graphs/ui/giulia/GiuliaFragment.kt | 4 +-- .../org/obd/graphs/ui/graph/GraphFragment.kt | 4 +-- .../ui/performance/PerformanceFragment.kt | 4 +-- .../graphs/ui/trip_info/TripInfoFragment.kt | 4 +-- datalogger/build.gradle | 3 ++ .../bl/datalogger}/DataLoggerConnector.kt | 14 +--------- 12 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/org/obd/graphs/ui/Extensions.kt rename {app/src/main/java/org/obd/graphs => datalogger/src/main/java/org/obd/graphs/bl/datalogger}/DataLoggerConnector.kt (81%) diff --git a/app/src/main/java/org/obd/graphs/activity/Receivers.kt b/app/src/main/java/org/obd/graphs/activity/Receivers.kt index e9442a6a..2a644c0e 100644 --- a/app/src/main/java/org/obd/graphs/activity/Receivers.kt +++ b/app/src/main/java/org/obd/graphs/activity/Receivers.kt @@ -82,7 +82,7 @@ import org.obd.graphs.registerReceiver import org.obd.graphs.ui.common.COLOR_CARDINAL import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.toast -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger internal val powerReceiver = PowerBroadcastReceiver() const val NOTIFICATION_GRAPH_VIEW_TOGGLE = "view.graph.toggle" diff --git a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt index 298d6f9d..d4924b5b 100644 --- a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -24,9 +24,8 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton import org.obd.graphs.R import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.bl.query.Query -import org.obd.graphs.withDataLogger - abstract class BaseFragment : Fragment() { +abstract class BaseFragment : Fragment() { protected fun attachToFloatingButton( activity: Activity?, query: Query, diff --git a/app/src/main/java/org/obd/graphs/ui/Extensions.kt b/app/src/main/java/org/obd/graphs/ui/Extensions.kt new file mode 100644 index 00000000..b9490fc0 --- /dev/null +++ b/app/src/main/java/org/obd/graphs/ui/Extensions.kt @@ -0,0 +1,16 @@ +package org.obd.graphs.ui + +import androidx.activity.ComponentActivity +import androidx.fragment.app.Fragment +import org.obd.graphs.bl.datalogger.DataLoggerConnector +import org.obd.graphs.bl.datalogger.DataLoggerService + +fun Fragment.withDataLogger(onConnected: (DataLoggerService) -> Unit) { + val connector = DataLoggerConnector(requireContext(), onConnected) + this.lifecycle.addObserver(connector) +} + +fun ComponentActivity.withDataLogger(onConnected: (DataLoggerService) -> Unit) { + val connector = DataLoggerConnector(this, onConnected) + this.lifecycle.addObserver(connector) +} \ No newline at end of file diff --git a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt index a494a85c..a1c794ec 100644 --- a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -39,7 +39,7 @@ import org.obd.graphs.preferences.getS import org.obd.graphs.registerReceiver import org.obd.graphs.ui.gauge.AdapterContext import org.obd.graphs.ui.recycler.RefreshableFragment -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger private const val CONFIGURATION_CHANGE_EVENT_DASH = "recycler.view.change.configuration.event.dash_id" @@ -137,19 +137,19 @@ class DashboardFragment : RefreshableFragment() { recyclerView = root.findViewById(R.id.dashboard_recycler_view)!!, metricsIdsPref = dashboardPreferences.dashboardSelectedMetrics.first, adapterContext = - AdapterContext( - layoutId = R.layout.item_dashboard, - spanCount = calculateSpanCount(), - height = calculateHeight(Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size), - ), + AdapterContext( + layoutId = R.layout.item_dashboard, + spanCount = calculateSpanCount(), + height = calculateHeight(Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size), + ), enableDragManager = dashboardPreferences.dragAndDropEnabled, enableOnTouchListener = enableOnTouchListener, enableSwipeToDelete = dashboardPreferences.swipeToDeleteEnabled, adapter = { - context: Context, - data: MutableList, - resourceId: Int, - height: Int?, + context: Context, + data: MutableList, + resourceId: Int, + height: Int?, -> DashboardViewAdapter(context, data, resourceId, height) }, diff --git a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt index ea778287..e69e0a81 100644 --- a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -40,7 +40,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger open class DragRacingFragment : BaseFragment() { diff --git a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt index ff5b2017..df28aa48 100644 --- a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -35,14 +35,21 @@ import org.obd.graphs.RenderingThread import org.obd.graphs.activity.TOOLBAR_TOGGLE_ACTION import org.obd.graphs.bl.collector.Metric import org.obd.graphs.bl.collector.MetricsCollector -import org.obd.graphs.bl.datalogger.* +import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTED_EVENT +import org.obd.graphs.bl.datalogger.DATA_LOGGER_CONNECTING_EVENT +import org.obd.graphs.bl.datalogger.DATA_LOGGER_SCHEDULED_START_EVENT +import org.obd.graphs.bl.datalogger.DATA_LOGGER_STOPPED_EVENT +import org.obd.graphs.bl.datalogger.DataLoggerRepository import org.obd.graphs.getPowerPreferences -import org.obd.graphs.preferences.* +import org.obd.graphs.preferences.Prefs +import org.obd.graphs.preferences.getS import org.obd.graphs.registerReceiver -import org.obd.graphs.ui.common.* +import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN +import org.obd.graphs.ui.common.COLOR_TRANSPARENT +import org.obd.graphs.ui.common.isTablet import org.obd.graphs.ui.recycler.RecyclerViewAdapter import org.obd.graphs.ui.recycler.RefreshableFragment -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger import kotlin.math.roundToInt private const val ENABLE_DRAG_AND_DROP_PREF = "pref.gauge_enable_drag_and_drop" @@ -78,8 +85,9 @@ class GaugeFragment : RefreshableFragment() { CONFIGURE_CHANGE_EVENT_GAUGE -> { configureView(false) } + DATA_LOGGER_CONNECTING_EVENT -> { - val recyclerView = root.findViewById(R.id.recycler_view) as RecyclerView + val recyclerView: RecyclerView = root.findViewById(R.id.recycler_view) val adapter = recyclerView.adapter as RecyclerViewAdapter val metrics = prepareMetrics( metricsIdsPref = gaugeVirtualScreen.getVirtualScreenPrefKey(), @@ -89,6 +97,7 @@ class GaugeFragment : RefreshableFragment() { adapter.data.addAll(metrics) adapter.notifyDataSetChanged() } + DATA_LOGGER_CONNECTED_EVENT -> { virtualScreensPanel { it.isVisible = false @@ -136,7 +145,7 @@ class GaugeFragment : RefreshableFragment() { if (DataLoggerRepository.isRunning()) { withDataLogger { dataLogger -> - dataLogger.updateQuery(query()) + dataLogger.updateQuery(query()) } renderingThread.start() @@ -150,7 +159,7 @@ class GaugeFragment : RefreshableFragment() { override fun onAttach(context: Context) { super.onAttach(context) - registerReceiver(activity, broadcastReceiver){ + registerReceiver(activity, broadcastReceiver) { it.addAction(CONFIGURE_CHANGE_EVENT_GAUGE) it.addAction(DATA_LOGGER_CONNECTING_EVENT) it.addAction(DATA_LOGGER_CONNECTED_EVENT) @@ -179,7 +188,7 @@ class GaugeFragment : RefreshableFragment() { private fun configureView(enableOnTouchListener: Boolean) { configureView( configureChangeEventId = CONFIGURE_CHANGE_EVENT_GAUGE, - recyclerView = root.findViewById(R.id.recycler_view) as RecyclerView, + recyclerView = root.findViewById(R.id.recycler_view)!!, metricsIdsPref = gaugeVirtualScreen.getVirtualScreenPrefKey(), adapterContext = AdapterContext( layoutId = R.layout.item_gauge, @@ -218,6 +227,7 @@ class GaugeFragment : RefreshableFragment() { } } } + else -> { when (numberOfPIDsToDisplay) { 0 -> 1 diff --git a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt index 7978129d..43a7c923 100644 --- a/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/giulia/GiuliaFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -46,7 +46,7 @@ import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger open class GiuliaFragment : BaseFragment() { private lateinit var root: View diff --git a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt index ebfc6768..e6aee4e2 100644 --- a/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -65,7 +65,7 @@ import org.obd.graphs.ui.common.COLOR_PHILIPPINE_GREEN import org.obd.graphs.ui.common.COLOR_TRANSPARENT import org.obd.graphs.ui.common.Colors import org.obd.graphs.ui.common.onDoubleClickListener -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger import org.obd.metrics.api.model.ObdMetric import org.obd.metrics.pid.PidDefinition import org.obd.metrics.pid.PidDefinitionRegistry diff --git a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt index 5bfdb334..140b22a9 100644 --- a/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/performance/PerformanceFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -41,7 +41,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger open class PerformanceFragment : BaseFragment() { private lateinit var root: View diff --git a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt index b8fb1a85..dab6dcf0 100644 --- a/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/trip_info/TripInfoFragment.kt @@ -1,4 +1,4 @@ - /** +/** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -41,7 +41,7 @@ import org.obd.graphs.renderer.SurfaceRendererType import org.obd.graphs.renderer.ViewSettings import org.obd.graphs.ui.BaseFragment import org.obd.graphs.ui.common.SurfaceController -import org.obd.graphs.withDataLogger +import org.obd.graphs.ui.withDataLogger open class TripInfoFragment : BaseFragment() { private lateinit var root: View diff --git a/datalogger/build.gradle b/datalogger/build.gradle index 11258c06..24563947 100644 --- a/datalogger/build.gradle +++ b/datalogger/build.gradle @@ -43,6 +43,9 @@ dependencies { implementation project(":common") implementation project(':profile') + // This specific library provides lifecycleScope + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2" + implementation 'com.google.android.gms:play-services-location:21.0.1' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.2.0' diff --git a/app/src/main/java/org/obd/graphs/DataLoggerConnector.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConnector.kt similarity index 81% rename from app/src/main/java/org/obd/graphs/DataLoggerConnector.kt rename to datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConnector.kt index 38973f79..4691914e 100644 --- a/app/src/main/java/org/obd/graphs/DataLoggerConnector.kt +++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerConnector.kt @@ -14,28 +14,16 @@ * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ -package org.obd.graphs +package org.obd.graphs.bl.datalogger import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder -import androidx.activity.ComponentActivity -import androidx.fragment.app.Fragment import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner -import org.obd.graphs.bl.datalogger.DataLoggerService -fun Fragment.withDataLogger(onConnected: (DataLoggerService) -> Unit) { - val connector = DataLoggerConnector(requireContext(), onConnected) - this.lifecycle.addObserver(connector) -} - -fun ComponentActivity.withDataLogger(onConnected: (DataLoggerService) -> Unit) { - val connector = DataLoggerConnector(this, onConnected) - this.lifecycle.addObserver(connector) -} class DataLoggerConnector( private val context: Context, From 489268463a08e5e9f3f628bbc3bf8f8ce63ce84b Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Tue, 3 Feb 2026 21:40:53 +0100 Subject: [PATCH 07/26] feat: unify datalogger access in the automotive module --- .../java/org/obd/graphs/ui/BaseFragment.kt | 2 +- .../main/java/org/obd/graphs/ui/Extensions.kt | 18 +- .../graphs/ui/dashboard/DashboardFragment.kt | 20 +- .../ui/drag_racing/DragRacingFragment.kt | 2 +- .../org/obd/graphs/ui/gauge/GaugeFragment.kt | 133 +++--- .../obd/graphs/ui/giulia/GiuliaFragment.kt | 2 +- .../org/obd/graphs/ui/graph/GraphFragment.kt | 2 +- .../ui/performance/PerformanceFragment.kt | 2 +- .../graphs/ui/trip_info/TripInfoFragment.kt | 2 +- .../org/obd/graphs/aa/screen/CarScreen.kt | 156 +++---- .../org/obd/graphs/aa/screen/Extensions.kt | 27 ++ .../aa/screen/iot/IotTemplateCarScreen.kt | 305 ++++++++------ .../aa/screen/nav/NavTemplateCarScreen.kt | 4 +- .../graphs/aa/screen/nav/RoutinesScreen.kt | 394 +++++++++++------- .../aa/screen/nav/SurfaceRendererScreen.kt | 383 ++++++++++------- 15 files changed, 836 insertions(+), 616 deletions(-) create mode 100644 automotive/src/main/java/org/obd/graphs/aa/screen/Extensions.kt diff --git a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt index d4924b5b..caaf7855 100644 --- a/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/BaseFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license diff --git a/app/src/main/java/org/obd/graphs/ui/Extensions.kt b/app/src/main/java/org/obd/graphs/ui/Extensions.kt index b9490fc0..289c5c9c 100644 --- a/app/src/main/java/org/obd/graphs/ui/Extensions.kt +++ b/app/src/main/java/org/obd/graphs/ui/Extensions.kt @@ -1,3 +1,19 @@ + /** + * Copyright 2019-2026, Tomasz Żebrowski + * + *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ package org.obd.graphs.ui import androidx.activity.ComponentActivity @@ -13,4 +29,4 @@ fun Fragment.withDataLogger(onConnected: (DataLoggerService) -> Unit) { fun ComponentActivity.withDataLogger(onConnected: (DataLoggerService) -> Unit) { val connector = DataLoggerConnector(this, onConnected) this.lifecycle.addObserver(connector) -} \ No newline at end of file +} diff --git a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt index a1c794ec..6274e744 100644 --- a/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/dashboard/DashboardFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -137,19 +137,19 @@ class DashboardFragment : RefreshableFragment() { recyclerView = root.findViewById(R.id.dashboard_recycler_view)!!, metricsIdsPref = dashboardPreferences.dashboardSelectedMetrics.first, adapterContext = - AdapterContext( - layoutId = R.layout.item_dashboard, - spanCount = calculateSpanCount(), - height = calculateHeight(Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size), - ), + AdapterContext( + layoutId = R.layout.item_dashboard, + spanCount = calculateSpanCount(), + height = calculateHeight(Prefs.getLongSet(dashboardPreferences.dashboardSelectedMetrics.first).size), + ), enableDragManager = dashboardPreferences.dragAndDropEnabled, enableOnTouchListener = enableOnTouchListener, enableSwipeToDelete = dashboardPreferences.swipeToDeleteEnabled, adapter = { - context: Context, - data: MutableList, - resourceId: Int, - height: Int?, + context: Context, + data: MutableList, + resourceId: Int, + height: Int?, -> DashboardViewAdapter(context, data, resourceId, height) }, diff --git a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt index e69e0a81..bd55dd68 100644 --- a/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/drag_racing/DragRacingFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license diff --git a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt index df28aa48..ae0863dc 100644 --- a/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt +++ b/app/src/main/java/org/obd/graphs/ui/gauge/GaugeFragment.kt @@ -1,4 +1,4 @@ -/** + /** * Copyright 2019-2026, Tomasz Żebrowski * *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license @@ -59,68 +59,74 @@ private const val GAUGE_PIDS_SETTINGS = "prefs.gauge.pids.settings" class GaugeFragment : RefreshableFragment() { private val metricsCollector = MetricsCollector.instance() - private val renderingThread: RenderingThread = RenderingThread( - id = "GaugeFragmentRenderingThread", - renderAction = { - refreshRecyclerView(metricsCollector, R.id.recycler_view) - }, - perfFrameRate = { - Prefs.getS("pref.gauge.fps", "10").toInt() - } - ) + private val renderingThread: RenderingThread = + RenderingThread( + id = "GaugeFragmentRenderingThread", + renderAction = { + refreshRecyclerView(metricsCollector, R.id.recycler_view) + }, + perfFrameRate = { + Prefs.getS("pref.gauge.fps", "10").toInt() + }, + ) @SuppressLint("NotifyDataSetChanged") - private var broadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - when (intent?.action) { - DATA_LOGGER_SCHEDULED_START_EVENT -> { - if (isAdded && isVisible) { - Log.i(org.obd.graphs.activity.LOG_TAG, "Scheduling data logger for=${query().getIDs()}") - withDataLogger { dataLogger -> - dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + private var broadcastReceiver = + object : BroadcastReceiver() { + override fun onReceive( + context: Context?, + intent: Intent?, + ) { + when (intent?.action) { + DATA_LOGGER_SCHEDULED_START_EVENT -> { + if (isAdded && isVisible) { + Log.i(org.obd.graphs.activity.LOG_TAG, "Scheduling data logger for=${query().getIDs()}") + withDataLogger { dataLogger -> + dataLogger.scheduleStart(getPowerPreferences().startDataLoggingAfter, query()) + } } } - } - CONFIGURE_CHANGE_EVENT_GAUGE -> { - configureView(false) - } + CONFIGURE_CHANGE_EVENT_GAUGE -> { + configureView(false) + } - DATA_LOGGER_CONNECTING_EVENT -> { - val recyclerView: RecyclerView = root.findViewById(R.id.recycler_view) - val adapter = recyclerView.adapter as RecyclerViewAdapter - val metrics = prepareMetrics( - metricsIdsPref = gaugeVirtualScreen.getVirtualScreenPrefKey(), - metricsSerializerPref = GAUGE_PIDS_SETTINGS - ) - adapter.data.clear() - adapter.data.addAll(metrics) - adapter.notifyDataSetChanged() - } + DATA_LOGGER_CONNECTING_EVENT -> { + val recyclerView: RecyclerView = root.findViewById(R.id.recycler_view) + val adapter = recyclerView.adapter as RecyclerViewAdapter + val metrics = + prepareMetrics( + metricsIdsPref = gaugeVirtualScreen.getVirtualScreenPrefKey(), + metricsSerializerPref = GAUGE_PIDS_SETTINGS, + ) + adapter.data.clear() + adapter.data.addAll(metrics) + adapter.notifyDataSetChanged() + } - DATA_LOGGER_CONNECTED_EVENT -> { - virtualScreensPanel { - it.isVisible = false + DATA_LOGGER_CONNECTED_EVENT -> { + virtualScreensPanel { + it.isVisible = false + } + renderingThread.start() } - renderingThread.start() - } - DATA_LOGGER_STOPPED_EVENT -> { - virtualScreensPanel { - it.isVisible = true + DATA_LOGGER_STOPPED_EVENT -> { + virtualScreensPanel { + it.isVisible = true + } + renderingThread.stop() + attachToFloatingButton(activity, query()) } - renderingThread.stop() - attachToFloatingButton(activity, query()) - } - TOOLBAR_TOGGLE_ACTION -> { - virtualScreensPanel { - it.isVisible = !it.isVisible + TOOLBAR_TOGGLE_ACTION -> { + virtualScreensPanel { + it.isVisible = !it.isVisible + } } } } } - } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) @@ -130,7 +136,7 @@ class GaugeFragment : RefreshableFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { root = inflater.inflate(R.layout.fragment_gauge, container, false) @@ -156,7 +162,6 @@ class GaugeFragment : RefreshableFragment() { return root } - override fun onAttach(context: Context) { super.onAttach(context) registerReceiver(activity, broadcastReceiver) { @@ -190,21 +195,23 @@ class GaugeFragment : RefreshableFragment() { configureChangeEventId = CONFIGURE_CHANGE_EVENT_GAUGE, recyclerView = root.findViewById(R.id.recycler_view)!!, metricsIdsPref = gaugeVirtualScreen.getVirtualScreenPrefKey(), - adapterContext = AdapterContext( - layoutId = R.layout.item_gauge, - spanCount = calculateSpan() - ), - + adapterContext = + AdapterContext( + layoutId = R.layout.item_gauge, + spanCount = calculateSpan(), + ), enableSwipeToDelete = Prefs.getBoolean(ENABLE_SWIPE_TO_DELETE_PREF, false), enableDragManager = Prefs.getBoolean(ENABLE_DRAG_AND_DROP_PREF, false), enableOnTouchListener = enableOnTouchListener, - adapter = { context: Context, - data: MutableList, - resourceId: Int, - height: Int? -> + adapter = { + context: Context, + data: MutableList, + resourceId: Int, + height: Int?, + -> GaugeAdapter(context, data, resourceId, height) }, - metricsSerializerPref = GAUGE_PIDS_SETTINGS + metricsSerializerPref = GAUGE_PIDS_SETTINGS, ) metricsCollector.applyFilter(getSelectedPIDs()) @@ -241,7 +248,11 @@ class GaugeFragment : RefreshableFragment() { private fun getSelectedPIDs() = query.filterBy(gaugeVirtualScreen.getVirtualScreenPrefKey()) - private fun setVirtualViewBtn(btnId: Int, selection: String, viewId: String) { + private fun setVirtualViewBtn( + btnId: Int, + selection: String, + viewId: String, + ) { (root.findViewById