diff --git a/android/app/src/main/java/deckers/thibault/aves/utils/MetadataHelper.java b/android/app/src/main/java/deckers/thibault/aves/utils/MetadataHelper.java deleted file mode 100644 index 21c601d99..000000000 --- a/android/app/src/main/java/deckers/thibault/aves/utils/MetadataHelper.java +++ /dev/null @@ -1,79 +0,0 @@ -package deckers.thibault.aves.utils; - -import androidx.annotation.Nullable; -import androidx.exifinterface.media.ExifInterface; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class MetadataHelper { - - // interpret EXIF code to angle (0, 90, 180 or 270 degrees) - public static int getOrientationDegreesForExifCode(int exifOrientation) { - switch (exifOrientation) { - case ExifInterface.ORIENTATION_ROTATE_180: // bottom, right side - return 180; - case ExifInterface.ORIENTATION_ROTATE_90: // right side, top - return 90; - case ExifInterface.ORIENTATION_ROTATE_270: // left side, bottom - return 270; - } - // all other orientations (regular, flipped...) default to an angle of 0 degree - return 0; - } - - // yyyyMMddTHHmmss(.sss)?(Z|+/-hhmm)? - public static long parseVideoMetadataDate(@Nullable String dateString) { - if (dateString == null) { - return 0; - } - - // optional sub-second - String subSecond = null; - Matcher subSecondMatcher = Pattern.compile("(\\d{6})(\\.\\d+)").matcher(dateString); - if (subSecondMatcher.find()) { - subSecond = subSecondMatcher.group(2).substring(1); - dateString = subSecondMatcher.replaceAll("$1"); - } - - // optional time zone - TimeZone timeZone = null; - Matcher timeZoneMatcher = Pattern.compile("(Z|[+-]\\d{4})$").matcher(dateString); - if (timeZoneMatcher.find()) { - timeZone = TimeZone.getTimeZone("GMT" + timeZoneMatcher.group().replaceAll("Z", "")); - dateString = timeZoneMatcher.replaceAll(""); - } - - Date date = null; - try { - DateFormat parser = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US); - parser.setTimeZone((timeZone != null) ? timeZone : TimeZone.getTimeZone("GMT")); - date = parser.parse(dateString); - } catch (ParseException e) { - // ignore - } - - if (date == null) { - return 0; - } - - long dateMillis = date.getTime(); - if (subSecond != null) { - try { - int millis = (int) (Double.parseDouble("." + subSecond) * 1000); - if (millis >= 0 && millis < 1000) { - dateMillis += millis; - } - } catch (NumberFormatException e) { - // ignore - } - } - return dateMillis; - } -} diff --git a/android/app/src/main/java/deckers/thibault/aves/utils/MimeTypes.java b/android/app/src/main/java/deckers/thibault/aves/utils/MimeTypes.java deleted file mode 100644 index debb8a3c3..000000000 --- a/android/app/src/main/java/deckers/thibault/aves/utils/MimeTypes.java +++ /dev/null @@ -1,19 +0,0 @@ -package deckers.thibault.aves.utils; - -public class MimeTypes { - public static final String IMAGE = "image"; - public static final String DNG = "image/x-adobe-dng"; // .dng - public static final String GIF = "image/gif"; - public static final String HEIC = "image/heic"; - public static final String HEIF = "image/heif"; - public static final String JPEG = "image/jpeg"; - public static final String PNG = "image/png"; - public static final String PSD = "image/x-photoshop"; // .psd - public static final String SVG = "image/svg+xml"; // .svg - public static final String WEBP = "image/webp"; - - public static final String VIDEO = "video"; - public static final String AVI = "video/avi"; - public static final String MP2T = "video/mp2t"; // .m2ts - public static final String MP4 = "video/mp4"; -} diff --git a/android/app/src/main/java/deckers/thibault/aves/utils/Utils.java b/android/app/src/main/java/deckers/thibault/aves/utils/Utils.java deleted file mode 100644 index 9dd458567..000000000 --- a/android/app/src/main/java/deckers/thibault/aves/utils/Utils.java +++ /dev/null @@ -1,54 +0,0 @@ -package deckers.thibault.aves.utils; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import java.util.regex.Pattern; - -public class Utils { - private static final int logTagMaxLength = 23; - private static final Pattern logTagPackagePattern = Pattern.compile("(\\w)(\\w*)\\."); - - public static String createLogTag(Class clazz) { - // shorten class name to "a.b.CccDdd" - String logTag = logTagPackagePattern.matcher(clazz.getName()).replaceAll("$1."); - if (logTag.length() > logTagMaxLength) { - // shorten class name to "a.b.CD" - String simpleName = clazz.getSimpleName(); - String shortSimpleName = simpleName.replaceAll("[a-z]", ""); - logTag = logTag.replace(simpleName, shortSimpleName); - if (logTag.length() > logTagMaxLength) { - // shorten class name to "CD" - logTag = shortSimpleName; - } - } - return logTag; - } - - public static void copyFile(final File source, final FileDescriptor descriptor) throws IOException { - try (FileInputStream inStream = new FileInputStream(source); FileOutputStream outStream = new FileOutputStream(descriptor)) { - final FileChannel inChannel = inStream.getChannel(); - final FileChannel outChannel = outStream.getChannel(); - final long size = inChannel.size(); - long position = 0; - while (position < size) { - position += inChannel.transferTo(position, 1024L * 1024L, outChannel); - } - } - } - - public static void copyFile(final File source, final File destination) throws IOException { - try (FileInputStream inStream = new FileInputStream(source); FileOutputStream outStream = new FileOutputStream(destination)) { - final FileChannel inChannel = inStream.getChannel(); - final FileChannel outChannel = outStream.getChannel(); - final long size = inChannel.size(); - long position = 0; - while (position < size) { - position += inChannel.transferTo(position, 1024L * 1024L, outChannel); - } - } - } -} \ No newline at end of file diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MetadataHelper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MetadataHelper.kt new file mode 100644 index 000000000..2c5d2ebb0 --- /dev/null +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MetadataHelper.kt @@ -0,0 +1,63 @@ +package deckers.thibault.aves.utils + +import androidx.exifinterface.media.ExifInterface +import java.text.DateFormat +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* +import java.util.regex.Pattern + +object MetadataHelper { + // interpret EXIF code to angle (0, 90, 180 or 270 degrees) + @JvmStatic + fun getOrientationDegreesForExifCode(exifOrientation: Int): Int = when (exifOrientation) { + ExifInterface.ORIENTATION_ROTATE_180 -> 180 + ExifInterface.ORIENTATION_ROTATE_90 -> 90 + ExifInterface.ORIENTATION_ROTATE_270 -> 270 + else -> 0 // all other orientations (regular, flipped...) default to an angle of 0 degree + } + + // yyyyMMddTHHmmss(.sss)?(Z|+/-hhmm)? + @JvmStatic + fun parseVideoMetadataDate(metadataDate: String?): Long { + var dateString = metadataDate ?: return 0 + + // optional sub-second + var subSecond: String? = null + val subSecondMatcher = Pattern.compile("(\\d{6})(\\.\\d+)").matcher(dateString) + if (subSecondMatcher.find()) { + subSecond = subSecondMatcher.group(2)?.substring(1) + dateString = subSecondMatcher.replaceAll("$1") + } + + // optional time zone + var timeZone: TimeZone? = null + val timeZoneMatcher = Pattern.compile("(Z|[+-]\\d{4})$").matcher(dateString) + if (timeZoneMatcher.find()) { + timeZone = TimeZone.getTimeZone("GMT" + timeZoneMatcher.group().replace("Z".toRegex(), "")) + dateString = timeZoneMatcher.replaceAll("") + } + + val date: Date = try { + val parser = SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US) + parser.timeZone = timeZone ?: TimeZone.getTimeZone("GMT") + parser.parse(dateString) + } catch (e: ParseException) { + // ignore + null + } ?: return 0 + + var dateMillis = date.time + if (subSecond != null) { + try { + val millis = (".$subSecond".toDouble() * 1000).toInt() + if (millis in 0..999) { + dateMillis += millis.toLong() + } + } catch (e: NumberFormatException) { + // ignore + } + } + return dateMillis + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt new file mode 100644 index 000000000..416e71994 --- /dev/null +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt @@ -0,0 +1,18 @@ +package deckers.thibault.aves.utils + +object MimeTypes { + const val IMAGE = "image" + const val DNG = "image/x-adobe-dng" // .dng + const val GIF = "image/gif" + const val HEIC = "image/heic" + const val HEIF = "image/heif" + const val JPEG = "image/jpeg" + const val PNG = "image/png" + const val PSD = "image/x-photoshop" // .psd + const val SVG = "image/svg+xml" // .svg + const val WEBP = "image/webp" + const val VIDEO = "video" + const val AVI = "video/avi" + const val MP2T = "video/mp2t" // .m2ts + const val MP4 = "video/mp4" +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/Utils.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/Utils.kt new file mode 100644 index 000000000..3c914314d --- /dev/null +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/Utils.kt @@ -0,0 +1,25 @@ +package deckers.thibault.aves.utils + +import java.util.regex.Pattern + +object Utils { + private const val LOG_TAG_MAX_LENGTH = 23 + private val LOG_TAG_PACKAGE_PATTERN = Pattern.compile("(\\w)(\\w*)\\.") + + @JvmStatic + fun createLogTag(clazz: Class<*>): String { + // shorten class name to "a.b.CccDdd" + var logTag = LOG_TAG_PACKAGE_PATTERN.matcher(clazz.name).replaceAll("$1.") + if (logTag.length > LOG_TAG_MAX_LENGTH) { + // shorten class name to "a.b.CD" + val simpleName = clazz.simpleName + val shortSimpleName = simpleName.replace("[a-z]".toRegex(), "") + logTag = logTag.replace(simpleName, shortSimpleName) + if (logTag.length > LOG_TAG_MAX_LENGTH) { + // shorten class name to "CD" + logTag = shortSimpleName + } + } + return logTag + } +} \ No newline at end of file