detect deleted files on start up. got rid of lagecy image provider for performance reasons. NOTE: this will prevent you to access images older than version 0.6

This commit is contained in:
iNPUTmice 2014-10-15 22:08:13 +02:00
parent 89cc4d1247
commit f5019ba966
12 changed files with 67 additions and 197 deletions

View file

@ -25,11 +25,6 @@
android:theme="@style/ConversationsTheme" > android:theme="@style/ConversationsTheme" >
<service android:name="eu.siacs.conversations.services.XmppConnectionService" /> <service android:name="eu.siacs.conversations.services.XmppConnectionService" />
<provider
android:name="eu.siacs.conversations.services.ImageProvider"
android:authorities="eu.siacs.conversations.images"
android:exported="true" />
<receiver android:name="eu.siacs.conversations.services.EventReceiver" > <receiver android:name="eu.siacs.conversations.services.EventReceiver" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />

View file

@ -267,5 +267,6 @@
<string name="conference_kicked">You have been kicked from this conference</string> <string name="conference_kicked">You have been kicked from this conference</string>
<string name="using_account">using account %s</string> <string name="using_account">using account %s</string>
<string name="checking_image">Checking image on HTTP host</string> <string name="checking_image">Checking image on HTTP host</string>
<string name="image_file_deleted">The image file has been deleted</string>
</resources> </resources>

View file

@ -88,9 +88,9 @@ public class PgpEngine {
} else if (message.getType() == Message.TYPE_IMAGE) { } else if (message.getType() == Message.TYPE_IMAGE) {
try { try {
final DownloadableFile inputFile = this.mXmppConnectionService final DownloadableFile inputFile = this.mXmppConnectionService
.getFileBackend().getConversationsFile(message, false); .getFileBackend().getFile(message, false);
final DownloadableFile outputFile = this.mXmppConnectionService final DownloadableFile outputFile = this.mXmppConnectionService
.getFileBackend().getConversationsFile(message, true); .getFileBackend().getFile(message, true);
outputFile.createNewFile(); outputFile.createNewFile();
InputStream is = new FileInputStream(inputFile); InputStream is = new FileInputStream(inputFile);
OutputStream os = new FileOutputStream(outputFile); OutputStream os = new FileOutputStream(outputFile);
@ -198,9 +198,9 @@ public class PgpEngine {
} else if (message.getType() == Message.TYPE_IMAGE) { } else if (message.getType() == Message.TYPE_IMAGE) {
try { try {
DownloadableFile inputFile = this.mXmppConnectionService DownloadableFile inputFile = this.mXmppConnectionService
.getFileBackend().getConversationsFile(message, true); .getFileBackend().getFile(message, true);
DownloadableFile outputFile = this.mXmppConnectionService DownloadableFile outputFile = this.mXmppConnectionService
.getFileBackend().getConversationsFile(message, false); .getFileBackend().getFile(message, false);
outputFile.createNewFile(); outputFile.createNewFile();
InputStream is = new FileInputStream(inputFile); InputStream is = new FileInputStream(inputFile);
OutputStream os = new FileOutputStream(outputFile); OutputStream os = new FileOutputStream(outputFile);

View file

@ -10,6 +10,7 @@ public interface Downloadable {
public static final int STATUS_FAILED = 0x202; public static final int STATUS_FAILED = 0x202;
public static final int STATUS_OFFER = 0x203; public static final int STATUS_OFFER = 0x203;
public static final int STATUS_DOWNLOADING = 0x204; public static final int STATUS_DOWNLOADING = 0x204;
public static final int STATUS_DELETED = 0x205;
public void start(); public void start();

View file

@ -9,7 +9,9 @@ import java.net.URL;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import android.content.Intent;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.net.Uri;
import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.Downloadable;
import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.DownloadableFile;
@ -24,8 +26,8 @@ public class HttpConnection implements Downloadable {
private URL mUrl; private URL mUrl;
private Message message; private Message message;
private DownloadableFile file; private DownloadableFile file;
private long mPreviousFileSize = 0;
private int mStatus = Downloadable.STATUS_UNKNOWN; private int mStatus = Downloadable.STATUS_UNKNOWN;
private boolean mAutostart = true;
public HttpConnection(HttpConnectionManager manager) { public HttpConnection(HttpConnectionManager manager) {
this.mHttpConnectionManager = manager; this.mHttpConnectionManager = manager;
@ -44,23 +46,14 @@ public class HttpConnection implements Downloadable {
try { try {
mUrl = new URL(message.getBody()); mUrl = new URL(message.getBody());
this.file = mXmppConnectionService.getFileBackend() this.file = mXmppConnectionService.getFileBackend()
.getConversationsFile(message, false); .getFile(message, false);
this.mAutostart = true;
checkFileSize(); checkFileSize();
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
this.cancel(); this.cancel();
} }
} }
public void init(Message message, URL url) {
this.message = message;
this.message.setDownloadable(this);
this.mUrl = url;
this.file = mXmppConnectionService.getFileBackend()
.getConversationsFile(message, false);
this.mPreviousFileSize = message.getImageParams().size;
checkFileSize();
}
private void checkFileSize() { private void checkFileSize() {
changeStatus(STATUS_CHECKING); changeStatus(STATUS_CHECKING);
new Thread(new FileSizeChecker()).start(); new Thread(new FileSizeChecker()).start();
@ -74,6 +67,9 @@ public class HttpConnection implements Downloadable {
} }
private void finish() { private void finish() {
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
mXmppConnectionService.sendBroadcast(intent);
message.setDownloadable(null); message.setDownloadable(null);
mHttpConnectionManager.finishConnection(this); mHttpConnectionManager.finishConnection(this);
} }
@ -96,8 +92,7 @@ public class HttpConnection implements Downloadable {
} }
file.setExpectedSize(size); file.setExpectedSize(size);
message.setType(Message.TYPE_IMAGE); message.setType(Message.TYPE_IMAGE);
if (size <= mHttpConnectionManager.getAutoAcceptFileSize() if (size <= mHttpConnectionManager.getAutoAcceptFileSize() && mAutostart) {
|| size == mPreviousFileSize) {
start(); start();
} else { } else {
changeStatus(STATUS_OFFER); changeStatus(STATUS_OFFER);

View file

@ -5,6 +5,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Message.ImageParams;
import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
@ -23,13 +24,6 @@ public class HttpConnectionManager extends AbstractConnectionManager {
return connection; return connection;
} }
public HttpConnection createNewConnection(Message message, URL url) {
HttpConnection connection = new HttpConnection(this);
connection.init(message, url);
this.connections.add(connection);
return connection;
}
public void finishConnection(HttpConnection connection) { public void finishConnection(HttpConnection connection) {
this.connections.remove(connection); this.connections.remove(connection);
} }

View file

@ -34,7 +34,6 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.ImageProvider;
import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.pep.Avatar;
@ -66,34 +65,11 @@ public class FileBackend {
return thumbnailCache; return thumbnailCache;
} }
public DownloadableFile getJingleFileLegacy(Message message) { public DownloadableFile getFile(Message message) {
return getJingleFileLegacy(message, true); return getFile(message, true);
} }
public DownloadableFile getJingleFileLegacy(Message message, public DownloadableFile getFile(Message message,
boolean decrypted) {
Conversation conversation = message.getConversation();
String prefix = context.getFilesDir().getAbsolutePath();
String path = prefix + "/" + conversation.getAccount().getJid() + "/"
+ conversation.getContactJid();
String filename;
if ((decrypted) || (message.getEncryption() == Message.ENCRYPTION_NONE)) {
filename = message.getUuid() + ".webp";
} else {
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
filename = message.getUuid() + ".webp";
} else {
filename = message.getUuid() + ".webp.pgp";
}
}
return new DownloadableFile(path + "/" + filename);
}
public DownloadableFile getJingleFile(Message message) {
return getConversationsFile(message, true);
}
public DownloadableFile getConversationsFile(Message message,
boolean decrypted) { boolean decrypted) {
StringBuilder filename = new StringBuilder(); StringBuilder filename = new StringBuilder();
filename.append(Environment.getExternalStoragePublicDirectory( filename.append(Environment.getExternalStoragePublicDirectory(
@ -151,7 +127,7 @@ public class FileBackend {
try { try {
InputStream is = context.getContentResolver() InputStream is = context.getContentResolver()
.openInputStream(image); .openInputStream(image);
DownloadableFile file = getJingleFile(message); DownloadableFile file = getFile(message);
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
file.createNewFile(); file.createNewFile();
Bitmap originalBitmap; Bitmap originalBitmap;
@ -240,7 +216,7 @@ public class FileBackend {
} }
public Bitmap getImageFromMessage(Message message) { public Bitmap getImageFromMessage(Message message) {
return BitmapFactory.decodeFile(getJingleFile(message) return BitmapFactory.decodeFile(getFile(message)
.getAbsolutePath()); .getAbsolutePath());
} }
@ -248,10 +224,7 @@ public class FileBackend {
throws FileNotFoundException { throws FileNotFoundException {
Bitmap thumbnail = thumbnailCache.get(message.getUuid()); Bitmap thumbnail = thumbnailCache.get(message.getUuid());
if ((thumbnail == null) && (!cacheOnly)) { if ((thumbnail == null) && (!cacheOnly)) {
File file = getJingleFile(message); File file = getFile(message);
if (!file.exists()) {
file = getJingleFileLegacy(message);
}
BitmapFactory.Options options = new BitmapFactory.Options(); BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = calcSampleSize(file, size); options.inSampleSize = calcSampleSize(file, size);
Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(), Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),
@ -447,12 +420,8 @@ public class FileBackend {
} }
public Uri getJingleFileUri(Message message) { public Uri getJingleFileUri(Message message) {
File file = getJingleFile(message); File file = getFile(message);
if (file.exists()) {
return Uri.parse("file://" + file.getAbsolutePath()); return Uri.parse("file://" + file.getAbsolutePath());
} else {
return ImageProvider.getProviderUri(message);
}
} }
public class ImageCopyException extends Exception { public class ImageCopyException extends Exception {
@ -476,4 +445,8 @@ public class FileBackend {
} }
return cropCenterSquare(bm, UIHelper.getRealPx(size, context)); return cropCenterSquare(bm, UIHelper.getRealPx(size, context));
} }
public boolean isFileAvailable(Message message) {
return getFile(message).exists();
}
} }

View file

@ -1,109 +0,0 @@
package eu.siacs.conversations.services;
import java.io.File;
import java.io.FileNotFoundException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
public class ImageProvider extends ContentProvider {
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
ParcelFileDescriptor pfd;
FileBackend fileBackend = new FileBackend(getContext());
if ("r".equals(mode)) {
DatabaseBackend databaseBackend = DatabaseBackend
.getInstance(getContext());
String uuids = uri.getPath();
Log.d(Config.LOGTAG, "uuids = " + uuids + " mode=" + mode);
if (uuids == null) {
throw new FileNotFoundException();
}
String[] uuidsSplited = uuids.split("/", 2);
if (uuidsSplited.length != 3) {
throw new FileNotFoundException();
}
String conversationUuid = uuidsSplited[1];
String messageUuid = uuidsSplited[2].split("\\.")[0];
Log.d(Config.LOGTAG, "messageUuid=" + messageUuid);
Conversation conversation = databaseBackend
.findConversationByUuid(conversationUuid);
if (conversation == null) {
throw new FileNotFoundException("conversation "
+ conversationUuid + " could not be found");
}
Message message = databaseBackend.findMessageByUuid(messageUuid);
if (message == null) {
throw new FileNotFoundException("message " + messageUuid
+ " could not be found");
}
Account account = databaseBackend.findAccountByUuid(conversation
.getAccountUuid());
if (account == null) {
throw new FileNotFoundException("account "
+ conversation.getAccountUuid() + " cound not be found");
}
message.setConversation(conversation);
conversation.setAccount(account);
File file = fileBackend.getJingleFileLegacy(message);
pfd = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_READ_ONLY);
return pfd;
} else {
throw new FileNotFoundException();
}
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
return 0;
}
@Override
public String getType(Uri arg0) {
return null;
}
@Override
public Uri insert(Uri arg0, ContentValues arg1) {
return null;
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4) {
return null;
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
return 0;
}
public static Uri getProviderUri(Message message) {
return Uri.parse("content://eu.siacs.conversations.images/"
+ message.getConversationUuid() + "/" + message.getUuid()
+ ".webp");
}
}

View file

@ -27,6 +27,7 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Downloadable;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener; import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
@ -797,10 +798,20 @@ public class XmppConnectionService extends Service {
Account account = accountLookupTable.get(conv.getAccountUuid()); Account account = accountLookupTable.get(conv.getAccountUuid());
conv.setAccount(account); conv.setAccount(account);
conv.setMessages(databaseBackend.getMessages(conv, 50)); conv.setMessages(databaseBackend.getMessages(conv, 50));
checkDeletedFiles(conv);
} }
} }
return this.conversations;
}
return this.conversations; private void checkDeletedFiles(Conversation conversation) {
for(Message message : conversation.getMessages()) {
if (message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP) {
if (!getFileBackend().isFileAvailable(message)) {
message.setDownloadable(new DeletedDownloadable());
}
}
}
} }
public void populateWithOrderedConversations(List<Conversation> list) { public void populateWithOrderedConversations(List<Conversation> list) {
@ -1833,4 +1844,23 @@ public class XmppConnectionService extends Service {
public HttpConnectionManager getHttpConnectionManager() { public HttpConnectionManager getHttpConnectionManager() {
return this.mHttpConnectionManager; return this.mHttpConnectionManager;
} }
private class DeletedDownloadable implements Downloadable {
@Override
public void start() {
return;
}
@Override
public int getStatus() {
return Downloadable.STATUS_DELETED;
}
@Override
public long getFileSize() {
return 0;
}
}
} }

View file

@ -92,6 +92,8 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
mLastMessage.setText(R.string.receiving_image); mLastMessage.setText(R.string.receiving_image);
} else if (d.getStatus() == Downloadable.STATUS_OFFER) { } else if (d.getStatus() == Downloadable.STATUS_OFFER) {
mLastMessage.setText(R.string.image_offered_for_download); mLastMessage.setText(R.string.image_offered_for_download);
} else if (d.getStatus() == Downloadable.STATUS_DELETED) {
mLastMessage.setText(R.string.image_file_deleted);
} else { } else {
mLastMessage.setText(""); mLastMessage.setText("");
} }

View file

@ -1,7 +1,5 @@
package eu.siacs.conversations.ui.adapter; package eu.siacs.conversations.ui.adapter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -476,6 +474,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else if (d != null } else if (d != null
&& d.getStatus() == Downloadable.STATUS_CHECKING) { && d.getStatus() == Downloadable.STATUS_CHECKING) {
displayInfoMessage(viewHolder, R.string.checking_image); displayInfoMessage(viewHolder, R.string.checking_image);
} else if (d != null && d.getStatus() == Downloadable.STATUS_DELETED) {
displayInfoMessage(viewHolder, R.string.image_file_deleted);
} else if (d != null && d.getStatus() == Downloadable.STATUS_OFFER) { } else if (d != null && d.getStatus() == Downloadable.STATUS_OFFER) {
viewHolder.image.setVisibility(View.GONE); viewHolder.image.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE);
@ -531,20 +531,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
downloadable.start(); downloadable.start();
return true; return true;
} else { } else {
ImageParams params = message.getImageParams();
if (params.origin != null) {
try {
URL url = new URL(params.origin);
activity.xmppConnectionService.getHttpConnectionManager()
.createNewConnection(message, url);
return true;
} catch (MalformedURLException e) {
return false; return false;
} }
} else {
return false;
}
}
} }
private static class ViewHolder { private static class ViewHolder {

View file

@ -327,7 +327,7 @@ public class JingleConnection implements Downloadable {
.push(message); .push(message);
} }
this.file = this.mXmppConnectionService.getFileBackend() this.file = this.mXmppConnectionService.getFileBackend()
.getConversationsFile(message, false); .getFile(message, false);
if (message.getEncryption() == Message.ENCRYPTION_OTR) { if (message.getEncryption() == Message.ENCRYPTION_OTR) {
byte[] key = conversation.getSymmetricKey(); byte[] key = conversation.getSymmetricKey();
if (key == null) { if (key == null) {
@ -359,7 +359,7 @@ public class JingleConnection implements Downloadable {
if (message.getType() == Message.TYPE_IMAGE) { if (message.getType() == Message.TYPE_IMAGE) {
content.setTransportId(this.transportId); content.setTransportId(this.transportId);
this.file = this.mXmppConnectionService.getFileBackend() this.file = this.mXmppConnectionService.getFileBackend()
.getConversationsFile(message, false); .getFile(message, false);
if (message.getEncryption() == Message.ENCRYPTION_OTR) { if (message.getEncryption() == Message.ENCRYPTION_OTR) {
Conversation conversation = this.message.getConversation(); Conversation conversation = this.message.getConversation();
this.mXmppConnectionService.renewSymmetricKey(conversation); this.mXmppConnectionService.renewSymmetricKey(conversation);