From 2441e1badafbd98166dbf9ff3618d921479caf33 Mon Sep 17 00:00:00 2001 From: andrekir Date: Mon, 3 Jan 2022 21:59:30 -0300 Subject: [PATCH] add provideLocation service start/stop --- .../com/geeksville/mesh/IMeshService.aidl | 10 ++- .../java/com/geeksville/mesh/MainActivity.kt | 21 ++---- .../geeksville/mesh/service/MeshService.kt | 18 +++-- .../geeksville/mesh/ui/SettingsFragment.kt | 68 +++++++++---------- 4 files changed, 60 insertions(+), 57 deletions(-) diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl index 17382d016..46d90f282 100644 --- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl +++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl @@ -109,11 +109,15 @@ interface IMeshService { /// Start updating the radios firmware void startFirmwareUpdate(); - /** - Return a number 0-100 for progress. -1 for completed and success, -2 for failure - */ + /// Return a number 0-100 for firmware update progress. -1 for completed and success, -2 for failure int getUpdateStatus(); int getRegion(); void setRegion(int regionCode); + + /// Start providing location (from phone GPS) to mesh + void setupProvideLocation(); + + /// Stop providing location (from phone GPS) to mesh + void stopProvideLocation(); } diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 994db498d..9c8c12c03 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -179,8 +179,7 @@ class MainActivity : AppCompatActivity(), Logging, ) ) - private - val tabsAdapter = object : FragmentStateAdapter(this) { + private val tabsAdapter = object : FragmentStateAdapter(this) { override fun getItemCount(): Int = tabInfos.size @@ -200,7 +199,6 @@ class MainActivity : AppCompatActivity(), Logging, updateBluetoothEnabled() } - /** * Don't tell our app we have bluetooth until we have bluetooth _and_ location access */ @@ -213,7 +211,6 @@ class MainActivity : AppCompatActivity(), Logging, Manifest.permission.BLUETOOTH_ADMIN ) - if (getMissingPermissions(requiredPerms).isEmpty()) { /// ask the adapter if we have access bluetoothAdapter?.apply { @@ -532,7 +529,6 @@ class MainActivity : AppCompatActivity(), Logging, } } - override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) handleIntent(intent) @@ -659,8 +655,7 @@ class MainActivity : AppCompatActivity(), Logging, } */ } - private - var receiverRegistered = false + private var receiverRegistered = false private fun registerMeshReceiver() { unregisterMeshReceiver() @@ -680,7 +675,6 @@ class MainActivity : AppCompatActivity(), Logging, } } - /// Pull our latest node db from the device private fun updateNodesFromDevice() { model.meshService?.let { service -> @@ -724,7 +718,6 @@ class MainActivity : AppCompatActivity(), Logging, showSettingsPage() // Default to the settings page in this case } - /// Called when we gain/lose a connection to our mesh radio private fun onMeshConnectionChanged(connected: MeshService.ConnectionState) { debug("connchange ${model.isConnected.value} -> $connected") @@ -773,6 +766,9 @@ class MainActivity : AppCompatActivity(), Logging, warn("Abandoning connect $ex, because we probably just lost device connection") model.isConnected.value = oldConnection } + // if provideLocation enabled: Start providing location (from phone GPS) to mesh + if (model.provideLocation.value == true && (oldConnection != connected)) + service.setupProvideLocation() } } else { // For other connection states, just slam them in @@ -842,8 +838,7 @@ class MainActivity : AppCompatActivity(), Logging, } } - private - val meshServiceReceiver = object : BroadcastReceiver() { + private val meshServiceReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) = exceptionReporter { @@ -891,8 +886,7 @@ class MainActivity : AppCompatActivity(), Logging, private var connectionJob: Job? = null - private - val mesh = object : + private val mesh = object : ServiceClient({ com.geeksville.mesh.IMeshService.Stub.asInterface(it) }) { @@ -1269,4 +1263,3 @@ class MainActivity : AppCompatActivity(), Logging, } } - diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index 43c759408..5c79f1d53 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1015,12 +1015,12 @@ class MeshService : Service(), Logging { maybeUpdateServiceStatusNotification() } - private fun setupLocationRequest() { + private fun setupLocationRequests() { stopLocationRequests() val mi = myNodeInfo val prefs = radioConfig?.preferences if (mi != null && prefs != null) { - var broadcastSecs = prefs.positionBroadcastSecs + val broadcastSecs = prefs.positionBroadcastSecs var desiredInterval = if (broadcastSecs == 0) // unset by device, use default 15 * 60 * 1000L @@ -1047,7 +1047,6 @@ class MeshService : Service(), Logging { } } - /** * Send in analytics about mesh connection */ @@ -1326,7 +1325,7 @@ class MeshService : Service(), Logging { hwModelStr, firmwareVersion, firmwareUpdateFilename != null, - isBluetoothInterface && com.geeksville.mesh.service.SoftwareUpdateService.shouldUpdate( + isBluetoothInterface && SoftwareUpdateService.shouldUpdate( this@MeshService, DeviceVersion(firmwareVersion) ), @@ -1481,8 +1480,6 @@ class MeshService : Service(), Logging { reportConnection() updateRegion() - - setupLocationRequest() // start sending location packets if needed } private fun handleConfigComplete(configCompleteId: Int) { @@ -1879,6 +1876,15 @@ class MeshService : Service(), Logging { info("in connectionState=$r") r.toString() } + + override fun setupProvideLocation() = toRemoteExceptions { + setupLocationRequests() + } + + override fun stopProvideLocation() = toRemoteExceptions { + stopLocationRequests() + } + } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index 45e651d06..d398daf55 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -58,7 +58,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import java.util.regex.Pattern - object SLogging : Logging /// Change to a new macaddr selection, updating GUI and radio @@ -326,7 +325,6 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging { val devices = object : MutableLiveData>(mutableMapOf()) { - /** * Called when the number of active observers change from 1 to 0. * @@ -439,7 +437,6 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging { } } - @SuppressLint("NewApi") class SettingsFragment : ScreenFragment("Settings"), Logging { private var _binding: SettingsFragmentBinding? = null @@ -495,7 +492,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { /// Set the correct update button configuration based on current progress private fun refreshUpdateButton(enable: Boolean) { - debug("Reiniting the udpate button") + debug("Reiniting the update button") val info = model.myNodeInfo.value val service = model.meshService if (model.isConnected.value == MeshService.ConnectionState.CONNECTED && info != null && info.shouldUpdate && info.couldUpdate && service != null) { @@ -629,7 +626,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { binding.usernameEditText.setText(name) }) - // Only let user edit their name or set software update while connected to a radio model.isConnected.observe(viewLifecycleOwner, Observer { _ -> updateNodeInfo() @@ -652,31 +648,38 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { requireActivity().hideKeyboard() } + binding.provideLocationCheckbox.isEnabled = isGooglePlayAvailable(requireContext()) binding.provideLocationCheckbox.setOnCheckedChangeListener { view, isChecked -> - // No matter what set our desired state in prefs - model.provideLocation.value = isChecked - - if (view.isPressed && isChecked) { // We want to ignore changes caused by code (as opposed to the user) + if (view.isPressed) { // We want to ignore changes caused by code (as opposed to the user) debug("User changed location tracking to $isChecked") - val hasLocationPermission = myActivity.hasLocationPermission() - val hasBackgroundPermission = myActivity.hasBackgroundPermission() + if (view.isChecked) { + val hasLocationPermission = myActivity.hasLocationPermission() + val hasBackgroundPermission = myActivity.hasBackgroundPermission() - // Don't check the box until the system setting changes - view.isChecked = hasLocationPermission && hasBackgroundPermission + // Don't check the box until the system setting changes + view.isChecked = hasLocationPermission && hasBackgroundPermission - if (!hasLocationPermission) // Make sure we have location permission (prerequisite) - myActivity.requestLocationPermission() - if (hasLocationPermission && !hasBackgroundPermission) - MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.background_required) - .setMessage(R.string.why_background_required) - .setNeutralButton(R.string.cancel) { _, _ -> - debug("User denied background permission") - } - .setPositiveButton(getString(R.string.accept)) { _, _ -> - myActivity.requestBackgroundPermission() - } - .show() + if (!hasLocationPermission) // Make sure we have location permission (prerequisite) + myActivity.requestLocationPermission() + if (hasLocationPermission && !hasBackgroundPermission) + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.background_required) + .setMessage(R.string.why_background_required) + .setNeutralButton(R.string.cancel) { _, _ -> + debug("User denied background permission") + } + .setPositiveButton(getString(R.string.accept)) { _, _ -> + myActivity.requestBackgroundPermission() + } + .show() + + if (view.isChecked) + model.provideLocation.value = isChecked + model.meshService?.setupProvideLocation() + } + else { + model.meshService?.stopProvideLocation() + } } } @@ -905,16 +908,14 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { initClassicScan() } - /** - * If the user has not turned on location access throw up a toast warning - */ + // If the user has not turned on location access throw up a toast warning private fun checkLocationEnabled() { - fun hasGpsSensor(): Boolean = + fun hasGps(): Boolean = myActivity.packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS) - // If they don't have google play FIXME for now we don't check for location access - if (hasGpsSensor() && isGooglePlayAvailable(requireContext())) { + // FIXME If they don't have google play for now we don't check for location enabled + if (hasGps() && isGooglePlayAvailable(requireContext())) { // We do this painful process because LocationManager.isEnabled is only SDK28 or latet val builder = LocationSettingsRequest.Builder() builder.setNeedBle(true) @@ -992,7 +993,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { scanModel.startScan() // system permissions might have changed while we were away - binding.provideLocationCheckbox.isChecked = myActivity.hasBackgroundPermission() && (model.provideLocation.value ?: false) + binding.provideLocationCheckbox.isChecked = myActivity.hasBackgroundPermission() && (model.provideLocation.value ?: false) && isGooglePlayAvailable(requireContext()) myActivity.registerReceiver(updateProgressReceiver, updateProgressFilter) @@ -1015,4 +1016,3 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { } } } -