Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 2e38bfc

Browse files
jdkorenGerrit Code Review
authored and
Gerrit Code Review
committed
Merge "Receive location updates" into main
2 parents d8aa95a + 594ec4e commit 2e38bfc

File tree

7 files changed

+126
-14
lines changed

7 files changed

+126
-14
lines changed

ForegroundLocationUpdates/app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ dependencies {
8080

8181
// Play Services
8282
implementation 'com.google.android.gms:play-services-base:17.6.0'
83+
implementation 'com.google.android.gms:play-services-location:18.0.0'
8384

8485
// Hilt
8586
kapt "androidx.hilt:hilt-compiler:$hilt_compiler_version"

ForegroundLocationUpdates/app/src/main/java/com/google/android/gms/location/sample/foregroundlocation/ForegroundLocationApp.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.google.android.gms.location.sample.foregroundlocation
1818

1919
import android.app.Application
2020
import com.google.android.gms.common.GoogleApiAvailability
21+
import com.google.android.gms.location.LocationServices
2122
import dagger.Module
2223
import dagger.Provides
2324
import dagger.hilt.InstallIn
@@ -35,4 +36,10 @@ object AppModule {
3536
@Provides
3637
@Singleton
3738
fun provideGoogleApiAvailability() = GoogleApiAvailability.getInstance()
39+
40+
@Provides
41+
@Singleton
42+
fun provideFusedLocationProviderClient(
43+
application: Application
44+
) = LocationServices.getFusedLocationProviderClient(application)
3845
}

ForegroundLocationUpdates/app/src/main/java/com/google/android/gms/location/sample/foregroundlocation/MainActivity.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.google.android.gms.location.sample.foregroundlocation
1818

1919
import android.os.Bundle
20-
import android.util.Log
2120
import androidx.activity.ComponentActivity
2221
import androidx.activity.compose.setContent
2322
import androidx.activity.viewModels
@@ -48,8 +47,7 @@ class MainActivity : ComponentActivity() {
4847

4948
val locationPermissionState = LocationPermissionState(this) {
5049
if (it.hasPermission()) {
51-
// TODO register for location updates
52-
Log.d("ForegroundLocation", "TODO register for location updates")
50+
viewModel.toggleLocationUpdates()
5351
}
5452
}
5553

@@ -80,14 +78,19 @@ fun MainScreen(
8078
locationPermissionState: LocationPermissionState
8179
) {
8280
val uiState by viewModel.playServicesAvailableState.collectAsState()
81+
val isLocationOn by viewModel.isReceivingLocationUpdates.collectAsState()
82+
val lastLocation by viewModel.lastLocation.collectAsState()
83+
8384
when (uiState) {
8485
Initializing -> InitializingScreen()
8586
PlayServicesUnavailable -> ServiceUnavailableScreen()
8687
PlayServicesAvailable -> {
8788
LocationUpdatesScreen(
8889
showDegradedExperience = locationPermissionState.showDegradedExperience,
8990
needsPermissionRationale = locationPermissionState.shouldShowRationale(),
90-
onButtonClick = locationPermissionState::requestPermissions
91+
onButtonClick = locationPermissionState::requestPermissions,
92+
isLocationOn = isLocationOn,
93+
location = lastLocation,
9194
)
9295
}
9396
}

ForegroundLocationUpdates/app/src/main/java/com/google/android/gms/location/sample/foregroundlocation/MainViewModel.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.lifecycle.viewModelScope
2121
import com.google.android.gms.location.sample.foregroundlocation.PlayServicesAvailableState.Initializing
2222
import com.google.android.gms.location.sample.foregroundlocation.PlayServicesAvailableState.PlayServicesAvailable
2323
import com.google.android.gms.location.sample.foregroundlocation.PlayServicesAvailableState.PlayServicesUnavailable
24+
import com.google.android.gms.location.sample.foregroundlocation.data.LocationRepository
2425
import com.google.android.gms.location.sample.foregroundlocation.data.PlayServicesAvailabilityChecker
2526
import dagger.hilt.android.lifecycle.HiltViewModel
2627
import kotlinx.coroutines.flow.SharingStarted
@@ -30,7 +31,8 @@ import javax.inject.Inject
3031

3132
@HiltViewModel
3233
class MainViewModel @Inject constructor(
33-
playServicesAvailabilityChecker: PlayServicesAvailabilityChecker
34+
playServicesAvailabilityChecker: PlayServicesAvailabilityChecker,
35+
private val locationRepository: LocationRepository
3436
) : ViewModel() {
3537

3638
val playServicesAvailableState = flow {
@@ -43,6 +45,16 @@ class MainViewModel @Inject constructor(
4345
)
4446
}.stateIn(viewModelScope, SharingStarted.Eagerly, Initializing)
4547

48+
val isReceivingLocationUpdates = locationRepository.isReceivingLocationUpdates
49+
val lastLocation = locationRepository.lastLocation
50+
51+
fun toggleLocationUpdates() {
52+
if (isReceivingLocationUpdates.value) {
53+
locationRepository.stopLocationUpdates()
54+
} else {
55+
locationRepository.startLocationUpdates()
56+
}
57+
}
4658
}
4759

4860
enum class PlayServicesAvailableState {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (C) 2021 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.android.gms.location.sample.foregroundlocation.data
18+
19+
import android.annotation.SuppressLint
20+
import android.location.Location
21+
import android.os.Looper
22+
import com.google.android.gms.location.FusedLocationProviderClient
23+
import com.google.android.gms.location.LocationCallback
24+
import com.google.android.gms.location.LocationRequest
25+
import com.google.android.gms.location.LocationResult
26+
import kotlinx.coroutines.flow.MutableStateFlow
27+
import kotlinx.coroutines.flow.asStateFlow
28+
import javax.inject.Inject
29+
30+
class LocationRepository @Inject constructor(
31+
private val fusedLocationProviderClient: FusedLocationProviderClient
32+
) {
33+
private val callback = Callback()
34+
35+
private val _isReceivingUpdates = MutableStateFlow(false)
36+
val isReceivingLocationUpdates = _isReceivingUpdates.asStateFlow()
37+
38+
private val _lastLocation = MutableStateFlow<Location?>(null)
39+
val lastLocation = _lastLocation.asStateFlow()
40+
41+
@SuppressLint("MissingPermission") // Only called when holding location permission.
42+
fun startLocationUpdates() {
43+
val request = LocationRequest.create().apply {
44+
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
45+
interval = 10_000 // 10 seconds
46+
}
47+
// Note: For this sample it's fine to use the main looper, so our callback will run on the
48+
// main thread. If your callback will perform any intensive operations (writing to disk,
49+
// making a network request, etc.), either change to a background thread from the callback,
50+
// or create a HandlerThread and pass its Looper here instead.
51+
// See https://developer.android.com/reference/android/os/HandlerThread.
52+
fusedLocationProviderClient.requestLocationUpdates(
53+
request,
54+
callback,
55+
Looper.getMainLooper()
56+
)
57+
_isReceivingUpdates.value = true
58+
}
59+
60+
fun stopLocationUpdates() {
61+
fusedLocationProviderClient.removeLocationUpdates(callback)
62+
_isReceivingUpdates.value = false
63+
_lastLocation.value = null
64+
}
65+
66+
inner class Callback : LocationCallback() {
67+
override fun onLocationResult(result: LocationResult) {
68+
_lastLocation.value = result.lastLocation
69+
}
70+
}
71+
}

ForegroundLocationUpdates/app/src/main/java/com/google/android/gms/location/sample/foregroundlocation/ui/LocationUpdatesScreen.kt

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.android.gms.location.sample.foregroundlocation.ui
1818

19+
import android.location.Location
1920
import androidx.compose.foundation.layout.Arrangement
2021
import androidx.compose.foundation.layout.Column
2122
import androidx.compose.foundation.layout.fillMaxSize
@@ -42,7 +43,9 @@ import com.google.android.gms.location.sample.foregroundlocation.ui.theme.Foregr
4243
fun LocationUpdatesScreen(
4344
showDegradedExperience: Boolean,
4445
needsPermissionRationale: Boolean,
45-
onButtonClick: () -> Unit
46+
onButtonClick: () -> Unit,
47+
isLocationOn: Boolean,
48+
location: Location?
4649
) {
4750
var showRationaleDialog by remember { mutableStateOf(false) }
4851
if (showRationaleDialog) {
@@ -63,26 +66,35 @@ fun LocationUpdatesScreen(
6366
}
6467
}
6568

69+
val message = when {
70+
isLocationOn -> if (location != null) {
71+
stringResource(
72+
id = R.string.location_lat_lng,
73+
location.latitude,
74+
location.longitude
75+
)
76+
} else {
77+
stringResource(id = R.string.waiting_for_location)
78+
}
79+
showDegradedExperience -> stringResource(id = R.string.please_allow_permission)
80+
else -> stringResource(id = R.string.not_started)
81+
}
82+
val labelResId = if (isLocationOn) R.string.stop else R.string.start
83+
6684
Column(
6785
modifier = Modifier
6886
.fillMaxSize()
6987
.padding(16.dp),
7088
horizontalAlignment = Alignment.CenterHorizontally,
7189
verticalArrangement = Arrangement.SpaceEvenly
7290
) {
73-
val message = if (showDegradedExperience) {
74-
stringResource(id = R.string.please_allow_permission)
75-
} else {
76-
stringResource(id = R.string.not_started)
77-
}
78-
7991
Text(
8092
text = message,
8193
style = MaterialTheme.typography.h6,
8294
textAlign = TextAlign.Center
8395
)
8496
Button(onClick = { onClick() }) {
85-
Text(text = stringResource(id = R.string.start))
97+
Text(text = stringResource(id = labelResId))
8698
}
8799
}
88100
}
@@ -120,7 +132,9 @@ fun LocationUpdatesScreenPreview() {
120132
LocationUpdatesScreen(
121133
showDegradedExperience = false,
122134
needsPermissionRationale = false,
123-
onButtonClick = {}
135+
onButtonClick = {},
136+
isLocationOn = true,
137+
location = null,
124138
)
125139
}
126140
}

ForegroundLocationUpdates/app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222
<string name="start">Start</string>
2323
<string name="stop">Stop</string>
2424
<string name="not_started">Tap Start to receive location updates</string>
25+
2526
<string name="please_allow_permission">Please allow permission to access location</string>
2627
<string name="permission_rationale_dialog_title">Permission needed</string>
2728
<string name="permission_rationale_dialog_message">This app requires permission to access your location. Please accept.</string>
29+
30+
<string name="waiting_for_location">Waiting for location…</string>
31+
<string name="location_lat_lng">Lat: %1$f\nLng: %2$f</string>
2832
</resources>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy