diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 09725f98b..3cca27c39 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -30,6 +30,9 @@
+
+
+
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt b/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt
index 773f2ef19..1c4d47dce 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt
@@ -119,7 +119,9 @@ class MainActivity : FlutterActivity() {
when (requestCode) {
DOCUMENT_TREE_ACCESS_REQUEST -> onDocumentTreeAccessResult(data, resultCode, requestCode)
DELETE_PERMISSION_REQUEST -> onDeletePermissionResult(resultCode)
- CREATE_FILE_REQUEST, OPEN_FILE_REQUEST, SELECT_DIRECTORY_REQUEST -> onPermissionResult(requestCode, data?.data)
+ CREATE_FILE_REQUEST,
+ OPEN_FILE_REQUEST,
+ SELECT_DIRECTORY_REQUEST -> onStorageAccessResult(requestCode, data?.data)
}
}
@@ -127,7 +129,7 @@ class MainActivity : FlutterActivity() {
private fun onDocumentTreeAccessResult(data: Intent?, resultCode: Int, requestCode: Int) {
val treeUri = data?.data
if (resultCode != RESULT_OK || treeUri == null) {
- onPermissionResult(requestCode, null)
+ onStorageAccessResult(requestCode, null)
return
}
@@ -138,7 +140,7 @@ class MainActivity : FlutterActivity() {
contentResolver.takePersistableUriPermission(treeUri, takeFlags)
// resume pending action
- onPermissionResult(requestCode, treeUri)
+ onStorageAccessResult(requestCode, treeUri)
}
private fun onDeletePermissionResult(resultCode: Int) {
@@ -152,9 +154,17 @@ class MainActivity : FlutterActivity() {
when (intent?.action) {
Intent.ACTION_MAIN -> {
intent.getStringExtra("page")?.let { page ->
+ var filters = intent.getStringArrayExtra("filters")?.toList()
+ if (filters == null) {
+ // fallback for shortcuts created on API < 26
+ val filterString = intent.getStringExtra("filtersString")
+ if (filterString != null) {
+ filters = filterString.split(EXTRA_STRING_ARRAY_SEPARATOR)
+ }
+ }
return hashMapOf(
"page" to page,
- "filters" to intent.getStringArrayExtra("filters")?.toList(),
+ "filters" to filters,
)
}
}
@@ -209,9 +219,13 @@ class MainActivity : FlutterActivity() {
private fun setupShortcuts() {
// do not use 'route' as extra key, as the Flutter framework acts on it
+ // shortcut adaptive icons are placed in `mipmap`, not `drawable`,
+ // so that foreground is rendered at the intended scale
+ val supportAdaptiveIcon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+
val search = ShortcutInfoCompat.Builder(this, "search")
.setShortLabel(getString(R.string.search_shortcut_short_label))
- .setIcon(IconCompat.createWithResource(this, R.mipmap.ic_shortcut_search))
+ .setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_search else R.drawable.ic_shortcut_search))
.setIntent(
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
.putExtra("page", "/search")
@@ -220,7 +234,7 @@ class MainActivity : FlutterActivity() {
val videos = ShortcutInfoCompat.Builder(this, "videos")
.setShortLabel(getString(R.string.videos_shortcut_short_label))
- .setIcon(IconCompat.createWithResource(this, R.mipmap.ic_shortcut_movie))
+ .setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_movie else R.drawable.ic_shortcut_movie))
.setIntent(
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
.putExtra("page", "/collection")
@@ -234,18 +248,19 @@ class MainActivity : FlutterActivity() {
companion object {
private val LOG_TAG = LogUtils.createTag()
const val VIEWER_CHANNEL = "deckers.thibault/aves/viewer"
+ const val EXTRA_STRING_ARRAY_SEPARATOR = "###"
const val DOCUMENT_TREE_ACCESS_REQUEST = 1
const val DELETE_PERMISSION_REQUEST = 2
const val CREATE_FILE_REQUEST = 3
const val OPEN_FILE_REQUEST = 4
const val SELECT_DIRECTORY_REQUEST = 5
- // permission request code to pending runnable
- val pendingResultHandlers = ConcurrentHashMap()
+ // request code to pending runnable
+ val pendingStorageAccessResultHandlers = ConcurrentHashMap()
- fun onPermissionResult(requestCode: Int, uri: Uri?) {
- Log.d(LOG_TAG, "onPermissionResult with requestCode=$requestCode, uri=$uri")
- val handler = pendingResultHandlers.remove(requestCode) ?: return
+ private fun onStorageAccessResult(requestCode: Int, uri: Uri?) {
+ Log.d(LOG_TAG, "onStorageAccessResult with requestCode=$requestCode, uri=$uri")
+ val handler = pendingStorageAccessResultHandlers.remove(requestCode) ?: return
if (uri != null) {
handler.onGranted(uri)
} else {
@@ -261,4 +276,4 @@ class MainActivity : FlutterActivity() {
// onGranted: user selected a directory/file (with no guarantee that it matches the requested `path`)
// onDenied: user cancelled
-data class PendingResultHandler(val path: String?, val onGranted: (uri: Uri) -> Unit, val onDenied: () -> Unit)
+data class PendingStorageAccessResultHandler(val path: String?, val onGranted: (uri: Uri) -> Unit, val onDenied: () -> Unit)
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt
index df5d58108..24820960d 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt
@@ -46,8 +46,12 @@ class SearchSuggestionsProvider : MethodChannel.MethodCallHandler, ContentProvid
val matrixCursor = MatrixCursor(columns)
context?.let { context ->
+ // shortcut adaptive icons are placed in `mipmap`, not `drawable`,
+ // so that foreground is rendered at the intended scale
+ val supportAdaptiveIcon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+
val searchShortcutTitle = "${context.resources.getString(R.string.search_shortcut_short_label)} $query"
- val searchShortcutIcon = context.resourceUri(R.mipmap.ic_shortcut_search)
+ val searchShortcutIcon = context.resourceUri(if (supportAdaptiveIcon) R.mipmap.ic_shortcut_search else R.drawable.ic_shortcut_search)
matrixCursor.addRow(arrayOf(null, null, null, searchShortcutTitle, null, searchShortcutIcon))
runBlocking {
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppShortcutHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppShortcutHandler.kt
index 24b81b739..452d35213 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppShortcutHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppShortcutHandler.kt
@@ -3,6 +3,7 @@ package deckers.thibault.aves.channel.calls
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
+import android.os.Build
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
@@ -52,16 +53,24 @@ class AppShortcutHandler(private val context: Context) : MethodCallHandler {
var bitmap = BitmapFactory.decodeByteArray(iconBytes, 0, iconBytes.size)
bitmap = centerSquareCrop(context, bitmap, 256)
if (bitmap != null) {
- icon = IconCompat.createWithBitmap(bitmap)
+ // adaptive, so the bitmap is used as background and covers the whole icon
+ icon = IconCompat.createWithAdaptiveBitmap(bitmap)
}
}
if (icon == null) {
- icon = IconCompat.createWithResource(context, R.mipmap.ic_shortcut_collection)
+ // shortcut adaptive icons are placed in `mipmap`, not `drawable`,
+ // so that foreground is rendered at the intended scale
+ val supportAdaptiveIcon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+
+ icon = IconCompat.createWithResource(context, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_collection else R.drawable.ic_shortcut_collection)
}
val intent = Intent(Intent.ACTION_MAIN, null, context, MainActivity::class.java)
.putExtra("page", "/collection")
.putExtra("filters", filters.toTypedArray())
+ // on API 25, `String[]` or `ArrayList` extras are null when using the shortcut
+ // so we use a joined `String` as fallback
+ .putExtra("filtersString", filters.joinToString(MainActivity.EXTRA_STRING_ARRAY_SEPARATOR))
// multiple shortcuts sharing the same ID cannot be created with different labels or icons
// so we provide a unique ID for each one, and let the user manage duplicates (i.e. same filter set), if any
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/StorageAccessStreamHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/StorageAccessStreamHandler.kt
index cd7e590a4..58f2729cf 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/StorageAccessStreamHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/StorageAccessStreamHandler.kt
@@ -7,7 +7,7 @@ import android.os.Handler
import android.os.Looper
import android.util.Log
import deckers.thibault.aves.MainActivity
-import deckers.thibault.aves.PendingResultHandler
+import deckers.thibault.aves.PendingStorageAccessResultHandler
import deckers.thibault.aves.utils.LogUtils
import deckers.thibault.aves.utils.PermissionManager
import deckers.thibault.aves.utils.StorageUtils
@@ -82,7 +82,7 @@ class StorageAccessStreamHandler(private val activity: Activity, arguments: Any?
type = mimeType
putExtra(Intent.EXTRA_TITLE, name)
}
- MainActivity.pendingResultHandlers[MainActivity.CREATE_FILE_REQUEST] = PendingResultHandler(null, { uri ->
+ MainActivity.pendingStorageAccessResultHandlers[MainActivity.CREATE_FILE_REQUEST] = PendingStorageAccessResultHandler(null, { uri ->
GlobalScope.launch(Dispatchers.IO) {
try {
activity.contentResolver.openOutputStream(uri)?.use { output ->
@@ -116,7 +116,7 @@ class StorageAccessStreamHandler(private val activity: Activity, arguments: Any?
addCategory(Intent.CATEGORY_OPENABLE)
type = mimeType
}
- MainActivity.pendingResultHandlers[MainActivity.OPEN_FILE_REQUEST] = PendingResultHandler(null, { uri ->
+ MainActivity.pendingStorageAccessResultHandlers[MainActivity.OPEN_FILE_REQUEST] = PendingStorageAccessResultHandler(null, { uri ->
GlobalScope.launch(Dispatchers.IO) {
activity.contentResolver.openInputStream(uri)?.use { input ->
val buffer = ByteArray(BUFFER_SIZE)
@@ -138,7 +138,7 @@ class StorageAccessStreamHandler(private val activity: Activity, arguments: Any?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
- MainActivity.pendingResultHandlers[MainActivity.SELECT_DIRECTORY_REQUEST] = PendingResultHandler(null, { uri ->
+ MainActivity.pendingStorageAccessResultHandlers[MainActivity.SELECT_DIRECTORY_REQUEST] = PendingStorageAccessResultHandler(null, { uri ->
success(StorageUtils.convertTreeUriToDirPath(activity, uri))
endOfStream()
}, {
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt
index cfb0bb307..96da1ae62 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt
@@ -10,7 +10,7 @@ import android.os.storage.StorageManager
import android.util.Log
import androidx.annotation.RequiresApi
import deckers.thibault.aves.MainActivity
-import deckers.thibault.aves.PendingResultHandler
+import deckers.thibault.aves.PendingStorageAccessResultHandler
import deckers.thibault.aves.utils.StorageUtils.PathSegments
import java.io.File
import java.util.*
@@ -35,7 +35,7 @@ object PermissionManager {
}
if (intent.resolveActivity(activity.packageManager) != null) {
- MainActivity.pendingResultHandlers[MainActivity.DOCUMENT_TREE_ACCESS_REQUEST] = PendingResultHandler(path, onGranted, onDenied)
+ MainActivity.pendingStorageAccessResultHandlers[MainActivity.DOCUMENT_TREE_ACCESS_REQUEST] = PendingStorageAccessResultHandler(path, onGranted, onDenied)
activity.startActivityForResult(intent, MainActivity.DOCUMENT_TREE_ACCESS_REQUEST)
} else {
Log.e(LOG_TAG, "failed to resolve activity for intent=$intent")
diff --git a/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_collection.xml b/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_collection.xml
new file mode 100644
index 000000000..f20e57d59
--- /dev/null
+++ b/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_collection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_movie.xml b/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_movie.xml
new file mode 100644
index 000000000..c69c3792a
--- /dev/null
+++ b/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_movie.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_search.xml b/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_search.xml
new file mode 100644
index 000000000..f28c5497f
--- /dev/null
+++ b/android/app/src/main/res/drawable-anydpi-v21/ic_shortcut_search.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_collection_foreground.xml b/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_collection_foreground.xml
index 45b1c8cb2..13e09005a 100644
--- a/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_collection_foreground.xml
+++ b/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_collection_foreground.xml
@@ -1,15 +1,16 @@
-
-
-
+ android:viewportHeight="108">
+
+
+
diff --git a/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_movie_foreground.xml b/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_movie_foreground.xml
index 0955cd1d5..84db2f541 100644
--- a/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_movie_foreground.xml
+++ b/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_movie_foreground.xml
@@ -1,15 +1,16 @@
-
-
-
+ android:viewportHeight="108">
+
+
+
diff --git a/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_search_foreground.xml b/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_search_foreground.xml
index fb2972b41..13f707135 100644
--- a/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_search_foreground.xml
+++ b/android/app/src/main/res/drawable-anydpi-v26/ic_shortcut_search_foreground.xml
@@ -1,15 +1,16 @@
-
-
-
+ android:viewportHeight="108">
+
+
+
diff --git a/android/app/src/main/res/drawable-v21/ic_shortcut_collection.xml b/android/app/src/main/res/drawable-v21/ic_shortcut_collection.xml
new file mode 100644
index 000000000..0f3548712
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/ic_shortcut_collection.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-v21/ic_shortcut_movie.xml b/android/app/src/main/res/drawable-v21/ic_shortcut_movie.xml
new file mode 100644
index 000000000..9d24cc9e2
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/ic_shortcut_movie.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-v21/ic_shortcut_search.xml b/android/app/src/main/res/drawable-v21/ic_shortcut_search.xml
new file mode 100644
index 000000000..5bd1ca0b2
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/ic_shortcut_search.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-v26/ic_shortcut_collection.xml b/android/app/src/main/res/drawable-v26/ic_shortcut_collection.xml
new file mode 100644
index 000000000..8ec076f9f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v26/ic_shortcut_collection.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable-v26/ic_shortcut_collection_foreground.xml b/android/app/src/main/res/drawable-v26/ic_shortcut_collection_foreground.xml
new file mode 100644
index 000000000..13e09005a
--- /dev/null
+++ b/android/app/src/main/res/drawable-v26/ic_shortcut_collection_foreground.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-v26/ic_shortcut_movie.xml b/android/app/src/main/res/drawable-v26/ic_shortcut_movie.xml
new file mode 100644
index 000000000..8789ba05f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v26/ic_shortcut_movie.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable-v26/ic_shortcut_movie_foreground.xml b/android/app/src/main/res/drawable-v26/ic_shortcut_movie_foreground.xml
new file mode 100644
index 000000000..84db2f541
--- /dev/null
+++ b/android/app/src/main/res/drawable-v26/ic_shortcut_movie_foreground.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable-v26/ic_shortcut_search.xml b/android/app/src/main/res/drawable-v26/ic_shortcut_search.xml
new file mode 100644
index 000000000..ab1fb94ae
--- /dev/null
+++ b/android/app/src/main/res/drawable-v26/ic_shortcut_search.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable-v26/ic_shortcut_search_foreground.xml b/android/app/src/main/res/drawable-v26/ic_shortcut_search_foreground.xml
new file mode 100644
index 000000000..13f707135
--- /dev/null
+++ b/android/app/src/main/res/drawable-v26/ic_shortcut_search_foreground.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection.xml
index e069568b3..8ec076f9f 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection_foreground.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection_foreground.xml
new file mode 100644
index 000000000..13e09005a
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_collection_foreground.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie.xml
index a31978c2d..8789ba05f 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie_foreground.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie_foreground.xml
new file mode 100644
index 000000000..84db2f541
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_movie_foreground.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search.xml
index 1ab11ea64..ab1fb94ae 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search_foreground.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search_foreground.xml
new file mode 100644
index 000000000..13f707135
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_shortcut_search_foreground.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
index 9a0f0bc25..6e3fbd50f 100644
--- a/android/app/src/main/res/values/colors.xml
+++ b/android/app/src/main/res/values/colors.xml
@@ -2,5 +2,6 @@
#FFFFFF
#FFFFFF
+ #455A64
#3f51b5
\ No newline at end of file