Skip to content

Commit

Permalink
fix: sharing location crash when device location off (dev) (WPB-6182) (
Browse files Browse the repository at this point in the history
…#2606)

Co-authored-by: Alexandre Ferris <[email protected]>
  • Loading branch information
yamilmedina and alexandreferris authored Jan 23, 2024
1 parent 0ecc5d4 commit 9601c92
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package com.wire.android.ui.home.messagecomposer.location

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
Expand All @@ -30,16 +31,22 @@ import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SheetValue
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import com.wire.android.R
import com.wire.android.ui.common.Icon
Expand All @@ -58,6 +65,7 @@ import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.orDefault
import com.wire.android.util.permission.PermissionsDeniedRequestDialog
import com.wire.android.util.permission.rememberCurrentLocationFlow
import kotlinx.coroutines.launch

/**
* Component to pick the current location to send.
Expand Down Expand Up @@ -104,42 +112,91 @@ fun LocationPickerComponent(
}
}
add {
Column(
Box(
modifier = Modifier
.align(alignment = Alignment.Start)
.padding(horizontal = dimensions().spacing16x)
.wrapContentHeight()
.fillMaxWidth()
) {
WirePrimaryButton(
onClick = {
onLocationPicked(geoLocatedAddress!!)
onLocationClosed()
},
leadingIcon = Icons.Filled.Send.Icon(Modifier.padding(end = dimensions().spacing8x)),
text = stringResource(id = R.string.content_description_send_button),
state = if (isLocationLoading || geoLocatedAddress == null) {
WireButtonState.Disabled
} else {
WireButtonState.Default
if (showLocationSharingError) {
LocationErrorMessage {
coroutineScope.launch {
sheetState.hide()
viewModel.onLocationSharingErrorDialogDiscarded()
onLocationClosed()
}
}
}
SendLocationButton(
isLocationLoading = isLocationLoading,
geoLocatedAddress = geoLocatedAddress,
onLocationPicked = onLocationPicked,
onLocationClosed = onLocationClosed
)
VerticalSpace.x16()
}
}
}
)

if (showPermissionDeniedDialog) {
PermissionsDeniedRequestDialog(
body = R.string.location_app_permission_dialog_body,
onDismiss = {
viewModel.onPermissionsDialogDiscarded()
onLocationClosed()
}
)
}
}
}
}

if (viewModel.state.showPermissionDeniedDialog) {
PermissionsDeniedRequestDialog(
body = R.string.location_app_permission_dialog_body,
onDismiss = {
viewModel.onPermissionsDialogDiscarded()
@Composable
private fun SendLocationButton(
isLocationLoading: Boolean,
geoLocatedAddress: GeoLocatedAddress?,
onLocationPicked: (GeoLocatedAddress) -> Unit,
onLocationClosed: () -> Unit
) {
Column(
modifier = Modifier
.padding(horizontal = dimensions().spacing16x)
.wrapContentHeight()
.fillMaxWidth()
) {
WirePrimaryButton(
onClick = {
onLocationPicked(geoLocatedAddress!!)
onLocationClosed()
},
leadingIcon = Icons.Filled.Send.Icon(Modifier.padding(end = dimensions().spacing8x)),
text = stringResource(id = R.string.content_description_send_button),
state = if (isLocationLoading || geoLocatedAddress == null) {
WireButtonState.Disabled
} else {
WireButtonState.Default
}
)
VerticalSpace.x16()
}
}

@Composable
private fun LocationErrorMessage(
message: String = stringResource(id = R.string.location_could_not_be_shared),
onLocationClosed: () -> Unit
) {
Box(Modifier.zIndex(Float.MAX_VALUE), contentAlignment = Alignment.BottomCenter) {
val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(snackbarHostState) {
val result = snackbarHostState.showSnackbar(message = message, duration = SnackbarDuration.Short)
when (result) {
SnackbarResult.Dismissed -> onLocationClosed()
SnackbarResult.ActionPerformed -> {
/* do nothing */
}
}
}
SnackbarHost(hostState = snackbarHostState)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ data class LocationPickerState(
val isLocationLoading: Boolean = false,
val isPermissionDiscarded: Boolean = false,
val showPermissionDeniedDialog: Boolean = false,
val showLocationSharingError: Boolean = false,
val wireModalSheetState: WireModalSheetState = WireModalSheetState(SheetValue.Hidden)
)
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import android.location.LocationManager
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.location.LocationManagerCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.gms.location.LocationServices
Expand All @@ -40,23 +41,44 @@ import javax.inject.Inject

@HiltViewModel
class LocationPickerViewModel @Inject constructor() : ViewModel() {

var state: LocationPickerState by mutableStateOf(LocationPickerState())
private set

fun onPermissionsDialogDiscarded() {
state = state.copy(showPermissionDeniedDialog = false)
}

fun onLocationSharingErrorDialogDiscarded() {
state = state.copy(showLocationSharingError = false)
}

fun onPermissionsDenied() {
state = state.copy(showPermissionDeniedDialog = true)
}

private fun toStartLoadingLocationState() {
state = state.copy(isLocationLoading = true, geoLocatedAddress = null)
state = state.copy(
showLocationSharingError = false,
isLocationLoading = true,
geoLocatedAddress = null
)
}

private fun toLocationLoadedState(geoLocatedAddress: GeoLocatedAddress) {
state = state.copy(isLocationLoading = false, geoLocatedAddress = geoLocatedAddress)
state = state.copy(
showLocationSharingError = false,
isLocationLoading = false,
geoLocatedAddress = geoLocatedAddress
)
}

private fun toLocationError() {
state = state.copy(
showLocationSharingError = true,
isLocationLoading = false,
geoLocatedAddress = null,
)
}

fun getCurrentLocation(context: Context) {
Expand All @@ -74,23 +96,36 @@ class LocationPickerViewModel @Inject constructor() : ViewModel() {
@SuppressLint("MissingPermission")
private fun getLocationWithGms(context: Context) = viewModelScope.launch {
appLogger.d("Getting location with GMS")
val locationProvider = LocationServices.getFusedLocationProviderClient(context)
val currentLocation = locationProvider.getCurrentLocation(PRIORITY_HIGH_ACCURACY, CancellationTokenSource().token).await()
val address = Geocoder(context).getFromLocation(currentLocation.latitude, currentLocation.longitude, 1).orEmpty()
toLocationLoadedState(GeoLocatedAddress(address.firstOrNull(), currentLocation))
if (isLocationServicesEnabled(context)) {
val locationProvider = LocationServices.getFusedLocationProviderClient(context)
val currentLocation = locationProvider.getCurrentLocation(PRIORITY_HIGH_ACCURACY, CancellationTokenSource().token).await()
val address = Geocoder(context).getFromLocation(currentLocation.latitude, currentLocation.longitude, 1).orEmpty()
toLocationLoadedState(GeoLocatedAddress(address.firstOrNull(), currentLocation))
} else {
toLocationError()
}
}

@SuppressLint("MissingPermission")
private fun getLocationWithoutGms(context: Context) = viewModelScope.launch {
appLogger.d("Getting location without GMS")
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val networkLocationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
val address = Geocoder(context).getFromLocation(location.latitude, location.longitude, 1).orEmpty()
toLocationLoadedState(GeoLocatedAddress(address.firstOrNull(), location))
locationManager.removeUpdates(this) // important step, otherwise it will keep listening for location changes
if (isLocationServicesEnabled(context)) {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val networkLocationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
val address = Geocoder(context).getFromLocation(location.latitude, location.longitude, 1).orEmpty()
toLocationLoadedState(GeoLocatedAddress(address.firstOrNull(), location))
locationManager.removeUpdates(this) // important step, otherwise it will keep listening for location changes
}
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, networkLocationListener)
} else {
toLocationError()
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, networkLocationListener)
}

private fun isLocationServicesEnabled(context: Context): Boolean {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return LocationManagerCompat.isLocationEnabled(locationManager)
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1360,4 +1360,5 @@
<string name="location_attachment_share_title">Share Location</string>
<string name="location_app_permission_dialog_body">Allow Wire to access your device location to send your location.</string>
<string name="location_loading_label">Please wait...</string>
<string name="location_could_not_be_shared">Location could not be shared</string>
</resources>

0 comments on commit 9601c92

Please sign in to comment.