Skip to main content
Added more code segments using Log statement
Source Link
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LocationScreen(
startLocationUpdates: ()->Unit,
context: Context,
currentLocation: LatLng
) {

////// This permissions are use down bellow at a Button Click event that
////// actually calls for the GPS location. The Button  is part of the BottomSheet content.
val permissions = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION,
)

////// startActivityForResult function is deprecated and in Jetpack Compose the solution is 
////// to use "rememberLauncherForActivityResult" with "ActivityResultContracts" 
val launchMultiplePermissions = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissionMaps ->
    val areGranted = permissionMaps.values.reduce { acc, next -> acc && next }
    if (areGranted) {
        locationRequired = true
        startLocationUpdates()
        Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
    }
}

var readable by remember { mutableStateOf("") }
//val scope = rememberCoroutineScope()
val scaffoldState = rememberBottomSheetScaffoldState()

BottomSheetScaffold(
    //modifier = Modifier.heightIn(min=0.dp, max=400.dp),
    scaffoldState = scaffoldState,
    sheetPeekHeight = 590.dp,
    sheetSwipeEnabled = false,
    sheetContent = {

        Column(
            Modifier
                .fillMaxWidth()
                .padding(6.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble() && readable != "") {
                WebViewScreen(location = currentLocation) //, address = readable)
                showdialog.value = false
            } else {Text(text = "Please click [Get your location]")}
            
        }
    }) { innerPadding ->
    Box(Modifier.padding(innerPadding)) {

        Column(
            modifier = Modifier.fillMaxWidth(),
            verticalArrangement = Arrangement.SpaceEvenly,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Your location: ${currentLocation.latitude}/${currentLocation.longitude}")
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble()) {
                Text(
                    text = "Readable location: $currentLocation"
                )
                location = ""
                readable = getReadableLocation(currentLocation.latitude, currentLocation.longitude, context)
                glocation = currentLocation
            }
    //////Here is where the permissions are used to call for the system permissions pop up.
            Button(onClick = {
                if (permissions.all {
                        ContextCompat.checkSelfPermission(
                            context,
                            it
                        ) == PackageManager.PERMISSION_GRANTED
                    }) {
                    //Get Locations
  ////// Here once the permissions are granted I call my function that actually gets the GPS Location
                    startLocationUpdates()
                } else {
                    launchMultiplePermissions.launch(permissions)
                }
                =
            }) {
                Text(text = "Get your location")
            }
        }
    }
}

The GPS Location function is the following:

private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback


override fun onResume() {
    super.onResume()
    if (locationRequired)
        startLocationUpdates()
}

override fun onPause() {
    super.onPause()
    if (this::locationCallback.isInitialized) {
        locationCallback?.let {
            fusedLocationClient?.removeLocationUpdates(it)
        }
    }
}

@SuppressLint("MissingPermission")
private fun startLocationUpdates() {
    locationCallback?.let {
        val locationRequest = LocationRequest.Builder(
            Priority.PRIORITY_HIGH_ACCURACY, 100
        )
            .setWaitForAccurateLocation(false)
            .setMinUpdateIntervalMillis(3000)
            .setMaxUpdateDelayMillis(100)
            .build()

        fusedLocationClient?.requestLocationUpdates(
            locationRequest,
            it,
            Looper.getMainLooper()
        )
    }
}

This code is written in the MainActivity before the onCreate and is pass to the Screen as a Lambda function along the currentLocation:LatLng which is calculated/retrieved by the "startLocationUpdates" function already detail above.

Then inside the onCreate the following code:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

    setContent {

        var currentLocation by remember {
            mutableStateOf(LatLng(0.toDouble(), 0.toDouble()))
        }

        locationCallback = object : LocationCallback() {
            override fun onLocationResult(p0: LocationResult) {
                super.onLocationResult(p0)
                for (location in p0.locations) {
                    currentLocation = LatLng(location.latitude, location.longitude)

                }
            }
        }

        MainTheme { ...
        
        NavHost(navController = navController, startDestination = "MainScreen") {
              composable("LocationScreen") {
                   LocationScreen(
                      { startLocationUpdates() },
                        this@MainActivity,
                        currentLocation
                      )
                   }

        ...
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LocationScreen(
startLocationUpdates: ()->Unit,
context: Context,
currentLocation: LatLng
) {

////// This permissions are use down bellow at a Button Click event that
////// actually calls for the GPS location. The Button  is part of the BottomSheet content.
val permissions = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION,
)

////// startActivityForResult function is deprecated and in Jetpack Compose the solution is 
////// to use "rememberLauncherForActivityResult" with "ActivityResultContracts" 
val launchMultiplePermissions = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissionMaps ->
    val areGranted = permissionMaps.values.reduce { acc, next -> acc && next }
    if (areGranted) {
        locationRequired = true
        startLocationUpdates()
        Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
    }
}

var readable by remember { mutableStateOf("") }
//val scope = rememberCoroutineScope()
val scaffoldState = rememberBottomSheetScaffoldState()

BottomSheetScaffold(
    //modifier = Modifier.heightIn(min=0.dp, max=400.dp),
    scaffoldState = scaffoldState,
    sheetPeekHeight = 590.dp,
    sheetSwipeEnabled = false,
    sheetContent = {

        Column(
            Modifier
                .fillMaxWidth()
                .padding(6.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble() && readable != "") {
                WebViewScreen(location = currentLocation) //, address = readable)
                showdialog.value = false
            } else {Text(text = "Please click [Get your location]")}
            
        }
    }) { innerPadding ->
    Box(Modifier.padding(innerPadding)) {

        Column(
            modifier = Modifier.fillMaxWidth(),
            verticalArrangement = Arrangement.SpaceEvenly,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Your location: ${currentLocation.latitude}/${currentLocation.longitude}")
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble()) {
                Text(
                    text = "Readable location: $currentLocation"
                )
                location = ""
                readable = getReadableLocation(currentLocation.latitude, currentLocation.longitude, context)
                glocation = currentLocation
            }
    //////Here is where the permissions are used to call for the system permissions pop up.
            Button(onClick = {
                if (permissions.all {
                        ContextCompat.checkSelfPermission(
                            context,
                            it
                        ) == PackageManager.PERMISSION_GRANTED
                    }) {
                    //Get Locations
                    startLocationUpdates()
                } else {
                    launchMultiplePermissions.launch(permissions)
                }
                =
            }) {
                Text(text = "Get your location")
            }
        }
    }
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LocationScreen(
startLocationUpdates: ()->Unit,
context: Context,
currentLocation: LatLng
) {

////// This permissions are use down bellow at a Button Click event that
////// actually calls for the GPS location. The Button  is part of the BottomSheet content.
val permissions = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION,
)

////// startActivityForResult function is deprecated and in Jetpack Compose the solution is 
////// to use "rememberLauncherForActivityResult" with "ActivityResultContracts" 
val launchMultiplePermissions = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissionMaps ->
    val areGranted = permissionMaps.values.reduce { acc, next -> acc && next }
    if (areGranted) {
        locationRequired = true
        startLocationUpdates()
        Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
    }
}

var readable by remember { mutableStateOf("") }
//val scope = rememberCoroutineScope()
val scaffoldState = rememberBottomSheetScaffoldState()

BottomSheetScaffold(
    //modifier = Modifier.heightIn(min=0.dp, max=400.dp),
    scaffoldState = scaffoldState,
    sheetPeekHeight = 590.dp,
    sheetSwipeEnabled = false,
    sheetContent = {

        Column(
            Modifier
                .fillMaxWidth()
                .padding(6.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble() && readable != "") {
                WebViewScreen(location = currentLocation) //, address = readable)
                showdialog.value = false
            } else {Text(text = "Please click [Get your location]")}
            
        }
    }) { innerPadding ->
    Box(Modifier.padding(innerPadding)) {

        Column(
            modifier = Modifier.fillMaxWidth(),
            verticalArrangement = Arrangement.SpaceEvenly,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Your location: ${currentLocation.latitude}/${currentLocation.longitude}")
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble()) {
                Text(
                    text = "Readable location: $currentLocation"
                )
                location = ""
                readable = getReadableLocation(currentLocation.latitude, currentLocation.longitude, context)
                glocation = currentLocation
            }
    //////Here is where the permissions are used to call for the system permissions pop up.
            Button(onClick = {
                if (permissions.all {
                        ContextCompat.checkSelfPermission(
                            context,
                            it
                        ) == PackageManager.PERMISSION_GRANTED
                    }) {
                    //Get Locations
  ////// Here once the permissions are granted I call my function that actually gets the GPS Location
                    startLocationUpdates()
                } else {
                    launchMultiplePermissions.launch(permissions)
                }
                =
            }) {
                Text(text = "Get your location")
            }
        }
    }
}

The GPS Location function is the following:

private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback


override fun onResume() {
    super.onResume()
    if (locationRequired)
        startLocationUpdates()
}

override fun onPause() {
    super.onPause()
    if (this::locationCallback.isInitialized) {
        locationCallback?.let {
            fusedLocationClient?.removeLocationUpdates(it)
        }
    }
}

@SuppressLint("MissingPermission")
private fun startLocationUpdates() {
    locationCallback?.let {
        val locationRequest = LocationRequest.Builder(
            Priority.PRIORITY_HIGH_ACCURACY, 100
        )
            .setWaitForAccurateLocation(false)
            .setMinUpdateIntervalMillis(3000)
            .setMaxUpdateDelayMillis(100)
            .build()

        fusedLocationClient?.requestLocationUpdates(
            locationRequest,
            it,
            Looper.getMainLooper()
        )
    }
}

This code is written in the MainActivity before the onCreate and is pass to the Screen as a Lambda function along the currentLocation:LatLng which is calculated/retrieved by the "startLocationUpdates" function already detail above.

Then inside the onCreate the following code:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

    setContent {

        var currentLocation by remember {
            mutableStateOf(LatLng(0.toDouble(), 0.toDouble()))
        }

        locationCallback = object : LocationCallback() {
            override fun onLocationResult(p0: LocationResult) {
                super.onLocationResult(p0)
                for (location in p0.locations) {
                    currentLocation = LatLng(location.latitude, location.longitude)

                }
            }
        }

        MainTheme { ...
        
        NavHost(navController = navController, startDestination = "MainScreen") {
              composable("LocationScreen") {
                   LocationScreen(
                      { startLocationUpdates() },
                        this@MainActivity,
                        currentLocation
                      )
                   }

        ...
Source Link

After many days or weeks I end up using a BottomSheetScaffold.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LocationScreen(
startLocationUpdates: ()->Unit,
context: Context,
currentLocation: LatLng
) {

////// This permissions are use down bellow at a Button Click event that
////// actually calls for the GPS location. The Button  is part of the BottomSheet content.
val permissions = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION,
)

////// startActivityForResult function is deprecated and in Jetpack Compose the solution is 
////// to use "rememberLauncherForActivityResult" with "ActivityResultContracts" 
val launchMultiplePermissions = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissionMaps ->
    val areGranted = permissionMaps.values.reduce { acc, next -> acc && next }
    if (areGranted) {
        locationRequired = true
        startLocationUpdates()
        Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
    }
}

var readable by remember { mutableStateOf("") }
//val scope = rememberCoroutineScope()
val scaffoldState = rememberBottomSheetScaffoldState()

BottomSheetScaffold(
    //modifier = Modifier.heightIn(min=0.dp, max=400.dp),
    scaffoldState = scaffoldState,
    sheetPeekHeight = 590.dp,
    sheetSwipeEnabled = false,
    sheetContent = {

        Column(
            Modifier
                .fillMaxWidth()
                .padding(6.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble() && readable != "") {
                WebViewScreen(location = currentLocation) //, address = readable)
                showdialog.value = false
            } else {Text(text = "Please click [Get your location]")}
            
        }
    }) { innerPadding ->
    Box(Modifier.padding(innerPadding)) {

        Column(
            modifier = Modifier.fillMaxWidth(),
            verticalArrangement = Arrangement.SpaceEvenly,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Your location: ${currentLocation.latitude}/${currentLocation.longitude}")
            if (currentLocation.latitude != 0.toDouble() && currentLocation.longitude != 0.toDouble()) {
                Text(
                    text = "Readable location: $currentLocation"
                )
                location = ""
                readable = getReadableLocation(currentLocation.latitude, currentLocation.longitude, context)
                glocation = currentLocation
            }
    //////Here is where the permissions are used to call for the system permissions pop up.
            Button(onClick = {
                if (permissions.all {
                        ContextCompat.checkSelfPermission(
                            context,
                            it
                        ) == PackageManager.PERMISSION_GRANTED
                    }) {
                    //Get Locations
                    startLocationUpdates()
                } else {
                    launchMultiplePermissions.launch(permissions)
                }
                =
            }) {
                Text(text = "Get your location")
            }
        }
    }
}

}

Maybe you can read this post for better explanation. In there the example is directed toward Pictures instead of GPS location.