getLastKnownLocation first time return null issue - java

I'm developing a simple android location app but I have a little bit trauble.(Also sorry for my bad english.)
I want to get current location with button click, but getLastKnownLocation returns null all of first time.
But also if I first opened google maps and show my current location on map, after that I passed background it then I opened my own app, click the button that works. But I dont want this way, I just want provide location on the my app not with this way.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Object clipboardService = getSystemService(CLIPBOARD_SERVICE);
final ClipboardManager clipboardManager = (ClipboardManager) clipboardService;
tvEnlem = (TextView) findViewById(R.id.textViewEnlem);
tvBoylam = (TextView) findViewById(R.id.textViewBoylam);
retrieveLocationButton = (Button) findViewById(R.id.buttonNeredeyim);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
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(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 101);
// 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;
}
retrieveLocationButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showCurrentLocation();
}
});
}
protected void showCurrentLocation() {
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(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 101);
// 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 = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
String message = String.format(
"Current Location \n Longitude: %1$s \n Latitude: %2$s",
location.getLongitude(), location.getLatitude()
);
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_LONG).show();
this.tvBoylam.setText(String.valueOf(location.getLongitude()));
this.tvEnlem.setText(String.valueOf(location.getLatitude()));
}
else{
Toast.makeText(MainActivity.this,"LOKASYON BİLGİLERİ BOŞ",
Toast.LENGTH_SHORT).show();
}
}
private class MyLocationListener implements LocationListener {
public void onLocationChanged(Location location) {
String message = String.format(
"New Location \n Longitude: %1$s \n Latitude: %2$s",
location.getLongitude(), location.getLatitude()
);
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
}
public void onStatusChanged(String s, int i, Bundle b) {
Toast.makeText(MainActivity.this, "Provider status changed",
Toast.LENGTH_LONG).show();
}
public void onProviderDisabled(String s) {
Toast.makeText(MainActivity.this,
"Provider disabled by the user. GPS turned off",
Toast.LENGTH_LONG).show();
}
public void onProviderEnabled(String s) {
Toast.makeText(MainActivity.this,
"Provider enabled by the user. GPS turned on",
Toast.LENGTH_LONG).show();
}
}
}
How can I get location without null values?

this isn't a bug but simply the Google politics.
The getLastKnowLocation() method return the last location that google service has retrieved.
As Google Documentation says:
The location object may be null in the following situations:
Location is turned off in the device settings. The result could be null even if the last location was previously retrieved because
disabling location also clears the cache.
The device never recorded its location, which could be the case of a new device or a device that has been restored to factory
settings.
Google Play services on the device has restarted, and there is no active Fused Location Provider client that has requested
location after the services restarted.
This is why if you switch from Google Maps to your app, you can get last location.
To get actual position without pass from an app to other, you need to implement a new client and request location updates yourself. For more information, see Receiving Location Updates.
I hope I have clarified your every doubt. Otherwise, do not hesitate to write :)

Related

Android Studio - GoogleAPIClient deprecated fix

I am building a GPS app, but GoogleAPIClient is deprecated and I'm not sure how to fix it. Also when I run the app, I get a sign-in button that doesn't lead to anything, which may be related to this since I know that GoogleSignInClient exists. Also, if you could link me to a more detailed explanation of GoogleApi I would really appreciate it!
public static final String MA = "MainActivity";
private final static int REQUEST_CODE = 100;
private GoogleApiClient gac;
private Location location;
private TextView locationTV;
private TextView distanceTV;
private TextView addressET;
private TextView timeLeftTV;
private String destinationAddress = "";
private TravelManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationTV = (TextView) findViewById(R.id.location_tv);
manager = new TravelManager();
addressET = (EditText) findViewById(R.id.destination_et);
distanceTV = (TextView) findViewById(R.id.distance_tv);
timeLeftTV = (TextView) findViewById(R.id.time_left_tv);
gac = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
}
public void updateTrip(View v) {
String address = addressET.getText().toString();
boolean goodGeoCoding = true;
if (!address.equals(destinationAddress)) {
destinationAddress = address;
Geocoder geocoder = new Geocoder(this);
try {
List<Address> addresses = geocoder.getFromLocationName(destinationAddress, 5);
if (address != null) {
double latitude = addresses.get(0).getLatitude();
double longitude = addresses.get(0).getLongitude();
Location destinationLocation = new Location("destination");
destinationLocation.setLatitude(latitude);
destinationLocation.setLongitude(longitude);
manager.setDestination(destinationLocation);
}
} catch (IOException ioException) {
goodGeoCoding = false;
}
}
FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
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 current = fusedLocationProviderApi.getLastLocation(gac);
if (current != null && goodGeoCoding) {
distanceTV.setText(manager.milesToDestination(current));
timeLeftTV.setText(manager.timeToDestination(current));
}
}
public void displayLocation() {
FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
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 = fusedLocationProviderApi.getLastLocation(gac);
if (location != null) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
locationTV.setText(latitude + ", " + longitude);
Log.w(MA, "latutude = " + latitude + "; longitude = " + longitude);
}else
locationTV.setText("Error locating the device");
}
public void onConnected(Bundle hint) {
Log.w(MA, "connected");
displayLocation();
}
public void onConnectionSuspended(int cause) {
Log.w(MA, "connection suspended");
}
public void onConnectionFailed(ConnectionResult result) {
Log.w(MA, "connection failed");
if (result.hasResolution()){
try {
result.startResolutionForResult(this, REQUEST_CODE);
}catch (IntentSender.SendIntentException sendIntentException) {
Toast.makeText(this,"Google Play services problem, exiting", Toast.LENGTH_LONG).show();
finish();
}
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
gac.connect();
}
}
protected void onStart() {
super.onStart();
if (gac != null)
gac.connect();
}
}
Regarding your concern for reference related to Google API, this API might help you with your GPS app needs.
Location and Context APIs
The location and context APIs harness the sensors and signals of mobile devices to provide awareness of user actions and their environment, enabling delightful and engaging experiences that simplify user interactions, provide assistance, and help users to better understand themselves.
This contains a list of APIs' and Platforms that you can use depending on what you are looking for.
In your case, you may check the following:
Places API
Give your users contextual information about where they are, when they’re there. Access detailed information about 100 million places across a wide range of categories.
Geofencing
Geofencing combines awareness of the user's current location with awareness of the user's proximity to locations that may be of interest.
Fused Location Provider API
Get location data for your app based on combined signals from the device sensors using a battery-efficient API.
Places API
Before you start using the Places API, you need a project with a billing account and the Places API enabled. (Please refer to the link on how to create a project with billing account)
You need to get an API key that will authenticate you request.
For more details regarding this API, you can visit the link provided.
The following place requests are available:
Place Search returns a list of places based on a user's location or search string.
Place Details returns more detailed information about a specific place, including user reviews.
Place Photos provides access to the millions of place-related photos stored in Google's Place database.
Place Autocomplete automatically fills in the name and/or address of a place as users type.
Query Autocomplete provides a query prediction service for text-based geographic searches, returning suggested queries as users type.
Fused Location Provider API
The fused location provider is one of the location APIs in Google Play services. It manages the underlying location technology and provides a simple API so that you can specify requirements at a high level, like high accuracy or low power. It also optimizes the device's use of battery power.
Support for common location scenarios:
Last known location
Includes step-by-step procedures to setup and access fused location provider
Location settings
Location updates
You can explore this reference to learn more:
https://developer.android.com/training/location

Why my app doesn't show location button when I accept the permission request dialog the second time is runned?

I am programming an Android App in Java. The activity holds a Google map and what I want is to have a button location at the top, like is shown in the picture:
I want that when I click the location to point to my current Location and for that I am using the class FusedLocationProviderClient.
When I run the program everything goes fine until i follow these steps sequencially:
1- Run app first time and I deny permissions
2- Run app second time. It request again permissions so I answer ok, but the button doesn't appear.
3- I close the app, and because I said yes last time, to the location permission, the button is on the map and is working.
Here is my code:
private void checkPermissions(int fineLocationPermission) {
if (fineLocationPermission != PackageManager.PERMISSION_GRANTED) { //If we don't have any permissions yet
// TODO: Consider calling
//We have to request permissions and in case the user refuse the permission we show an explanation of why he needs the permission
//The following method returns true in case the user reject the permission
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_CODE);
} else
mLocationPermissionGranted=true;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//If the user accepts the dialog box then we get the last location and show button
mLocationPermissionGranted=true;
} else {
mLocationPermissionGranted=false;
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
}
}
public void onLocationChanged(final Location location) {
String msg = "Updated location: " +
Double.toString(location.getLatitude()) + ", " +
Double.toString(location.getLongitude());
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
final LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
//Show button to locate current position
mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() {
#Override
public boolean onMyLocationButtonClick() {
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
CameraUpdateFactory.newLatLngZoom(latLng,12);
//mMap.setMaxZoomPreference(12);
return false;
}
});
// Add a marker our current position
LatLng CurrentPosition = new LatLng(location.getLatitude(), location.getLongitude());
mMap.addMarker(new MarkerOptions().position(CurrentPosition).title("Here you are!"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(CurrentPosition));
}
#Override
public void onMapReady(GoogleMap googleMap) {
//Create the map
mMap = googleMap;
//Set the type of the map: HYBRID, NORMAL, SATELLITE or TERRAIN. In our case TERRAIN type
mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
//Set the zoom
mMap.setMaxZoomPreference(12);
//Set the markers
MarkerOptions markerOptions= new MarkerOptions();
//Checking permissions with the permissions we have included in the manifiest
checkPermissions(permissionCheckFineLocation);
if (mLocationPermissionGranted) {
try {
mMap.setMyLocationEnabled(true);
//Last location task
Task<Location> locationResult = mFusedLocationClient.getLastLocation();
locationResult.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) {
//Logic to handle location object
onLocationChanged(location);
}
}
});
} catch (SecurityException e) {
Log.e("error", e.getMessage());
}
}
}
I know is a weird question, but I don't know how to express myself.
Any help would be great!
Thank you in advance!
onMapReady isn't called (again) after permission is granted (this happens after onMapReady).
Move the code in onMapReady in the if (mLocationPermissionGranted) clause to a separate method and call it from inside the if as well as from onRequestPermissionsResult if permission was granted.

Permission Requests causes infinite loop in OnResume

In API >= 23, we are required to ask users for permission at run-time. But for some reason, the permissions are causing onResume to be called infinitely. What causes this?
#Override
protected void onResume() {
super.onResume();
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ANYPERMISSION},1);
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
}
When you show dialog of permission question, Acitvity goes to onPause, and when dialog hides, it goes to onResume. You have to change place of asking of permission.
A small piece of code for permissions to complete previous response :)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 23)
ensurePermissions(
Manifest.permission.GET_ACCOUNTS,
Manifest.permission.WRITE_EXTERNAL_STORAGE
);
}
and:
#TargetApi(23)
private void ensurePermissions(String... permissions) {
boolean request = false;
for (String permission : permissions)
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
request = true;
break;
}
if (request) {
requestPermissions(permissions, REQUEST_CODE_PERMISSION);
}
}
first, your app needs to check whether you have been granted a particular permission before asking runtime permission.
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
} else {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE);
}

Call requires permission which may be rejected by the user when trying to get the location

I looked on other questions, but was unable to find the anwer.
Anyway, I am trying to get the location of the device, and it just wont work. I am using Android 5.0 (API 21).
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);
Location location = locationManager.getLastKnownLocation(provider);
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
The error is when in .getLastKnowLocation(). It says I should check for permissions, but I already added the permissions to the Android manifest.
uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
When I click the red light bulb, there is 'Add permission check' option, and when I click it, it ads this:
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;
}
But when I run it, it always does the return; , like I don't have the permissions.
You need to enable run time permissions,
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION},1200);
If you only want your app to work up to API level 21, you can set targetSdkVersion 21 in your module level build.gradle file, which will make the error you're facing go away.
If/when you want to start targeting API level 23 or higher, you'll need to request permissions at runtime in addition to having them declared in your manifest.

When to request permission at runtime for Android Marshmallow 6.0?

I am testing my app on Marshmallow 6.0 and it's getting force closed for the android.permission.READ_EXTERNAL_STORAGE, even if it is defined in the Manifest already. Somewhere I have read that if I request permission at runtime then it would not force close your application. I have read this android document also, which is for requesting runtime permission.
So, I came to know that we can request a permission like below which is mentioned in the android document.
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation 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.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
The above code has a callback method onRequestPermissionsResult which gets the result.
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
}
}
My question is where to exactly request the permission to user? Should we use the requesting permission at start of the app or should we do it as when the permission is required?
This is worked for me !!!
In Your Splash Activity of your application do the following,
1) Declare an int variable for request code,
private static final int REQUEST_CODE_PERMISSION = 2;
2) Declare a string array with the number of permissions you need,
String[] mPermission = {Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
3) Next Check the condition for runtime permission on your onCreate method,
try {
if (ActivityCompat.checkSelfPermission(this, mPermission[0])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[1])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[2])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[3])
!= MockPackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
mPermission, REQUEST_CODE_PERMISSION);
// If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
}
} catch (Exception e) {
e.printStackTrace();
}
4) Now Declare onRequestPermissionsResult method to check the request code,
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.e("Req Code", "" + requestCode);
if (requestCode == REQUEST_CODE_PERMISSION) {
if (grantResults.length == 4 &&
grantResults[0] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[1] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[2] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[3] == MockPackageManager.PERMISSION_GRANTED) {
// Success Stuff here
}
}
}
Do like this
private static final int REQUEST_ACCESS_FINE_LOCATION = 111;
In your onCreate
boolean hasPermissionLocation = (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!hasPermissionLocation) {
ActivityCompat.requestPermissions(ThisActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_ACCESS_FINE_LOCATION);
}
then check result
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode)
{
case REQUEST_ACCESS_FINE_LOCATION: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(ThisActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();
//reload my activity with permission granted
finish();
startActivity(getIntent());
} else
{
Toast.makeText(ThisActivity.this, "The app was not allowed to get your location. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
}
}
}
}
In general, request needed permissions it as soon as you need them. This way you can inform the user why you need the permission and handle permission denies much easier.
Think of scenarios where the user revokes the permission while your app runs: If you request it at startup and never check it later this could lead to unexpected behaviour or exceptions.
In my opinion, there is no one correct answer to your question. I strongly suggest you to look at this official permissions patterns page.
Couple of things suggested by Google :
"Your permissions strategy depends on the clarity and importance of the permission type you are requesting. These patterns offer different ways of introducing permissions to the user."
"Critical permissions should be requested up-front. Secondary permissions may be requested in-context."
"Permissions that are less clear should provide education about what the permission involves, whether done up-front or in context."
This illustration might give you better understanding.
Maybe the most crucial thing here is that whether you ask the permission up-front or in the context, you should always keep in mind that these permissions can be revoked anytime by the user (e.g. your app is still running, in background).
You should make sure that your app doesn't crash just because you asked the permission on the very beginning of the app and assumed that user didn't change his/her preference about that permission.
For requesting runtime permission i use GitHub Library
Add library in Build.gradle file
dependencies {
compile 'gun0912.ted:tedpermission:1.0.3'
}
Create Activity and add PermissionListener
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PermissionListener permissionlistener = new PermissionListener() {
#Override
public void onPermissionGranted() {
Toast.makeText(RationaleDenyActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
//Camera Intent and access Location logic here
}
#Override
public void onPermissionDenied(ArrayList<String> deniedPermissions) {
Toast.makeText(RationaleDenyActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
}
};
new TedPermission(this)
.setPermissionListener(permissionlistener)
.setRationaleTitle(R.string.rationale_title)
.setRationaleMessage(R.string.rationale_message) // "we need permission for access camera and find your location"
.setDeniedTitle("Permission denied")
.setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
.setGotoSettingButtonText("Settings")
.setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.check();
}
}
string.xml
<resources>
<string name="rationale_title">Permission required</string>
<string name="rationale_message">we need permission for read <b>camera</b> and find your <b>location</b></string>
</resources>
Android Easy Runtime Permissions with Dexter:
1. Dexter Permissions Library
To get started with Dexter, add the dependency in your build.gradle
dependencies {
// Dexter runtime permissions
implementation 'com.karumi:dexter:4.2.0'
}
1.1 Requesting Single Permission
To request a single permission, you can use withPermission() method by passing the required permission. You also need a PermissionListener callback to receive the state of the permission.
> onPermissionGranted() will be called once the permission is granted.
> onPermissionDenied() will be called when the permission is denied. Here you can check whether the permission is permanently denied by using response.isPermanentlyDenied() condition.
The below code requests CAMERA permission.
Dexter.withActivity(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener() {
#Override
public void onPermissionGranted(PermissionGrantedResponse response) {
// permission is granted, open the camera
}
#Override
public void onPermissionDenied(PermissionDeniedResponse response) {
// check for permanent denial of permission
if (response.isPermanentlyDenied()) {
// navigate user to app settings
}
}
#Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
token.continuePermissionRequest();
}
}).check();
1.2 Requesting Multiple Permissions
To request multiple permissions at the same time, you can use withPermissions() method. Below code requests STORAGE and LOCATION permissions.
Dexter.withActivity(this)
.withPermissions(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
// check if all permissions are granted
if (report.areAllPermissionsGranted()) {
// do you work now
}
// check for permanent denial of any permission
if (report.isAnyPermissionPermanentlyDenied()) {
// permission is denied permenantly, navigate user to app settings
}
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
token.continuePermissionRequest();
}
})
.onSameThread()
.check();
A good explanation and HowTo can be found here:
https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
I wrote this code to check and request the permissions at runtime in a BaseActivity.class which is parent of every other Activity.class I implemented:
public static final int PERMISSION_REQUEST = 42;
public static final int MULTIPLE_PERMISSION_REQUEST = 43;
//Marshmallow Permission Model
public boolean requestPermission(String permission /* Manifest.permission...*/) {
if (ContextCompat.checkSelfPermission(this,
permission) != PackageManager.PERMISSION_GRANTED) {
if (Utils.hasMarshmallow())
ActivityCompat.requestPermissions(this,
new String[]{permission}, PERMISSION_REQUEST
);
else {
requestPermissions(new String[]{permission},
PERMISSION_REQUEST);
}
return false;
} else {
return true;
}
}
public boolean requestPermission(String... permissions) {
final List<String> permissionsList = new ArrayList<String>();
for (String perm : permissions) {
addPermission(permissionsList, perm);
}
if (permissionsList.size() > 0) {
if (Utils.hasMarshmallow())
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
MULTIPLE_PERMISSION_REQUEST);
else
ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
MULTIPLE_PERMISSION_REQUEST);
return false;
} else
return true;
}
private boolean addPermission(List<String> permissionsList, String permission) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
// Check for Rationale Option
if (Utils.hasMarshmallow())
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST:
case MULTIPLE_PERMISSION_REQUEST: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
Simply example call:
activity.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);
Return result will let you know if the permission is already granted or not.
calling this function we can allow user to open dialog for asking permission to allow camera and record Audio.
if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
ActivityCompat.shouldShowRequestPermissionRationale (this,
Manifest.permission.RECORD_AUDIO) ) {
Toast.makeText (this,
R.string.permissions_needed,
Toast.LENGTH_LONG).show ();
} else {
ActivityCompat.requestPermissions (
this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
CAMERA_MIC_PERMISSION_REQUEST_CODE);
}
https://material.io/guidelines/patterns/permissions.html
This link will give you different type of scenario where permissions can be asked. Choose accordingly to your needs.
I like short code. I use RxPermission for permissions.
RxPermission is best library, which makes permission code unexpected just 1 line.
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE) // ask single or multiple permission once
.subscribe(granted -> {
if (granted) {
// All requested permissions are granted
} else {
// At least one permission is denied
}
});
add in your build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
}
Isn't this easy?
if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
ActivityCompat.shouldShowRequestPermissionRationale (this,
Manifest.permission.RECORD_AUDIO) ) {
Toast.makeText (this,
R.string.permissions_needed,
Toast.LENGTH_LONG).show ();
} else {
ActivityCompat.requestPermissions (
this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
CAMERA_MIC_PERMISSION_REQUEST_CODE);
}

Categories

Resources