Detailed changes
@@ -60,6 +60,14 @@
<implements rdf:resource="https://xmpp.org/rfcs/rfc6122.html"/>
<implements rdf:resource="https://xmpp.org/rfcs/rfc7590.html"/>
+ <implements>
+ <xmpp:SupportedXep>
+ <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0221.html"/>
+ <xmpp:status>partial</xmpp:status>
+ <xmpp:version>1.0</xmpp:version>
+ <xmpp:note xml:lang='en'>When used with XEP-0050, images over HTTPS only</xmpp:note>
+ </xmpp:SupportedXep>
+ </implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0224.html"/>
@@ -16,6 +16,19 @@
android:paddingBottom="4dp"
android:textAppearance="@style/TextAppearance.Conversations.Caption" />
+ <ImageView
+ android:id="@+id/media_image"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="8dp"
+ android:layout_gravity="center"
+ android:adjustViewBounds="true"
+ android:background="@color/black87"
+ android:longClickable="false"
+ android:scaleType="centerCrop"/>
+
<ListView
android:id="@+id/values"
android:layout_width="fill_parent"
@@ -7,6 +7,7 @@ import android.content.Intent;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -41,6 +42,7 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebChromeClient;
import android.util.DisplayMetrics;
+import android.util.LruCache;
import android.util.Pair;
import android.util.SparseArray;
@@ -112,6 +114,7 @@ import eu.siacs.conversations.databinding.CommandSpinnerFieldBinding;
import eu.siacs.conversations.databinding.CommandTextFieldBinding;
import eu.siacs.conversations.databinding.CommandWebviewBinding;
import eu.siacs.conversations.databinding.DialogQuickeditBinding;
+import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.QuickConversationsService;
@@ -1742,6 +1745,42 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
setTextOrHide(binding.label, field.getLabel());
setTextOrHide(binding.desc, field.getDesc());
+ Element media = field.el.findChild("media", "urn:xmpp:media-element");
+ if (media == null) {
+ binding.mediaImage.setVisibility(View.GONE);
+ } else {
+ final LruCache<String, Drawable> cache = xmppConnectionService.getDrawableCache();
+ final HttpConnectionManager httpManager = xmppConnectionService.getHttpConnectionManager();
+ for (Element uriEl : media.getChildren()) {
+ if (!"uri".equals(uriEl.getName())) continue;
+ if (!"urn:xmpp:media-element".equals(uriEl.getNamespace())) continue;
+ String mimeType = uriEl.getAttribute("type");
+ String uriS = uriEl.getContent();
+ if (mimeType == null || uriS == null) continue;
+ Uri uri = Uri.parse(uriS);
+ if (mimeType.startsWith("image/") && "https".equals(uri.getScheme())) {
+ final Drawable d = cache.get(uri.toString());
+ if (d == null) {
+ int size = (int)(xmppConnectionService.getResources().getDisplayMetrics().density * 288);
+ Message dummy = new Message(Conversation.this, uri.toString(), Message.ENCRYPTION_NONE);
+ dummy.setFileParams(new Message.FileParams(uri.toString()));
+ httpManager.createNewDownloadConnection(dummy, true, (file) -> {
+ if (file == null) {
+ dummy.getTransferable().start();
+ } else {
+ try {
+ xmppConnectionService.getFileBackend().getThumbnail(file, xmppConnectionService.getResources(), size, false, uri.toString());
+ } catch (final Exception e) { }
+ }
+ });
+ } else {
+ binding.mediaImage.setImageDrawable(d);
+ binding.mediaImage.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+ }
+
Element validate = field.el.findChild("validate", "http://jabber.org/protocol/xdata-validate");
String datatype = validate == null ? null : validate.getAttribute("datatype");
@@ -2987,7 +3026,9 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return false;
}
- public void refresh() { }
+ public void refresh() {
+ notifyDataSetChanged();
+ }
protected void loading() {
View v = getView();
@@ -27,9 +27,11 @@ import javax.net.ssl.X509TrustManager;
import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.Consumer;
import eu.siacs.conversations.utils.TLSSocketFactory;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
@@ -85,6 +87,10 @@ public class HttpConnectionManager extends AbstractConnectionManager {
}
public void createNewDownloadConnection(final Message message, boolean interactive) {
+ createNewDownloadConnection(message, interactive, null);
+ }
+
+ public void createNewDownloadConnection(final Message message, boolean interactive, Consumer<DownloadableFile> cb) {
synchronized (this.downloadConnections) {
for (HttpDownloadConnection connection : this.downloadConnections) {
if (connection.getMessage() == message) {
@@ -92,7 +98,7 @@ public class HttpConnectionManager extends AbstractConnectionManager {
return;
}
}
- final HttpDownloadConnection connection = new HttpDownloadConnection(message, this);
+ final HttpDownloadConnection connection = new HttpDownloadConnection(message, this, cb);
connection.init(interactive);
this.downloadConnections.add(connection);
}
@@ -24,6 +24,7 @@ import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.Consumer;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.FileWriterException;
import eu.siacs.conversations.utils.MimeUtils;
@@ -46,11 +47,13 @@ public class HttpDownloadConnection implements Transferable {
private boolean acceptedAutomatically = false;
private int mProgress = 0;
private Call mostRecentCall;
+ final private Consumer<DownloadableFile> cb;
- HttpDownloadConnection(Message message, HttpConnectionManager manager) {
+ HttpDownloadConnection(Message message, HttpConnectionManager manager, Consumer<DownloadableFile> cb) {
this.message = message;
this.mHttpConnectionManager = manager;
this.mXmppConnectionService = manager.getXmppConnectionService();
+ this.cb = cb;
}
@Override
@@ -188,7 +191,7 @@ public class HttpDownloadConnection implements Transferable {
}
private void finish() {
- boolean notify = acceptedAutomatically && !message.isRead();
+ boolean notify = acceptedAutomatically && !message.isRead() && cb == null;
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
notify = message.getConversation().getAccount().getPgpDecryptionService().decrypt(message, notify);
}
@@ -210,6 +213,7 @@ public class HttpDownloadConnection implements Transferable {
message.setDeleted(true);
}
message.setTransferable(null);
+ cb.accept(file);
mXmppConnectionService.updateMessage(message);
mHttpConnectionManager.finishConnection(this);
final boolean notifyAfterScan = notify;
@@ -325,7 +329,11 @@ public class HttpDownloadConnection implements Transferable {
} else {
changeStatus(STATUS_OFFER);
HttpDownloadConnection.this.acceptedAutomatically = false;
- HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message);
+ if (cb == null) {
+ HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message);
+ } else {
+ cb.accept(null);
+ }
}
}
@@ -1164,11 +1164,15 @@ public class FileBackend {
}
public Drawable getThumbnail(DownloadableFile file, Resources res, int size, boolean cacheOnly) throws IOException {
+ return getThumbnail(file, res, size, cacheOnly, file.getAbsolutePath());
+ }
+
+ public Drawable getThumbnail(DownloadableFile file, Resources res, int size, boolean cacheOnly, String cacheKey) throws IOException {
final LruCache<String, Drawable> cache = mXmppConnectionService.getDrawableCache();
- Drawable thumbnail = cache.get(file.getAbsolutePath());
+ Drawable thumbnail = cache.get(cacheKey);
if ((thumbnail == null) && (!cacheOnly)) {
synchronized (THUMBNAIL_LOCK) {
- thumbnail = cache.get(file.getAbsolutePath());
+ thumbnail = cache.get(cacheKey);
if (thumbnail != null) {
return thumbnail;
}
@@ -1183,7 +1187,7 @@ public class FileBackend {
throw new FileNotFoundException();
}
}
- cache.put(file.getAbsolutePath(), thumbnail);
+ cache.put(cacheKey, thumbnail);
}
}
return thumbnail;