android 14

This commit is contained in:
Thibault Deckers 2023-06-11 19:28:59 +02:00
parent bd55ff2971
commit 55acf408d0
16 changed files with 38 additions and 64 deletions

View file

@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
### Changed
- target Android 14 (API 34)
- upgraded Flutter to stable v3.10.4
### Fixed

View file

@ -48,7 +48,7 @@ if (keystorePropertiesFile.exists()) {
android {
namespace 'deckers.thibault.aves'
compileSdk 33
compileSdk 34
ndkVersion flutter.ndkVersion
compileOptions {
@ -75,7 +75,7 @@ android {
// which implementation `DocumentBuilderImpl` is provided by the OS and is not customizable on Android,
// but the implementation on API <19 is not robust enough and fails to build XMP documents
minSdkVersion 19
targetSdkVersion 33
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
manifestPlaceholders = [googleApiKey: keystoreProperties["googleApiKey"] ?: "<NONE>",

View file

@ -15,6 +15,7 @@
TODO TLAD [Android 14 (API 34)] request/handle READ_MEDIA_VISUAL_USER_SELECTED permission
cf https://developer.android.com/about/versions/14/changes/partial-photo-video-access
-->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission

View file

@ -96,12 +96,7 @@ class SvgRegionFetcher internal constructor(
svg.renderToCanvas(canvas, renderOptions)
bitmap = Bitmap.createBitmap(bitmap, bleedX, bleedY, targetBitmapWidth, targetBitmapHeight)
if (bitmap != null) {
result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} else {
result.error("fetch-null", "failed to decode region for uri=$uri regionRect=$regionRect", null)
}
} catch (e: Exception) {
result.error("fetch-read-exception", "failed to initialize region decoder for uri=$uri regionRect=$regionRect", e.message)
}

View file

@ -36,7 +36,6 @@ fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): Ap
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong()))
} else {
@Suppress("deprecation")
getApplicationInfo(packageName, flags)
}
}
@ -45,7 +44,6 @@ fun PackageManager.queryIntentActivitiesCompat(intent: Intent, flags: Int): List
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(flags.toLong()))
} else {
@Suppress("deprecation")
queryIntentActivities(intent, flags)
}
}

View file

@ -1,13 +1,10 @@
package deckers.thibault.aves.utils
import android.app.ActivityManager
import android.app.Service
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.util.Log
import deckers.thibault.aves.utils.UriUtils.tryParseId
@ -24,19 +21,6 @@ object ContextUtils {
.build()
}
fun Context.isMyServiceRunning(serviceClass: Class<out Service>): Boolean {
val am = this.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
am ?: return false
@Suppress("deprecation")
return am.getRunningServices(Integer.MAX_VALUE).any { it.service.className == serviceClass.name }
}
// `flag`: `DocumentsContract.Document.FLAG_SUPPORTS_COPY`, etc.
fun Context.queryDocumentProviderFlag(docUri: Uri, flag: Int): Boolean {
val flags = queryContentPropValue(docUri, "", DocumentsContract.Document.COLUMN_FLAGS) as Long?
return if (flags != null) (flags.toInt() and flag) == flag else false
}
fun Context.queryContentPropValue(uri: Uri, mimeType: String, column: String): Any? {
var contentUri: Uri = uri
if (StorageUtils.isMediaStoreContentUri(uri)) {

View file

@ -11,6 +11,7 @@ import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.embedding.engine.loader.FlutterLoader
import io.flutter.view.FlutterCallbackInformation
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@ -60,7 +61,7 @@ object FlutterUtils {
suspend fun runOnUiThread(r: Runnable) {
val mainLooper = Looper.getMainLooper()
if (Looper.myLooper() != mainLooper) {
suspendCoroutine<Boolean> { cont ->
suspendCoroutine { cont: Continuation<Boolean> ->
Handler(mainLooper).post {
r.run()
cont.resume(true)

View file

@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.8.21'
agp_version = '8.0.1'
agp_version = '8.0.2'
glide_version = '4.15.1'
// AppGallery Connect plugin versions: https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550
// TODO TLAD AppGallery Connect plugin v1.9.0.300 does not support Gradle 8+

View file

@ -17,7 +17,7 @@ class AIcons {
static const brightnessMin = Icons.brightness_low_outlined;
static const brightnessMax = Icons.brightness_high_outlined;
static const checked = Icons.done_outlined;
static const count = MdiIcons.counter;
static final count = MdiIcons.counter;
static const counter = Icons.plus_one_outlined;
static const date = Icons.calendar_today_outlined;
static const dateByDay = Icons.today_outlined;
@ -42,11 +42,11 @@ class AIcons {
static const mainStorage = Icons.smartphone_outlined;
static const mimeType = Icons.code_outlined;
static const opacity = Icons.opacity;
static const privacy = MdiIcons.shieldAccountOutline;
static final privacy = MdiIcons.shieldAccountOutline;
static const rating = Icons.star_border_outlined;
static const ratingFull = Icons.star;
static const ratingRejected = MdiIcons.starMinusOutline;
static const ratingUnrated = MdiIcons.starOffOutline;
static final ratingRejected = MdiIcons.starMinusOutline;
static final ratingUnrated = MdiIcons.starOffOutline;
static const raw = Icons.raw_on_outlined;
static const shooting = Icons.camera_outlined;
static const removableStorage = Icons.sd_storage_outlined;
@ -56,7 +56,7 @@ class AIcons {
static const size = Icons.data_usage_outlined;
static const text = Icons.format_quote_outlined;
static const tag = Icons.local_offer_outlined;
static const tagUntagged = MdiIcons.tagOffOutline;
static final tagUntagged = MdiIcons.tagOffOutline;
static const volumeMin = Icons.volume_mute_outlined;
static const volumeMax = Icons.volume_up_outlined;
@ -79,35 +79,35 @@ class AIcons {
static const clear = Icons.clear_outlined;
static const clipboard = Icons.content_copy_outlined;
static const convert = Icons.transform_outlined;
static const convertToStillImage = MdiIcons.movieRemoveOutline;
static final convertToStillImage = MdiIcons.movieRemoveOutline;
static const copy = Icons.file_copy_outlined;
static const debug = Icons.whatshot_outlined;
static const delete = Icons.delete_outlined;
static const edit = Icons.edit_outlined;
static const emptyBin = Icons.delete_sweep_outlined;
static const export = Icons.open_with_outlined;
static const fileExport = MdiIcons.fileExportOutline;
static const fileImport = MdiIcons.fileImportOutline;
static final fileExport = MdiIcons.fileExportOutline;
static final fileImport = MdiIcons.fileImportOutline;
static const flip = Icons.flip_outlined;
static const favourite = Icons.favorite_border;
static const favouriteActive = Icons.favorite;
static const filter = MdiIcons.filterOutline;
static const filterOff = MdiIcons.filterOffOutline;
static final filter = MdiIcons.filterOutline;
static final filterOff = MdiIcons.filterOffOutline;
static const geoBounds = Icons.public_outlined;
static const goUp = Icons.arrow_upward_outlined;
static const hide = Icons.visibility_off_outlined;
static const info = Icons.info_outlined;
static const layers = Icons.layers_outlined;
static const map = Icons.map_outlined;
static const move = MdiIcons.fileMoveOutline;
static final move = MdiIcons.fileMoveOutline;
static const mute = Icons.volume_off_outlined;
static const unmute = Icons.volume_up_outlined;
static const name = Icons.abc_outlined;
static const newTier = Icons.fiber_new_outlined;
static const openOutside = Icons.open_in_new_outlined;
static const openVideo = MdiIcons.moviePlayOutline;
static final openVideo = MdiIcons.moviePlayOutline;
static const pin = Icons.push_pin_outlined;
static const unpin = MdiIcons.pinOffOutline;
static final unpin = MdiIcons.pinOffOutline;
static const play = Icons.play_arrow;
static const pause = Icons.pause;
static const print = Icons.print_outlined;
@ -123,10 +123,10 @@ class AIcons {
static const search = Icons.search_outlined;
static const select = Icons.select_all_outlined;
static const setAs = Icons.wallpaper_outlined;
static const setCover = MdiIcons.imageEditOutline;
static final setCover = MdiIcons.imageEditOutline;
static const share = Icons.share_outlined;
static const show = Icons.visibility_outlined;
static const showFullscreen = MdiIcons.arrowExpand;
static final showFullscreen = MdiIcons.arrowExpand;
static const slideshow = Icons.slideshow_outlined;
static const speed = Icons.speed_outlined;
static const stats = Icons.donut_small_outlined;
@ -136,7 +136,7 @@ class AIcons {
static const streamText = Icons.closed_caption_outlined;
static const vaultLock = Icons.lock_outline;
static const vaultAdd = Icons.enhanced_encryption_outlined;
static const vaultConfigure = MdiIcons.shieldLockOutline;
static final vaultConfigure = MdiIcons.shieldLockOutline;
static const videoSettings = Icons.video_settings_outlined;
static const view = Icons.grid_view_outlined;
static const viewerLock = Icons.lock_outline;
@ -176,6 +176,6 @@ class AIcons {
static const selected = Icons.check_circle_outline;
static const unselected = Icons.radio_button_unchecked;
static const github = MdiIcons.github;
static const legal = MdiIcons.scaleBalance;
static final github = MdiIcons.github;
static final legal = MdiIcons.scaleBalance;
}

View file

@ -19,7 +19,7 @@ class AppReference extends StatefulWidget {
static List<Widget> buildLinks(BuildContext context) {
final l10n = context.l10n;
return [
const LinkChip(
LinkChip(
leading: Icon(
AIcons.github,
size: 24,
@ -28,7 +28,7 @@ class AppReference extends StatefulWidget {
urlString: AppReference.avesGithub,
),
LinkChip(
leading: const Icon(
leading: Icon(
AIcons.legal,
size: 22,
),
@ -36,7 +36,7 @@ class AppReference extends StatefulWidget {
urlString: '${AppReference.avesGithub}/blob/main/LICENSE',
),
LinkChip(
leading: const Icon(
leading: Icon(
AIcons.privacy,
size: 22,
),

View file

@ -100,7 +100,7 @@ class TagIcon extends StatelessWidget {
factory TagIcon.tagged() => const TagIcon._private(icon: AIcons.tag);
factory TagIcon.untagged() => const TagIcon._private(icon: AIcons.tagUntagged);
factory TagIcon.untagged() => TagIcon._private(icon: AIcons.tagUntagged);
static const scale = .9;

View file

@ -171,7 +171,7 @@ class _TagEditorPageState extends State<TagEditorPage> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(AIcons.tagUntagged, color: untaggedColor),
Icon(AIcons.tagUntagged, color: untaggedColor),
const SizedBox(width: 8),
Text(
l10n.filterNoTagLabel,

View file

@ -61,11 +61,11 @@ class _SettingsMobilePageState extends State<SettingsMobilePage> with FeedbackMi
return [
PopupMenuItem(
value: SettingsAction.export,
child: MenuRow(text: context.l10n.settingsActionExport, icon: const Icon(AIcons.fileExport)),
child: MenuRow(text: context.l10n.settingsActionExport, icon: Icon(AIcons.fileExport)),
),
PopupMenuItem(
value: SettingsAction.import,
child: MenuRow(text: context.l10n.settingsActionImport, icon: const Icon(AIcons.fileImport)),
child: MenuRow(text: context.l10n.settingsActionImport, icon: Icon(AIcons.fileImport)),
),
];
},

View file

@ -77,7 +77,7 @@ class _WelcomePageState extends State<WelcomePage> {
Padding(
padding: const EdgeInsets.all(16),
child: LinkChip(
leading: const Icon(
leading: Icon(
AIcons.privacy,
size: 22,
),

View file

@ -798,18 +798,18 @@ packages:
dependency: "direct main"
description:
name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "0.2.0"
material_design_icons_flutter:
dependency: "direct main"
description:
name: material_design_icons_flutter
sha256: "8ef8562d16e747b2d93e5da5c2508931588939c5c00ebc8e2768e803db7dfd3c"
sha256: "6f986b7a51f3ad4c00e33c5c84e8de1bdd140489bbcdc8b66fc1283dad4dea5a"
url: "https://pub.dev"
source: hosted
version: "6.0.7096"
version: "7.0.7296"
meta:
dependency: transitive
description:

View file

@ -128,12 +128,6 @@ dev_dependencies:
shared_preferences_platform_interface:
test:
dependency_overrides:
# as of Flutter beta v3.10.0-1.5.pre, `flutter_driver`
# constrains `material_color_utilities` to v0.2.0, which
# constrains `dynamic_color` to v1.6.4, which is incompatible with AGP8
material_color_utilities: ^0.5.0
flutter:
assets:
- assets/