From f8337f6e3dc71902236faacb79aab17a522267aa Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 9 Aug 2021 21:45:09 +0900 Subject: [PATCH] info: check prop exists before querying owner package --- .../aves/channel/calls/MetadataHandler.kt | 20 +++++++++++++++++ lib/services/app_shortcut_service.dart | 4 +--- lib/services/metadata_service.dart | 22 +++++++++++++++++++ lib/widgets/viewer/info/basic_section.dart | 5 ++++- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt index bd9e7967c..af85b3467 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataHandler.kt @@ -5,6 +5,7 @@ import android.content.Context import android.database.Cursor import android.media.MediaMetadataRetriever import android.net.Uri +import android.os.Build import android.provider.MediaStore import android.util.Log import androidx.exifinterface.media.ExifInterface @@ -77,6 +78,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler { "getOverlayMetadata" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getOverlayMetadata) } "getMultiPageInfo" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getMultiPageInfo) } "getPanoramaInfo" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getPanoramaInfo) } + "hasContentResolverProp" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::hasContentResolverProp) } "getContentResolverProp" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getContentResolverProp) } else -> result.notImplemented() } @@ -681,6 +683,24 @@ class MetadataHandler(private val context: Context) : MethodCallHandler { result.error("getPanoramaInfo-empty", "failed to read XMP from uri=$uri", null) } + private fun hasContentResolverProp(call: MethodCall, result: MethodChannel.Result) { + val prop = call.argument("prop") + if (prop == null) { + result.error("hasContentResolverProp-args", "failed because of missing arguments", null) + return + } + + result.success( + when (prop) { + "owner_package_name" -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q + else -> { + result.error("hasContentResolverProp-unknown", "unknown property=$prop", null) + return + } + } + ) + } + private fun getContentResolverProp(call: MethodCall, result: MethodChannel.Result) { val mimeType = call.argument("mimeType") val uri = call.argument("uri")?.let { Uri.parse(it) } diff --git a/lib/services/app_shortcut_service.dart b/lib/services/app_shortcut_service.dart index 80a5b82b0..9d96312b5 100644 --- a/lib/services/app_shortcut_service.dart +++ b/lib/services/app_shortcut_service.dart @@ -13,9 +13,7 @@ class AppShortcutService { static bool? _canPin; static Future canPin() async { - if (_canPin != null) { - return SynchronousFuture(_canPin!); - } + if (_canPin != null) return SynchronousFuture(_canPin!); try { final result = await platform.invokeMethod('canPin'); diff --git a/lib/services/metadata_service.dart b/lib/services/metadata_service.dart index d3f329295..d6ab7c509 100644 --- a/lib/services/metadata_service.dart +++ b/lib/services/metadata_service.dart @@ -4,6 +4,7 @@ import 'package:aves/model/multipage.dart'; import 'package:aves/model/panorama.dart'; import 'package:aves/services/service_policy.dart'; import 'package:aves/services/services.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; abstract class MetadataService { @@ -18,6 +19,8 @@ abstract class MetadataService { Future getPanoramaInfo(AvesEntry entry); + Future hasContentResolverProp(String prop); + Future getContentResolverProp(AvesEntry entry, String prop); } @@ -137,6 +140,25 @@ class PlatformMetadataService implements MetadataService { return null; } + final Map _contentResolverProps = {}; + + @override + Future hasContentResolverProp(String prop) async { + var exists = _contentResolverProps[prop]; + if (exists != null) return SynchronousFuture(exists); + + try { + exists = await platform.invokeMethod('hasContentResolverProp', { + 'prop': prop, + }); + } on PlatformException catch (e, stack) { + await reportService.recordError(e, stack); + } + exists ??= false; + _contentResolverProps[prop] = exists; + return exists; + } + @override Future getContentResolverProp(AvesEntry entry, String prop) async { try { diff --git a/lib/widgets/viewer/info/basic_section.dart b/lib/widgets/viewer/info/basic_section.dart index 94a717100..5f0876519 100644 --- a/lib/widgets/viewer/info/basic_section.dart +++ b/lib/widgets/viewer/info/basic_section.dart @@ -135,6 +135,7 @@ class _OwnerPropState extends State { AvesEntry get entry => widget.entry; + static const ownerPackageNamePropKey = 'owner_package_name'; static const iconSize = 20.0; @override @@ -142,7 +143,9 @@ class _OwnerPropState extends State { super.initState(); final isMediaContent = entry.uri.startsWith('content://media/external/'); if (isMediaContent) { - _ownerPackageFuture = metadataService.getContentResolverProp(entry, 'owner_package_name'); + _ownerPackageFuture = metadataService.hasContentResolverProp(ownerPackageNamePropKey).then((exists) { + return exists ? metadataService.getContentResolverProp(entry, ownerPackageNamePropKey) : SynchronousFuture(null); + }); } else { _ownerPackageFuture = SynchronousFuture(null); }