mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
fix : prevent crash on geo: intent when no compatible map app is inst… (#1936)
Co-authored-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
ac22ac3f28
commit
f6f3cf5c20
2 changed files with 78 additions and 37 deletions
|
|
@ -86,6 +86,14 @@
|
|||
android:name="android.hardware.usb.host"
|
||||
android:required="false" />
|
||||
|
||||
<!-- Declare geo: intent visibility for Android 11+ (needed for resolveActivity with map apps) -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="geo" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<!-- hardware acceleration is required for zxing barcode lib -->
|
||||
<application
|
||||
android:name="com.geeksville.mesh.MeshUtilApplication"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package com.geeksville.mesh.ui
|
|||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -29,7 +31,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.ClipEntry
|
||||
import androidx.compose.ui.platform.Clipboard
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
|
|
@ -37,6 +39,7 @@ import androidx.compose.ui.text.withStyle
|
|||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.core.net.toUri
|
||||
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.GpsCoordinateFormat
|
||||
import com.geeksville.mesh.android.BuildUtils.debug
|
||||
import com.geeksville.mesh.ui.theme.AppTheme
|
||||
|
|
@ -54,53 +57,29 @@ fun LinkedCoordinates(
|
|||
format: Int,
|
||||
nodeName: String,
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
val context = LocalContext.current
|
||||
val clipboard: Clipboard = LocalClipboard.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val style = SpanStyle(
|
||||
color = HyperlinkBlue,
|
||||
fontSize = MaterialTheme.typography.labelLarge.fontSize,
|
||||
textDecoration = TextDecoration.Underline
|
||||
)
|
||||
val annotatedString = buildAnnotatedString {
|
||||
pushStringAnnotation(
|
||||
tag = "gps",
|
||||
// URI scheme is defined at:
|
||||
// https://developer.android.com/guide/components/intents-common#Maps
|
||||
annotation = "geo:0,0?q=$latitude,$longitude&z=17&label=${
|
||||
URLEncoder.encode(nodeName, "utf-8")
|
||||
}"
|
||||
)
|
||||
withStyle(style = style) {
|
||||
val gpsString = when (format) {
|
||||
GpsCoordinateFormat.DEC_VALUE -> GPSFormat.toDEC(latitude, longitude)
|
||||
GpsCoordinateFormat.DMS_VALUE -> GPSFormat.toDMS(latitude, longitude)
|
||||
GpsCoordinateFormat.UTM_VALUE -> GPSFormat.toUTM(latitude, longitude)
|
||||
GpsCoordinateFormat.MGRS_VALUE -> GPSFormat.toMGRS(latitude, longitude)
|
||||
else -> GPSFormat.toDEC(latitude, longitude)
|
||||
}
|
||||
append(gpsString)
|
||||
}
|
||||
pop()
|
||||
}
|
||||
val clipboard: Clipboard = LocalClipboard.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val annotatedString = rememberAnnotatedString(latitude, longitude, format, nodeName, style)
|
||||
|
||||
Text(
|
||||
modifier = modifier.combinedClickable(
|
||||
onClick = {
|
||||
annotatedString.getStringAnnotations(
|
||||
tag = "gps",
|
||||
start = 0,
|
||||
end = annotatedString.length
|
||||
).firstOrNull()?.let {
|
||||
try {
|
||||
uriHandler.openUri(it.item)
|
||||
} catch (ex: ActivityNotFoundException) {
|
||||
debug("No application found: $ex")
|
||||
}
|
||||
}
|
||||
handleClick(context, annotatedString)
|
||||
},
|
||||
onLongClick = {
|
||||
coroutineScope.launch {
|
||||
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("", annotatedString)))
|
||||
clipboard.setClipEntry(
|
||||
ClipEntry(
|
||||
ClipData.newPlainText("", annotatedString)
|
||||
)
|
||||
)
|
||||
debug("Copied to clipboard")
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +88,60 @@ fun LinkedCoordinates(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberAnnotatedString(
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
format: Int,
|
||||
nodeName: String,
|
||||
style: SpanStyle
|
||||
) = buildAnnotatedString {
|
||||
pushStringAnnotation(
|
||||
tag = "gps",
|
||||
annotation = "geo:0,0?q=$latitude,$longitude&z=17&label=${
|
||||
URLEncoder.encode(nodeName, "utf-8")
|
||||
}"
|
||||
)
|
||||
withStyle(style = style) {
|
||||
val gpsString = when (format) {
|
||||
GpsCoordinateFormat.DEC_VALUE -> GPSFormat.toDEC(latitude, longitude)
|
||||
GpsCoordinateFormat.DMS_VALUE -> GPSFormat.toDMS(latitude, longitude)
|
||||
GpsCoordinateFormat.UTM_VALUE -> GPSFormat.toUTM(latitude, longitude)
|
||||
GpsCoordinateFormat.MGRS_VALUE -> GPSFormat.toMGRS(latitude, longitude)
|
||||
else -> GPSFormat.toDEC(latitude, longitude)
|
||||
}
|
||||
append(gpsString)
|
||||
}
|
||||
pop()
|
||||
}
|
||||
|
||||
private fun handleClick(context: android.content.Context, annotatedString: androidx.compose.ui.text.AnnotatedString) {
|
||||
annotatedString.getStringAnnotations(
|
||||
tag = "gps",
|
||||
start = 0,
|
||||
end = annotatedString.length
|
||||
).firstOrNull()?.let {
|
||||
val uri = it.item.toUri()
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
try {
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"No application available to open this location!",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
} catch (ex: ActivityNotFoundException) {
|
||||
debug("Failed to open geo intent: $ex")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
fun LinkedCoordinatesPreview(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue