From e439c223ee07e8ee10394db601cad43320c000e9 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 25 Aug 2022 19:22:40 +0200 Subject: [PATCH] add overflow menu action to delete own avatar --- .../crypto/axolotl/AxolotlService.java | 8 +-- .../conversations/generator/IqGenerator.java | 17 +++-- .../conversations/parser/MessageParser.java | 2 + .../services/XmppConnectionService.java | 72 +++++++++++++++++-- .../ui/PublishProfilePictureActivity.java | 23 +++++- .../eu/siacs/conversations/xml/Namespace.java | 2 + .../menu/activity_publish_profile_picture.xml | 10 +++ src/main/res/values/strings.xml | 1 + 8 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 src/main/res/menu/activity_publish_profile_picture.xml diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 4da07af9faf3ea992d318489e9cfb745f5177f0a..faef2e098dfa2ff9d501bc278625759575183740 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -708,11 +708,11 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } public void deleteOmemoIdentity() { - final String node = AxolotlService.PEP_BUNDLES + ":" + getOwnDeviceId(); - final IqPacket deleteBundleNode = mXmppConnectionService.getIqGenerator().deleteNode(node); - mXmppConnectionService.sendIqPacket(account, deleteBundleNode, null); + mXmppConnectionService.deletePepNode( + account, AxolotlService.PEP_BUNDLES + ":" + getOwnDeviceId()); final Set ownDeviceIds = getOwnDeviceIds(); - publishDeviceIdsAndRefineAccessModel(ownDeviceIds == null ? Collections.emptySet() : ownDeviceIds); + publishDeviceIdsAndRefineAccessModel( + ownDeviceIds == null ? Collections.emptySet() : ownDeviceIds); } public List getCryptoTargets(Conversation conversation) { diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 6b87cb36ddbe98a4b2415920c4288a9b444f152d..52a19eaa4cb26fb8b44db9048433bc940c90a509 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -156,9 +156,9 @@ public class IqGenerator extends AbstractGenerator { public IqPacket publishAvatar(Avatar avatar, Bundle options) { final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); - final Element data = item.addChild("data", "urn:xmpp:avatar:data"); + final Element data = item.addChild("data", Namespace.AVATAR_DATA); data.setContent(avatar.image); - return publish("urn:xmpp:avatar:data", item, options); + return publish(Namespace.AVATAR_DATA, item, options); } public IqPacket publishElement(final String namespace, final Element element, String id, final Bundle options) { @@ -172,20 +172,20 @@ public class IqGenerator extends AbstractGenerator { final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); final Element metadata = item - .addChild("metadata", "urn:xmpp:avatar:metadata"); + .addChild("metadata", Namespace.AVATAR_METADATA); final Element info = metadata.addChild("info"); info.setAttribute("bytes", avatar.size); info.setAttribute("id", avatar.sha1sum); info.setAttribute("height", avatar.height); info.setAttribute("width", avatar.height); info.setAttribute("type", avatar.type); - return publish("urn:xmpp:avatar:metadata", item, options); + return publish(Namespace.AVATAR_METADATA, item, options); } public IqPacket retrievePepAvatar(final Avatar avatar) { final Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); - final IqPacket packet = retrieve("urn:xmpp:avatar:data", item); + final IqPacket packet = retrieve(Namespace.AVATAR_DATA, item); packet.setTo(avatar.owner); return packet; } @@ -197,6 +197,13 @@ public class IqGenerator extends AbstractGenerator { return packet; } + public IqPacket retrieveVcardAvatar(final Jid to) { + final IqPacket packet = new IqPacket(IqPacket.TYPE.GET); + packet.setTo(to); + packet.addChild("vCard", "vcard-temp"); + return packet; + } + public IqPacket retrieveAvatarMetaData(final Jid to) { final IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null); if (to != null) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 5c66451ce5d1af7024457d6d92fe1df9d0c832af..50743312ca4fa0f03a43b17a97aaf147a63eac6e 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -279,6 +279,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } else if (Namespace.BOOKMARKS2.equals(node) && account.getJid().asBareJid().equals(from)) { account.setBookmarks(Collections.emptyMap()); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": deleted bookmarks node"); + } else if (Namespace.AVATAR_METADATA.equals(node) && account.getJid().asBareJid().equals(from)) { + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": deleted avatar metadata node"); } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 43d0e769f233daf07b8456b04a622294321dae9b..79da6d551ae1f855b7182bbfb38774ee22eb07b4 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -38,7 +38,6 @@ import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.security.KeyChain; import android.telephony.PhoneStateListener; -import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DisplayMetrics; @@ -48,6 +47,7 @@ import android.util.Pair; import androidx.annotation.BoolRes; import androidx.annotation.IntegerRes; +import androidx.annotation.NonNull; import androidx.core.app.RemoteInput; import androidx.core.content.ContextCompat; @@ -2792,7 +2792,6 @@ public class XmppConnectionService extends Service { } }); } - public void joinMuc(Conversation conversation) { joinMuc(conversation, null, false); } @@ -3010,6 +3009,71 @@ public class XmppConnectionService extends Service { } } + public void deleteAvatar(final Account account) { + final AtomicBoolean executed = new AtomicBoolean(false); + final Runnable onDeleted = + () -> { + if (executed.compareAndSet(false, true)) { + account.setAvatar(null); + databaseBackend.updateAccount(account); + getAvatarService().clear(account); + updateAccountUi(); + } + }; + deleteVcardAvatar(account, onDeleted); + deletePepNode(account, Namespace.AVATAR_DATA); + deletePepNode(account, Namespace.AVATAR_METADATA, onDeleted); + } + + public void deletePepNode(final Account account, final String node) { + deletePepNode(account, node, null); + } + + private void deletePepNode(final Account account, final String node, final Runnable runnable) { + final IqPacket request = mIqGenerator.deleteNode(node); + sendIqPacket(account, request, (a, packet) -> { + if (packet.getType() == IqPacket.TYPE.RESULT) { + Log.d(Config.LOGTAG,a.getJid().asBareJid()+": successfully deleted pep node "+node); + if (runnable != null) { + runnable.run(); + } + } else { + Log.d(Config.LOGTAG,a.getJid().asBareJid()+": failed to delete "+ packet); + } + }); + } + + private void deleteVcardAvatar(final Account account, @NonNull final Runnable runnable) { + final IqPacket retrieveVcard = mIqGenerator.retrieveVcardAvatar(account.getJid().asBareJid()); + sendIqPacket(account, retrieveVcard, (a, response) -> { + if (response.getType() != IqPacket.TYPE.RESULT) { + Log.d(Config.LOGTAG,a.getJid().asBareJid()+": no vCard set. nothing to do"); + return; + } + final Element vcard = response.findChild("vCard", "vcard-temp"); + if (vcard == null) { + Log.d(Config.LOGTAG,a.getJid().asBareJid()+": no vCard set. nothing to do"); + return; + } + Element photo = vcard.findChild("PHOTO"); + if (photo == null) { + photo = vcard.addChild("PHOTO"); + } + photo.clearChildren(); + IqPacket publication = new IqPacket(IqPacket.TYPE.SET); + publication.setTo(a.getJid().asBareJid()); + publication.addChild(vcard); + sendIqPacket(account, publication, (a1, publicationResponse) -> { + if (publicationResponse.getType() == IqPacket.TYPE.RESULT) { + Log.d(Config.LOGTAG,a1.getJid().asBareJid()+": successfully deleted vcard avatar"); + runnable.run(); + } else { + Log.d(Config.LOGTAG, "failed to publish vcard " + publicationResponse.getErrorCondition()); + } + }); + }); + } + private boolean hasEnabledAccounts() { if (this.accounts == null) { return false; @@ -3598,7 +3662,7 @@ public class XmppConnectionService extends Service { if (result.getType() == IqPacket.TYPE.RESULT) { publishAvatarMetadata(account, avatar, options, true, callback); } else if (retry && PublishOptions.preconditionNotMet(result)) { - pushNodeConfiguration(account, "urn:xmpp:avatar:data", options, new OnConfigurationPushed() { + pushNodeConfiguration(account, Namespace.AVATAR_DATA, options, new OnConfigurationPushed() { @Override public void onPushSucceeded() { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": changed node configuration for avatar node"); @@ -3638,7 +3702,7 @@ public class XmppConnectionService extends Service { callback.onAvatarPublicationSucceeded(); } } else if (retry && PublishOptions.preconditionNotMet(result)) { - pushNodeConfiguration(account, "urn:xmpp:avatar:metadata", options, new OnConfigurationPushed() { + pushNodeConfiguration(account, Namespace.AVATAR_METADATA, options, new OnConfigurationPushed() { @Override public void onPushSucceeded() { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": changed node configuration for avatar meta data node"); diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index cb1d0ad31884d8eeaeae8a34c02a3e52566b2a95..0e14fcc8fe86fa5b2513f5c300d3a425a88a3c4a 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -7,6 +7,8 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.View.OnLongClickListener; import android.widget.Button; @@ -14,6 +16,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.StringRes; import com.theartofdev.edmodo.cropper.CropImage; @@ -120,7 +123,25 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC } @Override - public void onSaveInstanceState(Bundle outState) { + public boolean onCreateOptionsMenu(@NonNull final Menu menu) { + getMenuInflater().inflate(R.menu.activity_publish_profile_picture, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + if (item.getItemId() == R.id.action_delete_avatar) { + if (xmppConnectionService != null && account != null) { + xmppConnectionService.deleteAvatar(account); + } + return true; + } else { + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { if (this.avatarUri != null) { outState.putParcelable("uri", this.avatarUri); } diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 09bbda4cdcb4dbbe7a08352f452f931bf7ea4866..72c35a92f6f74dbc9f869610e60eb40d4f29f2ba 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -26,6 +26,8 @@ public final class Namespace { public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0"; public static final String BOOKMARKS = "storage:bookmarks"; public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0"; + public static final String AVATAR_DATA = "urn:xmpp:avatar:data"; + public static final String AVATAR_METADATA = "urn:xmpp:avatar:metadata"; public static final String AVATAR_CONVERSION = "urn:xmpp:pep-vcard-conversion:0"; public static final String JINGLE = "urn:xmpp:jingle:1"; public static final String JINGLE_ERRORS = "urn:xmpp:jingle:errors:1"; diff --git a/src/main/res/menu/activity_publish_profile_picture.xml b/src/main/res/menu/activity_publish_profile_picture.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcfb99ae83fc100ba426e10187415376d97fff09 --- /dev/null +++ b/src/main/res/menu/activity_publish_profile_picture.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 299c57b3367596be7e495af42eb82d3643147189..53fb4871df2f9348faba349bf306a2aa1852bf7c 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -979,5 +979,6 @@ Account registrations are not supported No XMPP address found Temporary authentication failure + Delete avatar