sforkowany z mirror/meshtastic-android
Merge branch 'meshtastic:master' into osmdroid-phase3
commit
11915df72e
|
|
@ -3,6 +3,7 @@ package com.geeksville.mesh.android
|
|||
import android.Manifest
|
||||
import android.app.NotificationManager
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.location.LocationManager
|
||||
import android.companion.CompanionDeviceManager
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
|
|
@ -29,6 +30,8 @@ val Context.usbManager: UsbManager get() = requireNotNull(getSystemService(Conte
|
|||
|
||||
val Context.notificationManager: NotificationManager get() = requireNotNull(getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager?)
|
||||
|
||||
val Context.locationManager: LocationManager get() = requireNotNull(getSystemService(Context.LOCATION_SERVICE) as? LocationManager?)
|
||||
|
||||
/**
|
||||
* @return true if CompanionDeviceManager API is present
|
||||
*/
|
||||
|
|
@ -40,8 +43,13 @@ fun Context.hasCompanionDeviceApi(): Boolean =
|
|||
/**
|
||||
* @return true if the device has a GPS receiver
|
||||
*/
|
||||
fun Context.hasGps(): Boolean =
|
||||
packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)
|
||||
fun Context.hasGps(): Boolean = locationManager.allProviders.contains(LocationManager.GPS_PROVIDER)
|
||||
|
||||
/**
|
||||
* @return true if the device has a GPS receiver and it is disabled (location turned off)
|
||||
*/
|
||||
fun Context.gpsDisabled(): Boolean =
|
||||
if (hasGps()) !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) else false
|
||||
|
||||
/**
|
||||
* return a list of the permissions we don't have
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ data class ChannelSet(
|
|||
multiFormatWriter.encode(
|
||||
getChannelUrl(true).toString(),
|
||||
BarcodeFormat.QR_CODE,
|
||||
192,
|
||||
192
|
||||
960,
|
||||
960
|
||||
)
|
||||
val barcodeEncoder = BarcodeEncoder()
|
||||
barcodeEncoder.createBitmap(bitMatrix)
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ class UIViewModel @Inject constructor(
|
|||
|
||||
private val _channels = MutableStateFlow(ChannelSet())
|
||||
val channels: StateFlow<ChannelSet> = _channels
|
||||
val channelSet get() = channels.value.protobuf
|
||||
|
||||
private val _quickChatActions = MutableStateFlow<List<QuickChatAction>>(emptyList())
|
||||
val quickChatActions: StateFlow<List<QuickChatAction>> = _quickChatActions
|
||||
|
|
@ -355,6 +356,8 @@ class UIViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val adminChannelIndex: Int get() = channelSet.settingsList.map { it.name }.indexOf("admin")
|
||||
|
||||
fun requestShutdown(idNum: Int) {
|
||||
try {
|
||||
meshService?.requestShutdown(idNum)
|
||||
|
|
|
|||
|
|
@ -463,6 +463,9 @@ class MeshService : Service(), Logging {
|
|||
/// My node ID string
|
||||
private val myNodeID get() = toNodeID(myNodeNum)
|
||||
|
||||
/// Admin channel index
|
||||
private var adminChannelIndex: Int = 0
|
||||
|
||||
/// Convert the channels array into a ChannelSet
|
||||
private var channelSet: AppOnlyProtos.ChannelSet
|
||||
get() {
|
||||
|
|
@ -543,6 +546,7 @@ class MeshService : Service(), Logging {
|
|||
initFn: AdminProtos.AdminMessage.Builder.() -> Unit
|
||||
): MeshPacket = buildMeshPacket(
|
||||
wantAck = true,
|
||||
channel = adminChannelIndex,
|
||||
priority = MeshPacket.Priority.RELIABLE
|
||||
)
|
||||
{
|
||||
|
|
@ -958,9 +962,10 @@ class MeshService : Service(), Logging {
|
|||
}
|
||||
}
|
||||
|
||||
private fun addChannelSettings(channel: ChannelProtos.Channel) {
|
||||
private fun addChannelSettings(ch: ChannelProtos.Channel) {
|
||||
if (ch.index == 0 || ch.settings.name == "admin") adminChannelIndex = ch.index
|
||||
serviceScope.handledLaunch {
|
||||
channelSetRepository.addSettings(channel)
|
||||
channelSetRepository.addSettings(ch)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1363,12 +1368,16 @@ class MeshService : Service(), Logging {
|
|||
warn("Ignoring stale config complete")
|
||||
}
|
||||
|
||||
private fun requestDeviceConfig() {
|
||||
AdminProtos.AdminMessage.ConfigType.values().forEach {
|
||||
sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket(wantResponse = true) {
|
||||
if (it != AdminProtos.AdminMessage.ConfigType.UNRECOGNIZED) getConfigRequest = it
|
||||
})
|
||||
}
|
||||
private fun requestConfig(config: AdminProtos.AdminMessage.ConfigType) {
|
||||
sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket(wantResponse = true) {
|
||||
getConfigRequest = config
|
||||
})
|
||||
}
|
||||
|
||||
private fun requestAllConfig() {
|
||||
AdminProtos.AdminMessage.ConfigType.values().filter {
|
||||
it != AdminProtos.AdminMessage.ConfigType.UNRECOGNIZED
|
||||
}.forEach(::requestConfig)
|
||||
}
|
||||
|
||||
private fun requestChannel(channelIndex: Int) {
|
||||
|
|
@ -1377,9 +1386,10 @@ class MeshService : Service(), Logging {
|
|||
})
|
||||
}
|
||||
|
||||
private fun setChannel(channel: ChannelProtos.Channel) {
|
||||
private fun setChannel(ch: ChannelProtos.Channel) {
|
||||
if (ch.index == 0 || ch.settings.name == "admin") adminChannelIndex = ch.index
|
||||
sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket(wantResponse = true) {
|
||||
setChannel = channel
|
||||
setChannel = ch
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
|
|||
val node = nodes[if (fromLocal) contact.to else contact.from]
|
||||
|
||||
//grab channel names from DeviceConfig
|
||||
val channels = model.channels.value.protobuf
|
||||
val channels = model.channelSet
|
||||
val channelName = if (channels.settingsCount > contact.channel)
|
||||
Channel(channels.settingsList[contact.channel], channels.loraConfig).name else null
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
|
|||
fun onContactsChanged(contacts: Map<String, Packet>) {
|
||||
// Add empty channel placeholders (always show Broadcast contacts, even when empty)
|
||||
val mutableMap = contacts.toMutableMap()
|
||||
for (ch in 0 until model.channels.value.protobuf.settingsCount) {
|
||||
for (ch in 0 until model.channelSet.settingsCount) {
|
||||
val contactKey = "$ch${DataPacket.ID_BROADCAST}"
|
||||
if (mutableMap[contactKey] == null) mutableMap[contactKey] = Packet(
|
||||
0L, 1, contactKey, 0L,
|
||||
|
|
|
|||
|
|
@ -2,14 +2,22 @@ package com.geeksville.mesh.ui
|
|||
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.companion.CompanionDeviceManager
|
||||
import android.content.*
|
||||
import android.location.LocationManager
|
||||
import android.os.*
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.*
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.RadioButton
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
|
@ -161,7 +169,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
if (connected == MeshService.ConnectionState.DISCONNECTED)
|
||||
model.setOwner("")
|
||||
|
||||
if (model.config.position.gpsEnabled) {
|
||||
if (requireContext().hasGps() && model.config.position.gpsEnabled) {
|
||||
binding.provideLocationCheckbox.isEnabled = true
|
||||
} else {
|
||||
binding.provideLocationCheckbox.isChecked = false
|
||||
|
|
@ -537,17 +545,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
// Default warning valid only for classic bluetooth scan
|
||||
warningReason: String = getString(R.string.location_disabled_warning)
|
||||
) {
|
||||
val locationManager =
|
||||
myActivity.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
var gpsEnabled = false
|
||||
|
||||
try {
|
||||
gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
|
||||
} catch (ex: Throwable) {
|
||||
debug("LocationManager GPS_PROVIDER error: ${ex.message}")
|
||||
}
|
||||
|
||||
if (myActivity.hasGps() && !gpsEnabled) {
|
||||
if (requireContext().gpsDisabled()) {
|
||||
warn("Telling user we need need location access")
|
||||
showSnackbar(warningReason)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
|||
private fun popup(view: View, position: Int) {
|
||||
val node = nodes[position]
|
||||
val user = node.user
|
||||
val showAdmin = position == 0 // TODO add admin channel check
|
||||
val showAdmin = position == 0 || model.adminChannelIndex > 0
|
||||
val popup = PopupMenu(requireContext(), view)
|
||||
popup.inflate(R.menu.menu_nodes)
|
||||
popup.menu.findItem(R.id.direct_message).isVisible = position > 0
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit d3375fe599da1dd48572354325d3186eccf6f449
|
||||
Subproject commit d3dfaa63a5108c1da7571cd780efaf561b99cc74
|
||||
Ładowanie…
Reference in New Issue