I am new to Android and in my current project I am trying to retrieve location using GPS. The code for obtaining the location is in a separate non-activity class, because the fragment where I display the coordinates is crammed.
I have tried to use the guidelines from developer.android.com but I can't get any permission prompt, and when I press the button in the fragment, I only get the default 0-values for latitude and longitude.
I have provided the permissions in the manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
The GPS locator class:
public class LocationProvider implements ActivityCompat.OnRequestPermissionsResultCallback {
private static final int PERMISSION_REQUEST_LOCATION = 1;
private Activity activity;
Location gps_loc;
Location final_loc;
double longitude;
double latitude;
private LocationManager locationManager;
public LocationProvider(Activity activity) {
this.activity =activity;
locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_LOCATION) {
// Request for permission.
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLocation();
} else {
requestLocationPermission();
}
}
}
private void getLocation() {
// Check if the permission has been granted
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
gps_loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (gps_loc != null) {
Log.v("Loc_provider",gps_loc.toString());
final_loc = gps_loc;
latitude = final_loc.getLatitude();
longitude = final_loc.getLongitude();
}
} else {
requestLocationPermission();
}
}
private void requestLocationPermission() {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_LOCATION);
}
public String getCoordinates() {
return latitude + " "+ longitude;
}
}
The code in the fragment:
FloatingActionButton fab=view.findViewById(R.id.floatingActionButton);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
locProvider=new LocationProvider(requireActivity());
gpsCoordinates.setText(locProvider.getCoordinates());
}
});
Tips and solutions for fixing the code are most welcome.
UPDATE 1:
I moved the code in the fragment instead, so that it looks like below:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!checkIfAlreadyhavePermission()) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
} else {
gps_loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
gpsCoordinates.setText(getCoordinates());
}
}
});
private String getCoordinates() {
if (gps_loc != null) {
Log.v("Loc_provider", gps_loc.toString());
final_loc = gps_loc;
latitude = gps_loc.getLatitude();
longitude = gps_loc.getLongitude();
}
return latitude + " " + longitude;
}
private boolean checkIfAlreadyhavePermission() {
int result = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Log.v("Grant_Results", String.valueOf(grantResults[0]));
Toast.makeText(getActivity(), "permission granted", Toast.LENGTH_LONG).show();
gpsCoordinates.setText(getCoordinates());
} else {
Toast.makeText(getActivity(), "permission denied", Toast.LENGTH_LONG).show();
}
break;
}
}
}
I now get the permission prompt, but the location still doesn't update (I get 0).
Please note:
Saving an Activity object is not recommended this may cause memory leaks. Activity may be destroyed and recreated (for example when screen orientation changes). Holding a reference to the old activity will cause you problems.
Implementing the ActivityCompat.OnRequestPermissionsResultCallback interface does nothing. Your method will never be called. You will have to call it explicitly from the activity.
You have not requested permission, so your permission prompt will never be shown and the default value of double that is 0 will get returned. You need to call your getLocation() method so that the control falls on the else block and your permission prompt is shown
I recommend you handle permission in the activity. Have the activity get the coordinates for the location. You can have the activity implement an interface, say LocationFetcher, with a method getCoordinates(). You can then call this in the fragment like so:
LocationFetcher locationFetcher = (LocationFetcher) activity;
gpsCoordinates.setText(locationFetcher.getCoordinates());
Fixed by implementing LocationListener in Fragment and then adding
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 400, 1, this);
in onRequestPermissionsResult().
Related
I am working on an android app that needs user location, every time user logins into the app.
I have written code to get user location and works fine, but the problem is if the user denies permission twice it didn't ask again, here is my code:
public class MainActivity extends AppCompatActivity {
String myLocation = "";
private LocationRequest locationRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(2000);
getCurrentLocation();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (isGPSEnabled()) {
getCurrentLocation();
} else {
turnOnGPS();
}
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2) {
if (resultCode == Activity.RESULT_OK) {
getCurrentLocation();
}
}
}
private void getCurrentLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (isGPSEnabled()) {
LocationServices.getFusedLocationProviderClient(MainActivity.this)
.requestLocationUpdates(locationRequest, new LocationCallback() {
#Override
public void onLocationResult(#NonNull LocationResult locationResult) {
super.onLocationResult(locationResult);
LocationServices.getFusedLocationProviderClient(MainActivity.this)
.removeLocationUpdates(this);
if (locationResult != null && locationResult.getLocations().size() > 0) {
int index = locationResult.getLocations().size() - 1;
double latitude = locationResult.getLocations().get(index).getLatitude();
double longitude = locationResult.getLocations().get(index).getLongitude();
myLocation = "Latitude: " + latitude + " Longitude: " + longitude;
Toast.makeText(getApplicationContext(), myLocation, Toast.LENGTH_LONG).show();
}
}
}, Looper.getMainLooper());
} else {
turnOnGPS();
}
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
}
private void turnOnGPS() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
Task<LocationSettingsResponse> result = LocationServices.getSettingsClient(getApplicationContext())
.checkLocationSettings(builder.build());
result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
#Override
public void onComplete(#NonNull Task<LocationSettingsResponse> task) {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
Toast.makeText(MainActivity.this, "GPS is already tured on", Toast.LENGTH_SHORT).show();
} catch (ApiException e) {
switch (e.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException resolvableApiException = (ResolvableApiException) e;
resolvableApiException.startResolutionForResult(MainActivity.this, 2);
} catch (IntentSender.SendIntentException ex) {
ex.printStackTrace();
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
//Device does not have location
break;
}
}
}
});
}
private boolean isGPSEnabled() {
LocationManager locationManager = null;
boolean isEnabled = false;
if (locationManager == null) {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
isEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
return isEnabled;
}
}
As, the user's location is mandatory for the working of app. Now, I want the app to:
1- ask for permission on activity start, if the permission is not granted or denied previously.
2- if permission is granted then proceed further else close the activity.
So, how can I achieve this.
Thanks
You can check whether the user has given permission or not using checkSelfPermission and if not then you ask for permission again else process with program flow.
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED){
doStuff()
} else {
requestStoragePermission()
}
but the problem is if the user denies permission twice it didn't ask
again,
Yes, you cannot ask again once the user denies the permission with "Don't ask again" checked. This checkbox is normally checked by default on the second permission request. Beware that on api 11, there is no checkbox and the denial is automatic auto-denial auto-reset.
The way is that, you don't assume something about it, just put logic for handling it. If denied, you can only inform the user about the required permission. The official doc says: ref
If the ContextCompat.checkSelfPermission() method returns
PERMISSION_DENIED, call shouldShowRequestPermissionRationale(). If
this method returns true, show an educational UI to the user. In this
UI, describe why the feature, which the user wants to enable, needs a
particular permission.
info
I am facing a memory leak problem during GPS location implementation. I have used basic implementation process of FusedLocationProvider to get last location.
But according to the backtrace, it is showing memory leak due to this implementation.
Is any one face same type of memory leak issue while implementing FusedLocationProvider API? And what should I follow to avoid memory leak here?
I am sharing my dumpstate log, memory trace log, and the code snippet for better understanding of the problem.
Here is the log link:
https://drive.google.com/drive/folders/1bzeACMj6erp2up9pgmueawixi8JVhICw?usp=sharing
Any kind of suggestion would be helpful.
Tested the issue on below device:
RAM: 2GB
Software Version: T295XXU4BUD3
Samsung
Here is the Code Snippet:
build.gradle
implementation 'com.google.android.gms:play-services-location:17.0.0'
Android Manifest
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Initialization
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest locationRequest;
private LocationCallback locationCallback;
private boolean isGPS = false;
private boolean skipGPS;
private static final long UPDATE_INTERVAL = 5000, FASTEST_INTERVAL = 3000;
onCreate
skipGPS = false;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
new GpsUtils(HouseholdActivity.this).turnGPSOn(new GpsUtils.onGpsListener() {
#Override
public void gpsStatus(boolean isGPSEnable) {
// turn on GPS
isGPS = isGPSEnable;
}
});
//prepareGpsAccess(); //causing memory leak..
}
Method Implementation:
public void getLocation() {
if (ActivityCompat.checkSelfPermission(HouseholdActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(HouseholdActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(HouseholdActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
AppConstants.LOCATION_REQUEST);
} else {
if (mFusedLocationClient != null) {
mFusedLocationClient.getLastLocation().addOnSuccessListener(HouseholdActivity.this, location -> {
if (location != null) {
Log.e(TAG, "Location: " + location.getLatitude());
Log.e(TAG, "Location: " + location.getLongitude());
} else {
Log.e(TAG, "Location: callback triggered...");
}
});
}
}
}
#SuppressLint("MissingPermission")
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.e(TAG, "Permission missing... result");
switch (requestCode) {
case 1000: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.getLastLocation().addOnSuccessListener(HouseholdActivity.this, location -> {
if (location != null) {
household.setLat(location.getLatitude());
household.setLon(location.getLongitude());
} else {
//mFusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
}
});
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
finish();
}
break;
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == AppConstants.GPS_REQUEST) {
isGPS = true; // flag maintain before get location
}
}
}
Google has recently resolved this memory leak issue in their latest play-services-location:20.0.0 release. Release Note.
So update your lib version to 20.0.0 and it will solve the problem, it did for me.
To know more about the history of this memory leak, check this and this.
I want to get location data but first I have to get permission from the user. so i want to pause the app while the user grants or denies the permission
this is how I tried to do it:
MainActivity:
public class MainActivity extends AppCompatActivity {
private static final long LOCATION_REFRESH_TIME = 15000;
private static final float LOCATION_REFRESH_DISTANCE = 500;
public static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
public Boolean locationPermissionResults=null;
double longitudeNetwork;
double latitudeNetwork;
TextView locationText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationText=findViewById(R.id.locationtext);
//getting the permission if its not granted
if(ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
locationText.setText("give permission1");
ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
//resume if granted
}
else{
locationManager();
}
}
private final LocationListener mLocationListenerNetwork = new LocationListener() {
#Override
public void onLocationChanged(final Location location) {
latitudeNetwork = location.getLatitude();
longitudeNetwork = location.getLongitude();
locationText.setText(Double.toString(longitudeNetwork) + "//" + Double.toString(latitudeNetwork));
}
};
#SuppressLint("MissingPermission")
public void locationManager(){
LocationManager locationManagerNetwork = (LocationManager) getSystemService(LOCATION_SERVICE);
locationManagerNetwork.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_REFRESH_TIME,
LOCATION_REFRESH_DISTANCE, mLocationListenerNetwork);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case LOCATION_PERMISSION_REQUEST_CODE: {
if (permissions[0].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
locationManager();
} else{
locationText.setText("give permission2");
}
}
}
}
}
}
I have a problem with getting permission and handling the result. when the user denies the or grants the permission request the locationText shows give permission1 which means the moved over the first else in onCreate method and also the else in onRequestPermissionsResult.
why is this happening?
NOTE: in onRequestPermissionsResult I'm only checking for one of the permissions asked in onCreate because if one of them is granted the other one is granted too. can this be the problem?
You can't pause an app. Nor can you wait on the main thread. You need to reorganize your Activity so you don't need to do that- create an empty or waiting state that displays until that data is available.
This question already has answers here:
Location is empty at the start
(5 answers)
Closed 3 years ago.
Inspite of my best effort, I am unable to get my location correct. This is my main.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
//new SecondFragment();
//TabLayout tabs = findViewById(R.id.tabs);
//tabs.setupWithViewPager(viewPager);
FloatingActionButton fab = findViewById(R.id.fab);
FontDrawable drawable = new FontDrawable(this, R.string.fa_plus_solid, true, false);
drawable.setTextColor(ContextCompat.getColor(this, android.R.color.white));
fab.setImageDrawable(drawable);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
//Check permission
if (ContextCompat.checkSelfPermission(getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getApplicationContext(),
android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION}, 101);
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
latlang.Lat =location.getLatitude();
latlang.Lang =location.getLongitude();
}
}
});
}
}
}
the latlang is defined in another file as:
public class latlang {
public static double Lat;
public static double Lang;
}
If I hardcode the value here in latlang, everything is fine. But, of course I want the value of last known location.
Kindly help.
The problem is that you try to get the location before the permission is granted.
After calling requestPermissions() you immediately try to get location while the permission dialog is being displayed which means that the code that gets the location is being executed while you are seeing the permission dialog. This is why there is onRequestPermissionsResult function in activity that reports only after the user is done with permissions dialog.
You will need to get the location in onRequestPermissionsResult().
Second problem in your code is that you are only getting location when the permission is not granted. Your code does not handle the case when permission is already granted.
Here is how you would solve this:
#Override
protected void onCreate(Bundle savedInstanceState) {
if (ContextCompat.checkSelfPermission(getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getApplicationContext(),
android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[] {
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION
}, 101);
} else {
fetchLocation();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case 101:
{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 &&
(grantResults[0] == PackageManager.PERMISSION_GRANTED ||
grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
// permission was granted
fetchLocation()
} else {
Show some error
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
public void fetchLocation() {
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener < Location > () {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
latlang.Lat = location.getLatitude();
latlang.Lang = location.getLongitude();
}
}
});
}
Basically, Create a separate function that gets the location. You will call this function from 2 places. First is in onCreate when the permission is granted, and second in onPermissionResult. Don't forget to handle permission errors.
I'm trying to get the GPS coordinates to display when I click a button in my activity layout. The following is the method that gets called when I click the button:
public void getLocation(View view) {
TextView tv = (TextView) findViewById(R.id.gps_coord_view);
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
tv.setText("Latitude: " + loc.getLatitude() + "\nLongitude: " + loc.getLongitude());
}
I'm getting an error that says
Call requires permission which may be rejected by user. Code should explicitly check to see if permission is available.
I have already granted these permissions in my AndroidManifest. The error is taken care of and the app compiles when I add the following before calling lm.getLastKnownLocation:
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
However, the app crashes when I press the button that calls getLocation when it's clicked. What is going on? Is there better/simpler way to grab the GPS coordinates of the device?
With Android API level (23), we are required to check for permissions.
https://developer.android.com/training/permissions/requesting.html
I had your same problem, but the following worked for me and I am able to retrieve Location data successfully:
(1) Ensure you have your permissions listed in the Manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
(2) Ensure you request permissions from the user:
if ( ContextCompat.checkSelfPermission( this, android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions( this, new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION },
LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION );
}
(3) Ensure you use ContextCompat as this has compatibility with older API levels.
(4) In your location service, or class that initializes your LocationManager and gets the last known location, we need to check the permissions:
if ( Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return ;
}
(5) This approach only worked for me after I included #TargetApi(23) at the top of my initLocationService method.
(6) I also added this to my gradle build:
compile 'com.android.support:support-v4:23.0.1'
Here is my LocationService for reference:
public class LocationService implements LocationListener {
//The minimum distance to change updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters
//The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 0;//1000 * 60 * 1; // 1 minute
private final static boolean forceNetwork = false;
private static LocationService instance = null;
private LocationManager locationManager;
public Location location;
public double longitude;
public double latitude;
/**
* Singleton implementation
* #return
*/
public static LocationService getLocationManager(Context context) {
if (instance == null) {
instance = new LocationService(context);
}
return instance;
}
/**
* Local constructor
*/
private LocationService( Context context ) {
initLocationService(context);
LogService.log("LocationService created");
}
/**
* Sets up location service after permissions is granted
*/
#TargetApi(23)
private void initLocationService(Context context) {
if ( Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return ;
}
try {
this.longitude = 0.0;
this.latitude = 0.0;
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
// Get GPS and network status
this.isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
this.isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (forceNetwork) isGPSEnabled = false;
if (!isNetworkEnabled && !isGPSEnabled) {
// cannot get location
this.locationServiceAvailable = false;
}
//else
{
this.locationServiceAvailable = true;
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
updateCoordinates();
}
}//end if
if (isGPSEnabled) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
updateCoordinates();
}
}
}
} catch (Exception ex) {
LogService.log( "Error creating location service: " + ex.getMessage() );
}
}
#Override
public void onLocationChanged(Location location) {
// do stuff here with location object
}
}
I tested with an Android Lollipop device so far only.
Hope this works for you.
SIMPLE SOLUTION
I wanted to support apps pre api 23 and instead of using checkSelfPermission I used a try / catch
try {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException e) {
dialogGPS(this.getContext()); // lets the user know there is a problem with the gps
}
The last part of the error message you quoted states:
...with ("checkPermission") or explicitly handle a potential "SecurityException"
A much quicker/simpler way of checking if you have permissions is to surround your code with try { ... } catch (SecurityException e) { [insert error handling code here] }. If you have permissions, the 'try' part will execute, if you don't, the 'catch' part will.
Use my custome class to check or request permisson
public class Permissons {
//Request Permisson
public static void Request_STORAGE(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},code);
}
public static void Request_CAMERA(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.CAMERA},code);
}
public static void Request_FINE_LOCATION(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.ACCESS_FINE_LOCATION},code);
}
public static void Request_READ_SMS(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.READ_SMS},code);
}
public static void Request_READ_CONTACTS(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.READ_CONTACTS},code);
}
public static void Request_READ_CALENDAR(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.READ_CALENDAR},code);
}
public static void Request_RECORD_AUDIO(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.RECORD_AUDIO},code);
}
//Check Permisson
public static boolean Check_STORAGE(Activity act)
{
int result = ContextCompat.checkSelfPermission(act,android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_CAMERA(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.CAMERA);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_FINE_LOCATION(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_READ_SMS(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_SMS);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_READ_CONTACTS(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CONTACTS);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_READ_CALENDAR(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CALENDAR);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_RECORD_AUDIO(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.RECORD_AUDIO);
return result == PackageManager.PERMISSION_GRANTED;
}
}
Example
if(!Permissons.Check_STORAGE(MainActivity.this))
{
//if not permisson granted so request permisson with request code
Permissons.Request_STORAGE(MainActivity.this,22);
}
if you are working on dynamic permissions and any permission like ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION giving error "cannot resolve method PERMISSION_NAME" in this case write you code with permission name and then rebuild your project this will regenerate the manifest(Manifest.permission) file.
If you simply want to check for permissions (rather than request for permissions), I wrote a simple extension like so:
fun BaseActivity.checkPermission(permissionName: String): Boolean {
return if (Build.VERSION.SDK_INT >= 23) {
val granted =
ContextCompat.checkSelfPermission(this, permissionName)
granted == PackageManager.PERMISSION_GRANTED
} else {
val granted =
PermissionChecker.checkSelfPermission(this, permissionName)
granted == PermissionChecker.PERMISSION_GRANTED
}
}
Now, if I want to check for a permission I can simply pass in a permission like so:
checkPermission(Manifest.permission.READ_CONTACTS)