In the manifest file I added permissions coarse and fine, and when I run on device with Android 6, nothing happens! I try everything but no way to get location updates…
What am I doing wrong?
public class MainActivity extends AppCompatActivity implements LocationListener { LocationManager locationManager; String provider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); provider = locationManager.getBestProvider(new Criteria(), false); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } Location location = locationManager.getLastKnownLocation(provider); if (location != null) { Log.i("Location Info", "Location achieved!"); } else { Log.i("Location Info", "No location :("); } } @Override protected void onResume() { super.onResume(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } locationManager.requestLocationUpdates(provider, 400, 1, this); } @Override protected void onPause() { super.onPause(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } locationManager.removeUpdates(this); } @Override public void onLocationChanged(Location location) { Double lat = location.getLatitude(); Double lng = location.getLongitude(); Log.i("Location info: Lat", lat.toString()); Log.i("Location info: Lng", lng.toString()); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } public void getLocation(View view) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } Location location = locationManager.getLastKnownLocation(provider); onLocationChanged(location); } }
Advertisement
Answer
You need to actually request the Location permission at runtime (notice the comments in your code stating this).
Updated with Kotlin and background location for API 31 (Android 12):
Starting with API 30 background location must be requested separately.
This example is using targetSdk 31
and compileSdk 31
.
Note that it’s possible to bundle the background location request along with the main location request on API 29, however to do that you would need to maintain three separate code paths.
It’s easier to just break it out to separate requests for 29 and above.
Be sure to include the latest location services in the app level gradle (18.0.0 at the time of writing):
implementation "com.google.android.gms:play-services-location:18.0.0"
Include the location permissions in the manifest:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
This is a simplified example that does handle most cases, but in a simplified way. In the case where a user chooses “Don’t ask again”, on the next app launch it will open up the settings for the user to manually enable the permission.
Full activity code:
import android.Manifest import android.app.AlertDialog import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Looper import android.provider.Settings import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.google.android.gms.location.* class MainActivity : AppCompatActivity() { private var fusedLocationProvider: FusedLocationProviderClient? = null private val locationRequest: LocationRequest = LocationRequest.create().apply { interval = 30 fastestInterval = 10 priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY maxWaitTime = 60 } private var locationCallback: LocationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult) { val locationList = locationResult.locations if (locationList.isNotEmpty()) { //The last location in the list is the newest val location = locationList.last() Toast.makeText( this@MainActivity, "Got Location: " + location.toString(), Toast.LENGTH_LONG ) .show() } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) fusedLocationProvider = LocationServices.getFusedLocationProviderClient(this) checkLocationPermission() } override fun onResume() { super.onResume() if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) } } override fun onPause() { super.onPause() if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.removeLocationUpdates(locationCallback) } } private fun checkLocationPermission() { if (ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) ) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. AlertDialog.Builder(this) .setTitle("Location Permission Needed") .setMessage("This app needs the Location permission, please accept to use location functionality") .setPositiveButton( "OK" ) { _, _ -> //Prompt the user once explanation has been shown requestLocationPermission() } .create() .show() } else { // No explanation needed, we can request the permission. requestLocationPermission() } } else { checkBackgroundLocation() } } private fun checkBackgroundLocation() { if (ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_BACKGROUND_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { requestBackgroundLocationPermission() } } private fun requestLocationPermission() { ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, ), MY_PERMISSIONS_REQUEST_LOCATION ) } private fun requestBackgroundLocationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_BACKGROUND_LOCATION ), MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION ) } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), MY_PERMISSIONS_REQUEST_LOCATION ) } } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { when (requestCode) { MY_PERMISSIONS_REQUEST_LOCATION -> { // If request is cancelled, the result arrays are empty. if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // location-related task you need to do. if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) // Now check background location checkBackgroundLocation() } } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show() // Check if we are in a state where the user has denied the permission and // selected Don't ask again if (!ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) ) { startActivity( Intent( Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", this.packageName, null), ), ) } } return } MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION -> { // If request is cancelled, the result arrays are empty. if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // location-related task you need to do. if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) Toast.makeText( this, "Granted Background Location Permission", Toast.LENGTH_LONG ).show() } } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show() } return } } } companion object { private const val MY_PERMISSIONS_REQUEST_LOCATION = 99 private const val MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION = 66 } }
On Android 10 (API 29) it will give the user the choice to grant background location after the initial location request:
On Android 12 (API 31) it will do the same, but the interface is different:
Original Answer in Java:
Here is tested and working code to request the Location permission.
Put this code in the Activity:
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99; public boolean checkLocationPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. new AlertDialog.Builder(this) .setTitle(R.string.title_location_permission) .setMessage(R.string.text_location_permission) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //Prompt the user once explanation has been shown ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } }) .create() .show(); } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } return false; } else { return true; } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_LOCATION: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // location-related task you need to do. if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { //Request location updates: locationManager.requestLocationUpdates(provider, 400, 1, this); } } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } } }
Then call the checkLocationPermission()
method in onCreate()
:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //......... checkLocationPermission(); }
You can then use onResume()
and onPause()
exactly as it is in the question.
Here is a condensed version that is a bit more clean:
@Override protected void onResume() { super.onResume(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager.requestLocationUpdates(provider, 400, 1, this); } } @Override protected void onPause() { super.onPause(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager.removeUpdates(this); } }