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,6 +2357,13 @@ 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;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								publishAvatar(account, avatar, callback);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								callback.error(R.string.error_publish_avatar_converting, null);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
 | 
				
			||||||
		final IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
 | 
							final IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
 | 
				
			||||||
		this.sendIqPacket(account, packet, new OnIqPacketReceived() {
 | 
							this.sendIqPacket(account, packet, new OnIqPacketReceived() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2374,24 +2380,73 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 | 
				
			||||||
									getAvatarService().clear(account);
 | 
														getAvatarService().clear(account);
 | 
				
			||||||
									databaseBackend.updateAccount(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,14 +1530,16 @@ 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 true;
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					info = disco.get(account.getJid().toBareJid());
 | 
					 | 
				
			||||||
				return info != null && info.hasIdentity("pubsub", "pep");
 | 
									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");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public boolean mam() {
 | 
							public boolean mam() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue