Skip to content

Commit 17e7030

Browse files
RD-1152: Add location tracking
1 parent 2d3341a commit 17e7030

File tree

5 files changed

+330
-5
lines changed

5 files changed

+330
-5
lines changed

.idea/vcs.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Examples/MapTilerMobileDemo/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools">
44
<uses-permission android:name="android.permission.INTERNET" />
5+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
6+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
57

68
<application
79
android:hardwareAccelerated="true"
@@ -31,4 +33,4 @@
3133
android:value="${MAPTILER_API_KEY}" />
3234
</application>
3335

34-
</manifest>
36+
</manifest>

Examples/MapTilerMobileDemo/app/src/main/java/com/maptilerdemo/maptilermobiledemo/HomeScreen.kt

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,33 @@ package com.maptilerdemo.maptilermobiledemo
88

99
import android.content.Context
1010
import android.graphics.BitmapFactory
11-
import android.graphics.Color
11+
import android.location.Location
1212
import android.util.Log
13+
import androidx.activity.compose.rememberLauncherForActivityResult
14+
import androidx.activity.result.contract.ActivityResultContracts
1315
import androidx.compose.foundation.layout.Arrangement
1416
import androidx.compose.foundation.layout.Box
1517
import androidx.compose.foundation.layout.Column
1618
import androidx.compose.foundation.layout.fillMaxSize
1719
import androidx.compose.foundation.layout.padding
1820
import androidx.compose.runtime.Composable
21+
import androidx.compose.runtime.DisposableEffect
22+
import androidx.compose.runtime.MutableState
23+
import androidx.compose.runtime.mutableStateOf
24+
import androidx.compose.runtime.remember
1925
import androidx.compose.ui.Alignment
2026
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.graphics.Color
28+
import androidx.compose.ui.graphics.toArgb
2129
import androidx.compose.ui.unit.dp
2230
import androidx.navigation.NavController
2331
import com.maptiler.maptilersdk.MTConfig
2432
import com.maptiler.maptilersdk.annotations.MTMarker
2533
import com.maptiler.maptilersdk.annotations.MTTextPopup
2634
import com.maptiler.maptilersdk.events.MTEvent
35+
import com.maptiler.maptilersdk.location.MTLocationError
36+
import com.maptiler.maptilersdk.location.MTLocationManager
37+
import com.maptiler.maptilersdk.location.MTLocationManagerDelegate
2738
import com.maptiler.maptilersdk.map.LngLat
2839
import com.maptiler.maptilersdk.map.MTMapOptions
2940
import com.maptiler.maptilersdk.map.MTMapView
@@ -47,6 +58,54 @@ fun HomeScreen(
4758
context: Context,
4859
) {
4960
val mapController = MapController(context)
61+
val locationManager = remember(context) { MTLocationManager(context) }
62+
val userMarker: MutableState<MTMarker?> = remember { mutableStateOf(null) }
63+
64+
val permissionLauncher =
65+
rememberLauncherForActivityResult(
66+
ActivityResultContracts.RequestMultiplePermissions(),
67+
) { grants ->
68+
val granted =
69+
(grants[android.Manifest.permission.ACCESS_FINE_LOCATION] == true) ||
70+
(grants[android.Manifest.permission.ACCESS_COARSE_LOCATION] == true)
71+
if (granted) {
72+
locationManager.startLocationUpdates()
73+
} else {
74+
Log.w("Demo App", "Location permission denied by user")
75+
}
76+
}
77+
78+
DisposableEffect(Unit) {
79+
// Wire delegate; stop on dispose
80+
locationManager.delegate =
81+
object : MTLocationManagerDelegate {
82+
override fun didUpdateLocation(location: Location) {
83+
val lngLat = LngLat(location.longitude, location.latitude)
84+
val marker = userMarker.value
85+
if (marker == null) {
86+
val newMarker = MTMarker(lngLat, Color.Blue.toArgb())
87+
userMarker.value = newMarker
88+
mapController.controller.style?.addMarker(newMarker)
89+
90+
mapController.controller.easeTo(MTCameraOptions((lngLat)))
91+
} else {
92+
marker.setCoordinates(lngLat, mapController.controller)
93+
}
94+
}
95+
96+
override fun didFailWithError(error: Throwable) {
97+
if (error is MTLocationError) {
98+
Log.e("Demo App", "Location error: ${error.message}")
99+
} else {
100+
Log.e("Demo App", "Location error: $error")
101+
}
102+
}
103+
}
104+
onDispose {
105+
locationManager.stopLocationUpdates()
106+
locationManager.delegate = null
107+
}
108+
}
50109

51110
val options = MTMapOptions()
52111
options.setMapTilerLogoIsVisible(true)
@@ -79,8 +138,8 @@ fun HomeScreen(
79138
} else if (type == MTLayerType.FILL) {
80139
try {
81140
val layer = MTFillLayer("fillLayer", "openmapsource")
82-
layer.color = Color.BLUE
83-
layer.outlineColor = Color.CYAN
141+
layer.color = Color.Blue.toArgb()
142+
layer.outlineColor = Color.Cyan.toArgb()
84143
layer.sourceLayer = "aeroway"
85144
mapController.controller.style?.addLayer(layer)
86145
} catch (error: MTStyleError) {
@@ -89,7 +148,7 @@ fun HomeScreen(
89148
} else if (type == MTLayerType.LINE) {
90149
try {
91150
val layer = MTLineLayer("lineLayer", "openmapsource")
92-
layer.color = Color.BLUE
151+
layer.color = Color.Blue.toArgb()
93152
layer.sourceLayer = "water"
94153
mapController.controller.style?.addLayer(layer)
95154
} catch (error: MTStyleError) {
@@ -127,6 +186,24 @@ fun HomeScreen(
127186
Modifier
128187
.padding(10.dp),
129188
)
189+
190+
LocationControl(
191+
onLocate = {
192+
if (locationManager.hasLocationPermission()) {
193+
locationManager.startLocationUpdates()
194+
} else {
195+
permissionLauncher.launch(
196+
arrayOf(
197+
android.Manifest.permission.ACCESS_FINE_LOCATION,
198+
android.Manifest.permission.ACCESS_COARSE_LOCATION,
199+
),
200+
)
201+
}
202+
},
203+
modifier =
204+
Modifier
205+
.padding(10.dp),
206+
)
130207
}
131208

132209
NavigationControl(
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025, MapTiler
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD 3-Clause
5+
*/
6+
7+
package com.maptilerdemo.maptilermobiledemo
8+
9+
import androidx.compose.foundation.background
10+
import androidx.compose.foundation.layout.Row
11+
import androidx.compose.foundation.layout.height
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.width
14+
import androidx.compose.foundation.shape.RoundedCornerShape
15+
import androidx.compose.material.icons.Icons
16+
import androidx.compose.material.icons.filled.LocationOn
17+
import androidx.compose.material3.Icon
18+
import androidx.compose.material3.IconButton
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.ui.Alignment
21+
import androidx.compose.ui.Modifier
22+
import androidx.compose.ui.graphics.Color
23+
import androidx.compose.ui.unit.dp
24+
25+
@Suppress("FunctionName")
26+
@Composable
27+
fun LocationControl(
28+
onLocate: () -> Unit,
29+
modifier: Modifier = Modifier,
30+
) {
31+
val width = 60.dp
32+
val height = 60.dp
33+
34+
Row(
35+
modifier =
36+
modifier
37+
.background(Color(0xFFF6F7FD), RoundedCornerShape(30.dp))
38+
.height(height)
39+
.width(width),
40+
verticalAlignment = Alignment.CenterVertically,
41+
) {
42+
IconButton(onClick = onLocate) {
43+
Icon(Icons.Default.LocationOn, contentDescription = "Locate Me", modifier = Modifier.padding(start = 10.dp))
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)