diff --git a/.travis.yml b/.travis.yml
index 247e8fd9b..239637ba4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,7 +11,7 @@ android:
- '.+'
before_script:
- mkdir libs
- - wget -O libs/libwebrtc-m84.aar http://gultsch.de/files/libwebrtc-m84.aar
+ - wget -O libs/libwebrtc-m85.aar https://gultsch.de/files/libwebrtc-m85.aar
script:
- ./gradlew assembleConversationsFreeSystemRelease
- ./gradlew assembleQuicksyFreeCompatRelease
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89f2e0d30..532d3c0b9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+### Version 2.9.0
+
+* Search individual conversations
+* Notify user if message delivery fails
+* Remember display names (nicks) from Quicksy users across restarts
+* Add button to start Orbot (Tor) from notification if necessary
+
### Version 2.8.10
* Handle GPX files
diff --git a/build.gradle b/build.gradle
index 5f99f8268..c63d1a14f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -80,7 +80,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation 'com.google.guava:guava:27.1-android'
quicksyImplementation 'io.michaelrocks:libphonenumber-android:8.11.1'
- //implementation fileTree(include: ['libwebrtc-m83.aar'], dir: 'libs')
+ //implementation fileTree(include: ['libwebrtc-m85.aar'], dir: 'libs')
implementation 'org.webrtc:google-webrtc:1.0.32006'
}
@@ -96,8 +96,8 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
- versionCode 398
- versionName "2.8.10.1"
+ versionCode 399
+ versionName "2.9.0"
archivesBaseName += "-$versionName"
applicationId "eu.sum7.conversations"
resValue "string", "applicationId", applicationId
diff --git a/src/conversations/res/values-pl/strings.xml b/src/conversations/res/values-pl/strings.xml
index 85a833b15..9108588df 100644
--- a/src/conversations/res/values-pl/strings.xml
+++ b/src/conversations/res/values-pl/strings.xml
@@ -8,4 +8,5 @@
Zostałeś zaproszony do %1$s. Poprowadzimy ciebie przez proces tworzenia konta.\nWybierając %1$s jako dostawcę będziesz mógł komunikować się z innymi użytkownikami podając swój pełny adres XMPP.
Zostałeś zaproszony do %1$s. Nazwa użytkownika została już dla ciebie wybrana. Poprowadzimy ciebie przez proces tworzenia konta.\nBęziesz mógł komunikować się z innymi użytkownikami podając swój adres XMPP.
Zaproszenie twojego serwera
-
+ Niepoprawnie sformatowany kod zaopatrywania
+
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index c78d32a98..ffd06ec0f 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
@@ -36,10 +37,6 @@
-
-
{
return UIHelper.getColorForName(room != null ? room.asBareJid().toEscapedString() : name);
}
+ @Override
+ public String getAvatarName() {
+ return name;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java
index 2227e4a80..0701afcfe 100644
--- a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java
@@ -13,81 +13,81 @@ import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
public class PresenceGenerator extends AbstractGenerator {
- public PresenceGenerator(XmppConnectionService service) {
- super(service);
- }
+ public PresenceGenerator(XmppConnectionService service) {
+ super(service);
+ }
- private PresencePacket subscription(String type, Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", type);
- packet.setTo(contact.getJid());
- packet.setFrom(contact.getAccount().getJid().asBareJid());
- return packet;
- }
+ private PresencePacket subscription(String type, Contact contact) {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("type", type);
+ packet.setTo(contact.getJid());
+ packet.setFrom(contact.getAccount().getJid().asBareJid());
+ return packet;
+ }
- public PresencePacket requestPresenceUpdatesFrom(Contact contact) {
- PresencePacket packet = subscription("subscribe", contact);
- String displayName = contact.getAccount().getDisplayName();
- if (!TextUtils.isEmpty(displayName)) {
- packet.addChild("nick",Namespace.NICK).setContent(displayName);
- }
- return packet;
- }
+ public PresencePacket requestPresenceUpdatesFrom(Contact contact) {
+ PresencePacket packet = subscription("subscribe", contact);
+ String displayName = contact.getAccount().getDisplayName();
+ if (!TextUtils.isEmpty(displayName)) {
+ packet.addChild("nick", Namespace.NICK).setContent(displayName);
+ }
+ return packet;
+ }
- public PresencePacket stopPresenceUpdatesFrom(Contact contact) {
- return subscription("unsubscribe", contact);
- }
+ public PresencePacket stopPresenceUpdatesFrom(Contact contact) {
+ return subscription("unsubscribe", contact);
+ }
- public PresencePacket stopPresenceUpdatesTo(Contact contact) {
- return subscription("unsubscribed", contact);
- }
+ public PresencePacket stopPresenceUpdatesTo(Contact contact) {
+ return subscription("unsubscribed", contact);
+ }
- public PresencePacket sendPresenceUpdatesTo(Contact contact) {
- return subscription("subscribed", contact);
- }
+ public PresencePacket sendPresenceUpdatesTo(Contact contact) {
+ return subscription("subscribed", contact);
+ }
- public PresencePacket selfPresence(Account account, Presence.Status status) {
- return selfPresence(account, status, true);
- }
+ public PresencePacket selfPresence(Account account, Presence.Status status) {
+ return selfPresence(account, status, true);
+ }
- public PresencePacket selfPresence(final Account account, final Presence.Status status, final boolean personal) {
- final PresencePacket packet = new PresencePacket();
- if (personal) {
- final String sig = account.getPgpSignature();
- final String message = account.getPresenceStatusMessage();
- if(status.toShowString() != null) {
- packet.addChild("show").setContent(status.toShowString());
- }
- if (!TextUtils.isEmpty(message)) {
- packet.addChild(new Element("status").setContent(message));
- }
- if (sig != null && mXmppConnectionService.getPgpEngine() != null) {
- packet.addChild("x", "jabber:x:signed").setContent(sig);
- }
- }
- final String capHash = getCapHash(account);
- if (capHash != null) {
- Element cap = packet.addChild("c",
- "http://jabber.org/protocol/caps");
- cap.setAttribute("hash", "sha-1");
- cap.setAttribute("node", "https://sum7.eu");
- cap.setAttribute("ver", capHash);
- }
- return packet;
- }
+ public PresencePacket selfPresence(final Account account, final Presence.Status status, final boolean personal) {
+ final PresencePacket packet = new PresencePacket();
+ if (personal) {
+ final String sig = account.getPgpSignature();
+ final String message = account.getPresenceStatusMessage();
+ if (status.toShowString() != null) {
+ packet.addChild("show").setContent(status.toShowString());
+ }
+ if (!TextUtils.isEmpty(message)) {
+ packet.addChild(new Element("status").setContent(message));
+ }
+ if (sig != null && mXmppConnectionService.getPgpEngine() != null) {
+ packet.addChild("x", "jabber:x:signed").setContent(sig);
+ }
+ }
+ final String capHash = getCapHash(account);
+ if (capHash != null) {
+ Element cap = packet.addChild("c",
+ "http://jabber.org/protocol/caps");
+ cap.setAttribute("hash", "sha-1");
+ cap.setAttribute("node", "http://conversations.im");
+ cap.setAttribute("ver", capHash);
+ }
+ return packet;
+ }
- public PresencePacket leave(final MucOptions mucOptions) {
- PresencePacket presencePacket = new PresencePacket();
- presencePacket.setTo(mucOptions.getSelf().getFullJid());
- presencePacket.setFrom(mucOptions.getAccount().getJid());
- presencePacket.setAttribute("type", "unavailable");
- return presencePacket;
- }
+ public PresencePacket leave(final MucOptions mucOptions) {
+ PresencePacket presencePacket = new PresencePacket();
+ presencePacket.setTo(mucOptions.getSelf().getFullJid());
+ presencePacket.setFrom(mucOptions.getAccount().getJid());
+ presencePacket.setAttribute("type", "unavailable");
+ return presencePacket;
+ }
- public PresencePacket sendOfflinePresence(Account account) {
- PresencePacket packet = new PresencePacket();
- packet.setFrom(account.getJid());
- packet.setAttribute("type","unavailable");
- return packet;
- }
+ public PresencePacket sendOfflinePresence(Account account) {
+ PresencePacket packet = new PresencePacket();
+ packet.setFrom(account.getJid());
+ packet.setAttribute("type", "unavailable");
+ return packet;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 7622d3071..07541e7cb 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -300,6 +300,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
} else {
Contact contact = account.getRoster().getContact(user);
if (contact.setPresenceName(nick)) {
+ mXmppConnectionService.syncRoster(account);
mXmppConnectionService.getAvatarService().clear(contact);
}
}
@@ -307,8 +308,14 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
mXmppConnectionService.updateAccountUi();
}
- private boolean handleErrorMessage(Account account, MessagePacket packet) {
+ private boolean handleErrorMessage(final Account account, final MessagePacket packet) {
if (packet.getType() == MessagePacket.TYPE_ERROR) {
+ if (packet.fromServer(account)) {
+ final Pair forwarded = packet.getForwardedMessagePacket("received", "urn:xmpp:carbons:2");
+ if (forwarded != null) {
+ return handleErrorMessage(account, forwarded.first);
+ }
+ }
final Jid from = packet.getFrom();
final String id = packet.getId();
if (from != null && id != null) {
@@ -362,7 +369,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final Element result = MessageArchiveService.Version.findResult(original);
final MessageArchiveService.Query query = result == null ? null : mXmppConnectionService.getMessageArchiveService().findQuery(result.getAttribute("queryid"));
if (query != null && query.validFrom(original.getFrom())) {
- Pair f = original.getForwardedMessagePacket("result", query.version.namespace);
+ final Pair f = original.getForwardedMessagePacket("result", query.version.namespace);
if (f == null) {
return;
}
@@ -370,6 +377,9 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
packet = f.first;
serverMsgId = result.getAttribute("id");
query.incrementMessageCount();
+ if (handleErrorMessage(account, packet)) {
+ return;
+ }
} else if (query != null) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received mam result from invalid sender");
return;
@@ -1011,8 +1021,9 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final String nick = packet.findChildContent("nick", Namespace.NICK);
if (nick != null && InvalidJid.hasValidFrom(original)) {
- Contact contact = account.getRoster().getContact(from);
+ final Contact contact = account.getRoster().getContact(from);
if (contact.setPresenceName(nick)) {
+ mXmppConnectionService.syncRoster(account);
mXmppConnectionService.getAvatarService().clear(contact);
}
}
diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
index 4e862ddf6..7f57ef733 100644
--- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
@@ -337,6 +337,7 @@ public class PresenceParser extends AbstractParser implements
mXmppConnectionService.onContactStatusChanged.onContactStatusChanged(contact, false);
} else if (type.equals("subscribe")) {
if (contact.setPresenceName(packet.findChildContent("nick", Namespace.NICK))) {
+ mXmppConnectionService.syncRoster(account);
mXmppConnectionService.getAvatarService().clear(contact);
}
if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index f2a59348e..dce2f8e20 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -63,11 +63,12 @@ import eu.siacs.conversations.xmpp.Jid;
public class DatabaseBackend extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "history";
- private static final int DATABASE_VERSION = 47;
+ private static final int DATABASE_VERSION = 48;
private static DatabaseBackend instance = null;
private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
+ Contact.SERVERNAME + " TEXT, " + Contact.SYSTEMNAME + " TEXT,"
+ + Contact.PRESENCE_NAME + " TEXT,"
+ Contact.JID + " TEXT," + Contact.KEYS + " TEXT,"
+ Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER,"
+ Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, "
@@ -559,6 +560,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL(CREATE_RESOLVER_RESULTS_TABLE);
}
+ if (oldVersion < 48 && newVersion >= 48) {
+ db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.PRESENCE_NAME + " TEXT");
+ }
}
private void canonicalizeJids(SQLiteDatabase db) {
@@ -577,7 +581,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
continue;
}
- String updateArgs[] = {
+ final String[] updateArgs = {
newJid,
cursor.getString(cursor.getColumnIndex(Conversation.UUID)),
};
@@ -780,11 +784,20 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return list;
}
- public Cursor getMessageSearchCursor(List term) {
- SQLiteDatabase db = this.getReadableDatabase();
- String SQL = "SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + '.' + Conversation.CONTACTJID + ',' + Conversation.TABLENAME + '.' + Conversation.ACCOUNT + ',' + Conversation.TABLENAME + '.' + Conversation.MODE + " FROM " + Message.TABLENAME + " join " + Conversation.TABLENAME + " on " + Message.TABLENAME + '.' + Message.CONVERSATION + '=' + Conversation.TABLENAME + '.' + Conversation.UUID + " join messages_index ON messages_index.uuid=messages.uuid where " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + ',' + Message.ENCRYPTION_PGP + ',' + Message.ENCRYPTION_DECRYPTION_FAILED + ',' + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + ',' + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ? ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS;
+ public Cursor getMessageSearchCursor(final List term, final String uuid) {
+ final SQLiteDatabase db = this.getReadableDatabase();
+ final StringBuilder SQL = new StringBuilder();
+ final String[] selectionArgs;
+ SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + '.' + Conversation.CONTACTJID + ',' + Conversation.TABLENAME + '.' + Conversation.ACCOUNT + ',' + Conversation.TABLENAME + '.' + Conversation.MODE + " FROM " + Message.TABLENAME + " join " + Conversation.TABLENAME + " on " + Message.TABLENAME + '.' + Message.CONVERSATION + '=' + Conversation.TABLENAME + '.' + Conversation.UUID + " join messages_index ON messages_index.uuid=messages.uuid where " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + ',' + Message.ENCRYPTION_PGP + ',' + Message.ENCRYPTION_DECRYPTION_FAILED + ',' + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + ',' + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?");
+ if (uuid == null) {
+ selectionArgs = new String[]{FtsUtils.toMatchString(term)};
+ } else {
+ selectionArgs = new String[]{FtsUtils.toMatchString(term), uuid};
+ SQL.append(" AND "+Conversation.TABLENAME+'.'+Conversation.UUID+"=?");
+ }
+ SQL.append(" ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS);
Log.d(Config.LOGTAG, "search term: " + FtsUtils.toMatchString(term));
- return db.rawQuery(SQL, new String[]{FtsUtils.toMatchString(term)});
+ return db.rawQuery(SQL.toString(), selectionArgs);
}
public List markFileAsDeleted(final File file, final boolean internal) {
@@ -1006,7 +1019,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 || contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) {
+ if (contact.getOption(Contact.Options.IN_ROSTER) || contact.hasAvatarOrPresenceName() || 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/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java
index 92835b8a9..1b29194e6 100644
--- a/src/main/java/eu/siacs/conversations/services/AvatarService.java
+++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java
@@ -685,5 +685,6 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
public interface Avatarable {
@ColorInt int getAvatarBackgroundColor();
+ String getAvatarName();
}
}
diff --git a/src/main/java/eu/siacs/conversations/services/EventReceiver.java b/src/main/java/eu/siacs/conversations/services/EventReceiver.java
index 985effc3a..500eb25e5 100644
--- a/src/main/java/eu/siacs/conversations/services/EventReceiver.java
+++ b/src/main/java/eu/siacs/conversations/services/EventReceiver.java
@@ -8,6 +8,8 @@ import android.preference.PreferenceManager;
import android.support.v4.content.ContextCompat;
import android.util.Log;
+import com.google.common.base.Strings;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.Compatibility;
@@ -19,17 +21,13 @@ public class EventReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent originalIntent) {
final Intent intentForService = new Intent(context, XmppConnectionService.class);
- if (originalIntent.getAction() != null) {
- intentForService.setAction(originalIntent.getAction());
- final Bundle extras = originalIntent.getExtras();
- if (extras != null) {
- intentForService.putExtras(extras);
- }
- } else {
- intentForService.setAction("other");
- }
final String action = originalIntent.getAction();
- if (action.equals("ui") || hasEnabledAccounts(context)) {
+ intentForService.setAction(Strings.isNullOrEmpty(action) ? "other" : action);
+ final Bundle extras = originalIntent.getExtras();
+ if (extras != null) {
+ intentForService.putExtras(extras);
+ }
+ if ("ui".equals(action) || hasEnabledAccounts(context)) {
Compatibility.startService(context, intentForService);
} else {
Log.d(Config.LOGTAG, "EventReceiver ignored action " + intentForService.getAction());
diff --git a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java
index 6fd2413f8..c18c94cf2 100644
--- a/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java
+++ b/src/main/java/eu/siacs/conversations/services/MessageSearchTask.java
@@ -56,18 +56,20 @@ public class MessageSearchTask implements Runnable, Cancellable {
private final XmppConnectionService xmppConnectionService;
private final List term;
+ private final String uuid;
private final OnSearchResultsAvailable onSearchResultsAvailable;
private boolean isCancelled = false;
- private MessageSearchTask(XmppConnectionService xmppConnectionService, List term, OnSearchResultsAvailable onSearchResultsAvailable) {
+ private MessageSearchTask(XmppConnectionService xmppConnectionService, List term, final String uuid, OnSearchResultsAvailable onSearchResultsAvailable) {
this.xmppConnectionService = xmppConnectionService;
this.term = term;
+ this.uuid = uuid;
this.onSearchResultsAvailable = onSearchResultsAvailable;
}
- public static void search(XmppConnectionService xmppConnectionService, List term, OnSearchResultsAvailable onSearchResultsAvailable) {
- new MessageSearchTask(xmppConnectionService, term, onSearchResultsAvailable).executeInBackground();
+ public static void search(XmppConnectionService xmppConnectionService, List term, final String uuid, OnSearchResultsAvailable onSearchResultsAvailable) {
+ new MessageSearchTask(xmppConnectionService, term, uuid, onSearchResultsAvailable).executeInBackground();
}
public static void cancelRunningTasks() {
@@ -86,7 +88,7 @@ public class MessageSearchTask implements Runnable, Cancellable {
try {
final HashMap conversationCache = new HashMap<>();
final List result = new ArrayList<>();
- cursor = xmppConnectionService.databaseBackend.getMessageSearchCursor(term);
+ cursor = xmppConnectionService.databaseBackend.getMessageSearchCursor(term, uuid);
long dbTimer = SystemClock.elapsedRealtime();
if (isCancelled) {
Log.d(Config.LOGTAG, "canceled search task");
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index c53dbd7d5..3c2a093bc 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -61,6 +61,7 @@ import eu.siacs.conversations.ui.TimePreference;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.GeoHelper;
+import eu.siacs.conversations.utils.TorServiceUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
@@ -82,6 +83,7 @@ public class NotificationService {
private static final int ERROR_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 6;
private static final int INCOMING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 8;
public static final int ONGOING_CALL_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 10;
+ private static final int DELIVERY_FAILED_NOTIFICATION_ID = NOTIFICATION_ID_MULTIPLIER * 12;
private final XmppConnectionService mXmppConnectionService;
private final LinkedHashMap> notifications = new LinkedHashMap<>();
private final HashMap mBacklogMessageCounter = new HashMap<>();
@@ -220,9 +222,20 @@ public class NotificationService {
quietHoursChannel.setSound(null, null);
notificationManager.createNotificationChannel(quietHoursChannel);
+
+ final NotificationChannel deliveryFailedChannel = new NotificationChannel("delivery_failed",
+ c.getString(R.string.delivery_failed_channel_name),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ deliveryFailedChannel.setShowBadge(false);
+ deliveryFailedChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
+ .build());
+ deliveryFailedChannel.setGroup("chats");
+ notificationManager.createNotificationChannel(deliveryFailedChannel);
}
- public boolean notify(final Message message) {
+ private boolean notify(final Message message) {
final Conversation conversation = (Conversation) message.getConversation();
return message.getStatus() == Message.STATUS_RECEIVED
&& !conversation.isMuted()
@@ -342,6 +355,37 @@ public class NotificationService {
}
}
+ public void pushFailedDelivery(final Message message) {
+ final Conversation conversation = (Conversation) message.getConversation();
+ final boolean isScreenOn = mXmppConnectionService.isInteractive();
+ if (this.mIsInForeground && isScreenOn && this.mOpenConversation == message.getConversation()) {
+ Log.d(Config.LOGTAG, message.getConversation().getAccount().getJid().asBareJid() + ": suppressing failed delivery notification because conversation is open");
+ return;
+ }
+ final PendingIntent pendingIntent = createContentIntent(conversation);
+ final int notificationId = generateRequestCode(conversation, 0) + DELIVERY_FAILED_NOTIFICATION_ID;
+ final int failedDeliveries = conversation.countFailedDeliveries();
+ final Notification notification =
+ new Builder(mXmppConnectionService, "delivery_failed")
+ .setContentTitle(conversation.getName())
+ .setAutoCancel(true)
+ .setSmallIcon(R.drawable.ic_error_white_24dp)
+ .setContentText(mXmppConnectionService.getResources().getQuantityText(R.plurals.some_messages_could_not_be_delivered, failedDeliveries))
+ .setGroup("delivery_failed")
+ .setContentIntent(pendingIntent).build();
+ final Notification summaryNotification =
+ new Builder(mXmppConnectionService, "delivery_failed")
+ .setContentTitle(mXmppConnectionService.getString(R.string.failed_deliveries))
+ .setContentText(mXmppConnectionService.getResources().getQuantityText(R.plurals.some_messages_could_not_be_delivered, 1024))
+ .setSmallIcon(R.drawable.ic_error_white_24dp)
+ .setGroup("delivery_failed")
+ .setGroupSummary(true)
+ .setAutoCancel(true)
+ .build();
+ notify(notificationId, notification);
+ notify(DELIVERY_FAILED_NOTIFICATION_ID, summaryNotification);
+ }
+
public void showIncomingCallNotification(final AbstractJingleConnection.Id id, final Set media) {
final Intent fullScreenIntent = new Intent(mXmppConnectionService, RtpSessionActivity.class);
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toEscapedString());
@@ -1092,9 +1136,11 @@ public class NotificationService {
}
final boolean showAllErrors = QuickConversationsService.isConversations();
final List errors = new ArrayList<>();
+ boolean torNotAvailable = false;
for (final Account account : mXmppConnectionService.getAccounts()) {
if (account.hasErrorStatus() && account.showErrorNotification() && (showAllErrors || account.getLastErrorStatus() == Account.State.UNAUTHORIZED)) {
errors.add(account);
+ torNotAvailable |= account.getStatus() == Account.State.TOR_NOT_AVAILABLE;
}
}
if (mXmppConnectionService.foregroundNotificationNeedsUpdatingWhenErrorStateChanges()) {
@@ -1113,7 +1159,23 @@ public class NotificationService {
}
mBuilder.addAction(R.drawable.ic_autorenew_white_24dp,
mXmppConnectionService.getString(R.string.try_again),
- createTryAgainIntent());
+ createTryAgainIntent()
+ );
+ if (torNotAvailable) {
+ if (TorServiceUtils.isOrbotInstalled(mXmppConnectionService)) {
+ mBuilder.addAction(
+ R.drawable.ic_play_circle_filled_white_48dp,
+ mXmppConnectionService.getString(R.string.start_orbot),
+ PendingIntent.getActivity(mXmppConnectionService, 147, TorServiceUtils.LAUNCH_INTENT, 0)
+ );
+ } else {
+ mBuilder.addAction(
+ R.drawable.ic_file_download_white_24dp,
+ mXmppConnectionService.getString(R.string.install_orbot),
+ PendingIntent.getActivity(mXmppConnectionService, 146, TorServiceUtils.INSTALL_INTENT, 0)
+ );
+ }
+ }
mBuilder.setDeleteIntent(createDismissErrorIntent());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mBuilder.setVisibility(Notification.VISIBILITY_PRIVATE);
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 8bc43c99f..3225be67d 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -36,6 +36,8 @@ import android.support.annotation.BoolRes;
import android.support.annotation.IntegerRes;
import android.support.v4.app.RemoteInput;
import android.support.v4.content.ContextCompat;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -127,6 +129,7 @@ import eu.siacs.conversations.utils.ReplacingTaskManager;
import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.utils.StringUtils;
+import eu.siacs.conversations.utils.TorServiceUtils;
import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
@@ -261,6 +264,16 @@ public class XmppConnectionService extends Service {
return false;
}
};
+ private final AtomicBoolean isPhoneInCall = new AtomicBoolean(false);
+ private final PhoneStateListener phoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onCallStateChanged(final int state, final String phoneNumber) {
+ isPhoneInCall.set(state != TelephonyManager.CALL_STATE_IDLE);
+ if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
+ mJingleConnectionManager.notifyPhoneCallStarted();
+ }
+ }
+ };
private boolean destroyed = false;
@@ -602,8 +615,8 @@ public class XmppConnectionService extends Service {
return c != null && c.getMode() == Conversational.MODE_MULTI;
}
- public void search(List term, OnSearchResultsAvailable onSearchResultsAvailable) {
- MessageSearchTask.search(this, term, onSearchResultsAvailable);
+ public void search(final List term, final String uuid, final OnSearchResultsAvailable onSearchResultsAvailable) {
+ MessageSearchTask.search(this, term, uuid, onSearchResultsAvailable);
}
@Override
@@ -652,8 +665,15 @@ public class XmppConnectionService extends Service {
final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID);
Log.d(Config.LOGTAG, "received intent to dismiss call with session id " + sessionId);
mJingleConnectionManager.rejectRtpSession(sessionId);
+ break;
}
- break;
+ case TorServiceUtils.ACTION_STATUS:
+ final String status = intent.getStringExtra(TorServiceUtils.EXTRA_STATUS);
+ if ("ON".equals(status)) {
+ handleOrbotStartedEvent();
+ return START_STICKY;
+ }
+ break;
case ACTION_END_CALL: {
final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID);
Log.d(Config.LOGTAG, "received intent to end call with session id " + sessionId);
@@ -787,6 +807,14 @@ public class XmppConnectionService extends Service {
return START_STICKY;
}
+ private void handleOrbotStartedEvent() {
+ for (final Account account : accounts) {
+ if (account.getStatus() == Account.State.TOR_NOT_AVAILABLE) {
+ reconnectAccount(account, true, false);
+ }
+ }
+ }
+
private boolean processAccountState(Account account, boolean interactive, boolean isUiAction, boolean isAccountPushed, HashSet pingCandidates) {
boolean pingNow = false;
if (account.getStatus().isAttemptReconnect()) {
@@ -1128,17 +1156,31 @@ public class XmppConnectionService extends Service {
toggleForegroundService();
updateUnreadCountBadge();
toggleScreenEventReceiver();
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TorServiceUtils.ACTION_STATUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
scheduleNextIdlePing();
- IntentFilter intentFilter = new IntentFilter();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
}
intentFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
- registerReceiver(this.mInternalEventReceiver, intentFilter);
}
+ registerReceiver(this.mInternalEventReceiver, intentFilter);
mForceDuringOnCreate.set(false);
toggleForegroundService();
+ setupPhoneStateListener();
+ }
+
+
+ private void setupPhoneStateListener() {
+ final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+ if (telephonyManager != null) {
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+ }
+ }
+
+ public boolean isPhoneInCall() {
+ return isPhoneInCall.get();
}
private void checkForDeletedFiles() {
@@ -1192,7 +1234,7 @@ public class XmppConnectionService extends Service {
public void onDestroy() {
try {
unregisterReceiver(this.mInternalEventReceiver);
- } catch (IllegalArgumentException e) {
+ } catch (final IllegalArgumentException e) {
//ignored
}
destroyed = false;
@@ -2193,7 +2235,7 @@ public class XmppConnectionService extends Service {
final Jid jid = Jid.ofEscaped(address);
final Account account = new Account(jid, password);
account.setOption(Account.OPTION_DISABLED, true);
- Log.d(Config.LOGTAG,jid.asBareJid().toEscapedString()+": provisioning account");
+ Log.d(Config.LOGTAG, jid.asBareJid().toEscapedString() + ": provisioning account");
createAccount(account);
}
@@ -3880,7 +3922,7 @@ public class XmppConnectionService extends Service {
}
- public void markMessage(Message message, int status, String errorMessage) {
+ public void markMessage(final Message message, final int status, final String errorMessage) {
final int oldStatus = message.getStatus();
if (status == Message.STATUS_SEND_FAILED && (oldStatus == Message.STATUS_SEND_RECEIVED || oldStatus == Message.STATUS_SEND_DISPLAYED)) {
return;
@@ -3892,6 +3934,9 @@ public class XmppConnectionService extends Service {
message.setStatus(status);
databaseBackend.updateMessage(message, false);
updateConversationUi();
+ if (oldStatus != status && status == Message.STATUS_SEND_FAILED) {
+ mNotificationService.pushFailedDelivery(message);
+ }
}
private SharedPreferences getPreferences() {
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 0136e99e0..845c601e1 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -1240,6 +1240,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
case R.id.attach_location:
handleAttachmentSelection(item);
break;
+ case R.id.action_search:
+ startSearch();
+ break;
case R.id.action_archive:
activity.xmppConnectionService.archiveConversation(conversation);
break;
@@ -1289,6 +1292,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
return super.onOptionsItemSelected(item);
}
+ private void startSearch() {
+ final Intent intent = new Intent(getActivity(), SearchActivity.class);
+ intent.putExtra(SearchActivity.EXTRA_CONVERSATION_UUID, conversation.getUuid());
+ startActivity(intent);
+ }
+
private void returnToOngoingCall() {
final Optional ongoingRtpSession = activity.xmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact());
if (ongoingRtpSession.isPresent()) {
@@ -2034,9 +2043,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
toggleInputMethod();
}
- public void reInit(Conversation conversation, Bundle extras) {
+ public void reInit(final Conversation conversation, final Bundle extras) {
QuickLoader.set(conversation.getUuid());
- this.saveMessageDraftStopAudioPlayer();
+ final boolean changedConversation = this.conversation != conversation;
+ if (changedConversation) {
+ this.saveMessageDraftStopAudioPlayer();
+ }
this.clearPending();
if (this.reInit(conversation, extras != null)) {
if (extras != null) {
@@ -2753,7 +2765,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
correctMessage(lastEditableMessage);
return true;
} else {
- Toast.makeText(getActivity(),R.string.could_not_correct_message, Toast.LENGTH_LONG).show();
+ Toast.makeText(getActivity(), R.string.could_not_correct_message, Toast.LENGTH_LONG).show();
return false;
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
index 261907d5b..049c0f27e 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
@@ -266,8 +266,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private boolean processViewIntent(Intent intent) {
- String uuid = intent.getStringExtra(EXTRA_CONVERSATION);
- Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null;
+ final String uuid = intent.getStringExtra(EXTRA_CONVERSATION);
+ final Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null;
if (conversation == null) {
Log.d(Config.LOGTAG, "unable to view conversation with uuid:" + uuid);
return false;
@@ -380,8 +380,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_conversations, menu);
- AccountUtils.showHideMenuItems(menu);
- MenuItem qrCodeScanMenuItem = menu.findItem(R.id.action_scan_qr_code);
+ final MenuItem qrCodeScanMenuItem = menu.findItem(R.id.action_scan_qr_code);
if (qrCodeScanMenuItem != null) {
if (isCameraFeatureAvailable()) {
Fragment fragment = getFragmentManager().findFragmentById(R.id.main_fragment);
@@ -489,6 +488,18 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
case R.id.action_scan_qr_code:
UriHandlerActivity.scan(this);
return true;
+ case R.id.action_search_all_conversations:
+ startActivity(new Intent(this, SearchActivity.class));
+ return true;
+ case R.id.action_search_this_conversation:
+ final Conversation conversation = ConversationFragment.getConversation(this);
+ if (conversation == null) {
+ return true;
+ }
+ final Intent intent = new Intent(this, SearchActivity.class);
+ intent.putExtra(SearchActivity.EXTRA_CONVERSATION_UUID, conversation.getUuid());
+ startActivity(intent);
+ return true;
}
return super.onOptionsItemSelected(item);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
index 829785073..ffbf6f7d9 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
@@ -64,6 +64,7 @@ import eu.siacs.conversations.ui.util.PendingActionHelper;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.ScrollState;
import eu.siacs.conversations.ui.util.StyledAttributes;
+import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.ThemeHelper;
import static android.support.v7.widget.helper.ItemTouchHelper.LEFT;
@@ -284,6 +285,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
menuInflater.inflate(R.menu.fragment_conversations_overview, menu);
+ AccountUtils.showHideMenuItems(menu);
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 92d6f2093..dcccec104 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -89,7 +89,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private static final int REQUEST_CHANGE_STATUS = 0xee11;
private static final int REQUEST_ORBOT = 0xff22;
private final PendingItem mPendingPresenceTemplate = new PendingItem<>();
- private final AtomicBoolean mPendingReconnect = new AtomicBoolean(false);
private AlertDialog mCaptchaDialog = null;
private Jid jidToEdit;
private boolean mInitMode = false;
@@ -475,13 +474,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
Log.d(Config.LOGTAG, "pgp result not ok");
}
}
- if (requestCode == REQUEST_ORBOT) {
- if (xmppConnectionService != null && mAccount != null) {
- xmppConnectionService.reconnectAccountInBackground(mAccount);
- } else {
- mPendingReconnect.set(true);
- }
- }
}
@Override
@@ -781,11 +773,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
if (mAccount != null) {
-
- if (mPendingReconnect.compareAndSet(true, false)) {
- xmppConnectionService.reconnectAccountInBackground(mAccount);
- }
-
this.mInitMode |= this.mAccount.isOptionSet(Account.OPTION_REGISTER);
this.mUsernameMode |= mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && mAccount.isOptionSet(Account.OPTION_REGISTER);
if (mPendingFingerprintVerificationUri != null) {
diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
index 0fd9ee187..0cf2d6f33 100644
--- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java
@@ -677,18 +677,22 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setVisibility(View.INVISIBLE);
} else if (state == RtpEndUserState.INCOMING_CALL) {
+ this.binding.rejectCall.setContentDescription(getString(R.string.dismiss_call));
this.binding.rejectCall.setOnClickListener(this::rejectCall);
this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
+ this.binding.acceptCall.setContentDescription(getString(R.string.answer_call));
this.binding.acceptCall.setOnClickListener(this::acceptCall);
this.binding.acceptCall.setImageResource(R.drawable.ic_call_white_48dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else if (state == RtpEndUserState.DECLINED_OR_BUSY) {
+ this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
+ this.binding.acceptCall.setContentDescription(getString(R.string.record_voice_mail));
this.binding.acceptCall.setOnClickListener(this::recordVoiceMail);
this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_white_24dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
@@ -698,15 +702,18 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
RtpEndUserState.APPLICATION_ERROR,
RtpEndUserState.RETRACTED
).contains(state)) {
+ this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
+ this.binding.acceptCall.setContentDescription(getString(R.string.try_again));
this.binding.acceptCall.setOnClickListener(this::retry);
this.binding.acceptCall.setImageResource(R.drawable.ic_replay_white_48dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else {
this.binding.rejectCall.setVisibility(View.INVISIBLE);
+ this.binding.endCall.setContentDescription(getString(R.string.hang_up));
this.binding.endCall.setOnClickListener(this::endCall);
this.binding.endCall.setImageResource(R.drawable.ic_call_end_white_48dp);
this.binding.endCall.setVisibility(View.VISIBLE);
diff --git a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java
index 3b337e0c2..d73249f4b 100644
--- a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java
@@ -29,6 +29,7 @@
package eu.siacs.conversations.ui;
+import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
@@ -42,6 +43,8 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
+import com.google.common.base.Strings;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -70,17 +73,21 @@ import static eu.siacs.conversations.ui.util.SoftKeyboardUtils.showKeyboard;
public class SearchActivity extends XmppActivity implements TextWatcher, OnSearchResultsAvailable, MessageAdapter.OnContactPictureClicked {
private static final String EXTRA_SEARCH_TERM = "search-term";
+ public static final String EXTRA_CONVERSATION_UUID = "uuid";
private ActivitySearchBinding binding;
private MessageAdapter messageListAdapter;
private final List messages = new ArrayList<>();
private WeakReference selectedMessageReference = new WeakReference<>(null);
+ private String uuid;
private final ChangeWatcher> currentSearch = new ChangeWatcher<>();
private final PendingItem pendingSearchTerm = new PendingItem<>();
private final PendingItem> pendingSearch = new PendingItem<>();
@Override
public void onCreate(final Bundle bundle) {
+ final Intent intent = getIntent();
+ this.uuid = intent == null ? null : Strings.emptyToNull(intent.getStringExtra(EXTRA_CONVERSATION_UUID));
final String searchTerm = bundle == null ? null : bundle.getString(EXTRA_SEARCH_TERM);
if (searchTerm != null) {
pendingSearchTerm.push(searchTerm);
@@ -103,10 +110,10 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
final String term = pendingSearchTerm.pop();
if (term != null) {
searchField.append(term);
- List searchTerm = FtsUtils.parse(term);
+ final List searchTerm = FtsUtils.parse(term);
if (xmppConnectionService != null) {
if (currentSearch.watch(searchTerm)) {
- xmppConnectionService.search(searchTerm, this);
+ xmppConnectionService.search(searchTerm, uuid, this);
}
} else {
pendingSearch.push(searchTerm);
@@ -114,6 +121,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
}
searchField.addTextChangedListener(this);
searchField.setHint(R.string.search_messages);
+ searchField.setContentDescription(getString(R.string.search_messages));
searchField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
if (term == null) {
showKeyboard(searchField);
@@ -206,7 +214,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
void onBackendConnected() {
final List searchTerm = pendingSearch.pop();
if (searchTerm != null && currentSearch.watch(searchTerm)) {
- xmppConnectionService.search(searchTerm, this);
+ xmppConnectionService.search(searchTerm, uuid,this);
}
}
@@ -239,7 +247,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
return;
}
if (term.size() > 0) {
- xmppConnectionService.search(term, this);
+ xmppConnectionService.search(term, uuid,this);
} else {
MessageSearchTask.cancelRunningTasks();
this.messages.clear();
diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
index 4d31d74d6..fa0d5ada9 100644
--- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -621,8 +621,10 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
if (binding.startConversationViewPager.getCurrentItem() == 0) {
mSearchEditText.setHint(R.string.search_contacts);
+ mSearchEditText.setContentDescription(getString(R.string.search_contacts));
} else {
mSearchEditText.setHint(R.string.search_bookmarks);
+ mSearchEditText.setContentDescription(getString(R.string.search_bookmarks));
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/service/AudioPlayer.java b/src/main/java/eu/siacs/conversations/ui/service/AudioPlayer.java
index 785f0ac01..5d3766452 100644
--- a/src/main/java/eu/siacs/conversations/ui/service/AudioPlayer.java
+++ b/src/main/java/eu/siacs/conversations/ui/service/AudioPlayer.java
@@ -112,17 +112,21 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f);
viewHolder.playPause.setOnClickListener(this);
+ final Context context = viewHolder.playPause.getContext();
if (message == currentlyPlayingMessage) {
if (AudioPlayer.player != null && AudioPlayer.player.isPlaying()) {
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
+ viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
viewHolder.progress.setEnabled(true);
} else {
+ viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
viewHolder.progress.setEnabled(false);
}
return true;
} else {
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
+ viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
viewHolder.progress.setProgress(0);
viewHolder.progress.setEnabled(false);
@@ -156,7 +160,8 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
}
- private boolean playPauseCurrent(ViewHolder viewHolder) {
+ private boolean playPauseCurrent(final ViewHolder viewHolder) {
+ final Context context = viewHolder.playPause.getContext();
viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f);
if (player.isPlaying()) {
viewHolder.progress.setEnabled(false);
@@ -164,6 +169,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
messageAdapter.flagScreenOff();
releaseProximityWakeLock();
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
+ viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
} else {
viewHolder.progress.setEnabled(true);
player.start();
@@ -171,6 +177,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
acquireProximityWakeLock();
this.stopRefresher(true);
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
+ viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
}
return false;
}
@@ -194,6 +201,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
acquireProximityWakeLock();
viewHolder.progress.setEnabled(true);
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
+ viewHolder.playPause.setContentDescription(viewHolder.playPause.getContext().getString(R.string.pause_audio));
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
return true;
} catch (Exception e) {
@@ -248,6 +256,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
final ViewHolder viewHolder = ViewHolder.get(audioPlayer);
final Message message = (Message) audioPlayer.getTag();
+ viewHolder.playPause.setContentDescription(viewHolder.playPause.getContext().getString(R.string.play_audio));
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
if (message != null) {
viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
diff --git a/src/main/java/eu/siacs/conversations/ui/util/AvatarWorkerTask.java b/src/main/java/eu/siacs/conversations/ui/util/AvatarWorkerTask.java
index 4e23f14f1..ad7da7189 100644
--- a/src/main/java/eu/siacs/conversations/ui/util/AvatarWorkerTask.java
+++ b/src/main/java/eu/siacs/conversations/ui/util/AvatarWorkerTask.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.ui.util;
+import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
@@ -11,11 +12,10 @@ import android.widget.ImageView;
import java.lang.ref.WeakReference;
import java.util.concurrent.RejectedExecutionException;
+import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.ui.adapter.AccountAdapter;
-import eu.siacs.conversations.utils.UIHelper;
public class AvatarWorkerTask extends AsyncTask {
private final WeakReference imageViewReference;
@@ -80,6 +80,7 @@ public class AvatarWorkerTask extends AsyncTask avatarWorkerTaskReference;
diff --git a/src/main/java/eu/siacs/conversations/ui/util/ConversationMenuConfigurator.java b/src/main/java/eu/siacs/conversations/ui/util/ConversationMenuConfigurator.java
index 98986e03a..24bbdd7c7 100644
--- a/src/main/java/eu/siacs/conversations/ui/util/ConversationMenuConfigurator.java
+++ b/src/main/java/eu/siacs/conversations/ui/util/ConversationMenuConfigurator.java
@@ -112,16 +112,16 @@ public class ConversationMenuConfigurator {
none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
axolotl.setVisible(Config.supportOmemo());
switch (conversation.getNextEncryption()) {
- case Message.ENCRYPTION_NONE:
- none.setChecked(true);
- break;
case Message.ENCRYPTION_PGP:
+ menuSecure.setTitle(R.string.encrypted_with_openpgp);
pgp.setChecked(true);
break;
case Message.ENCRYPTION_AXOLOTL:
+ menuSecure.setTitle(R.string.encrypted_with_omemo);
axolotl.setChecked(true);
break;
default:
+ menuSecure.setTitle(R.string.not_encrypted);
none.setChecked(true);
break;
}
diff --git a/src/main/java/eu/siacs/conversations/utils/StylingHelper.java b/src/main/java/eu/siacs/conversations/utils/StylingHelper.java
index c26a86ea4..4d4339a42 100644
--- a/src/main/java/eu/siacs/conversations/utils/StylingHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/StylingHelper.java
@@ -129,7 +129,7 @@ public class StylingHelper {
int start = indexOfIgnoreCase(string, needle, 0);
while (start != -1) {
int end = start + length;
- editable.setSpan(new BackgroundColorSpan(ContextCompat.getColor(context, dark ? R.color.blue_a100 : R.color.blue_a200)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
+ editable.setSpan(new BackgroundColorSpan(ContextCompat.getColor(context, dark ? R.color.blue_a100 : R.color.blue_a400)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
editable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, dark ? R.color.black87 : R.color.white)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
start = indexOfIgnoreCase(string, needle, start + length);
}
diff --git a/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java b/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java
index 3e333483b..9fc9f5082 100644
--- a/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java
+++ b/src/main/java/eu/siacs/conversations/utils/TorServiceUtils.java
@@ -16,6 +16,12 @@ public class TorServiceUtils {
private static final Uri ORBOT_PLAYSTORE_URI = Uri.parse("market://details?id=" + URI_ORBOT);
private final static String ACTION_START_TOR = "org.torproject.android.START_TOR";
+ public static final Intent INSTALL_INTENT = new Intent(Intent.ACTION_VIEW, ORBOT_PLAYSTORE_URI);
+ public static final Intent LAUNCH_INTENT = new Intent(ACTION_START_TOR);
+
+ public final static String ACTION_STATUS = "org.torproject.android.intent.action.STATUS";
+ public final static String EXTRA_STATUS = "org.torproject.android.intent.extra.STATUS";
+
public static boolean isOrbotInstalled(Context context) {
try {
context.getPackageManager().getPackageInfo(URI_ORBOT, PackageManager.GET_ACTIVITIES);
@@ -27,17 +33,14 @@ public class TorServiceUtils {
public static void downloadOrbot(Activity activity, int requestCode) {
- final Intent intent = new Intent(Intent.ACTION_VIEW, ORBOT_PLAYSTORE_URI);
try {
- activity.startActivityForResult(intent, requestCode);
+ activity.startActivityForResult(INSTALL_INTENT, requestCode);
} catch (ActivityNotFoundException e) {
ToastCompat.makeText(activity, R.string.no_market_app_installed, ToastCompat.LENGTH_SHORT).show();
}
}
public static void startOrbot(Activity activity, int requestCode) {
- final Intent launchIntent = new Intent(URI_ORBOT);
- launchIntent.setAction(ACTION_START_TOR);
- activity.startActivityForResult(launchIntent, requestCode);
+ activity.startActivityForResult(LAUNCH_INTENT, requestCode);
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
index 67ff221b7..178ac659c 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
@@ -14,6 +14,7 @@ import com.google.common.collect.ImmutableSet;
import java.lang.ref.WeakReference;
import java.security.SecureRandom;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -90,7 +91,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
final AbstractJingleConnection connection;
if (FileTransferDescription.NAMESPACES.contains(descriptionNamespace)) {
connection = new JingleFileTransferConnection(this, id, from);
- } else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace) && !usesTor(account)) {
+ } else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace) && isUsingClearNet(account)) {
final boolean sessionEnded = this.terminatedSessions.asMap().containsKey(PersistableSessionId.of(id));
final boolean stranger = isWithStrangerAndStrangerNotificationsAreOff(account, id.with);
if (isBusy() || sessionEnded || stranger) {
@@ -116,11 +117,14 @@ public class JingleConnectionManager extends AbstractConnectionManager {
}
}
- private boolean usesTor(final Account account) {
- return account.isOnion() || mXmppConnectionService.useTorToConnect();
+ private boolean isUsingClearNet(final Account account) {
+ return !account.isOnion() && !mXmppConnectionService.useTorToConnect();
}
public boolean isBusy() {
+ if (mXmppConnectionService.isPhoneInCall()) {
+ return true;
+ }
for (AbstractJingleConnection connection : this.connections.values()) {
if (connection instanceof JingleRtpConnection) {
if (((JingleRtpConnection) connection).isTerminated()) {
@@ -134,6 +138,18 @@ public class JingleConnectionManager extends AbstractConnectionManager {
}
}
+ public void notifyPhoneCallStarted() {
+ for (AbstractJingleConnection connection : connections.values()) {
+ if (connection instanceof JingleRtpConnection) {
+ final JingleRtpConnection rtpConnection = (JingleRtpConnection) connection;
+ if (rtpConnection.isTerminated()) {
+ continue;
+ }
+ rtpConnection.notifyPhoneCall();
+ }
+ }
+ }
+
private Optional findMatchingSessionProposal(final Account account, final Jid with, final Set media) {
synchronized (this.rtpSessionProposals) {
for (Map.Entry entry : this.rtpSessionProposals.entrySet()) {
@@ -257,7 +273,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
Collections2.filter(descriptions, d -> d instanceof RtpDescription),
input -> (RtpDescription) input
);
- if (rtpDescriptions.size() > 0 && rtpDescriptions.size() == descriptions.size() && !usesTor(account)) {
+ if (rtpDescriptions.size() > 0 && rtpDescriptions.size() == descriptions.size() && isUsingClearNet(account)) {
final Collection media = Collections2.transform(rtpDescriptions, RtpDescription::getMedia);
if (media.contains(Media.UNKNOWN)) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": encountered unknown media in session proposal. " + propose);
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
index bc3487ad6..d2c340639 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java
@@ -371,8 +371,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
if (transition(State.SESSION_ACCEPTED)) {
respondOk(jinglePacket);
receiveSessionAccept(contentMap);
- final List identificationTags = contentMap.group == null ? contentMap.getNames() : contentMap.group.getIdentificationTags();
- processCandidates(identificationTags, contentMap.contents.entrySet());
} else {
Log.d(Config.LOGTAG, String.format("%s: received session-accept while in state %s", id.account.getJid().asBareJid(), state));
respondOk(jinglePacket);
@@ -390,7 +388,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
sendSessionTerminate(Reason.FAILED_APPLICATION, e.getMessage());
return;
}
- org.webrtc.SessionDescription answer = new org.webrtc.SessionDescription(
+ final org.webrtc.SessionDescription answer = new org.webrtc.SessionDescription(
org.webrtc.SessionDescription.Type.ANSWER,
sessionDescription.toString()
);
@@ -400,7 +398,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to set remote description after receiving session-accept", Throwables.getRootCause(e));
webRTCWrapper.close();
sendSessionTerminate(Reason.FAILED_APPLICATION);
+ return;
}
+ final List identificationTags = contentMap.group == null ? contentMap.getNames() : contentMap.group.getIdentificationTags();
+ processCandidates(identificationTags, contentMap.contents.entrySet());
}
private void sendSessionAccept() {
@@ -900,6 +901,16 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
}
}
+
+ public void notifyPhoneCall() {
+ Log.d(Config.LOGTAG, "a phone call has just been started. killing jingle rtp connections");
+ if (Arrays.asList(State.PROPOSED, State.SESSION_INITIALIZED).contains(this.state)) {
+ rejectCall();
+ } else {
+ endCall();
+ }
+ }
+
public synchronized void rejectCall() {
if (isTerminated()) {
Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": received rejectCall() when session has already been terminated. nothing to do");
diff --git a/src/main/res/drawable-hdpi/ic_error_white_24dp.png b/src/main/res/drawable-hdpi/ic_error_white_24dp.png
new file mode 100644
index 000000000..69cbb1e0b
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_error_white_24dp.png differ
diff --git a/src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png
new file mode 100644
index 000000000..30330cfad
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png differ
diff --git a/src/main/res/drawable-mdpi/ic_error_white_24dp.png b/src/main/res/drawable-mdpi/ic_error_white_24dp.png
new file mode 100644
index 000000000..ca148fc7c
Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_error_white_24dp.png differ
diff --git a/src/main/res/drawable-mdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-mdpi/ic_play_circle_filled_white_48dp.png
new file mode 100644
index 000000000..5dcdf0d7a
Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_play_circle_filled_white_48dp.png differ
diff --git a/src/main/res/drawable-xhdpi/ic_error_white_24dp.png b/src/main/res/drawable-xhdpi/ic_error_white_24dp.png
new file mode 100644
index 000000000..9829698dd
Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_error_white_24dp.png differ
diff --git a/src/main/res/drawable-xhdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-xhdpi/ic_play_circle_filled_white_48dp.png
new file mode 100644
index 000000000..9dc082586
Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_play_circle_filled_white_48dp.png differ
diff --git a/src/main/res/drawable-xxhdpi/ic_error_white_24dp.png b/src/main/res/drawable-xxhdpi/ic_error_white_24dp.png
new file mode 100644
index 000000000..abe2573b1
Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_error_white_24dp.png differ
diff --git a/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png
new file mode 100644
index 000000000..1d73fb5f4
Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_error_white_24dp.png b/src/main/res/drawable-xxxhdpi/ic_error_white_24dp.png
new file mode 100644
index 000000000..830fb7e1e
Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_error_white_24dp.png differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_48dp.png b/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_48dp.png
new file mode 100644
index 000000000..166f5c5ce
Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_48dp.png differ
diff --git a/src/main/res/layout/activity_start_conversation.xml b/src/main/res/layout/activity_start_conversation.xml
index b83f595b9..1fd915bd6 100644
--- a/src/main/res/layout/activity_start_conversation.xml
+++ b/src/main/res/layout/activity_start_conversation.xml
@@ -50,6 +50,7 @@
app:sdMainFabClosedBackgroundColor="?colorPrimary"
app:sdMainFabOpenedBackgroundColor="?colorPrimaryDark"
app:sdUseReverseAnimationOnClose="true"
+ android:contentDescription="@string/add_contact_or_create_or_join_group_chat"
app:sdOverlayLayout="@id/overlay"/>
diff --git a/src/main/res/layout/message_received.xml b/src/main/res/layout/message_received.xml
index f63f612b1..75b1eb340 100644
--- a/src/main/res/layout/message_received.xml
+++ b/src/main/res/layout/message_received.xml
@@ -37,7 +37,9 @@
android:orientation="vertical"
android:padding="2dp">
-
+
diff --git a/src/main/res/layout/message_sent.xml b/src/main/res/layout/message_sent.xml
index 82d122ec8..f84d07e34 100644
--- a/src/main/res/layout/message_sent.xml
+++ b/src/main/res/layout/message_sent.xml
@@ -51,7 +51,9 @@
android:orientation="vertical"
android:padding="2dp">
-
+
diff --git a/src/main/res/menu/activity_conversations.xml b/src/main/res/menu/activity_conversations.xml
index 3275fdc6d..bcf227ee5 100644
--- a/src/main/res/menu/activity_conversations.xml
+++ b/src/main/res/menu/activity_conversations.xml
@@ -1,26 +1,25 @@
\ No newline at end of file
diff --git a/src/main/res/menu/fragment_conversation.xml b/src/main/res/menu/fragment_conversation.xml
index 5eb0b313b..1e12f91c1 100644
--- a/src/main/res/menu/fragment_conversation.xml
+++ b/src/main/res/menu/fragment_conversation.xml
@@ -28,7 +28,7 @@
android:id="@+id/action_security"
android:icon="?attr/icon_not_secure"
android:orderInCategory="20"
- android:title="@string/action_secure"
+ android:title="@string/encrypted_with_omemo"
app:showAsAction="always">
@@ -99,6 +99,12 @@
android:orderInCategory="45"
android:title="@string/invite_contact"
app:showAsAction="never" />
+
+ android:title="@string/more_options">
+
+
+
+
+
+
+
-
-
\ No newline at end of file
diff --git a/src/main/res/menu/fragment_conversations_overview.xml b/src/main/res/menu/fragment_conversations_overview.xml
index 39daf7d8c..52937ebd1 100644
--- a/src/main/res/menu/fragment_conversations_overview.xml
+++ b/src/main/res/menu/fragment_conversations_overview.xml
@@ -28,10 +28,26 @@
-->
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ android:visible="@bool/show_individual_search_options"
+ app:showAsAction="never" />
+
+
+
\ No newline at end of file
diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml
index 0da16ab13..c8079d2ad 100644
--- a/src/main/res/values-ar/strings.xml
+++ b/src/main/res/values-ar/strings.xml
@@ -4,11 +4,9 @@
محادثة جديدة
إدارة الحسابات
إدارة الحساب
- أغلق هذه المحادثة
بيانات جهة الإتصال
تفاصيل مجموعة المحادثة
تفاصيل القناة
- تشفير المحادثة
إضافة حساب
تعديل الإسم
أضف إلى دفتر العناوين
diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml
index 00e7b3c3b..915ff2951 100644
--- a/src/main/res/values-bg/strings.xml
+++ b/src/main/res/values-bg/strings.xml
@@ -4,11 +4,9 @@
Нов разговор
Управление на профилите
Управление на профила
- Затваряне на този разговор
Подробности за контакта
Подробности за груповия разговор
Подробности за канала
- Защитен разговор
Добавяне на профил
Редактиране на името
Добавяне към адресния указател
diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml
index f5a3db49d..2749e83d9 100644
--- a/src/main/res/values-ca/strings.xml
+++ b/src/main/res/values-ca/strings.xml
@@ -4,10 +4,8 @@
Nova conversa
Gestiona els comptes
Administrar compte
- Tancar aquesta conversa
Detalls del contacte
Detalls del xat de grup
- Conversa segura
Afegeix un compte
Edita el nom
Afegeix a la llibreta d\'adreces
diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml
index 103c03430..4b0ce3f36 100644
--- a/src/main/res/values-cs/strings.xml
+++ b/src/main/res/values-cs/strings.xml
@@ -4,9 +4,7 @@
Nová konverzace
Nastavení účtů
Nastavení účtu
- Zavřít tuto konverzaci
Detaily kontaktu
- Zabezpečená konverzace
Přidat účet
Upravit jméno
Přidat do adresáře
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index e79d6e9ed..ce06c6380 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -4,11 +4,10 @@
Neue Unterhaltung
Konten verwalten
Konto verwalten
- Diese Unterhaltung beenden
+ Unterhaltung beenden
Kontaktdetails
Gruppenchatdetails
Channeldetails
- Verschlüsselte Unterhaltung
Konto hinzufügen
Namen bearbeiten
Zum Telefonbuch hinzufügen
@@ -754,6 +753,7 @@
Laufende Anrufe
Lautlose Nachrichten
Diese Benachrichtigungsart wird verwendet, um Benachrichtigungen anzuzeigen, die keinen Ton auslösen sollen. Zum Beispiel, wenn du auf einem anderen Gerät aktiv bist (Schonfrist).
+ Fehlgeschlagene Zustellungen
Benachrichtigungseinstellungen
Anrufeinstellungen
Wichtigkeit, Klang, Vibrationen
@@ -921,12 +921,30 @@
Du kannst immer nur einen Anruf zur gleichen Zeit machen.
Zurück zum laufenden Aufruf
Kamera konnte nicht gewechselt werden
- Zu Favoriten hinzufügen
- Von Favoriten entfernen
+ Oben anheften
+ Von oben ablösen
GPX-Strecke
Nachricht konnte nicht korrigiert werden
+ Alle Unterhaltungen
+ Diese Unterhaltung
+ Dein Avatar
+ Avatar für %s
+ Verschlüsselt mit OMEMO
+ Verschlüsselt mit OpenPGP
+ Nicht verschlüsselt
+ Beenden
+ Sprachnachricht aufzeichnen
+ Audio abspielen
+ Audio anhalten
+ Kontakt hinzufügen, Gruppenchat erstellen oder beitreten oder Channels entdecken
- %1$d Teilnehmer anzeigen
- %1$d Teilnehmer anzeigen
+
+ - Eine Nachricht konnte nicht zugestellt werden
+ - Einige Nachrichten konnten nicht zugestellt werden
+
+ Fehlgeschlagene Zustellungen
+ Weitere Optionen
diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml
index 6948212ed..640d82e2d 100644
--- a/src/main/res/values-el/strings.xml
+++ b/src/main/res/values-el/strings.xml
@@ -4,11 +4,9 @@
Νέα συζήτηση
Διαχείριση λογαριασμών
Διαχείριση λογαριασμού
- Κλείσιμο συζήτησης
Λεπτομέρειες επαφής
Λεπτομέρειες ομαδικής συζήτησης
Λεπτομέρειες καναλιού
- Ασφαλής συζήτηση
Προσθήκη λογαριασμού
Επεξεργασία ονόματος
Προσθήκη στην ατζέντα
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index 1daf200c5..31301b574 100644
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -4,11 +4,10 @@
Nueva conversación
Gestionar cuentas
Gestionar cuenta
- Cerrar esta conversación
+ Cerrar conversación
Detalles del contacto
Detalles de conversación
Detalles del canal
- Conversación segura
Añadir cuenta
Editar contacto
Añadir a contactos
@@ -921,10 +920,20 @@
Solo puedes hacer una llamada a la vez
Volver a la llamada en curso
No se ha podido cambiar de cámara
- Añadir a los favoritos
- Eliminar de favoritos
Recorrido GPX
No se pudo corregir el mensaje
+ Todas las conversaciones
+ Esta conversación
+ Tu imagen de perfil
+ Imagen de perfil de %s
+ Encriptado con OMEMO
+ Encriptado con OpenPGP
+ Sin encriptar
+ Salir
+ Grabar mensaje de voz
+ Reproducir audio
+ Pausar audio
+ Añadir contacto, crear o unirse a un grupo de chat, o descubrir canales
- Ver %1$d Participante
- Ver %1$d Participantes
diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml
index bf595e4a5..e3dc29fb4 100644
--- a/src/main/res/values-eu/strings.xml
+++ b/src/main/res/values-eu/strings.xml
@@ -4,11 +4,9 @@
Elkarrizketa berria
Kontuak kudeatu
Kontua kudeatu
- Elkarrizketa hau itxi
Kontaktuaren xehetasunak
Taldearen xehetasunak
Kanalaren xehetasunak
- Elkarrizketa segurua
Kontua gehitu
Izena editatu
Helbideen liburura gehitu
diff --git a/src/main/res/values-fa-rIR/strings.xml b/src/main/res/values-fa-rIR/strings.xml
index 682185323..728ec8e9c 100644
--- a/src/main/res/values-fa-rIR/strings.xml
+++ b/src/main/res/values-fa-rIR/strings.xml
@@ -5,7 +5,6 @@
مدیریت حساب های کاربری
جزییات مخاطب
جزئیات چت گروهی
- مکالمه امن
اضافه کردن حساب کاربری
تغییر نام
اضافه کردن به لیست ادرس ها
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index a6ebebacf..523ec019f 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -4,11 +4,9 @@
Nouvelle conversation
Gérer les comptes
Gérer le compte
- Fermer cette conversation
Détails du contact
Détails du groupe
Détails du canal
- Conversation sécurisée
Ajouter un compte
Modifier le nom
Ajouter au carnet d\'adresses
@@ -913,8 +911,6 @@
Vous ne pouvez prendre qu\'un appel à la fois.
Reprendre l\'appel en cours
Impossible de changer de caméra
- Ajouter aux favoris
- Enlever des favoris
- Voir %1$d participant
- Voir %1$d participants
diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml
index a3c7a63e7..7f38f1f4a 100644
--- a/src/main/res/values-gl/strings.xml
+++ b/src/main/res/values-gl/strings.xml
@@ -4,11 +4,10 @@
Nova conversa
Xestionar contas
Xestionar conta
- Pechar esta conversa
+ Pechar conversa
Detalles do contacto
Detalles da conversa de grupo
Detalles do canal
- Conversa segura
Engadir conta
Editar contacto
Engadir a libreta de enderezos
@@ -754,6 +753,7 @@
Chamadas realizadas
Mensaxes acalados
Este grupo de notificacións é utilizado para mostrar notificacións que non debería activar ningún son. Por exemplo, cando está activo en outro dispositivo (Período de Graza).
+ Entregas fallidas
Axustes de notificación das mensaxes
Axustes da notificación de chamadas
Importancia, Son, Vibrar
@@ -921,12 +921,30 @@
Só podes manter unha chamada en cada momento.
Voltar á chamada activa
Non se puido activar a cámara
- Engadir a favoritas
- Eliminar das favoritas
+ Fixar enriba
+ Desafixar de enriba
Ruta GPX
No se pode correxir a mensaxe
+ Todas as conversas
+ Esta conversa
+ O teu avatar
+ Avatar para %s
+ Cifrado con OMEMO
+ Cifrado con OpenPGP
+ Sen cifrar
+ Saír
+ Gravar correo de voz
+ Reproducir audio
+ Pausar audio
+ Engade un contacto, crea o únete a unha conversa en grupo ou descubre canles.
- Ver %1$d Participante
- Ver %1$d Participantes
+
+ - Unha mensaxe non se entregou
+ - Algunhas mensaxes non se entregaron
+
+ Entregas fallidas
+ Máis opcións
diff --git a/src/main/res/values-hu/strings.xml b/src/main/res/values-hu/strings.xml
index 0aff10aa7..2201a659f 100644
--- a/src/main/res/values-hu/strings.xml
+++ b/src/main/res/values-hu/strings.xml
@@ -4,11 +4,9 @@
Új beszélgetés
Fiókok kezelése
Fiók kezelése
- Beszélgetés bezárása
Partner részletei
Csoportos csevegés részletei
Csatorna részletei
- Biztonságos beszélgetés
Fiók hozzáadása
Név szerkesztése
Hozzáadás a címjegyzékhez
@@ -883,8 +881,6 @@
Egyszerre csak egy hívásban vehet részt.
Visszatérés a kimenő híváshoz
Nem sikerült átváltani a kamerát
- Hozzáadás a kedvencekhez
- Eltávolítás a kedvencekből
- %1$d résztvevő megtekintése
- %1$d résztvevő megtekintése
diff --git a/src/main/res/values-id/strings.xml b/src/main/res/values-id/strings.xml
index 78fa9411f..08fb2bc34 100644
--- a/src/main/res/values-id/strings.xml
+++ b/src/main/res/values-id/strings.xml
@@ -4,7 +4,6 @@
Percakapan Baru
Pengaturan Akun
Detil Kontak
- Amankan Percakapan
Tambah Akun
Ubah Nama
Tambahkan ke daftar kontak
diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml
index c42c050d0..b7b8e356a 100644
--- a/src/main/res/values-it/strings.xml
+++ b/src/main/res/values-it/strings.xml
@@ -4,11 +4,9 @@
Nuova conversazione
Gestisci account
Gestisci account
- Chiudi questa conversazione
Dettagli del contatto
Dettagli chat di gruppo
Dettagli canale
- Conversazione sicura
Aggiungi account
Modifica il nome
Aggiungi alla rubrica
@@ -461,7 +459,11 @@
Rotto
Disponibilità
\"Non disponibile\" a schermo spento
+ Imposta come non disponibile quando lo schermo è spento
+ \"Occupato\" in modalità silenziosa
+ Imposta come occupato quando il dispositivo è in modalità silenziosa
Tratta vibrazione come modalità silenziosa
+ Imposta come occupato quando il dispositivo è in modalità vibrazione
Impostazioni estese di connessione
Mostra nome host e impostazioni della porta quando configuri un account
xmpp.esempio.it
@@ -917,8 +919,8 @@
Puoi fare solo una chiamata alla volta.
Torna alla chiamata in corso
Impossibile cambiare fotocamera
- Aggiungi ai preferiti
- Rimuovi dai preferiti
+ Traccia GPX
+ Impossibile correggere il messaggio
- Vedi %1$d partecipante
- Vedi %1$d partecipanti
diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml
index e12b2b5b3..228704ef3 100644
--- a/src/main/res/values-iw/strings.xml
+++ b/src/main/res/values-iw/strings.xml
@@ -4,7 +4,6 @@
שיחה חדשה
נהל חשבונות
פרטי איש קשר
- דיון מאובטח
הוסף חשבון
ערוך שם
מחק מרשימת אנשי הקשר
diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml
index 870ac2ac2..92bf10639 100644
--- a/src/main/res/values-ja/strings.xml
+++ b/src/main/res/values-ja/strings.xml
@@ -4,11 +4,9 @@
新しい会話
アカウントの管理
アカウントの管理
- この会話を閉じる
連絡先の詳細
談話室の詳細
チャンネルの詳細
- 安全に会話
アカウントを追加
名前の編集
アドレス帳に追加
diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml
index b8ae856be..d00ee1940 100644
--- a/src/main/res/values-ko/strings.xml
+++ b/src/main/res/values-ko/strings.xml
@@ -4,7 +4,6 @@
새 대화
계정
연락처 정보
- 안전한 대화
계정 추가
이름 편집
주소록에 추가
diff --git a/src/main/res/values-nb-rNO/strings.xml b/src/main/res/values-nb-rNO/strings.xml
index c237a8c79..2c94fcbba 100644
--- a/src/main/res/values-nb-rNO/strings.xml
+++ b/src/main/res/values-nb-rNO/strings.xml
@@ -5,7 +5,6 @@
Kontobehandling
Kontaktdetaljer
Gruppesludringsdetaljer
- Sikret samtale
Legg til samtale
Rediger navn
Legg til i kontaktliste
diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml
index 23bea3fa6..2f2b64cab 100644
--- a/src/main/res/values-nl/strings.xml
+++ b/src/main/res/values-nl/strings.xml
@@ -4,11 +4,9 @@
Nieuw gesprek
Accounts beheren
Account beheren
- Dit gesprek sluiten
Contactgegevens
Gespreksgegevens
Kanaalinformatie
- Beveiligd gesprek
Account toevoegen
Naam veranderen
Toevoegen aan adresboek
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index c27c4b484..07e572ae9 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -4,11 +4,10 @@
Nowa konwersacja
Zarządzaj kontami
Zarządzaj kontem
- Zamknij konwersację
+ Zamknij rozmowę
Szczegóły kontaktu
Szczegóły konferencji
Szczegóły kanału
- Konwersacja szyfrowana
Dodaj konto
Edytuj nazwę
Dodaj do kontaktów
@@ -401,6 +400,7 @@
Oznacz jako przeczytane
Ustawienia wprowadzania
Enter wysyła
+ Użyj klawisza Enter aby wysłać wiadomość. Możesz zawsze użyć Ctrl+Enter do wysyłania wiadomości, nawet jeśli ta opcja jest wyłączona.
Pokaż klawisz Enter
Zamień klawisz emotikon na klawisz Enter
plik audio
@@ -424,8 +424,8 @@
Nie odnaleziono aplikacji do wyświetlenia lokalizacji
Lokalizacja
Zamknięto konwersację
- Opuść prywatną rozmowę grupową
- Opuść publiczny kanał
+ Opuszczono prywatną rozmowę grupową
+ Opuszczono publiczny kanał
Nie ufaj certyfikatom systemowym
Wymagaj ręcznego potwierdzania certyfikatów
Usuń certyfikaty
@@ -462,7 +462,11 @@
Zepsute
Dostępność
Status \"Oddalony\" gdy wyświetlacz jest wyłączony
+ Pokaż jako Oddalony kiedy ekran jest wyłączony.
+ Zajęty w trybie cichym
+ Pokaż jako Zajęty jeśli urządzenie jest w trybie cichym
Traktuj tryb wibracji jak tryb cichy
+ Pokaż jako Zajęty kiedy urządzenie jest w trybie wibracji
Rozszerzone ustawienia połączenia
Pokaż nazwę hosta i ustawienia portu przy dodawaniu konta
xmpp.example.com
@@ -767,6 +771,7 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż
Połączenia wychodzące
Ciche wiadomości
Ta kategoria powiadomień jest używana aby wyświetlać powiadomienia które nie powodują żadnych dźwięków. Na przykład w ciągu aktywności na innym urządzeniu (okres karencji).
+ Nie dostarczone wiadomości
Ustawienia powiadomień wiadomości
Ustawienia powiadomień dla przychodzących połączeń
Ważność, Dźwięk, Wibracja
@@ -929,16 +934,39 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż
Połączenie audio
Połączenie wideo
Pomoc
+ Przełącz do rozmowy
Twój mikrofon jest niedostępny
Możesz mieć tylko jedno połączenie na raz.
Powróć do trwającego połączenia
Nie można zmienić aparatu
- Dodaj do ulubionych
- Usuń z ulubionych
+ Przypnij
+ Odepnij
+ Ścieżka GPX
+ Nie można poprawić wiadomości
+ Wszystkie rozmowy
+ Ta rozmowa
+ Twój awatar
+ Awatar dla %s
+ Zaszyfrowane OMEMO
+ Zaszyfrowane OpenPGP
+ Niezaszyfrowane
+ Wyjście
+ Zapisz pocztę głosową
+ Odtwórz audio
+ Spauzuj audio
+ Dodaj kontakt, stwórz lub dołącz do rozmowy grupowej lub odkryj kanały
- Pokaż %1$d uczestnika
- Pokaż %1$d uczestników
- Pokaż %1$d uczestników
- Pokaż %1$d uczestników
+
+ - Wiadomość nie mogła zostać dostarczona
+ - Niektóre wiadomości nie mogły być dostarczone
+ - Niektóre wiadomości nie mogły być dostarczone
+ - Niektóre wiadomości nie mogły być dostarczone
+
+ Nie dostarczone wiadomości
+ Więcej ustawień
diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml
index aaadafa17..a8d56e895 100644
--- a/src/main/res/values-pt-rBR/strings.xml
+++ b/src/main/res/values-pt-rBR/strings.xml
@@ -4,11 +4,9 @@
Nova conversa
Gerenciar contas
Gerenciar conta
- Encerrar essa conversa
Detalhes do contato
Detalhes da conversa em grupo
Detalhes do canal
- Conversa segura
Adicionar conta
Editar o nome
Adicionar ao livro de endereços
@@ -921,8 +919,6 @@
Você só pode ter uma chamada de cada vez
Retornar para a chamada em andamento
Não foi possível trocar a câmera
- Adicionar aos favoritos
- Remover dos favoritos
Trilha GPX
Não foi possível corrigir a mensagem
diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml
index 48ac1af22..aa40d9cc8 100644
--- a/src/main/res/values-pt/strings.xml
+++ b/src/main/res/values-pt/strings.xml
@@ -4,7 +4,6 @@
Nova conversa
Gerir contas
Detalhes do contacto
- Conversa segura
Adicionar conta
Editar nome
Adicionar ao livro de endereços
diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml
index ac36077c6..e17bc8fff 100644
--- a/src/main/res/values-ro-rRO/strings.xml
+++ b/src/main/res/values-ro-rRO/strings.xml
@@ -8,7 +8,6 @@
Detalii contact
Detalii discuție de grup
Detalii canal
- Securizează conferința
Adaugă cont
Editează nume
Adaugă la lista de contacte
@@ -762,6 +761,7 @@
Apeluri în curs
Mesaje silențioase
Acest grup de notificări este folosit pentru a arăta notificări care nu emit sunete. De exemplu atunci când sunteți activi pe un alt dispozitiv (Perioada de grație).
+ Trimiteri eșuate
Setări de notificare ale mesajelor
Setări de notificare ale apelurilor primite
Importanță, sunete, vibrații
@@ -929,13 +929,32 @@
Puteți avea un singur apel simultan.
Reveniți la apelul în curs
Nu s-a putut face comutarea camerei foto
- Adaugă la favorite
- Înlătură din favorite
+ Fixează sus
+ Anulează fixarea
Traseu GPX
Nu s-a putut corecta mesajul
+ Toate conversațiile
+ Această conversație
+ Avatarul dumneavoastră
+ Avatar pentru %s
+ Criptare OMEMO
+ Criptare OpenPGP
+ Fără criptare
+ Ieșire
+ Înregistrare mesaj vocal
+ Redare audio
+ Pauză audio
+ Adaugă contact, creează sau alătură-te discuției de grup, sau descoperă canale
- Arată %1$d participant
- Arată %1$d participanți
- Arată %1$d de participanți
+
+ - Un mesaj nu a putut fi livrat
+ - Niște mesaje nu au putut fi livrate
+ - Niște mesaje nu au putut fi livrate
+
+ Trimiteri eșuate
+ Mai multe
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index b4328ad26..0942bbae8 100644
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -4,11 +4,9 @@
Новая беседа
Управление аккаунтами
Управление аккаунтом
- Закрыть текущую беседу
Сведения о контакте
Подробности конференции
Сведения о канале
- Защищённая беседа
Добавить аккаунт
Редактировать контакт
Добавить в адресную книгу
@@ -933,8 +931,6 @@
Нельзя одновременно совершать больше одного звонка.
Вернуться к текущему звонку
Не удалось переключить камеру
- Добавить в избранные
- Убрать из избранных
- Просмотр %1$d участника
- Просмотр %1$d участников
diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml
index cd8643ff1..6cee3cc8e 100644
--- a/src/main/res/values-sk/strings.xml
+++ b/src/main/res/values-sk/strings.xml
@@ -4,7 +4,6 @@
Nová konverzácia
Nastavenie účtov
Detaily kontaktu
- Zabezpečená konverzácia
Pridať účet
Upraviť meno
Vymazať zo zoznamu
diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml
index b89041668..0c5ef2675 100644
--- a/src/main/res/values-sr/strings.xml
+++ b/src/main/res/values-sr/strings.xml
@@ -5,7 +5,6 @@
Управљај налозима
Детаљи контакта
Детаљи групног ћаскања
- Безбедна преписка
Додај налог
Уреди име
Додај у именик
diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml
index 95c39ba06..0f371f3ef 100644
--- a/src/main/res/values-sv/strings.xml
+++ b/src/main/res/values-sv/strings.xml
@@ -4,11 +4,9 @@
Ny konversation
Kontoinställningar
Hantera konto
- Stäng denna konversation
Kontaktdetaljer
Gruppchattdetaljer
Kanaldetaljer
- Säker konversation
Lägg till konto
Ändra namn
Lägg till i kontakter
diff --git a/src/main/res/values-tr-rTR/strings.xml b/src/main/res/values-tr-rTR/strings.xml
index 00fe5d929..d23a9f999 100644
--- a/src/main/res/values-tr-rTR/strings.xml
+++ b/src/main/res/values-tr-rTR/strings.xml
@@ -4,11 +4,9 @@
Yeni konuşma
Hesapları yönet
Hesabı yönet
- Bu konuşmayı kapat
Kişi bilgileri
Küme konuşması ayrıntıları
Kanal ayrıntıları
- Güvenli konuşma
Hesap ekle
İsmi düzenle
Telefon rehberine ekle
diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml
index 9d02b5ff9..34361619d 100644
--- a/src/main/res/values-uk/strings.xml
+++ b/src/main/res/values-uk/strings.xml
@@ -4,11 +4,9 @@
Нова розмова
Мої облікові записи
Мій обліковий запис
- Завершити розмову
Деталі контакту
Деталі групи
Деталі каналу
- Захищена розмова
Додати обліковий запис
Редагувати ім\'я
Додати до контактів
@@ -933,8 +931,6 @@
Водночас можливо здійснювати лише один виклик.
Назад до активного виклику
Неможливо перемкнути камеру
- Додати до обраного
- Вилучити з обраного
- Перегляд %1$d учасника
- Перегляд %1$d учасників
diff --git a/src/main/res/values-vi/strings.xml b/src/main/res/values-vi/strings.xml
index adcd79e96..57d506c2d 100644
--- a/src/main/res/values-vi/strings.xml
+++ b/src/main/res/values-vi/strings.xml
@@ -4,7 +4,6 @@
Hội thoại mới
Quản lý tài khoản
Thông tin liên hệ
- Bảo mật hội thoại
Thêm tài khoản
Chỉnh sửa tên
Thêm vào danh bạ
diff --git a/src/main/res/values-w945dp/defaults.xml b/src/main/res/values-w945dp/defaults.xml
index 855f5b520..f17a59a91 100644
--- a/src/main/res/values-w945dp/defaults.xml
+++ b/src/main/res/values-w945dp/defaults.xml
@@ -1,5 +1,7 @@
false
+ false
+ true
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index cdd7e736a..0e44707be 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -4,11 +4,9 @@
新对话
管理账户
管理账户
- 关闭对话
联系人详情
群聊详情
频道详情
- 加密对话
添加账户
编辑名称
添加到通讯录
@@ -460,7 +458,11 @@
损坏
可用性
锁屏时显示离开
+ 屏幕关闭时显示为“离开”
+ 在静音模式显示为忙碌
+ 设备处于静音模式时显示为忙碌
将振动看作静音
+ 设备振动时显示为忙碌
高级连接设置
注册账户时显示主机名和端口
xmpp.example.com
@@ -909,8 +911,8 @@
只能同时打一通电话
返回正在进行的通话
无法切换摄像头
- 添加到收藏夹
- 从收藏夹删除
+ GPX轨迹
+ 无法更正消息
- 查看%1$d成员
diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml
index 94e26a277..d1dfd6e6b 100644
--- a/src/main/res/values-zh-rTW/strings.xml
+++ b/src/main/res/values-zh-rTW/strings.xml
@@ -4,7 +4,6 @@
新對話
管理帳戶
聯絡人詳情
- 安全對話
新增帳戶
編輯姓名
添加到地址薄
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
index 3b52f4c24..37a8fe124 100644
--- a/src/main/res/values/colors.xml
+++ b/src/main/res/values/colors.xml
@@ -26,6 +26,8 @@
#ff4CAF50
#ff82B1FF
#ff448AFF
+ #ff2979FF
+ #ff2962FF
#ffff9800
#fffb8c00
#ffF57C00
diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml
index 9f07f3f34..8fef0fa5c 100644
--- a/src/main/res/values/defaults.xml
+++ b/src/main/res/values/defaults.xml
@@ -34,6 +34,8 @@
false
false
true
+ true
+ false
true
default_on
small
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index eb624be38..a16bf406c 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -4,11 +4,10 @@
New conversation
Manage accounts
Manage account
- Close this conversation
+ Close conversation
Contact details
Group chat details
Channel details
- Secure conversation
Add account
Edit name
Add to address book
@@ -756,6 +755,7 @@
Ongoing calls
Silent messages
This notification group is used to display notifications that should not trigger any sound. For example when being active on another device (Grace Period).
+ Failed deliveries
Message notification settings
Incoming calls notification settings
Importance, Sound, Vibrate
@@ -923,12 +923,30 @@
You can only have one call at a time.
Return to ongoing call
Could not switch camera
- Add to favorites
- Remove from favorites
+ Pin to top
+ Unpin from top
GPX track
Could not correct message
+ All conversations
+ This conversation
+ Your avatar
+ Avatar for %s
+ Encrypted with OMEMO
+ Encrypted with OpenPGP
+ Not encrypted
+ Exit
+ Record voice mail
+ Play audio
+ Pause audio
+ Add contact, create or join group chat, or discover channels
- View %1$d Participant
- View %1$d Participants
+
+ - A message could not be delivered
+ - Some messages could not be delivered
+
+ Failed deliveries
+ More options
diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml
index 201cecab5..881a21037 100644
--- a/src/main/res/values/themes.xml
+++ b/src/main/res/values/themes.xml
@@ -4,7 +4,7 @@