secondary permission request is never presented - android

This is a rewrite of my original post because I have found that, contrary to Permissions overview:
a) The secondary permission dialog is never displayed
b) After
clicking "Deny" for the initial permission dialog, it is never shown
again.
Therefore, if I click deny, I can never allow calendar permission.
I set permissions in the manifest:
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
On start, I check for calendar permissions in MainActivity because they are necessary for the user to add appointments via my app and make them available to Google calendar (this works, if I allow, my app adds the calendar):
AccessCalendar accessCalendar = new AccessCalendar();
if(accessCalendar.requestCalendarPermissions(mContext, this)){
/**
* calendar read and write permissions not allowed: explain why needed
*/
Log.d(TAG, "calendar read and write permissions not allowed: explain why needed");
ConstraintLayout constraintLayout = (ConstraintLayout) findViewById(R.id.constraintLayout);
Snackbar.make(constraintLayout, R.string.write_calendar_permission_explanation, Snackbar.LENGTH_LONG).show();
DialogFragment permissionDialog = new CalendarPermissionExplanationFragment();
try {
permissionDialog.show(getSupportFragmentManager(), "CalendarPermissionExplanationFragment");
}catch (Exception e){
Log.d(TAG, "exception e is: " + e);
}
}else{
/**
* calendar read and write permissions allowed! No need to explain
*/
Log.d(TAG, "calendar read and write permissions allowed! No need to explain");
}
AccessCalendar.requestCalendarPermissions is (pretty much plagarized from Request App Permissions):
public boolean requestCalendarPermissions(Context context, Activity activity){
Log.d(TAG, "Entered: requestCalendarPermissions");
boolean explain = false;
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR)
!= PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context,
Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED ) {
// Permission is not granted
Log.d(TAG, "read and write permission not granted");
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.READ_CALENDAR) &&
ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.WRITE_CALENDAR)) {
Log.d(TAG, "shouldShowRequestPermissionRationale is true");
// 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.
Toast.makeText(context, R.string.write_calendar_permission_explanation, Toast.LENGTH_LONG).show();
explain = true;
} else {
Log.d(TAG, "shouldShowRequestPermissionRationale is false");
// No explanation needed; request the permission
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR},
MY_PERMISSIONS_REQUEST_CALENDAR);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}else{
//permission is granted, so set permission to true
Log.d(TAG, "read and write calendar permissions granted");
}
return explain;
}
Due to some problems, I am forced to use Toast to provide an explanation. I am now presented with the initial permissions dialog who's request attempt, Deny or Allow, is handled by MainActivity.onRequestPermissionsResult():
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.d(TAG, "Entered: onRequestPermissionsResult");
Log.d(TAG, "requestCode is: " + requestCode);
Log.d(TAG, "permissions is: " + permissions);
Log.d(TAG, "grantResults is: " + grantResults);
int cntPermissions = grantResults.length;
if(cntPermissions > 0) {
for (int i = 0; i < cntPermissions; i++) {
Log.d(TAG, "permissions[" + i + "] is: " + permissions[i]);
}
}
int cntGrantResults = grantResults.length;
if(cntGrantResults > 0) {
for (int i = 0; i < cntGrantResults; i++) {
Log.d(TAG, "grantResults[" + i + "] is: " + grantResults[i]);
}
}
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CALENDAR:
Log.d(TAG, "Entered: case MY_PERMISSIONS_REQUEST_CALENDAR");
if(cntPermissions > 0) {
if(permissions[1].equals("android.permission.WRITE_CALENDAR") && grantResults[1] == 0){
Toast.makeText(this, R.string.write_calendar_permission, Toast.LENGTH_LONG).show();
AccessCalendar accessCalendar = new AccessCalendar();
accessCalendar.createCalendar(mContext, this);
//get calendar information again to see if petrecords calendar was created
Log.d(TAG, "get the calendars in the system to see if petrecords now exists");
accessCalendar.getCalendars(mContext, this);
}else{
Toast.makeText(this, R.string.error_no_write_calendar_permission, Toast.LENGTH_LONG).show();
Log.d(TAG, "create alertdialog to explain why the permission is required");
}
}else{
Log.d(TAG, "no permissions returned");
}
break;
default:
Log.d(TAG, "illegal requestCode value");
break;
}
return;
}
In that case, a new calendar is created. Otherwise, the user proceeds after Denying. Later, the user is presented with Appointments and may, at that point, desire to add an appointment via my app and so clicks the Appointment tab and then the Manage Appointments button. At that point, precisely the same code is entered to check calendar permissions as shown above.
At that point I expect to be presented with the secondary permissions dialog, but no, all I get is my explanation. I would also expect to see the secondary permissions dialog when I relaunch my app after initially Denying, but no.
So, why doesn't Android ever present the secondary permissions dialog?

The shouldShowRequestPermissionRationale() method implies that the permission was rejected before and that you should explain why you're asking for the permissions.
For this you should use a Dialog or Snackbar with an action the user can use to trigger the permission request again.
If you're app doesn't work without this permission, you might want to show a bigger screen explaining that the app doesn't work without.
You could even ignore the shouldShowRequestPermissionRationale() flag and just show the permission request again and again. That's very annoying though.

Related

Android : unable to list /storage/emulated/0 files despite permissions

I have the following code to handle storage permissions :
private void getGalleryPermission() {
Log.d(TAG, "getGalleryPermission: checking permissions.");
String[] permissions = { WRITE_STORAGE, READ_STORAGE };
if (ContextCompat.checkSelfPermission(requireActivity(), WRITE_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "getGalleryPermission: write storage is granted.");
if (ContextCompat.checkSelfPermission(requireActivity(), READ_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "getGalleryPermission: read storage is granted.");
setupRecyclerView();
}
else {
Log.d(TAG, "getGalleryPermission: asking to read the storage.");
requestPermissions(permissions, REQUEST_STORAGE_PERMISSION_RESULT);
}
}
else {
Log.d(TAG, "getGalleryPermission: asking to write the storage.");
requestPermissions(permissions, REQUEST_STORAGE_PERMISSION_RESULT);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.d(TAG, "onRequestPermissionsResult: request code " + requestCode);
if (requestCode == REQUEST_STORAGE_PERMISSION_RESULT) {
Log.d(TAG, "onRequestPermissionsResult: request code is correct.");
if (grantResults.length > 0) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(requireActivity(), "Don't have permission to access the Gallery !", Toast.LENGTH_SHORT).show();
break;
}
}
// Setup the gallery once the permissions are granted
setupRecyclerView();
}
}
}
I am testing this code on several of my phones, and it's working perfectly. However, on my Huawei, the listFiles() method returns null on the /storage/emulated/0 directory.
I have checked in the phone Settings + in logs, and the storage permissions are granted (like on other working phones).
What can prevent the files from being read despite granted permissions ?
On some phones, is it possible that the /storage/emulated/0 is not the correct directory to target to get all gallery files ?
PS : i have checked the directory from the Files application in my phone and it's not empty (DCIM, etc.... are inside).
Thanks
is the Huawei device which returns null running Android 10? It seems that for that path Android returns null since API 29. You might want to check this question here.

WifiManager.WifiInfo getSSID & getBSSID not working if targetSdkVersion >= 26

I'm getting correctly those values if I compile with API 27 but target API 25. If I set targetSdkVersion to 27, then, those values are not correctly retrieved.
Targeting SDK 25 or less, values are correct, but targeting 26 or more, I get those values:
SSID gives <unknown ssid>
BBSSID gives 02:00:00:00:00:00
These are my manifest permissions, all are normal permissions and don't require user grant:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
And this is the sample code:
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiInfo connectionInfo = wifiManager.getConnectionInfo();
connectionInfo.getSSID();
connectionInfo.getBSSID();
What has changed when targeting SDK 26 or more? what more should we do to get those values?
You need location permission starting with API 27
Google has changed their policy with WifiManager since you can track user's location tracking wifi location from SDK>=27. Therefore you need to access location permission in order to use getSSID() for your appliaction.
In order to use this code follow below.
As #Samuel Eminet answer above, you need either ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION. I used ACCESS_FINE_LOCATION because
ACCESS_COARSE_LOCATION request permission for only NETWORK_PROVIDE whereas
ACCESS_FINE_LOCATION request permissions for NETWORK_PROVIDE AND GPS_PROVIDER.
Refer here for more information
In your Manifest file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
and where your wifi manager is, add this code to request permissions.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
//Permission Not Granted
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_FINE_LOCATION);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_FINE_LOCATION:
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//permission granted keep going status
Log.d(TAG, "PERMISSION GRANTED");
}
else {
Log.d(TAG, "PERMISSION DENIED");
}
}
}
One more thing to remember (I learned the hard way). If you are side-loading your app onto a device, don't forget to "allow" location permission in the app permissions (long press app, app info). It is off by default, thus you will get
I met with same problem. This problem happens higher android versions than API 23.
Solution:
You need to add below to build.gradle file.
implementation 'com.google.android.gms:play-services-location:15.0.0'
And you permission below rules.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">
Below code provides automatically permission for location in application.
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
try {
LocationRequest request = new LocationRequest()
.setFastestInterval(1500)
.setInterval(3000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
builder = new LocationSettingsRequest.Builder()
.addLocationRequest(request);
try {
Task<LocationSettingsResponse> result =
LocationServices.getSettingsClient(this.getApplicationContext()).checkLocationSettings(builder.build());
result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
#Override
public void onComplete(#NonNull Task<LocationSettingsResponse> task) {
try {
task.getResult(ApiException.class);
} catch (ApiException e) {
switch (e.getStatusCode()) {
case LocationSettingsStatusCodes
.RESOLUTION_REQUIRED:
ResolvableApiException resolveApiException = (ResolvableApiException) e;
try {
resolveApiException.startResolutionForResult(WifiConnectionActivity.this, REQUEST_CHECK_CODE);
} catch (IntentSender.SendIntentException ex) {
ex.printStackTrace();
} catch (ClassCastException ex) {
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
}
});
} catch (Exception x) {
}
checkPermissions();
} catch (Exception a) {
}
}
void checkPermissions() {
if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(WifiConnectionActivity.this, new String[]
{
Manifest.permission.ACCESS_COARSE_LOCATION
}, REQUEST_LOCATION);
}
else{
//Toast.makeText(getActivity(), "GPS is already permissioned", Toast.LENGTH_SHORT).show();
}
}
The below is the code .
public String getMac() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//Permission Not Granted
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}else{
WifiManager wifimanage = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
WifiInfo wifiinfo = wifimanage.getConnectionInfo();
macAddress = wifiinfo.getBSSID();//Get the mac address of the currently connected network;
}
return macAddress;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//permission granted keep going status
Log.d("mac", "PERMISSION GRANTED");
WifiManager wifimanage = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
WifiInfo wifiinfo = wifimanage.getConnectionInfo();
macAddress = wifiinfo.getBSSID();//Get the mac address of the currently connected network;
} else {
Log.d("mac", "PERMISSION DENIED");
}
}
}
Then call getMac() to solve the problem.

internet permission not granted

I am writing an app to send msg over TCP Socket. I am struggling to get access to the internet permission. (API 26 is the target)
socket EACCESS permission denied
I have setup in my Manfest :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.seb.sebastien.opengardenirc">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.persmission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
As I am using the API26, I have to add a permission check in the code to make sure it works fine:
if (shouldAskPermission()) {
Log.d(TAG, "Permission is required");
String[] PERMISSIONS_STORAGE = {
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_WIFI_STATE
};
int permission_internet = ActivityCompat.checkSelfPermission(this, Manifest.permission.INTERNET);
int permission_network = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE);
int permission_wifi = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_WIFI_STATE);
Log.d(TAG, "Package Manager: " + PackageManager.PERMISSION_GRANTED);
Log.d(TAG, "INTERNET : " + permission_internet);
Log.d(TAG, "NETWORK : " + permission_network);
Log.d(TAG, "WIFI : " + permission_wifi);
if ((permission_internet != PackageManager.PERMISSION_GRANTED)
|| (permission_network != PackageManager.PERMISSION_GRANTED)
|| (permission_wifi != PackageManager.PERMISSION_GRANTED)){
Log.d(TAG, "Asking for permission");
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
this,
PERMISSIONS_STORAGE,
REQUEST_CONNECTION_PERMISSION
);
} else {
Toast.makeText(MainActivity.this, "Permission (already) Granted!", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Permission already granted");
startTcpInAThread("str");
}
}
And I have also the method to catch the onRequestPermissionsResult.
private boolean shouldAskPermission(){
return(Build.VERSION.SDK_INT> Build.VERSION_CODES.LOLLIPOP_MR1);
}
#Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){
switch(permsRequestCode){
case REQUEST_CONNECTION_PERMISSION:
Log.d(TAG, "Permission granted result : " + grantResults[0]);
Log.d(TAG, "Permission granted result : " + grantResults[1]);
Log.d(TAG, "Permission granted result : " + grantResults[2]);
boolean accepted = (grantResults[0]== PackageManager.PERMISSION_GRANTED)
&& (grantResults[1]== PackageManager.PERMISSION_GRANTED)
&& (grantResults[2]== PackageManager.PERMISSION_GRANTED);
if(accepted) {
startTcpInAThread("str");
} else {
Toast.makeText(getApplicationContext(), "Permissions issues!!!!", Toast.LENGTH_SHORT).show();
}
break;
}
}
First things is that when checking the permission, I can see that android.persmission.INTERNETis not granted. Good thing is that it's going to call the request permission method ActivityCompat.requestPermissions
I was expecting a Dialog box showing up but my understanding is that the dlgbox only show up for some on the permission requests some other do not need to ask.
My concerns is that when I got onRequestPermissionsResultthe permission is still not granted.
Anybody know how to grant the permission to internet ?
I have also pay attention to not run the network access in the same thread.
Regards

Files from remote source do not get copied to external SDCard and prompt an error like "No Write Permission"

I am trying to copy some files from remotely connected pc to my Android Device's SDCard but it is showing an error "No write permission". while i transfer same files to internal storage, it transferred successfully.
I have already included these permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
My Android Device is running on Android Version 6.0.1
Use Run time permission for Android Version 6.0.0 and more
Click here for more information
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v("======>", "Permission is granted");
return true;
} else {
Log.v("======>", "Permission is revoked");
//1 is request code
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
return false;
}
} else { //permission is automatically granted on sdk<23 upon installation
Log.v("======>", "Permission is granted");
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
//1 is request code
case 1: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.v("======>", "Permission: " + permissions[0] + "was " + grantResults[0]);
openFileAttachDialog();
}
return;
}
}

How to get the status of location access permission to warn user

How can I detect the status of location access when user rejected the permission in the permission manager of the app.
this is not about Android M,but all the API Level
I tried to use Context#checkPermission,but it always return true.so i can't get the right status of location access permission if the user rejected it.
private static boolean checkPermission(Context context, String permName, String pkgName){
PackageManager pm = context.getPackageManager();
if(PackageManager.PERMISSION_GRANTED == pm.checkPermission(permName, pkgName)){
System.out.println(pkgName + "has permission : " + permName);
return true;
}else{
//PackageManager.PERMISSION_DENIED == pm.checkPermission(permName, pkgName)
System.out.println(pkgName + "not has permission : " + permName);
return false;
}
}
Using ContextCompat.checkSelfPermission() has worked for me:
if(ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED){
return true;
}else{
Log.d(LOG_TAG, "Permission not granted: " + permission);
return false;
}

Categories

Resources