don’t scall images to a 0 width or height

This commit is contained in:
Daniel Gultsch 2018-05-07 11:13:46 +02:00
parent 7ca719b8be
commit 78b56bb904
3 changed files with 320 additions and 318 deletions

View file

@ -77,12 +77,299 @@ public class FileBackend {
this.mXmppConnectionService = service; this.mXmppConnectionService = service;
} }
private static boolean isInDirectoryThatShouldNotBeScanned(Context context, File file) {
return isInDirectoryThatShouldNotBeScanned(context, file.getAbsolutePath());
}
public static boolean isInDirectoryThatShouldNotBeScanned(Context context, String path) {
for (String type : new String[]{RecordingActivity.STORAGE_DIRECTORY_TYPE_NAME, "Files"}) {
if (path.startsWith(getConversationsDirectory(context, type))) {
return true;
}
}
return false;
}
public static long getFileSize(Context context, Uri uri) {
try {
final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
long size = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
cursor.close();
return size;
} else {
return -1;
}
} catch (Exception e) {
return -1;
}
}
public static boolean allFilesUnderSize(Context context, List<Uri> uris, long max) {
if (max <= 0) {
Log.d(Config.LOGTAG, "server did not report max file size for http upload");
return true; //exception to be compatible with HTTP Upload < v0.2
}
for (Uri uri : uris) {
String mime = context.getContentResolver().getType(uri);
if (mime != null && mime.startsWith("video/")) {
try {
Dimensions dimensions = FileBackend.getVideoDimensions(context, uri);
if (dimensions.getMin() > 720) {
Log.d(Config.LOGTAG, "do not consider video file with min width larger than 720 for size check");
continue;
}
} catch (NotAVideoFile notAVideoFile) {
//ignore and fall through
}
}
if (FileBackend.getFileSize(context, uri) > max) {
Log.d(Config.LOGTAG, "not all files are under " + max + " bytes. suggesting falling back to jingle");
return false;
}
}
return true;
}
public static String getConversationsDirectory(Context context, final String type) {
if (Config.ONLY_INTERNAL_STORAGE) {
return context.getFilesDir().getAbsolutePath() + "/" + type + "/";
} else {
return getAppMediaDirectory(context) + context.getString(R.string.app_name) + " " + type + "/";
}
}
public static String getAppMediaDirectory(Context context) {
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + context.getString(R.string.app_name) + "/Media/";
}
public static String getConversationsLogsDirectory() {
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/Conversations/";
}
private static Bitmap rotate(Bitmap bitmap, int degree) {
if (degree == 0) {
return bitmap;
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(degree);
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
return result;
}
public static boolean isPathBlacklisted(String path) {
final String androidDataPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/";
return path.startsWith(androidDataPath);
}
private static Paint createAntiAliasingPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
return paint;
}
private static String getTakePhotoPath() {
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/";
}
public static Uri getUriForFile(Context context, File file) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || Config.ONLY_INTERNAL_STORAGE) {
try {
return FileProvider.getUriForFile(context, getAuthority(context), file);
} catch (IllegalArgumentException e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
throw new SecurityException(e);
} else {
return Uri.fromFile(file);
}
}
} else {
return Uri.fromFile(file);
}
}
public static String getAuthority(Context context) {
return context.getPackageName() + FILE_PROVIDER;
}
public static Uri getIndexableTakePhotoUri(Uri original) {
if (Config.ONLY_INTERNAL_STORAGE || "file".equals(original.getScheme())) {
return original;
} else {
List<String> segments = original.getPathSegments();
return Uri.parse("file://" + getTakePhotoPath() + segments.get(segments.size() - 1));
}
}
private static boolean hasAlpha(final Bitmap bitmap) {
for (int x = 0; x < bitmap.getWidth(); ++x) {
for (int y = 0; y < bitmap.getWidth(); ++y) {
if (Color.alpha(bitmap.getPixel(x, y)) < 255) {
return true;
}
}
}
return false;
}
private static int calcSampleSize(File image, int size) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(image.getAbsolutePath(), options);
return calcSampleSize(options, size);
}
public static int calcSampleSize(BitmapFactory.Options options, int size) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
if (height > size || width > size) {
int halfHeight = height / 2;
int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > size
&& (halfWidth / inSampleSize) > size) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
private static Dimensions getVideoDimensions(Context context, Uri uri) throws NotAVideoFile {
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
try {
mediaMetadataRetriever.setDataSource(context, uri);
} catch (RuntimeException e) {
throw new NotAVideoFile(e);
}
return getVideoDimensions(mediaMetadataRetriever);
}
private static Dimensions getVideoDimensionsOfFrame(MediaMetadataRetriever mediaMetadataRetriever) {
Bitmap bitmap = null;
try {
bitmap = mediaMetadataRetriever.getFrameAtTime();
return new Dimensions(bitmap.getHeight(), bitmap.getWidth());
} catch (Exception e) {
return null;
} finally {
if (bitmap != null) {
bitmap.recycle();
;
}
}
}
private static Dimensions getVideoDimensions(MediaMetadataRetriever metadataRetriever) throws NotAVideoFile {
String hasVideo = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
if (hasVideo == null) {
throw new NotAVideoFile();
}
Dimensions dimensions = getVideoDimensionsOfFrame(metadataRetriever);
if (dimensions != null) {
return dimensions;
}
int rotation = extractRotationFromMediaRetriever(metadataRetriever);
boolean rotated = rotation == 90 || rotation == 270;
int height;
try {
String h = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
height = Integer.parseInt(h);
} catch (Exception e) {
height = -1;
}
int width;
try {
String w = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
width = Integer.parseInt(w);
} catch (Exception e) {
width = -1;
}
metadataRetriever.release();
Log.d(Config.LOGTAG, "extracted video dims " + width + "x" + height);
return rotated ? new Dimensions(width, height) : new Dimensions(height, width);
}
private static int extractRotationFromMediaRetriever(MediaMetadataRetriever metadataRetriever) {
String r = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
try {
return Integer.parseInt(r);
} catch (Exception e) {
return 0;
}
}
public static void close(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
}
public static void close(Socket socket) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
public static boolean weOwnFile(Context context, Uri uri) {
if (uri == null || !ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
return false;
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return fileIsInFilesDir(context, uri);
} else {
return weOwnFileLollipop(uri);
}
}
/**
* This is more than hacky but probably way better than doing nothing
* Further 'optimizations' might contain to get the parents of CacheDir and NoBackupDir
* and check against those as well
*/
private static boolean fileIsInFilesDir(Context context, Uri uri) {
try {
final String haystack = context.getFilesDir().getParentFile().getCanonicalPath();
final String needle = new File(uri.getPath()).getCanonicalPath();
return needle.startsWith(haystack);
} catch (IOException e) {
return false;
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean weOwnFileLollipop(Uri uri) {
try {
File file = new File(uri.getPath());
FileDescriptor fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY).getFileDescriptor();
StructStat st = Os.fstat(fd);
return st.st_uid == android.os.Process.myUid();
} catch (FileNotFoundException e) {
return false;
} catch (Exception e) {
return true;
}
}
private void createNoMedia(File diretory) { private void createNoMedia(File diretory) {
final File noMedia = new File(diretory,".nomedia"); final File noMedia = new File(diretory, ".nomedia");
if (!noMedia.exists()) { if (!noMedia.exists()) {
try { try {
if (!noMedia.createNewFile()) { if (!noMedia.createNewFile()) {
Log.d(Config.LOGTAG,"created nomedia file "+noMedia.getAbsolutePath()); Log.d(Config.LOGTAG, "created nomedia file " + noMedia.getAbsolutePath());
} }
} catch (Exception e) { } catch (Exception e) {
Log.d(Config.LOGTAG, "could not create nomedia file"); Log.d(Config.LOGTAG, "could not create nomedia file");
@ -100,19 +387,6 @@ public class FileBackend {
} }
} }
private static boolean isInDirectoryThatShouldNotBeScanned(Context context, File file) {
return isInDirectoryThatShouldNotBeScanned(context, file.getAbsolutePath());
}
public static boolean isInDirectoryThatShouldNotBeScanned(Context context, String path) {
for(String type : new String[]{RecordingActivity.STORAGE_DIRECTORY_TYPE_NAME, "Files"}) {
if (path.startsWith(getConversationsDirectory(context, type))) {
return true;
}
}
return false;
}
public boolean deleteFile(Message message) { public boolean deleteFile(Message message) {
File file = getFile(message); File file = getFile(message);
if (file.delete()) { if (file.delete()) {
@ -159,82 +433,27 @@ public class FileBackend {
} }
} }
public static long getFileSize(Context context, Uri uri) {
try {
final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
long size = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
cursor.close();
return size;
} else {
return -1;
}
} catch (Exception e) {
return -1;
}
}
public static boolean allFilesUnderSize(Context context, List<Uri> uris, long max) {
if (max <= 0) {
Log.d(Config.LOGTAG, "server did not report max file size for http upload");
return true; //exception to be compatible with HTTP Upload < v0.2
}
for (Uri uri : uris) {
String mime = context.getContentResolver().getType(uri);
if (mime != null && mime.startsWith("video/")) {
try {
Dimensions dimensions = FileBackend.getVideoDimensions(context, uri);
if (dimensions.getMin() > 720) {
Log.d(Config.LOGTAG, "do not consider video file with min width larger than 720 for size check");
continue;
}
} catch (NotAVideoFile notAVideoFile) {
//ignore and fall through
}
}
if (FileBackend.getFileSize(context, uri) > max) {
Log.d(Config.LOGTAG, "not all files are under " + max + " bytes. suggesting falling back to jingle");
return false;
}
}
return true;
}
public String getConversationsDirectory(final String type) { public String getConversationsDirectory(final String type) {
return getConversationsDirectory(mXmppConnectionService, type); return getConversationsDirectory(mXmppConnectionService, type);
} }
public static String getConversationsDirectory(Context context, final String type) { private Bitmap resize(final Bitmap originalBitmap, int size) throws IOException {
if (Config.ONLY_INTERNAL_STORAGE) {
return context.getFilesDir().getAbsolutePath() + "/" + type + "/";
} else {
return getAppMediaDirectory(context)+context.getString(R.string.app_name)+" " + type + "/";
}
}
public static String getAppMediaDirectory(Context context) {
return Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+context.getString(R.string.app_name)+"/Media/";
}
public static String getConversationsLogsDirectory() {
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/Conversations/";
}
public Bitmap resize(Bitmap originalBitmap, int size) {
int w = originalBitmap.getWidth(); int w = originalBitmap.getWidth();
int h = originalBitmap.getHeight(); int h = originalBitmap.getHeight();
if (Math.max(w, h) > size) { if (w <= 0 || h <= 0) {
throw new IOException("Decoded bitmap reported bounds smaller 0");
} else if (Math.max(w, h) > size) {
int scalledW; int scalledW;
int scalledH; int scalledH;
if (w <= h) { if (w <= h) {
scalledW = (int) (w / ((double) h / size)); scalledW = Math.max((int) (w / ((double) h / size)), 1);
scalledH = size; scalledH = size;
} else { } else {
scalledW = size; scalledW = size;
scalledH = (int) (h / ((double) w / size)); scalledH = Math.max((int) (h / ((double) w / size)), 1);
} }
Bitmap result = Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true); final Bitmap result = Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true);
if (originalBitmap != null && !originalBitmap.isRecycled()) { if (!originalBitmap.isRecycled()) {
originalBitmap.recycle(); originalBitmap.recycle();
} }
return result; return result;
@ -243,22 +462,6 @@ public class FileBackend {
} }
} }
private static Bitmap rotate(Bitmap bitmap, int degree) {
if (degree == 0) {
return bitmap;
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(degree);
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
return result;
}
public boolean useImageAsIs(Uri uri) { public boolean useImageAsIs(Uri uri) {
String path = getOriginalPath(uri); String path = getOriginalPath(uri);
if (path == null || isPathBlacklisted(path)) { if (path == null || isPathBlacklisted(path)) {
@ -282,11 +485,6 @@ public class FileBackend {
} }
} }
public static boolean isPathBlacklisted(String path) {
final String androidDataPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/";
return path.startsWith(androidDataPath);
}
public String getOriginalPath(Uri uri) { public String getOriginalPath(Uri uri) {
return FileUtils.getPath(mXmppConnectionService, uri); return FileUtils.getPath(mXmppConnectionService, uri);
} }
@ -332,7 +530,7 @@ public class FileBackend {
Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage (mime=" + mime + ")"); Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage (mime=" + mime + ")");
String extension = MimeUtils.guessExtensionFromMimeType(mime); String extension = MimeUtils.guessExtensionFromMimeType(mime);
if (extension == null) { if (extension == null) {
Log.d(Config.LOGTAG,"extension from mime type was null"); Log.d(Config.LOGTAG, "extension from mime type was null");
extension = getExtensionFromUri(uri); extension = getExtensionFromUri(uri);
} }
if ("ogg".equals(extension) && type != null && type.startsWith("audio/")) { if ("ogg".equals(extension) && type != null && type.startsWith("audio/")) {
@ -360,7 +558,7 @@ public class FileBackend {
if (filename == null) { if (filename == null) {
final List<String> segments = uri.getPathSegments(); final List<String> segments = uri.getPathSegments();
if (segments.size() > 0) { if (segments.size() > 0) {
filename = segments.get(segments.size() -1); filename = segments.get(segments.size() - 1);
} }
} }
int pos = filename == null ? -1 : filename.lastIndexOf('.'); int pos = filename == null ? -1 : filename.lastIndexOf('.');
@ -463,7 +661,7 @@ public class FileBackend {
} }
} }
public Bitmap getThumbnail(Message message, int size, boolean cacheOnly) throws FileNotFoundException { public Bitmap getThumbnail(Message message, int size, boolean cacheOnly) throws IOException {
final String uuid = message.getUuid(); final String uuid = message.getUuid();
final LruCache<String, Bitmap> cache = mXmppConnectionService.getBitmapCache(); final LruCache<String, Bitmap> cache = mXmppConnectionService.getBitmapCache();
Bitmap thumbnail = cache.get(uuid); Bitmap thumbnail = cache.get(uuid);
@ -519,14 +717,6 @@ public class FileBackend {
canvas.drawBitmap(overlay, null, dst, createAntiAliasingPaint()); canvas.drawBitmap(overlay, null, dst, createAntiAliasingPaint());
} }
private static Paint createAntiAliasingPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
return paint;
}
private Bitmap getVideoPreview(File file, int size) { private Bitmap getVideoPreview(File file, int size) {
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever(); MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
Bitmap frame; Bitmap frame;
@ -535,7 +725,7 @@ public class FileBackend {
frame = metadataRetriever.getFrameAtTime(0); frame = metadataRetriever.getFrameAtTime(0);
metadataRetriever.release(); metadataRetriever.release();
frame = resize(frame, size); frame = resize(frame, size);
} catch (RuntimeException e) { } catch (IOException | RuntimeException e) {
frame = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); frame = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
frame.eraseColor(0xff000000); frame.eraseColor(0xff000000);
} }
@ -543,10 +733,6 @@ public class FileBackend {
return frame; return frame;
} }
private static String getTakePhotoPath() {
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/";
}
public Uri getTakePhotoUri() { public Uri getTakePhotoUri() {
File file; File file;
if (Config.ONLY_INTERNAL_STORAGE) { if (Config.ONLY_INTERNAL_STORAGE) {
@ -558,35 +744,6 @@ public class FileBackend {
return getUriForFile(mXmppConnectionService, file); return getUriForFile(mXmppConnectionService, file);
} }
public static Uri getUriForFile(Context context, File file) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || Config.ONLY_INTERNAL_STORAGE) {
try {
return FileProvider.getUriForFile(context, getAuthority(context), file);
} catch (IllegalArgumentException e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
throw new SecurityException(e);
} else {
return Uri.fromFile(file);
}
}
} else {
return Uri.fromFile(file);
}
}
public static String getAuthority(Context context) {
return context.getPackageName() + FILE_PROVIDER;
}
public static Uri getIndexableTakePhotoUri(Uri original) {
if (Config.ONLY_INTERNAL_STORAGE || "file".equals(original.getScheme())) {
return original;
} else {
List<String> segments = original.getPathSegments();
return Uri.parse("file://" + getTakePhotoPath() + segments.get(segments.size() - 1));
}
}
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) { public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
Bitmap bm = cropCenterSquare(image, size); Bitmap bm = cropCenterSquare(image, size);
if (bm == null) { if (bm == null) {
@ -601,17 +758,6 @@ public class FileBackend {
return getPepAvatar(bm, format, 100); return getPepAvatar(bm, format, 100);
} }
private static boolean hasAlpha(final Bitmap bitmap) {
for (int x = 0; x < bitmap.getWidth(); ++x) {
for (int y = 0; y < bitmap.getWidth(); ++y) {
if (Color.alpha(bitmap.getPixel(x, y)) < 255) {
return true;
}
}
}
return false;
}
private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) { private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
try { try {
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
@ -698,12 +844,12 @@ public class FileBackend {
} else { } else {
file = new File(mXmppConnectionService.getCacheDir().getAbsolutePath() + "/" + UUID.randomUUID().toString()); file = new File(mXmppConnectionService.getCacheDir().getAbsolutePath() + "/" + UUID.randomUUID().toString());
if (file.getParentFile().mkdirs()) { if (file.getParentFile().mkdirs()) {
Log.d(Config.LOGTAG,"created cache directory"); Log.d(Config.LOGTAG, "created cache directory");
} }
OutputStream os = null; OutputStream os = null;
try { try {
if (!file.createNewFile()) { if (!file.createNewFile()) {
Log.d(Config.LOGTAG,"unable to create temporary file "+file.getAbsolutePath()); Log.d(Config.LOGTAG, "unable to create temporary file " + file.getAbsolutePath());
} }
os = new FileOutputStream(file); os = new FileOutputStream(file);
MessageDigest digest = MessageDigest.getInstance("SHA-1"); MessageDigest digest = MessageDigest.getInstance("SHA-1");
@ -717,17 +863,17 @@ public class FileBackend {
if (sha1sum.equals(avatar.sha1sum)) { if (sha1sum.equals(avatar.sha1sum)) {
File outputFile = new File(getAvatarPath(avatar.getFilename())); File outputFile = new File(getAvatarPath(avatar.getFilename()));
if (outputFile.getParentFile().mkdirs()) { if (outputFile.getParentFile().mkdirs()) {
Log.d(Config.LOGTAG,"created avatar directory"); Log.d(Config.LOGTAG, "created avatar directory");
} }
String filename = getAvatarPath(avatar.getFilename()); String filename = getAvatarPath(avatar.getFilename());
if (!file.renameTo(new File(filename))) { if (!file.renameTo(new File(filename))) {
Log.d(Config.LOGTAG,"unable to rename "+file.getAbsolutePath()+" to "+outputFile); Log.d(Config.LOGTAG, "unable to rename " + file.getAbsolutePath() + " to " + outputFile);
return false; return false;
} }
} else { } else {
Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner); Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner);
if (!file.delete()) { if (!file.delete()) {
Log.d(Config.LOGTAG,"unable to delete temporary file"); Log.d(Config.LOGTAG, "unable to delete temporary file");
} }
return false; return false;
} }
@ -846,30 +992,6 @@ public class FileBackend {
return calcSampleSize(options, size); return calcSampleSize(options, size);
} }
private static int calcSampleSize(File image, int size) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(image.getAbsolutePath(), options);
return calcSampleSize(options, size);
}
public static int calcSampleSize(BitmapFactory.Options options, int size) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
if (height > size || width > size) {
int halfHeight = height / 2;
int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > size
&& (halfWidth / inSampleSize) > size) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public void updateFileParams(Message message) { public void updateFileParams(Message message) {
updateFileParams(message, null); updateFileParams(message, null);
} }
@ -942,67 +1064,19 @@ public class FileBackend {
return getVideoDimensions(metadataRetriever); return getVideoDimensions(metadataRetriever);
} }
private static Dimensions getVideoDimensions(Context context, Uri uri) throws NotAVideoFile { public Bitmap getAvatar(String avatar, int size) {
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); if (avatar == null) {
try {
mediaMetadataRetriever.setDataSource(context, uri);
} catch (RuntimeException e) {
throw new NotAVideoFile(e);
}
return getVideoDimensions(mediaMetadataRetriever);
}
private static Dimensions getVideoDimensionsOfFrame(MediaMetadataRetriever mediaMetadataRetriever) {
Bitmap bitmap = null;
try {
bitmap = mediaMetadataRetriever.getFrameAtTime();
return new Dimensions(bitmap.getHeight(), bitmap.getWidth());
} catch (Exception e) {
return null; return null;
} finally {
if (bitmap != null) {
bitmap.recycle();;
}
} }
Bitmap bm = cropCenter(getAvatarUri(avatar), size, size);
if (bm == null) {
return null;
}
return bm;
} }
private static Dimensions getVideoDimensions(MediaMetadataRetriever metadataRetriever) throws NotAVideoFile { public boolean isFileAvailable(Message message) {
String hasVideo = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO); return getFile(message).exists();
if (hasVideo == null) {
throw new NotAVideoFile();
}
Dimensions dimensions = getVideoDimensionsOfFrame(metadataRetriever);
if (dimensions != null) {
return dimensions;
}
int rotation = extractRotationFromMediaRetriever(metadataRetriever);
boolean rotated = rotation == 90 || rotation == 270;
int height;
try {
String h = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
height = Integer.parseInt(h);
} catch (Exception e) {
height = -1;
}
int width;
try {
String w = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
width = Integer.parseInt(w);
} catch (Exception e) {
width = -1;
}
metadataRetriever.release();
Log.d(Config.LOGTAG, "extracted video dims " + width + "x" + height);
return rotated ? new Dimensions(width, height) : new Dimensions(height, width);
}
private static int extractRotationFromMediaRetriever(MediaMetadataRetriever metadataRetriever) {
String r = metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
try {
return Integer.parseInt(r);
} catch (Exception e) {
return 0;
}
} }
private static class Dimensions { private static class Dimensions {
@ -1045,78 +1119,4 @@ public class FileBackend {
return resId; return resId;
} }
} }
public Bitmap getAvatar(String avatar, int size) {
if (avatar == null) {
return null;
}
Bitmap bm = cropCenter(getAvatarUri(avatar), size, size);
if (bm == null) {
return null;
}
return bm;
}
public boolean isFileAvailable(Message message) {
return getFile(message).exists();
}
public static void close(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
}
public static void close(Socket socket) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
public static boolean weOwnFile(Context context, Uri uri) {
if (uri == null || !ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
return false;
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return fileIsInFilesDir(context, uri);
} else {
return weOwnFileLollipop(uri);
}
}
/**
* This is more than hacky but probably way better than doing nothing
* Further 'optimizations' might contain to get the parents of CacheDir and NoBackupDir
* and check against those as well
*/
private static boolean fileIsInFilesDir(Context context, Uri uri) {
try {
final String haystack = context.getFilesDir().getParentFile().getCanonicalPath();
final String needle = new File(uri.getPath()).getCanonicalPath();
return needle.startsWith(haystack);
} catch (IOException e) {
return false;
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean weOwnFileLollipop(Uri uri) {
try {
File file = new File(uri.getPath());
FileDescriptor fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY).getFileDescriptor();
StructStat st = Os.fstat(fd);
return st.st_uid == android.os.Process.myUid();
} catch (FileNotFoundException e) {
return false;
} catch (Exception e) {
return true;
}
}
} }

View file

@ -26,6 +26,7 @@ import android.util.Pair;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
@ -504,7 +505,7 @@ public class NotificationService {
builder.setContentText(UIHelper.getFileDescriptionString(mXmppConnectionService, message)); builder.setContentText(UIHelper.getFileDescriptionString(mXmppConnectionService, message));
} }
builder.setStyle(bigPictureStyle); builder.setStyle(bigPictureStyle);
} catch (final FileNotFoundException e) { } catch (final IOException e) {
modifyForTextOnly(builder, uBuilder, messages); modifyForTextOnly(builder, uBuilder, messages);
} }
} }

View file

@ -48,6 +48,7 @@ import android.widget.ImageView;
import android.widget.Toast; import android.widget.Toast;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -876,7 +877,7 @@ public abstract class XmppActivity extends ActionBarActivity {
Bitmap bm; Bitmap bm;
try { try {
bm = xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288), true); bm = xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288), true);
} catch (FileNotFoundException e) { } catch (IOException e) {
bm = null; bm = null;
} }
if (bm != null) { if (bm != null) {
@ -970,7 +971,7 @@ public abstract class XmppActivity extends ActionBarActivity {
} else { } else {
return null; return null;
} }
} catch (FileNotFoundException e) { } catch (IOException e) {
return null; return null;
} }
} }