aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/pixart/messenger/Config.java4
-rw-r--r--src/main/java/de/pixart/messenger/entities/Account.java6
-rw-r--r--src/main/java/de/pixart/messenger/generator/AbstractGenerator.java5
-rw-r--r--src/main/java/de/pixart/messenger/generator/IqGenerator.java10
-rw-r--r--src/main/java/de/pixart/messenger/parser/MessageParser.java7
-rw-r--r--src/main/java/de/pixart/messenger/persistance/FileBackend.java6
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java256
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationFragment.java13
-rw-r--r--src/main/java/de/pixart/messenger/ui/SettingsActivity.java14
-rw-r--r--src/main/java/de/pixart/messenger/ui/XmppActivity.java6
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/SendButtonTool.java11
-rw-r--r--src/main/java/de/pixart/messenger/utils/Namespace.java2
-rw-r--r--src/main/java/de/pixart/messenger/utils/UIHelper.java3
-rw-r--r--src/main/java/de/pixart/messenger/utils/XEP0392Helper.java30
-rw-r--r--src/main/java/de/pixart/messenger/xmpp/InvalidJid.java5
-rw-r--r--src/main/java/de/pixart/messenger/xmpp/XmppConnection.java4
-rw-r--r--src/main/java/de/pixart/messenger/xmpp/pep/PublishOptions.java7
-rw-r--r--src/main/res/values/defaults.xml1
-rw-r--r--src/main/res/values/strings.xml2
-rw-r--r--src/main/res/xml/preferences.xml5
20 files changed, 276 insertions, 121 deletions
diff --git a/src/main/java/de/pixart/messenger/Config.java b/src/main/java/de/pixart/messenger/Config.java
index ac99b1709..e2914f9d3 100644
--- a/src/main/java/de/pixart/messenger/Config.java
+++ b/src/main/java/de/pixart/messenger/Config.java
@@ -77,6 +77,8 @@ public final class Config {
public static final int CONNECT_DISCO_TIMEOUT = 30;
public static final int MINI_GRACE_PERIOD = 750;
+ public static final boolean XEP_0392 = false; //enables a variant of XEP-0392 that is based on HSLUV
+
public static final int FILE_SIZE = 1048576; // 1 MiB
public static final int AVATAR_SIZE = 480;
@@ -86,8 +88,6 @@ public final class Config {
public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.JPEG;
public static final int IMAGE_QUALITY = 75;
- public static final boolean QUICK_SHARE_ATTACHMENT_CHOICE = true; // set to true to use attachment choice instead of quick share for send button
-
public static final int DEFAULT_ZOOM = 15; //for locations
public final static long LOCATION_FIX_TIME_DELTA = 1000 * 10; // ms
public final static float LOCATION_FIX_SPACE_DELTA = 10; // m
diff --git a/src/main/java/de/pixart/messenger/entities/Account.java b/src/main/java/de/pixart/messenger/entities/Account.java
index a8c72cdf9..46d036419 100644
--- a/src/main/java/de/pixart/messenger/entities/Account.java
+++ b/src/main/java/de/pixart/messenger/entities/Account.java
@@ -638,8 +638,10 @@ public class Account extends AbstractEntity {
return this.avatar;
}
- public void activateGracePeriod(long duration) {
- this.mEndGracePeriod = SystemClock.elapsedRealtime() + duration;
+ public void activateGracePeriod(final long duration) {
+ if (duration > 0) {
+ this.mEndGracePeriod = SystemClock.elapsedRealtime() + duration;
+ }
}
public void deactivateGracePeriod() {
diff --git a/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java b/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java
index 37a098300..507c0c39a 100644
--- a/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java
+++ b/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java
@@ -36,6 +36,7 @@ public abstract class AbstractGenerator {
"http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify",
"http://jabber.org/protocol/nick+notify",
+ Namespace.BOOKMARKS + "+notify",
"urn:xmpp:ping",
"jabber:iq:version",
"http://jabber.org/protocol/chatstates"
@@ -59,11 +60,11 @@ public abstract class AbstractGenerator {
protected XmppConnectionService mXmppConnectionService;
- protected AbstractGenerator(XmppConnectionService service) {
+ AbstractGenerator(XmppConnectionService service) {
this.mXmppConnectionService = service;
}
- protected String getIdentityVersion() {
+ String getIdentityVersion() {
if (mVersion == null) {
this.mVersion = PhoneHelper.getVersionName(mXmppConnectionService);
}
diff --git a/src/main/java/de/pixart/messenger/generator/IqGenerator.java b/src/main/java/de/pixart/messenger/generator/IqGenerator.java
index 918c95e6f..86f58af69 100644
--- a/src/main/java/de/pixart/messenger/generator/IqGenerator.java
+++ b/src/main/java/de/pixart/messenger/generator/IqGenerator.java
@@ -138,6 +138,13 @@ public class IqGenerator extends AbstractGenerator {
return publish("urn:xmpp:avatar:data", item);
}
+ public IqPacket publishElement(final String namespace, final Element element, final Bundle options) {
+ final Element item = new Element("item");
+ item.setAttribute("id", "current");
+ item.addChild(element);
+ return publish(namespace, item, options);
+ }
+
public IqPacket publishAvatarMetadata(final Avatar avatar) {
final Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
@@ -197,6 +204,7 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket publishDeviceIds(final Set<Integer> ids, final Bundle publishOptions) {
final Element item = new Element("item");
+ item.setAttribute("id", "current");
final Element list = item.addChild("list", AxolotlService.PEP_PREFIX);
for (Integer id : ids) {
final Element device = new Element("device");
@@ -209,6 +217,7 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket publishBundles(final SignedPreKeyRecord signedPreKeyRecord, final IdentityKey identityKey,
final Set<PreKeyRecord> preKeyRecords, final int deviceId, Bundle publishOptions) {
final Element item = new Element("item");
+ item.setAttribute("id", "current");
final Element bundle = item.addChild("bundle", AxolotlService.PEP_PREFIX);
final Element signedPreKeyPublic = bundle.addChild("signedPreKeyPublic");
signedPreKeyPublic.setAttribute("signedPreKeyId", signedPreKeyRecord.getId());
@@ -231,6 +240,7 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket publishVerification(byte[] signature, X509Certificate[] certificates, final int deviceId) {
final Element item = new Element("item");
+ item.setAttribute("id", "current");
final Element verification = item.addChild("verification", AxolotlService.PEP_PREFIX);
final Element chain = verification.addChild("chain");
for (int i = 0; i < certificates.length; ++i) {
diff --git a/src/main/java/de/pixart/messenger/parser/MessageParser.java b/src/main/java/de/pixart/messenger/parser/MessageParser.java
index 7cfd69e8b..df85f2f25 100644
--- a/src/main/java/de/pixart/messenger/parser/MessageParser.java
+++ b/src/main/java/de/pixart/messenger/parser/MessageParser.java
@@ -304,6 +304,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
AxolotlService axolotlService = account.getAxolotlService();
axolotlService.registerDevices(from, deviceIds);
mXmppConnectionService.updateAccountUi();
+ } else if (Namespace.BOOKMARKS.equals(node)) {
+ Log.d(Config.LOGTAG, "received bookmarks from " + from);
+ if (account.getJid().asBareJid().equals(from)) {
+ final Element i = items.findChild("item");
+ final Element storage = i == null ? null : i.findChild("storage", Namespace.BOOKMARKS);
+ mXmppConnectionService.processBookmarks(account, storage);
+ }
}
}
diff --git a/src/main/java/de/pixart/messenger/persistance/FileBackend.java b/src/main/java/de/pixart/messenger/persistance/FileBackend.java
index 3bb1e5c4e..6b35219e4 100644
--- a/src/main/java/de/pixart/messenger/persistance/FileBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/FileBackend.java
@@ -641,11 +641,12 @@ public class FileBackend {
bitmap = BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(uri));
return getPepAvatar(bitmap, Bitmap.CompressFormat.PNG, 100);
} catch (Exception e) {
+ return null;
+ } finally {
if (bitmap != null) {
bitmap.recycle();
}
}
- return null;
}
private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
@@ -679,6 +680,9 @@ public class FileBackend {
avatar.width = bitmap.getWidth();
avatar.height = bitmap.getHeight();
return avatar;
+ } catch (OutOfMemoryError e) {
+ Log.d(Config.LOGTAG, "unable to convert avatar to base64 due to low memory");
+ return null;
} catch (Exception e) {
return null;
}
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index e50f0d9e2..f4e0bf877 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -150,6 +150,7 @@ import de.pixart.messenger.xmpp.jingle.OnJinglePacketReceived;
import de.pixart.messenger.xmpp.jingle.stanzas.JinglePacket;
import de.pixart.messenger.xmpp.mam.MamReference;
import de.pixart.messenger.xmpp.pep.Avatar;
+import de.pixart.messenger.xmpp.pep.PublishOptions;
import de.pixart.messenger.xmpp.stanzas.IqPacket;
import de.pixart.messenger.xmpp.stanzas.MessagePacket;
import de.pixart.messenger.xmpp.stanzas.PresencePacket;
@@ -167,11 +168,11 @@ public class XmppConnectionService extends Service {
public static final String ACTION_IDLE_PING = "idle_ping";
public static final String ACTION_FCM_TOKEN_REFRESH = "fcm_token_refresh";
public static final String ACTION_FCM_MESSAGE_RECEIVED = "fcm_message_received";
- private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
- private static final String SETTING_LAST_ACTIVITY_TS = "last_activity_timestamp";
public static final String FDroid = "org.fdroid.fdroid";
public static final String PlayStore = "com.android.vending";
public static final String Yalp = "com.github.yeriomin.yalpstore";
+ private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+ private static final String SETTING_LAST_ACTIVITY_TS = "last_activity_timestamp";
static {
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
@@ -198,7 +199,45 @@ public class XmppConnectionService extends Service {
}
}
};
+ //Ui callback listeners
+ private final Set<OnConversationUpdate> mOnConversationUpdates = Collections.newSetFromMap(new WeakHashMap<OnConversationUpdate, Boolean>());
+ private final Set<OnShowErrorToast> mOnShowErrorToasts = Collections.newSetFromMap(new WeakHashMap<OnShowErrorToast, Boolean>());
+ private final Set<OnAccountUpdate> mOnAccountUpdates = Collections.newSetFromMap(new WeakHashMap<OnAccountUpdate, Boolean>());
+ private final Set<OnCaptchaRequested> mOnCaptchaRequested = Collections.newSetFromMap(new WeakHashMap<OnCaptchaRequested, Boolean>());
+ private final Set<OnRosterUpdate> mOnRosterUpdates = Collections.newSetFromMap(new WeakHashMap<OnRosterUpdate, Boolean>());
+ private final Set<OnUpdateBlocklist> mOnUpdateBlocklist = Collections.newSetFromMap(new WeakHashMap<OnUpdateBlocklist, Boolean>());
+ private final Set<OnMucRosterUpdate> mOnMucRosterUpdate = Collections.newSetFromMap(new WeakHashMap<OnMucRosterUpdate, Boolean>());
+ private final Set<OnKeyStatusUpdated> mOnKeyStatusUpdated = Collections.newSetFromMap(new WeakHashMap<OnKeyStatusUpdated, Boolean>());
+ private final Object LISTENER_LOCK = new Object();
public DatabaseBackend databaseBackend;
+ private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
+
+ @Override
+ public boolean onMessageAcknowledged(Account account, String uuid) {
+ for (final Conversation conversation : getConversations()) {
+ if (conversation.getAccount() == account) {
+ Message message = conversation.findUnsentMessageWithUuid(uuid);
+ if (message != null) {
+ message.setStatus(Message.STATUS_SEND);
+ message.setErrorMessage(null);
+ databaseBackend.updateMessage(message, false);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ };
+ public FileBackend fileBackend = new FileBackend(this);
+ private final ConversationsFileObserver fileObserver = new ConversationsFileObserver(
+ Environment.getExternalStorageDirectory().getAbsolutePath()
+ ) {
+ @Override
+ public void onEvent(int event, String path) {
+ markFileDeleted(path);
+ }
+ };
+ public HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(this);
private ReplacingSerialSingleThreadExecutor mContactMergerExecutor = new ReplacingSerialSingleThreadExecutor(true);
private long mLastActivity = 0;
private ContentObserver contactObserver = new ContentObserver(null) {
@@ -211,7 +250,6 @@ public class XmppConnectionService extends Service {
startService(intent);
}
};
- public FileBackend fileBackend = new FileBackend(this);
private MemorizingTrustManager mMemorizingTrustManager;
private NotificationService mNotificationService = new NotificationService(this);
private ShortcutService mShortcutService = new ShortcutService(this);
@@ -221,6 +259,9 @@ public class XmppConnectionService extends Service {
private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
private IqParser mIqParser = new IqParser(this);
private MessageGenerator mMessageGenerator = new MessageGenerator(this);
+ private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
+ private List<Account> accounts;
+ private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(this);
public OnContactStatusChanged onContactStatusChanged = (contact, online) -> {
Conversation conversation = find(getConversations(), contact);
if (conversation != null) {
@@ -240,9 +281,6 @@ public class XmppConnectionService extends Service {
}
}
};
- private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
- private List<Account> accounts;
- private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(this);
private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
@Override
@@ -250,51 +288,9 @@ public class XmppConnectionService extends Service {
mJingleConnectionManager.deliverPacket(account, packet);
}
};
- public HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(this);
private AvatarService mAvatarService = new AvatarService(this);
private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
private PushManagementService mPushManagementService = new PushManagementService(this);
- private final ConversationsFileObserver fileObserver = new ConversationsFileObserver(
- Environment.getExternalStorageDirectory().getAbsolutePath()
- ) {
- @Override
- public void onEvent(int event, String path) {
- markFileDeleted(path);
- }
- };
- private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
-
- @Override
- public boolean onMessageAcknowledged(Account account, String uuid) {
- for (final Conversation conversation : getConversations()) {
- if (conversation.getAccount() == account) {
- Message message = conversation.findUnsentMessageWithUuid(uuid);
- if (message != null) {
- message.setStatus(Message.STATUS_SEND);
- message.setErrorMessage(null);
- databaseBackend.updateMessage(message, false);
- return true;
- }
- }
- }
- return false;
- }
- };
-
- private int unreadCount = -1;
-
- //Ui callback listeners
- private final Set<OnConversationUpdate> mOnConversationUpdates = Collections.newSetFromMap(new WeakHashMap<OnConversationUpdate, Boolean>());
- private final Set<OnShowErrorToast> mOnShowErrorToasts = Collections.newSetFromMap(new WeakHashMap<OnShowErrorToast, Boolean>());
- private final Set<OnAccountUpdate> mOnAccountUpdates = Collections.newSetFromMap(new WeakHashMap<OnAccountUpdate, Boolean>());
- private final Set<OnCaptchaRequested> mOnCaptchaRequested = Collections.newSetFromMap(new WeakHashMap<OnCaptchaRequested, Boolean>());
- private final Set<OnRosterUpdate> mOnRosterUpdates = Collections.newSetFromMap(new WeakHashMap<OnRosterUpdate, Boolean>());
- private final Set<OnUpdateBlocklist> mOnUpdateBlocklist = Collections.newSetFromMap(new WeakHashMap<OnUpdateBlocklist, Boolean>());
- private final Set<OnMucRosterUpdate> mOnMucRosterUpdate = Collections.newSetFromMap(new WeakHashMap<OnMucRosterUpdate, Boolean>());
- private final Set<OnKeyStatusUpdated> mOnKeyStatusUpdated = Collections.newSetFromMap(new WeakHashMap<OnKeyStatusUpdated, Boolean>());
-
- private final Object LISTENER_LOCK = new Object();
-
private final OnBindListener mOnBindListener = new OnBindListener() {
@Override
@@ -315,7 +311,9 @@ public class XmppConnectionService extends Service {
account.getRoster().clearPresences();
mJingleConnectionManager.cancelInTransmission();
fetchRosterFromServer(account);
- fetchBookmarks(account);
+ if (!account.getXmppConnection().getFeatures().bookmarksConversion()) {
+ fetchBookmarks(account);
+ }
final boolean flexible = account.getXmppConnection().getFeatures().flexibleOfflineMessageRetrieval();
final boolean catchup = getMessageArchiveService().inCatchup(account);
if (flexible && catchup) {
@@ -333,6 +331,7 @@ public class XmppConnectionService extends Service {
syncDirtyContacts(account);
}
};
+ private int unreadCount = -1;
private AtomicLong mLastExpiryRun = new AtomicLong(0);
private SecureRandom mRandom;
private LruCache<Pair<String, String>, ServiceDiscoveryResult> discoCache = new LruCache<>(20);
@@ -925,6 +924,10 @@ public class XmppConnectionService extends Service {
}
}
+ public boolean getAttachmentChoicePreference() {
+ return getBooleanPreference(SettingsActivity.QUICK_SHARE_ATTACHMENT_CHOICE, R.bool.quick_share_attachment_choice);
+ }
+
private Presence.Status getTargetPresence() {
if (dndOnSilentMode() && isPhoneSilenced()) {
return Presence.Status.DND;
@@ -1494,7 +1497,7 @@ public class XmppConnectionService extends Service {
@Override
public void onMessageFound(Message message) {
if (mHttpConnectionManager.getAutoAcceptFileSize() >= message.getFileParams().size) {
- Log.d(Config.LOGTAG, "Resend failed message with size " + message.getFileParams().size + " bytes for " + conversation.getJid());
+ Log.d(Config.LOGTAG, "Resend failed message with size " + message.getFileParams().size + " bytes for " + conversation.getJid());
resendMessage(message, true);
}
}
@@ -1520,45 +1523,53 @@ public class XmppConnectionService extends Service {
public void fetchBookmarks(final Account account) {
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
final Element query = iqPacket.query("jabber:iq:private");
- query.addChild("storage", "storage:bookmarks");
- final OnIqPacketReceived callback = new OnIqPacketReceived() {
+ query.addChild("storage", Namespace.BOOKMARKS);
+ final OnIqPacketReceived callback = (a, response) -> {
+ if (response.getType() == IqPacket.TYPE.RESULT) {
+ final Element query1 = response.query();
+ final Element storage = query1.findChild("storage", "storage:bookmarks");
+ processBookmarks(a, storage);
+ } else {
+ Log.d(Config.LOGTAG, a.getJid().asBareJid() + ": could not fetch bookmarks");
+ }
+ };
+ sendIqPacket(account, iqPacket, callback);
+ }
- @Override
- public void onIqPacketReceived(final Account account, final IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- final Element query = packet.query();
- final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
- final Element storage = query.findChild("storage", "storage:bookmarks");
- final boolean autojoin = respectAutojoin();
- if (storage != null) {
- for (final Element item : storage.getChildren()) {
- if (item.getName().equals("conference")) {
- final Bookmark bookmark = Bookmark.parse(item, account);
- Bookmark old = bookmarks.put(bookmark.getJid(), bookmark);
- if (old != null && old.getBookmarkName() != null && bookmark.getBookmarkName() == null) {
- bookmark.setBookmarkName(old.getBookmarkName());
- }
- Conversation conversation = find(bookmark);
- if (conversation != null) {
- bookmark.setConversation(conversation);
- } else if (bookmark.autojoin() && bookmark.getJid() != null && autojoin) {
- conversation = findOrCreateConversation(account, bookmark.getJid(), true, true, false);
- bookmark.setConversation(conversation);
- }
- }
- }
+ public void processBookmarks(Account account, Element storage) {
+ final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
+ final boolean autojoin = respectAutojoin();
+ if (storage != null) {
+ for (final Element item : storage.getChildren()) {
+ if (item.getName().equals("conference")) {
+ final Bookmark bookmark = Bookmark.parse(item, account);
+ Bookmark old = bookmarks.put(bookmark.getJid(), bookmark);
+ if (old != null && old.getBookmarkName() != null && bookmark.getBookmarkName() == null) {
+ bookmark.setBookmarkName(old.getBookmarkName());
+ }
+ Conversation conversation = find(bookmark);
+ if (conversation != null) {
+ bookmark.setConversation(conversation);
+ } else if (bookmark.autojoin() && bookmark.getJid() != null && autojoin) {
+ conversation = findOrCreateConversation(account, bookmark.getJid(), true, true, false);
+ bookmark.setConversation(conversation);
}
- account.setBookmarks(new CopyOnWriteArrayList<>(bookmarks.values()));
- } else {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not fetch bookmarks");
}
}
- };
- sendIqPacket(account, iqPacket, callback);
+ }
+ account.setBookmarks(new CopyOnWriteArrayList<>(bookmarks.values()));
}
public void pushBookmarks(Account account) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmarks");
+ if (account.getXmppConnection().getFeatures().bookmarksConversion()) {
+ pushBookmarksPep(account);
+ } else {
+ pushBookmarksPrivateXml(account);
+ }
+ }
+
+ private void pushBookmarksPrivateXml(Account account) {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmarks via private xml");
IqPacket iqPacket = new IqPacket(IqPacket.TYPE.SET);
Element query = iqPacket.query("jabber:iq:private");
Element storage = query.addChild("storage", "storage:bookmarks");
@@ -1568,6 +1579,46 @@ public class XmppConnectionService extends Service {
sendIqPacket(account, iqPacket, mDefaultIqHandler);
}
+ private void pushBookmarksPep(Account account) {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmarks via pep");
+ Element storage = new Element("storage", "storage:bookmarks");
+ for (Bookmark bookmark : account.getBookmarks()) {
+ storage.addChild(bookmark);
+ }
+ pushNodeAndEnforcePublishOptions(account, Namespace.BOOKMARKS, storage, PublishOptions.persistentWhitelistAccess());
+ }
+
+ private void pushNodeAndEnforcePublishOptions(final Account account, final String node, final Element element, final Bundle options) {
+ pushNodeAndEnforcePublishOptions(account, node, element, options, true);
+ }
+
+ private void pushNodeAndEnforcePublishOptions(final Account account, final String node, final Element element, final Bundle options, final boolean retry) {
+ IqPacket packet = mIqGenerator.publishElement(node, element, options);
+ Log.d(Config.LOGTAG, packet.toString());
+ sendIqPacket(account, packet, (a, response) -> {
+ if (response.getType() == IqPacket.TYPE.RESULT) {
+ return;
+ }
+ final Element error = response.getType() == IqPacket.TYPE.ERROR ? response.findChild("error") : null;
+ final boolean preconditionNotMet = error != null && error.hasChild("precondition-not-met", Namespace.PUBSUB_ERROR);
+ if (retry && preconditionNotMet) {
+ pushNodeConfiguration(account, node, options, new OnConfigurationPushed() {
+ @Override
+ public void onPushSucceeded() {
+ pushNodeAndEnforcePublishOptions(account, node, element, options, false);
+ }
+
+ @Override
+ public void onPushFailed() {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to push node configuration (" + node + ")");
+ }
+ });
+ } else {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": error publishing bookmarks (retry=" + Boolean.toString(retry) + ") " + response);
+ }
+ });
+ }
+
private void restoreFromDatabase() {
synchronized (this.conversations) {
final Map<String, Account> accountLookupTable = new Hashtable<>();
@@ -1860,7 +1911,7 @@ public class XmppConnectionService extends Service {
conversation.setContactJid(jid.asBareJid());
}
databaseBackend.updateConversation(conversation);
- loadMessagesFromDb = conversation.messagesLoaded.compareAndSet(true,false);
+ loadMessagesFromDb = conversation.messagesLoaded.compareAndSet(true, false);
} else {
String conversationName;
Contact contact = account.getRoster().getContact(jid);
@@ -1934,7 +1985,7 @@ public class XmppConnectionService extends Service {
conversation.setContactJid(jid.asBareJid());
}
databaseBackend.updateConversation(conversation);
- loadMessagesFromDb = conversation.messagesLoaded.compareAndSet(true,false);
+ loadMessagesFromDb = conversation.messagesLoaded.compareAndSet(true, false);
} else {
String conversationName;
Contact contact = account.getRoster().getContact(jid);
@@ -2147,7 +2198,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnConversationUpdates.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as ConversationListChangedListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as ConversationListChangedListener");
}
this.mNotificationService.setIsInForeground(this.mOnConversationUpdates.size() > 0);
}
@@ -2173,7 +2224,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnShowErrorToasts.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnShowErrorToastListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnShowErrorToastListener");
}
}
if (remainingListeners) {
@@ -2197,7 +2248,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnAccountUpdates.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnAccountListChangedtListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnAccountListChangedtListener");
}
}
if (remainingListeners) {
@@ -2221,7 +2272,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnCaptchaRequested.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnCaptchaRequestListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnCaptchaRequestListener");
}
}
if (remainingListeners) {
@@ -2245,7 +2296,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnRosterUpdates.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnRosterUpdateListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnRosterUpdateListener");
}
}
if (remainingListeners) {
@@ -2269,7 +2320,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnUpdateBlocklist.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnUpdateBlocklistListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnUpdateBlocklistListener");
}
}
if (remainingListeners) {
@@ -2293,7 +2344,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnKeyStatusUpdated.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnKeyStatusUpdateListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnKeyStatusUpdateListener");
}
}
if (remainingListeners) {
@@ -2317,7 +2368,7 @@ public class XmppConnectionService extends Service {
synchronized (LISTENER_LOCK) {
remainingListeners = checkListeners();
if (!this.mOnMucRosterUpdate.add(listener)) {
- Log.w(Config.LOGTAG,listener.getClass().getName()+" is already registered as OnMucRosterListener");
+ Log.w(Config.LOGTAG, listener.getClass().getName() + " is already registered as OnMucRosterListener");
}
}
if (remainingListeners) {
@@ -2581,7 +2632,7 @@ public class XmppConnectionService extends Service {
}
private boolean hasEnabledAccounts() {
- for(Account account : this.accounts) {
+ for (Account account : this.accounts) {
if (account.isEnabled()) {
return true;
}
@@ -2744,13 +2795,13 @@ public class XmppConnectionService extends Service {
if (callback != null) {
callback.error(R.string.conference_creation_failed, null);
}
- return true;
+ return false;
}
} else {
if (callback != null) {
callback.error(R.string.not_connected_try_again, null);
}
- return true;
+ return false;
}
}
@@ -2796,6 +2847,7 @@ public class XmppConnectionService extends Service {
}
public void pushNodeConfiguration(Account account, final String node, final Bundle options, final OnConfigurationPushed callback) {
+ Log.d(Config.LOGTAG, "pushing node configuration");
pushNodeConfiguration(account, account.getJid().asBareJid(), node, options, callback);
}
@@ -3172,7 +3224,7 @@ public class XmppConnectionService extends Service {
getAvatarService().clear(account);
databaseBackend.updateAccount(account);
}
- Log.d(Config.LOGTAG,account.getJid().asBareJid()+": published avatar "+(avatar.size/1024)+"KiB");
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": published avatar " + (avatar.size / 1024) + "KiB");
if (callback != null) {
callback.onAvatarPublicationSucceeded();
}
@@ -3185,7 +3237,7 @@ public class XmppConnectionService extends Service {
});
} else {
Element error = result.findChild("error");
- Log.d(Config.LOGTAG,account.getJid().asBareJid()+": server rejected avatar "+(avatar.size/1024)+"KiB "+(error!=null?error.toString():""));
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server rejected avatar " + (avatar.size / 1024) + "KiB " + (error != null ? error.toString() : ""));
if (callback != null) {
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_server_reject);
}
@@ -3539,7 +3591,7 @@ public class XmppConnectionService extends Service {
public long getLongPreference(String name, @IntegerRes int res) {
long defaultValue = getResources().getInteger(res);
try {
- return Long.parseLong(getPreferences().getString(name,String.valueOf(defaultValue)));
+ return Long.parseLong(getPreferences().getString(name, String.valueOf(defaultValue)));
} catch (NumberFormatException e) {
return defaultValue;
}
@@ -3777,7 +3829,7 @@ public class XmppConnectionService extends Service {
public void updateMemorizingTrustmanager() {
final MemorizingTrustManager tm;
- final boolean dontTrustSystemCAs = getPreferences().getBoolean("dont_trust_system_cas", getResources().getBoolean(R.bool.dont_trust_system_cas));
+ final boolean dontTrustSystemCAs = getBooleanPreference("dont_trust_system_cas", R.bool.dont_trust_system_cas);
if (dontTrustSystemCAs) {
tm = new MemorizingTrustManager(getApplicationContext(), null);
} else {
@@ -4270,11 +4322,11 @@ public class XmppConnectionService extends Service {
}
public boolean blindTrustBeforeVerification() {
- return getPreferences().getBoolean(SettingsActivity.BLIND_TRUST_BEFORE_VERIFICATION, getResources().getBoolean(R.bool.btbv));
+ return getBooleanPreference(SettingsActivity.BLIND_TRUST_BEFORE_VERIFICATION, R.bool.btbv);
}
public boolean showForegroundService() {
- return getPreferences().getBoolean(SettingsActivity.SHOW_FOREGROUND_SERVICE, getResources().getBoolean(R.bool.show_foreground_service));
+ return getBooleanPreference(SettingsActivity.SHOW_FOREGROUND_SERVICE, R.bool.show_foreground_service);
}
public void ScheduleAutomaticExport() {
@@ -4293,7 +4345,7 @@ public class XmppConnectionService extends Service {
if (timetoexport.before(now)) {
SimpleDateFormat newDate = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
timetoexport.add(Calendar.DAY_OF_YEAR, 1); //DATE or DAY_OF_MONTH
- Log.d(Config.LOGTAG, "Schedule automatic export logs, for today, the export time is in the past, scheduling first export run for the next day ("+ newDate.format(timetoexport.getTimeInMillis()) +").");
+ Log.d(Config.LOGTAG, "Schedule automatic export logs, for today, the export time is in the past, scheduling first export run for the next day (" + newDate.format(timetoexport.getTimeInMillis()) + ").");
}
final PendingIntent ScheduleExportIntent = PendingIntent.getBroadcast(this, AlarmReceiver.SCHEDULE_ALARM_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
((AlarmManager) getSystemService(ALARM_SERVICE)).setInexactRepeating(AlarmManager.RTC_WAKEUP, timetoexport.getTimeInMillis(), AlarmManager.INTERVAL_DAY, ScheduleExportIntent);
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
index 0374e643c..ec9dcf8f0 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
@@ -126,6 +126,7 @@ import rocks.xmpp.addr.Jid;
import static de.pixart.messenger.ui.XmppActivity.EXTRA_ACCOUNT;
import static de.pixart.messenger.ui.XmppActivity.REQUEST_INVITE_TO_CONVERSATION;
+import static de.pixart.messenger.ui.util.SendButtonAction.TEXT;
import static de.pixart.messenger.ui.util.SoftKeyboardUtils.hideSoftKeyboard;
import static de.pixart.messenger.xmpp.Patches.ENCRYPTION_EXCEPTIONS;
@@ -1186,7 +1187,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
menuNeedHelp.setVisible(true);
menuSearchUpdates.setVisible(false);
- ConversationMenuConfigurator.configureAttachmentMenu(conversation, menu, Config.QUICK_SHARE_ATTACHMENT_CHOICE);
+ ConversationMenuConfigurator.configureAttachmentMenu(conversation, menu, activity.xmppConnectionService.getAttachmentChoicePreference());
ConversationMenuConfigurator.configureEncryptionMenu(conversation, menu);
} else {
menuNeedHelp.setVisible(false);
@@ -1223,11 +1224,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
final boolean received = message.getStatus() <= Message.STATUS_RECEIVED;
if (received) {
if (message.getConversation() instanceof Conversation && message.getConversation().getMode() == Conversation.MODE_MULTI) {
+ Jid tcp = message.getTrueCounterpart();
Jid user = message.getCounterpart();
if (user != null && !user.isBareJid()) {
final MucOptions mucOptions = ((Conversation) message.getConversation()).getMucOptions();
if (mucOptions.participating() || ((Conversation) message.getConversation()).getNextCounterpart() != null) {
- if (!mucOptions.isUserInRoom(user)) {
+ if (!mucOptions.isUserInRoom(user) && mucOptions.findUserByRealJid(tcp == null ? null : tcp.asBareJid()) == null) {
Toast.makeText(getActivity(), activity.getString(R.string.user_has_left_conference, user.getResource()), Toast.LENGTH_SHORT).show();
}
highlightInConference(user.getResource());
@@ -2411,7 +2413,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
showSnackbar(R.string.conference_kicked, R.string.join, joinMuc);
break;
case UNKNOWN:
- showSnackbar(R.string.conference_unknown_error, R.string.leave, joinMuc);
+ showSnackbar(R.string.conference_unknown_error, R.string.join, joinMuc);
break;
case INVALID_NICK:
showSnackbar(R.string.invalid_muc_nick, R.string.edit, clickToMuc);
@@ -2556,7 +2558,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
final Conversation c = this.conversation;
final Presence.Status status;
final String text = this.binding.textinput == null ? "" : this.binding.textinput.getText().toString();
- final SendButtonAction action = SendButtonTool.getAction(getActivity(), c, text);
+ SendButtonAction action = SendButtonTool.getAction(getActivity(), c, text);
if (useSendButtonToIndicateStatus && c.getAccount().getStatus() == Account.State.ONLINE) {
if (activity.xmppConnectionService != null && activity.xmppConnectionService.getMessageArchiveService().isCatchingUp(c)) {
status = Presence.Status.OFFLINE;
@@ -2568,6 +2570,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
} else {
status = Presence.Status.OFFLINE;
}
+ if (action.toString().equals("CHOOSE_ATTACHMENT") && !activity.xmppConnectionService.getAttachmentChoicePreference()) {
+ action = TEXT;
+ }
this.binding.textSendButton.setTag(action);
this.binding.textSendButton.setImageResource(SendButtonTool.getSendButtonImageResource(getActivity(), action, status));
}
diff --git a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
index 9ee11bd0b..1ace03e5e 100644
--- a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
@@ -58,12 +58,15 @@ public class SettingsActivity extends XmppActivity implements
public static final String SHOW_FOREGROUND_SERVICE = "show_foreground_service";
public static final String USE_BUNDLED_EMOJIS = "use_bundled_emoji";
public static final String USE_MULTI_ACCOUNTS = "use_multi_accounts";
+ public static final String QUICK_SHARE_ATTACHMENT_CHOICE = "quick_share_attachment_choice";
public static final int REQUEST_WRITE_LOGS = 0xbf8701;
Preference multiAccountPreference;
Preference BundledEmojiPreference;
+ Preference QuickShareAttachmentChoicePreference;
boolean isMultiAccountChecked = false;
boolean isBundledEmojiChecked;
+ boolean isQuickShareAttachmentChoiceChecked = false;
private SettingsFragment mSettingsFragment;
@Override
@@ -105,6 +108,15 @@ public class SettingsActivity extends XmppActivity implements
isBundledEmojiChecked = ((CheckBoxPreference) BundledEmojiPreference).isChecked();
}
+ QuickShareAttachmentChoicePreference = mSettingsFragment.findPreference("quick_share_attachment_choice");
+ if (QuickShareAttachmentChoicePreference != null) {
+ QuickShareAttachmentChoicePreference.setOnPreferenceChangeListener((preference, newValue) -> {
+ recreate();
+ return true;
+ });
+ isQuickShareAttachmentChoiceChecked = ((CheckBoxPreference) QuickShareAttachmentChoicePreference).isChecked();
+ }
+
changeOmemoSettingSummary();
if (Config.FORCE_ORBOT) {
@@ -173,7 +185,7 @@ public class SettingsActivity extends XmppActivity implements
quickAction.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()]));
}
- if (Config.QUICK_SHARE_ATTACHMENT_CHOICE) {
+ if (isQuickShareAttachmentChoiceChecked) {
if (UIPreferenceScreen != null && quickAction != null) {
UIPreferenceScreen.removePreference(quickAction);
}
diff --git a/src/main/java/de/pixart/messenger/ui/XmppActivity.java b/src/main/java/de/pixart/messenger/ui/XmppActivity.java
index f52b2d72c..3ab6bfc6a 100644
--- a/src/main/java/de/pixart/messenger/ui/XmppActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/XmppActivity.java
@@ -943,7 +943,11 @@ public abstract class XmppActivity extends ActionBarActivity {
}
public void inviteUser() {
- if (xmppConnectionServiceBound && !xmppConnectionService.multipleAccounts()) {
+ if (!xmppConnectionServiceBound) {
+ Toast.makeText(this, R.string.not_connected_try_again, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ if (!xmppConnectionService.multipleAccounts()) {
Account mAccount = xmppConnectionService.getAccounts().get(0);
String user = Jid.of(mAccount.getJid()).getLocal();
String domain = Jid.of(mAccount.getJid()).getDomain();
diff --git a/src/main/java/de/pixart/messenger/ui/util/SendButtonTool.java b/src/main/java/de/pixart/messenger/ui/util/SendButtonTool.java
index 291edb822..b4b0ecc28 100644
--- a/src/main/java/de/pixart/messenger/ui/util/SendButtonTool.java
+++ b/src/main/java/de/pixart/messenger/ui/util/SendButtonTool.java
@@ -38,10 +38,9 @@ import de.pixart.messenger.R;
import de.pixart.messenger.entities.Conversation;
import de.pixart.messenger.entities.Presence;
import de.pixart.messenger.ui.ConversationFragment;
+import de.pixart.messenger.ui.SettingsActivity;
import de.pixart.messenger.utils.UIHelper;
-import static de.pixart.messenger.Config.QUICK_SHARE_ATTACHMENT_CHOICE;
-
public class SendButtonTool {
public static SendButtonAction getAction(Activity activity, Conversation c, String text) {
@@ -61,12 +60,13 @@ public class SendButtonTool {
if (conference && c.getNextCounterpart() != null) {
return SendButtonAction.CANCEL;
} else {
- if (QUICK_SHARE_ATTACHMENT_CHOICE && AttachmentsVisible(c)) {
+ boolean quickShareChoice = preferences.getBoolean(SettingsActivity.QUICK_SHARE_ATTACHMENT_CHOICE, activity.getResources().getBoolean(R.bool.quick_share_attachment_choice));
+ String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action));
+ if (quickShareChoice && AttachmentsVisible(c)) {
return SendButtonAction.CHOOSE_ATTACHMENT;
- } else if (QUICK_SHARE_ATTACHMENT_CHOICE && !AttachmentsVisible(c)) {
+ } else if (quickShareChoice && !AttachmentsVisible(c)) {
return SendButtonAction.TEXT;
} else {
- String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action));
if (!setting.equals("none") && UIHelper.receivedLocationQuestion(c.getLatestMessage())) {
return SendButtonAction.SEND_LOCATION;
} else {
@@ -198,5 +198,4 @@ public class SendButtonTool {
return res;
}
-
} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/utils/Namespace.java b/src/main/java/de/pixart/messenger/utils/Namespace.java
index d76e4fede..146a9784d 100644
--- a/src/main/java/de/pixart/messenger/utils/Namespace.java
+++ b/src/main/java/de/pixart/messenger/utils/Namespace.java
@@ -20,4 +20,6 @@ public final class Namespace {
public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = "http://jabber.org/protocol/offline";
public static final String BIND = "urn:ietf:params:xml:ns:xmpp-bind";
public static final String P1_S3_FILE_TRANSFER = "p1:s3filetransfer";
+ public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0";
+ public static final String BOOKMARKS = "storage:bookmarks";
}
diff --git a/src/main/java/de/pixart/messenger/utils/UIHelper.java b/src/main/java/de/pixart/messenger/utils/UIHelper.java
index f5730e981..b603f68ee 100644
--- a/src/main/java/de/pixart/messenger/utils/UIHelper.java
+++ b/src/main/java/de/pixart/messenger/utils/UIHelper.java
@@ -222,6 +222,9 @@ public class UIHelper {
}
public static int getColorForName(String name, boolean safe) {
+ if (Config.XEP_0392) {
+ return XEP0392Helper.rgbFromNick(name);
+ }
if (name == null || name.isEmpty()) {
return 0xFF202020;
}
diff --git a/src/main/java/de/pixart/messenger/utils/XEP0392Helper.java b/src/main/java/de/pixart/messenger/utils/XEP0392Helper.java
new file mode 100644
index 000000000..bbfe50898
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/XEP0392Helper.java
@@ -0,0 +1,30 @@
+package de.pixart.messenger.utils;
+
+import android.graphics.Color;
+
+import org.hsluv.HUSLColorConverter;
+
+import java.security.MessageDigest;
+
+public class XEP0392Helper {
+
+ private static double angle(String nickname) {
+ try {
+ MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+ byte[] digest = sha1.digest(nickname.getBytes("UTF-8"));
+ int angle = ((int) (digest[0]) & 0xff) + ((int) (digest[1]) & 0xff) * 256;
+ return angle / 65536.;
+ } catch (Exception e) {
+ return 0.0;
+ }
+ }
+
+ public static int rgbFromNick(String name) {
+ double[] hsluv = new double[3];
+ hsluv[0] = angle(name) * 360;
+ hsluv[1] = 100;
+ hsluv[2] = 50;
+ double[] rgb = HUSLColorConverter.hsluvToRgb(hsluv);
+ return Color.rgb((int) Math.round(rgb[0] * 255), (int) Math.round(rgb[1] * 255), (int) Math.round(rgb[2] * 255));
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/xmpp/InvalidJid.java b/src/main/java/de/pixart/messenger/xmpp/InvalidJid.java
index ce381abdc..fdaadeab2 100644
--- a/src/main/java/de/pixart/messenger/xmpp/InvalidJid.java
+++ b/src/main/java/de/pixart/messenger/xmpp/InvalidJid.java
@@ -69,6 +69,11 @@ public class InvalidJid implements Jid {
}
@Override
+ public boolean isDomainJid() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
public Jid asBareJid() {
throw new AssertionError("Not implemented");
}
diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
index a6fe3756a..7373291fd 100644
--- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
+++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
@@ -1789,6 +1789,10 @@ public class XmppConnection implements Runnable {
return hasDiscoFeature(Jid.of(account.getServer()), "urn:xmpp:carbons:2");
}
+ public boolean bookmarksConversion() {
+ return hasDiscoFeature(account.getJid().asBareJid(), Namespace.BOOKMARKS_CONVERSION) && pepPublishOptions();
+ }
+
public boolean blocking() {
return hasDiscoFeature(Jid.of(account.getServer()), Namespace.BLOCKING);
}
diff --git a/src/main/java/de/pixart/messenger/xmpp/pep/PublishOptions.java b/src/main/java/de/pixart/messenger/xmpp/pep/PublishOptions.java
index 534f4005c..56b85169c 100644
--- a/src/main/java/de/pixart/messenger/xmpp/pep/PublishOptions.java
+++ b/src/main/java/de/pixart/messenger/xmpp/pep/PublishOptions.java
@@ -14,4 +14,11 @@ public class PublishOptions {
return options;
}
+ public static Bundle persistentWhitelistAccess() {
+ final Bundle options = new Bundle();
+ options.putString("pubsub#persist_items", "true");
+ options.putString("pubsub#access_model", "whitelist");
+ return options;
+ }
+
} \ No newline at end of file
diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml
index 98509a48e..214dbe642 100644
--- a/src/main/res/values/defaults.xml
+++ b/src/main/res/values/defaults.xml
@@ -108,6 +108,7 @@
<string name="default_font_size">small</string>
<bool name="start_searching">false</bool>
<bool name="show_record_voice_btn">true</bool>
+ <bool name="quick_share_attachment_choice">true</bool>
<string-array name="domains">
<item>pix-art.de</item>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 47a01d3c9..f5dabc615 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -810,4 +810,6 @@
<string name="no_location_permission">Pix-Art Messenger needs access to location services</string>
<string name="pref_show_record_voice_btn_summary">Show record voice button in chats as quick action</string>
<string name="pref_show_record_voice_btn">Show record voice button</string>
+ <string name="pref_use_quick_share_attachment_choice_summary">Replace send button with attachment choice if no message is typed. Otherwise show quick actions, which can be cofigured in the following setting.</string>
+ <string name="pref_quick_share_attachment_choice">Attachment choice</string>
</resources>
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index 31ca6158b..b4edb7a34 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -38,6 +38,11 @@
android:key="presence_colored_names"
android:summary="@string/pref_use_colored_names_to_indicate_status_summary"
android:title="@string/pref_use_colored_names_to_indicate_status" />
+ <CheckBoxPreference
+ android:defaultValue="@bool/quick_share_attachment_choice"
+ android:key="quick_share_attachment_choice"
+ android:summary="@string/pref_use_quick_share_attachment_choice_summary"
+ android:title="@string/pref_quick_share_attachment_choice" />
<ListPreference
android:defaultValue="@string/quick_action"
android:dialogTitle="@string/choose_quick_action"