In my app I have created a class name Untility where I wrore the code for permission of READ_EXTERNAL_STORAGE. But the problem is when I click Deny on the app, I am not finding the alert notification to set it allow again. Initialy I have the option "Never ask Again". Once I clicked on it, the dialog desapperas. and now after running the app if I click on deny, I cannot find Dialog message anymore to make it allow again. How can I modify my code to show this message every time.
My Utility Class is
public class Utility {
public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123;
@TargetApi(Build.VERSION_CODES.M)
public static boolean checkPermission(final Context context) {
int currentAPIVersion = Build.VERSION.SDK_INT;
if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.READ_EXTERNAL_STORAGE)) {
Log.v("TAG", "Permission is granted");
}
else {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
}
return false;
} else {
return true;
}
} else {
return true;
}
}
My Another class here I am calling the Utility class is
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case Utility.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if(userChoosenTask.equals("Take Photo"))
cameraIntent();
else if(userChoosenTask.equals("Choose from Library"))
galleryIntent();
//do something here
} else {
//code for deny
Toast.makeText(DetailMyColleague.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
break;
}
}
private void selectImage() {
final CharSequence[] items = { "Take Photo", "Choose from Library",
"Cancel" };
AlertDialog.Builder builder = new AlertDialog.Builder(DetailMyColleague.this);
builder.setTitle("Add Photo!");
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
boolean result=Utility.checkPermission(DetailMyColleague.this);
if (items[item].equals("Take Photo")) {
userChoosenTask ="Take Photo";
if(result)
cameraIntent();
} else if (items[item].equals("Choose from Library")) {
userChoosenTask ="Choose from Library";
if(result)
galleryIntent();
} else if (items[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
}
private void galleryIntent()
{
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);//
startActivityForResult(Intent.createChooser(intent, "Select File"),SELECT_FILE);
}
private void cameraIntent()
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQUEST_CAMERA);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == SELECT_FILE)
onSelectFromGalleryResult(data);
else if (requestCode == REQUEST_CAMERA)
onCaptureImageResult(data);
}
}
private void onCaptureImageResult(Intent data) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File destination = new File(Environment.getExternalStorageDirectory(),
System.currentTimeMillis() + ".jpg");
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
profilePic.setImageBitmap(thumbnail);
}
@SuppressWarnings("deprecation")
private void onSelectFromGalleryResult(Intent data) {
Bitmap bm=null;
if (data != null) {
try {
bm = MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(), data.getData());
} catch (IOException e) {
e.printStackTrace();
}
}
profilePic.setImageBitmap(bm);
}
You cannot show the same Request message once they say "don't ask again", but you can check for the permission, and if denied, show a custom dialog that directs them to the settings page with an intent:
startActivityForResult(new Intent(android.provider.Settings.ACTION_SETTINGS), 0);
If you permission check fails:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// show a dialog
new AlertDialog.Builder(this).setMessage("You need to enable permissions to use this feature").setPositiveButton("Go to settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// navigate to settings
startActivityForResult(new Intent(android.provider.Settings.ACTION_SETTINGS), 0);
}
}).setNegativeButton("Go back", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// leave?
MyActivity.this.onBackPressed();
}
}).show();
}
'Don't show again' state can be figured out when permission is already 'Denied' and method shouldShowRequestPermissionRationale() returns false
This method can be used as possibility to show additional info to user, when system dialogs can't be shown (user selects "Accept" of "Don't show again") by system
Deny >> shouldShowRequestPermissionRationale(permission) -> true
Don't ask again >> shouldShowRequestPermissionRationale(permission) -> false
Accept >> shouldShowRequestPermissionRationale(permission) -> false
In case if you can't provide any action while all permissions you requested are Denied and at least one of them is denied by 'Don't ask again' checkbox - the best approach is to navigate user to Application Settings in System.
Here is a solution for "Accept"/"Deny"/"Don't ask again" workflow. Also here is an example for Jetpack Activity Result API. (requesting multiple permissions and navigation to another activity with coming back)
Comments for code:
PS. Code is not perfect, but good for understanding
Fragment
class Fragment_ActiityResultAPI_RequestMultiplePermissions : Fragment(){
val actionPermLocation = {
tvPerm1.text = "GRANTED";
tvPerm1.setTextColor(Color.GREEN)
}
val actionPermReadExt = {
tvPerm2.text = "GRANTED";
tvPerm2.setTextColor(Color.GREEN)
}
val permissionsAll = mutableMapOf(
Manifest.permission.ACCESS_FINE_LOCATION to actionPermLocation,
Manifest.permission.READ_EXTERNAL_STORAGE to actionPermReadExt,
)
private val arcRequestPermissions = registerForActivityResult(RequestMultiplePermissions()){ perms ->
perms.entries.forEach {
if(it.value){
permissionsAll[it.key]?.invoke()
}
}
}
private val arcNavigateToSettings = registerForActivityResult(StartSettingsActivityContract()) {
arcRequestPermissions.launch(permissionsAll.keys.toTypedArray())
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_layout, container, false)
}
override fun onViewCreated(layoutView: View, savedInstanceState: Bundle?) {
super.onViewCreated(layoutView, savedInstanceState)
// CHECK PERMISSIONS AT FRAGMENT START
arcRequestPermissions.launch(permissionsAll.keys.toTypedArray())
btn.setOnClickListener {
// CHECK PERMISSION AT BUTTON CLICK
processPermission()
}
}
private fun processPermission() {
var atLeastOnePermDenied = false
var atLeastOnePermAsDontAskAgain = false
permissionsAll.keys.toTypedArray().forEach {
atLeastOnePermDenied = atLeastOnePermDenied || checkPermDenied(it)
atLeastOnePermAsDontAskAgain = atLeastOnePermAsDontAskAgain || checkPermDontAskAgain(it)
}
if(atLeastOnePermAsDontAskAgain){
showAlertNavigateToAppSettings()
return
}
if(atLeastOnePermDenied){
arcRequestPermissions.launch(permissionsAll.keys.toTypedArray())
return
}
Utils.toast(requireContext(), ">>> Execute your target action!! <<<")
}
private fun checkPermDenied(perm: String): Boolean {
return (ActivityCompat.checkSelfPermission(requireContext(), perm)
==
PackageManager.PERMISSION_DENIED)
}
private fun checkPermDontAskAgain(perm: String): Boolean {
return checkPermDenied(perm) && !shouldShowRequestPermissionRationale(perm)
}
private fun showAlertNavigateToAppSettings() {
val builder = AlertDialog.Builder(requireContext())
builder.setMessage("You have to grant permissions for action")
builder.setPositiveButton("Go to Settings") { dialog, which -> // Do nothing but close the dialog
arcNavigateToSettings.launch(1)
}
builder.setNegativeButton("Cancel") { dialog, which -> // Do nothing
dialog.dismiss()
}
val alert = builder.create()
alert.show()
}
class StartSettingsActivityContract : ActivityResultContract<Int, String?>() {
override fun createIntent(context: Context, input: Int): Intent {
return Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
val uri = Uri.fromParts("package", context.packageName, null)
this.data = uri
}
}
override fun parseResult(resultCode: Int, intent: Intent?): String? {
return ""
}
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="150dp"
android:layout_height="wrap_content"
android:text="LOCATION: "
android:textColor="@android:color/darker_gray"/>
<TextView
android:id="@+id/tvPerm1"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Denied"
android:textColor="@android:color/darker_gray"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="150dp"
android:layout_height="wrap_content"
android:text="READ_STORAGE: "
android:textColor="@android:color/darker_gray"/>
<TextView
android:id="@+id/tvPerm2"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Denied"
android:textColor="@android:color/darker_gray"/>
</TableRow>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_gravity="center_horizontal"
android:text="Launch a Camera"/>
</FrameLayout>
</LinearLayout>
build.gradle
implementation 'androidx.activity:activity-ktx:1.2.1'
implementation 'androidx.fragment:fragment:1.3.0-alpha05'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With