I am trying to get the user's location in my Activity using Google Location API. I have a button, on which if user taps, the location of the user should be retrieved and sent to the app backend.
As per Google's documentation, the
LocationServices.FusedLocationApi
.getLastLocation(apiClient)
method has to be called in onConnected method. However, the method throws error if I am not checking for permission granted by the user.
My problem is I am asking for permission in onClick method of my button.
I tried putting
LocationServices.FusedLocationApi
.getLastLocation(apiClient)
inside the onClick method but it returns a null object.
Is there a proper way to ask location permission from user on tap of a button and not in onCreate method of the activity and still be able to get the location of the user?
I assume you are calling :
mGoogleApiClient.connect();
in onStart(). Which calls the onConnected() method when the activity starts. You can call it on Button Click after asking run-time permission for Location. Then you will be able to getLastLocation() in onConnected() and you won't face permission error.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)){
mGoogleApiClient.connect();
}
else{
// ask run-time permission
}
}
}
});
Hope this helps.
Related
I am trying to request STORAGE Permission from the user at runtime after clicking a certain button. But somehow, this code (which is contained within a fragment's class) is not working at all no matter what I try.
binding.button.setOnClickListener {
requestPermissions(this.requireActivity(), "android.permission.WRITE_EXTERNAL_STORAGE", 392)
}
This piece of code isn't working either for both write and read permissions :
binding.button.setOnClickListener {
ActivityCompat.requestPermissions(this.requireActivity(), "android.permission.WRITE_EXTERNAL_STORAGE", 392)
}
No dialogue appears no matter what.
NOTE: I am testing on a physical device running on API 29.
NOTE2: I added the permission both WRITE and READ permissions to the manifest.
NOTE3: Performing any IO task crashes my app.
I looked up all over the internet but I still don't understand why it's not working.
As for your way for checking the permissions if it's inside a fragment maybe it's not correct , since these methods are deprecated and you may use another way which is the recommended one
Documentation for how to request permissions|android developers
which is the right way which goes as this:
Step 1 -You put this code as global in fragment/activity:
private final ActivityResultLauncher<String> requestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) doSomething()
else
Toast.makeText(getContext(), "Can't continue without the required permissions", Toast.LENGTH_LONG).show();
});
Step 2- Then when you need to request for a permission you call launch on the object you declared as global , which is to be called in the OnCreate() function of the Fragment / Activity .So if you want to ask these permissions at the creation of the fragment / Activity then just place this code in OnCreate() or if are using a button to check permission then set the onClickListener for the same in onCreate() function:
public void getNecessaryPermissionsAnddoSomething() {
if (ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
} else doSomething();
}
In my app I am using location services, and after first install the app asks for Location permission. If the user click OK, permission is granted, if Cancel, then I have another dialog with some info.
Then - if the user has turned off the GPSon his device, a dialog will come up which asks to enable GPS - if Ok is clicked, the device settings are opened and here the user can enable the GPS.
As far as now everything works fine. But I need to restart the activity after the user is back from settings. (So I can load some items according the location).
For this I used onresume():
#Override
protected void onResume() { //restart activity after back from GPS settings
String action = getIntent().getAction();
// Prevent endless loop by adding a unique action, don't restart if action is present
if(action == null || !action.equals("created")) {
Intent intent = new Intent(this, Okoli.class);
startActivity(intent);
finish();
}
// Remove the unique action so the next time onResume is called it will restart
else
getIntent().setAction(null);
super.onResume();
}
I used there a unique action to avoid loop restart, so in oncreate I am setting also getIntent().setAction("created");
Now this is working fine - the activity restarts after the user is back from settings, but it conflicts with Permission dialog which I mentioned as first.
So if I have the onResume function, and the user installs the app, the Location permission dialog comes up, but in this case the user can't click CANCEL, because the dialog is looping forever if he clicks cancel. So it is appearing again and again until he clicks OK.
When I remove the whole onResume section from my code, then the Permission dialog works fine, but I need onresume for restarting activity.
okey, finally I store a value to SharedPreferences - when user doesn't allow the location access, and then I check this value onResume and only restart the activity if the value is not set. Works fine!
Is it possible to provide a custom text for the system dialog which is displayed when the user is asked to grant permission?
No, you can't customize the text of the dialog, but you can provide an explanation before request the permission. Quoting from developer.android.com:
Request Permissions
If your app needs a dangerous permission that was listed in the app
manifest, it must ask the user to grant the permission. Android
provides several methods you can use to request a permission. Calling
these methods brings up a standard Android dialog, which you cannot
customize.
Explain why the app needs permissions
In some circumstances, you might want to help the user understand why
your app needs a permission. For example, if a user launches a
photography app, the user probably won't be surprised that the app
asks for permission to use the camera, but the user might not
understand why the app wants access to the user's location or
contacts. Before you request a permission, you should consider
providing an explanation to the user. Keep in mind that you don't want
to overwhelm the user with explanations; if you provide too many
explanations, the user might find the app frustrating and remove it.
One approach you might use is to provide an explanation only if the
user has already turned down that permission request. If a user keeps
trying to use functionality that requires a permission, but keeps
turning down the permission request, that probably shows that the user
doesn't understand why the app needs the permission to provide that
functionality. In a situation like that, it's probably a good idea to
show an explanation.
To help find situations where the user might need an explanation,
Android provides a utiltity method,
shouldShowRequestPermissionRationale(). This method returns true if
the app has requested this permission previously and the user denied
the request.
We cannot customize request permission dialog but we can provide user a custom explanation that why we are requesting below is the method with custom explanation
private void checkForCameraPermission() {
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
alertBuilder.setCancelable(true);
alertBuilder.setTitle("Camera permission necessary");
alertBuilder.setMessage("FITsociety need camera permission to read barcode.");
alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(BarCodeScannerActivity.this,
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
}
});
AlertDialog alert = alertBuilder.create();
alert.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
// MY_PERMISSIONS_REQUEST_CAMERA is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
setBarCodeScannerView();
}
}
the above method check whether permission is already granted if not then it check if custom explanation is required with this method
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
the documentation for this method is here shouldShowRequestPermissionRationale() this method return true only if user deny to permission dialog or user close the permission from the setting of the application if user did so then show alert dialog with custom explanation and proceed further hope it works
My app needs to access the user's storage in near to every activity. How can I access the storage without making the app ask at every app startup for the permission to access it with the new Android M permission model? (Read and write)
Thanks!
If you do not want to prompt the user "on every app startup to give memory access to be able to do anything", then don't do that. Only call requestPermissions() if checkSelfPermission() returns PERMISSION_DENIED.
#Override
public void onCreate(Bundle icicle) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)==
PackageManager.PERMISSION_GRANTED) {
init();
}
else {
requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
REQUEST_STORAGE);
}
}
(native API Level 23 methods shown; you may want to use ContextCompat andActivityCompat` for backwards compatibility)
Or, only call requestPermissions() if the user does something positive in the UI that needs WRITE_EXTERNAL_STORAGE (e.g., clicks an action bar item) and you do not already have the permission.
I am using Google API V2 in an Android application.
I want to get my current location and add a marker on it.
I am using my friend device. when I run the code, it shows me my-friend's house location. I am really shocked why.
could anyone please help me getting my current location..
Thats because you're first loading the LastKnownLocation, because it's your friends phone it will show your friend last known location (his house).
The code looks fine, I think you have to wait untill it finds the real location.
(make sure you got all permissions, and gps is on)
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<!-- The following two permissions are not required to use
Google Maps Android API v2, but are recommended. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
When you call locationManager.getLastKnownLocation(provider) your are retrieving the last location of the GPS that can be like you say when your friend was at home.
If you want to have the location where you are at, you should call requestSingleUpdate for just one time update or requestLocationUpdates for a continuous update.
An example for the one time update with a button listener:
btnupdate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
locationManager.requestSingleUpdate(criteria, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}, getMainLooper());
}
});
This implements a listener for the LocationManager, that gives you the posibility to do some actions depending of the Location status.
In your case, you have implemented the listener on the activity, so just try calling:
locationManager.requestSingleUpdate(criteria, this);
This request just single update to show your present location
I am coming with an answer to my question. I don't know if it will work with all people facing the same problem. I just tried to restart the mobile device. After it restarts, it gets the correct current location. So it was a hardware problem though I thought it is something in the code..