migration to Kotlin (WIP)
This commit is contained in:
parent
bdd18d9e71
commit
b315ebe724
6 changed files with 106 additions and 152 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue