Enable sharing media directly from Tusky (#852)
* Extract duplicated code into BaseActivity * Migrate MediaUtils to kotlin * Migrate ViewVideoActivity to kotlin * Migrate ViewMediaActivity to kotlin * Initial media sharing functionality * Address code review feedback * Make share icon match * Address code review feedback
This commit is contained in:
parent
ab601c4566
commit
0bca94b94e
18 changed files with 785 additions and 690 deletions
|
|
@ -27,6 +27,10 @@ import java.io.FileOutputStream;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import static com.keylesspalace.tusky.util.MediaUtilsKt.calculateInSampleSize;
|
||||
import static com.keylesspalace.tusky.util.MediaUtilsKt.getImageOrientation;
|
||||
import static com.keylesspalace.tusky.util.MediaUtilsKt.reorientBitmap;
|
||||
|
||||
/**
|
||||
* Reduces the file size of images to fit under a given limit by resizing them, maintaining both
|
||||
* aspect ratio and orientation.
|
||||
|
|
@ -65,7 +69,7 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
|
|||
BitmapFactory.decodeStream(inputStream, null, options);
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
// Get EXIF data, for orientation info.
|
||||
int orientation = MediaUtils.getImageOrientation(uri, contentResolver);
|
||||
int orientation = getImageOrientation(uri, contentResolver);
|
||||
/* Unfortunately, there isn't a determined worst case compression ratio for image
|
||||
* formats. So, the only way to tell if they're too big is to compress them and
|
||||
* test, and keep trying at smaller sizes. The initial estimate should be good for
|
||||
|
|
@ -84,7 +88,7 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
|
|||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
options.inSampleSize = MediaUtils.calculateInSampleSize(options, scaledImageSize, scaledImageSize);
|
||||
options.inSampleSize = calculateInSampleSize(options, scaledImageSize, scaledImageSize);
|
||||
options.inJustDecodeBounds = false;
|
||||
Bitmap scaledBitmap;
|
||||
try {
|
||||
|
|
@ -97,7 +101,7 @@ public class DownsizeImageTask extends AsyncTask<Uri, Void, Boolean> {
|
|||
if (scaledBitmap == null) {
|
||||
return false;
|
||||
}
|
||||
Bitmap reorientedBitmap = MediaUtils.reorientBitmap(scaledBitmap, orientation);
|
||||
Bitmap reorientedBitmap = reorientBitmap(scaledBitmap, orientation);
|
||||
if (reorientedBitmap == null) {
|
||||
scaledBitmap.recycle();
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,260 +0,0 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.media.ThumbnailUtils;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.Px;
|
||||
import android.support.media.ExifInterface;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Class with helper methods for obtaining and resizing media files
|
||||
*/
|
||||
public class MediaUtils {
|
||||
private static final String TAG = "MediaUtils";
|
||||
public static final int MEDIA_SIZE_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* Copies the entire contents of the given stream into a byte array and returns it. Beware of
|
||||
* OutOfMemoryError for streams of unknown size.
|
||||
*/
|
||||
@Nullable
|
||||
public static byte[] inputStreamGetBytes(InputStream stream) {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int read;
|
||||
byte[] data = new byte[16384];
|
||||
try {
|
||||
while ((read = stream.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, read);
|
||||
}
|
||||
buffer.flush();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the size of the media represented by the given URI, assuming it is openable and
|
||||
* the ContentResolver is able to resolve it.
|
||||
*
|
||||
* @return the size of the media in bytes or {@link MediaUtils#MEDIA_SIZE_UNKNOWN}
|
||||
*/
|
||||
public static long getMediaSize(@NonNull ContentResolver contentResolver, @Nullable Uri uri) {
|
||||
if(uri == null) return MEDIA_SIZE_UNKNOWN;
|
||||
long mediaSize;
|
||||
Cursor cursor;
|
||||
try {
|
||||
cursor = contentResolver.query(uri, null, null, null, null);
|
||||
} catch (SecurityException e) {
|
||||
return MEDIA_SIZE_UNKNOWN;
|
||||
}
|
||||
if (cursor != null) {
|
||||
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
|
||||
cursor.moveToFirst();
|
||||
mediaSize = cursor.getLong(sizeIndex);
|
||||
cursor.close();
|
||||
} else {
|
||||
mediaSize = MEDIA_SIZE_UNKNOWN;
|
||||
}
|
||||
return mediaSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Bitmap getSampledBitmap(ContentResolver contentResolver, Uri uri, @Px int reqWidth, @Px int reqHeight) {
|
||||
// First decode with inJustDecodeBounds=true to check dimensions
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
InputStream stream;
|
||||
try {
|
||||
stream = contentResolver.openInputStream(uri);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
BitmapFactory.decodeStream(stream, null, options);
|
||||
|
||||
IOUtils.closeQuietly(stream);
|
||||
|
||||
// Calculate inSampleSize
|
||||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
|
||||
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false;
|
||||
try {
|
||||
stream = contentResolver.openInputStream(uri);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
|
||||
int orientation = getImageOrientation(uri, contentResolver);
|
||||
return reorientBitmap(bitmap, orientation);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.e(TAG, "OutOfMemoryError while trying to get sampled Bitmap", e);
|
||||
return null;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Bitmap getImageThumbnail(ContentResolver contentResolver, Uri uri, @Px int thumbnailSize) {
|
||||
Bitmap source = getSampledBitmap(contentResolver, uri, thumbnailSize, thumbnailSize);
|
||||
if(source == null) {
|
||||
return null;
|
||||
}
|
||||
return ThumbnailUtils.extractThumbnail(source, thumbnailSize, thumbnailSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Bitmap getVideoThumbnail(Context context, Uri uri, @Px int thumbnailSize) {
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(context, uri);
|
||||
Bitmap source = retriever.getFrameAtTime();
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return ThumbnailUtils.extractThumbnail(source, thumbnailSize, thumbnailSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
|
||||
}
|
||||
|
||||
public static long getImageSquarePixels(ContentResolver contentResolver, Uri uri) throws FileNotFoundException {
|
||||
InputStream input = contentResolver.openInputStream(uri);
|
||||
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(input, null, options);
|
||||
|
||||
IOUtils.closeQuietly(input);
|
||||
|
||||
return (long) options.outWidth * options.outHeight;
|
||||
}
|
||||
|
||||
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
||||
// Raw height and width of image
|
||||
final int height = options.outHeight;
|
||||
final int width = options.outWidth;
|
||||
int inSampleSize = 1;
|
||||
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
|
||||
final int halfHeight = height / 2;
|
||||
final int halfWidth = width / 2;
|
||||
|
||||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
|
||||
// height and width larger than the requested height and width.
|
||||
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
|
||||
inSampleSize *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Bitmap reorientBitmap(Bitmap bitmap, int orientation) {
|
||||
Matrix matrix = new Matrix();
|
||||
switch (orientation) {
|
||||
default:
|
||||
case ExifInterface.ORIENTATION_NORMAL: {
|
||||
return bitmap;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: {
|
||||
matrix.setScale(-1, 1);
|
||||
break;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_ROTATE_180: {
|
||||
matrix.setRotate(180);
|
||||
break;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_FLIP_VERTICAL: {
|
||||
matrix.setRotate(180);
|
||||
matrix.postScale(-1, 1);
|
||||
break;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_TRANSPOSE: {
|
||||
matrix.setRotate(90);
|
||||
matrix.postScale(-1, 1);
|
||||
break;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_ROTATE_90: {
|
||||
matrix.setRotate(90);
|
||||
break;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_TRANSVERSE: {
|
||||
matrix.setRotate(-90);
|
||||
matrix.postScale(-1, 1);
|
||||
break;
|
||||
}
|
||||
case ExifInterface.ORIENTATION_ROTATE_270: {
|
||||
matrix.setRotate(-90);
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
|
||||
bitmap.getHeight(), matrix, true);
|
||||
if (!bitmap.sameAs(result)) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
return result;
|
||||
} catch (OutOfMemoryError e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getImageOrientation(Uri uri, ContentResolver contentResolver) {
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = contentResolver.openInputStream(uri);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
return ExifInterface.ORIENTATION_UNDEFINED;
|
||||
}
|
||||
if (inputStream == null) {
|
||||
return ExifInterface.ORIENTATION_UNDEFINED;
|
||||
}
|
||||
ExifInterface exifInterface;
|
||||
try {
|
||||
exifInterface = new ExifInterface(inputStream);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
return ExifInterface.ORIENTATION_UNDEFINED;
|
||||
}
|
||||
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
|
||||
ExifInterface.ORIENTATION_NORMAL);
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
return orientation;
|
||||
}
|
||||
}
|
||||
245
app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.kt
Normal file
245
app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.kt
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.util
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.media.ThumbnailUtils
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.support.annotation.Px
|
||||
import android.support.media.ExifInterface
|
||||
import android.util.Log
|
||||
import java.io.*
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Helper methods for obtaining and resizing media files
|
||||
*/
|
||||
private const val TAG = "MediaUtils"
|
||||
private const val MEDIA_TEMP_PREFIX = "Tusky_Share_Media"
|
||||
const val MEDIA_SIZE_UNKNOWN = -1L
|
||||
|
||||
/**
|
||||
* Fetches the size of the media represented by the given URI, assuming it is openable and
|
||||
* the ContentResolver is able to resolve it.
|
||||
*
|
||||
* @return the size of the media in bytes or {@link MediaUtils#MEDIA_SIZE_UNKNOWN}
|
||||
*/
|
||||
fun getMediaSize(contentResolver: ContentResolver, uri: Uri?): Long {
|
||||
if(uri == null) {
|
||||
return MEDIA_SIZE_UNKNOWN
|
||||
}
|
||||
|
||||
var mediaSize = MEDIA_SIZE_UNKNOWN
|
||||
val cursor: Cursor?
|
||||
try {
|
||||
cursor = contentResolver.query(uri, null, null, null, null)
|
||||
} catch (e: SecurityException) {
|
||||
return MEDIA_SIZE_UNKNOWN
|
||||
}
|
||||
if (cursor != null) {
|
||||
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||
cursor.moveToFirst()
|
||||
mediaSize = cursor.getLong(sizeIndex)
|
||||
cursor.close()
|
||||
}
|
||||
return mediaSize
|
||||
}
|
||||
|
||||
fun getSampledBitmap(contentResolver: ContentResolver, uri: Uri, @Px reqWidth: Int, @Px reqHeight: Int): Bitmap? {
|
||||
// First decode with inJustDecodeBounds=true to check dimensions
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
var stream: InputStream?
|
||||
try {
|
||||
stream = contentResolver.openInputStream(uri)
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.w(TAG, e)
|
||||
return null
|
||||
}
|
||||
|
||||
BitmapFactory.decodeStream(stream, null, options)
|
||||
|
||||
IOUtils.closeQuietly(stream)
|
||||
|
||||
// Calculate inSampleSize
|
||||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
|
||||
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false
|
||||
return try {
|
||||
stream = contentResolver.openInputStream(uri)
|
||||
val bitmap = BitmapFactory.decodeStream(stream, null, options)
|
||||
val orientation = getImageOrientation(uri, contentResolver)
|
||||
reorientBitmap(bitmap, orientation)
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.w(TAG, e)
|
||||
null
|
||||
} catch (e: OutOfMemoryError) {
|
||||
Log.e(TAG, "OutOfMemoryError while trying to get sampled Bitmap", e)
|
||||
null
|
||||
} finally {
|
||||
IOUtils.closeQuietly(stream)
|
||||
}
|
||||
}
|
||||
|
||||
fun getImageThumbnail(contentResolver: ContentResolver, uri: Uri, @Px thumbnailSize: Int): Bitmap? {
|
||||
val source = getSampledBitmap(contentResolver, uri, thumbnailSize, thumbnailSize) ?: return null
|
||||
return ThumbnailUtils.extractThumbnail(source, thumbnailSize, thumbnailSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
|
||||
}
|
||||
|
||||
fun getVideoThumbnail(context: Context, uri: Uri, @Px thumbnailSize: Int): Bitmap? {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(context, uri)
|
||||
val source = retriever.frameAtTime ?: return null
|
||||
return ThumbnailUtils.extractThumbnail(source, thumbnailSize, thumbnailSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
fun getImageSquarePixels(contentResolver: ContentResolver, uri: Uri): Long {
|
||||
val input = contentResolver.openInputStream(uri)
|
||||
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeStream(input, null, options)
|
||||
|
||||
IOUtils.closeQuietly(input)
|
||||
|
||||
return (options.outWidth * options.outHeight).toLong()
|
||||
}
|
||||
|
||||
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
|
||||
// Raw height and width of image
|
||||
val height = options.outHeight
|
||||
val width = options.outWidth
|
||||
var inSampleSize = 1
|
||||
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
|
||||
val halfHeight = height / 2
|
||||
val halfWidth = width / 2
|
||||
|
||||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
|
||||
// height and width larger than the requested height and width.
|
||||
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
|
||||
inSampleSize *= 2
|
||||
}
|
||||
}
|
||||
|
||||
return inSampleSize
|
||||
}
|
||||
|
||||
fun reorientBitmap(bitmap: Bitmap?, orientation: Int): Bitmap? {
|
||||
val matrix = Matrix()
|
||||
when (orientation) {
|
||||
ExifInterface.ORIENTATION_NORMAL -> return bitmap
|
||||
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.setScale(-1.0f, 1.0f)
|
||||
ExifInterface.ORIENTATION_ROTATE_180 -> matrix.setRotate(180.0f)
|
||||
ExifInterface.ORIENTATION_FLIP_VERTICAL -> {
|
||||
matrix.setRotate(180.0f)
|
||||
matrix.postScale(-1.0f, 1.0f)
|
||||
}
|
||||
ExifInterface.ORIENTATION_TRANSPOSE -> {
|
||||
matrix.setRotate(90.0f)
|
||||
matrix.postScale(-1.0f, 1.0f)
|
||||
}
|
||||
ExifInterface.ORIENTATION_ROTATE_90 -> matrix.setRotate(90.0f)
|
||||
ExifInterface.ORIENTATION_TRANSVERSE -> {
|
||||
matrix.setRotate(-90.0f)
|
||||
matrix.postScale(-1.0f, 1.0f)
|
||||
}
|
||||
ExifInterface.ORIENTATION_ROTATE_270 -> matrix.setRotate(-90.0f)
|
||||
else -> return bitmap
|
||||
}
|
||||
|
||||
if (bitmap == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
val result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width,
|
||||
bitmap.height, matrix, true)
|
||||
if (!bitmap.sameAs(result)) {
|
||||
bitmap.recycle()
|
||||
}
|
||||
result
|
||||
} catch (e: OutOfMemoryError) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getImageOrientation(uri: Uri, contentResolver: ContentResolver): Int {
|
||||
val inputStream: InputStream?
|
||||
try {
|
||||
inputStream = contentResolver.openInputStream(uri)
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.w(TAG, e)
|
||||
return ExifInterface.ORIENTATION_UNDEFINED
|
||||
}
|
||||
if (inputStream == null) {
|
||||
return ExifInterface.ORIENTATION_UNDEFINED
|
||||
}
|
||||
val exifInterface: ExifInterface
|
||||
try {
|
||||
exifInterface = ExifInterface(inputStream)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
IOUtils.closeQuietly(inputStream)
|
||||
return ExifInterface.ORIENTATION_UNDEFINED
|
||||
}
|
||||
val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
||||
IOUtils.closeQuietly(inputStream)
|
||||
return orientation
|
||||
}
|
||||
|
||||
fun deleteStaleCachedMedia(mediaDirectory: File?) {
|
||||
if (mediaDirectory == null || !mediaDirectory.exists()) {
|
||||
// Nothing to do
|
||||
return
|
||||
}
|
||||
|
||||
val twentyfourHoursAgo = Calendar.getInstance()
|
||||
twentyfourHoursAgo.add(Calendar.HOUR, -24)
|
||||
val unixTime = twentyfourHoursAgo.timeInMillis
|
||||
|
||||
val files = mediaDirectory.listFiles{ file -> unixTime > file.lastModified() && file.name.contains(MEDIA_TEMP_PREFIX) }
|
||||
if (files == null || files.isEmpty()) {
|
||||
// Nothing to do
|
||||
return
|
||||
}
|
||||
|
||||
for (file in files) {
|
||||
try {
|
||||
file.delete()
|
||||
} catch (se: SecurityException) {
|
||||
Log.e(TAG, "Error removing stale cached media")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTemporaryMediaFilename(extension: String): String {
|
||||
return "${MEDIA_TEMP_PREFIX}_${SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())}.$extension"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue