republish avatar if server offers non-persistent pep :-(
This commit is contained in:
parent
23a0beab43
commit
7ff890e513
|
@ -26,6 +26,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -402,6 +403,43 @@ public class FileBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Avatar getStoredPepAvatar(String hash) {
|
||||||
|
if (hash == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Avatar avatar = new Avatar();
|
||||||
|
File file = new File(getAvatarPath(hash));
|
||||||
|
FileInputStream is = null;
|
||||||
|
try {
|
||||||
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
options.inJustDecodeBounds = true;
|
||||||
|
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
|
||||||
|
is = new FileInputStream(file);
|
||||||
|
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
Base64OutputStream mBase64OutputStream = new Base64OutputStream(mByteArrayOutputStream, Base64.DEFAULT);
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
|
DigestOutputStream os = new DigestOutputStream(mBase64OutputStream, digest);
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int length;
|
||||||
|
while ((length = is.read(buffer)) > 0) {
|
||||||
|
os.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
os.flush();
|
||||||
|
os.close();
|
||||||
|
avatar.sha1sum = CryptoHelper.bytesToHex(digest.digest());
|
||||||
|
avatar.image = new String(mByteArrayOutputStream.toByteArray());
|
||||||
|
avatar.height = options.outHeight;
|
||||||
|
avatar.width = options.outWidth;
|
||||||
|
return avatar;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
close(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAvatarCached(Avatar avatar) {
|
public boolean isAvatarCached(Avatar avatar) {
|
||||||
File file = new File(getAvatarPath(avatar.getFilename()));
|
File file = new File(getAvatarPath(avatar.getFilename()));
|
||||||
return file.exists();
|
return file.exists();
|
||||||
|
|
|
@ -6,11 +6,13 @@ import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
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;
|
||||||
|
@ -19,8 +21,10 @@ import eu.siacs.conversations.entities.ListItem;
|
||||||
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.utils.UIHelper;
|
import eu.siacs.conversations.utils.UIHelper;
|
||||||
|
import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
|
||||||
|
import eu.siacs.conversations.xmpp.XmppConnection;
|
||||||
|
|
||||||
public class AvatarService {
|
public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
|
|
||||||
private static final int FG_COLOR = 0xFFFAFAFA;
|
private static final int FG_COLOR = 0xFFFAFAFA;
|
||||||
private static final int TRANSPARENT = 0x00000000;
|
private static final int TRANSPARENT = 0x00000000;
|
||||||
|
@ -227,8 +231,7 @@ public class AvatarService {
|
||||||
if (avatar != null || cachedOnly) {
|
if (avatar != null || cachedOnly) {
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
avatar = mXmppConnectionService.getFileBackend().getAvatar(
|
avatar = mXmppConnectionService.getFileBackend().getAvatar(account.getAvatar(), size);
|
||||||
account.getAvatar(), size);
|
|
||||||
if (avatar == null) {
|
if (avatar == null) {
|
||||||
avatar = get(account.getJid().toBareJid().toString(), size,false);
|
avatar = get(account.getJid().toBareJid().toString(), size,false);
|
||||||
}
|
}
|
||||||
|
@ -387,10 +390,20 @@ public class AvatarService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean drawTile(Canvas canvas, Bitmap bm, int dstleft, int dsttop,
|
private boolean drawTile(Canvas canvas, Bitmap bm, int dstleft, int dsttop, int dstright, int dstbottom) {
|
||||||
int dstright, int dstbottom) {
|
|
||||||
Rect dst = new Rect(dstleft, dsttop, dstright, dstbottom);
|
Rect dst = new Rect(dstleft, dsttop, dstright, dstbottom);
|
||||||
canvas.drawBitmap(bm, null, dst, null);
|
canvas.drawBitmap(bm, null, dst, null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAdvancedStreamFeaturesAvailable(Account account) {
|
||||||
|
XmppConnection.Features features = account.getXmppConnection().getFeatures();
|
||||||
|
if (features.pep() && !features.pepPersistent()) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": has pep but is not persistent");
|
||||||
|
if (account.getAvatar() != null) {
|
||||||
|
mXmppConnectionService.republishAvatarIfNeeded(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,6 +840,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
connection.setOnBindListener(this.mOnBindListener);
|
connection.setOnBindListener(this.mOnBindListener);
|
||||||
connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
|
connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
|
||||||
connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService);
|
connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService);
|
||||||
|
connection.addOnAdvancedStreamFeaturesAvailableListener(this.mAvatarService);
|
||||||
AxolotlService axolotlService = account.getAxolotlService();
|
AxolotlService axolotlService = account.getAxolotlService();
|
||||||
if (axolotlService != null) {
|
if (axolotlService != null) {
|
||||||
connection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
|
connection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
|
||||||
|
@ -2338,9 +2339,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publishAvatar(final Account account,
|
public void publishAvatar(Account account, Uri image, UiCallback<Avatar> callback) {
|
||||||
final Uri image,
|
|
||||||
final UiCallback<Avatar> callback) {
|
|
||||||
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
|
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
|
||||||
final int size = Config.AVATAR_SIZE;
|
final int size = Config.AVATAR_SIZE;
|
||||||
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
|
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
|
||||||
|
@ -2358,40 +2357,96 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
callback.error(R.string.error_saving_avatar, avatar);
|
callback.error(R.string.error_saving_avatar, avatar);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
|
publishAvatar(account, avatar, callback);
|
||||||
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
} else {
|
||||||
|
callback.error(R.string.error_publish_avatar_converting, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
|
||||||
public void onIqPacketReceived(Account account, IqPacket result) {
|
final IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
|
||||||
if (result.getType() == IqPacket.TYPE.RESULT) {
|
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
final IqPacket packet = XmppConnectionService.this.mIqGenerator
|
|
||||||
.publishAvatarMetadata(avatar);
|
@Override
|
||||||
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
public void onIqPacketReceived(Account account, IqPacket result) {
|
||||||
@Override
|
if (result.getType() == IqPacket.TYPE.RESULT) {
|
||||||
public void onIqPacketReceived(Account account, IqPacket result) {
|
final IqPacket packet = XmppConnectionService.this.mIqGenerator
|
||||||
if (result.getType() == IqPacket.TYPE.RESULT) {
|
.publishAvatarMetadata(avatar);
|
||||||
if (account.setAvatar(avatar.getFilename())) {
|
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
getAvatarService().clear(account);
|
@Override
|
||||||
databaseBackend.updateAccount(account);
|
public void onIqPacketReceived(Account account, IqPacket result) {
|
||||||
}
|
if (result.getType() == IqPacket.TYPE.RESULT) {
|
||||||
|
if (account.setAvatar(avatar.getFilename())) {
|
||||||
|
getAvatarService().clear(account);
|
||||||
|
databaseBackend.updateAccount(account);
|
||||||
|
}
|
||||||
|
if (callback != null) {
|
||||||
callback.success(avatar);
|
callback.success(avatar);
|
||||||
} else {
|
} else {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": published avatar");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (callback != null) {
|
||||||
callback.error(
|
callback.error(
|
||||||
R.string.error_publish_avatar_server_reject,
|
R.string.error_publish_avatar_server_reject,
|
||||||
avatar);
|
avatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
|
} else {
|
||||||
|
if (callback != null) {
|
||||||
callback.error(
|
callback.error(
|
||||||
R.string.error_publish_avatar_server_reject,
|
R.string.error_publish_avatar_server_reject,
|
||||||
avatar);
|
avatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
callback.error(R.string.error_publish_avatar_converting, null);
|
}
|
||||||
|
|
||||||
|
public void republishAvatarIfNeeded(Account account) {
|
||||||
|
if (account.getAxolotlService().isPepBroken()) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping republication of avatar because pep is broken");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
IqPacket packet = this.mIqGenerator.retrieveAvatarMetaData(null);
|
||||||
|
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
|
|
||||||
|
private Avatar parseAvatar(IqPacket packet) {
|
||||||
|
Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub");
|
||||||
|
if (pubsub != null) {
|
||||||
|
Element items = pubsub.findChild("items");
|
||||||
|
if (items != null) {
|
||||||
|
return Avatar.parseMetadata(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean errorIsItemNotFound(IqPacket packet) {
|
||||||
|
Element error = packet.findChild("error");
|
||||||
|
return packet.getType() == IqPacket.TYPE.ERROR
|
||||||
|
&& error != null
|
||||||
|
&& error.hasChild("item-not-found");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
|
if (packet.getType() == IqPacket.TYPE.RESULT || errorIsItemNotFound(packet)) {
|
||||||
|
Avatar serverAvatar = parseAvatar(packet);
|
||||||
|
if (serverAvatar == null && account.getAvatar() != null) {
|
||||||
|
Avatar avatar = fileBackend.getStoredPepAvatar(account.getAvatar());
|
||||||
|
if (avatar != null) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": avatar on server was null. republishing");
|
||||||
|
publishAvatar(account, fileBackend.getStoredPepAvatar(account.getAvatar()), null);
|
||||||
|
} else {
|
||||||
|
Log.e(Config.LOGTAG, account.getJid().toBareJid()+": error rereading avatar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetchAvatar(Account account, Avatar avatar) {
|
public void fetchAvatar(Account account, Avatar avatar) {
|
||||||
|
@ -2526,8 +2581,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
Element pubsub = packet.findChild("pubsub",
|
Element pubsub = packet.findChild("pubsub","http://jabber.org/protocol/pubsub");
|
||||||
"http://jabber.org/protocol/pubsub");
|
|
||||||
if (pubsub != null) {
|
if (pubsub != null) {
|
||||||
Element items = pubsub.findChild("items");
|
Element items = pubsub.findChild("items");
|
||||||
if (items != null) {
|
if (items != null) {
|
||||||
|
|
|
@ -1530,13 +1530,15 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public boolean pep() {
|
public boolean pep() {
|
||||||
synchronized (XmppConnection.this.disco) {
|
synchronized (XmppConnection.this.disco) {
|
||||||
ServiceDiscoveryResult info = disco.get(account.getServer());
|
ServiceDiscoveryResult info = disco.get(account.getJid().toBareJid());
|
||||||
if (info != null && info.hasIdentity("pubsub", "pep")) {
|
return info != null && info.hasIdentity("pubsub", "pep");
|
||||||
return true;
|
}
|
||||||
} else {
|
}
|
||||||
info = disco.get(account.getJid().toBareJid());
|
|
||||||
return info != null && info.hasIdentity("pubsub", "pep");
|
public boolean pepPersistent() {
|
||||||
}
|
synchronized (XmppConnection.this.disco) {
|
||||||
|
ServiceDiscoveryResult info = disco.get(account.getJid().toBareJid());
|
||||||
|
return info != null && info.getFeatures().contains("http://jabber.org/protocol/pubsub#persistent-items");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue