-
Notifications
You must be signed in to change notification settings - Fork 129
/
LocationTrackingActivity.kt
154 lines (132 loc) · 5.45 KB
/
LocationTrackingActivity.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package com.google.maps.android.compose
import android.location.Location
import android.os.Bundle
import android.util.Log
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.LocationSource
import com.google.android.gms.maps.LocationSource.OnLocationChangedListener
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.shareIn
import kotlin.random.Random
private const val TAG = "LocationTrackActivity"
private const val zoom = 8f
/**
* This shows how to use a custom location source to show a blue dot on the map based on your own
* locations.
*/
class LocationTrackingActivity : AppCompatActivity() {
private val locationSource = MyLocationSource()
private var counter = 0
// Generates "fake" locations randomly every 2 seconds.
// Normally you'd request location updates:
// https://developer.android.com/training/location/request-updates
private val locationFlow = callbackFlow {
while (true) {
++counter
val location = newLocation()
Log.d(TAG, "Location $counter: $location")
trySend(location)
delay(2_000)
}
}.shareIn(
lifecycleScope,
replay = 0,
started = SharingStarted.WhileSubscribed()
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var isMapLoaded by remember { mutableStateOf(false) }
// To control and observe the map camera
val cameraPositionState = rememberCameraPositionState {
position = defaultCameraPosition
}
// To show blue dot on map
val mapProperties by remember { mutableStateOf(MapProperties(isMyLocationEnabled = true)) }
// Collect location updates
val locationState = locationFlow.collectAsState(initial = newLocation())
// Update blue dot and camera when the location changes
LaunchedEffect(locationState.value) {
Log.d(TAG, "Updating blue dot on map...")
locationSource.onLocationChanged(locationState.value)
Log.d(TAG, "Updating camera position...")
val cameraPosition = CameraPosition.fromLatLngZoom(LatLng(locationState.value.latitude, locationState.value.longitude), zoom)
cameraPositionState.animate(CameraUpdateFactory.newCameraPosition(cameraPosition), 1_000)
}
// Detect when the map starts moving and print the reason
LaunchedEffect(cameraPositionState.isMoving) {
if (cameraPositionState.isMoving) {
Log.d(TAG, "Map camera started moving due to ${cameraPositionState.cameraMoveStartedReason.name}")
}
}
Box(Modifier.fillMaxSize()) {
GoogleMap(
modifier = Modifier.matchParentSize(),
cameraPositionState = cameraPositionState,
onMapLoaded = {
isMapLoaded = true
},
locationSource = locationSource,
properties = mapProperties
)
if (!isMapLoaded) {
AnimatedVisibility(
modifier = Modifier
.matchParentSize(),
visible = !isMapLoaded,
enter = EnterTransition.None,
exit = fadeOut()
) {
CircularProgressIndicator(
modifier = Modifier
.background(MaterialTheme.colors.background)
.wrapContentSize()
)
}
}
}
}
}
}
/**
* A [LocationSource] which allows it's location to be set. In practice you would request location
* updates (https://developer.android.com/training/location/request-updates).
*/
private class MyLocationSource : LocationSource {
private var listener: OnLocationChangedListener? = null
override fun activate(listener: OnLocationChangedListener) {
this.listener = listener
}
override fun deactivate() {
listener = null
}
fun onLocationChanged(location: Location) {
listener?.onLocationChanged(location)
}
}
private fun newLocation(): Location {
val location = Location("MyLocationProvider")
location.apply {
latitude = singapore.latitude + Random.nextFloat()
longitude = singapore.longitude + Random.nextFloat()
}
return location
}