mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
commit
852cd2ddc7
10 changed files with 61 additions and 58 deletions
|
|
@ -42,8 +42,8 @@ android {
|
|||
applicationId "com.geeksville.mesh"
|
||||
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
|
||||
targetSdkVersion 30 // 30 can't work until an explicit location permissions dialog is added
|
||||
versionCode 20253 // format is Mmmss (where M is 1+the numeric major number
|
||||
versionName "1.2.53"
|
||||
versionCode 20254 // format is Mmmss (where M is 1+the numeric major number
|
||||
versionName "1.2.54"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// per https://developer.android.com/studio/write/vector-asset-studio
|
||||
|
|
@ -121,16 +121,16 @@ protobuf {
|
|||
|
||||
dependencies {
|
||||
|
||||
def room_version = '2.4.0'
|
||||
def room_version = '2.4.1'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.4.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.4.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
|
||||
|
|
@ -171,10 +171,10 @@ dependencies {
|
|||
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
|
||||
|
||||
// location services
|
||||
implementation 'com.google.android.gms:play-services-location:19.0.0'
|
||||
implementation 'com.google.android.gms:play-services-location:19.0.1'
|
||||
|
||||
// For Google Sign-In (owner name accesss)
|
||||
implementation 'com.google.android.gms:play-services-auth:20.0.0'
|
||||
implementation 'com.google.android.gms:play-services-auth:20.0.1'
|
||||
|
||||
// Add the Firebase SDK for Crashlytics.
|
||||
implementation 'com.google.firebase:firebase-crashlytics:18.2.6'
|
||||
|
|
|
|||
|
|
@ -298,13 +298,13 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
fun requestScanPermission() = requestPermission(getScanPermissions(), true)
|
||||
|
||||
/** Ask the user to grant camera permission */
|
||||
fun requestCameraPermission() = requestPermission(getCameraPermissions(), false)
|
||||
fun requestCameraPermission() = requestPermission(getCameraPermissions())
|
||||
|
||||
/** Ask the user to grant foreground location permission */
|
||||
fun requestLocationPermission() = requestPermission(getLocationPermissions(), false)
|
||||
fun requestLocationPermission() = requestPermission(getLocationPermissions())
|
||||
|
||||
/** Ask the user to grant background location permission */
|
||||
fun requestBackgroundPermission() = requestPermission(getBackgroundPermissions(), false)
|
||||
fun requestBackgroundPermission() = requestPermission(getBackgroundPermissions())
|
||||
|
||||
/**
|
||||
* @return a localized string warning user about missing permissions. Or null if everything is find
|
||||
|
|
@ -344,7 +344,7 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
*/
|
||||
private fun requestPermission(
|
||||
missingPerms: List<String> = getMinimumPermissions(),
|
||||
shouldShowDialog: Boolean = true
|
||||
shouldShowDialog: Boolean = false
|
||||
): Boolean =
|
||||
if (missingPerms.isNotEmpty()) {
|
||||
val shouldShow = missingPerms.filter {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ class MeshService : Service(), Logging {
|
|||
}
|
||||
|
||||
private val locationCallback = MeshServiceLocationCallback(
|
||||
::perhapsSendPosition,
|
||||
::sendPositionScoped,
|
||||
onSendPositionFailed = { onConnectionChanged(ConnectionState.DEVICE_SLEEP) },
|
||||
getNodeNum = { myNodeNum }
|
||||
)
|
||||
|
|
@ -170,7 +170,7 @@ class MeshService : Service(), Logging {
|
|||
* We first check to see if our local device has already sent a position and if so, we punt until the next check.
|
||||
* This allows us to only 'fill in' with GPS positions when the local device happens to have no good GPS sats.
|
||||
*/
|
||||
private fun perhapsSendPosition(
|
||||
private fun sendPositionScoped(
|
||||
lat: Double = 0.0,
|
||||
lon: Double = 0.0,
|
||||
alt: Int = 0,
|
||||
|
|
@ -181,17 +181,7 @@ class MeshService : Service(), Logging {
|
|||
// do most of the work in my service thread
|
||||
serviceScope.handledLaunch {
|
||||
// if android called us too soon, just ignore
|
||||
|
||||
val myInfo = localNodeInfo
|
||||
val lastLat = (myInfo?.position?.latitude ?: 0.0)
|
||||
val lastLon = (myInfo?.position?.longitude ?: 0.0)
|
||||
val lastSendMsec = (myInfo?.position?.time ?: 0) * 1000L
|
||||
val now = System.currentTimeMillis()
|
||||
if ((lastLat == 0.0 && lastLon == 0.0) || (now - lastSendMsec > locationIntervalMsec)) // && minBroadcastPeriod ?
|
||||
sendPosition(lat, lon, alt, destNum, wantResponse)
|
||||
else {
|
||||
debug("Not sending position - local node sent ${(now - lastSendMsec) / 1000L}s ago ${myInfo?.position?.toPIIString()}")
|
||||
}
|
||||
sendPosition(lat, lon, alt, destNum, wantResponse)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1028,10 +1018,10 @@ class MeshService : Service(), Logging {
|
|||
else
|
||||
broadcastSecs * 1000L
|
||||
|
||||
// if (prefs.locationShare == RadioConfigProtos.LocationSharing.LocDisabled) {
|
||||
// info("GPS location sharing is disabled")
|
||||
// desiredInterval = 0
|
||||
// }
|
||||
if (prefs.locationShare == RadioConfigProtos.LocationSharing.LocDisabled) {
|
||||
info("GPS location sharing is disabled")
|
||||
desiredInterval = 0
|
||||
}
|
||||
|
||||
// if (prefs.fixedPosition) {
|
||||
// info("Node has fixed position, therefore not overriding position")
|
||||
|
|
@ -1043,6 +1033,7 @@ class MeshService : Service(), Logging {
|
|||
startLocationRequests(desiredInterval)
|
||||
} else {
|
||||
info("No GPS assistance desired, but sending UTC time to mesh")
|
||||
warnUserAboutLocation()
|
||||
sendPosition()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ class MeshServiceLocationCallback(
|
|||
if (location.isAccurateForMesh) { // if within 200 meters, or accuracy is unknown
|
||||
|
||||
try {
|
||||
// Do we want to broadcast this position globally, or are we just telling the local node what its current position is (
|
||||
// Do we want to broadcast this position globally, or are we just telling the local node what its current position is
|
||||
val shouldBroadcast =
|
||||
true // no need to rate limit, because we are just sending at the interval requested by the preferences
|
||||
false // no need to rate limit, because we are just sending to the local node
|
||||
val destinationNumber =
|
||||
if (shouldBroadcast) DataPacket.NODENUM_BROADCAST else getNodeNum()
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
): View {
|
||||
_binding = AdvancedSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
|
|||
model.radioConfig.observe(viewLifecycleOwner, {
|
||||
binding.positionBroadcastPeriodEditText.setText(model.positionBroadcastSecs.toString())
|
||||
binding.lsSleepEditText.setText(model.lsSleepSecs.toString())
|
||||
binding.positionBroadcastPeriodView.isEnabled = model.locationShare ?: true
|
||||
binding.positionBroadcastSwitch.isChecked = model.locationShare ?: true
|
||||
binding.lsSleepView.isEnabled = model.isPowerSaving ?: false
|
||||
binding.lsSleepSwitch.isChecked = model.isPowerSaving ?: false
|
||||
|
|
@ -47,7 +48,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
|
|||
|
||||
model.isConnected.observe(viewLifecycleOwner, { connectionState ->
|
||||
val connected = connectionState == MeshService.ConnectionState.CONNECTED
|
||||
binding.positionBroadcastPeriodView.isEnabled = connected
|
||||
binding.positionBroadcastPeriodView.isEnabled = connected && model.locationShare ?: true
|
||||
binding.lsSleepView.isEnabled = connected && model.isPowerSaving ?: false
|
||||
binding.positionBroadcastSwitch.isEnabled = connected
|
||||
binding.lsSleepSwitch.isEnabled = connected
|
||||
|
|
|
|||
|
|
@ -615,22 +615,29 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
regionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
spinner.adapter = regionAdapter
|
||||
|
||||
model.bluetoothEnabled.observe(
|
||||
viewLifecycleOwner, {
|
||||
if (it) binding.changeRadioButton.show()
|
||||
else binding.changeRadioButton.hide()
|
||||
})
|
||||
model.bluetoothEnabled.observe(viewLifecycleOwner, {
|
||||
if (it) binding.changeRadioButton.show()
|
||||
else binding.changeRadioButton.hide()
|
||||
})
|
||||
|
||||
model.ownerName.observe(viewLifecycleOwner, { name ->
|
||||
binding.usernameEditText.setText(name)
|
||||
})
|
||||
|
||||
// Only let user edit their name or set software update while connected to a radio
|
||||
model.isConnected.observe(
|
||||
viewLifecycleOwner, {
|
||||
updateNodeInfo()
|
||||
updateDevicesButtons(scanModel.devices.value)
|
||||
})
|
||||
model.isConnected.observe(viewLifecycleOwner, {
|
||||
updateNodeInfo()
|
||||
updateDevicesButtons(scanModel.devices.value)
|
||||
})
|
||||
|
||||
model.radioConfig.observe(viewLifecycleOwner, {
|
||||
binding.provideLocationCheckbox.isEnabled =
|
||||
isGooglePlayAvailable(requireContext()) && model.locationShare ?: true
|
||||
if (model.locationShare == false) {
|
||||
model.provideLocation.value = false
|
||||
binding.provideLocationCheckbox.isChecked = false
|
||||
}
|
||||
})
|
||||
|
||||
// Also watch myNodeInfo because it might change later
|
||||
model.myNodeInfo.observe(viewLifecycleOwner, {
|
||||
|
|
@ -659,7 +666,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
requireActivity().hideKeyboard()
|
||||
}
|
||||
|
||||
binding.provideLocationCheckbox.isEnabled = isGooglePlayAvailable(requireContext())
|
||||
binding.provideLocationCheckbox.setOnCheckedChangeListener { view, isChecked ->
|
||||
if (view.isPressed && isChecked) { // We want to ignore changes caused by code (as opposed to the user)
|
||||
// Don't check the box until the system setting changes
|
||||
|
|
@ -896,7 +902,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
debug("We have location access")
|
||||
}
|
||||
|
||||
locationSettingsResponse.addOnFailureListener { _ ->
|
||||
locationSettingsResponse.addOnFailureListener {
|
||||
errormsg("Failed to get location access")
|
||||
// We always show the toast regardless of what type of exception we receive. Because even non
|
||||
// resolvable api exceptions mean user still needs to fix something.
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
|
||||
</vector>
|
||||
16
app/src/main/res/drawable/ic_twotone_send_24.xml
Normal file
16
app/src/main/res/drawable/ic_twotone_send_24.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,8.25l7.51,1 -7.5,-3.22zM4.01,17.97l7.5,-3.22 -7.51,1z"
|
||||
android:strokeAlpha="0.3"
|
||||
android:fillAlpha="0.3"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M2.01,3L2,10l15,2 -15,2 0.01,7L23,12 2.01,3zM4,8.25L4,6.03l7.51,3.22 -7.51,-1zM4.01,17.97v-2.22l7.51,-1 -7.51,3.22z"/>
|
||||
</vector>
|
||||
|
|
@ -48,6 +48,6 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/textInputLayout"
|
||||
app:srcCompat="@drawable/ic_send_24" />
|
||||
app:srcCompat="@drawable/ic_twotone_send_24" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ buildscript {
|
|||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||
|
||||
// protobuf plugin - docs here https://github.com/google/protobuf-gradle-plugin
|
||||
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.15'
|
||||
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.17'
|
||||
|
||||
//classpath "app.brant:amazonappstorepublisher:0.1.0"
|
||||
classpath 'com.github.triplet.gradle:play-publisher:2.8.0'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue