Merge pull request #336 from meshtastic/provideLocation

add provideLocation service start/stop
This commit is contained in:
Jm Casler
2022-01-04 16:45:02 -08:00
committed by GitHub
4 changed files with 61 additions and 57 deletions

View File

@@ -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>({
com.geeksville.mesh.IMeshService.Stub.asInterface(it)
}) {
@@ -1269,4 +1263,3 @@ class MainActivity : AppCompatActivity(), Logging,
}
}

View File

@@ -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()
}
}
}

View File

@@ -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<MutableMap<String, DeviceListEntry>>(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,39 @@ 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.isChecked) {
debug("User changed location tracking to $isChecked")
val hasLocationPermission = myActivity.hasLocationPermission()
val hasBackgroundPermission = myActivity.hasBackgroundPermission()
if (view.isPressed) { // We want to ignore changes caused by code (as opposed to the user)
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.provideLocation.value = isChecked
model.meshService?.stopProvideLocation()
}
}
@@ -905,16 +909,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 +994,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.hasLocationPermission() && myActivity.hasBackgroundPermission() && (model.provideLocation.value ?: false) && isGooglePlayAvailable(requireContext())
myActivity.registerReceiver(updateProgressReceiver, updateProgressFilter)
@@ -1015,4 +1017,3 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
}
}
}