How to handle don't ask me again in android on demand permission request. Is their any best practice if the user chooses don't ask me again and later if he want to get access any best practice suggestion? Thanks.
shouldShowRequestPermissionRationale will help you with this.
shouldShowRequestPermissionRationale() will be used to check whether user have selected Never ask again. It will return value as True or False, If user have selected Never ask before it will return false, else will return true.
boolean shouldShow = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
if (!shouldShow) {
// show some dialog which will give information about required permission, so that user can understand what is need of that permission.
}
on button click of dialog, you can redirect user to setting screen of app.
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,Uri.fromParts("package", getPackageName(), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
If you are working for pre-marshmallow, you need to use ActivityCompat.shouldShowRequestPermissionRationale()
Related
My app uses Internet access to display ads so I have the Internet permission declared in Manifest.
With latest Android releases, the user can disable this permission.
My problem is that if the user cancels this permission, the app is not able to load ads.
I know I can check if there is any current connection, in that case I will not try to load the app. But I want to know if the user has denied that permission in Android settings.
The idea is to prompt the user to enable it or the app will not run.
I add a screenshot of the Huawei Android Pie where the user can modify these settings
You just need to check first that whether the user enable (Allow the permission) or not. If not then redirect the user to the phone setting so that the user allow that permission otherwise just finish the app.
if (ContextCompat.checkSelfPermission(this,Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED )
{
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
// if user blocked permission
android.app.AlertDialog.Builder dlgAlert = new android.app.AlertDialog.Builder(this);
dlgAlert.setPositiveButton("Take me to app settings",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
});
dlgAlert.setNegativeButton("Cancel",null);
dlgAlert.setCancelable(true);
dlgAlert.setIcon(R.drawable.appicon);
dlgAlert.setMessage("The app needs the permission please allow it other wise you cannot proceed.");
dlgAlert.setTitle("Oops!");
dlgAlert.create().show();
}
}
else
{
finish();
}
If internet connection is all you want to check, you dont have to check permissions for this because Internet is not a critical permission. What you can simply do is use ConnectivityManager class to check if the device has active internet connection or not and then write your logic accordingly.
Refer: This on how you can check for internet connectivity.
I am having an inconsistent user experience due to the way android navigates back from Android Settings.
In my application the user needs to give my app access to ACTION_USAGE_ACCESS_SETTINGS, which I access with the following:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
After toggling the setting to on for my application, I need the user to return to my application. The only way to do this that I know of is for them to press the back button on the phone ( would love to know if it is possible to return automatically after the setting has been toggled!!!?!).
Now one of two things will happen:
1) The user has not used android settings recently, so it was not already open ( ie open in the open app drawer). The first press of the back button will take them to my application as desired.
2) The user had used android settings recently. Thus settings was already open in the application drawer. Now when the user presses back, Android will take them back through each setting page they had been using recently (ie the back button takes them through their history in the android settings pages). It may take 2, 3 or 4 presses of the back button to leave Android settings, and return to my application. This is obviously terrible UI/UX, and I was wondering if there is a better way?
I have noticed that when installing Google apps, after toggling the setting to ON, it automatically exits and returns to the application that called the setting. Being able to do that would be ideal, but I just cant work it out.
Thanks!
Ok, so after trying about a millions things, I have come up with 3 different ways to improve my problem.
1) Was provided by #CommonsWare, by removing the FLAG_ACTIVITY_NEW_TASK, it prevented an inconsistent number of back presses needed, and means every time the user would only have to press back twice.
2) Upon further research into the flags, I found that using three combined:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
reduced the number of back presses required to 1 single back press. This is simple and reasonable user friendly.
3) Using a handler to continuously check for the required permission after the settings intent has fired. This seems a like a bit of a hack, and I can't believe there is not a better way to do this, but it works exactly as it works when using a Google App. Ie, as soon as you switch the toggle to on, it exits the Android Settings page, and returns to your application, where you left off. I am using:
Handler handler = new Handler();
Runnable checkSettingOn = new Runnable() {
#Override
//#TargetApi(23)
public void run() {
Log.d(TAG, "run: 1");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Log.d(TAG, "run: 2");
return;
}
if (isAccessGranted()) {
Log.d(TAG, "run: 3");
//You have the permission, re-launch MainActivity
Intent i = new Intent(MainActivity.this, MainActivity.class);
Log.d(TAG, "run: 4");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
return;
}
handler.postDelayed(this, 200);
}
};
Then when you fire the intent to get to the Android settings page, just be sure to start the handler:
handler.postDelayed(checkSettingOn, 1000);
Hope this helps someone else with a similar issue.
After you have started Settings activity you can run periodical task, that is invoked every, for example 500ms, and checks if permission is granted.
Mark your setup activity with flag singleTask/singleInstance, and start it, if permission is granted. Existing instance of activity will be moved to top.
I did this for notifications access permission.
Extending upon Ufkoku's answer, I used a periodic check on the status of the permission. To get the user back, I used startActivityForResult and finishActivity.
Sample Code : I used this for the "USAGE_ACCESS_SETTINGS".
var intent = Intent("android.settings.USAGE_ACCESS_SETTINGS")
intent.data = Uri.fromParts("package", "com.example.app", null)
startActivityForResult(intent,101)
var timer = Timer(true)
timer.scheduleAtFixedRate(object: TimerTask(){
override fun run(){
if(checkUsageAccessPermission()){ // checkUsageAccessPermission() is a helper function
finishActivity(101)
cancel()
}
}
}, 0, 1000)
The solution from #Geordie Wicks was close to what I was looking for, but it seems like having the Android Settings open before launching your intent would cause the back button to take you to the previous Android Settings screen.
My solution involves two more flags, Intent.FLAG_ACTIVITY_CLEAR_TOP and Intent.FLAG_ACTIVITY_CLEAR_TASK.
You can define your intent as below:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
From my experience, this will make it so that a back button press will take you back to your application regardless of whether or not the Android Settings were open beforehand.
You can do one thing here. you have to confirm that you only open the settings component that you require to be opened .... Do not open the main settings app. Open only a single component within settings app that you want. So in that way when ever you will press back, you will jump back to your application.
For example if i want to open bluetooth settings in settings
application, I wont open the main Settings app instead i will open
only bluetooth component of settings. In that way when i press back i
will return to my own app because i haven't open the main setting app so i do not need to navigate in it.
ComponentName cn = new ComponentName("com.android.settings",
"com.android.settings.bluetooth.BluetoothSettings");
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent);
This is also the simplest way to navigate it
Sorry if the answer was late but I left my answer here for others to overcome this problems. To me the problems might be ourself not from Android. For e.g I have a listener, which listen to the state of the switch
setOnCheckedChangeListener { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data =
Uri.fromParts(
"package",
navigator.activeFragment?.activity?.packageName,
null
)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
navigator.activeFragment?.startActivity(intent)
}
What happened with this code?
The user go to Setting and then navigate back. If you have set something that update the UI like belows here after user go back, then this will cause multiple listener listen to the change of switch
override fun onResume() {
super.onResume()
if (!isFirst) {
// Notify that user might have change the notification setting
(binding.rvSetting2.adapter as SettingAdapter).notifyItemChanged(0)
}
isFirst = false
My solution
You may add this line inside the listener, this will remove the current switch listener, which can avoid go to Setting after and after when switch change.
setOnCheckedChangeListener { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data =
Uri.fromParts(
"package",
navigator.activeFragment?.activity?.packageName,
null
)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
navigator.activeFragment?.startActivity(intent)
// Remove the current listener in case of user went back from Setting and call on bind view holder again
// This cause multiple listener listen to the change of this switch
setOnCheckedChangeListener(null)
}
I know that this is just my personal solution, but if you share similar ways, this might be help.
You have to confirm that you only open the settings of your app that you require to be opened. Do not open the main settings app. Open only your app settings that you want. So in that way whenever you will press back, you will jump back to your application.
Uri uri = Uri.fromParts("package", getPackageName(), null);
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(uri);
startActivity(intent);
I have created an app which continuously run in background and show an floating overlay TextView(By using the permission android.permission.SYSTEM_ALERT_WINDOW).
I have problem in Lenovo android devices, when other applications try to request for user permission there is an alert dialog says "Screen Overlay Detected". While I have test the same application on Redmi 3S Prime device the "Allow" button in permission dialog is not clickable, until I have turned off the Floating Overlay TextView in my application.
So is there any solution to resolve this device specific issue? One of the possible solution may be disable floating TextView while permission dialog is visible to user and show floating overlay when permission dialog is closed, but the problem is how can I detect the permission dialog open/close state for other foreground application from my app.
Please suggest...
Unfortunately it seems that this is inherent to the Android OS, and as far as I know there is no way to detect when another app is requesting permissions. The general flow for interacting with other apps is to send intents to them in a push manner, so theoretically it could be done if the other apps send an intent to your app to disable the overlay, though this is not a practical solution.
I could be completely wrong, but I am yet to see a programmatic solution to this problem. The best you can probably do is warn your users that your app may cause this problem, and provide them with a quick temporary disable button.
how can I detect the permission dialog open/close state from my app??
Implement Method Mentioned Below, to run this check at the onCreate of the first Activity
public final static int PERM_REQUEST_CODE_DRAW_OVERLAYS = 1234;
/**
* Permission to draw Overlays/On Other Apps, related to
'android.permission.SYSTEM_ALERT_WINDOW'
in Manifest
Resolves issue of popup in Android M and above "Screen overlay detected- To change this permission setting you first have to turn off the screen overlay from Settings > Apps"
If app has not been granted permission to draw on the screen, create an Intent &
set its destination to
Settings.ACTION_MANAGE_OVERLAY_PERMISSION
&
* add a URI in the form of
"package:"
to send users directly to your app's page.
Note: Alternative Ignore URI to send user to the full list of apps.
public void permissionToDrawOverlays() {
if (android.os.Build.VERSION.SDK_INT >= 23) { //Android M Or Over
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, PERM_REQUEST_CODE_DRAW_OVERLAYS);
}
}
}
Called on the activity, to check on the results returned of the user action within the settings
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PERM_REQUEST_CODE_DRAW_OVERLAYS) {
if (android.os.Build.VERSION.SDK_INT >= 23) { //Android M Or Over
if (!Settings.canDrawOverlays(this)) {
// ADD UI FOR USER TO KNOW THAT UI for SYSTEM_ALERT_WINDOW permission was not granted earlier...
}
}
}
}
NOTE:Above code and extract is taken from following gist.
Hope this Helps!!!..
Just clear data of the Es explorer from device then after restart device.
I think these two links could help you.
firstlink
secondlink
Try to use for debug build -- targetSdkVersion 22.
After signed APK (for all targetSdkVersion(s)) application will work 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
i would like to know how to show
the check box that makes some application the
default in the createChooser dlg.
thanks in advance.
yes David i would like to know how to clear the app from being default. also i would like to know whether i can call any intent if i know its action, category, package and "class name", can I?
I actually tried to call some activity i previously known its intent contents put some SECURITY EXP. raised. why?
Your question isn't 100% clear to me, so forgive me if I'm answering the wrong question. It sounds like you want to either:
Pop up the dialog that lets the user select your activity as the default to handle some intent; or
Check if your activity is the default for an intent.
I'll answer both.
To pop up the dialog that lets the user select your activity as the default to handle some intent, simply call startActivity() with that intent. If for example you wanted to register yourself as the default home screen you would simply:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
1 of 3 things would happen.
Either there is no default specified (and if a user just installed your app, it will clear the default value) and thus the pop up will appear, or you're already the default or someone else is the default.
If you're already the default, then awesome, just figure out how to handle the intent this once (maybe add an EXTRA that explains that this was just a test so your activity knows to finish() immediately).
If someone else is the default you'll need to walk the user through clearing defaults for that app. If no one is the default you may want to throw up a Toast notification that explains what the user should do.
Toast.makeText(this,
"Please check 'Use by default for this action' and then press 'MyActivity'",
Toast.LENGTH_LONG).show();
These are all sort of messy situations to handle and it would be better to check first before calling startActivity(). To do that, use ResolveInfo.
ResolveInfo res = getPackageManager().resolveActivity(intent, 0);
// Got to be a better way to determine if there is no default...
if (res.activityInfo.packageName.equals("android")) {
// No default selected
} else if (res.activityInfo.packageName.equals(getPackageName())) {
// We are default
} else {
// Someone else is default
}
Hope this helps! If you want to know about how to make it easy for the user to clear another app from being default, let me know.