diff options
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/persistance')
-rw-r--r-- | src/main/java/de/thedevstack/conversationsplus/persistance/DatabaseBackend.java | 90 | ||||
-rw-r--r-- | src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java | 154 |
2 files changed, 176 insertions, 68 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/persistance/DatabaseBackend.java b/src/main/java/de/thedevstack/conversationsplus/persistance/DatabaseBackend.java index bee19e4f..21eaf476 100644 --- a/src/main/java/de/thedevstack/conversationsplus/persistance/DatabaseBackend.java +++ b/src/main/java/de/thedevstack/conversationsplus/persistance/DatabaseBackend.java @@ -4,11 +4,13 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import de.thedevstack.conversationsplus.Config; import de.thedevstack.conversationsplus.entities.Account; import de.thedevstack.conversationsplus.entities.Contact; import de.thedevstack.conversationsplus.entities.Conversation; import de.thedevstack.conversationsplus.entities.Message; import de.thedevstack.conversationsplus.entities.Roster; +import de.thedevstack.conversationsplus.xmpp.jid.InvalidJidException; import de.thedevstack.conversationsplus.xmpp.jid.Jid; import android.content.Context; @@ -16,13 +18,14 @@ import android.database.Cursor; import android.database.sqlite.SQLiteCantOpenDatabaseException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 13; + private static final int DATABASE_VERSION = 14; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -130,6 +133,88 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("delete from "+Contact.TABLENAME); db.execSQL("update "+Account.TABLENAME+" set "+Account.ROSTERVERSION+" = NULL"); } + if (oldVersion < 14 && newVersion >= 14) { + // migrate db to new, canonicalized JID domainpart representation + + // Conversation table + Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME, new String[0]); + while(cursor.moveToNext()) { + String newJid; + try { + newJid = Jid.fromString( + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + ).toString(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID " + +cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + +": " + ignored +". Skipping..."); + continue; + } + + String updateArgs[] = { + newJid, + cursor.getString(cursor.getColumnIndex(Conversation.UUID)), + }; + db.execSQL("update " + Conversation.TABLENAME + + " set " + Conversation.CONTACTJID + " = ? " + + " where " + Conversation.UUID + " = ?", updateArgs); + } + cursor.close(); + + // Contact table + cursor = db.rawQuery("select * from " + Contact.TABLENAME, new String[0]); + while(cursor.moveToNext()) { + String newJid; + try { + newJid = Jid.fromString( + cursor.getString(cursor.getColumnIndex(Contact.JID)) + ).toString(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Contact JID " + +cursor.getString(cursor.getColumnIndex(Contact.JID)) + +": " + ignored +". Skipping..."); + continue; + } + + String updateArgs[] = { + newJid, + cursor.getString(cursor.getColumnIndex(Contact.ACCOUNT)), + cursor.getString(cursor.getColumnIndex(Contact.JID)), + }; + db.execSQL("update " + Contact.TABLENAME + + " set " + Contact.JID + " = ? " + + " where " + Contact.ACCOUNT + " = ? " + + " AND " + Contact.JID + " = ?", updateArgs); + } + cursor.close(); + + // Account table + cursor = db.rawQuery("select * from " + Account.TABLENAME, new String[0]); + while(cursor.moveToNext()) { + String newServer; + try { + newServer = Jid.fromParts( + cursor.getString(cursor.getColumnIndex(Account.USERNAME)), + cursor.getString(cursor.getColumnIndex(Account.SERVER)), + "mobile" + ).getDomainpart(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Account SERVER " + +cursor.getString(cursor.getColumnIndex(Account.SERVER)) + +": " + ignored +". Skipping..."); + continue; + } + + String updateArgs[] = { + newServer, + cursor.getString(cursor.getColumnIndex(Account.UUID)), + }; + db.execSQL("update " + Account.TABLENAME + + " set " + Account.SERVER + " = ? " + + " where " + Account.UUID + " = ?", updateArgs); + } + cursor.close(); + } } public static synchronized DatabaseBackend getInstance(Context context) { @@ -301,8 +386,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor; String args[] = { roster.getAccount().getUuid() }; - cursor = db.query(Contact.TABLENAME, null, Contact.ACCOUNT + "=?", - args, null, null, null); + cursor = db.query(Contact.TABLENAME, null, Contact.ACCOUNT + "=?", args, null, null, null); while (cursor.moveToNext()) { roster.initContact(Contact.fromCursor(cursor)); } diff --git a/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java b/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java index e3bf58c7..3a245d62 100644 --- a/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java +++ b/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java @@ -1,6 +1,7 @@ package de.thedevstack.conversationsplus.persistance; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -12,6 +13,7 @@ import java.security.DigestOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; import java.util.Locale; @@ -31,6 +33,7 @@ import android.webkit.MimeTypeMap; import de.thedevstack.conversationsplus.Config; import de.thedevstack.conversationsplus.R; +import de.thedevstack.conversationsplus.entities.Transferable; import de.thedevstack.conversationsplus.entities.DownloadableFile; import de.thedevstack.conversationsplus.entities.Message; import de.thedevstack.conversationsplus.services.XmppConnectionService; @@ -42,8 +45,7 @@ public class FileBackend { private static int IMAGE_SIZE = 1920; - private SimpleDateFormat imageDateFormat = new SimpleDateFormat( - "yyyyMMdd_HHmmssSSS", Locale.US); + private final SimpleDateFormat imageDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); private XmppConnectionService mXmppConnectionService; @@ -78,10 +80,10 @@ public class FileBackend { if (path.startsWith("/")) { return new DownloadableFile(path); } else { - if (message.getType() == Message.TYPE_FILE) { + if (Arrays.asList(Transferable.VALID_IMAGE_EXTENSIONS).contains(extension)) { return new DownloadableFile(getConversationsFileDirectory() + path); } else { - return new DownloadableFile(getConversationsImageDirectory()+path); + return new DownloadableFile(getConversationsImageDirectory() + path); } } } @@ -110,9 +112,7 @@ public class FileBackend { scalledW = size; scalledH = (int) (h / ((double) w / size)); } - Bitmap scalledBitmap = Bitmap.createScaledBitmap(originalBitmap, - scalledW, scalledH, true); - return scalledBitmap; + return Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true); } else { return originalBitmap; } @@ -148,31 +148,35 @@ public class FileBackend { } public DownloadableFile copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException { + Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage"); + String mime = mXmppConnectionService.getContentResolver().getType(uri); + String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); + message.setRelativeFilePath(message.getUuid() + "." + extension); + DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); + file.getParentFile().mkdirs(); + OutputStream os = null; + InputStream is = null; try { - Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage"); - String mime = mXmppConnectionService.getContentResolver().getType(uri); - String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); - message.setRelativeFilePath(message.getUuid() + "." + extension); - DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); - file.getParentFile().mkdirs(); file.createNewFile(); - OutputStream os = new FileOutputStream(file); - InputStream is = mXmppConnectionService.getContentResolver().openInputStream(uri); + os = new FileOutputStream(file); + is = mXmppConnectionService.getContentResolver().openInputStream(uri); byte[] buffer = new byte[1024]; - int length; - while ((length = is.read(buffer)) > 0) { + int length; + while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); - } + } os.flush(); - os.close(); - is.close(); - Log.d(Config.LOGTAG, "output file name " + mXmppConnectionService.getFileBackend().getFile(message)); - return file; - } catch (FileNotFoundException e) { + } catch(FileNotFoundException e) { throw new FileCopyException(R.string.error_file_not_found); } catch (IOException e) { + e.printStackTrace(); throw new FileCopyException(R.string.error_io_exception); + } finally { + close(os); + close(is); } + Log.d(Config.LOGTAG, "output file name " + mXmppConnectionService.getFileBackend().getFile(message)); + return file; } public DownloadableFile copyImageToPrivateStorage(Message message, Uri image) @@ -182,49 +186,48 @@ public class FileBackend { private DownloadableFile copyImageToPrivateStorage(Message message, Uri image, int sampleSize) throws FileCopyException { + DownloadableFile file = getFile(message); + file.getParentFile().mkdirs(); + InputStream is = null; + OutputStream os = null; try { - InputStream is = mXmppConnectionService.getContentResolver() - .openInputStream(image); - DownloadableFile file = getFile(message); - file.getParentFile().mkdirs(); file.createNewFile(); + is = mXmppConnectionService.getContentResolver().openInputStream(image); + os = new FileOutputStream(file); + Bitmap originalBitmap; BitmapFactory.Options options = new BitmapFactory.Options(); int inSampleSize = (int) Math.pow(2, sampleSize); - Log.d(Config.LOGTAG, "reading bitmap with sample size " - + inSampleSize); + Log.d(Config.LOGTAG, "reading bitmap with sample size " + inSampleSize); options.inSampleSize = inSampleSize; originalBitmap = BitmapFactory.decodeStream(is, null, options); is.close(); if (originalBitmap == null) { throw new FileCopyException(R.string.error_not_an_image_file); } - Bitmap scalledBitmap = resize(originalBitmap, IMAGE_SIZE); - originalBitmap = null; + Bitmap scaledBitmap = resize(originalBitmap, IMAGE_SIZE); int rotation = getRotation(image); if (rotation > 0) { - scalledBitmap = rotate(scalledBitmap, rotation); + scaledBitmap = rotate(scaledBitmap, rotation); } - OutputStream os = new FileOutputStream(file); - boolean success = scalledBitmap.compress( - Bitmap.CompressFormat.WEBP, 75, os); + + boolean success = scaledBitmap.compress(Bitmap.CompressFormat.WEBP, 75, os); if (!success) { throw new FileCopyException(R.string.error_compressing_image); } os.flush(); - os.close(); long size = file.getSize(); - int width = scalledBitmap.getWidth(); - int height = scalledBitmap.getHeight(); - message.setBody(Long.toString(size) + ',' + width + ',' + height); + int width = scaledBitmap.getWidth(); + int height = scaledBitmap.getHeight(); + message.setBody(Long.toString(size) + '|' + width + '|' + height); return file; } catch (FileNotFoundException e) { throw new FileCopyException(R.string.error_file_not_found); } catch (IOException e) { + e.printStackTrace(); throw new FileCopyException(R.string.error_io_exception); } catch (SecurityException e) { - throw new FileCopyException( - R.string.error_security_exception_during_image_copy); + throw new FileCopyException(R.string.error_security_exception_during_image_copy); } catch (OutOfMemoryError e) { ++sampleSize; if (sampleSize <= 3) { @@ -232,23 +235,26 @@ public class FileBackend { } else { throw new FileCopyException(R.string.error_out_of_memory); } + } catch (NullPointerException e) { + throw new FileCopyException(R.string.error_io_exception); + } finally { + close(os); + close(is); } } private int getRotation(Uri image) { + InputStream is = null; try { - InputStream is = mXmppConnectionService.getContentResolver() - .openInputStream(image); + is = mXmppConnectionService.getContentResolver().openInputStream(image); return ExifHelper.getOrientation(is); } catch (FileNotFoundException e) { return 0; + } finally { + close(is); } } - public Bitmap getImageFromMessage(Message message) { - return BitmapFactory.decodeFile(getFile(message).getAbsolutePath()); - } - public Bitmap getThumbnail(Message message, int size, boolean cacheOnly) throws FileNotFoundException { Bitmap thumbnail = mXmppConnectionService.getBitmapCache().get( @@ -257,8 +263,7 @@ public class FileBackend { File file = getFile(message); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(file, size); - Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(), - options); + Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),options); if (fullsize == null) { throw new FileNotFoundException(); } @@ -271,13 +276,11 @@ public class FileBackend { public Uri getTakePhotoUri() { StringBuilder pathBuilder = new StringBuilder(); - pathBuilder.append(Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)); + pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)); pathBuilder.append('/'); pathBuilder.append("Camera"); pathBuilder.append('/'); - pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date()) - + ".jpg"); + pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date()) + ".jpg"); Uri uri = Uri.parse("file://" + pathBuilder.toString()); File file = new File(uri.toString()); file.getParentFile().mkdirs(); @@ -325,13 +328,13 @@ public class FileBackend { String filename = getAvatarPath(avatar.getFilename()); file = new File(filename + ".tmp"); file.getParentFile().mkdirs(); + OutputStream os = null; try { file.createNewFile(); - FileOutputStream mFileOutputStream = new FileOutputStream(file); + os = new FileOutputStream(file); MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); - DigestOutputStream mDigestOutputStream = new DigestOutputStream( - mFileOutputStream, digest); + DigestOutputStream mDigestOutputStream = new DigestOutputStream(os, digest); mDigestOutputStream.write(avatar.getImageAsBytes()); mDigestOutputStream.flush(); mDigestOutputStream.close(); @@ -349,6 +352,8 @@ public class FileBackend { return false; } catch (NoSuchAlgorithmException e) { return false; + } finally { + close(os); } } avatar.size = file.length(); @@ -356,8 +361,7 @@ public class FileBackend { } public String getAvatarPath(String avatar) { - return mXmppConnectionService.getFilesDir().getAbsolutePath() - + "/avatars/" + avatar; + return mXmppConnectionService.getFilesDir().getAbsolutePath()+ "/avatars/" + avatar; } public Uri getAvatarUri(String avatar) { @@ -368,10 +372,11 @@ public class FileBackend { if (image == null) { return null; } + InputStream is = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(image, size); - InputStream is = mXmppConnectionService.getContentResolver().openInputStream(image); + is = mXmppConnectionService.getContentResolver().openInputStream(image); Bitmap input = BitmapFactory.decodeStream(is, null, options); if (input == null) { return null; @@ -384,6 +389,8 @@ public class FileBackend { } } catch (FileNotFoundException e) { return null; + } finally { + close(is); } } @@ -391,12 +398,15 @@ public class FileBackend { if (image == null) { return null; } + InputStream is = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(image,Math.max(newHeight, newWidth)); - InputStream is = mXmppConnectionService.getContentResolver().openInputStream(image); + is = mXmppConnectionService.getContentResolver().openInputStream(image); Bitmap source = BitmapFactory.decodeStream(is, null, options); - + if (source == null) { + return null; + } int sourceWidth = source.getWidth(); int sourceHeight = source.getHeight(); float xScale = (float) newWidth / sourceWidth; @@ -408,14 +418,15 @@ public class FileBackend { float top = (newHeight - scaledHeight) / 2; RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight); - Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig()); + Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(dest); canvas.drawBitmap(source, null, targetRect, null); return dest; } catch (FileNotFoundException e) { return null; + } finally { + close(is); } - } public Bitmap cropCenterSquare(Bitmap input, int size) { @@ -430,7 +441,7 @@ public class FileBackend { float top = (size - outHeight) / 2; RectF target = new RectF(left, top, left + outWidth, top + outHeight); - Bitmap output = Bitmap.createBitmap(size, size, input.getConfig()); + Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); canvas.drawBitmap(input, null, target, null); return output; @@ -490,7 +501,11 @@ public class FileBackend { message.setBody(url.toString()+"|"+Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight); } } else { - message.setBody(Long.toString(file.getSize())); + if (url != null) { + message.setBody(url.toString()+"|"+Long.toString(file.getSize())); + } else { + message.setBody(Long.toString(file.getSize())); + } } } @@ -522,4 +537,13 @@ public class FileBackend { public boolean isFileAvailable(Message message) { return getFile(message).exists(); } + + public static void close(Closeable stream) { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } } |