diff options
52 files changed, 679 insertions, 389 deletions
diff --git a/build.gradle b/build.gradle index 1393b25e2..914b8b69d 100644 --- a/build.gradle +++ b/build.gradle @@ -81,6 +81,7 @@ dependencies { implementation 'org.hsluv:hsluv:0.2' implementation 'org.conscrypt:conscrypt-android:1.3.0' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15' + implementation 'me.drakeet.support:toastcompat:1.1.0' } ext { diff --git a/src/main/java/de/pixart/messenger/Config.java b/src/main/java/de/pixart/messenger/Config.java index 5181b24b1..68ab52590 100644 --- a/src/main/java/de/pixart/messenger/Config.java +++ b/src/main/java/de/pixart/messenger/Config.java @@ -18,7 +18,6 @@ public final class Config { private static final int OMEMO = 8; private static final int ENCRYPTION_MASK = UNENCRYPTED | OPENPGP | OTR | OMEMO; - public static boolean supportUnencrypted() { return (ENCRYPTION_MASK & UNENCRYPTED) != 0; } @@ -39,6 +38,7 @@ public final class Config { return (ENCRYPTION_MASK & (ENCRYPTION_MASK - 1)) != 0; } + public static final String LOGTAG = "Pix-Art_Messenger"; public static final Jid BUG_REPORTS = Jid.of("bugs@pix-art.de"); @@ -52,6 +52,7 @@ public final class Config { public static final Integer[] XMPP_Ports = null; //BuildConfig.XMPP_Ports; // set to null means disable public static final String DOMAIN_LOCK = null; //BuildConfig.DOMAIN_LOCK; //only allow account creation for this domain public static final String MAGIC_CREATE_DOMAIN = "blabber.im"; + public static final String QUICKSY_DOMAIN = "quicksy.im"; public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean USE_RANDOM_RESOURCE_ON_EVERY_BIND = false; @@ -59,6 +60,7 @@ public final class Config { public static final boolean ALLOW_NON_TLS_CONNECTIONS = false; //very dangerous. you should have a good reason to set this to true public static final boolean FORCE_ORBOT = false; // always use TOR + public static final boolean HIDE_MESSAGE_TEXT_IN_NOTIFICATION = false; public static final boolean SHOW_CONNECTED_ACCOUNTS = false; //show number of connected accounts in foreground notification diff --git a/src/main/java/de/pixart/messenger/android/AbstractPhoneContact.java b/src/main/java/de/pixart/messenger/android/AbstractPhoneContact.java new file mode 100644 index 000000000..32dbfa77e --- /dev/null +++ b/src/main/java/de/pixart/messenger/android/AbstractPhoneContact.java @@ -0,0 +1,39 @@ +package de.pixart.messenger.android; + +import android.database.Cursor; +import android.net.Uri; +import android.provider.ContactsContract; +import android.text.TextUtils; + +public abstract class AbstractPhoneContact { + + private final Uri lookupUri; + private final String displayName; + private final String photoUri; + + + AbstractPhoneContact(Cursor cursor) { + int phoneId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Data._ID)); + String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY)); + this.lookupUri = ContactsContract.Contacts.getLookupUri(phoneId, lookupKey); + this.displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)); + this.photoUri = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.PHOTO_URI)); + } + + public Uri getLookupUri() { + return lookupUri; + } + + public String getDisplayName() { + return displayName; + } + + public String getPhotoUri() { + return photoUri; + } + + + public int rating() { + return (TextUtils.isEmpty(displayName) ? 0 : 2) + (TextUtils.isEmpty(photoUri) ? 0 : 1); + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/android/JabberIdContact.java b/src/main/java/de/pixart/messenger/android/JabberIdContact.java new file mode 100644 index 000000000..bfafb54c9 --- /dev/null +++ b/src/main/java/de/pixart/messenger/android/JabberIdContact.java @@ -0,0 +1,73 @@ +package de.pixart.messenger.android; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.os.Build; +import android.provider.ContactsContract; +import android.util.Log; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import de.pixart.messenger.Config; +import rocks.xmpp.addr.Jid; + +public class JabberIdContact extends AbstractPhoneContact { + + private final Jid jid; + + private JabberIdContact(Cursor cursor) throws IllegalArgumentException { + super(cursor); + try { + this.jid = Jid.of(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA))); + } catch (IllegalArgumentException | NullPointerException e) { + throw new IllegalArgumentException(e); + } + } + + public Jid getJid() { + return jid; + } + + public static Map<Jid, JabberIdContact> load(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { + return Collections.emptyMap(); + } + final String[] PROJECTION = new String[]{ContactsContract.Data._ID, + ContactsContract.Data.DISPLAY_NAME, + ContactsContract.Data.PHOTO_URI, + ContactsContract.Data.LOOKUP_KEY, + ContactsContract.CommonDataKinds.Im.DATA}; + + final String SELECTION = "(" + ContactsContract.Data.MIMETYPE + "=\"" + + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + + "\") AND (" + ContactsContract.CommonDataKinds.Im.PROTOCOL + + "=\"" + ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER + + "\")"; + final Cursor cursor; + try { + cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null, null); + } catch (Exception e) { + return Collections.emptyMap(); + } + final HashMap<Jid, JabberIdContact> contacts = new HashMap<>(); + while (cursor != null && cursor.moveToNext()) { + try { + final JabberIdContact contact = new JabberIdContact(cursor); + final JabberIdContact preexisting = contacts.put(contact.getJid(), contact); + if (preexisting == null || preexisting.rating() < contact.rating()) { + contacts.put(contact.getJid(), contact); + } + } catch (IllegalArgumentException e) { + Log.d(Config.LOGTAG,"unable to create jabber id contact"); + } + } + if (cursor != null) { + cursor.close(); + } + return contacts; + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/entities/Account.java b/src/main/java/de/pixart/messenger/entities/Account.java index 9e3711535..1bdd130d5 100644 --- a/src/main/java/de/pixart/messenger/entities/Account.java +++ b/src/main/java/de/pixart/messenger/entities/Account.java @@ -73,6 +73,7 @@ public class Account extends AbstractEntity { protected String password; protected int options = 0; protected State status = State.OFFLINE; + private State lastErrorStatus = State.OFFLINE; protected String resource; protected String avatar; protected String hostname = null; @@ -271,8 +272,15 @@ public class Account extends AbstractEntity { } } + public State getLastErrorStatus() { + return this.lastErrorStatus; + } + public void setStatus(final State status) { this.status = status; + if (status.isError || status == State.ONLINE) { + this.lastErrorStatus = status; + } } public State getTrueStatus() { diff --git a/src/main/java/de/pixart/messenger/entities/Bookmark.java b/src/main/java/de/pixart/messenger/entities/Bookmark.java index fc7725bb5..e670673dd 100644 --- a/src/main/java/de/pixart/messenger/entities/Bookmark.java +++ b/src/main/java/de/pixart/messenger/entities/Bookmark.java @@ -87,6 +87,11 @@ public class Bookmark extends Element implements ListItem { return this.jid; } + public Jid getFullJid() { + final String nick = getNick(); + return jid == null || nick == null || nick.trim().isEmpty() ? jid : jid.withResource(nick); + } + @Override public List<Tag> getTags(Context context) { ArrayList<Tag> tags = new ArrayList<>(); @@ -160,7 +165,12 @@ public class Bookmark extends Element implements ListItem { if (this.conversation != null) { this.conversation.clear(); } - this.conversation = new WeakReference<>(conversation); + if (conversation == null) { + this.conversation = null; + } else { + this.conversation = new WeakReference<>(conversation); + conversation.getMucOptions().notifyOfBookmarkNick(getNick()); + } } public String getBookmarkName() { diff --git a/src/main/java/de/pixart/messenger/entities/Contact.java b/src/main/java/de/pixart/messenger/entities/Contact.java index a74b09dff..1df6e120a 100644 --- a/src/main/java/de/pixart/messenger/entities/Contact.java +++ b/src/main/java/de/pixart/messenger/entities/Contact.java @@ -20,6 +20,7 @@ import java.util.Locale; import de.pixart.messenger.Config; import de.pixart.messenger.R; +import de.pixart.messenger.android.AbstractPhoneContact; import de.pixart.messenger.utils.JidHelper; import de.pixart.messenger.utils.UIHelper; import de.pixart.messenger.xml.Element; @@ -48,7 +49,7 @@ public class Contact implements ListItem, Blockable { private String commonName; protected Jid jid; private int subscription = 0; - private String systemAccount; + private Uri systemAccount; private String photoUri; private final JSONObject keys; private JSONArray groups = new JSONArray(); @@ -62,7 +63,7 @@ public class Contact implements ListItem, Blockable { public Contact(final String account, final String systemName, final String serverName, final Jid jid, final int subscription, final String photoUri, - final String systemAccount, final String keys, final String avatar, final long lastseen, + final Uri systemAccount, final String keys, final String avatar, final long lastseen, final String presence, final String groups) { this.accountUuid = account; this.systemName = systemName; @@ -105,13 +106,19 @@ public class Contact implements ListItem, Blockable { // TODO: Borked DB... handle this somehow? return null; } + Uri systemAccount; + try { + systemAccount = Uri.parse(cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT))); + } catch (Exception e) { + systemAccount = null; + } return new Contact(cursor.getString(cursor.getColumnIndex(ACCOUNT)), cursor.getString(cursor.getColumnIndex(SYSTEMNAME)), cursor.getString(cursor.getColumnIndex(SERVERNAME)), jid, cursor.getInt(cursor.getColumnIndex(OPTIONS)), cursor.getString(cursor.getColumnIndex(PHOTOURI)), - cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT)), + systemAccount, cursor.getString(cursor.getColumnIndex(KEYS)), cursor.getString(cursor.getColumnIndex(AVATAR)), cursor.getLong(cursor.getColumnIndex(LAST_TIME)), @@ -159,9 +166,6 @@ public class Contact implements ListItem, Blockable { if (isBlocked()) { tags.add(new Tag(context.getString(R.string.blocked), 0xff2e2f3b, 0)); } - if (showInPhoneBook()) { - tags.add(new Tag(context.getString(R.string.phone_book), 0xFF1E88E5, 0)); - } return tags; } @@ -203,7 +207,7 @@ public class Contact implements ListItem, Blockable { values.put(SERVERNAME, serverName); values.put(JID, jid.toString()); values.put(OPTIONS, subscription); - values.put(SYSTEMACCOUNT, systemAccount); + values.put(SYSTEMACCOUNT, systemAccount != null ? systemAccount.toString() : null); values.put(PHOTOURI, photoUri); values.put(KEYS, keys.toString()); values.put(AVATAR, avatar == null ? null : avatar.getFilename()); @@ -277,21 +281,11 @@ public class Contact implements ListItem, Blockable { } public Uri getSystemAccount() { - if (systemAccount == null) { - return null; - } else { - String[] parts = systemAccount.split("#"); - if (parts.length != 2) { - return null; - } else { - long id = Long.parseLong(parts[0]); - return ContactsContract.Contacts.getLookupUri(id, parts[1]); - } - } + return systemAccount; } - public void setSystemAccount(String account) { - this.systemAccount = account; + public void setSystemAccount(Uri lookupUri) { + this.systemAccount = lookupUri; } private Collection<String> getGroups(final boolean unique) { @@ -390,8 +384,8 @@ public class Contact implements ListItem, Blockable { || (this.getOption(Contact.Options.DIRTY_PUSH)); } - public boolean showInPhoneBook() { - return systemAccount != null && !systemAccount.trim().isEmpty(); + public boolean showInContactList() { + return showInRoster() || getOption(Options.SYNCED_VIA_OTHER); } public void parseSubscriptionFromElement(Element item) { @@ -583,6 +577,27 @@ public class Contact implements ListItem, Blockable { return serverName; } + public synchronized boolean setPhoneContact(AbstractPhoneContact phoneContact) { + setOption(getOption(phoneContact.getClass())); + setSystemAccount(phoneContact.getLookupUri()); + boolean changed = setSystemName(phoneContact.getDisplayName()); + changed |= setPhotoUri(phoneContact.getPhotoUri()); + return changed; + } + public synchronized boolean unsetPhoneContact(Class<?extends AbstractPhoneContact> clazz) { + resetOption(getOption(clazz)); + boolean changed = false; + if (!getOption(Options.SYNCED_VIA_ADDRESSBOOK) && !getOption(Options.SYNCED_VIA_OTHER)) { + setSystemAccount(null); + changed |= setPhotoUri(null); + changed |= setSystemName(null); + } + return changed; + } + public static int getOption(Class<? extends AbstractPhoneContact> clazz) { + return Options.SYNCED_VIA_OTHER; + } + public final class Options { public static final int TO = 0; public static final int FROM = 1; @@ -592,5 +607,7 @@ public class Contact implements ListItem, Blockable { public static final int PENDING_SUBSCRIPTION_REQUEST = 5; public static final int DIRTY_PUSH = 6; public static final int DIRTY_DELETE = 7; + private static final int SYNCED_VIA_ADDRESSBOOK = 8; + public static final int SYNCED_VIA_OTHER = 9; } } diff --git a/src/main/java/de/pixart/messenger/entities/Conversation.java b/src/main/java/de/pixart/messenger/entities/Conversation.java index db6006ca3..1fa1c7a2d 100644 --- a/src/main/java/de/pixart/messenger/entities/Conversation.java +++ b/src/main/java/de/pixart/messenger/entities/Conversation.java @@ -1147,9 +1147,9 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl final Contact contact = getContact(); return mode == MODE_SINGLE && !contact.isOwnServer() - && !contact.showInRoster() + && !contact.showInContactList() && !contact.isSelf() - && !contact.showInPhoneBook() + && !Config.QUICKSY_DOMAIN.equals(contact.getJid().toEscapedString()) && sentMessagesCount() == 0; } diff --git a/src/main/java/de/pixart/messenger/entities/Message.java b/src/main/java/de/pixart/messenger/entities/Message.java index 14d235553..6d11d54d3 100644 --- a/src/main/java/de/pixart/messenger/entities/Message.java +++ b/src/main/java/de/pixart/messenger/entities/Message.java @@ -295,7 +295,7 @@ public class Message extends AbstractEntity { return null; } else { return this.conversation.getAccount().getRoster() - .getContactFromRoster(this.trueCounterpart); + .getContactFromContactList(this.trueCounterpart); } } } @@ -673,7 +673,7 @@ public class Message extends AbstractEntity { public boolean trusted() { Contact contact = this.getContact(); - return status > STATUS_RECEIVED || (contact != null && (contact.showInRoster() || contact.isSelf())); + return status > STATUS_RECEIVED || (contact != null && (contact.showInContactList() || contact.isSelf())); } public boolean fixCounterpart() { diff --git a/src/main/java/de/pixart/messenger/entities/MucOptions.java b/src/main/java/de/pixart/messenger/entities/MucOptions.java index ec7770d77..01ad8816e 100644 --- a/src/main/java/de/pixart/messenger/entities/MucOptions.java +++ b/src/main/java/de/pixart/messenger/entities/MucOptions.java @@ -3,6 +3,7 @@ package de.pixart.messenger.entities; import android.annotation.SuppressLint; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.TextUtils; import java.util.ArrayList; import java.util.Collections; @@ -43,6 +44,7 @@ public class MucOptions { private Error error = Error.NONE; private User self; private String password = null; + private boolean tookProposedNickFromBookmark = false; public MucOptions(Conversation conversation) { this.account = conversation.getAccount(); this.conversation = conversation; @@ -95,6 +97,16 @@ public class MucOptions { } } + public boolean isTookProposedNickFromBookmark() { + return tookProposedNickFromBookmark; + } + + void notifyOfBookmarkNick(String nick) { + if (nick != null && nick.trim().equals(getSelf().getFullJid().getResource())) { + this.tookProposedNickFromBookmark = true; + } + } + public boolean mamSupport() { return MessageArchiveService.Version.has(getFeatures()); } @@ -374,15 +386,21 @@ public class MucOptions { } } - public String getProposedNick() { - if (conversation.getBookmark() != null - && conversation.getBookmark().getNick() != null - && !conversation.getBookmark().getNick().trim().isEmpty()) { - return conversation.getBookmark().getNick().trim(); + private String getProposedNick() { + final Bookmark bookmark = this.conversation.getBookmark(); + final String bookmarkedNick = bookmark == null ? null : bookmark.getNick(); + if (bookmarkedNick != null && !bookmarkedNick.trim().isEmpty()) { + this.tookProposedNickFromBookmark = true; + return bookmarkedNick.trim(); } else if (!conversation.getJid().isBareJid()) { return conversation.getJid().getResource(); } else { - return JidHelper.localPartOrFallback(account.getJid()); + final String displayName = account.getDisplayName(); + if (TextUtils.isEmpty(displayName)) { + return JidHelper.localPartOrFallback(account.getJid()); + } else { + return displayName; + } } } @@ -563,7 +581,7 @@ public class MucOptions { ArrayList<Jid> members = new ArrayList<>(); synchronized (users) { for (User user : users) { - if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null && (!user.isDomain() || includeDomains)) { + if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null && !user.realJid.asBareJid().equals(conversation.account.getJid().asBareJid()) && (!user.isDomain() || includeDomains)) { members.add(user.realJid); } } @@ -730,7 +748,7 @@ public class MucOptions { public Contact getContact() { if (fullJid != null) { - return getAccount().getRoster().getContactFromRoster(realJid); + return getAccount().getRoster().getContactFromContactList(realJid); } else if (realJid != null) { return getAccount().getRoster().getContact(realJid); } else { diff --git a/src/main/java/de/pixart/messenger/entities/Roster.java b/src/main/java/de/pixart/messenger/entities/Roster.java index 2db0c796e..13856c068 100644 --- a/src/main/java/de/pixart/messenger/entities/Roster.java +++ b/src/main/java/de/pixart/messenger/entities/Roster.java @@ -5,24 +5,25 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import de.pixart.messenger.android.AbstractPhoneContact; import rocks.xmpp.addr.Jid; public class Roster { - final Account account; - final HashMap<Jid, Contact> contacts = new HashMap<>(); + private final Account account; + private final HashMap<Jid, Contact> contacts = new HashMap<>(); private String version = null; public Roster(Account account) { this.account = account; } - public Contact getContactFromRoster(Jid jid) { + public Contact getContactFromContactList(Jid jid) { if (jid == null) { return null; } synchronized (this.contacts) { Contact contact = contacts.get(jid.asBareJid()); - if (contact != null && contact.showInRoster()) { + if (contact != null && contact.showInContactList()) { return contact; } else { return null; @@ -54,11 +55,12 @@ public class Roster { } } - public List<Contact> getWithSystemAccounts() { + public List<Contact> getWithSystemAccounts(Class<?extends AbstractPhoneContact> clazz) { + int option = Contact.getOption(clazz); List<Contact> with = getContacts(); for (Iterator<Contact> iterator = with.iterator(); iterator.hasNext(); ) { Contact contact = iterator.next(); - if (contact.getSystemAccount() == null) { + if (!contact.getOption(option)) { iterator.remove(); } } diff --git a/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java b/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java index ac57c74d1..710a4fb8e 100644 --- a/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java +++ b/src/main/java/de/pixart/messenger/generator/AbstractGenerator.java @@ -35,7 +35,7 @@ public abstract class AbstractGenerator { "http://jabber.org/protocol/caps", "http://jabber.org/protocol/disco#info", "urn:xmpp:avatar:metadata+notify", - "http://jabber.org/protocol/nick+notify", + Namespace.NICK + "+notify", Namespace.BOOKMARKS + "+notify", "urn:xmpp:ping", "jabber:iq:version", diff --git a/src/main/java/de/pixart/messenger/generator/IqGenerator.java b/src/main/java/de/pixart/messenger/generator/IqGenerator.java index 86f58af69..cb56d66a8 100644 --- a/src/main/java/de/pixart/messenger/generator/IqGenerator.java +++ b/src/main/java/de/pixart/messenger/generator/IqGenerator.java @@ -126,8 +126,15 @@ public class IqGenerator extends AbstractGenerator { public IqPacket publishNick(String nick) { final Element item = new Element("item"); - item.addChild("nick", "http://jabber.org/protocol/nick").setContent(nick); - return publish("http://jabber.org/protocol/nick", item); + item.addChild("nick", Namespace.NICK).setContent(nick); + return publish(Namespace.NICK, item); + } + + public IqPacket deleteNode(String node) { + IqPacket packet = new IqPacket(IqPacket.TYPE.SET); + final Element pubsub = packet.addChild("pubsub", Namespace.PUBSUB_OWNER); + pubsub.addChild("delete").setAttribute("node", node); + return packet; } public IqPacket publishAvatar(Avatar avatar) { diff --git a/src/main/java/de/pixart/messenger/parser/MessageParser.java b/src/main/java/de/pixart/messenger/parser/MessageParser.java index dca999069..ed12d6473 100644 --- a/src/main/java/de/pixart/messenger/parser/MessageParser.java +++ b/src/main/java/de/pixart/messenger/parser/MessageParser.java @@ -286,16 +286,11 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece mXmppConnectionService.fetchAvatar(account, avatar); } } - } else if ("http://jabber.org/protocol/nick".equals(node)) { + } else if (Namespace.NICK.equals(node)) { final Element i = items.findChild("item"); final String nick = i == null ? null : i.findChildContent("nick", Namespace.NICK); if (nick != null) { - Contact contact = account.getRoster().getContact(from); - if (contact.setPresenceName(nick)) { - mXmppConnectionService.getAvatarService().clear(contact); - } - mXmppConnectionService.updateConversationUi(); - mXmppConnectionService.updateAccountUi(); + setNick(account, from, nick); } } else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) { Element item = items.findChild("item"); @@ -313,6 +308,31 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } + private void parseDeleteEvent(final Element event, final Jid from, final Account account) { + final Element delete = event.findChild("delete"); + if (delete == null) { + return; + } + String node = delete.getAttribute("node"); + if (Namespace.NICK.equals(node)) { + Log.d(Config.LOGTAG, "parsing nick delete event from " + from); + setNick(account, from, null); + } + } + + private void setNick(Account account, Jid user, String nick) { + if (user.asBareJid().equals(account.getJid().asBareJid())) { + account.setDisplayName(nick); + } else { + Contact contact = account.getRoster().getContact(user); + if (contact.setPresenceName(nick)) { + mXmppConnectionService.getAvatarService().clear(contact); + } + } + mXmppConnectionService.updateConversationUi(); + mXmppConnectionService.updateAccountUi(); + } + private boolean handleErrorMessage(Account account, MessagePacket packet) { if (packet.getType() == MessagePacket.TYPE_ERROR) { Jid from = packet.getFrom(); @@ -784,7 +804,9 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } else if ("item".equals(child.getName())) { MucOptions.User user = AbstractParser.parseItem(conversation, child); - Log.d(Config.LOGTAG, account.getJid() + ": changing affiliation for " + user.getRealJid() + " to " + user.getAffiliation() + " in " + conversation.getJid().asBareJid()); + Log.d(Config.LOGTAG, account.getJid() + ": changing affiliation for " + + user.getRealJid() + " to " + user.getAffiliation() + " in " + + conversation.getJid().asBareJid()); if (!user.realJidMatchesAccount()) { boolean isNew = conversation.getMucOptions().updateUser(user); mXmppConnectionService.getAvatarService().clear(conversation); @@ -850,17 +872,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (message.addReadByMarker(readByMarker)) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": added read by (" + readByMarker.getRealJid() + ") to message '" + message.getBody() + "'"); mXmppConnectionService.updateMessage(message, false); - final Message displayedMessage = mXmppConnectionService.markMessage(account, from.asBareJid(), id, Message.STATUS_SEND_DISPLAYED); - Message m = displayedMessage == null ? null : displayedMessage.prev(); - while (m != null - && m.getStatus() == Message.STATUS_SEND_RECEIVED - && m.getTimeSent() < displayedMessage.getTimeSent()) { - mXmppConnectionService.markMessage(m, Message.STATUS_SEND_DISPLAYED); - m = m.prev(); - } - if (displayedMessage != null && selfAddressed) { - dismissNotification(account, counterpart, query); - } } } } @@ -881,9 +892,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } } - Element event = original.findChild("event", "http://jabber.org/protocol/pubsub#event"); + final Element event = original.findChild("event", "http://jabber.org/protocol/pubsub#event"); if (event != null && InvalidJid.hasValidFrom(original)) { - parseEvent(event, original.getFrom(), account); + if (event.hasChild("items")) { + parseEvent(event, original.getFrom(), account); + } else if (event.hasChild("delete")) { + parseDeleteEvent(event, original.getFrom(), account); + } } final String nick = packet.findChildContent("nick", Namespace.NICK); @@ -958,4 +973,4 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece return false; } } -} +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java index 7b316af70..d148ba0f9 100644 --- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java +++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java @@ -664,17 +664,23 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.insert(RESOLVER_RESULTS_TABLENAME, null, contentValues); } - public Resolver.Result findResolverResult(String domain) { + public synchronized Resolver.Result findResolverResult(String domain) { SQLiteDatabase db = this.getReadableDatabase(); String where = Resolver.Result.DOMAIN + "=?"; String[] whereArgs = {domain}; final Cursor cursor = db.query(RESOLVER_RESULTS_TABLENAME, null, where, whereArgs, null, null, null); Resolver.Result result = null; if (cursor != null) { - if (cursor.moveToFirst()) { - result = Resolver.Result.fromCursor(cursor); + try { + if (cursor.moveToFirst()) { + result = Resolver.Result.fromCursor(cursor); + } + } catch (Exception e) { + Log.d(Config.LOGTAG, "unable to find cached resolver result in database " + e.getMessage()); + return null; + } finally { + cursor.close(); } - cursor.close(); } return result; } @@ -928,7 +934,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { final SQLiteDatabase db = this.getWritableDatabase(); db.beginTransaction(); for (Contact contact : roster.getContacts()) { - if (contact.getOption(Contact.Options.IN_ROSTER) || contact.getAvatarFilename() != null) { + if (contact.getOption(Contact.Options.IN_ROSTER) || contact.getAvatarFilename() != null || contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) { db.insert(Contact.TABLENAME, null, contact.getContentValues()); } else { String where = Contact.ACCOUNT + "=? AND " + Contact.JID + "=?"; diff --git a/src/main/java/de/pixart/messenger/services/AbstractQuickConversationsService.java b/src/main/java/de/pixart/messenger/services/AbstractQuickConversationsService.java new file mode 100644 index 000000000..f5647bd60 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/AbstractQuickConversationsService.java @@ -0,0 +1,26 @@ +package de.pixart.messenger.services; + +public abstract class AbstractQuickConversationsService { + + protected final XmppConnectionService service; + + public AbstractQuickConversationsService(XmppConnectionService service) { + this.service = service; + } + + public abstract void considerSync(); + + public static boolean isQuicksy() { + return false; + } + + public static boolean isConversations() { + return true; + } + + public abstract void signalAccountStateChange(); + + public abstract boolean isSynchronizing(); + + public abstract void considerSyncBackground(boolean force); +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/services/AvatarService.java b/src/main/java/de/pixart/messenger/services/AvatarService.java index aa861c147..bd157f442 100644 --- a/src/main/java/de/pixart/messenger/services/AvatarService.java +++ b/src/main/java/de/pixart/messenger/services/AvatarService.java @@ -12,6 +12,7 @@ import android.graphics.RectF; import android.graphics.Typeface; import android.net.Uri; import android.support.annotation.Nullable; +import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.util.LruCache; @@ -80,7 +81,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { if (avatar != null || cachedOnly) { return avatar; } - if (avatar == null && contact.getAvatarFilename() != null) { + if (contact.getAvatarFilename() != null) { avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatarFilename(), size); } if (avatar == null && contact.getProfilePhoto() != null) { @@ -91,7 +92,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { } } if (avatar == null) { - avatar = get(contact.getDisplayName(), contact.getJid().asBareJid().toString(), size, cachedOnly); + avatar = get(contact.getDisplayName(), contact.getJid().asBareJid().toString(), size, false); } this.mXmppConnectionService.getBitmapCache().put(KEY, avatar); return avatar; @@ -165,10 +166,10 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { if (avatar == null) { Contact contact = user.getContact(); if (contact != null) { - avatar = get(contact, size, cachedOnly); + avatar = get(contact, size, false); } else { String seed = user.getRealJid() != null ? user.getRealJid().asBareJid().toString() : null; - avatar = get(user.getName(), seed, size, cachedOnly); + avatar = get(user.getName(), seed, size, false); } } this.mXmppConnectionService.getBitmapCache().put(KEY, avatar); @@ -235,7 +236,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { if (bookmark.getConversation() != null) { return get(bookmark.getConversation(), size, cachedOnly); } else { - Jid jid = bookmark.getJid(); + final Jid jid = bookmark.getFullJid(); Account account = bookmark.getAccount(); Contact contact = jid == null ? null : account.getRoster().getContact(jid); if (contact != null && contact.getAvatarFilename() != null) { @@ -406,7 +407,8 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { } avatar = mXmppConnectionService.getFileBackend().getAvatar(account.getAvatar(), size); if (avatar == null) { - avatar = get(account.getJid().asBareJid().toString(), null, size, false); + final String jid = account.getJid().asBareJid().toEscapedString(); + avatar = get(jid, null, size, false); } mXmppConnectionService.getBitmapCache().put(KEY, avatar); return avatar; @@ -474,7 +476,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { } public Bitmap get(final String name, String seed, final int size, boolean cachedOnly) { - final String KEY = key(seed == null ? name : seed, size); + final String KEY = key(seed == null ? name : name + "\0" + seed, size); Bitmap bitmap = mXmppConnectionService.getBitmapCache().get(KEY); if (bitmap != null || cachedOnly) { return bitmap; @@ -524,11 +526,14 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { Contact contact = user.getContact(); if (contact != null) { Uri uri = null; - if (contact.getProfilePhoto() != null) { + if (contact.getAvatarFilename() != null) { + try { + uri = mXmppConnectionService.getFileBackend().getAvatarUri(contact.getAvatarFilename()); + } catch (Exception e) { + e.printStackTrace(); + } + } else if (contact.getProfilePhoto() != null) { uri = Uri.parse(contact.getProfilePhoto()); - } else if (contact.getAvatarFilename() != null) { - uri = mXmppConnectionService.getFileBackend().getAvatarUri( - contact.getAvatarFilename()); } if (drawTile(canvas, uri, left, top, right, bottom)) { return true; diff --git a/src/main/java/de/pixart/messenger/services/EventReceiver.java b/src/main/java/de/pixart/messenger/services/EventReceiver.java index a77db569e..03bf68ed9 100644 --- a/src/main/java/de/pixart/messenger/services/EventReceiver.java +++ b/src/main/java/de/pixart/messenger/services/EventReceiver.java @@ -13,6 +13,7 @@ import de.pixart.messenger.utils.Compatibility; public class EventReceiver extends BroadcastReceiver { public static final String SETTING_ENABLED_ACCOUNTS = "enabled_accounts"; + public static final String EXTRA_NEEDS_FOREGROUND_SERVICE = "needs_foreground_service"; @Override public void onReceive(final Context context, final Intent originalIntent) { @@ -26,6 +27,7 @@ public class EventReceiver extends BroadcastReceiver { if (action.equals("ui") || hasEnabledAccounts(context)) { try { if (Compatibility.runsAndTargetsTwentySix(context)) { + intentForService.putExtra(EXTRA_NEEDS_FOREGROUND_SERVICE, true); ContextCompat.startForegroundService(context, intentForService); } else { context.startService(intentForService); @@ -42,4 +44,4 @@ public class EventReceiver extends BroadcastReceiver { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTING_ENABLED_ACCOUNTS, true); } -} +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/services/NotificationService.java b/src/main/java/de/pixart/messenger/services/NotificationService.java index 053685fc6..6e93145b8 100644 --- a/src/main/java/de/pixart/messenger/services/NotificationService.java +++ b/src/main/java/de/pixart/messenger/services/NotificationService.java @@ -209,9 +209,9 @@ public class NotificationService { return false; } final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mXmppConnectionService); - final long startTime = preferences.getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY; - final long endTime = preferences.getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY; - final long nowTime = Calendar.getInstance().getTimeInMillis() % Config.MILLISECONDS_IN_DAY; + final long startTime = TimePreference.minutesToTimestamp(preferences.getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE)); + final long endTime = TimePreference.minutesToTimestamp(preferences.getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE)); + final long nowTime = Calendar.getInstance().getTimeInMillis(); if (endTime < startTime) { return nowTime > startTime || nowTime < endTime; @@ -238,7 +238,7 @@ public class NotificationService { } } - public void pushFromDirectReply(final Message message) { + void pushFromDirectReply(final Message message) { synchronized (notifications) { pushToStack(message); updateNotification(false); @@ -264,8 +264,7 @@ public class NotificationService { private List<String> getBacklogConversations(Account account) { final List<String> conversations = new ArrayList<>(); - for (Iterator<Map.Entry<Conversation, AtomicInteger>> it = mBacklogMessageCounter.entrySet().iterator(); it.hasNext(); ) { - Map.Entry<Conversation, AtomicInteger> entry = it.next(); + for (Map.Entry<Conversation, AtomicInteger> entry : mBacklogMessageCounter.entrySet()) { if (entry.getKey().getAccount() == account) { conversations.add(entry.getKey().getUuid()); } @@ -286,7 +285,7 @@ public class NotificationService { return count; } - public void finishBacklog(boolean notify) { + void finishBacklog(boolean notify) { finishBacklog(notify, null); } @@ -385,7 +384,7 @@ public class NotificationService { updateNotification(notify, null, false); } - public void updateNotification(final boolean notify, final List<String> conversations) { + private void updateNotification(final boolean notify, final List<String> conversations) { updateNotification(notify, conversations, false); } @@ -860,7 +859,7 @@ public class NotificationService { return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace); } - public Notification createForegroundNotification() { + Notification createForegroundNotification() { final Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService); mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.conversations_foreground_service)); if (Compatibility.runsAndTargetsTwentySix(mXmppConnectionService) || Config.SHOW_CONNECTED_ACCOUNTS) { @@ -924,18 +923,19 @@ public class NotificationService { return PendingIntent.getActivity(mXmppConnectionService, 0, new Intent(mXmppConnectionService, ConversationsActivity.class), 0); } - public void updateErrorNotification() { + void updateErrorNotification() { if (Config.SUPPRESS_ERROR_NOTIFICATION) { cancel(ERROR_NOTIFICATION_ID); return; } + final boolean showAllErrors = QuickConversationsService.isConversations(); final List<Account> errors = new ArrayList<>(); for (final Account account : mXmppConnectionService.getAccounts()) { - if (account.hasErrorStatus() && account.showErrorNotification()) { + if (account.hasErrorStatus() && account.showErrorNotification() && (showAllErrors || account.getLastErrorStatus() == Account.State.UNAUTHORIZED)) { errors.add(account); } } - if (Compatibility.keepForegroundService(mXmppConnectionService)) { + if (mXmppConnectionService.foregroundNotificationNeedsUpdatingWhenErrorStateChanges()) { notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification()); } final Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService); @@ -978,7 +978,7 @@ public class NotificationService { notify(ERROR_NOTIFICATION_ID, mBuilder.build()); } - public void updateFileAddingNotification(int current, Message message) { + void updateFileAddingNotification(int current, Message message) { Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService); mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.transcoding_video)); mBuilder.setProgress(100, current, false); @@ -992,11 +992,11 @@ public class NotificationService { notify(FOREGROUND_NOTIFICATION_ID, notification); } - public void dismissForcedForegroundNotification() { + void dismissForcedForegroundNotification() { cancel(FOREGROUND_NOTIFICATION_ID); } - public Notification exportLogsNotification() { + Notification exportLogsNotification() { Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService); mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.app_name)); mBuilder.setContentText(mXmppConnectionService.getString(R.string.notification_export_logs_title)); @@ -1009,11 +1009,11 @@ public class NotificationService { return mBuilder.build(); } - public void exportLogsServiceNotification(Notification notification) { + void exportLogsServiceNotification(Notification notification) { notify(FOREGROUND_NOTIFICATION_ID, notification); } - public Notification AppUpdateNotification(PendingIntent intent, String version, String filesize) { + Notification AppUpdateNotification(PendingIntent intent, String version, String filesize) { Notification.Builder mBuilder = new Notification.Builder(mXmppConnectionService); mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.app_name)); mBuilder.setContentText(mXmppConnectionService.getString(R.string.notification_export_logs_title)); diff --git a/src/main/java/de/pixart/messenger/services/QuickConversationsService.java b/src/main/java/de/pixart/messenger/services/QuickConversationsService.java new file mode 100644 index 000000000..e268ac856 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/QuickConversationsService.java @@ -0,0 +1,28 @@ +package de.pixart.messenger.services; + +public class QuickConversationsService extends AbstractQuickConversationsService { + + QuickConversationsService(XmppConnectionService xmppConnectionService) { + super(xmppConnectionService); + } + + @Override + public void considerSync() { + + } + + @Override + public void signalAccountStateChange() { + + } + + @Override + public boolean isSynchronizing() { + return false; + } + + @Override + public void considerSyncBackground(boolean force) { + + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/services/ShortcutService.java b/src/main/java/de/pixart/messenger/services/ShortcutService.java index 0578a8ce5..8051c8849 100644 --- a/src/main/java/de/pixart/messenger/services/ShortcutService.java +++ b/src/main/java/de/pixart/messenger/services/ShortcutService.java @@ -24,7 +24,7 @@ import rocks.xmpp.addr.Jid; public class ShortcutService { private final XmppConnectionService xmppConnectionService; - private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor = new ReplacingSerialSingleThreadExecutor(false); + private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor = new ReplacingSerialSingleThreadExecutor(ShortcutService.class.getSimpleName()); public ShortcutService(XmppConnectionService xmppConnectionService) { this.xmppConnectionService = xmppConnectionService; diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java index bb704c6b6..7c5d2b64d 100644 --- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java +++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java @@ -81,6 +81,7 @@ import java.util.concurrent.atomic.AtomicLong; import de.pixart.messenger.BuildConfig; import de.pixart.messenger.Config; import de.pixart.messenger.R; +import de.pixart.messenger.android.JabberIdContact; import de.pixart.messenger.crypto.OmemoSetting; import de.pixart.messenger.crypto.PgpDecryptionService; import de.pixart.messenger.crypto.PgpEngine; @@ -243,7 +244,7 @@ public class XmppConnectionService extends Service { } }; public HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(this); - private ReplacingSerialSingleThreadExecutor mContactMergerExecutor = new ReplacingSerialSingleThreadExecutor(true); + private ReplacingSerialSingleThreadExecutor mContactMergerExecutor = new ReplacingSerialSingleThreadExecutor("ContactMerger"); private long mLastActivity = 0; private MemorizingTrustManager mMemorizingTrustManager; private NotificationService mNotificationService = new NotificationService(this); @@ -286,6 +287,7 @@ public class XmppConnectionService extends Service { private AvatarService mAvatarService = new AvatarService(this); private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this); private PushManagementService mPushManagementService = new PushManagementService(this); + private QuickConversationsService mQuickConversationsService = new QuickConversationsService(this); private final OnBindListener mOnBindListener = new OnBindListener() { @Override @@ -298,13 +300,22 @@ public class XmppConnectionService extends Service { } } } - boolean needsUpdating = account.setOption(Account.OPTION_LOGGED_IN_SUCCESSFULLY, true); - needsUpdating |= account.setOption(Account.OPTION_HTTP_UPLOAD_AVAILABLE, account.getXmppConnection().getFeatures().httpUpload(0)); - if (needsUpdating) { + boolean loggedInSuccessfully = account.setOption(Account.OPTION_LOGGED_IN_SUCCESSFULLY, true); + boolean gainedFeature = account.setOption(Account.OPTION_HTTP_UPLOAD_AVAILABLE, account.getXmppConnection().getFeatures().httpUpload(0)); + if (loggedInSuccessfully || gainedFeature) { databaseBackend.updateAccount(account); } + + if (loggedInSuccessfully) { + if (!TextUtils.isEmpty(account.getDisplayName())) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": display name wasn't empty on first log in. publishing"); + publishDisplayName(account); + } + } + account.getRoster().clearPresences(); mJingleConnectionManager.cancelInTransmission(); + mQuickConversationsService.considerSyncBackground(false); fetchRosterFromServer(account); if (!account.getXmppConnection().getFeatures().bookmarksConversion()) { fetchBookmarks(account); @@ -336,6 +347,9 @@ public class XmppConnectionService extends Service { public void onStatusChanged(final Account account) { XmppConnection connection = account.getXmppConnection(); updateAccountUi(); + if (account.getStatus() == Account.State.ONLINE || account.getStatus().isError()) { + mQuickConversationsService.signalAccountStateChange(); + } if (account.getStatus() == Account.State.ONLINE) { synchronized (mLowPingTimeoutMode) { if (mLowPingTimeoutMode.remove(account.getJid().asBareJid())) { @@ -567,6 +581,11 @@ public class XmppConnectionService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { final String action = intent == null ? null : intent.getAction(); + final boolean needsForegroundService = intent != null && intent.getBooleanExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, false); + if (needsForegroundService) { + Log.d(Config.LOGTAG, "toggle forced foreground service after receiving event"); + toggleForegroundService(true); + } String pushedAccountHash = null; boolean interactive = false; if (action != null) { @@ -938,15 +957,18 @@ public class XmppConnectionService extends Service { @SuppressLint("NewApi") @SuppressWarnings("deprecation") public boolean isInteractive() { - final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - - final boolean isScreenOn; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - isScreenOn = pm.isScreenOn(); - } else { - isScreenOn = pm.isInteractive(); + try { + final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + final boolean isScreenOn; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + isScreenOn = pm.isScreenOn(); + } else { + isScreenOn = pm.isInteractive(); + } + return isScreenOn; + } catch (RuntimeException e) { + return false; } - return isScreenOn; } private boolean isPhoneSilenced() { @@ -1229,8 +1251,12 @@ public class XmppConnectionService extends Service { } public void toggleForegroundService() { + toggleForegroundService(false); + } + + private void toggleForegroundService(boolean force) { final boolean status; - if (mForceForegroundService.get() || (Compatibility.keepForegroundService(this)/* && hasEnabledAccounts()*/)) { + if (force || mForceForegroundService.get() || (Compatibility.keepForegroundService(this)/* && hasEnabledAccounts()*/)) { startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification()); status = true; } else { @@ -1241,6 +1267,10 @@ public class XmppConnectionService extends Service { Log.d(Config.LOGTAG, "ForegroundService: " + (status ? "on" : "off")); } + public boolean foregroundNotificationNeedsUpdatingWhenErrorStateChanges() { + return !mForceForegroundService.get() && Compatibility.keepForegroundService(this) && hasEnabledAccounts(); + } + @Override public void onTaskRemoved(final Intent rootIntent) { super.onTaskRemoved(rootIntent); @@ -1351,6 +1381,13 @@ public class XmppConnectionService extends Service { } final Conversation conversation = (Conversation) message.getConversation(); account.deactivateGracePeriod(); + if (QuickConversationsService.isQuicksy() && conversation.getMode() == Conversation.MODE_SINGLE) { + final Contact contact = conversation.getContact(); + if (!contact.showInRoster() && contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": adding " + contact.getJid() + " on sending message"); + createContact(contact, true); + } + } MessagePacket packet = null; final boolean addToConversation = (conversation.getMode() != Conversation.MODE_MULTI || !Patches.BAD_MUC_REFLECTION.contains(account.getServerIdentity())) @@ -1585,7 +1622,7 @@ public class XmppConnectionService extends Service { if (conversation != null) { bookmark.setConversation(conversation); } else if (bookmark.autojoin() && bookmark.getJid() != null && autojoin) { - conversation = findOrCreateConversation(account, bookmark.getJid(), true, true, false); + conversation = findOrCreateConversation(account, bookmark.getFullJid(), true, true, false); bookmark.setConversation(conversation); } } @@ -1720,45 +1757,31 @@ public class XmppConnectionService extends Service { } public void loadPhoneContacts() { - mContactMergerExecutor.execute(() -> PhoneHelper.loadPhoneContacts(XmppConnectionService.this, new OnPhoneContactsLoadedListener() { - @Override - public void onPhoneContactsLoaded(List<Bundle> phoneContacts) { - Log.d(Config.LOGTAG, "start merging phone contacts with roster"); - for (Account account : accounts) { - List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts(); - for (Bundle phoneContact : phoneContacts) { - Jid jid; - try { - jid = Jid.of(phoneContact.getString("jid")); - } catch (final IllegalArgumentException e) { - continue; - } - final Contact contact = account.getRoster().getContact(jid); - String systemAccount = phoneContact.getInt("phoneid") - + "#" - + phoneContact.getString("lookup"); - contact.setSystemAccount(systemAccount); - boolean needsCacheClean = contact.setPhotoUri(phoneContact.getString("photouri")); - needsCacheClean |= contact.setSystemName(phoneContact.getString("displayname")); - if (needsCacheClean) { - getAvatarService().clear(contact); - } - withSystemAccounts.remove(contact); + mContactMergerExecutor.execute(() -> { + Map<Jid, JabberIdContact> contacts = JabberIdContact.load(this); + Log.d(Config.LOGTAG, "start merging phone contacts with roster"); + for (Account account : accounts) { + List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts(JabberIdContact.class); + for (JabberIdContact jidContact : contacts.values()) { + final Contact contact = account.getRoster().getContact(jidContact.getJid()); + boolean needsCacheClean = contact.setPhoneContact(jidContact); + if (needsCacheClean) { + getAvatarService().clear(contact); } - for (Contact contact : withSystemAccounts) { - contact.setSystemAccount(null); - boolean needsCacheClean = contact.setPhotoUri(null); - needsCacheClean |= contact.setSystemName(null); - if (needsCacheClean) { - getAvatarService().clear(contact); - } + withSystemAccounts.remove(contact); + } + for (Contact contact : withSystemAccounts) { + boolean needsCacheClean = contact.unsetPhoneContact(JabberIdContact.class); + if (needsCacheClean) { + getAvatarService().clear(contact); } } - Log.d(Config.LOGTAG, "finished merging phone contacts"); - mShortcutService.refresh(mInitialAddressbookSyncCompleted.compareAndSet(false, true)); - updateRosterUi(); } - })); + Log.d(Config.LOGTAG, "finished merging phone contacts"); + mShortcutService.refresh(mInitialAddressbookSyncCompleted.compareAndSet(false, true)); + updateRosterUi(); + mQuickConversationsService.considerSync(); + }); } public void syncRoster(final Account account) { @@ -2072,11 +2095,7 @@ public class XmppConnectionService extends Service { } else { conversation.endOtrIfNeeded(); if (conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { - Log.d(Config.LOGTAG, "Canceling presence request from " + conversation.getJid().toString()); - sendPresencePacket( - conversation.getAccount(), - mPresenceGenerator.stopPresenceUpdatesTo(conversation.getContact()) - ); + stopPresenceUpdatesTo(conversation.getContact()); } } updateConversation(conversation); @@ -2085,6 +2104,12 @@ public class XmppConnectionService extends Service { } } + public void stopPresenceUpdatesTo(Contact contact) { + Log.d(Config.LOGTAG, "Canceling presence request from " + contact.getJid().toString()); + sendPresencePacket(contact.getAccount(), mPresenceGenerator.stopPresenceUpdatesTo(contact)); + contact.resetOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); + } + public void createAccount(final Account account) { account.initAccountServices(this); databaseBackend.createAccount(account); @@ -2695,15 +2720,17 @@ public class XmppConnectionService extends Service { public void persistSelfNick(MucOptions.User self) { final Conversation conversation = self.getConversation(); + final boolean tookProposedNickFromBookmark = conversation.getMucOptions().isTookProposedNickFromBookmark(); Jid full = self.getFullJid(); if (!full.equals(conversation.getJid())) { Log.d(Config.LOGTAG, "nick changed. updating"); conversation.setContactJid(full); databaseBackend.updateConversation(conversation); } - - Bookmark bookmark = conversation.getBookmark(); - if (bookmark != null && !full.getResource().equals(bookmark.getNick())) { + final Bookmark bookmark = conversation.getBookmark(); + final String bookmarkedNick = bookmark == null ? null : bookmark.getNick(); + if (bookmark != null && (tookProposedNickFromBookmark || TextUtils.isEmpty(bookmarkedNick)) && !full.getResource().equals(bookmarkedNick)) { + Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": persist nick '" + full.getResource() + "' into bookmark for " + conversation.getJid().asBareJid()); bookmark.setNick(full.getResource()); pushBookmarks(bookmark.getAccount()); } @@ -3683,11 +3710,11 @@ public class XmppConnectionService extends Service { } public boolean useTorToConnect() { - return Config.FORCE_ORBOT || getBooleanPreference("use_tor", R.bool.use_tor); + return QuickConversationsService.isConversations() && getBooleanPreference("use_tor", R.bool.use_tor); } public boolean showExtendedConnectionOptions() { - return getBooleanPreference("show_connection_options", R.bool.show_connection_options); + return QuickConversationsService.isConversations() && getBooleanPreference("show_connection_options", R.bool.show_connection_options); } public boolean warnUnecryptedChat() { @@ -4053,12 +4080,16 @@ public class XmppConnectionService extends Service { return this.mMessageArchiveService; } + public QuickConversationsService getQuickConversationsService() { + return this.mQuickConversationsService; + } + public List<Contact> findContacts(Jid jid, String accountJid) { ArrayList<Contact> contacts = new ArrayList<>(); for (Account account : getAccounts()) { if ((account.isEnabled() || accountJid != null) && (accountJid == null || accountJid.equals(account.getJid().asBareJid().toString()))) { - Contact contact = account.getRoster().getContactFromRoster(jid); + Contact contact = account.getRoster().getContactFromContactList(jid); if (contact != null) { contacts.add(contact); } @@ -4201,14 +4232,18 @@ public class XmppConnectionService extends Service { public void publishDisplayName(Account account) { String displayName = account.getDisplayName(); - if (displayName != null && !displayName.isEmpty()) { - IqPacket publish = mIqGenerator.publishNick(displayName); - sendIqPacket(account, publish, (account1, packet) -> { - if (packet.getType() == IqPacket.TYPE.ERROR) { - Log.d(Config.LOGTAG, account1.getJid().asBareJid() + ": could not publish nick"); - } - }); + final IqPacket request; + if (TextUtils.isEmpty(displayName)) { + request = mIqGenerator.deleteNode(Namespace.NICK); + } else { + request = mIqGenerator.publishNick(displayName); } + mAvatarService.clear(account); + sendIqPacket(account, request, (account1, packet) -> { + if (packet.getType() == IqPacket.TYPE.ERROR) { + Log.d(Config.LOGTAG, account1.getJid().asBareJid() + ": unable to modify nick name " + packet.toString()); + } + }); } public ServiceDiscoveryResult getCachedServiceDiscoveryResult(Pair<String, String> key) { diff --git a/src/main/java/de/pixart/messenger/ui/ChooseContactActivity.java b/src/main/java/de/pixart/messenger/ui/ChooseContactActivity.java index a760a563b..ac1866fec 100644 --- a/src/main/java/de/pixart/messenger/ui/ChooseContactActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ChooseContactActivity.java @@ -263,7 +263,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im for (final Account account : xmppConnectionService.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { for (final Contact contact : account.getRoster().getContacts()) { - if (contact.showInRoster() && + if (contact.showInContactList() && !filterContacts.contains(contact.getJid().asBareJid().toString()) && contact.match(this, needle)) { getListItems().add(contact); diff --git a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java index 745ed67c7..7f9e971d3 100644 --- a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java @@ -24,6 +24,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; +import android.view.WindowManager; import android.widget.ImageView; import android.widget.Toast; @@ -66,6 +67,7 @@ import de.pixart.messenger.utils.StylingHelper; import de.pixart.messenger.utils.TimeframeUtils; import de.pixart.messenger.utils.UIHelper; import de.pixart.messenger.utils.XmppUri; +import me.drakeet.support.toast.ToastCompat; import rocks.xmpp.addr.Jid; import static de.pixart.messenger.entities.Bookmark.printableValue; @@ -113,8 +115,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers private UiCallback<Conversation> renameCallback = new UiCallback<Conversation>() { @Override public void success(Conversation object) { + displayToast(getString(R.string.your_nick_has_been_changed)); runOnUiThread(() -> { - Toast.makeText(ConferenceDetailsActivity.this, getString(R.string.your_nick_has_been_changed), Toast.LENGTH_SHORT).show(); updateView(); }); @@ -122,7 +124,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override public void error(final int errorCode, Conversation object) { - runOnUiThread(() -> Toast.makeText(ConferenceDetailsActivity.this, getString(errorCode), Toast.LENGTH_SHORT).show()); + displayToast(getString(errorCode)); } @Override @@ -466,7 +468,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.mSelectedUser = user; String name; final Contact contact = user.getContact(); - if (contact != null && contact.showInRoster()) { + if (contact != null && contact.showInContactList()) { name = contact.getDisplayName(); } else if (user.getRealJid() != null) { name = user.getRealJid().asBareJid().toString(); @@ -785,7 +787,12 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } private void displayToast(final String msg) { - runOnUiThread(() -> Toast.makeText(ConferenceDetailsActivity.this, msg, Toast.LENGTH_SHORT).show()); + runOnUiThread(() -> { + if (isFinishing()) { + return; + } + ToastCompat.makeText(this, msg, Toast.LENGTH_SHORT).show(); + }); } public void loadAvatar(User user, ImageView imageView) { diff --git a/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java index 619c2b3f2..9db7ce7c9 100644 --- a/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ContactDetailsActivity.java @@ -86,7 +86,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { - xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator().sendPresenceUpdatesTo(contact)); + xmppConnectionService.stopPresenceUpdatesTo(contact); } else { contact.setOption(Contact.Options.PREEMPTIVE_GRANT); } diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java index 69aa51918..949dba90d 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java @@ -1334,10 +1334,11 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke MenuItem downloadFile = menu.findItem(R.id.download_file); MenuItem deleteFile = menu.findItem(R.id.delete_file); MenuItem showErrorMessage = menu.findItem(R.id.show_error_message); + final boolean showError = m.getStatus() == Message.STATUS_SEND_FAILED && m.getErrorMessage() != null && !Message.ERROR_MESSAGE_CANCELLED.equals(m.getErrorMessage()); deleteMessage.setVisible(true); if (!m.isFileOrImage() && !encrypted && !m.isGeoUri() && !m.treatAsDownloadable()) { copyMessage.setVisible(true); - quoteMessage.setVisible(MessageUtils.prepareQuote(m).length() > 0); + quoteMessage.setVisible(!showError && MessageUtils.prepareQuote(m).length() > 0); String body = m.getMergedBody().toString(); if (ShareUtil.containsXmppUri(body)) { copyLink.setTitle(R.string.copy_jabber_id); @@ -1349,7 +1350,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke if (m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { retryDecryption.setVisible(true); } - if (relevantForCorrection.getType() == Message.TYPE_TEXT + if (!showError + && relevantForCorrection.getType() == Message.TYPE_TEXT && relevantForCorrection.isLastCorrectableMessage() && m.getConversation() instanceof Conversation && (((Conversation) m.getConversation()).getMucOptions().nonanonymous() || m.getConversation().getMode() == Conversation.MODE_SINGLE)) { @@ -1388,7 +1390,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke deleteFile.setTitle(activity.getString(R.string.delete_x_file, UIHelper.getFileDescriptionString(activity, m))); } } - if (m.getStatus() == Message.STATUS_SEND_FAILED && m.getErrorMessage() != null && !Message.ERROR_MESSAGE_CANCELLED.equals(m.getErrorMessage())) { + if (showError) { showErrorMessage.setVisible(true); } } @@ -1883,6 +1885,10 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.error_message); builder.setMessage(message.getErrorMessage()); + builder.setNegativeButton(R.string.copy_to_clipboard, (dialog, which) -> { + activity.copyTextToClipboard(message.getErrorMessage(), R.string.error_message); + Toast.makeText(activity, R.string.error_message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); + }); builder.setPositiveButton(R.string.ok, null); builder.create().show(); } @@ -2332,25 +2338,28 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke private boolean showBlockSubmenu(View view) { final Jid jid = conversation.getJid(); - if (jid.getLocal() == null) { - BlockContactDialog.show(activity, conversation); - } else { - PopupMenu popupMenu = new PopupMenu(getActivity(), view); - popupMenu.inflate(R.menu.block); - popupMenu.setOnMenuItemClickListener(menuItem -> { - Blockable blockable; - switch (menuItem.getItemId()) { - case R.id.block_domain: - blockable = conversation.getAccount().getRoster().getContact(Jid.ofDomain(jid.getDomain())); - break; - default: - blockable = conversation; - } - BlockContactDialog.show(activity, blockable); - return true; - }); - popupMenu.show(); - } + final boolean showReject = !conversation.isWithStranger() && conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); + PopupMenu popupMenu = new PopupMenu(getActivity(), view); + popupMenu.inflate(R.menu.block); + popupMenu.getMenu().findItem(R.id.block_contact).setVisible(jid.getLocal() != null); + popupMenu.getMenu().findItem(R.id.reject).setVisible(showReject); + popupMenu.setOnMenuItemClickListener(menuItem -> { + Blockable blockable; + switch (menuItem.getItemId()) { + case R.id.reject: + activity.xmppConnectionService.stopPresenceUpdatesTo(conversation.getContact()); + updateSnackBar(conversation); + return true; + case R.id.block_domain: + blockable = conversation.getAccount().getRoster().getContact(Jid.ofDomain(jid.getDomain())); + break; + default: + blockable = conversation; + } + BlockContactDialog.show(activity, blockable); + return true; + }); + popupMenu.show(); return true; } diff --git a/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java b/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java index 5daaafacd..92962fb45 100644 --- a/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java +++ b/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java @@ -56,6 +56,7 @@ import de.pixart.messenger.entities.Presence; import de.pixart.messenger.entities.PresenceTemplate; import de.pixart.messenger.entities.ServiceDiscoveryResult; import de.pixart.messenger.services.BarcodeProvider; +import de.pixart.messenger.services.QuickConversationsService; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.services.XmppConnectionService.OnAccountUpdate; import de.pixart.messenger.services.XmppConnectionService.OnCaptchaRequested; @@ -66,6 +67,7 @@ import de.pixart.messenger.ui.util.SoftKeyboardUtils; import de.pixart.messenger.utils.CryptoHelper; import de.pixart.messenger.utils.MenuDoubleTabUtil; import de.pixart.messenger.utils.Namespace; +import de.pixart.messenger.utils.Resolver; import de.pixart.messenger.utils.SignupUtils; import de.pixart.messenger.utils.UIHelper; import de.pixart.messenger.utils.XmppUri; @@ -106,11 +108,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat final String password = binding.accountPassword.getText().toString(); final boolean wasDisabled = mAccount != null && mAccount.getStatus() == Account.State.DISABLED; final boolean accountInfoEdited = accountInfoEdited(); - - if (!mInitMode && passwordChangedInMagicCreateMode()) { - gotoChangePassword(password); - return; - } if (mInitMode && mAccount != null) { mAccount.setOption(Account.OPTION_DISABLED, false); } @@ -206,7 +203,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } } if (mAccount != null) { - if (mInitMode && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) { + if (mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) { mAccount.setOption(Account.OPTION_MAGIC_CREATE, mAccount.getPassword().contains(password)); } mAccount.setJid(jid); @@ -465,11 +462,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat protected void updateSaveButton() { boolean accountInfoEdited = accountInfoEdited(); - - if (!mInitMode && passwordChangedInMagicCreateMode()) { - this.binding.saveButton.setText(R.string.change_password); - this.binding.saveButton.setEnabled(true); - } else if (accountInfoEdited && !mInitMode) { + if (accountInfoEdited && !mInitMode) { this.binding.saveButton.setText(R.string.save); this.binding.saveButton.setEnabled(true); } else if (mAccount != null @@ -528,14 +521,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat return !unmodified.equals(this.binding.accountJid.getText().toString()); } - protected boolean passwordChangedInMagicCreateMode() { - return mAccount != null - && mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) - && !this.mAccount.getPassword().equals(binding.accountPassword.getText().toString()) - && !this.jidEdited() - && mAccount.isOnlineAndConnected(); - } - @Override protected String getShareableUri(boolean http) { if (mAccount != null) { @@ -562,20 +547,17 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat this.binding.hostname.addTextChangedListener(mTextWatcher); this.binding.hostname.setOnFocusChangeListener(mEditTextFocusListener); this.binding.clearDevices.setOnClickListener(v -> showWipePepDialog()); - this.binding.port.setText("5222"); + this.binding.port.setText(String.valueOf(Resolver.DEFAULT_PORT_XMPP)); this.binding.port.addTextChangedListener(mTextWatcher); this.binding.saveButton.setOnClickListener(this.mSaveButtonClickListener); this.binding.cancelButton.setOnClickListener(this.mCancelButtonClickListener); if (savedInstanceState != null && savedInstanceState.getBoolean("showMoreTable")) { changeMoreTableVisibility(true); } - final OnCheckedChangeListener OnCheckedShowConfirmPassword = new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { - updatePortLayout(); - updateSaveButton(); - updateInfoButtons(); - } + final OnCheckedChangeListener OnCheckedShowConfirmPassword = (buttonView, isChecked) -> { + updatePortLayout(); + updateSaveButton(); + updateInfoButtons(); }; this.binding.accountRegisterNew.setOnCheckedChangeListener(OnCheckedShowConfirmPassword); if (Config.DISALLOW_REGISTRATION_IN_UI) { @@ -689,8 +671,8 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } } SharedPreferences preferences = getPreferences(); - mUseTor = Config.FORCE_ORBOT || preferences.getBoolean("use_tor", false); - this.mShowOptions = mUseTor || preferences.getBoolean("show_connection_options", false); + mUseTor = QuickConversationsService.isConversations() && preferences.getBoolean("use_tor", getResources().getBoolean(R.bool.use_tor)); + this.mShowOptions = mUseTor || (QuickConversationsService.isConversations() && preferences.getBoolean("show_connection_options", getResources().getBoolean(R.bool.show_connection_options))); this.binding.namePort.setVisibility(mShowOptions ? View.VISIBLE : View.GONE); } @@ -976,16 +958,18 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } - final boolean editable = !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY); + final boolean editable = !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY) && QuickConversationsService.isConversations(); this.binding.accountJid.setEnabled(editable); this.binding.accountJid.setFocusable(editable); this.binding.accountJid.setFocusableInTouchMode(editable); - if (mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) { - this.binding.accountPasswordLayout.setPasswordVisibilityToggleEnabled(true); - } else { - this.binding.accountPasswordLayout.setPasswordVisibilityToggleEnabled(false); - } + final boolean tooglePassword = mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY); + final boolean editPassword = !mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || (!mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY) && QuickConversationsService.isConversations()) || mAccount.getLastErrorStatus() == Account.State.UNAUTHORIZED; + this.binding.accountPasswordLayout.setPasswordVisibilityToggleEnabled(tooglePassword); + this.binding.accountPassword.setFocusable(editPassword); + this.binding.accountPassword.setFocusableInTouchMode(editPassword); + this.binding.accountPassword.setCursorVisible(editPassword); + this.binding.accountPassword.setEnabled(editPassword); if (!mInitMode) { binding.avater.setVisibility(View.VISIBLE); @@ -1062,7 +1046,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat if (getHttpUploadMaxFileSize().equals("0")) { this.binding.serverInfoHttpUpload.setText(R.string.server_info_available); } else { - this.binding.serverInfoHttpUpload.setText(getString(R.string.server_info_available_with, getHttpUploadMaxFileSize())); + this.binding.serverInfoHttpUpload.setText(getHttpUploadMaxFileSize()); } } else if (features.p1S3FileTransfer()) { this.binding.serverInfoHttpUploadDescription.setText(R.string.p1_s3_filetransfer); diff --git a/src/main/java/de/pixart/messenger/ui/ShortcutActivity.java b/src/main/java/de/pixart/messenger/ui/ShortcutActivity.java index 52f87c5a3..ef5c296e0 100644 --- a/src/main/java/de/pixart/messenger/ui/ShortcutActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ShortcutActivity.java @@ -55,7 +55,7 @@ public class ShortcutActivity extends AbstractSearchableListItemActivity { for (final Account account : xmppConnectionService.getAccounts()) { if (account.getStatus() != Account.State.DISABLED) { for (final Contact contact : account.getRoster().getContacts()) { - if (contact.showInRoster() + if (contact.showInContactList() && contact.match(this, needle)) { getListItems().add(contact); } diff --git a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java index 1edbafd67..825494d90 100644 --- a/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java +++ b/src/main/java/de/pixart/messenger/ui/StartConversationActivity.java @@ -395,7 +395,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } protected void openConversationsForBookmark(Bookmark bookmark) { - Jid jid = bookmark.getJid(); + final Jid jid = bookmark.getFullJid(); if (jid == null) { Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show(); return; @@ -735,6 +735,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne @Override protected void onBackendConnected() { + xmppConnectionService.getQuickConversationsService().considerSyncBackground(false); if (mPostponedActivityResult != null) { onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); this.mPostponedActivityResult = null; @@ -868,12 +869,11 @@ public class StartConversationActivity extends XmppActivity implements XmppConne protected void filterContacts(String needle) { this.contacts.clear(); final List<Account> accounts = xmppConnectionService.getAccounts(); - final boolean singleAccountActive = isSingleAccountActive(accounts); for (Account account : accounts) { if (account.getStatus() != Account.State.DISABLED) { for (Contact contact : account.getRoster().getContacts()) { Presence.Status s = contact.getShownStatus(); - if ((contact.showInRoster() || (singleAccountActive && contact.showInPhoneBook())) && contact.match(this, needle) + if (contact.showInContactList() && contact.match(this, needle) && (!this.mHideOfflineContacts || (needle != null && !needle.trim().isEmpty()) || s.compareTo(Presence.Status.OFFLINE) < 0)) { @@ -886,16 +886,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne mContactsAdapter.notifyDataSetChanged(); } - private static boolean isSingleAccountActive(final List<Account> accounts) { - int i = 0; - for(Account account : accounts) { - if (account.getStatus() != Account.State.DISABLED) { - ++i; - } - } - return i == 1; - } - protected void filterConferences(String needle) { this.conferences.clear(); for (Account account : xmppConnectionService.getAccounts()) { @@ -1068,7 +1058,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne if (contact.isSelf()) { showContactDetailsItem.setVisible(false); } - deleteContactMenuItem.setVisible(contact.showInRoster()); + deleteContactMenuItem.setVisible(contact.showInRoster() && !contact.getOption(Contact.Options.SYNCED_VIA_OTHER)); XmppConnection xmpp = contact.getAccount().getXmppConnection(); if (xmpp != null && xmpp.getFeatures().blocking() && !contact.isSelf()) { if (contact.isBlocked()) { @@ -1115,10 +1105,10 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } public class ListPagerAdapter extends PagerAdapter { - FragmentManager fragmentManager; - MyListFragment[] fragments; + private final FragmentManager fragmentManager; + private final MyListFragment[] fragments; - public ListPagerAdapter(FragmentManager fm) { + ListPagerAdapter(FragmentManager fm) { fragmentManager = fm; fragments = new MyListFragment[2]; } @@ -1140,10 +1130,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne @NonNull @Override public Fragment instantiateItem(@NonNull ViewGroup container, int position) { - Fragment fragment = getItem(position); - FragmentTransaction trans = fragmentManager.beginTransaction(); + final Fragment fragment = getItem(position); + final FragmentTransaction trans = fragmentManager.beginTransaction(); trans.add(container.getId(), fragment, "fragment:" + position); - trans.commit(); + try { + trans.commit(); + } catch (IllegalStateException e) { + //ignore + } return fragment; } diff --git a/src/main/java/de/pixart/messenger/ui/TimePreference.java b/src/main/java/de/pixart/messenger/ui/TimePreference.java index 731a3bb50..97750d6e3 100644 --- a/src/main/java/de/pixart/messenger/ui/TimePreference.java +++ b/src/main/java/de/pixart/messenger/ui/TimePreference.java @@ -25,11 +25,12 @@ public class TimePreference extends DialogPreference implements Preference.OnPre persistLong(time); notifyDependencyChange(shouldDisableDependents()); notifyChanged(); + updateSummary(time); } - protected void updateSummary(final long time) { + private void updateSummary(final long time) { final DateFormat dateFormat = android.text.format.DateFormat.getTimeFormat(getContext()); - final Date date = new Date(time); + final Date date = minutesToCalender(time).getTime(); setSummary(dateFormat.format(date.getTime())); } @@ -40,21 +41,13 @@ public class TimePreference extends DialogPreference implements Preference.OnPre return picker; } - protected Calendar getPersistedTime() { - final Calendar c = Calendar.getInstance(); - c.setTimeInMillis(getPersistedLong(DEFAULT_VALUE)); - - return c; - } - @SuppressWarnings("NullableProblems") @Override protected void onBindDialogView(final View v) { super.onBindDialogView(v); - final Calendar c = getPersistedTime(); - - picker.setCurrentHour(c.get(Calendar.HOUR_OF_DAY)); - picker.setCurrentMinute(c.get(Calendar.MINUTE)); + long time = getPersistedLong(DEFAULT_VALUE); + picker.setCurrentHour((int) ((time % (24 * 60)) / 60)); + picker.setCurrentMinute((int) ((time % (24 * 60)) % 60)); } @Override @@ -62,17 +55,19 @@ public class TimePreference extends DialogPreference implements Preference.OnPre super.onDialogClosed(positiveResult); if (positiveResult) { - final Calendar c = Calendar.getInstance(); - c.set(Calendar.MINUTE, picker.getCurrentMinute()); - c.set(Calendar.HOUR_OF_DAY, picker.getCurrentHour()); - + setTime(picker.getCurrentHour() * 60 + picker.getCurrentMinute()); + } + } - if (!callChangeListener(c.getTimeInMillis())) { - return; - } + private static Calendar minutesToCalender(long time) { + final Calendar c = Calendar.getInstance(); + c.set(Calendar.HOUR_OF_DAY, (int) ((time % (24 * 60)) / 60)); + c.set(Calendar.MINUTE, (int) ((time % (24 * 60)) % 60)); + return c; + } - setTime(c.getTimeInMillis()); - } + public static long minutesToTimestamp(long time) { + return minutesToCalender(time).getTimeInMillis(); } @Override @@ -83,12 +78,8 @@ public class TimePreference extends DialogPreference implements Preference.OnPre @Override protected void onSetInitialValue(final boolean restorePersistedValue, final Object defaultValue) { long time; - if (defaultValue == null) { - time = restorePersistedValue ? getPersistedLong(DEFAULT_VALUE) : DEFAULT_VALUE; - } else if (defaultValue instanceof Long) { + if (defaultValue instanceof Long) { time = restorePersistedValue ? getPersistedLong((Long) defaultValue) : (Long) defaultValue; - } else if (defaultValue instanceof Calendar) { - time = restorePersistedValue ? getPersistedLong(((Calendar) defaultValue).getTimeInMillis()) : ((Calendar) defaultValue).getTimeInMillis(); } else { time = restorePersistedValue ? getPersistedLong(DEFAULT_VALUE) : DEFAULT_VALUE; } diff --git a/src/main/java/de/pixart/messenger/ui/XmppActivity.java b/src/main/java/de/pixart/messenger/ui/XmppActivity.java index ef8b753d0..ee606395a 100644 --- a/src/main/java/de/pixart/messenger/ui/XmppActivity.java +++ b/src/main/java/de/pixart/messenger/ui/XmppActivity.java @@ -744,6 +744,7 @@ public abstract class XmppActivity extends ActionBarActivity { SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); dialog.dismiss(); })); + dialog.setCanceledOnTouchOutside(false); dialog.setOnDismissListener(dialog1 -> { SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); }); @@ -1242,7 +1243,7 @@ public abstract class XmppActivity extends ActionBarActivity { builder.setTitle(R.string.install_from_unknown_sources_disabled); builder.setMessage(R.string.install_from_unknown_sources_disabled_dialog); builder.setPositiveButton(R.string.next, (dialog, which) -> { - Intent intent = null; + Intent intent; if (android.os.Build.VERSION.SDK_INT >= 26) { intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); Uri uri = Uri.parse("package:" + getPackageName()); @@ -1254,7 +1255,7 @@ public abstract class XmppActivity extends ActionBarActivity { try { startActivityForResult(intent, REQUEST_UNKNOWN_SOURCE_OP); } catch (ActivityNotFoundException e) { - Toast.makeText(XmppActivity.this, R.string.device_does_not_support_battery_op, Toast.LENGTH_SHORT).show(); + Toast.makeText(XmppActivity.this, R.string.device_does_not_support_unknown_source_op, Toast.LENGTH_SHORT).show(); } finally { UpdateService task = new UpdateService(this, xmppConnectionService.installedFrom(), xmppConnectionService); task.executeOnExecutor(UpdateService.THREAD_POOL_EXECUTOR, "true"); @@ -1262,6 +1263,10 @@ public abstract class XmppActivity extends ActionBarActivity { } }); builder.create().show(); + } else { + UpdateService task = new UpdateService(this, xmppConnectionService.installedFrom(), xmppConnectionService); + task.executeOnExecutor(UpdateService.THREAD_POOL_EXECUTOR, "true"); + Log.d(Config.LOGTAG, "AppUpdater started"); } } } diff --git a/src/main/java/de/pixart/messenger/ui/widget/TextInputEditText.java b/src/main/java/de/pixart/messenger/ui/widget/TextInputEditText.java new file mode 100644 index 000000000..51ad578df --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/widget/TextInputEditText.java @@ -0,0 +1,47 @@ +package de.pixart.messenger.ui.widget; + +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.TextView; + +import java.lang.reflect.Field; + +/** + * A wrapper class to fix some weird fuck ups on Meizu devices + * credit goes to the people in this thread https://github.com/android-in-china/Compatibility/issues/11 + */ +public class TextInputEditText extends android.support.design.widget.TextInputEditText { + + public TextInputEditText(Context context) { + super(context); + } + + public TextInputEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public TextInputEditText(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public CharSequence getHint() { + String manufacturer = Build.MANUFACTURER.toUpperCase(); + if (!manufacturer.contains("MEIZU") || Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + return super.getHint(); + } else { + try { + return getSuperHintHack(); + } catch (Exception e) { + return super.getHint(); + } + } + } + + private CharSequence getSuperHintHack() throws NoSuchFieldException, IllegalAccessException { + Field hintField = TextView.class.getDeclaredField("mHint"); + hintField.setAccessible(true); + return (CharSequence) hintField.get(this); + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/utils/Compatibility.java b/src/main/java/de/pixart/messenger/utils/Compatibility.java index f178f17c7..38f9db378 100644 --- a/src/main/java/de/pixart/messenger/utils/Compatibility.java +++ b/src/main/java/de/pixart/messenger/utils/Compatibility.java @@ -56,6 +56,8 @@ public class Compatibility { return applicationInfo == null || applicationInfo.targetSdkVersion >= 26; } catch (PackageManager.NameNotFoundException e) { return true; //when in doubt… + } catch (RuntimeException e) { + return true; //when in doubt… } } diff --git a/src/main/java/de/pixart/messenger/utils/Namespace.java b/src/main/java/de/pixart/messenger/utils/Namespace.java index 146a9784d..83d63cdaa 100644 --- a/src/main/java/de/pixart/messenger/utils/Namespace.java +++ b/src/main/java/de/pixart/messenger/utils/Namespace.java @@ -16,10 +16,12 @@ public final class Namespace { public static final String PUBSUB = "http://jabber.org/protocol/pubsub"; public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB + "#publish-options"; public static final String PUBSUB_ERROR = PUBSUB + "#errors"; + public static final String PUBSUB_OWNER = PUBSUB + "#owner"; public static final String NICK = "http://jabber.org/protocol/nick"; 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"; + public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0"; } diff --git a/src/main/java/de/pixart/messenger/utils/PhoneHelper.java b/src/main/java/de/pixart/messenger/utils/PhoneHelper.java index f5e2ffde1..327ae1904 100644 --- a/src/main/java/de/pixart/messenger/utils/PhoneHelper.java +++ b/src/main/java/de/pixart/messenger/utils/PhoneHelper.java @@ -24,55 +24,6 @@ public class PhoneHelper { return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); } - public static void loadPhoneContacts(Context context, final OnPhoneContactsLoadedListener listener) { - final List<Bundle> phoneContacts = new ArrayList<>(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { - listener.onPhoneContactsLoaded(phoneContacts); - return; - } - final String[] PROJECTION = new String[]{ContactsContract.Data._ID, - ContactsContract.Data.DISPLAY_NAME, - ContactsContract.Data.PHOTO_URI, - ContactsContract.Data.LOOKUP_KEY, - ContactsContract.CommonDataKinds.Im.DATA}; - - final String SELECTION = "(" + ContactsContract.Data.MIMETYPE + "=\"" - + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE - + "\") AND (" + ContactsContract.CommonDataKinds.Im.PROTOCOL - + "=\"" + ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER - + "\")"; - - CursorLoader mCursorLoader = new NotThrowCursorLoader(context, - ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null, - null); - mCursorLoader.registerListener(0, (arg0, c) -> { - if (c != null) { - while (c.moveToNext()) { - Bundle contact = new Bundle(); - contact.putInt("phoneid", c.getInt(c.getColumnIndex(ContactsContract.Data._ID))); - contact.putString("displayname", c.getString(c.getColumnIndex(ContactsContract.Data.DISPLAY_NAME))); - contact.putString("photouri", c.getString(c.getColumnIndex(ContactsContract.Data.PHOTO_URI))); - contact.putString("lookup", c.getString(c.getColumnIndex(ContactsContract.Data.LOOKUP_KEY))); - contact.putString("jid", c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA))); - phoneContacts.add(contact); - } - c.close(); - } - - if (listener != null) { - listener.onPhoneContactsLoaded(phoneContacts); - } - }); - try { - mCursorLoader.startLoading(); - } catch (RejectedExecutionException e) { - if (listener != null) { - listener.onPhoneContactsLoaded(phoneContacts); - } - } - } - public static Uri getProfilePictureUri(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { return null; @@ -106,24 +57,6 @@ public class PhoneHelper { } } - private static class NotThrowCursorLoader extends CursorLoader { - - private NotThrowCursorLoader(Context c, Uri u, String[] p, String s, String[] sa, String so) { - super(c, u, p, s, sa, so); - } - - @Override - public Cursor loadInBackground() { - - try { - return (super.loadInBackground()); - } catch (Throwable e) { - return (null); - } - } - - } - public static String getOSVersion(Context context) { return "Android/" + android.os.Build.MODEL + "/" + android.os.Build.VERSION.RELEASE; } diff --git a/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java b/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java index bf4d6e8c2..79e5126b2 100644 --- a/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java +++ b/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java @@ -3,17 +3,13 @@ package de.pixart.messenger.utils; public class ReplacingSerialSingleThreadExecutor extends SerialSingleThreadExecutor { public ReplacingSerialSingleThreadExecutor(String name) { - super(name, false); - } - - public ReplacingSerialSingleThreadExecutor(boolean prepareLooper) { - super(ReplacingSerialSingleThreadExecutor.class.getName(), prepareLooper); + super(name); } @Override public synchronized void execute(final Runnable r) { tasks.clear(); - if (active != null && active instanceof Cancellable) { + if (active instanceof Cancellable) { ((Cancellable) active).cancel(); } super.execute(r); @@ -21,8 +17,8 @@ public class ReplacingSerialSingleThreadExecutor extends SerialSingleThreadExecu public synchronized void cancelRunningTasks() { tasks.clear(); - if (active != null && active instanceof Cancellable) { + if (active instanceof Cancellable) { ((Cancellable) active).cancel(); } } -} +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/utils/ReplacingTaskManager.java b/src/main/java/de/pixart/messenger/utils/ReplacingTaskManager.java index 3c9f386cd..c25c6fce4 100644 --- a/src/main/java/de/pixart/messenger/utils/ReplacingTaskManager.java +++ b/src/main/java/de/pixart/messenger/utils/ReplacingTaskManager.java @@ -41,7 +41,7 @@ public class ReplacingTaskManager { synchronized (this.executors) { executor = this.executors.get(account); if (executor == null) { - executor = new ReplacingSerialSingleThreadExecutor(false); + executor = new ReplacingSerialSingleThreadExecutor(ReplacingTaskManager.class.getSimpleName()); this.executors.put(account, executor); } executor.execute(runnable); diff --git a/src/main/java/de/pixart/messenger/utils/Resolver.java b/src/main/java/de/pixart/messenger/utils/Resolver.java index f2716a648..2378c429e 100644 --- a/src/main/java/de/pixart/messenger/utils/Resolver.java +++ b/src/main/java/de/pixart/messenger/utils/Resolver.java @@ -37,6 +37,7 @@ import de.pixart.messenger.services.XmppConnectionService; public class Resolver { + public static final int DEFAULT_PORT_XMPP = 5222; private static final String DIRECT_TLS_SERVICE = "_xmpps-client"; private static final String STARTTLS_SERICE = "_xmpp-client"; @@ -150,7 +151,7 @@ public class Resolver { try { Result result = new Result(); result.ip = InetAddress.getByName(domain); - result.port = 5222; + result.port = DEFAULT_PORT_XMPP; return Collections.singletonList(result); } catch (UnknownHostException e) { return Collections.emptyList(); @@ -270,7 +271,7 @@ public class Resolver { public static final String AUTHENTICATED = "authenticated"; private InetAddress ip; private DNSName hostname; - private int port = 5222; + private int port = DEFAULT_PORT_XMPP; private boolean directTls = false; private boolean authenticated = false; private int priority; @@ -286,7 +287,7 @@ public class Resolver { static Result createDefault(DNSName hostname, InetAddress ip) { Result result = new Result(); - result.port = 5222; + result.port = DEFAULT_PORT_XMPP; result.hostname = hostname; result.ip = ip; return result; diff --git a/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java b/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java index 500b03c5b..9846146a8 100644 --- a/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java +++ b/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java @@ -16,14 +16,8 @@ public class SerialSingleThreadExecutor implements Executor { private final String name; protected Runnable active; - public SerialSingleThreadExecutor(String name) { - this(name, false); - } - SerialSingleThreadExecutor(String name, boolean prepareLooper) { - if (prepareLooper) { - execute(Looper::prepare); - } + public SerialSingleThreadExecutor(String name) { this.name = name; } diff --git a/src/main/res/layout/activity_change_password.xml b/src/main/res/layout/activity_change_password.xml index 6bd7f2d0d..4ff57e22b 100644 --- a/src/main/res/layout/activity_change_password.xml +++ b/src/main/res/layout/activity_change_password.xml @@ -39,7 +39,7 @@ app:passwordToggleEnabled="true" app:passwordToggleTint="?android:textColorSecondary"> - <android.support.design.widget.TextInputEditText + <de.pixart.messenger.ui.widget.TextInputEditText.widget.TextInputEditText android:id="@+id/current_password" style="@style/Widget.Conversations.EditText" android:layout_width="match_parent" @@ -59,7 +59,7 @@ app:passwordToggleEnabled="true" app:passwordToggleTint="?android:textColorSecondary"> - <android.support.design.widget.TextInputEditText + <de.pixart.messenger.ui.widget.TextInputEditText android:id="@+id/new_password" style="@style/Widget.Conversations.EditText" android:layout_width="match_parent" diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index 0742955d3..011f89e5b 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -78,7 +78,7 @@ android:layout_height="wrap_content" android:imeOptions="actionNext" android:inputType="textEmailAddress" - android:textColor="?attr/text_Color_Main" /> + android:textColor="?attr/edit_text_color" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout @@ -91,13 +91,14 @@ app:passwordToggleEnabled="true" app:passwordToggleTint="?android:textColorSecondary"> - <android.support.design.widget.TextInputEditText + <de.pixart.messenger.ui.widget.TextInputEditText android:id="@+id/account_password" style="@style/Widget.Conversations.EditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/password" - android:inputType="textPassword" /> + android:inputType="textPassword" + android:textColor="?attr/edit_text_color" /> </android.support.design.widget.TextInputLayout> <LinearLayout diff --git a/src/main/res/menu/block.xml b/src/main/res/menu/block.xml index 1256f7142..0a86ef124 100644 --- a/src/main/res/menu/block.xml +++ b/src/main/res/menu/block.xml @@ -1,6 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item + android:id="@+id/reject" + android:title="@string/reject_request" /> + <item android:id="@+id/block_domain" android:title="@string/block_entire_domain" /> <item diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index e871df164..d29077753 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -836,7 +836,6 @@ <string name="remote_server_timeout">Timeout des Remote-Servers</string> <string name="already_drafting_message">Du bist bereits dabei, eine Nachricht zu entwerfen.</string> <string name="bad_key_for_encryption">Ungültiger Schlüssel für die Verschlüsselung.</string> - <string name="server_info_available_with">ja, %s</string> <string name="delete_message_dialog">Nachricht löschen</string> <string name="delete_message_dialog_msg">Bist du sicher, dass du diese Nachricht löschen möchtest?\n\n<b>Achtung:</b> Dies wird keine Kopien dieser Nachricht löschen, die auf anderen Geräten oder Servern gespeichert sind.</string> <string name="feature_not_implemented">Funktion ist nicht implementiert</string> diff --git a/src/main/res/values-fil/strings.xml b/src/main/res/values-fil/strings.xml index 449701f22..691e6fcf2 100644 --- a/src/main/res/values-fil/strings.xml +++ b/src/main/res/values-fil/strings.xml @@ -168,7 +168,7 @@ <string name="passwords_do_not_match">Ang password ay hindi magkatugma</string> <string name="invalid_jid">Hindi ito balido na Jabber-ID</string> <string name="error_out_of_memory">Wala ng memorya. Ang imahe ay napakalaki</string> - <string name="add_phone_book_text">Gusto mo bang magdagdag sa iyong address book?</string> + <string name="add_phone_book_text">Gusto mo bang magdagdag %s sa iyong address book?</string> <string name="server_info_show_more">Impormasyon sa server</string> <string name="server_info_mam">XEP-0313: MAM</string> <string name="server_info_carbon_messages">XEP-0280: Mensagheng karbon</string> diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 196ae0d5d..f4703e8bb 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -326,5 +326,4 @@ <string name="delete_file_dialog">Удалить файл</string> <string name="cancelled">отменён</string> <string name="bad_key_for_encryption">Неправильный ключ для шифрования.</string> - <string name="server_info_available_with">да, %s</string> </resources> diff --git a/src/main/res/values/attrs.xml b/src/main/res/values/attrs.xml index c537fd248..8c824c7a6 100644 --- a/src/main/res/values/attrs.xml +++ b/src/main/res/values/attrs.xml @@ -20,6 +20,7 @@ <attr name="color_background_tertiary" format="reference|color" /> <attr name="color_background_secondary" format="reference|color" /> <attr name="color_background_primary" format="reference|color" /> + <attr name="edit_text_color" format="reference|color" /> <attr name="color_warning" format="reference|color" /> <attr name="EmojiColor" format="reference|color" /> diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index 7c0072f86..e8ef0805e 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -52,6 +52,7 @@ \n\nhttp://leafletjs.com/\n(BSD 2-Clause) \n\nhttps://www.openstreetmap.org/\n(Open Database License) \n\nhttp://xmpp.rocks/\n(The MIT License (MIT)) + \n\nhttps://github.com/drakeet/ToastCompat/\n(Apache License, Version 2.0) </string> <string name="default_resource" translatable="false">Phone</string> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 0fd36d8b1..8e8d26713 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -836,9 +836,11 @@ <string name="remote_server_timeout">Remote server timeout</string> <string name="already_drafting_message">You are already drafting a message.</string> <string name="bad_key_for_encryption">Bad key for encryption.</string> - <string name="server_info_available_with">yes, %s</string> <string name="delete_message_dialog">Delete message</string> <string name="delete_message_dialog_msg">Are you sure you want to delete this message?\n\n<b>Warning:</b> This will not delete copies of this message that are stored on other devices or servers.</string> <string name="feature_not_implemented">Feature not implemented</string> + <string name="device_does_not_support_unknown_source_op">Your device does not support allowing app installs from unknon sources.</string> + <string name="reject_request">Reject request</string> + <string name="error_message_copied_to_clipboard">Copied error message to clipboard</string> </resources> diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index 342ed8aa1..c10f8bffd 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -16,6 +16,7 @@ <item name="color_warning">@color/red700</item> <item name="TextColorOnline">@color/green500</item> <item name="TextColorError">@color/red800</item> + <item name="edit_text_color">@color/black87</item> <item name="activity_background_search">@drawable/search_background_light</item> <item name="activity_background_no_results">@drawable/no_results_background_light</item> @@ -170,6 +171,7 @@ <item name="color_warning">@color/red700</item> <item name="TextColorOnline">@color/green500</item> <item name="TextColorError">@color/red500</item> + <item name="edit_text_color">@color/white</item> <item name="activity_background_search">@drawable/search_background_dark</item> <item name="activity_background_no_results">@drawable/no_results_background_dark</item> diff --git a/src/standardPush/java/de/pixart/messenger/services/InstanceIdService.java b/src/standardPush/java/de/pixart/messenger/services/InstanceIdService.java index d812105aa..9a3309be4 100644 --- a/src/standardPush/java/de/pixart/messenger/services/InstanceIdService.java +++ b/src/standardPush/java/de/pixart/messenger/services/InstanceIdService.java @@ -13,12 +13,17 @@ public class InstanceIdService extends FirebaseInstanceIdService { @Override public void onTokenRefresh() { - Intent intent = new Intent(this, XmppConnectionService.class); + final Intent intent = new Intent(this, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_FCM_TOKEN_REFRESH); try { - startService(intent); - } catch (Exception e) { - Log.e(Config.LOGTAG, "unable to refresh FCM token", e); + if (Compatibility.runsAndTargetsTwentySix(this)) { + intent.putExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, true); + ContextCompat.startForegroundService(this, intent); + } else { + startService(intent); + } + } catch (IllegalStateException e) { + Log.e(Config.LOGTAG, "InstanceIdService is not allowed to start service"); } } -} +}
\ No newline at end of file diff --git a/src/standardPush/java/de/pixart/messenger/services/MaintenanceReceiver.java b/src/standardPush/java/de/pixart/messenger/services/MaintenanceReceiver.java index 9368913bc..5706a487a 100644 --- a/src/standardPush/java/de/pixart/messenger/services/MaintenanceReceiver.java +++ b/src/standardPush/java/de/pixart/messenger/services/MaintenanceReceiver.java @@ -3,6 +3,7 @@ package de.pixart.messenger.services; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.support.v4.content.ContextCompat; import android.util.Log; import com.google.firebase.iid.FirebaseInstanceId; @@ -10,6 +11,7 @@ import com.google.firebase.iid.FirebaseInstanceId; import java.io.IOException; import de.pixart.messenger.Config; +import de.pixart.messenger.utils.Compatibility; public class MaintenanceReceiver extends BroadcastReceiver { @Override @@ -25,9 +27,14 @@ public class MaintenanceReceiver extends BroadcastReceiver { new Thread(() -> { try { FirebaseInstanceId.getInstance().deleteInstanceId(); - Intent intent = new Intent(context, XmppConnectionService.class); + final Intent intent = new Intent(context, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_FCM_TOKEN_REFRESH); - context.startService(intent); + if (Compatibility.runsAndTargetsTwentySix(context)) { + intent.putExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, true); + ContextCompat.startForegroundService(context, intent); + } else { + context.startService(intent); + } } catch (IOException e) { Log.d(Config.LOGTAG, "unable to renew instance token", e); } diff --git a/src/standardPush/java/de/pixart/messenger/services/PushMessageReceiver.java b/src/standardPush/java/de/pixart/messenger/services/PushMessageReceiver.java index 816d11118..f07167f8d 100644 --- a/src/standardPush/java/de/pixart/messenger/services/PushMessageReceiver.java +++ b/src/standardPush/java/de/pixart/messenger/services/PushMessageReceiver.java @@ -1,6 +1,7 @@ package de.pixart.messenger.services; import android.content.Intent; +import android.support.v4.content.ContextCompat; import android.util.Log; import com.google.firebase.messaging.FirebaseMessagingService; @@ -9,6 +10,7 @@ import com.google.firebase.messaging.RemoteMessage; import java.util.Map; import de.pixart.messenger.Config; +import de.pixart.messenger.utils.Compatibility; public class PushMessageReceiver extends FirebaseMessagingService { @@ -18,10 +20,19 @@ public class PushMessageReceiver extends FirebaseMessagingService { Log.d(Config.LOGTAG, "PushMessageReceiver ignored message because no accounts are enabled"); return; } - Map<String, String> data = message.getData(); - Intent intent = new Intent(this, XmppConnectionService.class); + final Map<String, String> data = message.getData(); + final Intent intent = new Intent(this, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_FCM_MESSAGE_RECEIVED); intent.putExtra("account", data.get("account")); - startService(intent); + try { + if (Compatibility.runsAndTargetsTwentySix(this)) { + intent.putExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, true); + ContextCompat.startForegroundService(this, intent); + } else { + startService(intent); + } + } catch (IllegalStateException e) { + Log.e(Config.LOGTAG, "PushMessageReceiver is not allowed to start service"); + } } -} +}
\ No newline at end of file |