Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DividerItemDecoration duplication and GPX export issues (#479 #480) #481

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 49 additions & 24 deletions app/src/main/java/net/osmtracker/activity/TrackDetail.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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.
*
* <p>For devices running Android R (API level 30) and above, this permission is not required,
* so the method will return {@code true} immediately.</p>
*
* @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(R.string.permission_required)
.setMessage(R.string.storage_permission_for_export_GPX)
.setPositiveButton(R.string.acccept, (dialog, which) -> {
// Request the permission again
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
RC_WRITE_PERMISSIONS);
})
.setNegativeButton(R.string.menu_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.
Expand Down
29 changes: 17 additions & 12 deletions app/src/main/java/net/osmtracker/activity/TrackManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ public class TrackManager extends AppCompatActivity

private TrackListRVAdapter recyclerViewAdapter;

// To check if the RecyclerView already has a DividerItemDecoration added
private boolean hasDivider;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand Down Expand Up @@ -139,19 +142,21 @@ protected void onResume() {


/**
*
* Configures and initializes the RecyclerView for displaying the list of tracks.
*/
private void setRecyclerView() {
RecyclerView recyclerView = findViewById(R.id.recyclerview);

LinearLayoutManager layoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);

DividerItemDecoration did = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(did);

// adds a divider decoration if not already present
if (!hasDivider) {
DividerItemDecoration did = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(did);
hasDivider = true;
}
recyclerView.setHasFixedSize(true);
Cursor cursor = getContentResolver().query(
TrackContentProvider.CONTENT_URI_TRACK, null, null, null,
Expand Down Expand Up @@ -281,7 +286,7 @@ private void tryStartTrackLogger(Intent intent){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
Log.i(TAG,"Should explain");
Toast.makeText(this, "Can't continue without GPS permission",
Toast.makeText(this, R.string.gps_perms_required,
Toast.LENGTH_LONG).show();
}

Expand Down Expand Up @@ -724,7 +729,7 @@ public void onRequestPermissionsResult(int requestCode, String permissions[],
// functionality that depends on this permission.
//TODO: add an informative message.
Log.w(TAG, "we should explain why we need write permission_EXPORT_ALL");
Toast.makeText(this, "To export the GPX trace we need to write on the storage.", Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.storage_permission_for_export_GPX, Toast.LENGTH_LONG).show();
}
break;
}
Expand All @@ -742,7 +747,7 @@ public void onRequestPermissionsResult(int requestCode, String permissions[],
// functionality that depends on this permission.
//TODO: add an informative message.
Log.w(TAG, "we should explain why we need write permission_EXPORT_ONE");
Toast.makeText(this, "To export the GPX trace we need to write on the storage.", Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.storage_permission_for_export_GPX, Toast.LENGTH_LONG).show();
}
break;
}
Expand All @@ -759,7 +764,7 @@ public void onRequestPermissionsResult(int requestCode, String permissions[],
// functionality that depends on this permission.
//TODO: add an informative message.
Log.w(TAG, "Permission not granted");
Toast.makeText(this, "To display the track properly we need access to the storage.", Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.storage_permission_for_display_track, Toast.LENGTH_LONG).show();
}
break;
}
Expand All @@ -777,7 +782,7 @@ public void onRequestPermissionsResult(int requestCode, String permissions[],
// functionality that depends on this permission.
//TODO: add an informative message.
Log.w(TAG, "Permission not granted");
Toast.makeText(this, "To share the track properly we need access to the storage.", Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.storage_permission_for_share_track, Toast.LENGTH_LONG).show();
}
break;
}
Expand All @@ -794,7 +799,7 @@ public void onRequestPermissionsResult(int requestCode, String permissions[],
// functionality that depends on this permission.
//TODO: add an informative message.
Log.w(TAG, "Permission not granted");
Toast.makeText(this, "To upload the track to OSM we need access to the storage.", Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.storage_permission_for_upload_to_OSM, Toast.LENGTH_LONG).show();
}
break;
}
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@
<string name="error_voicerec_failed">Voice recording has failed</string>
<string name="error_userlayout_parsing">Error while parsing XML layout file. Please revert to default layout.</string>

<!-- messages -->
<string name="permission_required">Permission required</string>
<string name="storage_permission_for_export_GPX">To export the GPX trace we need to write on the storage.</string>
<string name="storage_permission_for_display_track">To display the track properly we need access to the storage.</string>
<string name="storage_permission_for_share_track">To share the track properly we need access to the storage.</string>
<string name="storage_permission_for_upload_to_OSM">To upload the track to OSM we need access to the storage.</string>
<string name="acccept">Accept</string>
<string name="gps_perms_required">Can\'t continue without GPS permission</string>

<!-- GPX -->
<string name="gpx_track_name">Tracked with OSMTracker for Android™</string>
<string name="gpx_hdop_approximation_cmt">Warning: HDOP values aren\'t the HDOP as returned by the GPS device. They\'re approximated from the location accuracy in meters.</string>
Expand Down
Loading