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

iNPUTmice created

Change summary

AndroidManifest.xml                                            |   7 
res/values/strings.xml                                         |   1 
src/eu/siacs/conversations/crypto/PgpEngine.java               |   8 
src/eu/siacs/conversations/entities/Downloadable.java          |   1 
src/eu/siacs/conversations/http/HttpConnection.java            |  23 
src/eu/siacs/conversations/http/HttpConnectionManager.java     |   8 
src/eu/siacs/conversations/persistance/FileBackend.java        |  51 -
src/eu/siacs/conversations/services/ImageProvider.java         | 109 ----
src/eu/siacs/conversations/services/XmppConnectionService.java |  32 +
src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java |   2 
src/eu/siacs/conversations/ui/adapter/MessageAdapter.java      |  18 
src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java   |   4 
12 files changed, 67 insertions(+), 197 deletions(-)

Detailed changes

AndroidManifest.xml 🔗

@@ -25,11 +25,6 @@
         android:theme="@style/ConversationsTheme" >
         <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" >
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -124,4 +119,4 @@
         <activity android:name="de.duenndns.ssl.MemorizingActivity" />
     </application>
 
-</manifest>
+</manifest>

res/values/strings.xml 🔗

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

src/eu/siacs/conversations/crypto/PgpEngine.java 🔗

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

src/eu/siacs/conversations/entities/Downloadable.java 🔗

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

src/eu/siacs/conversations/http/HttpConnection.java 🔗

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

src/eu/siacs/conversations/http/HttpConnectionManager.java 🔗

@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.Message.ImageParams;
 import eu.siacs.conversations.services.AbstractConnectionManager;
 import eu.siacs.conversations.services.XmppConnectionService;
 
@@ -23,13 +24,6 @@ public class HttpConnectionManager extends AbstractConnectionManager {
 		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) {
 		this.connections.remove(connection);
 	}

src/eu/siacs/conversations/persistance/FileBackend.java 🔗

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

src/eu/siacs/conversations/services/ImageProvider.java 🔗

@@ -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");
-	}
-}

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -27,6 +27,7 @@ import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Bookmark;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Downloadable;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
 import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
@@ -797,11 +798,21 @@ public class XmppConnectionService extends Service {
 				Account account = accountLookupTable.get(conv.getAccountUuid());
 				conv.setAccount(account);
 				conv.setMessages(databaseBackend.getMessages(conv, 50));
+				checkDeletedFiles(conv);
 			}
 		}
-
 		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) {
 		populateWithOrderedConversations(list, true);
@@ -1833,4 +1844,23 @@ public class XmppConnectionService extends Service {
 	public HttpConnectionManager getHttpConnectionManager() {
 		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;
+		}
+		
+	}
 }

src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java 🔗

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

src/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -1,7 +1,5 @@
 package eu.siacs.conversations.ui.adapter;
 
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.util.HashMap;
 import java.util.List;
 
@@ -476,6 +474,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			} else if (d != null
 					&& d.getStatus() == Downloadable.STATUS_CHECKING) {
 				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) {
 				viewHolder.image.setVisibility(View.GONE);
 				viewHolder.messageBody.setVisibility(View.GONE);
@@ -531,19 +531,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 			downloadable.start();
 			return true;
 		} 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;
-				}
-			} else {
-				return false;
-			}
+			return false;
 		}
 	}
 

src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java 🔗

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