diff --git a/cyclestreets.app/src/main/play/release-notes/en-GB/beta.txt b/cyclestreets.app/src/main/play/release-notes/en-GB/beta.txt
index e69de29b..f0dcf012 100644
--- a/cyclestreets.app/src/main/play/release-notes/en-GB/beta.txt
+++ b/cyclestreets.app/src/main/play/release-notes/en-GB/beta.txt
@@ -0,0 +1,2 @@
+- If there are queued voice instructions, these are replaced with the latest instruction.
+- Update permissions for Android 13 so map tiles can be cached and photos added.
diff --git a/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/CycleMapFragment.kt b/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/CycleMapFragment.kt
index b12a91bf..b706a155 100644
--- a/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/CycleMapFragment.kt
+++ b/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/CycleMapFragment.kt
@@ -2,9 +2,8 @@ package net.cyclestreets
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.graphics.drawable.Drawable
+import android.os.Build
import android.os.Bundle
-import androidx.fragment.app.Fragment
-import androidx.preference.PreferenceManager
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
@@ -12,19 +11,22 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.preference.PreferenceManager
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
-
import net.cyclestreets.fragments.R
import net.cyclestreets.iconics.IconicsHelper
-import net.cyclestreets.util.*
+import net.cyclestreets.util.AsyncDelete
+import net.cyclestreets.util.Logging
import net.cyclestreets.util.MenuHelper.createMenuItem
import net.cyclestreets.util.MenuHelper.enableMenuItem
+import net.cyclestreets.util.Theme
+import net.cyclestreets.util.doOrRequestPermission
+import net.cyclestreets.util.requestPermissionsResultAction
import net.cyclestreets.views.CycleMapView
-
import org.osmdroid.config.Configuration
import org.osmdroid.config.DefaultConfigurationProvider
import org.osmdroid.views.overlay.Overlay
-
import java.io.File
import java.util.Date
@@ -43,7 +45,8 @@ open class CycleMapFragment : Fragment(), Undoable {
forceMenuRebuild = true
- checkPermissionNoMoreThanOnceEveryFiveMinutes()
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
+ checkPermissionNoMoreThanOnceEveryFiveMinutes()
map = CycleMapView(context, this.javaClass.name, this)
searchIcon = IconicsHelper.materialIcon(requireContext(), GoogleMaterial.Icon.gmd_search, Theme.lowlightColorInverse(context))
diff --git a/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/addphoto/AddPhotoFragment.kt b/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/addphoto/AddPhotoFragment.kt
index 78556733..cd4981c9 100644
--- a/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/addphoto/AddPhotoFragment.kt
+++ b/libraries/cyclestreets-fragments/src/main/java/net/cyclestreets/addphoto/AddPhotoFragment.kt
@@ -1,6 +1,9 @@
package net.cyclestreets.addphoto
-import android.Manifest.permission.*
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.Manifest.permission.READ_MEDIA_IMAGES
+import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.Activity
import android.content.Context
import android.content.Intent
@@ -9,13 +12,26 @@ import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Point
import android.os.AsyncTask
+import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
-import android.view.*
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.inputmethod.InputMethodManager
-import android.widget.*
+import android.widget.Button
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import android.widget.Spinner
+import android.widget.TextView
+import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.exifinterface.media.ExifInterface
import androidx.fragment.app.Fragment
@@ -27,15 +43,24 @@ import net.cyclestreets.api.PhotomapCategories
import net.cyclestreets.api.Upload
import net.cyclestreets.fragments.R
import net.cyclestreets.iconics.IconicsHelper.materialIcons
-import net.cyclestreets.util.*
+import net.cyclestreets.util.AsyncDelete
+import net.cyclestreets.util.Bitmaps
+import net.cyclestreets.util.Dialog
+import net.cyclestreets.util.Logging
import net.cyclestreets.util.MenuHelper.createMenuItem
import net.cyclestreets.util.MenuHelper.enableMenuItem
+import net.cyclestreets.util.MessageBox
+import net.cyclestreets.util.ProgressDialog
+import net.cyclestreets.util.Share
+import net.cyclestreets.util.doOrRequestPermission
+import net.cyclestreets.util.hasPermission
+import net.cyclestreets.util.requestPermissionsResultAction
import net.cyclestreets.views.CycleMapView
import net.cyclestreets.views.overlay.ThereOverlay
import org.osmdroid.api.IGeoPoint
import org.osmdroid.util.GeoPoint
import java.io.File
-import java.util.*
+import java.util.Date
internal val TAG = Logging.getTag(AddPhotoFragment::class.java)
@@ -461,15 +486,24 @@ class AddPhotoFragment : Fragment(), View.OnClickListener, Undoable, ThereOverla
override fun onClick(v: View) {
when (v.id) {
R.id.takephoto_button -> doOrLogin {
- doOrRequestPermission(null, this, WRITE_EXTERNAL_STORAGE) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
+ doOrRequestPermission(null, this, WRITE_EXTERNAL_STORAGE) {
+ dispatchTakePhotoIntent()
+ }
+ else
dispatchTakePhotoIntent()
- }
}
R.id.chooseexisting_button -> doOrLogin {
- doOrRequestPermission(null, this, READ_EXTERNAL_STORAGE) {
- startActivityForResult(Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI),
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
+ doOrRequestPermission(null, this, READ_EXTERNAL_STORAGE) {
+ startActivityForResult(Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI),
CHOOSE_PHOTO)
}
+ else
+ doOrRequestPermission(null, this, READ_MEDIA_IMAGES) {
+ startActivityForResult(Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI),
+ CHOOSE_PHOTO)
+ }
}
R.id.textonly_button -> doOrLogin {
photo = null
@@ -516,6 +550,7 @@ class AddPhotoFragment : Fragment(), View.OnClickListener, Undoable, ThereOverla
/* startActivityForResult(Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI),
CHOOSE_PHOTO) */
}
+ READ_MEDIA_IMAGES -> requestPermissionsResultAction(grantResult, permission){}
WRITE_EXTERNAL_STORAGE -> requestPermissionsResultAction(grantResult, permission) {
// As above
//dispatchTakePhotoIntent()
diff --git a/libraries/cyclestreets-view/src/main/AndroidManifest.xml b/libraries/cyclestreets-view/src/main/AndroidManifest.xml
index 83e8bfac..26a54363 100644
--- a/libraries/cyclestreets-view/src/main/AndroidManifest.xml
+++ b/libraries/cyclestreets-view/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
diff --git a/libraries/cyclestreets-view/src/main/java/net/cyclestreets/util/Permissions.kt b/libraries/cyclestreets-view/src/main/java/net/cyclestreets/util/Permissions.kt
index b2abf373..c1586029 100644
--- a/libraries/cyclestreets-view/src/main/java/net/cyclestreets/util/Permissions.kt
+++ b/libraries/cyclestreets-view/src/main/java/net/cyclestreets/util/Permissions.kt
@@ -5,16 +5,14 @@ import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
-import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_DENIED
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri
-import android.os.Build
import android.provider.Settings
import android.util.Log
import android.widget.Toast
-import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat.startActivity
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import net.cyclestreets.CycleStreetsPreferences.*
import net.cyclestreets.GENERIC_PERMISSION_REQUEST
@@ -27,7 +25,7 @@ private val TAG = Logging.getTag(Permissions::class.java)
// Check for permissions
fun hasPermission(context: Context?, permission: String): Boolean {
return if (context != null)
- context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED
+ ContextCompat.checkSelfPermission(context, permission) == PERMISSION_GRANTED
else false
}
@@ -153,7 +151,6 @@ fun requestPermissionsResultAction(grantResult: Int?, permission: String, action
}
// Go to settings - if dynamic permission requesting is no long an option
-@RequiresApi(api = Build.VERSION_CODES.M)
private fun goToSettings(context: Context) {
Log.d(TAG, "Opening Settings screen to allow user to update permissions")
val androidAppSettingsIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:net.cyclestreets"))
@@ -172,6 +169,7 @@ private fun justification(context: Context, permission: String, justificationFor
private object Permissions {
val justifications: Map = hashMapOf(
Manifest.permission.READ_EXTERNAL_STORAGE to R.string.perm_justification_read_external_storage,
+ Manifest.permission.READ_MEDIA_IMAGES to R.string.perm_justification_read_media_images,
Manifest.permission.WRITE_EXTERNAL_STORAGE to R.string.perm_justification_write_external_storage,
Manifest.permission.ACCESS_FINE_LOCATION to R.string.perm_justification_access_fine_location,
Manifest.permission.READ_CONTACTS to R.string.perm_justification_read_contacts
diff --git a/libraries/cyclestreets-view/src/main/java/net/cyclestreets/views/CycleMapView.java b/libraries/cyclestreets-view/src/main/java/net/cyclestreets/views/CycleMapView.java
index 860b39e2..17371f9b 100644
--- a/libraries/cyclestreets-view/src/main/java/net/cyclestreets/views/CycleMapView.java
+++ b/libraries/cyclestreets-view/src/main/java/net/cyclestreets/views/CycleMapView.java
@@ -5,6 +5,7 @@
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.location.Location;
+import android.os.Build;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.ContextMenu;
@@ -72,10 +73,12 @@ public CycleMapView(final Context context, final String name, final Fragment fra
// Make sure we can save map tiles, regardless of whether we have the write-external permission granted.
boolean hasWritePermission = PermissionsKt.hasPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ // WRITE_EXTERNAL_STORAGE deprecated in Android 13. Permission not req'd for app-specific storage
+ boolean android13Plus = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context));
- Log.i(TAG, "Creating map view. App has write-external permission? " + hasWritePermission +
- "; osmdroid base path: " + Configuration.getInstance().getOsmdroidBasePath().getAbsolutePath() +
- "; osmdroid tile cache location: " + Configuration.getInstance().getOsmdroidTileCache().getAbsolutePath());
+ Log.i(TAG, String.format("Creating map view" + (android13Plus ?";":". App has write-external permission? " + hasWritePermission + ";") +
+ " osmdroid base path: " + Configuration.getInstance().getOsmdroidBasePath().getAbsolutePath() +
+ "; osmdroid tile cache location: " + Configuration.getInstance().getOsmdroidTileCache().getAbsolutePath()));
mapView_ = new MapView(context, TileSource.mapTileProvider(context));
addView(mapView_);
diff --git a/libraries/cyclestreets-view/src/main/res/values/strings.xml b/libraries/cyclestreets-view/src/main/res/values/strings.xml
index ce1abca2..f358f1e5 100644
--- a/libraries/cyclestreets-view/src/main/res/values/strings.xml
+++ b/libraries/cyclestreets-view/src/main/res/values/strings.xml
@@ -161,6 +161,11 @@
allow you to select photographs from your image library for use in the Add Photo feature.
]]>
+
+ allow you to select photographs from your image library for use in the Add Photo feature.
+
+ ]]>
cache downloaded map tiles (without this the app will function poorly and consume much more data)