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)