From 943763dc903c1f106df8d0e8b3ccdb93e15b60e4 Mon Sep 17 00:00:00 2001 From: Milton Barrera Date: Sun, 8 Dec 2024 13:38:49 -0600 Subject: [PATCH] Fix #480: Refactor permission request for writing to external storage - Extracted permission handling logic into a reusable method. - Added support for Android R+ to avoid unnecessary permission requests. - Displayed a rationale dialog when permission is not granted. --- .../net/osmtracker/activity/TrackDetail.java | 73 +++++++++++++------ 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/net/osmtracker/activity/TrackDetail.java b/app/src/main/java/net/osmtracker/activity/TrackDetail.java index 5f4eb6d9..334c7fb4 100644 --- a/app/src/main/java/net/osmtracker/activity/TrackDetail.java +++ b/app/src/main/java/net/osmtracker/activity/TrackDetail.java @@ -15,12 +15,14 @@ import net.osmtracker.util.MercatorProjection; import android.Manifest; +import android.app.AlertDialog; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Paint; +import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import androidx.core.app.ActivityCompat; @@ -237,32 +239,10 @@ public boolean onOptionsItemSelected(MenuItem item) { startActivity(i); break; case R.id.trackdetail_menu_export: - if (ContextCompat.checkSelfPermission(this, - Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - - // Should we show an explanation? - if (ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - - // 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. - // TODO: explain why we need permission. - Log.w(TAG, "we should explain why we need write permission"); - - } else { - - // No explanation needed, we can request the permission. - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - RC_WRITE_PERMISSIONS); - break; - } - - } else { + if (writeExternalStoragePermissionGranted()) { exportTrack(); - break; } + break; case R.id.trackdetail_menu_osm_upload: i = new Intent(this, OpenStreetMapUpload.class); i.putExtra(TrackContentProvider.Schema.COL_TRACK_ID, trackId); @@ -272,6 +252,51 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } + /** + * Checks if the external storage write permission is granted. + * If not, it requests the permission and may display a rationale dialog explaining why it is needed. + * + *

For devices running Android R (API level 30) and above, this permission is not required, + * so the method will return {@code true} immediately.

+ * + * @return {@code true} if the write permission is already granted or not required (Android R+), + * {@code false} otherwise. + */ + private boolean writeExternalStoragePermissionGranted() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return true; + } + else if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + // Should we show an explanation? + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + // 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. + new AlertDialog.Builder(this) + .setTitle("Permission required") + .setMessage("To export the GPX trace we need to write on the storage.") + .setPositiveButton("Accept", (dialog, which) -> { + // Request the permission again + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + RC_WRITE_PERMISSIONS); + }) + .setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss()) + .show(); + } else { + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + RC_WRITE_PERMISSIONS); + } + } + + return ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; + } + /** * Invoke the export track task after external write permissions request.