moved debug related functions

This commit is contained in:
Thibault Deckers 2020-12-02 11:09:51 +09:00
parent f205075ac4
commit 4f7287de02
9 changed files with 322 additions and 277 deletions

View file

@ -41,6 +41,7 @@ class MainActivity : FlutterActivity() {
MethodChannel(messenger, ImageFileHandler.CHANNEL).setMethodCallHandler(ImageFileHandler(this)) MethodChannel(messenger, ImageFileHandler.CHANNEL).setMethodCallHandler(ImageFileHandler(this))
MethodChannel(messenger, MetadataHandler.CHANNEL).setMethodCallHandler(MetadataHandler(this)) MethodChannel(messenger, MetadataHandler.CHANNEL).setMethodCallHandler(MetadataHandler(this))
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this)) MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
MethodChannel(messenger, DebugHandler.CHANNEL).setMethodCallHandler(DebugHandler(this))
StreamsChannel(messenger, ImageByteStreamHandler.CHANNEL).setStreamHandlerFactory { args -> ImageByteStreamHandler(this, args) } StreamsChannel(messenger, ImageByteStreamHandler.CHANNEL).setStreamHandlerFactory { args -> ImageByteStreamHandler(this, args) }
StreamsChannel(messenger, ImageOpStreamHandler.CHANNEL).setStreamHandlerFactory { args -> ImageOpStreamHandler(this, args) } StreamsChannel(messenger, ImageOpStreamHandler.CHANNEL).setStreamHandlerFactory { args -> ImageOpStreamHandler(this, args) }

View file

@ -29,7 +29,6 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
when (call.method) { when (call.method) {
"getAppIcon" -> GlobalScope.launch { getAppIcon(call, Coresult(result)) } "getAppIcon" -> GlobalScope.launch { getAppIcon(call, Coresult(result)) }
"getAppNames" -> GlobalScope.launch { getAppNames(Coresult(result)) } "getAppNames" -> GlobalScope.launch { getAppNames(Coresult(result)) }
"getEnv" -> result.success(System.getenv())
"edit" -> { "edit" -> {
val title = call.argument<String>("title") val title = call.argument<String>("title")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) } val uri = call.argument<String>("uri")?.let { Uri.parse(it) }

View file

@ -0,0 +1,222 @@
package deckers.thibault.aves.channel.calls
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.exifinterface.media.ExifInterface
import com.drew.imaging.ImageMetadataReader
import com.drew.metadata.file.FileTypeDirectory
import deckers.thibault.aves.metadata.ExifInterfaceHelper
import deckers.thibault.aves.metadata.MediaMetadataRetrieverHelper
import deckers.thibault.aves.utils.LogUtils
import deckers.thibault.aves.utils.MimeTypes.isImage
import deckers.thibault.aves.utils.MimeTypes.isSupportedByExifInterface
import deckers.thibault.aves.utils.MimeTypes.isSupportedByMetadataExtractor
import deckers.thibault.aves.utils.MimeTypes.isVideo
import deckers.thibault.aves.utils.StorageUtils
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.IOException
import java.util.*
class DebugHandler(private val context: Context) : MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"getEnv" -> result.success(System.getenv())
"getBitmapFactoryInfo" -> GlobalScope.launch { getBitmapFactoryInfo(call, Coresult(result)) }
"getContentResolverMetadata" -> GlobalScope.launch { getContentResolverMetadata(call, Coresult(result)) }
"getExifInterfaceMetadata" -> GlobalScope.launch { getExifInterfaceMetadata(call, Coresult(result)) }
"getMediaMetadataRetrieverMetadata" -> GlobalScope.launch { getMediaMetadataRetrieverMetadata(call, Coresult(result)) }
"getMetadataExtractorSummary" -> GlobalScope.launch { getMetadataExtractorSummary(call, Coresult(result)) }
else -> result.notImplemented()
}
}
private fun getBitmapFactoryInfo(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (uri == null) {
result.error("getBitmapDecoderInfo-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String>()
try {
StorageUtils.openInputStream(context, uri)?.use { input ->
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeStream(input, null, options)
options.outMimeType?.let { metadataMap["MimeType"] = it }
options.outWidth.takeIf { it >= 0 }?.let { metadataMap["Width"] = it.toString() }
options.outHeight.takeIf { it >= 0 }?.let { metadataMap["Height"] = it.toString() }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
options.outColorSpace?.let { metadataMap["ColorSpace"] = it.toString() }
options.outConfig?.let { metadataMap["Config"] = it.toString() }
}
}
} catch (e: IOException) {
// ignore
}
result.success(metadataMap)
}
private fun getContentResolverMetadata(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (mimeType == null || uri == null) {
result.error("getContentResolverMetadata-args", "failed because of missing arguments", null)
return
}
var contentUri: Uri = uri
if (uri.scheme == ContentResolver.SCHEME_CONTENT && MediaStore.AUTHORITY.equals(uri.host, ignoreCase = true)) {
try {
val id = ContentUris.parseId(uri)
contentUri = when {
isImage(mimeType) -> ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
isVideo(mimeType) -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
else -> uri
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentUri = MediaStore.setRequireOriginal(contentUri)
}
} catch (e: NumberFormatException) {
// ignore
}
}
val cursor = context.contentResolver.query(contentUri, null, null, null, null)
if (cursor != null && cursor.moveToFirst()) {
val metadataMap = HashMap<String, Any?>()
val columnCount = cursor.columnCount
val columnNames = cursor.columnNames
for (i in 0 until columnCount) {
val key = columnNames[i]
try {
metadataMap[key] = when (cursor.getType(i)) {
Cursor.FIELD_TYPE_NULL -> null
Cursor.FIELD_TYPE_INTEGER -> cursor.getLong(i)
Cursor.FIELD_TYPE_FLOAT -> cursor.getFloat(i)
Cursor.FIELD_TYPE_STRING -> cursor.getString(i)
Cursor.FIELD_TYPE_BLOB -> cursor.getBlob(i)
else -> null
}
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get value for key=$key", e)
}
}
cursor.close()
result.success(metadataMap)
} else {
result.error("getContentResolverMetadata-null", "failed to get cursor for contentUri=$contentUri", null)
}
}
private fun getExifInterfaceMetadata(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
if (mimeType == null || uri == null) {
result.error("getExifInterfaceMetadata-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String?>()
if (isSupportedByExifInterface(mimeType, sizeBytes, strict = false)) {
try {
StorageUtils.openInputStream(context, uri)?.use { input ->
val exif = ExifInterface(input)
for (tag in ExifInterfaceHelper.allTags.keys.filter { exif.hasAttribute(it) }) {
metadataMap[tag] = exif.getAttribute(tag)
}
}
} catch (e: Exception) {
// ExifInterface initialization can fail with a RuntimeException
// caused by an internal MediaMetadataRetriever failure
result.error("getExifInterfaceMetadata-failure", "failed to get exif for uri=$uri", e.message)
return
}
}
result.success(metadataMap)
}
private fun getMediaMetadataRetrieverMetadata(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (uri == null) {
result.error("getMediaMetadataRetrieverMetadata-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String>()
val retriever = StorageUtils.openMetadataRetriever(context, uri)
if (retriever != null) {
try {
for ((code, name) in MediaMetadataRetrieverHelper.allKeys) {
retriever.extractMetadata(code)?.let { metadataMap[name] = it }
}
} catch (e: Exception) {
// ignore
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release()
}
}
result.success(metadataMap)
}
private fun getMetadataExtractorSummary(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
if (mimeType == null || uri == null) {
result.error("getMetadataExtractorSummary-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String>()
if (isSupportedByMetadataExtractor(mimeType, sizeBytes)) {
try {
StorageUtils.openInputStream(context, uri)?.use { input ->
val metadata = ImageMetadataReader.readMetadata(input, sizeBytes ?: -1)
metadataMap["mimeType"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir ->
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)
} else ""
}
metadataMap["typeName"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir ->
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_TYPE_NAME)) {
dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_TYPE_NAME)
} else ""
}
for (dir in metadata.directories) {
val dirName = dir.name ?: ""
var index = 0
while (metadataMap.containsKey("$dirName ($index)")) index++
var value = "${dir.tagCount} tags"
dir.parent?.let { value += ", parent: ${it.name}" }
metadataMap["$dirName ($index)"] = value
}
}
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
} catch (e: NoClassDefFoundError) {
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
}
}
result.success(metadataMap)
}
companion object {
private val LOG_TAG = LogUtils.createTag(DebugHandler::class.java)
const val CHANNEL = "deckers.thibault/aves/debug"
}
}

View file

@ -1,14 +1,8 @@
package deckers.thibault.aves.channel.calls package deckers.thibault.aves.channel.calls
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context import android.content.Context
import android.database.Cursor
import android.graphics.BitmapFactory
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import android.net.Uri import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log import android.util.Log
import androidx.exifinterface.media.ExifInterface import androidx.exifinterface.media.ExifInterface
import com.adobe.internal.xmp.XMPException import com.adobe.internal.xmp.XMPException
@ -25,7 +19,6 @@ import com.drew.metadata.file.FileTypeDirectory
import com.drew.metadata.gif.GifAnimationDirectory import com.drew.metadata.gif.GifAnimationDirectory
import com.drew.metadata.webp.WebpDirectory import com.drew.metadata.webp.WebpDirectory
import com.drew.metadata.xmp.XmpDirectory import com.drew.metadata.xmp.XmpDirectory
import deckers.thibault.aves.metadata.ExifInterfaceHelper
import deckers.thibault.aves.metadata.ExifInterfaceHelper.describeAll import deckers.thibault.aves.metadata.ExifInterfaceHelper.describeAll
import deckers.thibault.aves.metadata.ExifInterfaceHelper.getSafeDateMillis import deckers.thibault.aves.metadata.ExifInterfaceHelper.getSafeDateMillis
import deckers.thibault.aves.metadata.ExifInterfaceHelper.getSafeDouble import deckers.thibault.aves.metadata.ExifInterfaceHelper.getSafeDouble
@ -51,7 +44,6 @@ import deckers.thibault.aves.utils.BitmapUtils
import deckers.thibault.aves.utils.BitmapUtils.getBytes import deckers.thibault.aves.utils.BitmapUtils.getBytes
import deckers.thibault.aves.utils.LogUtils import deckers.thibault.aves.utils.LogUtils
import deckers.thibault.aves.utils.MimeTypes import deckers.thibault.aves.utils.MimeTypes
import deckers.thibault.aves.utils.MimeTypes.isImage
import deckers.thibault.aves.utils.MimeTypes.isMultimedia import deckers.thibault.aves.utils.MimeTypes.isMultimedia
import deckers.thibault.aves.utils.MimeTypes.isSupportedByExifInterface import deckers.thibault.aves.utils.MimeTypes.isSupportedByExifInterface
import deckers.thibault.aves.utils.MimeTypes.isSupportedByMetadataExtractor import deckers.thibault.aves.utils.MimeTypes.isSupportedByMetadataExtractor
@ -63,7 +55,6 @@ import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.IOException
import java.util.* import java.util.*
import kotlin.math.roundToLong import kotlin.math.roundToLong
@ -73,11 +64,6 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
"getAllMetadata" -> GlobalScope.launch { getAllMetadata(call, Coresult(result)) } "getAllMetadata" -> GlobalScope.launch { getAllMetadata(call, Coresult(result)) }
"getCatalogMetadata" -> GlobalScope.launch { getCatalogMetadata(call, Coresult(result)) } "getCatalogMetadata" -> GlobalScope.launch { getCatalogMetadata(call, Coresult(result)) }
"getOverlayMetadata" -> GlobalScope.launch { getOverlayMetadata(call, Coresult(result)) } "getOverlayMetadata" -> GlobalScope.launch { getOverlayMetadata(call, Coresult(result)) }
"getContentResolverMetadata" -> GlobalScope.launch { getContentResolverMetadata(call, Coresult(result)) }
"getExifInterfaceMetadata" -> GlobalScope.launch { getExifInterfaceMetadata(call, Coresult(result)) }
"getMediaMetadataRetrieverMetadata" -> GlobalScope.launch { getMediaMetadataRetrieverMetadata(call, Coresult(result)) }
"getBitmapFactoryInfo" -> GlobalScope.launch { getBitmapFactoryInfo(call, Coresult(result)) }
"getMetadataExtractorSummary" -> GlobalScope.launch { getMetadataExtractorSummary(call, Coresult(result)) }
"getEmbeddedPictures" -> GlobalScope.launch { getEmbeddedPictures(call, Coresult(result)) } "getEmbeddedPictures" -> GlobalScope.launch { getEmbeddedPictures(call, Coresult(result)) }
"getExifThumbnails" -> GlobalScope.launch { getExifThumbnails(call, Coresult(result)) } "getExifThumbnails" -> GlobalScope.launch { getExifThumbnails(call, Coresult(result)) }
"getXmpThumbnails" -> GlobalScope.launch { getXmpThumbnails(call, Coresult(result)) } "getXmpThumbnails" -> GlobalScope.launch { getXmpThumbnails(call, Coresult(result)) }
@ -446,180 +432,6 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
result.success(metadataMap) result.success(metadataMap)
} }
private fun getContentResolverMetadata(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (mimeType == null || uri == null) {
result.error("getContentResolverMetadata-args", "failed because of missing arguments", null)
return
}
var contentUri: Uri = uri
if (uri.scheme == ContentResolver.SCHEME_CONTENT && MediaStore.AUTHORITY.equals(uri.host, ignoreCase = true)) {
try {
val id = ContentUris.parseId(uri)
contentUri = when {
isImage(mimeType) -> ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
isVideo(mimeType) -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
else -> uri
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentUri = MediaStore.setRequireOriginal(contentUri)
}
} catch (e: NumberFormatException) {
// ignore
}
}
val cursor = context.contentResolver.query(contentUri, null, null, null, null)
if (cursor != null && cursor.moveToFirst()) {
val metadataMap = HashMap<String, Any?>()
val columnCount = cursor.columnCount
val columnNames = cursor.columnNames
for (i in 0 until columnCount) {
val key = columnNames[i]
try {
metadataMap[key] = when (cursor.getType(i)) {
Cursor.FIELD_TYPE_NULL -> null
Cursor.FIELD_TYPE_INTEGER -> cursor.getLong(i)
Cursor.FIELD_TYPE_FLOAT -> cursor.getFloat(i)
Cursor.FIELD_TYPE_STRING -> cursor.getString(i)
Cursor.FIELD_TYPE_BLOB -> cursor.getBlob(i)
else -> null
}
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get value for key=$key", e)
}
}
cursor.close()
result.success(metadataMap)
} else {
result.error("getContentResolverMetadata-null", "failed to get cursor for contentUri=$contentUri", null)
}
}
private fun getExifInterfaceMetadata(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
if (mimeType == null || uri == null) {
result.error("getExifInterfaceMetadata-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String?>()
if (isSupportedByExifInterface(mimeType, sizeBytes, strict = false)) {
try {
StorageUtils.openInputStream(context, uri)?.use { input ->
val exif = ExifInterface(input)
for (tag in ExifInterfaceHelper.allTags.keys.filter { exif.hasAttribute(it) }) {
metadataMap[tag] = exif.getAttribute(tag)
}
}
} catch (e: Exception) {
// ExifInterface initialization can fail with a RuntimeException
// caused by an internal MediaMetadataRetriever failure
result.error("getExifInterfaceMetadata-failure", "failed to get exif for uri=$uri", e.message)
return
}
}
result.success(metadataMap)
}
private fun getMediaMetadataRetrieverMetadata(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (uri == null) {
result.error("getMediaMetadataRetrieverMetadata-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String>()
val retriever = StorageUtils.openMetadataRetriever(context, uri)
if (retriever != null) {
try {
for ((code, name) in MediaMetadataRetrieverHelper.allKeys) {
retriever.extractMetadata(code)?.let { metadataMap[name] = it }
}
} catch (e: Exception) {
// ignore
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release()
}
}
result.success(metadataMap)
}
private fun getBitmapFactoryInfo(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (uri == null) {
result.error("getBitmapDecoderInfo-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String>()
try {
StorageUtils.openInputStream(context, uri)?.use { input ->
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeStream(input, null, options)
options.outMimeType?.let { metadataMap["MimeType"] = it }
options.outWidth.takeIf { it >= 0 }?.let { metadataMap["Width"] = it.toString() }
options.outHeight.takeIf { it >= 0 }?.let { metadataMap["Height"] = it.toString() }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
options.outColorSpace?.let { metadataMap["ColorSpace"] = it.toString() }
options.outConfig?.let { metadataMap["Config"] = it.toString() }
}
}
} catch (e: IOException) {
// ignore
}
result.success(metadataMap)
}
private fun getMetadataExtractorSummary(call: MethodCall, result: MethodChannel.Result) {
val mimeType = call.argument<String>("mimeType")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
val sizeBytes = call.argument<Number>("sizeBytes")?.toLong()
if (mimeType == null || uri == null) {
result.error("getMetadataExtractorSummary-args", "failed because of missing arguments", null)
return
}
val metadataMap = HashMap<String, String>()
if (isSupportedByMetadataExtractor(mimeType, sizeBytes)) {
try {
StorageUtils.openInputStream(context, uri)?.use { input ->
val metadata = ImageMetadataReader.readMetadata(input, sizeBytes ?: -1)
metadataMap["mimeType"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir ->
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)
} else ""
}
metadataMap["typeName"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir ->
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_TYPE_NAME)) {
dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_TYPE_NAME)
} else ""
}
for (dir in metadata.directories) {
val dirName = dir.name ?: ""
var index = 0
while (metadataMap.containsKey("$dirName ($index)")) index++
var value = "${dir.tagCount} tags"
dir.parent?.let { value += ", parent: ${it.name}" }
metadataMap["$dirName ($index)"] = value
}
}
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
} catch (e: NoClassDefFoundError) {
Log.w(LOG_TAG, "failed to get metadata by metadata-extractor for uri=$uri", e)
}
}
result.success(metadataMap)
}
private fun getEmbeddedPictures(call: MethodCall, result: MethodChannel.Result) { private fun getEmbeddedPictures(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) } val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
if (uri == null) { if (uri == null) {

View file

@ -31,16 +31,6 @@ class AndroidAppService {
return null; return null;
} }
static Future<Map> getEnv() async {
try {
final result = await platform.invokeMethod('getEnv');
return result as Map;
} on PlatformException catch (e) {
debugPrint('getEnv failed with code=${e.code}, exception=${e.message}, details=${e.details}}');
}
return {};
}
static Future<bool> edit(String uri, String mimeType) async { static Future<bool> edit(String uri, String mimeType) async {
try { try {
return await platform.invokeMethod('edit', <String, dynamic>{ return await platform.invokeMethod('edit', <String, dynamic>{

View file

@ -0,0 +1,91 @@
import 'dart:typed_data';
import 'package:aves/model/image_entry.dart';
import 'package:aves/model/image_metadata.dart';
import 'package:aves/services/service_policy.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
class AndroidDebugService {
static const platform = MethodChannel('deckers.thibault/aves/debug');
static Future<Map> getEnv() async {
try {
final result = await platform.invokeMethod('getEnv');
return result as Map;
} on PlatformException catch (e) {
debugPrint('getEnv failed with code=${e.code}, exception=${e.message}, details=${e.details}}');
}
return {};
}
static Future<Map> getBitmapFactoryInfo(ImageEntry entry) async {
try {
// return map with all data available when decoding image bounds with `BitmapFactory`
final result = await platform.invokeMethod('getBitmapFactoryInfo', <String, dynamic>{
'uri': entry.uri,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getBitmapFactoryInfo failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getContentResolverMetadata(ImageEntry entry) async {
try {
// return map with all data available from the content resolver
final result = await platform.invokeMethod('getContentResolverMetadata', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getContentResolverMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getExifInterfaceMetadata(ImageEntry entry) async {
try {
// return map with all data available from the `ExifInterface` library
final result = await platform.invokeMethod('getExifInterfaceMetadata', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
'sizeBytes': entry.sizeBytes,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getExifInterfaceMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getMediaMetadataRetrieverMetadata(ImageEntry entry) async {
try {
// return map with all data available from `MediaMetadataRetriever`
final result = await platform.invokeMethod('getMediaMetadataRetrieverMetadata', <String, dynamic>{
'uri': entry.uri,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getMediaMetadataRetrieverMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getMetadataExtractorSummary(ImageEntry entry) async {
try {
// return map with the mime type and tag count for each directory found by `metadata-extractor`
final result = await platform.invokeMethod('getMetadataExtractorSummary', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
'sizeBytes': entry.sizeBytes,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getMetadataExtractorSummary failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
}

View file

@ -80,76 +80,6 @@ class MetadataService {
return null; return null;
} }
static Future<Map> getBitmapFactoryInfo(ImageEntry entry) async {
try {
// return map with all data available when decoding image bounds with `BitmapFactory`
final result = await platform.invokeMethod('getBitmapFactoryInfo', <String, dynamic>{
'uri': entry.uri,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getBitmapFactoryInfo failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getContentResolverMetadata(ImageEntry entry) async {
try {
// return map with all data available from the content resolver
final result = await platform.invokeMethod('getContentResolverMetadata', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getContentResolverMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getExifInterfaceMetadata(ImageEntry entry) async {
try {
// return map with all data available from the `ExifInterface` library
final result = await platform.invokeMethod('getExifInterfaceMetadata', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
'sizeBytes': entry.sizeBytes,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getExifInterfaceMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getMediaMetadataRetrieverMetadata(ImageEntry entry) async {
try {
// return map with all data available from `MediaMetadataRetriever`
final result = await platform.invokeMethod('getMediaMetadataRetrieverMetadata', <String, dynamic>{
'uri': entry.uri,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getMediaMetadataRetrieverMetadata failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<Map> getMetadataExtractorSummary(ImageEntry entry) async {
try {
// return map with the mime type and tag count for each directory found by `metadata-extractor`
final result = await platform.invokeMethod('getMetadataExtractorSummary', <String, dynamic>{
'mimeType': entry.mimeType,
'uri': entry.uri,
'sizeBytes': entry.sizeBytes,
}) as Map;
return result;
} on PlatformException catch (e) {
debugPrint('getMetadataExtractorSummary failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return {};
}
static Future<List<Uint8List>> getEmbeddedPictures(String uri) async { static Future<List<Uint8List>> getEmbeddedPictures(String uri) async {
try { try {
final result = await platform.invokeMethod('getEmbeddedPictures', <String, dynamic>{ final result = await platform.invokeMethod('getEmbeddedPictures', <String, dynamic>{

View file

@ -1,6 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:aves/services/android_app_service.dart'; import 'package:aves/services/android_debug_service.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart'; import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/fullscreen/info/common.dart'; import 'package:aves/widgets/fullscreen/info/common.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -16,7 +16,7 @@ class _DebugAndroidEnvironmentSectionState extends State<DebugAndroidEnvironment
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loader = AndroidAppService.getEnv(); _loader = AndroidDebugService.getEnv();
} }
@override @override

View file

@ -2,7 +2,7 @@ import 'dart:collection';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/services/metadata_service.dart'; import 'package:aves/services/android_debug_service.dart';
import 'package:aves/utils/constants.dart'; import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart'; import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/fullscreen/info/common.dart'; import 'package:aves/widgets/fullscreen/info/common.dart';
@ -33,11 +33,11 @@ class _MetadataTabState extends State<MetadataTab> {
} }
void _loadMetadata() { void _loadMetadata() {
_bitmapFactoryLoader = MetadataService.getBitmapFactoryInfo(entry); _bitmapFactoryLoader = AndroidDebugService.getBitmapFactoryInfo(entry);
_contentResolverMetadataLoader = MetadataService.getContentResolverMetadata(entry); _contentResolverMetadataLoader = AndroidDebugService.getContentResolverMetadata(entry);
_exifInterfaceMetadataLoader = MetadataService.getExifInterfaceMetadata(entry); _exifInterfaceMetadataLoader = AndroidDebugService.getExifInterfaceMetadata(entry);
_mediaMetadataLoader = MetadataService.getMediaMetadataRetrieverMetadata(entry); _mediaMetadataLoader = AndroidDebugService.getMediaMetadataRetrieverMetadata(entry);
_metadataExtractorLoader = MetadataService.getMetadataExtractorSummary(entry); _metadataExtractorLoader = AndroidDebugService.getMetadataExtractorSummary(entry);
setState(() {}); setState(() {});
} }