Detailed changes
@@ -1,5 +1,17 @@
# Changelog
+### Version 2.17.10
+
+* Allow audio recording to be pause by tapping the timer
+* Fix reactions in MUC PMs
+* Stop accepting 'fallback messages' for reactions, receipts and display markers
+* Add some more media preview icons
+
+### Version 2.17.9
+
+* Make use of SASL SCRAM Downgrade Protection (XEP-0474)
+* Send reactions to MUC PMs to correct JID
+
### Version 2.17.8
* Fix some minor UI bugs
@@ -0,0 +1,2 @@
+* Verwendung von SASL SCRAM Downgrade Protection (XEP-0474)
+* Reaktionen an MUC PMs senden, damit die XMPP-Adresse korrekt ist
@@ -0,0 +1,4 @@
+* Audioaufnahme kann durch Antippen des Timers angehalten werden
+* Reaktionen in MUC PMs korrigiert
+* Annahme von 'Fallback-Nachrichten' für Reaktionen, Bestätigungen und Anzeigemarkierungen beendet
+* Weitere Medienvorschau-Symbole hinzugefügt
@@ -0,0 +1,2 @@
+* Make use of SASL SCRAM Downgrade Protection (XEP-0474)
+* Send reactions to MUC PMs to correct JID
@@ -0,0 +1,4 @@
+* Allow audio recording to be pause by tapping the timer
+* Fix reactions in MUC PMs
+* Stop accepting 'fallback messages' for reactions, receipts and display markers
+* Add some more media preview icons
@@ -0,0 +1,2 @@
+* Hicimos uso de la protección contra degradación de SCRAM SASL (XEP-0474)
+* Envíe reacciones a los mensajes privados de MUC para corregir el JID
@@ -0,0 +1 @@
+* Parandasime regressiooni, mis tekkis failide teisaldamisel P2P-ühenduse kaudu
@@ -0,0 +1,3 @@
+* Parandasime sõnumite kordussaatmise SASL2 kasutamisel
+* Parandasime musta videovaate tekkimise mõnede seadmete puhul
+* Parandasime rakenduse kokkujooksmise tühja salasõna puhul
@@ -0,0 +1 @@
+* Lõimisime UnifiedPushi tõuketeenuste levitajana teistele UnifiedPushi kasutajatele nagu Tusky ja Fedilab
@@ -0,0 +1 @@
+* Parandasime kokkujooksmise, mis ilmnes UnifiedPushi kasutamisel tõuketeenuste levitajana
@@ -0,0 +1 @@
+* Suurendasime profiilipiltide nurkade raadiust
@@ -0,0 +1,2 @@
+* Kompileerime jälle arvestades Androidi SDK versiooni 33
+* Parandasime vead serveritega, mis ilmnesid SASL2 kasutamisel ilma lõimitud meediavoo halduseta (inline Stream Management)
@@ -0,0 +1 @@
+* Parandasime olukorra, kus „q“ tuvastus kirillitsana
@@ -0,0 +1,2 @@
+* Võtsime kasutusele SASL SCRAM madaldusründe kaitse (SASL SCRAM Downgrade Protection XEP-0474)
+* saadame jututoa sõnumite reakstioonid õigetele kasutajatele
@@ -0,0 +1,4 @@
+* Nüüd saab heliklipi salvestust peatada taimeril klõpsides
+* Parandasime reageerimise jututubade otsesõnumitele
+* Enam me ei võta vastu reageerimiste, lugemisteatiste ja lugemismarkerite asendussõnumeid
+* Lisasime veel mõned meedia eelvaate ikoonid
@@ -0,0 +1,2 @@
+* Uso de SASL SCRAM Downgrade Protection (XEP-0474)
+* Envío de reaccións en MUC PMs ao JID correcto
@@ -0,0 +1,2 @@
+* Implementacja ochrony przed obniżeniem poziomu bezpieczeństwa SASL SCRAM (XEP-0474)
+* Wysyłanie reakcji w prywatnych wiadomościach w rozmowie grupowej do właściwego JID
@@ -0,0 +1,4 @@
+* Umożliwienie wstrzymania nagrywania dźwięku poprzez kliknięcie czasomierza
+* Naprawienie reakcji w prywatnych wiadomościach w rozmowie grupowej
+* Koniec akceptowania „zastępczych wiadomości”, dla reakcji, potwierdzeń i wskaźników przeczytania
+* Dodanie paru więcej ikonek załączników
@@ -0,0 +1,2 @@
+* Используется защита от понижения SASL SCRAM (XEP-0474)
+* Реакции отправляются в MUC PM для корректировки JID
@@ -0,0 +1,4 @@
+* Добавлена возможность приостановить запись звука нажатием на таймер
+* Исправлены реакции в MUC PM
+* Прекращён приём "резервных сообщений" для реакций, уведомлений о доставке и маркеров отображения
+* Добавлено ещё несколько значков для просмотра медиа
@@ -0,0 +1,4 @@
+* Lejim ndaljeje regjistrimi audio duke shtypur matësin e kohës
+* Ndreqje reagimesh në MP-ra MUC
+* Reshtje pranimi 'fallback messages' për reagime, dëftesa dhe shenja në ekrani
+* Shtim i disa ikonash paraparjeje media më tepër
@@ -0,0 +1,2 @@
+* Використання SASL SCRAM Downgrade Protection (XEP-0474)
+* Надсилання реакцій у приватні повідомлення MUC на правильний JID
@@ -0,0 +1,2 @@
+* 使用 SASL SCRAM 降级保护(XEP-0474)
+* 将 MUC 私信中的回应发送至正确的 JID
@@ -0,0 +1,4 @@
+* 允许通过点按计时器暂停录制音频
+* 修复 MUC 私信中的回应
+* 停止接收回应,回执和显示标记的“回退消息”
+* 添加更多媒体预览图标
@@ -308,7 +308,7 @@ public class ExportBackupService extends Worker {
}
Log.d(Config.LOGTAG, String.format("exporting data for account %s (%s)", account.getJid().asBareJid(), account.getUuid()));
final Progress progress = new Progress(notification, max, count);
- final File file = new File(FileBackend.getBackupDirectory(context), account.getJid().asBareJid().toEscapedString() + ".xml.pgp");
+ final File file = new File(FileBackend.getBackupDirectory(context), account.getJid().asBareJid().toString() + ".xml.pgp");
files.add(file);
final File directory = file.getParentFile();
if (directory != null && directory.mkdirs()) {
@@ -333,7 +333,7 @@ public class ExportBackupService extends Worker {
new byte[4096]
),
PGPLiteralDataGenerator.UTF8,
- account.getJid().asBareJid().toEscapedString() + ".xml",
+ account.getJid().asBareJid().toString() + ".xml",
PGPLiteralDataGenerator.NOW,
new byte[4096]
));
@@ -56,7 +56,7 @@ public class FinishOnboarding {
return;
}
- dataForm.put("new-jid", newAccount.getJid().toEscapedString());
+ dataForm.put("new-jid", newAccount.getJid().toString());
dataForm.submit();
command.setAttribute("action", "execute");
iq.setTo(iq.getFrom());
@@ -395,7 +395,7 @@ public class WebxdcPage implements ConversationPage {
final var occupantId = conversation.getMucOptions().getSelf().getOccupantId();
if (occupantId != null) return occupantId;
}
- return "xmpp:" + Uri.encode(selfJid().toEscapedString(), "@/+");
+ return "xmpp:" + Uri.encode(selfJid().toString(), "@/+");
}
@JavascriptInterface
@@ -63,7 +63,7 @@ public class WebxdcUpdate {
ContentValues cv = new ContentValues();
cv.put(Message.CONVERSATION, conversationId);
cv.put("message_id", messageId);
- cv.put("sender", sender.toEscapedString());
+ cv.put("sender", sender.toString());
cv.put("thread", thread);
cv.put("threadParent", threadParent);
if (info != null) cv.put("info", info);
@@ -75,7 +75,7 @@ public class WebxdcUpdate {
public String toString() {
StringBuilder body = new StringBuilder("{\"sender\":");
- body.append(JSONObject.quote(sender.toEscapedString()));
+ body.append(JSONObject.quote(sender.toString()));
if (serial != null) {
body.append(",\"serial\":");
body.append(serial.toString());
@@ -17,7 +17,7 @@ public class AccountConfiguration {
public String password;
public Jid getJid() {
- return Jid.ofEscaped(address);
+ return Jid.of(address);
}
public static AccountConfiguration parse(final String input) {
@@ -277,7 +277,7 @@ public class ImportBackupService extends Service {
db.setTransactionSuccessful();
db.endTransaction();
final Jid jid = backupFileHeader.getJid();
- final Cursor countCursor = db.rawQuery("select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?", new String[]{jid.getEscapedLocal(), jid.getDomain().toEscapedString()});
+ final Cursor countCursor = db.rawQuery("select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?", new String[]{jid.getLocal(), jid.getDomain().toString()});
countCursor.moveToFirst();
final int count = countCursor.getInt(0);
Log.d(Config.LOGTAG, String.format("restored %d messages in %s", count, stopwatch.stop().toString()));
@@ -133,7 +133,7 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
}
final Intent launchIntent = getIntent();
final String accountExtra = launchIntent.getStringExtra(EXTRA_ACCOUNT);
- final Jid jid = accountExtra == null ? null : Jid.ofEscaped(accountExtra);
+ final Jid jid = accountExtra == null ? null : Jid.of(accountExtra);
if (jid == null) {
return;
}
@@ -143,7 +143,7 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
public static void launch(final Account account, final Activity context) {
final Intent intent = new Intent(context, EasyOnboardingInviteActivity.class);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
context.startActivity(intent);
}
@@ -70,15 +70,15 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
final boolean fixedUsername;
if (this.domain != null && this.username != null) {
fixedUsername = true;
- jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain);
+ jid = Jid.ofLocalAndDomain(this.username, this.domain);
} else if (this.domain != null) {
fixedUsername = false;
- jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
+ jid = Jid.ofLocalAndDomain(username, this.domain);
} else {
fixedUsername = false;
- jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
+ jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN);
}
- if (!jid.getEscapedLocal().equals(jid.getLocal())) {
+ if (!jid.getLocal().equals(jid.getLocal())) {
binding.username.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
} else {
@@ -140,11 +140,11 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
binding.fullJid.setVisibility(View.VISIBLE);
final Jid jid;
if (this.domain == null) {
- jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
+ jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN);
} else {
- jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
+ jid = Jid.ofLocalAndDomain(username, this.domain);
}
- binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
+ binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toString()));
} catch (IllegalArgumentException e) {
binding.fullJid.setVisibility(View.INVISIBLE);
}
@@ -119,7 +119,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
String jid = savedInstanceState.getString(STATE_SELECTED_ACCOUNT);
if (jid != null) {
try {
- this.selectedAccountJid = Jid.ofEscaped(jid);
+ this.selectedAccountJid = Jid.of(jid);
} catch (IllegalArgumentException e) {
this.selectedAccountJid = null;
}
@@ -136,7 +136,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
@Override
public void onSaveInstanceState(final Bundle savedInstanceState) {
if (selectedAccount != null) {
- savedInstanceState.putString(STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString());
+ savedInstanceState.putString(STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toString());
}
super.onSaveInstanceState(savedInstanceState);
}
@@ -156,7 +156,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false);
menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false);
}
- menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toEscapedString());
+ menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toString());
}
@Override
@@ -347,7 +347,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
private void publishAvatar(Account account) {
Intent intent = new Intent(getApplicationContext(),
PublishProfilePictureActivity.class);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
startActivity(intent);
}
@@ -97,7 +97,7 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
Intent intent = new Intent(this, StartConversationActivity.class);
intent.putExtra("init", true);
- intent.putExtra(EXTRA_ACCOUNT, onboardingAccount.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, onboardingAccount.getJid().asBareJid().toString());
onboardingAccount = null;
startActivity(intent);
finish();
@@ -172,7 +172,7 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
} else {
binding.registerNewAccount.setText("Working...");
binding.registerNewAccount.setEnabled(false);
- onboardingAccount = new Account(Jid.ofLocalAndDomain(UUID.randomUUID().toString(), Config.ONBOARDING_DOMAIN.toEscapedString()), CryptoHelper.createPassword(new SecureRandom()));
+ onboardingAccount = new Account(Jid.ofLocalAndDomain(UUID.randomUUID().toString(), Config.ONBOARDING_DOMAIN.toString()), CryptoHelper.createPassword(new SecureRandom()));
onboardingAccount.setOption(Account.OPTION_REGISTER, true);
onboardingAccount.setOption(Account.OPTION_FIXED_USERNAME, true);
xmppConnectionService.createAccount(onboardingAccount);
@@ -259,7 +259,7 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
@Override
public void onAccountCreated(final Account account) {
final Intent intent = new Intent(this, EditAccountActivity.class);
- intent.putExtra("jid", account.getJid().asBareJid().toEscapedString());
+ intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", true);
addInviteUri(intent);
startActivity(intent);
@@ -26,12 +26,12 @@ public class PhoneNumberUtilWrapper {
try {
return getInstance(context).format(toPhoneNumber(context, jid), PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL).replace(' ','\u202F');
} catch (Exception e) {
- return jid.getEscapedLocal();
+ return jid.getLocal();
}
}
public static Phonenumber.PhoneNumber toPhoneNumber(Context context, Jid jid) throws NumberParseException {
- return getInstance(context).parse(jid.getEscapedLocal(), "de");
+ return getInstance(context).parse(jid.getLocal(), "de");
}
public static String normalize(Context context, String input) throws IllegalArgumentException, NumberParseException {
@@ -31,11 +31,11 @@ public class ProvisioningUtils {
}
final Intent serviceIntent = new Intent(activity, XmppConnectionService.class);
serviceIntent.setAction(XmppConnectionService.ACTION_PROVISION_ACCOUNT);
- serviceIntent.putExtra("address", jid.asBareJid().toEscapedString());
+ serviceIntent.putExtra("address", jid.asBareJid().toString());
serviceIntent.putExtra("password", accountConfiguration.password);
Compatibility.startService(activity, serviceIntent);
final Intent intent = new Intent(activity, EditAccountActivity.class);
- intent.putExtra("jid", jid.asBareJid().toEscapedString());
+ intent.putExtra("jid", jid.asBareJid().toString());
intent.putExtra("init", true);
activity.startActivity(intent);
}
@@ -24,10 +24,10 @@ public class SignupUtils {
public static Intent getTokenRegistrationIntent(final Activity activity, Jid jid, String preAuth) {
final Intent intent = new Intent(activity, MagicCreateActivity.class);
if (jid.isDomainJid()) {
- intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString());
+ intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toString());
} else {
- intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString());
- intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getEscapedLocal());
+ intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toString());
+ intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getLocal());
}
intent.putExtra(MagicCreateActivity.EXTRA_PRE_AUTH, preAuth);
return intent;
@@ -5,7 +5,6 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
-
import eu.siacs.conversations.xmpp.Jid;
public class AccountConfiguration {
@@ -17,7 +16,7 @@ public class AccountConfiguration {
public String password;
public Jid getJid() {
- return Jid.ofEscaped(address);
+ return Jid.of(address);
}
public static AccountConfiguration parse(final String input) {
@@ -27,24 +26,17 @@ public class AccountConfiguration {
} catch (JsonSyntaxException e) {
throw new IllegalArgumentException("Not a valid JSON string", e);
}
- Preconditions.checkArgument(
- c.protocol == Protocol.XMPP,
- "Protocol must be XMPP"
- );
+ Preconditions.checkArgument(c.protocol == Protocol.XMPP, "Protocol must be XMPP");
Preconditions.checkArgument(
c.address != null && c.getJid().isBareJid() && !c.getJid().isDomainJid(),
- "Invalid XMPP address"
- );
+ "Invalid XMPP address");
Preconditions.checkArgument(
- c.password != null && c.password.length() > 0,
- "No password specified"
- );
+ c.password != null && !c.password.isEmpty(), "No password specified");
return c;
}
public enum Protocol {
- @SerializedName("xmpp") XMPP,
+ @SerializedName("xmpp")
+ XMPP,
}
-
}
-
@@ -16,10 +16,8 @@ import android.os.Binder;
import android.os.IBinder;
import android.provider.OpenableColumns;
import android.util.Log;
-
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
-
import com.google.common.base.Charsets;
import com.google.common.base.Stopwatch;
import com.google.common.io.CountingInputStream;
@@ -27,7 +25,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore;
@@ -41,14 +38,6 @@ import eu.siacs.conversations.utils.BackupFileHeader;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.worker.ExportBackupWorker;
import eu.siacs.conversations.xmpp.Jid;
-
-import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.io.CipherInputStream;
-import org.bouncycastle.crypto.modes.AEADBlockCipher;
-import org.bouncycastle.crypto.modes.GCMBlockCipher;
-import org.bouncycastle.crypto.params.AEADParameters;
-import org.bouncycastle.crypto.params.KeyParameter;
-
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
@@ -72,8 +61,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipException;
-
import javax.crypto.BadPaddingException;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.io.CipherInputStream;
+import org.bouncycastle.crypto.modes.AEADBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.crypto.params.AEADParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
public class ImportBackupService extends Service {
@@ -314,10 +308,11 @@ public class ImportBackupService extends Service {
final Jid jid = backupFileHeader.getJid();
final Cursor countCursor =
db.rawQuery(
- "select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?",
- new String[] {
- jid.getEscapedLocal(), jid.getDomain().toEscapedString()
- });
+ "select count(messages.uuid) from messages join conversations on"
+ + " conversations.uuid=messages.conversationUuid join accounts on"
+ + " conversations.accountUuid=accounts.uuid where"
+ + " accounts.username=? and accounts.server=?",
+ new String[] {jid.getLocal(), jid.getDomain().toString()});
countCursor.moveToFirst();
final int count = countCursor.getInt(0);
Log.d(
@@ -11,13 +11,10 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityEasyInviteBinding;
@@ -153,7 +150,7 @@ public class EasyOnboardingInviteActivity extends XmppActivity
}
final Intent launchIntent = getIntent();
final String accountExtra = launchIntent.getStringExtra(EXTRA_ACCOUNT);
- final Jid jid = accountExtra == null ? null : Jid.ofEscaped(accountExtra);
+ final Jid jid = accountExtra == null ? null : Jid.of(accountExtra);
if (jid == null) {
return;
}
@@ -163,7 +160,7 @@ public class EasyOnboardingInviteActivity extends XmppActivity
public static void launch(final Account account, final Activity context) {
final Intent intent = new Intent(context, EasyOnboardingInviteActivity.class);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
context.startActivity(intent);
}
@@ -7,9 +7,7 @@ import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Toast;
-
import androidx.databinding.DataBindingUtil;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityMagicCreateBinding;
@@ -17,7 +15,6 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.InstallReferrerUtils;
import eu.siacs.conversations.xmpp.Jid;
-
import java.security.SecureRandom;
public class MagicCreateActivity extends XmppActivity implements TextWatcher {
@@ -68,15 +65,15 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
final boolean fixedUsername;
if (this.domain != null && this.username != null) {
fixedUsername = true;
- jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain);
+ jid = Jid.ofLocalAndDomain(this.username, this.domain);
} else if (this.domain != null) {
fixedUsername = false;
- jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
+ jid = Jid.ofLocalAndDomain(username, this.domain);
} else {
fixedUsername = false;
- jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
+ jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN);
}
- if (!jid.getEscapedLocal().equals(jid.getLocal())
+ if (!jid.getLocal().equals(jid.getLocal())
|| (this.username == null && username.length() < 3)) {
binding.usernameLayout.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
@@ -146,12 +143,11 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
binding.fullJid.setVisibility(View.VISIBLE);
final Jid jid;
if (this.domain == null) {
- jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
+ jid = Jid.ofLocalAndDomain(username, Config.MAGIC_CREATE_DOMAIN);
} else {
- jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
+ jid = Jid.ofLocalAndDomain(username, this.domain);
}
- binding.fullJid.setText(
- getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
+ binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toString()));
binding.usernameLayout.setError(null);
} catch (final IllegalArgumentException e) {
binding.fullJid.setVisibility(View.INVISIBLE);
@@ -17,13 +17,10 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.databinding.DataBindingUtil;
-
import com.google.common.base.Strings;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
@@ -34,12 +31,10 @@ import eu.siacs.conversations.ui.adapter.AccountAdapter;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
-
-import org.openintents.openpgp.util.OpenPgpApi;
-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.openintents.openpgp.util.OpenPgpApi;
public class ManageAccountActivity extends XmppActivity
implements OnAccountUpdate,
@@ -95,7 +90,7 @@ public class ManageAccountActivity extends XmppActivity
String jid = savedInstanceState.getString(STATE_SELECTED_ACCOUNT);
if (jid != null) {
try {
- this.selectedAccountJid = Jid.ofEscaped(jid);
+ this.selectedAccountJid = Jid.of(jid);
} catch (IllegalArgumentException e) {
this.selectedAccountJid = null;
}
@@ -113,7 +108,7 @@ public class ManageAccountActivity extends XmppActivity
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
if (selectedAccount != null) {
savedInstanceState.putString(
- STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString());
+ STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toString());
}
super.onSaveInstanceState(savedInstanceState);
}
@@ -132,7 +127,7 @@ public class ManageAccountActivity extends XmppActivity
menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false);
menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false);
}
- menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toEscapedString());
+ menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toString());
}
@Override
@@ -297,7 +292,7 @@ public class ManageAccountActivity extends XmppActivity
private void publishAvatar(Account account) {
Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
startActivity(intent);
}
@@ -357,7 +352,8 @@ public class ManageAccountActivity extends XmppActivity
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
- + ": quick start disabled. account will regain this capability on the next connect");
+ + ": quick start disabled. account will regain this capability on the"
+ + " next connect");
}
if (!xmppConnectionService.updateAccount(account)) {
Toast.makeText(this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show();
@@ -1,5 +1,8 @@
package eu.siacs.conversations.ui;
+import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
+import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
+
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@@ -12,14 +15,10 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
-
-import java.util.Arrays;
-import java.util.List;
-
+import com.google.common.base.Strings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityWelcomeBinding;
@@ -30,11 +29,8 @@ import eu.siacs.conversations.utils.InstallReferrerUtils;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
-
-import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
-import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
-
-import com.google.common.base.Strings;
+import java.util.Arrays;
+import java.util.List;
public class WelcomeActivity extends XmppActivity
implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback {
@@ -196,7 +192,7 @@ public class WelcomeActivity extends XmppActivity
@Override
public void onAccountCreated(final Account account) {
final Intent intent = new Intent(this, EditAccountActivity.class);
- intent.putExtra("jid", account.getJid().asBareJid().toEscapedString());
+ intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", true);
addInviteUri(intent);
startActivity(intent);
@@ -3,15 +3,13 @@ package eu.siacs.conversations.utils;
import android.app.Activity;
import android.content.Intent;
import android.widget.Toast;
-
-import java.util.List;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.AccountConfiguration;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.EditAccountActivity;
import eu.siacs.conversations.xmpp.Jid;
+import java.util.List;
public class ProvisioningUtils {
@@ -20,7 +18,8 @@ public class ProvisioningUtils {
try {
accountConfiguration = AccountConfiguration.parse(json);
} catch (final IllegalArgumentException e) {
- Toast.makeText(activity, R.string.improperly_formatted_provisioning, Toast.LENGTH_LONG).show();
+ Toast.makeText(activity, R.string.improperly_formatted_provisioning, Toast.LENGTH_LONG)
+ .show();
return;
}
final Jid jid = accountConfiguration.getJid();
@@ -31,13 +30,12 @@ public class ProvisioningUtils {
}
final Intent serviceIntent = new Intent(activity, XmppConnectionService.class);
serviceIntent.setAction(XmppConnectionService.ACTION_PROVISION_ACCOUNT);
- serviceIntent.putExtra("address", jid.asBareJid().toEscapedString());
+ serviceIntent.putExtra("address", jid.asBareJid().toString());
serviceIntent.putExtra("password", accountConfiguration.password);
Compatibility.startService(activity, serviceIntent);
final Intent intent = new Intent(activity, EditAccountActivity.class);
- intent.putExtra("jid", jid.asBareJid().toEscapedString());
+ intent.putExtra("jid", jid.asBareJid().toString());
intent.putExtra("init", true);
activity.startActivity(intent);
}
-
}
@@ -2,7 +2,6 @@ package eu.siacs.conversations.utils;
import android.app.Activity;
import android.content.Intent;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -21,13 +20,14 @@ public class SignupUtils {
return true;
}
- public static Intent getTokenRegistrationIntent(final Activity activity, Jid jid, String preAuth) {
+ public static Intent getTokenRegistrationIntent(
+ final Activity activity, Jid jid, String preAuth) {
final Intent intent = new Intent(activity, MagicCreateActivity.class);
if (jid.isDomainJid()) {
- intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString());
+ intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toString());
} else {
- intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString());
- intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getEscapedLocal());
+ intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toString());
+ intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getLocal());
}
intent.putExtra(MagicCreateActivity.EXTRA_PRE_AUTH, preAuth);
return intent;
@@ -55,7 +55,9 @@ public class SignupUtils {
intent = new Intent(activity, EditAccountActivity.class);
intent.putExtra("jid", pendingAccount.getJid().asBareJid().toString());
if (!pendingAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
- intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, pendingAccount.isOptionSet(Account.OPTION_REGISTER));
+ intent.putExtra(
+ EditAccountActivity.EXTRA_FORCE_REGISTER,
+ pendingAccount.isOptionSet(Account.OPTION_REGISTER));
}
} else {
if (service.getAccounts().size() == 0) {
@@ -74,4 +76,4 @@ public class SignupUtils {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
return intent;
}
-}
+}
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources></resources>
@@ -9,8 +9,8 @@ import java.util.Collection;
public class DowngradeProtection {
- private static final char SEPARATOR = ',';
- private static final char SEPARATOR_MECHANISM_AND_BINDING = '|';
+ private static final char SEPARATOR = 0x1E;
+ private static final char SEPARATOR_MECHANISM_AND_BINDING = 0x1F;
public final ImmutableList<String> mechanisms;
public final ImmutableList<String> channelBindings;
@@ -26,7 +26,7 @@ public class DowngradeProtection {
this.channelBindings = null;
}
- public String asDString() {
+ public String asHString() {
ensureSaslMechanismFormat(this.mechanisms);
ensureNoSeparators(this.mechanisms);
if (this.channelBindings != null) {
@@ -1,10 +1,8 @@
package eu.siacs.conversations.crypto.sasl;
import android.util.Base64;
-
-import javax.net.ssl.SSLSocket;
-
import eu.siacs.conversations.entities.Account;
+import javax.net.ssl.SSLSocket;
public class External extends SaslMechanism {
@@ -27,6 +25,6 @@ public class External extends SaslMechanism {
@Override
public String getClientFirstMessage(final SSLSocket sslSocket) {
return Base64.encodeToString(
- account.getJid().asBareJid().toEscapedString().getBytes(), Base64.NO_WRAP);
+ account.getJid().asBareJid().toString().getBytes(), Base64.NO_WRAP);
}
}
@@ -183,7 +183,7 @@ public abstract class ScramMechanism extends SaslMechanism {
final String i = attributes.get("i");
final String s = attributes.get("s");
final String nonce = attributes.get("r");
- final String d = attributes.get("d");
+ final String h = attributes.get("h");
if (Strings.isNullOrEmpty(s) || Strings.isNullOrEmpty(nonce) || Strings.isNullOrEmpty(i)) {
throw new AuthenticationException("Missing attributes from server first message");
}
@@ -205,15 +205,15 @@ public abstract class ScramMechanism extends SaslMechanism {
throw new AuthenticationException("Invalid salt in server first message");
}
- if (d != null && this.downgradeProtection != null) {
+ if (h != null && this.downgradeProtection != null) {
final String asSeenInFeatures;
try {
- asSeenInFeatures = downgradeProtection.asDString();
+ asSeenInFeatures = downgradeProtection.asHString();
} catch (final SecurityException e) {
throw new AuthenticationException(e);
}
final var hashed = BaseEncoding.base64().encode(digest(asSeenInFeatures.getBytes()));
- if (!hashed.equals(d)) {
+ if (!hashed.equals(h)) {
throw new AuthenticationException("Mismatch in SSDP");
}
}
@@ -306,7 +306,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
}
public String getUsername() {
- return jid.getEscapedLocal();
+ return jid.getLocal();
}
public boolean setJid(final Jid next) {
@@ -330,7 +330,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
}
public String getServer() {
- return jid.getDomain().toEscapedString();
+ return jid.getDomain().toString();
}
public String getPassword() {
@@ -546,7 +546,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
final ContentValues values = new ContentValues();
values.put(UUID, uuid);
values.put(USERNAME, jid.getLocal());
- values.put(SERVER, jid.getDomain().toEscapedString());
+ values.put(SERVER, jid.getDomain().toString());
values.put(PASSWORD, password);
values.put(OPTIONS, options);
synchronized (this.keys) {
@@ -768,11 +768,11 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
public String getShareableUri() {
List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
- String uri = "xmpp:" + Uri.encode(getJid().asBareJid().toEscapedString(), "@/+");
- if (fingerprints.size() > 0) {
- return XmppUri.getFingerprintUri(uri, fingerprints, ';');
- } else {
+ final String uri = "xmpp:" + Uri.encode(this.getJid().asBareJid().toString(), "@/+");
+ if (fingerprints.isEmpty()) {
return uri;
+ } else {
+ return XmppUri.getFingerprintUri(uri, fingerprints, ';');
}
}
@@ -780,11 +780,11 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
String uri =
"https://conversations.im/i/"
- + XmppUri.lameUrlEncode(this.getJid().asBareJid().toEscapedString());
- if (fingerprints.size() > 0) {
- return XmppUri.getFingerprintUri(uri, fingerprints, '&');
- } else {
+ + XmppUri.lameUrlEncode(this.getJid().asBareJid().toString());
+ if (fingerprints.isEmpty()) {
return uri;
+ } else {
+ return XmppUri.getFingerprintUri(uri, fingerprints, '&');
}
}
@@ -1,13 +1,15 @@
package eu.siacs.conversations.entities;
import android.content.Context;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
-
+import eu.siacs.conversations.utils.StringUtils;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xml.Namespace;
+import eu.siacs.conversations.xmpp.Jid;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -16,81 +18,76 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
-import eu.siacs.conversations.utils.StringUtils;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xmpp.InvalidJid;
-import eu.siacs.conversations.xmpp.Jid;
-
public class Bookmark extends Element implements ListItem {
- private final Account account;
- private WeakReference<Conversation> conversation;
- private Jid jid;
- protected Element extensions = new Element("extensions", Namespace.BOOKMARKS2);
-
- public Bookmark(final Account account, final Jid jid) {
- super("conference");
- this.jid = jid;
- this.setAttribute("jid", jid);
- this.account = account;
- }
-
- private Bookmark(Account account) {
- super("conference");
- this.account = account;
- }
-
- public static Map<Jid, Bookmark> parseFromStorage(Element storage, Account account) {
- if (storage == null) {
- return Collections.emptyMap();
- }
- final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
- for (final Element item : storage.getChildren()) {
- if (item.getName().equals("conference")) {
- final Bookmark bookmark = Bookmark.parse(item, account);
- if (bookmark != null) {
- final Bookmark old = bookmarks.put(bookmark.jid, bookmark);
- if (old != null && old.getBookmarkName() != null && bookmark.getBookmarkName() == null) {
- bookmark.setBookmarkName(old.getBookmarkName());
- }
- }
- }
- }
- return bookmarks;
- }
-
- public static Map<Jid, Bookmark> parseFromPubSub(final Element pubSub, final Account account) {
- if (pubSub == null) {
- return Collections.emptyMap();
- }
- final Element items = pubSub.findChild("items");
- if (items != null && Namespace.BOOKMARKS2.equals(items.getAttribute("node"))) {
- final Map<Jid, Bookmark> bookmarks = new HashMap<>();
- for(Element item : items.getChildren()) {
- if (item.getName().equals("item")) {
- final Bookmark bookmark = Bookmark.parseFromItem(item, account);
- if (bookmark != null) {
- bookmarks.put(bookmark.jid, bookmark);
- }
- }
- }
- return bookmarks;
- }
- return Collections.emptyMap();
- }
-
- public static Bookmark parse(Element element, Account account) {
- Bookmark bookmark = new Bookmark(account);
- bookmark.setAttributes(element.getAttributes());
- bookmark.setChildren(element.getChildren());
- bookmark.jid = InvalidJid.getNullForInvalid(bookmark.getAttributeAsJid("jid"));
- if (bookmark.jid == null) {
- return null;
- }
- return bookmark;
- }
+ private final Account account;
+ private WeakReference<Conversation> conversation;
+ private Jid jid;
+ protected Element extensions = new Element("extensions", Namespace.BOOKMARKS2);
+
+ public Bookmark(final Account account, final Jid jid) {
+ super("conference");
+ this.jid = jid;
+ this.setAttribute("jid", jid);
+ this.account = account;
+ }
+
+ private Bookmark(Account account) {
+ super("conference");
+ this.account = account;
+ }
+
+ public static Map<Jid, Bookmark> parseFromStorage(Element storage, Account account) {
+ if (storage == null) {
+ return Collections.emptyMap();
+ }
+ final HashMap<Jid, Bookmark> bookmarks = new HashMap<>();
+ for (final Element item : storage.getChildren()) {
+ if (item.getName().equals("conference")) {
+ final Bookmark bookmark = Bookmark.parse(item, account);
+ if (bookmark != null) {
+ final Bookmark old = bookmarks.put(bookmark.jid, bookmark);
+ if (old != null
+ && old.getBookmarkName() != null
+ && bookmark.getBookmarkName() == null) {
+ bookmark.setBookmarkName(old.getBookmarkName());
+ }
+ }
+ }
+ }
+ return bookmarks;
+ }
+
+ public static Map<Jid, Bookmark> parseFromPubSub(final Element pubSub, final Account account) {
+ if (pubSub == null) {
+ return Collections.emptyMap();
+ }
+ final Element items = pubSub.findChild("items");
+ if (items != null && Namespace.BOOKMARKS2.equals(items.getAttribute("node"))) {
+ final Map<Jid, Bookmark> bookmarks = new HashMap<>();
+ for (Element item : items.getChildren()) {
+ if (item.getName().equals("item")) {
+ final Bookmark bookmark = Bookmark.parseFromItem(item, account);
+ if (bookmark != null) {
+ bookmarks.put(bookmark.jid, bookmark);
+ }
+ }
+ }
+ return bookmarks;
+ }
+ return Collections.emptyMap();
+ }
+
+ public static Bookmark parse(Element element, Account account) {
+ Bookmark bookmark = new Bookmark(account);
+ bookmark.setAttributes(element.getAttributes());
+ bookmark.setChildren(element.getChildren());
+ bookmark.jid = Jid.Invalid.getNullForInvalid(bookmark.getAttributeAsJid("jid"));
+ if (bookmark.jid == null) {
+ return null;
+ }
+ return bookmark;
+ }
public static Bookmark parseFromItem(Element item, Account account) {
final Element conference = item.findChild("conference", Namespace.BOOKMARKS2);
@@ -98,7 +95,7 @@ public class Bookmark extends Element implements ListItem {
return null;
}
final Bookmark bookmark = new Bookmark(account);
- bookmark.jid = InvalidJid.getNullForInvalid(item.getAttributeAsJid("id"));
+ bookmark.jid = Jid.Invalid.getNullForInvalid(item.getAttributeAsJid("id"));
// TODO verify that we only use bare jids and ignore full jids
if (bookmark.jid == null) {
return null;
@@ -119,9 +116,9 @@ public class Bookmark extends Element implements ListItem {
return bookmark;
}
- public Element getExtensions() {
- return extensions;
- }
+ public Element getExtensions() {
+ return extensions;
+ }
public void addGroup(final String group) {
addChild("group", "jabber:iq:roster").setContent(group);
@@ -172,32 +169,32 @@ public class Bookmark extends Element implements ListItem {
another.getDisplayName());
}
- @Override
- public String getDisplayName() {
- final Conversation c = getConversation();
- final String name = getBookmarkName();
- if (c != null) {
- return c.getName().toString();
- } else if (printableValue(name, false)) {
- return name.trim();
- } else {
- Jid jid = this.getJid();
- return jid != null && jid.getLocal() != null ? jid.getLocal() : "";
- }
- }
-
- public static boolean printableValue(@Nullable String value, boolean permitNone) {
- return value != null && !value.trim().isEmpty() && (permitNone || !"None".equals(value));
- }
-
- public static boolean printableValue(@Nullable String value) {
- return printableValue(value, true);
- }
-
- @Override
- public Jid getJid() {
- return this.jid;
- }
+ @Override
+ public String getDisplayName() {
+ final Conversation c = getConversation();
+ final String name = getBookmarkName();
+ if (c != null) {
+ return c.getName().toString();
+ } else if (printableValue(name, false)) {
+ return name.trim();
+ } else {
+ Jid jid = this.getJid();
+ return jid != null && jid.getLocal() != null ? jid.getLocal() : "";
+ }
+ }
+
+ public static boolean printableValue(@Nullable String value, boolean permitNone) {
+ return value != null && !value.trim().isEmpty() && (permitNone || !"None".equals(value));
+ }
+
+ public static boolean printableValue(@Nullable String value) {
+ return printableValue(value, true);
+ }
+
+ @Override
+ public Jid getJid() {
+ return this.jid;
+ }
public Jid getFullJid() {
return getFullJid(getNick(), true);
@@ -236,32 +233,32 @@ public class Bookmark extends Element implements ListItem {
return tags;
}
- public String getNick() {
- return Strings.emptyToNull(this.findChildContent("nick"));
- }
+ public String getNick() {
+ return Strings.emptyToNull(this.findChildContent("nick"));
+ }
- public void setNick(String nick) {
- Element element = this.findChild("nick");
- if (element == null) {
- element = this.addChild("nick");
- }
- element.setContent(nick);
- }
+ public void setNick(String nick) {
+ Element element = this.findChild("nick");
+ if (element == null) {
+ element = this.addChild("nick");
+ }
+ element.setContent(nick);
+ }
- public boolean autojoin() {
- return this.getAttributeAsBoolean("autojoin");
- }
+ public boolean autojoin() {
+ return this.getAttributeAsBoolean("autojoin");
+ }
- public String getPassword() {
- return this.findChildContent("password");
- }
+ public String getPassword() {
+ return this.findChildContent("password");
+ }
- public void setPassword(String password) {
- Element element = this.findChild("password");
- if (element != null) {
- element.setContent(password);
- }
- }
+ public void setPassword(String password) {
+ Element element = this.findChild("password");
+ if (element != null) {
+ element.setContent(password);
+ }
+ }
@Override
public boolean match(Context context, String needle) {
@@ -289,56 +286,57 @@ public class Bookmark extends Element implements ListItem {
}
}
- private boolean matchInTag(Context context, String needle) {
- needle = needle.toLowerCase(Locale.US);
- for (Tag tag : getTags(context)) {
- if (tag.getName().toLowerCase(Locale.US).contains(needle)) {
- return true;
- }
- }
- return false;
- }
-
- public Account getAccount() {
- return this.account;
- }
-
- public synchronized Conversation getConversation() {
- return this.conversation != null ? this.conversation.get() : null;
- }
-
- public synchronized void setConversation(Conversation conversation) {
- if (this.conversation != null) {
- this.conversation.clear();
- }
- if (conversation == null) {
- this.conversation = null;
- } else {
- this.conversation = new WeakReference<>(conversation);
- }
- }
-
- public String getBookmarkName() {
- return this.getAttribute("name");
- }
-
- public boolean setBookmarkName(String name) {
- String before = getBookmarkName();
- if (name != null) {
- this.setAttribute("name", name);
- } else {
- this.removeAttribute("name");
- }
- return StringUtils.changed(before, name);
- }
-
- @Override
- public int getAvatarBackgroundColor() {
- return UIHelper.getColorForName(jid != null ? jid.asBareJid().toString() : getDisplayName());
- }
-
- @Override
- public String getAvatarName() {
- return getDisplayName();
- }
+ private boolean matchInTag(Context context, String needle) {
+ needle = needle.toLowerCase(Locale.US);
+ for (Tag tag : getTags(context)) {
+ if (tag.getName().toLowerCase(Locale.US).contains(needle)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Account getAccount() {
+ return this.account;
+ }
+
+ public synchronized Conversation getConversation() {
+ return this.conversation != null ? this.conversation.get() : null;
+ }
+
+ public synchronized void setConversation(Conversation conversation) {
+ if (this.conversation != null) {
+ this.conversation.clear();
+ }
+ if (conversation == null) {
+ this.conversation = null;
+ } else {
+ this.conversation = new WeakReference<>(conversation);
+ }
+ }
+
+ public String getBookmarkName() {
+ return this.getAttribute("name");
+ }
+
+ public boolean setBookmarkName(String name) {
+ String before = getBookmarkName();
+ if (name != null) {
+ this.setAttribute("name", name);
+ } else {
+ this.removeAttribute("name");
+ }
+ return StringUtils.changed(before, name);
+ }
+
+ @Override
+ public int getAvatarBackgroundColor() {
+ return UIHelper.getColorForName(
+ jid != null ? jid.asBareJid().toString() : getDisplayName());
+ }
+
+ @Override
+ public String getAvatarName() {
+ return getDisplayName();
+ }
}
@@ -16,7 +16,6 @@ import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
-
import com.google.common.base.Strings;
import org.json.JSONArray;
@@ -88,10 +87,21 @@ public class Contact implements ListItem, Blockable {
setAccount(other.getAccount());
}
- public Contact(final String account, final String systemName, final String serverName, final String presenceName,
- final Jid jid, final int subscription, final String photoUri,
- final Uri systemAccount, final String keys, final String avatar, final long lastseen,
- final String presence, final String groups, final RtpCapability.Capability rtpCapability) {
+ public Contact(
+ final String account,
+ final String systemName,
+ final String serverName,
+ final String presenceName,
+ final Jid jid,
+ final int subscription,
+ final String photoUri,
+ final Uri systemAccount,
+ final String keys,
+ final String avatar,
+ final long lastseen,
+ final String presence,
+ final String groups,
+ final RtpCapability.Capability rtpCapability) {
this.accountUuid = account;
this.systemName = systemName;
this.serverName = serverName;
@@ -110,7 +120,7 @@ public class Contact implements ListItem, Blockable {
if (avatar != null) {
this.avatar = new Avatar();
this.avatar.sha1sum = avatar;
- this.avatar.origin = Avatar.Origin.VCARD; //always assume worst
+ this.avatar.origin = Avatar.Origin.VCARD; // always assume worst
}
try {
this.groups = (groups == null ? new JSONArray() : new JSONArray(groups));
@@ -141,7 +151,8 @@ public class Contact implements ListItem, Blockable {
} catch (Exception e) {
systemAccount = null;
}
- return new Contact(cursor.getString(cursor.getColumnIndex(ACCOUNT)),
+ return new Contact(
+ cursor.getString(cursor.getColumnIndex(ACCOUNT)),
cursor.getString(cursor.getColumnIndex(SYSTEMNAME)),
cursor.getString(cursor.getColumnIndex(SERVERNAME)),
cursor.getString(cursor.getColumnIndex(PRESENCE_NAME)),
@@ -154,7 +165,8 @@ public class Contact implements ListItem, Blockable {
cursor.getLong(cursor.getColumnIndex(LAST_TIME)),
cursor.getString(cursor.getColumnIndex(LAST_PRESENCE)),
cursor.getString(cursor.getColumnIndex(GROUPS)),
- RtpCapability.Capability.of(cursor.getString(cursor.getColumnIndex(RTP_CAPABILITY))));
+ RtpCapability.Capability.of(
+ cursor.getString(cursor.getColumnIndex(RTP_CAPABILITY))));
}
public String getDisplayName() {
@@ -175,12 +187,14 @@ public class Contact implements ListItem, Blockable {
ListItem bookmark = account.getBookmark(jid);
if (bookmark != null) {
return bookmark.getDisplayName();
+ } else if (!TextUtils.isEmpty(this.presenceName) && mutualPresenceSubscription()) {
+ return this.presenceName;
} else if (!TextUtils.isEmpty(this.presenceName)) {
return this.presenceName + (mutualPresenceSubscription() ? "" : " (" + jid + ")");
} else if (jid.getLocal() != null) {
return JidHelper.localPartOrFallback(jid);
} else {
- return jid.getDomain().toEscapedString();
+ return jid.getDomain().toString();
}
}
@@ -190,7 +204,7 @@ public class Contact implements ListItem, Blockable {
} else if (jid.getLocal() != null) {
return JidHelper.localPartOrFallback(jid);
} else {
- return jid.getDomain().toEscapedString();
+ return jid.getDomain().toString();
}
}
@@ -242,8 +256,9 @@ public class Contact implements ListItem, Blockable {
getDisplayName().toLowerCase(Locale.US).contains(parts[0]) ||
matchInTag(context, parts[0]);
} else {
- return jid.toString().contains(needle) ||
- getDisplayName().toLowerCase(Locale.US).contains(needle);
+ return jid.toString().contains(needle)
+ || getDisplayName().toLowerCase(Locale.US).contains(needle)
+ || matchInTag(context, needle);
}
}
@@ -437,8 +452,8 @@ public class Contact implements ListItem, Blockable {
}
public boolean showInRoster() {
- return (this.getOption(Contact.Options.IN_ROSTER) && (!this
- .getOption(Contact.Options.DIRTY_DELETE)))
+ return (this.getOption(Contact.Options.IN_ROSTER)
+ && (!this.getOption(Contact.Options.DIRTY_DELETE)))
|| (this.getOption(Contact.Options.DIRTY_PUSH));
}
@@ -530,21 +545,25 @@ public class Contact implements ListItem, Blockable {
}
public String getServer() {
- return getJid().getDomain().toEscapedString();
+ return getJid().getDomain().toString();
}
- public void setAvatar(Avatar avatar) {
- setAvatar(avatar, false);
+ public boolean setAvatar(final Avatar avatar) {
+ return setAvatar(avatar, false);
}
- public void setAvatar(Avatar avatar, boolean previouslyOmittedPepFetch) {
+ public boolean setAvatar(final Avatar avatar, final boolean previouslyOmittedPepFetch) {
if (this.avatar != null && this.avatar.equals(avatar)) {
- return;
+ return false;
}
- if (!previouslyOmittedPepFetch && this.avatar != null && this.avatar.origin == Avatar.Origin.PEP && avatar.origin == Avatar.Origin.VCARD) {
- return;
+ if (!previouslyOmittedPepFetch
+ && this.avatar != null
+ && this.avatar.origin == Avatar.Origin.PEP
+ && avatar.origin == Avatar.Origin.VCARD) {
+ return false;
}
this.avatar = avatar;
+ return true;
}
public String getAvatarFilename() {
@@ -720,7 +739,8 @@ public class Contact implements ListItem, Blockable {
@Override
public int getAvatarBackgroundColor() {
- return UIHelper.getColorForName(jid != null ? jid.asBareJid().toString() : getDisplayName());
+ return UIHelper.getColorForName(
+ jid != null ? jid.asBareJid().toString() : getDisplayName());
}
@Override
@@ -287,8 +287,7 @@ public class Conversation extends AbstractEntity
cursor.getString(cursor.getColumnIndexOrThrow(NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTACT)),
cursor.getString(cursor.getColumnIndexOrThrow(ACCOUNT)),
- JidHelper.parseOrFallbackToInvalid(
- cursor.getString(cursor.getColumnIndexOrThrow(CONTACTJID))),
+ Jid.ofOrInvalid(cursor.getString(cursor.getColumnIndexOrThrow(CONTACTJID))),
cursor.getLong(cursor.getColumnIndexOrThrow(CREATED)),
cursor.getInt(cursor.getColumnIndexOrThrow(STATUS)),
cursor.getInt(cursor.getColumnIndexOrThrow(MODE)),
@@ -315,7 +314,7 @@ public class Conversation extends AbstractEntity
if (conversation.getContact().isOwnServer()) {
return false;
}
- final String contact = conversation.getJid().getDomain().toEscapedString();
+ final String contact = conversation.getJid().getDomain().toString();
final String account = conversation.getAccount().getServer();
if (Config.OMEMO_EXCEPTIONS.matchesContactDomain(contact)
|| Config.OMEMO_EXCEPTIONS.ACCOUNT_DOMAINS.contains(account)) {
@@ -2206,7 +2205,7 @@ public class Conversation extends AbstractEntity
if (field.getType().equals(Optional.of("jid-single")) || field.getType().equals(Optional.of("jid-multi"))) {
binding.values.setOnItemClickListener((arg0, arg1, pos, id) -> {
- new FixedURLSpan("xmpp:" + Uri.encode(Jid.ofEscaped(values.getItem(pos).getValue()).toEscapedString(), "@/+"), account).onClick(binding.values);
+ new FixedURLSpan("xmpp:" + Uri.encode(Jid.of(values.getItem(pos).getValue()).toString(), "@/+"), account).onClick(binding.values);
});
} else if ("xs:anyURI".equals(datatype)) {
binding.values.setOnItemClickListener((arg0, arg1, pos, id) -> {
@@ -2245,7 +2244,7 @@ public class Conversation extends AbstractEntity
String value = formatValue(datatype, cell.el.findChildContent("value", "jabber:x:data"), true);
SpannableStringBuilder text = new SpannableStringBuilder(value == null ? "" : value);
if (cell.reported.getType().equals(Optional.of("jid-single"))) {
- text.setSpan(new FixedURLSpan("xmpp:" + Jid.ofEscaped(text.toString()).toEscapedString(), account), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new FixedURLSpan("xmpp:" + Jid.of(text.toString()).toString(), account), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if ("xs:anyURI".equals(datatype)) {
text.setSpan(new FixedURLSpan(text.toString(), account), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if ("html:tel".equals(datatype)) {
@@ -1813,8 +1813,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
return encryption;
}
- public static boolean configurePrivateMessage(final Message message) {
- return configurePrivateMessage(message, false);
+ public static void configurePrivateMessage(final Message message) {
+ configurePrivateMessage(message, false);
}
public static boolean configurePrivateFileMessage(final Message message) {
@@ -1822,27 +1822,19 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
}
private static boolean configurePrivateMessage(final Message message, final boolean isFile) {
- final Conversation conversation;
- if (message.conversation instanceof Conversation) {
- conversation = (Conversation) message.conversation;
- } else {
- return false;
- }
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- final Jid nextCounterpart = conversation.getNextCounterpart();
- return configurePrivateMessage(conversation, message, nextCounterpart, isFile);
+ if (message.conversation instanceof Conversation conversation) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ final Jid nextCounterpart = conversation.getNextCounterpart();
+ return configurePrivateMessage(conversation, message, nextCounterpart, isFile);
+ }
}
return false;
}
- public static boolean configurePrivateMessage(final Message message, final Jid counterpart) {
- final Conversation conversation;
- if (message.conversation instanceof Conversation) {
- conversation = (Conversation) message.conversation;
- } else {
- return false;
+ public static void configurePrivateMessage(final Message message, final Jid counterpart) {
+ if (message.conversation instanceof Conversation conversation) {
+ configurePrivateMessage(conversation, message, counterpart, false);
}
- return configurePrivateMessage(conversation, message, counterpart, false);
}
private static boolean configurePrivateMessage(
@@ -1854,7 +1846,16 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
return false;
}
message.setCounterpart(counterpart);
- message.setTrueCounterpart(conversation.getMucOptions().getTrueCounterpart(counterpart));
+ final var mucOptions = conversation.getMucOptions();
+ if (counterpart.equals(mucOptions.getSelf().getFullJid())) {
+ message.setTrueCounterpart(conversation.getAccount().getJid().asBareJid());
+ } else {
+ final var user = mucOptions.findUserByFullJid(counterpart);
+ if (user != null) {
+ message.setTrueCounterpart(user.getRealJid());
+ message.setOccupantId(user.getOccupantId());
+ }
+ }
message.setType(isFile ? Message.TYPE_PRIVATE_FILE : Message.TYPE_PRIVATE);
return true;
}
@@ -12,7 +12,6 @@ import io.ipfs.cid.Cid;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.services.AvatarService;
@@ -71,16 +70,17 @@ public class MucOptions {
return this.conversation.getAccount();
}
- public boolean setSelf(User user) {
+ public boolean setSelf(final User user) {
this.self = user;
final boolean roleChanged = this.conversation.setAttribute("role", user.role.toString());
- final boolean affiliationChanged = this.conversation.setAttribute("affiliation", user.affiliation.toString());
+ final boolean affiliationChanged =
+ this.conversation.setAttribute("affiliation", user.affiliation.toString());
this.conversation.setAttribute("mucNick", user.getNick());
return roleChanged || affiliationChanged;
}
- public void changeAffiliation(Jid jid, Affiliation affiliation) {
- User user = findUserByRealJid(jid);
+ public void changeAffiliation(final Jid jid, final Affiliation affiliation) {
+ var user = findUserByRealJid(jid);
synchronized (users) {
if (user == null) {
user = new User(this, null, null, null, new HashSet<>());
@@ -130,21 +130,30 @@ public class MucOptions {
final var identities = serviceDiscoveryResult.getIdentities();
final String identityName = !identities.isEmpty() ? identities.get(0).getName() : null;
final Jid jid = conversation.getJid();
- if (identityName != null && !identityName.equals(jid == null ? null : jid.getEscapedLocal())) {
+ if (identityName != null && !identityName.equals(jid == null ? null : jid.getLocal())) {
name = identityName;
} else {
name = null;
}
}
boolean changed = conversation.setAttribute("muc_name", name);
- changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, this.hasFeature("muc_membersonly"));
- changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MODERATED, this.hasFeature("muc_moderated"));
- changed |= conversation.setAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous"));
+ changed |=
+ conversation.setAttribute(
+ Conversation.ATTRIBUTE_MEMBERS_ONLY, this.hasFeature("muc_membersonly"));
+ changed |=
+ conversation.setAttribute(
+ Conversation.ATTRIBUTE_MODERATED, this.hasFeature("muc_moderated"));
+ changed |=
+ conversation.setAttribute(
+ Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous"));
return changed;
}
private Data getRoomInfoForm() {
- final List<Data> forms = serviceDiscoveryResult == null ? Collections.emptyList() : serviceDiscoveryResult.forms;
+ final List<Data> forms =
+ serviceDiscoveryResult == null
+ ? Collections.emptyList()
+ : serviceDiscoveryResult.forms;
return forms.isEmpty() ? new Data() : forms.get(0);
}
@@ -153,7 +162,8 @@ public class MucOptions {
}
public boolean hasFeature(String feature) {
- return this.serviceDiscoveryResult != null && this.serviceDiscoveryResult.features.contains(feature);
+ return this.serviceDiscoveryResult != null
+ && this.serviceDiscoveryResult.features.contains(feature);
}
public boolean hasVCards() {
@@ -161,7 +171,8 @@ public class MucOptions {
}
public boolean canInvite() {
- final boolean hasPermission = !membersOnly() || self.getRole().ranks(Role.MODERATOR) || allowInvites();
+ final boolean hasPermission =
+ !membersOnly() || self.getRole().ranks(Role.MODERATOR) || allowInvites();
return hasPermission && online();
}
@@ -184,7 +195,7 @@ public class MucOptions {
public boolean allowPm() {
final Field field = getRoomInfoForm().getFieldByName("muc#roomconfig_allowpm");
if (field == null) {
- return true; //fall back if field does not exists
+ return true; // fall back if field does not exists
}
if ("anyone".equals(field.getValue())) {
return true;
@@ -199,7 +210,7 @@ public class MucOptions {
public boolean allowPmRaw() {
final Field field = getRoomInfoForm().getFieldByName("muc#roomconfig_allowpm");
- return field == null || Arrays.asList("anyone","participants").contains(field.getValue());
+ return field == null || Arrays.asList("anyone", "participants").contains(field.getValue());
}
public boolean participating() {
@@ -211,7 +222,9 @@ public class MucOptions {
}
public List<String> getFeatures() {
- return this.serviceDiscoveryResult != null ? this.serviceDiscoveryResult.features : Collections.emptyList();
+ return this.serviceDiscoveryResult != null
+ ? this.serviceDiscoveryResult.features
+ : Collections.emptyList();
}
public boolean nonanonymous() {
@@ -247,7 +260,8 @@ public class MucOptions {
break;
}
}
- boolean self = user.realJid != null && user.realJid.equals(account.getJid().asBareJid());
+ boolean self =
+ user.realJid != null && user.realJid.equals(account.getJid().asBareJid());
if (membersOnly()
&& nonanonymous()
&& user.affiliation.ranks(Affiliation.MEMBER)
@@ -264,7 +278,7 @@ public class MucOptions {
return user;
}
- //returns true if real jid was new;
+ // returns true if real jid was new;
public boolean updateUser(User user) {
User old;
boolean realJidFound = false;
@@ -273,7 +287,7 @@ public class MucOptions {
realJidFound = old != null;
if (old != null) {
if (old.fullJid != null) {
- return false; //don't add. user already exists
+ return false; // don't add. user already exists
} else {
synchronized (users) {
users.remove(old);
@@ -298,7 +312,10 @@ public class MucOptions {
if (old.hats != null && user.hats == null) user.hats = old.hats;
if (old.avatar != null && user.avatar == null) user.avatar = old.avatar;
}
- boolean fullJidIsSelf = isOnline && user.getFullJid() != null && user.getFullJid().equals(self.getFullJid());
+ boolean fullJidIsSelf =
+ isOnline
+ && user.getFullJid() != null
+ && user.getFullJid().equals(self.getFullJid());
if (!fullJidIsSelf) {
this.users.add(user);
return !realJidFound && user.realJid != null;
@@ -351,7 +368,9 @@ public class MucOptions {
public User findUserByOccupantId(final String occupantId, final Jid counterpart) {
synchronized (this.users) {
- final var found = Strings.isNullOrEmpty(occupantId) ? null : Iterables.find(this.users, u -> occupantId.equals(u.occupantId),null);
+ final var found = Strings.isNullOrEmpty(occupantId)
+ ? null
+ : Iterables.find(this.users, u -> occupantId.equals(u.occupantId), null);
if (Strings.isNullOrEmpty(occupantId) || found != null) return found;
final var user = new User(this, counterpart, occupantId, null, new HashSet<>());
user.setOnline(false);
@@ -372,7 +391,8 @@ public class MucOptions {
public User findUser(ReadByMarker readByMarker) {
if (readByMarker.getRealJid() != null) {
- return findOrCreateUserByRealJid(readByMarker.getRealJid().asBareJid(), readByMarker.getFullJid(), null);
+ return findOrCreateUserByRealJid(
+ readByMarker.getRealJid().asBareJid(), readByMarker.getFullJid(), null);
} else if (readByMarker.getFullJid() != null) {
return findUserByFullJid(readByMarker.getFullJid());
} else {
@@ -396,7 +416,7 @@ public class MucOptions {
public List<User> findUsers(final Collection<Reaction> reactions) {
final ImmutableList.Builder<User> builder = new ImmutableList.Builder<>();
- for(final Reaction reaction : reactions) {
+ for (final Reaction reaction : reactions) {
final var user = findUser(reaction);
if (user != null) {
builder.add(user);
@@ -470,13 +490,15 @@ public class MucOptions {
}
}
- public List<User> getUsers(int max) {
- ArrayList<User> subset = new ArrayList<>();
- HashSet<Jid> jids = new HashSet<>();
- jids.add(account.getJid().asBareJid());
+ public List<User> getUsers(final int max) {
+ final ArrayList<User> subset = new ArrayList<>();
+ final HashSet<Jid> addresses = new HashSet<>();
+ addresses.add(account.getJid().asBareJid());
synchronized (users) {
for (User user : users) {
- if (user.getRealJid() == null || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) {
+ if (user.getRealJid() == null
+ || (user.getRealJid().getLocal() != null
+ && addresses.add(user.getRealJid()))) {
subset.add(user);
}
if (subset.size() >= max) {
@@ -492,7 +514,8 @@ public class MucOptions {
HashSet<Jid> jids = new HashSet<>();
for (User user : users) {
jids.add(user.getAccount().getJid().asBareJid());
- if (user.getRealJid() == null || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) {
+ if (user.getRealJid() == null
+ || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) {
subset.add(user);
}
if (subset.size() >= max) {
@@ -530,7 +553,8 @@ public class MucOptions {
public String getProposedNickPure() {
final Bookmark bookmark = this.conversation.getBookmark();
- final String bookmarkedNick = normalize(account.getJid(), bookmark == null ? null : bookmark.getNick());
+ final String bookmarkedNick =
+ normalize(account.getJid(), bookmark == null ? null : bookmark.getNick());
if (bookmarkedNick != null) {
return bookmarkedNick;
} else {
@@ -718,7 +742,8 @@ public class MucOptions {
public String getPassword() {
this.password = conversation.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
- if (this.password == null && conversation.getBookmark() != null
+ if (this.password == null
+ && conversation.getBookmark() != null
&& conversation.getBookmark().getPassword() != null) {
return conversation.getBookmark().getPassword();
} else {
@@ -743,7 +768,12 @@ public class MucOptions {
ArrayList<Jid> members = new ArrayList<>();
synchronized (users) {
for (User user : users) {
- if (user.affiliation.ranks(Affiliation.MEMBER) && user.realJid != null && !user.realJid.asBareJid().equals(conversation.account.getJid().asBareJid()) && (!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);
}
}
@@ -859,9 +889,7 @@ public class MucOptions {
void onFailure();
}
- public interface OnRenameListener extends OnEventListener {
-
- }
+ public interface OnRenameListener extends OnEventListener {}
public static class Hat implements Comparable<Hat> {
private final Uri uri;
@@ -1014,7 +1042,7 @@ public class MucOptions {
}
}
- public boolean setAvatar(Avatar avatar) {
+ public boolean setAvatar(final Avatar avatar) {
if (occupantId != null) {
options.getConversation().setAttribute("occupantAvatar/" + occupantId, getContact() == null && avatar != null ? avatar.sha1sum : null);
}
@@ -1030,7 +1058,10 @@ public class MucOptions {
if (avatar != null) {
return avatar.getFilename();
}
- Avatar avatar = realJid != null ? getAccount().getRoster().getContact(realJid).getAvatar() : null;
+ Avatar avatar =
+ realJid != null
+ ? getAccount().getRoster().getContact(realJid).getAvatar()
+ : null;
return avatar == null ? null : avatar.getFilename();
}
@@ -1066,7 +1097,6 @@ public class MucOptions {
if (realJid != null ? !realJid.equals(user.realJid) : user.realJid != null)
return false;
return fullJid != null ? fullJid.equals(user.fullJid) : user.fullJid == null;
-
}
public boolean isDomain() {
@@ -1084,7 +1114,13 @@ public class MucOptions {
@Override
public String toString() {
- return "[fulljid:" + fullJid + ",realjid:" + realJid + ",nick:" + nick + ",affiliation" + affiliation.toString() + "]";
+ return "[fulljid:"
+ + fullJid
+ + ",realjid:"
+ + realJid
+ + ",affiliation"
+ + affiliation.toString()
+ + "]";
}
public boolean realJidMatchesAccount() {
@@ -2,14 +2,12 @@ package eu.siacs.conversations.entities;
import android.content.Context;
import android.text.TextUtils;
-
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.Jid;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.Jid;
-
public class RawBlockable implements ListItem, Blockable {
private final Account account;
@@ -40,7 +38,7 @@ public class RawBlockable implements ListItem, Blockable {
if (jid.isFullJid()) {
return jid.getResource();
} else {
- return jid.toEscapedString();
+ return jid.toString();
}
}
@@ -62,7 +60,7 @@ public class RawBlockable implements ListItem, Blockable {
needle = needle.toLowerCase(Locale.US).trim();
String[] parts = needle.split("\\s+");
for (String part : parts) {
- if (!jid.toEscapedString().contains(part)) {
+ if (!jid.toString().contains(part)) {
return false;
}
}
@@ -76,7 +74,7 @@ public class RawBlockable implements ListItem, Blockable {
@Override
public int getAvatarBackgroundColor() {
- return UIHelper.getColorForName(jid.toEscapedString());
+ return UIHelper.getColorForName(jid.toString());
}
@Override
@@ -86,7 +84,6 @@ public class RawBlockable implements ListItem, Blockable {
@Override
public int compareTo(ListItem o) {
- return this.getDisplayName().compareToIgnoreCase(
- o.getDisplayName());
+ return this.getDisplayName().compareToIgnoreCase(o.getDisplayName());
}
-}
+}
@@ -1,7 +1,6 @@
package eu.siacs.conversations.entities;
import android.util.Log;
-
import androidx.annotation.NonNull;
import com.cheogram.android.EmojiSearch;
@@ -29,7 +28,6 @@ import io.ipfs.cid.Cid;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.Emoticons;
import eu.siacs.conversations.xmpp.Jid;
-
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
@@ -178,7 +176,7 @@ public class Reaction {
if (value == null) {
out.nullValue();
} else {
- out.value(value.toEscapedString());
+ out.value(value.toString());
}
}
@@ -189,7 +187,7 @@ public class Reaction {
return null;
} else if (in.peek() == JsonToken.STRING) {
final String value = in.nextString();
- return Jid.ofEscaped(value);
+ return Jid.of(value);
}
throw new IOException("Unexpected token");
}
@@ -3,7 +3,6 @@ package eu.siacs.conversations.entities;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain;
-
import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.utils.LanguageUtils;
import eu.siacs.conversations.utils.UIHelper;
@@ -25,9 +24,7 @@ public class Room implements AvatarService.Avatarable, Comparable<Room> {
this.nusers = nusers;
}
- public Room() {
-
- }
+ public Room() {}
public String getName() {
return name;
@@ -52,7 +49,7 @@ public class Room implements AvatarService.Avatarable, Comparable<Room> {
@Override
public int getAvatarBackgroundColor() {
Jid room = getRoom();
- return UIHelper.getColorForName(room != null ? room.asBareJid().toEscapedString() : name);
+ return UIHelper.getColorForName(room != null ? room.asBareJid().toString() : name);
}
@Override
@@ -65,9 +62,9 @@ public class Room implements AvatarService.Avatarable, Comparable<Room> {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Room room = (Room) o;
- return Objects.equal(address, room.address) &&
- Objects.equal(name, room.name) &&
- Objects.equal(description, room.description);
+ return Objects.equal(address, room.address)
+ && Objects.equal(name, room.name)
+ && Objects.equal(description, room.description);
}
@Override
@@ -75,7 +72,6 @@ public class Room implements AvatarService.Avatarable, Comparable<Room> {
return Objects.hashCode(address, name, description);
}
-
public boolean contains(String needle) {
return Strings.nullToEmpty(name).contains(needle)
|| Strings.nullToEmpty(description).contains(needle)
@@ -90,4 +86,4 @@ public class Room implements AvatarService.Avatarable, Comparable<Room> {
.compare(Strings.nullToEmpty(address), Strings.nullToEmpty(o.address))
.result();
}
-}
+}
@@ -1,7 +1,6 @@
package eu.siacs.conversations.generator;
import android.util.Base64;
-
import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -10,7 +9,6 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.XmppConnection;
-
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
@@ -40,7 +38,8 @@ public abstract class AbstractGenerator {
Namespace.NICK + "+notify",
"urn:xmpp:ping",
"jabber:iq:version",
- "http://jabber.org/protocol/chatstates"
+ "http://jabber.org/protocol/chatstates",
+ Namespace.REACTIONS
};
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
"urn:xmpp:chat-markers:0", "urn:xmpp:receipts"
@@ -181,7 +181,7 @@ public class IqGenerator extends AbstractGenerator {
final Element pubsub = packet.addChild("pubsub", Namespace.PUBSUB);
final Element retract = pubsub.addChild("retract");
retract.setAttribute("node", node);
- retract.setAttribute("notify","true");
+ retract.setAttribute("notify", "true");
retract.addChild("item").setAttribute("id", id);
return packet;
}
@@ -194,7 +194,8 @@ public class IqGenerator extends AbstractGenerator {
return publish(Namespace.AVATAR_DATA, item, options);
}
- public Iq publishElement(final String namespace, final Element element, String id, final Bundle options) {
+ public Iq publishElement(
+ final String namespace, final Element element, String id, final Bundle options) {
final Element item = new Element("item");
item.setAttribute("id", id);
item.addChild(element);
@@ -204,8 +205,7 @@ public class IqGenerator extends AbstractGenerator {
public Iq publishAvatarMetadata(final Avatar avatar, final Bundle options) {
final Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
- final Element metadata = item
- .addChild("metadata", Namespace.AVATAR_METADATA);
+ final Element metadata = item.addChild("metadata", Namespace.AVATAR_METADATA);
final Element info = metadata.addChild("info");
info.setAttribute("bytes", avatar.size);
info.setAttribute("id", avatar.sha1sum);
@@ -292,7 +292,7 @@ public class IqGenerator extends AbstractGenerator {
if (password != null) {
conference.addChild("password").setContent(password);
}
- conference.setAttribute("autojoin",String.valueOf(autojoin));
+ conference.setAttribute("autojoin", String.valueOf(autojoin));
conference.addChild(bookmark.getExtensions());
return conference;
}
@@ -315,8 +315,12 @@ public class IqGenerator extends AbstractGenerator {
return displayed;
}
- public Iq publishBundles(final SignedPreKeyRecord signedPreKeyRecord, final IdentityKey identityKey,
- final Set<PreKeyRecord> preKeyRecords, final int deviceId, Bundle publishOptions) {
+ public Iq publishBundles(
+ final SignedPreKeyRecord signedPreKeyRecord,
+ final IdentityKey identityKey,
+ final Set<PreKeyRecord> preKeyRecords,
+ final int deviceId,
+ Bundle publishOptions) {
final Element item = new Element("item");
item.setAttribute("id", "current");
final Element bundle = item.addChild("bundle", AxolotlService.PEP_PREFIX);
@@ -325,21 +329,26 @@ public class IqGenerator extends AbstractGenerator {
ECPublicKey publicKey = signedPreKeyRecord.getKeyPair().getPublicKey();
signedPreKeyPublic.setContent(Base64.encodeToString(publicKey.serialize(), Base64.NO_WRAP));
final Element signedPreKeySignature = bundle.addChild("signedPreKeySignature");
- signedPreKeySignature.setContent(Base64.encodeToString(signedPreKeyRecord.getSignature(), Base64.NO_WRAP));
+ signedPreKeySignature.setContent(
+ Base64.encodeToString(signedPreKeyRecord.getSignature(), Base64.NO_WRAP));
final Element identityKeyElement = bundle.addChild("identityKey");
- identityKeyElement.setContent(Base64.encodeToString(identityKey.serialize(), Base64.NO_WRAP));
+ identityKeyElement.setContent(
+ Base64.encodeToString(identityKey.serialize(), Base64.NO_WRAP));
final Element prekeys = bundle.addChild("prekeys", AxolotlService.PEP_PREFIX);
for (PreKeyRecord preKeyRecord : preKeyRecords) {
final Element prekey = prekeys.addChild("preKeyPublic");
prekey.setAttribute("preKeyId", preKeyRecord.getId());
- prekey.setContent(Base64.encodeToString(preKeyRecord.getKeyPair().getPublicKey().serialize(), Base64.NO_WRAP));
+ prekey.setContent(
+ Base64.encodeToString(
+ preKeyRecord.getKeyPair().getPublicKey().serialize(), Base64.NO_WRAP));
}
return publish(AxolotlService.PEP_BUNDLES + ":" + deviceId, item, publishOptions);
}
- public Iq publishVerification(byte[] signature, X509Certificate[] certificates, final int deviceId) {
+ public Iq publishVerification(
+ byte[] signature, X509Certificate[] certificates, final int deviceId) {
final Element item = new Element("item");
item.setAttribute("id", "current");
final Element verification = item.addChild("verification", AxolotlService.PEP_PREFIX);
@@ -347,13 +356,16 @@ public class IqGenerator extends AbstractGenerator {
for (int i = 0; i < certificates.length; ++i) {
try {
Element certificate = chain.addChild("certificate");
- certificate.setContent(Base64.encodeToString(certificates[i].getEncoded(), Base64.NO_WRAP));
+ certificate.setContent(
+ Base64.encodeToString(certificates[i].getEncoded(), Base64.NO_WRAP));
certificate.setAttribute("index", i);
} catch (CertificateEncodingException e) {
Log.d(Config.LOGTAG, "could not encode certificate");
}
}
- verification.addChild("signature").setContent(Base64.encodeToString(signature, Base64.NO_WRAP));
+ verification
+ .addChild("signature")
+ .setContent(Base64.encodeToString(signature, Base64.NO_WRAP));
return publish(AxolotlService.PEP_VERIFICATION + ":" + deviceId, item);
}
@@ -366,7 +378,7 @@ public class IqGenerator extends AbstractGenerator {
if (mam.muc()) {
packet.setTo(mam.getWith());
} else if (mam.getWith() != null) {
- data.put("with", mam.getWith().toEscapedString());
+ data.put("with", mam.getWith().toString());
}
final long start = mam.getStart();
final long end = mam.getEnd();
@@ -395,7 +407,8 @@ public class IqGenerator extends AbstractGenerator {
return iq;
}
- public Iq generateSetBlockRequest(final Jid jid, final boolean reportSpam, final String serverMsgId) {
+ public Iq generateSetBlockRequest(
+ final Jid jid, final boolean reportSpam, final String serverMsgId) {
final Iq iq = new Iq(Iq.Type.SET);
final Element block = iq.addChild("block", Namespace.BLOCKING);
final Element item = block.addChild("item").setAttribute("jid", jid);
@@ -499,7 +512,9 @@ public class IqGenerator extends AbstractGenerator {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
- return Base64.encodeToString(bb.array(), Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP) + name.substring(pos);
+ return Base64.encodeToString(
+ bb.array(), Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP)
+ + name.substring(pos);
} catch (Exception e) {
return name;
}
@@ -508,7 +523,8 @@ public class IqGenerator extends AbstractGenerator {
}
}
- public static Iq generateCreateAccountWithCaptcha(final Account account, final String id, final Data data) {
+ public static Iq generateCreateAccountWithCaptcha(
+ final Account account, final String id, final Data data) {
final Iq register = new Iq(Iq.Type.SET);
register.setFrom(account.getJid().asBareJid());
register.setTo(account.getDomain());
@@ -534,7 +550,7 @@ public class IqGenerator extends AbstractGenerator {
data.put("token", token);
data.put("android-id", deviceId);
if (muc != null) {
- data.put("muc", muc.toEscapedString());
+ data.put("muc", muc.toString());
}
data.submit();
command.addChild(data);
@@ -581,7 +597,9 @@ public class IqGenerator extends AbstractGenerator {
public Iq queryAffiliation(Conversation conversation, String affiliation) {
final Iq packet = new Iq(Iq.Type.GET);
packet.setTo(conversation.getJid().asBareJid());
- packet.query("http://jabber.org/protocol/muc#admin").addChild("item").setAttribute("affiliation", affiliation);
+ packet.query("http://jabber.org/protocol/muc#admin")
+ .addChild("item")
+ .setAttribute("affiliation", affiliation);
return packet;
}
@@ -593,9 +611,9 @@ public class IqGenerator extends AbstractGenerator {
options.putString("muc#roomconfig_whois", "anyone");
options.putString("muc#roomconfig_changesubject", "0");
options.putString("muc#roomconfig_allowinvites", "0");
- options.putString("muc#roomconfig_enablearchiving", "1"); //prosody
- options.putString("mam", "1"); //ejabberd community
- options.putString("muc#roomconfig_mam", "1"); //ejabberd saas
+ options.putString("muc#roomconfig_enablearchiving", "1"); // prosody
+ options.putString("mam", "1"); // ejabberd community
+ options.putString("muc#roomconfig_mam", "1"); // ejabberd saas
return options;
}
@@ -606,9 +624,9 @@ public class IqGenerator extends AbstractGenerator {
options.putString("muc#roomconfig_publicroom", "1");
options.putString("muc#roomconfig_whois", "moderators");
options.putString("muc#roomconfig_changesubject", "0");
- options.putString("muc#roomconfig_enablearchiving", "1"); //prosody
- options.putString("mam", "1"); //ejabberd community
- options.putString("muc#roomconfig_mam", "1"); //ejabberd saas
+ options.putString("muc#roomconfig_enablearchiving", "1"); // prosody
+ options.putString("mam", "1"); // ejabberd community
+ options.putString("muc#roomconfig_mam", "1"); // ejabberd saas
return options;
}
@@ -648,7 +666,7 @@ public class IqGenerator extends AbstractGenerator {
public Iq queryDiscoInfo(final Jid jid) {
final Iq packet = new Iq(Iq.Type.GET);
packet.setTo(jid);
- packet.addChild("query",Namespace.DISCO_INFO);
+ packet.addChild("query", Namespace.DISCO_INFO);
return packet;
}
@@ -15,80 +15,82 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.stanza.Stanza;
public abstract class AbstractParser {
- protected final XmppConnectionService mXmppConnectionService;
- protected final Account account;
-
- protected AbstractParser(final XmppConnectionService service, final Account account) {
- this.mXmppConnectionService = service;
- this.account = account;
- }
-
- public static Long parseTimestamp(Element element, Long d) {
- return parseTimestamp(element,d,false);
- }
-
- public static Long parseTimestamp(Element element, Long d, boolean ignoreCsiAndSm) {
- long min = Long.MAX_VALUE;
- boolean returnDefault = true;
- final Jid to;
- if (ignoreCsiAndSm && element instanceof Stanza stanza) {
- to = stanza.getTo();
- } else {
- to = null;
- }
- for(Element child : element.getChildren()) {
- if ("delay".equals(child.getName()) && "urn:xmpp:delay".equals(child.getNamespace())) {
- final Jid f = to == null ? null : InvalidJid.getNullForInvalid(child.getAttributeAsJid("from"));
- if (f != null && (to.asBareJid().equals(f) || to.getDomain().equals(f))) {
- continue;
- }
- final String stamp = child.getAttribute("stamp");
- if (stamp != null) {
- try {
- min = Math.min(min,AbstractParser.parseTimestamp(stamp));
- returnDefault = false;
- } catch (Throwable t) {
- //ignore
- }
- }
- }
- }
- if (returnDefault) {
- return d;
- } else {
- return min;
- }
- }
-
- public static long parseTimestamp(Element element) {
- return parseTimestamp(element, System.currentTimeMillis());
- }
-
- public static long parseTimestamp(String timestamp) throws ParseException {
- timestamp = timestamp.replace("Z", "+0000");
- SimpleDateFormat dateFormat;
- long ms;
- if (timestamp.length() >= 25 && timestamp.charAt(19) == '.') {
- String millis = timestamp.substring(19,timestamp.length() - 5);
- try {
- double fractions = Double.parseDouble("0" + millis);
- ms = Math.round(1000 * fractions);
- } catch (NumberFormatException e) {
- ms = 0;
- }
- } else {
- ms = 0;
- }
- timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5);
- dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
- return Math.min(dateFormat.parse(timestamp).getTime()+ms, System.currentTimeMillis());
- }
+ protected final XmppConnectionService mXmppConnectionService;
+ protected final Account account;
+
+ protected AbstractParser(final XmppConnectionService service, final Account account) {
+ this.mXmppConnectionService = service;
+ this.account = account;
+ }
+
+ public static Long parseTimestamp(Element element, Long d) {
+ return parseTimestamp(element, d, false);
+ }
+
+ public static Long parseTimestamp(Element element, Long d, boolean ignoreCsiAndSm) {
+ long min = Long.MAX_VALUE;
+ boolean returnDefault = true;
+ final Jid to;
+ if (ignoreCsiAndSm && element instanceof Stanza stanza) {
+ to = stanza.getTo();
+ } else {
+ to = null;
+ }
+ for (Element child : element.getChildren()) {
+ if ("delay".equals(child.getName()) && "urn:xmpp:delay".equals(child.getNamespace())) {
+ final Jid f =
+ to == null
+ ? null
+ : Jid.Invalid.getNullForInvalid(child.getAttributeAsJid("from"));
+ if (f != null && (to.asBareJid().equals(f) || to.getDomain().equals(f))) {
+ continue;
+ }
+ final String stamp = child.getAttribute("stamp");
+ if (stamp != null) {
+ try {
+ min = Math.min(min, AbstractParser.parseTimestamp(stamp));
+ returnDefault = false;
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+ }
+ }
+ if (returnDefault) {
+ return d;
+ } else {
+ return min;
+ }
+ }
+
+ public static long parseTimestamp(Element element) {
+ return parseTimestamp(element, System.currentTimeMillis());
+ }
+
+ public static long parseTimestamp(String timestamp) throws ParseException {
+ timestamp = timestamp.replace("Z", "+0000");
+ SimpleDateFormat dateFormat;
+ long ms;
+ if (timestamp.length() >= 25 && timestamp.charAt(19) == '.') {
+ String millis = timestamp.substring(19, timestamp.length() - 5);
+ try {
+ double fractions = Double.parseDouble("0" + millis);
+ ms = Math.round(1000 * fractions);
+ } catch (NumberFormatException e) {
+ ms = 0;
+ }
+ } else {
+ ms = 0;
+ }
+ timestamp = timestamp.substring(0, 19) + timestamp.substring(timestamp.length() - 5);
+ dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
+ return Math.min(dateFormat.parse(timestamp).getTime() + ms, System.currentTimeMillis());
+ }
public static long getTimestamp(final String input) throws ParseException {
if (input == null) {
@@ -121,107 +123,107 @@ public abstract class AbstractParser {
}
}
- protected void updateLastseen(final Account account, final Jid from) {
- final Contact contact = account.getRoster().getContact(from);
- contact.setLastResource(from.isBareJid() ? "" : from.getResource());
- }
-
- protected static String avatarData(Element items) {
- Element item = items.findChild("item");
- if (item == null) {
- return null;
- }
- return item.findChildContent("data", "urn:xmpp:avatar:data");
- }
-
- public static MucOptions.User parseItem(Conversation conference, Element item) {
- return parseItem(conference,item,null,null,null,new Element("hats", "urn:xmpp:hats:0"));
- }
-
- public static MucOptions.User parseItem(final Conversation conference, Element item, Jid fullJid, final Element occupantId, final String nicknameIn, final Element hatsEl) {
- final String local = conference.getJid().getLocal();
- final String domain = conference.getJid().getDomain().toEscapedString();
- String affiliation = item.getAttribute("affiliation");
- String role = item.getAttribute("role");
- String nick = item.getAttribute("nick");
- if (nick != null && fullJid == null) {
- try {
- fullJid = Jid.of(local, domain, nick);
- } catch (IllegalArgumentException e) {
- fullJid = null;
- }
- }
- Jid realJid = item.getAttributeAsJid("jid");
- if (fullJid != null) nick = fullJid.getResource();
- String nickname = null;
- if (nick != null && nicknameIn != null) nickname = nick.equals(nicknameIn) ? nick : null;
- try {
- if (nickname == null && nicknameIn != null && nick != null && gnu.inet.encoding.Punycode.decode(nick).equals(nicknameIn)) {
- nickname = nicknameIn;
- }
- } catch (final Exception e) { }
- Set<MucOptions.Hat> hats = new TreeSet<>();
- for (Element hat : hatsEl.getChildren()) {
- if ("hat".equals(hat.getName()) && ("urn:xmpp:hats:0".equals(hat.getNamespace()) || "xmpp:prosody.im/protocol/hats:1".equals(hat.getNamespace()))) {
- hats.add(new MucOptions.Hat(hat));
- }
- }
- MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid, occupantId == null ? null : occupantId.getAttribute("id"), nickname, hatsEl == null ? null : hats);
- if (InvalidJid.isValid(realJid)) {
- user.setRealJid(realJid);
- }
- user.setAffiliation(affiliation);
- user.setRole(role);
- return user;
- }
-
- public static String extractErrorMessage(final Element packet) {
- final Element error = packet.findChild("error");
- if (error != null && error.getChildren().size() > 0) {
- final List<String> errorNames = orderedElementNames(error.getChildren());
- final String text = error.findChildContent("text");
- if (text != null && !text.trim().isEmpty()) {
- return prefixError(errorNames)+text;
- } else if (errorNames.size() > 0){
- return prefixError(errorNames)+errorNames.get(0).replace("-"," ");
- }
- }
- return null;
- }
-
- public static String errorMessage(Element packet) {
- final Element error = packet.findChild("error");
- if (error != null && error.getChildren().size() > 0) {
- final List<String> errorNames = orderedElementNames(error.getChildren());
- final String text = error.findChildContent("text");
- if (text != null && !text.trim().isEmpty()) {
- return text;
- } else if (errorNames.size() > 0){
- return errorNames.get(0).replace("-"," ");
- }
- }
- return null;
- }
-
- private static String prefixError(List<String> errorNames) {
- if (errorNames.size() > 0) {
- return errorNames.get(0)+'\u001f';
- }
- return "";
- }
-
- private static List<String> orderedElementNames(List<Element> children) {
- List<String> names = new ArrayList<>();
- for(Element child : children) {
- final String name = child.getName();
- if (name != null && !name.equals("text")) {
- if ("urn:ietf:params:xml:ns:xmpp-stanzas".equals(child.getNamespace())) {
- names.add(name);
- } else {
- names.add(0, name);
- }
- }
- }
- return names;
- }
+ protected void updateLastseen(final Account account, final Jid from) {
+ final Contact contact = account.getRoster().getContact(from);
+ contact.setLastResource(from.isBareJid() ? "" : from.getResource());
+ }
+
+ protected static String avatarData(Element items) {
+ Element item = items.findChild("item");
+ if (item == null) {
+ return null;
+ }
+ return item.findChildContent("data", "urn:xmpp:avatar:data");
+ }
+
+ public static MucOptions.User parseItem(Conversation conference, Element item) {
+ return parseItem(conference,item,null,null,null,new Element("hats", "urn:xmpp:hats:0"));
+ }
+
+ public static MucOptions.User parseItem(final Conversation conference, Element item, Jid fullJid, final Element occupantId, final String nicknameIn, final Element hatsEl) {
+ final String local = conference.getJid().getLocal();
+ final String domain = conference.getJid().getDomain().toString();
+ String affiliation = item.getAttribute("affiliation");
+ String role = item.getAttribute("role");
+ String nick = item.getAttribute("nick");
+ if (nick != null && fullJid == null) {
+ try {
+ fullJid = Jid.of(local, domain, nick);
+ } catch (IllegalArgumentException e) {
+ fullJid = null;
+ }
+ }
+ Jid realJid = item.getAttributeAsJid("jid");
+ if (fullJid != null) nick = fullJid.getResource();
+ String nickname = null;
+ if (nick != null && nicknameIn != null) nickname = nick.equals(nicknameIn) ? nick : null;
+ try {
+ if (nickname == null && nicknameIn != null && nick != null && gnu.inet.encoding.Punycode.decode(nick).equals(nicknameIn)) {
+ nickname = nicknameIn;
+ }
+ } catch (final Exception e) { }
+ Set<MucOptions.Hat> hats = new TreeSet<>();
+ for (Element hat : hatsEl.getChildren()) {
+ if ("hat".equals(hat.getName()) && ("urn:xmpp:hats:0".equals(hat.getNamespace()) || "xmpp:prosody.im/protocol/hats:1".equals(hat.getNamespace()))) {
+ hats.add(new MucOptions.Hat(hat));
+ }
+ }
+ MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid, occupantId == null ? null : occupantId.getAttribute("id"), nickname, hatsEl == null ? null : hats);
+ if (Jid.Invalid.isValid(realJid)) {
+ user.setRealJid(realJid);
+ }
+ user.setAffiliation(affiliation);
+ user.setRole(role);
+ return user;
+ }
+
+ public static String extractErrorMessage(final Element packet) {
+ final Element error = packet.findChild("error");
+ if (error != null && error.getChildren().size() > 0) {
+ final List<String> errorNames = orderedElementNames(error.getChildren());
+ final String text = error.findChildContent("text");
+ if (text != null && !text.trim().isEmpty()) {
+ return prefixError(errorNames) + text;
+ } else if (errorNames.size() > 0) {
+ return prefixError(errorNames) + errorNames.get(0).replace("-", " ");
+ }
+ }
+ return null;
+ }
+
+ public static String errorMessage(Element packet) {
+ final Element error = packet.findChild("error");
+ if (error != null && error.getChildren().size() > 0) {
+ final List<String> errorNames = orderedElementNames(error.getChildren());
+ final String text = error.findChildContent("text");
+ if (text != null && !text.trim().isEmpty()) {
+ return text;
+ } else if (errorNames.size() > 0) {
+ return errorNames.get(0).replace("-", " ");
+ }
+ }
+ return null;
+ }
+
+ private static String prefixError(List<String> errorNames) {
+ if (errorNames.size() > 0) {
+ return errorNames.get(0) + '\u001f';
+ }
+ return "";
+ }
+
+ private static List<String> orderedElementNames(List<Element> children) {
+ List<String> names = new ArrayList<>();
+ for (Element child : children) {
+ final String name = child.getName();
+ if (name != null && !name.equals("text")) {
+ if ("urn:ietf:params:xml:ns:xmpp-stanzas".equals(child.getNamespace())) {
+ names.add(name);
+ } else {
+ names.add(0, name);
+ }
+ }
+ }
+ return names;
+ }
}
@@ -3,18 +3,21 @@ package eu.siacs.conversations.parser;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
-
import androidx.annotation.NonNull;
-
import com.google.common.base.CharMatcher;
import com.google.common.io.BaseEncoding;
-
-import org.whispersystems.libsignal.IdentityKey;
-import org.whispersystems.libsignal.InvalidKeyException;
-import org.whispersystems.libsignal.ecc.Curve;
-import org.whispersystems.libsignal.ecc.ECPublicKey;
-import org.whispersystems.libsignal.state.PreKeyBundle;
-
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.Room;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xml.Namespace;
+import eu.siacs.conversations.xmpp.Jid;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import eu.siacs.conversations.xmpp.forms.Data;
+import im.conversations.android.xmpp.model.stanza.Iq;
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -37,12 +40,17 @@ import eu.siacs.conversations.entities.Room;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.forms.Data;
import im.conversations.android.xmpp.model.stanza.Iq;
+import org.whispersystems.libsignal.IdentityKey;
+import org.whispersystems.libsignal.InvalidKeyException;
+import org.whispersystems.libsignal.ecc.Curve;
+import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.libsignal.state.PreKeyBundle;
+
public class IqParser extends AbstractParser implements Consumer<Iq> {
public IqParser(final XmppConnectionService service, final Account account) {
@@ -95,8 +103,7 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
TextUtils.isEmpty(roomName) ? name : roomName,
description,
language,
- nusers
- );
+ nusers);
}
private void rosterItems(final Account account, final Element query) {
@@ -106,14 +113,16 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
}
for (final Element item : query.getChildren()) {
if (item.getName().equals("item")) {
- final Jid jid = InvalidJid.getNullForInvalid(item.getAttributeAsJid("jid"));
+ final Jid jid = Jid.Invalid.getNullForInvalid(item.getAttributeAsJid("jid"));
if (jid == null) {
continue;
}
final String name = item.getAttribute("name");
final String subscription = item.getAttribute("subscription");
final Contact contact = account.getRoster().getContact(jid);
- boolean bothPre = contact.getOption(Contact.Options.TO) && contact.getOption(Contact.Options.FROM);
+ boolean bothPre =
+ contact.getOption(Contact.Options.TO)
+ && contact.getOption(Contact.Options.FROM);
if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
contact.setServerName(name);
contact.parseGroupsFromElement(item);
@@ -127,9 +136,15 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
contact.resetOption(Contact.Options.DIRTY_PUSH);
contact.parseSubscriptionFromElement(item);
}
- boolean both = contact.getOption(Contact.Options.TO) && contact.getOption(Contact.Options.FROM);
+ boolean both =
+ contact.getOption(Contact.Options.TO)
+ && contact.getOption(Contact.Options.FROM);
if ((both != bothPre) && both) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": gained mutual presence subscription with " + contact.getJid());
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": gained mutual presence subscription with "
+ + contact.getJid());
AxolotlService axolotlService = account.getAxolotlService();
if (axolotlService != null) {
axolotlService.clearErrorsInFetchStatusMap(contact.getJid());
@@ -182,7 +197,15 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
Integer id = Integer.valueOf(device.getAttribute("id"));
deviceIds.add(id);
} catch (NumberFormatException e) {
- Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Encountered invalid <device> node in PEP (" + e.getMessage() + "):" + device.toString() + ", skipping...");
+ Log.e(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Encountered invalid <device> node in PEP ("
+ + e.getMessage()
+ + "):"
+ + device.toString()
+ + ", skipping...");
}
}
}
@@ -211,7 +234,12 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
try {
publicKey = Curve.decodePoint(base64decode(signedPreKeyPublic), 0);
} catch (final IllegalArgumentException | InvalidKeyException e) {
- Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Invalid signedPreKeyPublic in PEP: " + e.getMessage());
+ Log.e(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Invalid signedPreKeyPublic in PEP: "
+ + e.getMessage());
}
return publicKey;
}
@@ -224,7 +252,9 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
try {
return base64decode(signedPreKeySignature);
} catch (final IllegalArgumentException e) {
- Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX + " : Invalid base64 in signedPreKeySignature");
+ Log.e(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX + " : Invalid base64 in signedPreKeySignature");
return null;
}
}
@@ -237,7 +267,12 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
try {
return new IdentityKey(base64decode(identityKey), 0);
} catch (final IllegalArgumentException | InvalidKeyException e) {
- Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Invalid identityKey in PEP: " + e.getMessage());
+ Log.e(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Invalid identityKey in PEP: "
+ + e.getMessage());
return null;
}
}
@@ -246,7 +281,12 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
Map<Integer, ECPublicKey> preKeyRecords = new HashMap<>();
Element item = getItem(packet);
if (item == null) {
- Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Couldn't find <item> in bundle IQ packet: " + packet);
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Couldn't find <item> in bundle IQ packet: "
+ + packet);
return null;
}
final Element bundleElement = item.findChild("bundle");
@@ -255,12 +295,22 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
}
final Element prekeysElement = bundleElement.findChild("prekeys");
if (prekeysElement == null) {
- Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Couldn't find <prekeys> in bundle IQ packet: " + packet);
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Couldn't find <prekeys> in bundle IQ packet: "
+ + packet);
return null;
}
for (Element preKeyPublicElement : prekeysElement.getChildren()) {
if (!preKeyPublicElement.getName().equals("preKeyPublic")) {
- Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Encountered unexpected tag in prekeys list: " + preKeyPublicElement);
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Encountered unexpected tag in prekeys list: "
+ + preKeyPublicElement);
continue;
}
final String preKey = preKeyPublicElement.getContent();
@@ -273,9 +323,22 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
final ECPublicKey preKeyPublic = Curve.decodePoint(base64decode(preKey), 0);
preKeyRecords.put(preKeyId, preKeyPublic);
} catch (NumberFormatException e) {
- Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "could not parse preKeyId from preKey " + preKeyPublicElement.toString());
+ Log.e(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "could not parse preKeyId from preKey "
+ + preKeyPublicElement.toString());
} catch (Throwable e) {
- Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + "Invalid preKeyPublic (ID=" + preKeyId + ") in PEP: " + e.getMessage() + ", skipping...");
+ Log.e(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX
+ + " : "
+ + "Invalid preKeyPublic (ID="
+ + preKeyId
+ + ") in PEP: "
+ + e.getMessage()
+ + ", skipping...");
}
}
return preKeyRecords;
@@ -287,7 +350,8 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
public static Pair<X509Certificate[], byte[]> verification(final Iq packet) {
Element item = getItem(packet);
- Element verification = item != null ? item.findChild("verification", AxolotlService.PEP_PREFIX) : null;
+ Element verification =
+ item != null ? item.findChild("verification", AxolotlService.PEP_PREFIX) : null;
Element chain = verification != null ? verification.findChild("chain") : null;
String signature = verification != null ? verification.findChildContent("signature") : null;
if (chain != null && signature != null) {
@@ -301,7 +365,11 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
if (cert == null) {
continue;
}
- certificates[i] = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(BaseEncoding.base64().decode(cert)));
+ certificates[i] =
+ (X509Certificate)
+ certificateFactory.generateCertificate(
+ new ByteArrayInputStream(
+ BaseEncoding.base64().decode(cert)));
++i;
}
return new Pair<>(certificates, BaseEncoding.base64().decode(signature));
@@ -333,8 +401,15 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
|| signedPreKeySignature.length == 0) {
return null;
}
- return new PreKeyBundle(0, 0, 0, null,
- signedPreKeyId, signedPreKeyPublic, signedPreKeySignature, identityKey);
+ return new PreKeyBundle(
+ 0,
+ 0,
+ 0,
+ null,
+ signedPreKeyId,
+ signedPreKeyPublic,
+ signedPreKeySignature,
+ identityKey);
}
public static List<PreKeyBundle> preKeys(final Iq preKeys) {
@@ -343,8 +418,7 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
if (preKeyPublics != null) {
for (Integer preKeyId : preKeyPublics.keySet()) {
ECPublicKey preKeyPublic = preKeyPublics.get(preKeyId);
- bundles.add(new PreKeyBundle(0, 0, preKeyId, preKeyPublic,
- 0, null, null, null));
+ bundles.add(new PreKeyBundle(0, 0, preKeyId, preKeyPublic, 0, null, null, null));
}
}
@@ -364,15 +438,19 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
account.getRoster().markAllAsNotInRoster();
}
this.rosterItems(account, query);
- } else if ((packet.hasChild("block", Namespace.BLOCKING) || packet.hasChild("blocklist", Namespace.BLOCKING)) &&
- packet.fromServer(account)) {
+ } else if ((packet.hasChild("block", Namespace.BLOCKING)
+ || packet.hasChild("blocklist", Namespace.BLOCKING))
+ && packet.fromServer(account)) {
// Block list or block push.
Log.d(Config.LOGTAG, "Received blocklist update from server");
final Element blocklist = packet.findChild("blocklist", Namespace.BLOCKING);
final Element block = packet.findChild("block", Namespace.BLOCKING);
- final Collection<Element> items = blocklist != null ? blocklist.getChildren() :
- (block != null ? block.getChildren() : null);
- // If this is a response to a blocklist query, clear the block list and replace with the new one.
+ final Collection<Element> items =
+ blocklist != null
+ ? blocklist.getChildren()
+ : (block != null ? block.getChildren() : null);
+ // If this is a response to a blocklist query, clear the block list and replace with the
+ // new one.
// Otherwise, just update the existing blocklist.
if (packet.getType() == Iq.Type.RESULT) {
account.clearBlocklist();
@@ -383,7 +461,8 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
// Create a collection of Jids from the packet
for (final Element item : items) {
if (item.getName().equals("item")) {
- final Jid jid = InvalidJid.getNullForInvalid(item.getAttributeAsJid("jid"));
+ final Jid jid =
+ Jid.Invalid.getNullForInvalid(item.getAttributeAsJid("jid"));
if (jid != null) {
jids.add(jid);
}
@@ -406,10 +485,12 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
final Iq response = packet.generateResponse(Iq.Type.RESULT);
mXmppConnectionService.sendIqPacket(account, response, null);
}
- } else if (packet.hasChild("unblock", Namespace.BLOCKING) &&
- packet.fromServer(account) && packet.getType() == Iq.Type.SET) {
+ } else if (packet.hasChild("unblock", Namespace.BLOCKING)
+ && packet.fromServer(account)
+ && packet.getType() == Iq.Type.SET) {
Log.d(Config.LOGTAG, "Received unblock update from server");
- final Collection<Element> items = packet.findChild("unblock", Namespace.BLOCKING).getChildren();
+ final Collection<Element> items =
+ packet.findChild("unblock", Namespace.BLOCKING).getChildren();
if (items.isEmpty()) {
// No children to unblock == unblock all
account.getBlocklist().clear();
@@ -417,7 +498,8 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
final Collection<Jid> jids = new ArrayList<>(items.size());
for (final Element item : items) {
if (item.getName().equals("item")) {
- final Jid jid = InvalidJid.getNullForInvalid(item.getAttributeAsJid("jid"));
+ final Jid jid =
+ Jid.Invalid.getNullForInvalid(item.getAttributeAsJid("jid"));
if (jid != null) {
jids.add(jid);
}
@@ -431,10 +513,10 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
} else if (packet.hasChild("open", "http://jabber.org/protocol/ibb")
|| packet.hasChild("data", "http://jabber.org/protocol/ibb")
|| packet.hasChild("close", "http://jabber.org/protocol/ibb")) {
- mXmppConnectionService.getJingleConnectionManager()
- .deliverIbbPacket(account, packet);
+ mXmppConnectionService.getJingleConnectionManager().deliverIbbPacket(account, packet);
} else if (packet.hasChild("query", "http://jabber.org/protocol/disco#info")) {
- final Iq response = mXmppConnectionService.getIqGenerator().discoResponse(account, packet);
+ final Iq response =
+ mXmppConnectionService.getIqGenerator().discoResponse(account, packet);
mXmppConnectionService.sendIqPacket(account, response, null);
} else if (packet.hasChild("query", "jabber:iq:version") && isGet) {
final Iq response = mXmppConnectionService.getIqGenerator().versionResponse(packet);
@@ -453,7 +535,8 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
response = mXmppConnectionService.getIqGenerator().entityTimeResponse(packet);
}
mXmppConnectionService.sendIqPacket(account, response, null);
- } else if (packet.hasChild("push", Namespace.UNIFIED_PUSH) && packet.getType() == Iq.Type.SET) {
+ } else if (packet.hasChild("push", Namespace.UNIFIED_PUSH)
+ && packet.getType() == Iq.Type.SET) {
final Jid transport = packet.getFrom();
final Element push = packet.findChild("push", Namespace.UNIFIED_PUSH);
final boolean success =
@@ -485,5 +568,4 @@ public class IqParser extends AbstractParser implements Consumer<Iq> {
}
}
}
-
}
@@ -59,25 +59,27 @@ import eu.siacs.conversations.utils.Emoticons;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.LocalizedContent;
import eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
-import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
import eu.siacs.conversations.xmpp.pep.Avatar;
import im.conversations.android.xmpp.model.Extension;
+import im.conversations.android.xmpp.model.axolotl.Encrypted;
import im.conversations.android.xmpp.model.carbons.Received;
import im.conversations.android.xmpp.model.carbons.Sent;
import im.conversations.android.xmpp.model.correction.Replace;
import im.conversations.android.xmpp.model.forward.Forwarded;
+import im.conversations.android.xmpp.model.markers.Displayed;
import im.conversations.android.xmpp.model.occupant.OccupantId;
import im.conversations.android.xmpp.model.reactions.Reactions;
-public class MessageParser extends AbstractParser implements Consumer<im.conversations.android.xmpp.model.stanza.Message> {
+public class MessageParser extends AbstractParser
+ implements Consumer<im.conversations.android.xmpp.model.stanza.Message> {
- private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH);
+ private static final SimpleDateFormat TIME_FORMAT =
+ new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH);
private static final List<String> JINGLE_MESSAGE_ELEMENT_NAMES =
Arrays.asList("accept", "propose", "proceed", "reject", "retract", "ringing", "finish");
@@ -86,7 +88,8 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
super(service, account);
}
- private static String extractStanzaId(Element packet, boolean isTypeGroupChat, Conversation conversation) {
+ private static String extractStanzaId(
+ Element packet, boolean isTypeGroupChat, Conversation conversation) {
final Jid by;
final boolean safeToExtract;
if (isTypeGroupChat) {
@@ -109,7 +112,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
for (Element child : packet.getChildren()) {
if (child.getName().equals("stanza-id")
&& Namespace.STANZA_IDS.equals(child.getNamespace())
- && by.equals(InvalidJid.getNullForInvalid(child.getAttributeAsJid("by")))) {
+ && by.equals(Jid.Invalid.getNullForInvalid(child.getAttributeAsJid("by")))) {
return child.getAttribute("id");
}
}
@@ -118,11 +121,15 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
private static Jid getTrueCounterpart(Element mucUserElement, Jid fallback) {
final Element item = mucUserElement == null ? null : mucUserElement.findChild("item");
- Jid result = item == null ? null : InvalidJid.getNullForInvalid(item.getAttributeAsJid("jid"));
+ Jid result =
+ item == null ? null : Jid.Invalid.getNullForInvalid(item.getAttributeAsJid("jid"));
return result != null ? result : fallback;
}
- private boolean extractChatState(Conversation c, final boolean isTypeGroupChat, final im.conversations.android.xmpp.model.stanza.Message packet) {
+ private boolean extractChatState(
+ Conversation c,
+ final boolean isTypeGroupChat,
+ final im.conversations.android.xmpp.model.stanza.Message packet) {
ChatState state = ChatState.parse(packet);
if (state != null && c != null) {
final Account account = c.getAccount();
@@ -153,45 +160,76 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
return false;
}
- private Message parseAxolotlChat(Element axolotlMessage, Jid from, Conversation conversation, int status, final boolean checkedForDuplicates, boolean postpone) {
+ private Message parseAxolotlChat(
+ final Encrypted axolotlMessage,
+ final Jid from,
+ final Conversation conversation,
+ final int status,
+ final boolean checkedForDuplicates,
+ final boolean postpone) {
final AxolotlService service = conversation.getAccount().getAxolotlService();
final XmppAxolotlMessage xmppAxolotlMessage;
try {
xmppAxolotlMessage = XmppAxolotlMessage.fromElement(axolotlMessage, from.asBareJid());
- } catch (Exception e) {
- Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": invalid omemo message received " + e.getMessage());
+ } catch (final Exception e) {
+ Log.d(
+ Config.LOGTAG,
+ conversation.getAccount().getJid().asBareJid()
+ + ": invalid omemo message received "
+ + e.getMessage());
return null;
}
if (xmppAxolotlMessage.hasPayload()) {
final XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage;
try {
- plaintextMessage = service.processReceivingPayloadMessage(xmppAxolotlMessage, postpone);
+ plaintextMessage =
+ service.processReceivingPayloadMessage(xmppAxolotlMessage, postpone);
} catch (BrokenSessionException e) {
if (checkedForDuplicates) {
if (service.trustedOrPreviouslyResponded(from.asBareJid())) {
service.reportBrokenSessionException(e, postpone);
- return new Message(conversation, "", Message.ENCRYPTION_AXOLOTL_FAILED, status);
+ return new Message(
+ conversation, "", Message.ENCRYPTION_AXOLOTL_FAILED, status);
} else {
- Log.d(Config.LOGTAG, "ignoring broken session exception because contact was not trusted");
- return new Message(conversation, "", Message.ENCRYPTION_AXOLOTL_FAILED, status);
+ Log.d(
+ Config.LOGTAG,
+ "ignoring broken session exception because contact was not"
+ + " trusted");
+ return new Message(
+ conversation, "", Message.ENCRYPTION_AXOLOTL_FAILED, status);
}
} else {
- Log.d(Config.LOGTAG, "ignoring broken session exception because checkForDuplicates failed");
+ Log.d(
+ Config.LOGTAG,
+ "ignoring broken session exception because checkForDuplicates failed");
return null;
}
} catch (NotEncryptedForThisDeviceException e) {
- return new Message(conversation, "", Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE, status);
+ return new Message(
+ conversation, "", Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE, status);
} catch (OutdatedSenderException e) {
return new Message(conversation, "", Message.ENCRYPTION_AXOLOTL_FAILED, status);
}
if (plaintextMessage != null) {
- Message finishedMessage = new Message(conversation, plaintextMessage.getPlaintext(), Message.ENCRYPTION_AXOLOTL, status);
+ Message finishedMessage =
+ new Message(
+ conversation,
+ plaintextMessage.getPlaintext(),
+ Message.ENCRYPTION_AXOLOTL,
+ status);
finishedMessage.setFingerprint(plaintextMessage.getFingerprint());
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(finishedMessage.getConversation().getAccount()) + " Received Message with session fingerprint: " + plaintextMessage.getFingerprint());
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.getLogprefix(finishedMessage.getConversation().getAccount())
+ + " Received Message with session fingerprint: "
+ + plaintextMessage.getFingerprint());
return finishedMessage;
}
} else {
- Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": received OMEMO key transport message");
+ Log.d(
+ Config.LOGTAG,
+ conversation.getAccount().getJid().asBareJid()
+ + ": received OMEMO key transport message");
service.processReceivingKeyTransportMessage(xmppAxolotlMessage, postpone);
}
return null;
@@ -203,13 +241,13 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
final Element invite = mucUser.findChild("invite");
if (invite != null) {
final String password = mucUser.findChildContent("password");
- final Jid from = InvalidJid.getNullForInvalid(invite.getAttributeAsJid("from"));
- final Jid to = InvalidJid.getNullForInvalid(invite.getAttributeAsJid("to"));
+ final Jid from = Jid.Invalid.getNullForInvalid(invite.getAttributeAsJid("from"));
+ final Jid to = Jid.Invalid.getNullForInvalid(invite.getAttributeAsJid("to"));
if (to != null && from == null) {
- Log.d(Config.LOGTAG,"do not parse outgoing mediated invite "+message);
+ Log.d(Config.LOGTAG, "do not parse outgoing mediated invite " + message);
return null;
}
- final Jid room = InvalidJid.getNullForInvalid(message.getAttributeAsJid("from"));
+ final Jid room = Jid.Invalid.getNullForInvalid(message.getAttributeAsJid("from"));
if (room == null) {
return null;
}
@@ -218,8 +256,8 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
final Element conference = message.findChild("x", "jabber:x:conference");
if (conference != null) {
- Jid from = InvalidJid.getNullForInvalid(message.getAttributeAsJid("from"));
- Jid room = InvalidJid.getNullForInvalid(conference.getAttributeAsJid("jid"));
+ Jid from = Jid.Invalid.getNullForInvalid(message.getAttributeAsJid("from"));
+ Jid room = Jid.Invalid.getNullForInvalid(conference.getAttributeAsJid("jid"));
if (room == null) {
return null;
}
@@ -246,11 +284,12 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
mXmppConnectionService.updateAccountUi();
} else {
final Contact contact = account.getRoster().getContact(from);
- contact.setAvatar(avatar);
- mXmppConnectionService.syncRoster(account);
- mXmppConnectionService.getAvatarService().clear(contact);
- mXmppConnectionService.updateConversationUi();
- mXmppConnectionService.updateRosterUi(XmppConnectionService.UpdateRosterReason.AVATAR);
+ if (contact.setAvatar(avatar)) {
+ mXmppConnectionService.syncRoster(account);
+ mXmppConnectionService.getAvatarService().clear(contact);
+ mXmppConnectionService.updateConversationUi();
+ mXmppConnectionService.updateRosterUi(XmppConnectionService.UpdateRosterReason.AVATAR);
+ }
}
} else if (mXmppConnectionService.isDataSaverDisabled()) {
mXmppConnectionService.fetchAvatar(account, avatar);
@@ -265,7 +304,14 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
} else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) {
Element item = items.findChild("item");
final Set<Integer> deviceIds = IqParser.deviceIds(item);
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Received PEP device list " + deviceIds + " update from " + from + ", processing... ");
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.getLogprefix(account)
+ + "Received PEP device list "
+ + deviceIds
+ + " update from "
+ + from
+ + ", processing... ");
final AxolotlService axolotlService = account.getAxolotlService();
axolotlService.registerDevices(from, deviceIds);
} else if (Namespace.BOOKMARKS.equals(node) && account.getJid().asBareJid().equals(from)) {
@@ -275,7 +321,8 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
Log.w(
Config.LOGTAG,
account.getJid().asBareJid()
- + ": received storage:bookmark notification even though we opted into bookmarks:1");
+ + ": received storage:bookmark notification even though we"
+ + " opted into bookmarks:1");
}
final Element i = items.findChild("item");
final Element storage =
@@ -289,7 +336,8 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
- + ": ignoring bookmark PEP event because bookmark conversion was not detected");
+ + ": ignoring bookmark PEP event because bookmark conversion was"
+ + " not detected");
}
} else if (Namespace.BOOKMARKS2.equals(node) && account.getJid().asBareJid().equals(from)) {
final Element item = items.findChild("item");
@@ -303,10 +351,12 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
}
if (retract != null) {
- final Jid id = InvalidJid.getNullForInvalid(retract.getAttributeAsJid("id"));
+ final Jid id = Jid.Invalid.getNullForInvalid(retract.getAttributeAsJid("id"));
if (id != null) {
account.removeBookmark(id);
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": deleted bookmark for " + id);
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid() + ": deleted bookmark for " + id);
mXmppConnectionService.processDeletedBookmark(account, id);
mXmppConnectionService.updateConversationUi();
}
@@ -334,8 +384,9 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
} else if (Namespace.BOOKMARKS2.equals(node) && account.getJid().asBareJid().equals(from)) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": deleted bookmarks node");
deleteAllBookmarks(account);
- } else if (Namespace.AVATAR_METADATA.equals(node) && account.getJid().asBareJid().equals(from)) {
- Log.d(Config.LOGTAG,account.getJid().asBareJid()+": deleted avatar metadata node");
+ } else if (Namespace.AVATAR_METADATA.equals(node)
+ && account.getJid().asBareJid().equals(from)) {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": deleted avatar metadata node");
}
}
@@ -372,10 +423,13 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
mXmppConnectionService.updateAccountUi();
}
- private boolean handleErrorMessage(final Account account, final im.conversations.android.xmpp.model.stanza.Message packet) {
+ private boolean handleErrorMessage(
+ final Account account,
+ final im.conversations.android.xmpp.model.stanza.Message packet) {
if (packet.getType() == im.conversations.android.xmpp.model.stanza.Message.Type.ERROR) {
if (packet.fromServer(account)) {
- final var forwarded = getForwardedMessagePacket(packet,"received", Namespace.CARBONS);
+ final var forwarded =
+ getForwardedMessagePacket(packet, "received", Namespace.CARBONS);
if (forwarded != null) {
return handleErrorMessage(account, forwarded.first);
}
@@ -384,29 +438,51 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
final String id = packet.getId();
if (from != null && id != null) {
if (id.startsWith(JingleRtpConnection.JINGLE_MESSAGE_PROPOSE_ID_PREFIX)) {
- final String sessionId = id.substring(JingleRtpConnection.JINGLE_MESSAGE_PROPOSE_ID_PREFIX.length());
- mXmppConnectionService.getJingleConnectionManager()
- .updateProposedSessionDiscovered(account, from, sessionId, JingleConnectionManager.DeviceDiscoveryState.FAILED);
+ final String sessionId =
+ id.substring(
+ JingleRtpConnection.JINGLE_MESSAGE_PROPOSE_ID_PREFIX.length());
+ mXmppConnectionService
+ .getJingleConnectionManager()
+ .updateProposedSessionDiscovered(
+ account,
+ from,
+ sessionId,
+ JingleConnectionManager.DeviceDiscoveryState.FAILED);
return true;
}
if (id.startsWith(JingleRtpConnection.JINGLE_MESSAGE_PROCEED_ID_PREFIX)) {
- final String sessionId = id.substring(JingleRtpConnection.JINGLE_MESSAGE_PROCEED_ID_PREFIX.length());
+ final String sessionId =
+ id.substring(
+ JingleRtpConnection.JINGLE_MESSAGE_PROCEED_ID_PREFIX.length());
final String message = extractErrorMessage(packet);
- mXmppConnectionService.getJingleConnectionManager().failProceed(account, from, sessionId, message);
+ mXmppConnectionService
+ .getJingleConnectionManager()
+ .failProceed(account, from, sessionId, message);
return true;
}
- mXmppConnectionService.markMessage(account,
+ mXmppConnectionService.markMessage(
+ account,
from.asBareJid(),
id,
Message.STATUS_SEND_FAILED,
extractErrorMessage(packet));
final Element error = packet.findChild("error");
- final boolean pingWorthyError = error != null && (error.hasChild("not-acceptable") || error.hasChild("remote-server-timeout") || error.hasChild("remote-server-not-found"));
+ final boolean pingWorthyError =
+ error != null
+ && (error.hasChild("not-acceptable")
+ || error.hasChild("remote-server-timeout")
+ || error.hasChild("remote-server-not-found"));
if (pingWorthyError) {
Conversation conversation = mXmppConnectionService.find(account, from);
- if (conversation != null && conversation.getMode() == Conversational.MODE_MULTI) {
+ if (conversation != null
+ && conversation.getMode() == Conversational.MODE_MULTI) {
if (conversation.getMucOptions().online()) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received ping worthy error for seemingly online muc at " + from);
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": received ping worthy error for seemingly online"
+ + " muc at "
+ + from);
mXmppConnectionService.mucSelfPingAndRejoin(conversation);
}
}
@@ -426,17 +502,24 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
Long timestamp = null;
boolean isCarbon = false;
String serverMsgId = null;
- final Element fin = original.findChild("fin", MessageArchiveService.Version.MAM_0.namespace);
+ final Element fin =
+ original.findChild("fin", MessageArchiveService.Version.MAM_0.namespace);
if (fin != null) {
- mXmppConnectionService.getMessageArchiveService().processFinLegacy(fin, original.getFrom());
+ mXmppConnectionService
+ .getMessageArchiveService()
+ .processFinLegacy(fin, original.getFrom());
return;
}
final Element result = MessageArchiveService.Version.findResult(original);
final String queryId = result == null ? null : result.getAttribute("queryid");
- final MessageArchiveService.Query query = queryId == null ? null : mXmppConnectionService.getMessageArchiveService().findQuery(queryId);
- final boolean offlineMessagesRetrieved = account.getXmppConnection().isOfflineMessagesRetrieved();
+ final MessageArchiveService.Query query =
+ queryId == null
+ ? null
+ : mXmppConnectionService.getMessageArchiveService().findQuery(queryId);
+ final boolean offlineMessagesRetrieved =
+ account.getXmppConnection().isOfflineMessagesRetrieved();
if (query != null && query.validFrom(original.getFrom())) {
- final var f = getForwardedMessagePacket(original,"result", query.version.namespace);
+ final var f = getForwardedMessagePacket(original, "result", query.version.namespace);
if (f == null) {
return;
}
@@ -447,16 +530,24 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
if (handleErrorMessage(account, packet)) {
return;
}
- final var contact = packet.getFrom() == null || packet.getFrom() instanceof InvalidJid ? null : account.getRoster().getContact(packet.getFrom());
+ final var contact = packet.getFrom() == null || packet.getFrom() instanceof Jid.Invalid ? null : account.getRoster().getContact(packet.getFrom());
if (contact != null && contact.isBlocked()) {
Log.d(Config.LOGTAG, "Got MAM result from blocked contact, ignoring...");
return;
}
} else if (query != null) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received mam result with invalid from (" + original.getFrom() + ") or queryId (" + queryId + ")");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": received mam result with invalid from ("
+ + original.getFrom()
+ + ") or queryId ("
+ + queryId
+ + ")");
return;
} else if (original.fromServer(account)
- && original.getType() != im.conversations.android.xmpp.model.stanza.Message.Type.GROUPCHAT) {
+ && original.getType()
+ != im.conversations.android.xmpp.model.stanza.Message.Type.GROUPCHAT) {
Pair<im.conversations.android.xmpp.model.stanza.Message, Long> f;
f = getForwardedMessagePacket(original, Received.class);
f = f == null ? getForwardedMessagePacket(original, Sent.class) : f;
@@ -471,10 +562,14 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
if (timestamp == null) {
- timestamp = AbstractParser.parseTimestamp(original, AbstractParser.parseTimestamp(packet));
+ timestamp =
+ AbstractParser.parseTimestamp(original, AbstractParser.parseTimestamp(packet));
}
+
final Element mucUserElement = packet.findChild("x", Namespace.MUC_USER);
- final boolean isTypeGroupChat = packet.getType() == im.conversations.android.xmpp.model.stanza.Message.Type.GROUPCHAT;
+ final boolean isTypeGroupChat =
+ packet.getType()
+ == im.conversations.android.xmpp.model.stanza.Message.Type.GROUPCHAT;
final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
Element replaceElement = packet.findChild("replace", "urn:xmpp:message-correct:0");
@@ -512,7 +607,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
final var reactions = packet.getExtension(Reactions.class);
- final Element axolotlEncrypted = packet.findChildEnsureSingle(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
+ final var axolotlEncrypted = packet.getOnlyExtension(Encrypted.class);
int status;
final Jid counterpart;
final Jid to = packet.getTo();
@@ -531,12 +626,17 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
html = null;
}
- if (from == null || !InvalidJid.isValid(from) || !InvalidJid.isValid(to)) {
+ if (from == null || !Jid.Invalid.isValid(from) || !Jid.Invalid.isValid(to)) {
Log.e(Config.LOGTAG, "encountered invalid message from='" + from + "' to='" + to + "'");
return;
}
if (query != null && !query.muc() && isTypeGroupChat) {
- Log.e(Config.LOGTAG, account.getJid().asBareJid() + ": received groupchat (" + from + ") message on regular MAM request. skipping");
+ Log.e(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": received groupchat ("
+ + from
+ + ") message on regular MAM request. skipping");
return;
}
final Jid mucTrueCounterPart;
@@ -561,11 +661,25 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
? mucUserElement
: null,
mucTrueCounterPartByPresence);
+ } else if (mucUserElement != null) {
+ final Conversation conversation =
+ mXmppConnectionService.find(account, from.asBareJid());
+ if (conversation != null) {
+ final var mucOptions = conversation.getMucOptions();
+ occupant = mucOptions.occupantId() ? packet.getExtension(OccupantId.class) : null;
+ } else {
+ occupant = null;
+ }
+ mucTrueCounterPart = null;
} else {
mucTrueCounterPart = null;
occupant = null;
}
- boolean isMucStatusMessage = InvalidJid.hasValidFrom(packet) && from.isBareJid() && mucUserElement != null && mucUserElement.hasChild("status");
+ boolean isMucStatusMessage =
+ Jid.Invalid.hasValidFrom(packet)
+ && from.isBareJid()
+ && mucUserElement != null
+ && mucUserElement.hasChild("status");
boolean selfAddressed;
if (packet.fromAccount(account)) {
status = Message.STATUS_SEND;
@@ -584,18 +698,36 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
final Invite invite = extractInvite(packet);
if (invite != null) {
if (invite.jid.asBareJid().equals(account.getJid().asBareJid())) {
- Log.d(Config.LOGTAG,account.getJid().asBareJid()+": ignore invite to "+invite.jid+" because it matches account");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": ignore invite to "
+ + invite.jid
+ + " because it matches account");
} else if (isTypeGroupChat) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring invite to " + invite.jid + " because it was received as group chat");
- } else if (invite.direct && (mucUserElement != null || invite.inviter == null || mXmppConnectionService.isMuc(account, invite.inviter))) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring direct invite to " + invite.jid + " because it was received in MUC");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": ignoring invite to "
+ + invite.jid
+ + " because it was received as group chat");
+ } else if (invite.direct
+ && (mucUserElement != null
+ || invite.inviter == null
+ || mXmppConnectionService.isMuc(account, invite.inviter))) {
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": ignoring direct invite to "
+ + invite.jid
+ + " because it was received in MUC");
} else {
invite.execute(account);
return;
}
}
- final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain().toEscapedString());
+ final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain().toString());
final Element webxdc = packet.findChild("x", "urn:xmpp:webxdc:0");
final Element thread = packet.findChild("thread");
if (webxdc != null && thread != null) {
@@ -643,15 +775,25 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
}
- if (reactions == null && (body != null || pgpEncrypted != null || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload")) || !attachments.isEmpty() || html != null || (packet.hasChild("subject") && packet.hasChild("thread"))) && !isMucStatusMessage) {
- final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), conversationIsProbablyMuc, false, query, false);
+ if (reactions == null && (body != null
+ || pgpEncrypted != null
+ || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload"))
+ || !attachments.isEmpty() || html != null || (packet.hasChild("subject") && packet.hasChild("thread")))
+ && !isMucStatusMessage) {
+ final Conversation conversation =
+ mXmppConnectionService.findOrCreateConversation(
+ account,
+ counterpart.asBareJid(),
+ conversationIsProbablyMuc,
+ false,
+ query,
+ false);
final boolean conversationMultiMode = conversation.getMode() == Conversation.MODE_MULTI;
if (serverMsgId == null) {
serverMsgId = extractStanzaId(packet, isTypeGroupChat, conversation);
}
-
if (selfAddressed) {
// don’t store serverMsgId on reflections for edits
final var reflectedServerMsgId =
@@ -664,7 +806,8 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
return;
}
status = Message.STATUS_RECEIVED;
- if (remoteMsgId != null && conversation.findMessageWithRemoteId(remoteMsgId, counterpart) != null) {
+ if (remoteMsgId != null
+ && conversation.findMessageWithRemoteId(remoteMsgId, counterpart) != null) {
return;
}
}
@@ -672,7 +815,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
if (isTypeGroupChat) {
if (conversation.getMucOptions().isSelf(counterpart)) {
status = Message.STATUS_SEND_RECEIVED;
- isCarbon = true; //not really carbon but received from another resource
+ isCarbon = true; // not really carbon but received from another resource
// don’t store serverMsgId on reflections for edits
final var reflectedServerMsgId =
Strings.isNullOrEmpty(replacementId) ? serverMsgId : null;
@@ -698,17 +841,25 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
Jid origin;
Set<Jid> fallbacksBySourceId = Collections.emptySet();
if (conversationMultiMode) {
- final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);
+ final Jid fallback =
+ conversation.getMucOptions().getTrueCounterpart(counterpart);
origin = getTrueCounterpart(query != null ? mucUserElement : null, fallback);
if (origin == null) {
try {
- fallbacksBySourceId = account.getAxolotlService().findCounterpartsBySourceId(XmppAxolotlMessage.parseSourceId(axolotlEncrypted));
+ fallbacksBySourceId =
+ account.getAxolotlService()
+ .findCounterpartsBySourceId(
+ XmppAxolotlMessage.parseSourceId(
+ axolotlEncrypted));
} catch (IllegalArgumentException e) {
- //ignoring
+ // ignoring
}
}
- if (origin == null && fallbacksBySourceId.size() == 0) {
- Log.d(Config.LOGTAG, "axolotl message in anonymous conference received and no possible fallbacks");
+ if (origin == null && fallbacksBySourceId.isEmpty()) {
+ Log.d(
+ Config.LOGTAG,
+ "axolotl message in anonymous conference received and no possible"
+ + " fallbacks");
return;
}
} else {
@@ -716,17 +867,40 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
origin = from;
}
- final boolean liveMessage = query == null && !isTypeGroupChat && mucUserElement == null;
- final boolean checkedForDuplicates = liveMessage || (serverMsgId != null && remoteMsgId != null && !conversation.possibleDuplicate(serverMsgId, remoteMsgId));
+ final boolean liveMessage =
+ query == null && !isTypeGroupChat && mucUserElement == null;
+ final boolean checkedForDuplicates =
+ liveMessage
+ || (serverMsgId != null
+ && remoteMsgId != null
+ && !conversation.possibleDuplicate(
+ serverMsgId, remoteMsgId));
if (origin != null) {
- message = parseAxolotlChat(axolotlEncrypted, origin, conversation, status, checkedForDuplicates, query != null);
+ message =
+ parseAxolotlChat(
+ axolotlEncrypted,
+ origin,
+ conversation,
+ status,
+ checkedForDuplicates,
+ query != null);
} else {
Message trial = null;
for (Jid fallback : fallbacksBySourceId) {
- trial = parseAxolotlChat(axolotlEncrypted, fallback, conversation, status, checkedForDuplicates && fallbacksBySourceId.size() == 1, query != null);
+ trial =
+ parseAxolotlChat(
+ axolotlEncrypted,
+ fallback,
+ conversation,
+ status,
+ checkedForDuplicates && fallbacksBySourceId.size() == 1,
+ query != null);
if (trial != null) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": decoded muc message using fallback");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": decoded muc message using fallback");
origin = fallback;
break;
}
@@ -734,15 +908,26 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
message = trial;
}
if (message == null) {
- if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) {
+ if (query == null
+ && extractChatState(
+ mXmppConnectionService.find(account, counterpart.asBareJid()),
+ isTypeGroupChat,
+ packet)) {
mXmppConnectionService.updateConversationUi();
}
if (query != null && status == Message.STATUS_SEND && remoteMsgId != null) {
Message previouslySent = conversation.findSentMessageWithUuid(remoteMsgId);
- if (previouslySent != null && previouslySent.getServerMsgId() == null && serverMsgId != null) {
+ if (previouslySent != null
+ && previouslySent.getServerMsgId() == null
+ && serverMsgId != null) {
previouslySent.setServerMsgId(serverMsgId);
- mXmppConnectionService.databaseBackend.updateMessage(previouslySent, false);
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": encountered previously sent OMEMO message without serverId. updating...");
+ mXmppConnectionService.databaseBackend.updateMessage(
+ previouslySent, false);
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": encountered previously sent OMEMO message without"
+ + " serverId. updating...");
}
}
return;
@@ -766,7 +951,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
if (address.getAttribute("type").equals("ofrom") && address.getAttribute("jid") != null) {
Jid ofrom = address.getAttributeAsJid("jid");
- if (InvalidJid.isValid(ofrom) && ofrom.getDomain().equals(counterpart.getDomain()) &&
+ if (Jid.Invalid.isValid(ofrom) && ofrom.getDomain().equals(counterpart.getDomain()) &&
conversation.getAccount().getRoster().getContact(counterpart.getDomain()).getPresences().anySupport("http://jabber.org/protocol/address")) {
message.setTrueCounterpart(ofrom);
@@ -830,7 +1015,10 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
if (trueCounterpart != null && isTypeGroupChat) {
if (trueCounterpart.asBareJid().equals(account.getJid().asBareJid())) {
- status = isTypeGroupChat ? Message.STATUS_SEND_RECEIVED : Message.STATUS_SEND;
+ status =
+ isTypeGroupChat
+ ? Message.STATUS_SEND_RECEIVED
+ : Message.STATUS_SEND;
} else {
status = Message.STATUS_RECEIVED;
message.setCarbon(false);
@@ -846,19 +1034,32 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) {
- final Message replacedMessage = conversation.findMessageWithRemoteIdAndCounterpart(replacementId, counterpart);
+ final Message replacedMessage =
+ conversation.findMessageWithRemoteIdAndCounterpart(
+ replacementId,
+ counterpart);
if (replacedMessage != null) {
- final boolean fingerprintsMatch = replacedMessage.getFingerprint() == null
- || replacedMessage.getFingerprint().equals(message.getFingerprint());
- final boolean trueCountersMatch = replacedMessage.getTrueCounterpart() != null
- && message.getTrueCounterpart() != null
- && replacedMessage.getTrueCounterpart().asBareJid().equals(message.getTrueCounterpart().asBareJid());
+ final boolean fingerprintsMatch =
+ replacedMessage.getFingerprint() == null
+ || replacedMessage
+ .getFingerprint()
+ .equals(message.getFingerprint());
+ final boolean trueCountersMatch =
+ replacedMessage.getTrueCounterpart() != null
+ && message.getTrueCounterpart() != null
+ && replacedMessage
+ .getTrueCounterpart()
+ .asBareJid()
+ .equals(message.getTrueCounterpart().asBareJid());
final boolean occupantIdMatch =
replacedMessage.getOccupantId() != null
&& replacedMessage
.getOccupantId()
.equals(message.getOccupantId());
- final boolean mucUserMatches = query == null && replacedMessage.sameMucUser(message); //can not be checked when using mam
+ final boolean mucUserMatches =
+ query == null
+ && replacedMessage.sameMucUser(
+ message); // can not be checked when using mam
final boolean duplicate = conversation.hasDuplicateMessage(message);
if (fingerprintsMatch && (trueCountersMatch || occupantIdMatch || !conversationMultiMode || mucUserMatches || counterpart.isBareJid()) && !duplicate) {
synchronized (replacedMessage) {
@@ -921,21 +1122,35 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
mXmppConnectionService.updateMessage(replacedMessage, uuid);
if (mXmppConnectionService.confirmMessages()
&& replacedMessage.getStatus() == Message.STATUS_RECEIVED
- && (replacedMessage.trusted() || replacedMessage.isPrivateMessage()) //TODO do we really want to send receipts for all PMs?
+ && (replacedMessage.trusted()
+ || replacedMessage
+ .isPrivateMessage()) // TODO do we really want
+ // to send receipts for all
+ // PMs?
&& remoteMsgId != null
&& !selfAddressed
&& !isTypeGroupChat) {
processMessageReceipts(account, packet, remoteMsgId, query);
}
if (replacedMessage.getEncryption() == Message.ENCRYPTION_PGP) {
- conversation.getAccount().getPgpDecryptionService().discard(replacedMessage);
- conversation.getAccount().getPgpDecryptionService().decrypt(replacedMessage, false);
+ conversation
+ .getAccount()
+ .getPgpDecryptionService()
+ .discard(replacedMessage);
+ conversation
+ .getAccount()
+ .getPgpDecryptionService()
+ .decrypt(replacedMessage, false);
}
}
mXmppConnectionService.getNotificationService().updateNotification();
return;
} else {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received message correction but verification didn't check out");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": received message correction but verification didn't"
+ + " check out");
}
} else if (message.getBody() == null || message.getBody().equals("") || message.getBody().equals(" ")) {
return;
@@ -943,10 +1158,14 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
if (replaceElement != null && !replaceElement.getName().equals("replace")) return;
}
- boolean checkForDuplicates = (isTypeGroupChat && packet.hasChild("delay", "urn:xmpp:delay"))
- || message.isPrivateMessage()
- || message.getServerMsgId() != null
- || (query == null && mXmppConnectionService.getMessageArchiveService().isCatchupInProgress(conversation));
+ boolean checkForDuplicates =
+ (isTypeGroupChat && packet.hasChild("delay", "urn:xmpp:delay"))
+ || message.isPrivateMessage()
+ || message.getServerMsgId() != null
+ || (query == null
+ && mXmppConnectionService
+ .getMessageArchiveService()
+ .isCatchupInProgress(conversation));
if (checkForDuplicates) {
final Message duplicate = conversation.findDuplicateMessage(message);
if (duplicate != null) {
@@ -956,7 +1175,8 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
&& duplicate.getServerMsgId() == null
&& message.getServerMsgId() != null) {
duplicate.setServerMsgId(message.getServerMsgId());
- if (mXmppConnectionService.databaseBackend.updateMessage(duplicate, false)) {
+ if (mXmppConnectionService.databaseBackend.updateMessage(
+ duplicate, false)) {
serverMsgIdUpdated = true;
} else {
serverMsgIdUpdated = false;
@@ -965,12 +1185,18 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
} else {
serverMsgIdUpdated = false;
}
- Log.d(Config.LOGTAG, "skipping duplicate message with " + message.getCounterpart() + ". serverMsgIdUpdated=" + serverMsgIdUpdated);
+ Log.d(
+ Config.LOGTAG,
+ "skipping duplicate message with "
+ + message.getCounterpart()
+ + ". serverMsgIdUpdated="
+ + serverMsgIdUpdated);
return;
}
}
- if (query != null && query.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) {
+ if (query != null
+ && query.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) {
conversation.prepend(query.getActualInThisQuery(), message);
} else {
conversation.add(message);
@@ -979,7 +1205,7 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
query.incrementActualMessageCount();
}
- if (query == null || query.isCatchup()) { //either no mam or catchup
+ if (query == null || query.isCatchup()) { // either no mam or catchup
if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) {
mXmppConnectionService.markRead(conversation);
if (query == null) {
@@ -992,13 +1218,21 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
- notify = conversation.getAccount().getPgpDecryptionService().decrypt(message, notify);
- } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE || message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) {
+ notify =
+ conversation
+ .getAccount()
+ .getPgpDecryptionService()
+ .decrypt(message, notify);
+ } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE
+ || message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) {
notify = false;
}
if (query == null) {
- extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet);
+ extractChatState(
+ mXmppConnectionService.find(account, counterpart.asBareJid()),
+ isTypeGroupChat,
+ packet);
mXmppConnectionService.updateConversationUi();
}
@@ -1023,9 +1257,9 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
mXmppConnectionService.databaseBackend.createMessage(message);
-
- final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
- if (message.getRelativeFilePath() == null && message.trusted() && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
+ final HttpConnectionManager manager =
+ this.mXmppConnectionService.getHttpConnectionManager();
+ if (message.trusted() && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
if (message.getOob() != null && "cid".equalsIgnoreCase(message.getOob().getScheme())) {
try {
BobTransfer transfer = new BobTransfer.ForMessage(message, mXmppConnectionService);
@@ -1044,16 +1278,19 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
mXmppConnectionService.getNotificationService().push(message);
}
}
- } else if (!packet.hasChild("body")) { //no body
-
- final Conversation conversation = mXmppConnectionService.find(account, from.asBareJid());
+ } else if (!packet.hasChild("body")) { // no body
+ final Conversation conversation =
+ mXmppConnectionService.find(account, from.asBareJid());
if (axolotlEncrypted != null) {
Jid origin;
if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) {
- final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);
+ final Jid fallback =
+ conversation.getMucOptions().getTrueCounterpart(counterpart);
origin = getTrueCounterpart(query != null ? mucUserElement : null, fallback);
if (origin == null) {
- Log.d(Config.LOGTAG, "omemo key transport message in anonymous conference received");
+ Log.d(
+ Config.LOGTAG,
+ "omemo key transport message in anonymous conference received");
return;
}
} else if (isTypeGroupChat) {
@@ -1062,25 +1299,43 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
origin = from;
}
try {
- final XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(axolotlEncrypted, origin.asBareJid());
- account.getAxolotlService().processReceivingKeyTransportMessage(xmppAxolotlMessage, query != null);
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": omemo key transport message received from " + origin);
+ final XmppAxolotlMessage xmppAxolotlMessage =
+ XmppAxolotlMessage.fromElement(axolotlEncrypted, origin.asBareJid());
+ account.getAxolotlService()
+ .processReceivingKeyTransportMessage(xmppAxolotlMessage, query != null);
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": omemo key transport message received from "
+ + origin);
} catch (Exception e) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": invalid omemo key transport message received " + e.getMessage());
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": invalid omemo key transport message received "
+ + e.getMessage());
return;
}
}
- if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) {
+ if (query == null
+ && extractChatState(
+ mXmppConnectionService.find(account, counterpart.asBareJid()),
+ isTypeGroupChat,
+ packet)) {
mXmppConnectionService.updateConversationUi();
}
if (isTypeGroupChat) {
- if (packet.hasChild("subject") && !packet.hasChild("thread")) { // We already know it has no body per above
+ if (packet.hasChild("subject")
+ && !packet.hasChild("thread")) { // We already know it has no body per above
if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) {
conversation.setHasMessagesLeftOnServer(conversation.countMessages() > 0);
- final LocalizedContent subject = packet.findInternationalizedChildContentInDefaultNamespace("subject");
- if (subject != null && conversation.getMucOptions().setSubject(subject.content)) {
+ final LocalizedContent subject =
+ packet.findInternationalizedChildContentInDefaultNamespace(
+ "subject");
+ if (subject != null
+ && conversation.getMucOptions().setSubject(subject.content)) {
mXmppConnectionService.updateConversation(conversation);
}
mXmppConnectionService.updateConversationUi();
@@ -1088,7 +1343,10 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
}
}
}
- if (conversation != null && mucUserElement != null && InvalidJid.hasValidFrom(packet) && from.isBareJid()) {
+ if (conversation != null
+ && mucUserElement != null
+ && Jid.Invalid.hasValidFrom(packet)
+ && from.isBareJid()) {
for (Element child : mucUserElement.getChildren()) {
if ("status".equals(child.getName())) {
try {
@@ -1098,16 +1356,27 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
break;
}
} catch (Exception e) {
- //ignored
+ // ignored
}
} 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());
+ final var user = AbstractParser.parseItem(conversation, child);
+ 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);
+ final var mucOptions = conversation.getMucOptions();
+ final boolean isNew = mucOptions.updateUser(user);
+ final var avatarService = mXmppConnectionService.getAvatarService();
+ if (Strings.isNullOrEmpty(mucOptions.getAvatar())) {
+ avatarService.clear(mucOptions);
+ }
+ avatarService.clear(user);
mXmppConnectionService.updateMucRosterUi();
mXmppConnectionService.updateConversationUi();
Contact contact = user.getContact();
@@ -1115,7 +1384,13 @@ public class MessageParser extends AbstractParser implements Consumer<im.convers
Jid jid = user.getRealJid();
List<Jid> cryptoTargets = conversation.getAcceptedCryptoTargets();
if (cryptoTargets.remove(user.getRealJid())) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": removed " + jid + " from crypto targets of " + conversation.getName());
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": removed "
+ + jid
+ + " from crypto targets of "
+ + conversation.getName());
conversation.setAcceptedCryptoTargets(cryptoTargets);
mXmppConnectionService.updateConversation(conversation);
}
@@ -1,7 +1,7 @@
package eu.siacs.conversations.parser;
import android.util.Log;
-
+import com.google.common.base.Strings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -17,48 +17,51 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.pep.Avatar;
import im.conversations.android.xmpp.model.occupant.OccupantId;
-
-import org.openintents.openpgp.util.OpenPgpUtils;
-
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
+import org.openintents.openpgp.util.OpenPgpUtils;
-public class PresenceParser extends AbstractParser implements Consumer<im.conversations.android.xmpp.model.stanza.Presence> {
+public class PresenceParser extends AbstractParser
+ implements Consumer<im.conversations.android.xmpp.model.stanza.Presence> {
public PresenceParser(final XmppConnectionService service, final Account account) {
super(service, account);
}
- public void parseConferencePresence(final im.conversations.android.xmpp.model.stanza.Presence packet, Account account) {
+ public void parseConferencePresence(
+ final im.conversations.android.xmpp.model.stanza.Presence packet, Account account) {
final Conversation conversation =
packet.getFrom() == null
? null
: mXmppConnectionService.find(account, packet.getFrom().asBareJid());
- if (conversation != null) {
- final MucOptions mucOptions = conversation.getMucOptions();
- boolean before = mucOptions.online();
- int count = mucOptions.getUserCount();
- final List<MucOptions.User> tileUserBefore = mucOptions.getUsers(5);
- processConferencePresence(packet, conversation);
- final List<MucOptions.User> tileUserAfter = mucOptions.getUsers(5);
- if (!tileUserAfter.equals(tileUserBefore)) {
- mXmppConnectionService.getAvatarService().clear(mucOptions);
- }
- if (before != mucOptions.online()
- || (mucOptions.online() && count != mucOptions.getUserCount())) {
- mXmppConnectionService.updateConversationUi();
- } else if (mucOptions.online()) {
- mXmppConnectionService.updateMucRosterUi();
- }
+ if (conversation == null) {
+ return;
+ }
+ final MucOptions mucOptions = conversation.getMucOptions();
+ boolean before = mucOptions.online();
+ int count = mucOptions.getUserCount();
+ final List<MucOptions.User> tileUserBefore = mucOptions.getUsers(5);
+ processConferencePresence(packet, conversation);
+ final List<MucOptions.User> tileUserAfter = mucOptions.getUsers(5);
+ if (Strings.isNullOrEmpty(mucOptions.getAvatar())
+ && !tileUserAfter.equals(tileUserBefore)) {
+ mXmppConnectionService.getAvatarService().clear(mucOptions);
+ }
+ if (before != mucOptions.online()
+ || (mucOptions.online() && count != mucOptions.getUserCount())) {
+ mXmppConnectionService.updateConversationUi();
+ } else if (mucOptions.online()) {
+ mXmppConnectionService.updateMucRosterUi();
}
}
- private void processConferencePresence(final im.conversations.android.xmpp.model.stanza.Presence packet, Conversation conversation) {
+ private void processConferencePresence(
+ final im.conversations.android.xmpp.model.stanza.Presence packet,
+ Conversation conversation) {
final Account account = conversation.getAccount();
final MucOptions mucOptions = conversation.getMucOptions();
final Jid jid = conversation.getAccount().getJid();
@@ -82,12 +85,15 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
mucOptions.setError(MucOptions.Error.NONE);
MucOptions.User user = parseItem(conversation, item, from, occupantIdEl, nick == null ? null : nick.getContent(), hats);
final var occupant = packet.getExtension(OccupantId.class);
- final String occupantId = mucOptions.occupantId() && occupant != null ? occupant.getId() : null;
+ final String occupantId =
+ mucOptions.occupantId() && occupant != null
+ ? occupant.getId()
+ : null;
user.setOccupantId(occupantId);
if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE)
|| (codes.contains(MucOptions.STATUS_CODE_ROOM_CREATED)
&& jid.equals(
- InvalidJid.getNullForInvalid(
+ Jid.Invalid.getNullForInvalid(
item.getAttributeAsJid("jid"))))) {
if (mucOptions.setOnline()) {
mXmppConnectionService.getAvatarService().clear(mucOptions);
@@ -97,7 +103,8 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
Log.d(Config.LOGTAG,"role or affiliation changed");
mXmppConnectionService.databaseBackend.updateConversation(conversation);
}
- final var modified = current == null || !current.equals(user.getFullJid());
+ final var modified =
+ current == null || !current.equals(user.getFullJid());
mXmppConnectionService.persistSelfNick(user, modified);
invokeRenameListener(mucOptions, true);
}
@@ -154,9 +161,11 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
.getAccount()
.getRoster()
.getContact(user.getRealJid());
- c.setAvatar(avatar);
- mXmppConnectionService.syncRoster(conversation.getAccount());
- mXmppConnectionService.getAvatarService().clear(c);
+ if (c.setAvatar(avatar)) {
+ mXmppConnectionService.syncRoster(
+ conversation.getAccount());
+ mXmppConnectionService.getAvatarService().clear(c);
+ }
mXmppConnectionService.updateRosterUi(XmppConnectionService.UpdateRosterReason.AVATAR);
}
} else if (mXmppConnectionService.isDataSaverDisabled()) {
@@ -172,7 +181,7 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
final Jid alternate =
destroy == null
? null
- : InvalidJid.getNullForInvalid(
+ : Jid.Invalid.getNullForInvalid(
destroy.getAttributeAsJid("jid"));
mucOptions.setError(MucOptions.Error.DESTROYED);
if (alternate != null) {
@@ -307,7 +316,9 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
return codes;
}
- private void parseContactPresence(final im.conversations.android.xmpp.model.stanza.Presence packet, final Account account) {
+ private void parseContactPresence(
+ final im.conversations.android.xmpp.model.stanza.Presence packet,
+ final Account account) {
final PresenceGenerator mPresenceGenerator = mXmppConnectionService.getPresenceGenerator();
final Jid from = packet.getFrom();
if (from == null || from.equals(account.getJid())) {
@@ -329,11 +340,12 @@ public class PresenceParser extends AbstractParser implements Consumer<im.conver
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
} else {
- contact.setAvatar(avatar);
- mXmppConnectionService.syncRoster(account);
- mXmppConnectionService.getAvatarService().clear(contact);
- mXmppConnectionService.updateConversationUi();
- mXmppConnectionService.updateRosterUi(XmppConnectionService.UpdateRosterReason.AVATAR);
+ if (contact.setAvatar(avatar)) {
+ mXmppConnectionService.syncRoster(account);
+ mXmppConnectionService.getAvatarService().clear(contact);
+ mXmppConnectionService.updateConversationUi();
+ mXmppConnectionService.updateRosterUi(XmppConnectionService.UpdateRosterReason.AVATAR);
+ }
}
} else if (mXmppConnectionService.isDataSaverDisabled()) {
mXmppConnectionService.fetchAvatar(account, avatar);
@@ -69,7 +69,6 @@ import eu.siacs.conversations.utils.CursorUtils;
import eu.siacs.conversations.utils.FtsUtils;
import eu.siacs.conversations.utils.MimeUtils;
import eu.siacs.conversations.utils.Resolver;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.mam.MamReference;
import java.io.ByteArrayInputStream;
@@ -1340,7 +1339,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
cursor.getString(cursor.getColumnIndex(Account.SERVER)),
null)
.getDomain()
- .toEscapedString();
+ .toString();
} catch (IllegalArgumentException ignored) {
Log.e(
Config.LOGTAG,
@@ -1647,7 +1646,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
selectionArgs);
while (cursor.moveToNext()) {
final Conversation conversation = Conversation.fromCursor(cursor);
- if (conversation.getJid() instanceof InvalidJid) {
+ if (conversation.getJid() instanceof Jid.Invalid) {
continue;
}
list.add(conversation);
@@ -2032,7 +2031,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
cursor.moveToFirst();
final Conversation conversation = Conversation.fromCursor(cursor);
- if (conversation.getJid() instanceof InvalidJid) {
+ if (conversation.getJid() instanceof Jid.Invalid) {
return null;
}
return conversation;
@@ -2065,7 +2064,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
cursor.moveToFirst();
final Conversation conversation = Conversation.fromCursor(cursor);
- if (conversation.getJid() instanceof InvalidJid) {
+ if (conversation.getJid() instanceof Jid.Invalid) {
return null;
}
conversation.setAccount(account);
@@ -2073,6 +2072,28 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
}
+ public String findConversationUuid(final Jid account, final Jid jid) {
+ final SQLiteDatabase db = this.getReadableDatabase();
+ final String[] selectionArgs = {
+ account.getLocal(),
+ account.getDomain().toString(),
+ jid.asBareJid().toString() + "/%",
+ jid.asBareJid().toString()
+ };
+ try (final Cursor cursor =
+ db.rawQuery(
+ "SELECT conversations.uuid FROM conversations JOIN accounts ON"
+ + " conversations.accountUuid=accounts.uuid WHERE accounts.username=?"
+ + " AND accounts.server=? AND (contactJid=? OR contactJid LIKE ?)",
+ selectionArgs)) {
+ if (cursor.getCount() == 0) {
+ return null;
+ }
+ cursor.moveToFirst();
+ return cursor.getString(0);
+ }
+ }
+
public void updateConversation(final Conversation conversation) {
final SQLiteDatabase db = this.getWritableDatabase();
final String[] args = {conversation.getUuid()};
@@ -6,19 +6,15 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.services.UnifiedPushBroker;
+import java.util.List;
public class UnifiedPushDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "unified-push-distributor";
@@ -42,7 +38,9 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
@Override
public void onCreate(final SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(
- "CREATE TABLE push (account TEXT, transport TEXT, application TEXT NOT NULL, instance TEXT NOT NULL UNIQUE, endpoint TEXT, expiration NUMBER DEFAULT 0)");
+ "CREATE TABLE push (account TEXT, transport TEXT, application TEXT NOT NULL,"
+ + " instance TEXT NOT NULL UNIQUE, endpoint TEXT, expiration NUMBER DEFAULT"
+ + " 0)");
}
public boolean register(final String application, final String instance) {
@@ -113,7 +111,8 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
sqLiteDatabase.query(
"push",
new String[] {"application", "endpoint"},
- "account = ? AND transport = ? AND instance = ? AND endpoint IS NOT NULL AND expiration >= "
+ "account = ? AND transport = ? AND instance = ? AND endpoint IS NOT NULL"
+ + " AND expiration >= "
+ expiration,
new String[] {account, transport, instance},
null,
@@ -131,17 +130,26 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
public List<PushTarget> deletePushTargets() {
final SQLiteDatabase sqLiteDatabase = getReadableDatabase();
final ImmutableList.Builder<PushTarget> builder = new ImmutableList.Builder<>();
- try (final Cursor cursor = sqLiteDatabase.query("push",new String[]{"application","instance"},null,null,null,null,null)) {
+ try (final Cursor cursor =
+ sqLiteDatabase.query(
+ "push",
+ new String[] {"application", "instance"},
+ null,
+ null,
+ null,
+ null,
+ null)) {
if (cursor != null && cursor.moveToFirst()) {
- builder.add(new PushTarget(
- cursor.getString(cursor.getColumnIndexOrThrow("application")),
- cursor.getString(cursor.getColumnIndexOrThrow("instance"))));
+ builder.add(
+ new PushTarget(
+ cursor.getString(cursor.getColumnIndexOrThrow("application")),
+ cursor.getString(cursor.getColumnIndexOrThrow("instance"))));
}
} catch (final Exception e) {
- Log.d(Config.LOGTAG,"unable to retrieve push targets",e);
+ Log.d(Config.LOGTAG, "unable to retrieve push targets", e);
return builder.build();
}
- sqLiteDatabase.delete("push",null,null);
+ sqLiteDatabase.delete("push", null, null);
return builder.build();
}
@@ -149,9 +157,10 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
final SQLiteDatabase sqLiteDatabase = getReadableDatabase();
try (final Cursor cursor =
sqLiteDatabase.rawQuery(
- "SELECT EXISTS(SELECT endpoint FROM push WHERE account = ? AND transport = ?)",
+ "SELECT EXISTS(SELECT endpoint FROM push WHERE account = ? AND transport ="
+ + " ?)",
new String[] {
- transport.account.getUuid(), transport.transport.toEscapedString()
+ transport.account.getUuid(), transport.transport.toString()
})) {
if (cursor != null && cursor.moveToFirst()) {
return cursor.getInt(0) > 0;
@@ -18,17 +18,10 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LruCache;
-
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
+import com.google.common.base.Strings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -46,6 +39,11 @@ import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
import eu.siacs.conversations.xmpp.XmppConnection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
@@ -99,7 +97,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
if (conversation != null) {
return get(conversation,size,cacheOnly);
}
- return get(CHANNEL_SYMBOL, room != null ? room.asBareJid().toEscapedString() : result.getName(), size, cacheOnly);
+ return get(CHANNEL_SYMBOL, room != null ? room.asBareJid().toString() : result.getName(), size, cacheOnly);
}
private Drawable get(final Contact contact, final int size, boolean cachedOnly) {
@@ -287,7 +285,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
public Drawable get(ListItem item, int size, boolean cachedOnly) {
if (item instanceof RawBlockable) {
- return get(item.getDisplayName(), item.getJid().toEscapedString(), size, cachedOnly);
+ return get(item.getDisplayName(), item.getJid().toString(), size, cachedOnly);
} else if (item instanceof Contact) {
return get((Contact) item, size, cachedOnly);
} else if (item instanceof Bookmark) {
@@ -472,7 +470,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
avatar = mXmppConnectionService.getFileBackend().getAvatar(account.getAvatar(), size);
if (avatar == null) {
final String displayName = account.getDisplayName();
- final String jid = account.getJid().asBareJid().toEscapedString();
+ final String jid = account.getJid().asBareJid().toString();
if (QuickConversationsService.isQuicksy() && !TextUtils.isEmpty(displayName)) {
avatar = get(displayName, jid, size, false);
} else {
@@ -551,7 +549,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
}
public static Drawable get(final Jid jid, final int size) {
- return getImpl(jid.asBareJid().toEscapedString(), null, size);
+ return getImpl(jid.asBareJid().toString(), null, size);
}
private static Drawable getImpl(final String name, final String seed, final int size) {
@@ -460,7 +460,7 @@ public class CallIntegration extends Connection {
}
public static Uri address(final Jid contact) {
- return Uri.parse(String.format("xmpp:%s", contact.toEscapedString()));
+ return Uri.parse(String.format("xmpp:%s", contact.toString()));
}
public void verifyDisconnected() {
@@ -21,14 +21,11 @@ import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.util.Log;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
-
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -41,7 +38,6 @@ import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
import eu.siacs.conversations.xmpp.jingle.Media;
import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
-
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
@@ -93,7 +89,8 @@ public class CallIntegrationConnectionService extends ConnectionService {
if (service == null) {
Log.d(
Config.LOGTAG,
- "CallIntegrationConnection service was unable to bind to XmppConnectionService");
+ "CallIntegrationConnection service was unable to bind to"
+ + " XmppConnectionService");
return Connection.createFailedConnection(
new DisconnectCause(DisconnectCause.ERROR, "service connection not found"));
}
@@ -109,8 +106,8 @@ public class CallIntegrationConnectionService extends ConnectionService {
Log.d(Config.LOGTAG, "create outgoing rtp connection!");
final Intent intent = new Intent(service, RtpSessionActivity.class);
intent.setAction(Intent.ACTION_VIEW);
- intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, account.getJid().toEscapedString());
- intent.putExtra(RtpSessionActivity.EXTRA_WITH, with.toEscapedString());
+ intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, account.getJid().toString());
+ intent.putExtra(RtpSessionActivity.EXTRA_WITH, with.toString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
final Connection callIntegration;
@@ -137,7 +134,8 @@ public class CallIntegrationConnectionService extends ConnectionService {
return Connection.createFailedConnection(
new DisconnectCause(
DisconnectCause.ERROR,
- "Phone is busy. Probably race condition. Try again in a moment"));
+ "Phone is busy. Probably race condition. Try again in a"
+ + " moment"));
}
if (proposal == null) {
// TODO instead of just null checking try to get the sessionID
@@ -189,9 +187,9 @@ public class CallIntegrationConnectionService extends ConnectionService {
}
final Jid jid;
if ("tel".equals(uri.getScheme())) {
- jid = Jid.ofEscaped(extras.getString(EXTRA_ADDRESS));
+ jid = Jid.of(extras.getString(EXTRA_ADDRESS));
} else {
- jid = Jid.ofEscaped(uri.getSchemeSpecificPart());
+ jid = Jid.of(uri.getSchemeSpecificPart());
}
final int videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE);
final Set<Media> media =
@@ -228,7 +226,7 @@ public class CallIntegrationConnectionService extends ConnectionService {
return Connection.createFailedConnection(
new DisconnectCause(DisconnectCause.ERROR, "service connection not found"));
}
- final var jid = Jid.ofEscaped(uri.getSchemeSpecificPart());
+ final var jid = Jid.of(uri.getSchemeSpecificPart());
final Account account = service.findAccountByUuid(phoneAccountHandle.getId());
final var weakReference =
service.getJingleConnectionManager().findJingleRtpConnection(account, jid, sid);
@@ -367,7 +365,7 @@ public class CallIntegrationConnectionService extends ConnectionService {
} else {
// for Android 8 we need to put in a fake tel uri
final var outgoingCallExtras = new Bundle();
- outgoingCallExtras.putString(EXTRA_ADDRESS, with.toEscapedString());
+ outgoingCallExtras.putString(EXTRA_ADDRESS, with.toString());
extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, outgoingCallExtras);
address = Uri.parse("tel:0");
}
@@ -1,14 +1,10 @@
package eu.siacs.conversations.services;
-
import android.util.Log;
-
import androidx.annotation.NonNull;
-
import com.google.common.base.Strings;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Room;
@@ -17,18 +13,7 @@ import eu.siacs.conversations.http.services.MuclumbusService;
import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
-
import im.conversations.android.xmpp.model.stanza.Iq;
-
-import okhttp3.OkHttpClient;
-import okhttp3.ResponseBody;
-
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-import retrofit2.Retrofit;
-import retrofit2.converter.gson.GsonConverterFactory;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -38,6 +23,13 @@ import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import okhttp3.OkHttpClient;
+import okhttp3.ResponseBody;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
public class ChannelDiscoveryService {
@@ -57,7 +49,8 @@ public class ChannelDiscoveryService {
this.muclumbusService = null;
return;
}
- final OkHttpClient.Builder builder = HttpConnectionManager.okHttpClient(service).newBuilder();
+ final OkHttpClient.Builder builder =
+ HttpConnectionManager.okHttpClient(service).newBuilder();
if (service.useTorToConnect()) {
builder.proxy(HttpConnectionManager.getProxy());
}
@@ -207,10 +200,8 @@ public class ChannelDiscoveryService {
account,
infoRequest,
infoResponse -> {
- if (infoResponse.getType()
- == Iq.Type.RESULT) {
- final Room room =
- IqParser.parseRoom(infoResponse);
+ if (infoResponse.getType() == Iq.Type.RESULT) {
+ final Room room = IqParser.parseRoom(infoResponse);
if (room != null) {
rooms.add(room);
}
@@ -262,7 +253,7 @@ public class ChannelDiscoveryService {
continue;
}
for (final String mucService : xmppConnection.getMucServers()) {
- Jid jid = Jid.ofEscaped(mucService);
+ final Jid jid = Jid.of(mucService);
if (!localMucServices.containsKey(jid)) {
localMucServices.put(jid, account);
}
@@ -639,9 +639,8 @@ public class NotificationService {
final Intent fullScreenIntent =
new Intent(mXmppConnectionService, RtpSessionActivity.class);
fullScreenIntent.putExtra(
- RtpSessionActivity.EXTRA_ACCOUNT,
- id.account.getJid().asBareJid().toEscapedString());
- fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
+ RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toString());
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toString());
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -797,9 +796,8 @@ public class NotificationService {
new Intent(mXmppConnectionService, RtpSessionActivity.class);
fullScreenIntent.setAction(action);
fullScreenIntent.putExtra(
- RtpSessionActivity.EXTRA_ACCOUNT,
- id.account.getJid().asBareJid().toEscapedString());
- fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
+ RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().asBareJid().toString());
+ fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toString());
fullScreenIntent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
return PendingIntent.getActivity(
mXmppConnectionService,
@@ -2081,7 +2079,7 @@ public class NotificationService {
} else if (errors.size() == 1) {
mBuilder.setContentTitle(
mXmppConnectionService.getString(R.string.problem_connecting_to_account));
- mBuilder.setContentText(errors.get(0).getJid().asBareJid().toEscapedString());
+ mBuilder.setContentText(errors.get(0).getJid().asBareJid().toString());
} else {
mBuilder.setContentTitle(
mXmppConnectionService.getString(R.string.problem_connecting_to_accounts));
@@ -2140,7 +2138,7 @@ public class NotificationService {
intent = new Intent(mXmppConnectionService, AccountUtils.MANAGE_ACCOUNT_ACTIVITY);
} else {
intent = new Intent(mXmppConnectionService, EditAccountActivity.class);
- intent.putExtra("jid", errors.get(0).getJid().asBareJid().toEscapedString());
+ intent.putExtra("jid", errors.get(0).getJid().asBareJid().toString());
intent.putExtra(EditAccountActivity.EXTRA_OPENED_FROM_NOTIFICATION, true);
}
mBuilder.setContentIntent(
@@ -14,10 +14,12 @@ import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -32,11 +34,11 @@ import eu.siacs.conversations.ui.StartConversationActivity;
import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
import eu.siacs.conversations.xmpp.Jid;
-import java.util.Collection;
-import java.util.List;
public class ShortcutService {
+ public static final char ID_SEPARATOR = '#';
+
private final XmppConnectionService xmppConnectionService;
private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor =
new ReplacingSerialSingleThreadExecutor(ShortcutService.class.getSimpleName());
@@ -167,17 +169,17 @@ public class ShortcutService {
}
private static String getShortcutId(final Contact contact) {
- return contact.getAccount().getJid().asBareJid().toEscapedString()
- + "#"
- + contact.getJid().asBareJid().toEscapedString();
+ return Joiner.on(ID_SEPARATOR)
+ .join(
+ contact.getAccount().getJid().asBareJid().toString(),
+ contact.getJid().asBareJid().toString());
}
private static String getShortcutId(final MucOptions mucOptions) {
final Account account = mucOptions.getAccount();
final Jid jid = mucOptions.getConversation().getJid();
- return account.getJid().asBareJid().toEscapedString()
- + "#"
- + jid.asBareJid().toEscapedString();
+ return Joiner.on(ID_SEPARATOR)
+ .join(account.getJid().asBareJid().toString(), jid.asBareJid().toString());
}
private Intent getShortcutIntent(final MucOptions mucOptions) {
@@ -187,17 +189,12 @@ public class ShortcutService {
Uri.parse(
String.format(
"xmpp:%s?join",
- mucOptions
- .getConversation()
- .getJid()
- .asBareJid()
- .toEscapedString())));
+ mucOptions.getConversation().getJid().asBareJid().toString())));
}
private Intent getShortcutIntent(final Contact contact) {
return getShortcutIntent(
- contact.getAccount(),
- Uri.parse("xmpp:" + contact.getJid().asBareJid().toEscapedString()));
+ contact.getAccount(), Uri.parse("xmpp:" + contact.getJid().asBareJid().toString()));
}
private Intent getShortcutIntent(final Account account, final Uri uri) {
@@ -10,10 +10,8 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
@@ -22,7 +20,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -34,7 +31,6 @@ import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.stanza.Iq;
import im.conversations.android.xmpp.model.stanza.Presence;
-
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.List;
@@ -92,7 +88,8 @@ public class UnifiedPushBroker {
renewUnifiedPushEndpoints(null);
}
- public Optional<Transport> renewUnifiedPushEndpoints(@Nullable final PushTargetMessenger pushTargetMessenger) {
+ public Optional<Transport> renewUnifiedPushEndpoints(
+ @Nullable final PushTargetMessenger pushTargetMessenger) {
final Optional<Transport> transportOptional = getTransport();
if (transportOptional.isPresent()) {
final Transport transport = transportOptional.get();
@@ -100,13 +97,13 @@ public class UnifiedPushBroker {
renewUnifiedEndpoint(transportOptional.get(), pushTargetMessenger);
} else {
if (pushTargetMessenger != null && pushTargetMessenger.messenger != null) {
- sendRegistrationDelayed(pushTargetMessenger.messenger,"account is disabled");
+ sendRegistrationDelayed(pushTargetMessenger.messenger, "account is disabled");
}
Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. Account is disabled");
}
} else {
if (pushTargetMessenger != null && pushTargetMessenger.messenger != null) {
- sendRegistrationDelayed(pushTargetMessenger.messenger,"no transport selected");
+ sendRegistrationDelayed(pushTargetMessenger.messenger, "no transport selected");
}
Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. No transport selected");
}
@@ -121,16 +118,16 @@ public class UnifiedPushBroker {
try {
messenger.send(message);
} catch (final RemoteException e) {
- Log.d(Config.LOGTAG,"unable to tell messenger of delayed registration",e);
+ Log.d(Config.LOGTAG, "unable to tell messenger of delayed registration", e);
}
}
- private void renewUnifiedEndpoint(final Transport transport, final PushTargetMessenger pushTargetMessenger) {
+ private void renewUnifiedEndpoint(
+ final Transport transport, final PushTargetMessenger pushTargetMessenger) {
final Account account = transport.account;
final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service);
final List<UnifiedPushDatabase.PushTarget> renewals =
- unifiedPushDatabase.getRenewals(
- account.getUuid(), transport.transport.toEscapedString());
+ unifiedPushDatabase.getRenewals(account.getUuid(), transport.transport.toString());
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
@@ -142,7 +139,11 @@ public class UnifiedPushBroker {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": try to renew UnifiedPush " + renewal);
- UnifiedPushDistributor.quickLog(service,String.format("%s: try to renew UnifiedPush %s", account.getJid(), renewal.toString()));
+ UnifiedPushDistributor.quickLog(
+ service,
+ String.format(
+ "%s: try to renew UnifiedPush %s",
+ account.getJid(), renewal.toString()));
final String hashedApplication =
UnifiedPushDistributor.hash(account.getUuid(), renewal.application);
final String hashedInstance =
@@ -205,7 +206,7 @@ public class UnifiedPushBroker {
unifiedPushDatabase.updateEndpoint(
renewal.instance,
transport.account.getUuid(),
- transport.transport.toEscapedString(),
+ transport.transport.toString(),
endpoint,
expiration);
if (modified) {
@@ -231,15 +232,21 @@ public class UnifiedPushBroker {
}
}
- private void sendEndpoint(final Messenger messenger, String instance, final UnifiedPushDatabase.ApplicationEndpoint applicationEndpoint) {
+ private void sendEndpoint(
+ final Messenger messenger,
+ String instance,
+ final UnifiedPushDatabase.ApplicationEndpoint applicationEndpoint) {
if (messenger != null) {
- Log.d(Config.LOGTAG,"using messenger instead of broadcast to communicate endpoint to "+applicationEndpoint.application);
+ Log.d(
+ Config.LOGTAG,
+ "using messenger instead of broadcast to communicate endpoint to "
+ + applicationEndpoint.application);
final Message message = new Message();
message.obj = endpointIntent(instance, applicationEndpoint);
try {
messenger.send(message);
} catch (final RemoteException e) {
- Log.d(Config.LOGTAG,"messenger failed. falling back to broadcast");
+ Log.d(Config.LOGTAG, "messenger failed. falling back to broadcast");
broadcastEndpoint(instance, applicationEndpoint);
}
} else {
@@ -281,8 +288,7 @@ public class UnifiedPushBroker {
future,
new FutureCallback<>() {
@Override
- public void onSuccess(
- final List<UnifiedPushDatabase.PushTarget> pushTargets) {
+ public void onSuccess(final List<UnifiedPushDatabase.PushTarget> pushTargets) {
broadcastUnregistered(pushTargets);
}
@@ -290,19 +296,21 @@ public class UnifiedPushBroker {
public void onFailure(@NonNull Throwable throwable) {
Log.d(
Config.LOGTAG,
- "could not delete endpoints after UnifiedPushDistributor was disabled");
+ "could not delete endpoints after UnifiedPushDistributor was"
+ + " disabled");
}
},
MoreExecutors.directExecutor());
}
private ListenableFuture<List<UnifiedPushDatabase.PushTarget>> deletePushTargets() {
- return Futures.submit(() -> UnifiedPushDatabase.getInstance(service).deletePushTargets(),SCHEDULER);
+ return Futures.submit(
+ () -> UnifiedPushDatabase.getInstance(service).deletePushTargets(), SCHEDULER);
}
private void broadcastUnregistered(final List<UnifiedPushDatabase.PushTarget> pushTargets) {
- for(final UnifiedPushDatabase.PushTarget pushTarget : pushTargets) {
- Log.d(Config.LOGTAG,"sending unregistered to "+pushTarget);
+ for (final UnifiedPushDatabase.PushTarget pushTarget : pushTargets) {
+ Log.d(Config.LOGTAG, "sending unregistered to " + pushTarget);
broadcastUnregistered(pushTarget);
}
}
@@ -368,8 +376,8 @@ public class UnifiedPushBroker {
final Jid transport;
final Jid jid;
try {
- transport = Jid.ofEscaped(Strings.nullToEmpty(pushServerPreference).trim());
- jid = Jid.ofEscaped(Strings.nullToEmpty(accountPreference).trim());
+ transport = Jid.of(Strings.nullToEmpty(pushServerPreference).trim());
+ jid = Jid.of(Strings.nullToEmpty(accountPreference).trim());
} catch (final IllegalArgumentException e) {
return Optional.absent();
}
@@ -390,8 +398,7 @@ public class UnifiedPushBroker {
}
final String uuid = account.getUuid();
final List<UnifiedPushDatabase.PushTarget> pushTargets =
- UnifiedPushDatabase.getInstance(service)
- .getPushTargets(uuid, transport.toEscapedString());
+ UnifiedPushDatabase.getInstance(service).getPushTargets(uuid, transport.toString());
return Iterables.tryFind(
pushTargets,
pt ->
@@ -422,7 +429,8 @@ public class UnifiedPushBroker {
service.sendBroadcast(updateIntent);
}
- private Intent endpointIntent(final String instance, final UnifiedPushDatabase.ApplicationEndpoint endpoint) {
+ private Intent endpointIntent(
+ final String instance, final UnifiedPushDatabase.ApplicationEndpoint endpoint) {
final Intent intent = new Intent(UnifiedPushDistributor.ACTION_NEW_ENDPOINT);
intent.setPackage(endpoint.application);
intent.putExtra("token", instance);
@@ -449,13 +457,12 @@ public class UnifiedPushBroker {
return intent;
}
- public void rebroadcastEndpoint(final Messenger messenger, final String instance, final Transport transport) {
+ public void rebroadcastEndpoint(
+ final Messenger messenger, final String instance, final Transport transport) {
final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service);
final UnifiedPushDatabase.ApplicationEndpoint endpoint =
unifiedPushDatabase.getEndpoint(
- transport.account.getUuid(),
- transport.transport.toEscapedString(),
- instance);
+ transport.account.getUuid(), transport.transport.toString(), instance);
if (endpoint != null) {
sendEndpoint(messenger, instance, endpoint);
}
@@ -184,7 +184,6 @@ import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.LocalizedContent;
import eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnGatewayResult;
@@ -2554,7 +2553,7 @@ public class XmppConnectionService extends Service {
if (uri != null) {
final EasyOnboardingInvite invite =
new EasyOnboardingInvite(
- jid.getDomain().toEscapedString(), uri, landingUrl);
+ jid.getDomain().toString(), uri, landingUrl);
callback.inviteRequested(invite);
return;
}
@@ -2630,7 +2629,7 @@ public class XmppConnectionService extends Service {
public void processMdsItem(final Account account, final Element item) {
final Jid jid =
- item == null ? null : InvalidJid.getNullForInvalid(item.getAttributeAsJid("id"));
+ item == null ? null : Jid.Invalid.getNullForInvalid(item.getAttributeAsJid("id"));
if (jid == null) {
return;
}
@@ -2791,7 +2790,7 @@ public class XmppConnectionService extends Service {
account,
Namespace.BOOKMARKS2,
item,
- bookmark.getJid().asBareJid().toEscapedString(),
+ bookmark.getJid().asBareJid().toString(),
PublishOptions.persistentWhitelistAccessMaxItems());
} else if (connection.getFeatures().bookmarksConversion()) {
pushBookmarksPep(account);
@@ -2811,7 +2810,7 @@ public class XmppConnectionService extends Service {
if (connection.getFeatures().bookmarks2()) {
final Iq request =
mIqGenerator.deleteItem(
- Namespace.BOOKMARKS2, bookmark.getJid().asBareJid().toEscapedString());
+ Namespace.BOOKMARKS2, bookmark.getJid().asBareJid().toString());
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": removing bookmark via Bookmarks 2");
@@ -3577,10 +3576,10 @@ public class XmppConnectionService extends Service {
}
private void provisionAccount(final String address, final String password) {
- final Jid jid = Jid.ofEscaped(address);
+ final Jid jid = Jid.of(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().toString() + ": provisioning account");
createAccount(account);
}
@@ -4018,15 +4017,15 @@ public class XmppConnectionService extends Service {
}
public boolean checkListeners() {
- return (this.mOnAccountUpdates.size() == 0
- && this.mOnConversationUpdates.size() == 0
- && this.mOnRosterUpdates.size() == 0
- && this.mOnCaptchaRequested.size() == 0
- && this.mOnMucRosterUpdate.size() == 0
- && this.mOnUpdateBlocklist.size() == 0
- && this.mOnShowErrorToasts.size() == 0
- && this.onJingleRtpConnectionUpdate.size() == 0
- && this.mOnKeyStatusUpdated.size() == 0);
+ return (this.mOnAccountUpdates.isEmpty()
+ && this.mOnConversationUpdates.isEmpty()
+ && this.mOnRosterUpdates.isEmpty()
+ && this.mOnCaptchaRequested.isEmpty()
+ && this.mOnMucRosterUpdate.isEmpty()
+ && this.mOnUpdateBlocklist.isEmpty()
+ && this.mOnShowErrorToasts.isEmpty()
+ && this.onJingleRtpConnectionUpdate.isEmpty()
+ && this.mOnKeyStatusUpdated.isEmpty());
}
private void switchToForeground() {
@@ -4383,7 +4382,8 @@ public class XmppConnectionService extends Service {
}
++i;
if (i >= affiliations.size()) {
- List<Jid> members = conversation.getMucOptions().getMembers(true);
+ final var mucOptions = conversation.getMucOptions();
+ List<Jid> members = mucOptions.getMembers(true);
if (success) {
List<Jid> cryptoTargets = conversation.getAcceptedCryptoTargets();
boolean changed = false;
@@ -4408,7 +4408,7 @@ public class XmppConnectionService extends Service {
updateConversation(conversation);
}
}
- getAvatarService().clear(conversation);
+ getAvatarService().clear(mucOptions);
updateMucRosterUi();
updateConversationUi();
}
@@ -5093,8 +5093,9 @@ public class XmppConnectionService extends Service {
request,
(response) -> {
if (response.getType() == Iq.Type.RESULT) {
- conference.getMucOptions().changeAffiliation(jid, affiliation);
- getAvatarService().clear(conference);
+ final var mucOptions = conference.getMucOptions();
+ mucOptions.changeAffiliation(jid, affiliation);
+ getAvatarService().clear(mucOptions);
if (callback != null) {
callback.onAffiliationChangedSuccessful(jid);
} else {
@@ -6373,7 +6374,7 @@ public class XmppConnectionService extends Service {
account,
Namespace.MDS_DISPLAYED,
item,
- itemId.toEscapedString(),
+ itemId.toString(),
PublishOptions.persistentWhitelistAccessMaxItems());
}
@@ -6526,7 +6527,7 @@ public class XmppConnectionService extends Service {
if (Config.QUICKSY_DOMAIN != null) {
hosts.remove(
Config.QUICKSY_DOMAIN
- .toEscapedString()); // we only want to show this when we type a e164
+ .toString()); // we only want to show this when we type a e164
// number
}
if (Config.MAGIC_CREATE_DOMAIN != null) {
@@ -6543,7 +6544,7 @@ public class XmppConnectionService extends Service {
mucServers.addAll(account.getXmppConnection().getMucServers());
for (final Bookmark bookmark : account.getBookmarks()) {
final Jid jid = bookmark.getJid();
- final String s = jid == null ? null : jid.getDomain().toEscapedString();
+ final String s = jid == null ? null : jid.getDomain().toString();
if (s != null) {
mucServers.add(s);
}
@@ -2,13 +2,9 @@ package eu.siacs.conversations.ui;
import android.view.View;
import android.widget.Toast;
-
import androidx.annotation.StringRes;
-import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.DialogBlockContactBinding;
import eu.siacs.conversations.entities.Blockable;
@@ -17,43 +13,56 @@ import eu.siacs.conversations.ui.util.JidDialog;
public final class BlockContactDialog {
- public static void show(final XmppActivity xmppActivity, final Blockable blockable) {
- show(xmppActivity, blockable, null);
- }
- public static void show(final XmppActivity xmppActivity, final Blockable blockable, final String serverMsgId) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(xmppActivity);
- final boolean isBlocked = blockable.isBlocked();
- builder.setNegativeButton(R.string.cancel, null);
- DialogBlockContactBinding binding = DataBindingUtil.inflate(xmppActivity.getLayoutInflater(), R.layout.dialog_block_contact, null, false);
- final boolean reporting = blockable.getAccount().getXmppConnection().getFeatures().spamReporting();
- if (reporting && !isBlocked) {
- binding.reportSpam.setVisibility(View.VISIBLE);
- if (serverMsgId != null) {
- binding.reportSpam.setChecked(true);
- binding.reportSpam.setEnabled(false);
- } else {
- binding.reportSpam.setEnabled(true);
- }
- } else {
- binding.reportSpam.setVisibility(View.GONE);
- }
- builder.setView(binding.getRoot());
+ public static void show(final XmppActivity xmppActivity, final Blockable blockable) {
+ show(xmppActivity, blockable, null);
+ }
- final String value;
- @StringRes int res;
- if (blockable.getJid().isFullJid()) {
- builder.setTitle(isBlocked ? R.string.action_unblock_participant : R.string.action_block_participant);
- value = blockable.getJid().toEscapedString();
- res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text;
- } else if (blockable.getJid().getLocal() == null || blockable.getAccount().isBlocked(blockable.getJid().getDomain())) {
- builder.setTitle(isBlocked ? R.string.action_unblock_domain : R.string.action_block_domain);
- value =blockable.getJid().getDomain().toEscapedString();
- res = isBlocked ? R.string.unblock_domain_text : R.string.block_domain_text;
- } else {
- if (isBlocked) {
- builder.setTitle(R.string.action_unblock_contact);
- } else if (serverMsgId != null) {
- builder.setTitle(R.string.report_spam_and_block);
+ public static void show(
+ final XmppActivity xmppActivity, final Blockable blockable, final String serverMsgId) {
+ final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(xmppActivity);
+ final boolean isBlocked = blockable.isBlocked();
+ builder.setNegativeButton(R.string.cancel, null);
+ DialogBlockContactBinding binding =
+ DataBindingUtil.inflate(
+ xmppActivity.getLayoutInflater(),
+ R.layout.dialog_block_contact,
+ null,
+ false);
+ final boolean reporting =
+ blockable.getAccount().getXmppConnection().getFeatures().spamReporting();
+ if (reporting && !isBlocked) {
+ binding.reportSpam.setVisibility(View.VISIBLE);
+ if (serverMsgId != null) {
+ binding.reportSpam.setChecked(true);
+ binding.reportSpam.setEnabled(false);
+ } else {
+ binding.reportSpam.setEnabled(true);
+ }
+ } else {
+ binding.reportSpam.setVisibility(View.GONE);
+ }
+ builder.setView(binding.getRoot());
+
+ final String value;
+ @StringRes int res;
+ if (blockable.getJid().isFullJid()) {
+ builder.setTitle(
+ isBlocked
+ ? R.string.action_unblock_participant
+ : R.string.action_block_participant);
+ value = blockable.getJid().toString();
+ res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text;
+ } else if (blockable.getJid().getLocal() == null
+ || blockable.getAccount().isBlocked(blockable.getJid().getDomain())) {
+ builder.setTitle(
+ isBlocked ? R.string.action_unblock_domain : R.string.action_block_domain);
+ value = blockable.getJid().getDomain().toString();
+ res = isBlocked ? R.string.unblock_domain_text : R.string.block_domain_text;
+ } else {
+ if (isBlocked) {
+ builder.setTitle(R.string.action_unblock_contact);
+ } else if (serverMsgId != null) {
+ builder.setTitle(R.string.report_spam_and_block);
} else {
final int resBlockAction =
blockable instanceof Conversation
@@ -61,34 +70,44 @@ public final class BlockContactDialog {
? R.string.block_stranger
: R.string.action_block_contact;
builder.setTitle(resBlockAction);
- }
- value = blockable.getJid().asBareJid().toEscapedString();
- res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text;
- }
- binding.text.setText(JidDialog.style(xmppActivity, res, value));
- builder.setPositiveButton(isBlocked ? R.string.unblock : R.string.block, (dialog, which) -> {
- if (isBlocked) {
- xmppActivity.xmppConnectionService.sendUnblockRequest(blockable);
- } else {
- boolean toastShown = false;
- var finalServerId = serverMsgId;
- if (serverMsgId == null && binding.reportSpam.isChecked() && blockable instanceof Conversation) {
- final var lastM = ((Conversation) blockable).getLatestMessage();
- if (lastM != null) finalServerId = lastM.getServerMsgId();
- }
-
- if (xmppActivity.xmppConnectionService.sendBlockRequest(blockable, binding.reportSpam.isChecked(), finalServerId)) {
- Toast.makeText(xmppActivity, R.string.corresponding_chats_closed, Toast.LENGTH_SHORT).show();
- toastShown = true;
- }
- if (xmppActivity instanceof ContactDetailsActivity) {
- if (!toastShown) {
- Toast.makeText(xmppActivity, R.string.contact_blocked_past_tense, Toast.LENGTH_SHORT).show();
- }
- xmppActivity.finish();
- }
- }
- });
- builder.create().show();
- }
+ }
+ value = blockable.getJid().asBareJid().toString();
+ res = isBlocked ? R.string.unblock_contact_text : R.string.block_contact_text;
+ }
+ binding.text.setText(JidDialog.style(xmppActivity, res, value));
+ builder.setPositiveButton(
+ isBlocked ? R.string.unblock : R.string.block,
+ (dialog, which) -> {
+ if (isBlocked) {
+ xmppActivity.xmppConnectionService.sendUnblockRequest(blockable);
+ } else {
+ boolean toastShown = false;
+ var finalServerId = serverMsgId;
+ if (serverMsgId == null && binding.reportSpam.isChecked() && blockable instanceof Conversation) {
+ final var lastM = ((Conversation) blockable).getLatestMessage();
+ if (lastM != null) finalServerId = lastM.getServerMsgId();
+ }
+ if (xmppActivity.xmppConnectionService.sendBlockRequest(
+ blockable, binding.reportSpam.isChecked(), finalServerId)) {
+ Toast.makeText(
+ xmppActivity,
+ R.string.corresponding_chats_closed,
+ Toast.LENGTH_SHORT)
+ .show();
+ toastShown = true;
+ }
+ if (xmppActivity instanceof ContactDetailsActivity) {
+ if (!toastShown) {
+ Toast.makeText(
+ xmppActivity,
+ R.string.contact_blocked_past_tense,
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ xmppActivity.finish();
+ }
+ }
+ });
+ builder.create().show();
+ }
}
@@ -3,12 +3,8 @@ package eu.siacs.conversations.ui;
import android.os.Bundle;
import android.text.Editable;
import android.widget.Toast;
-
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
-
-import java.util.Collections;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
@@ -17,99 +13,109 @@ import eu.siacs.conversations.entities.RawBlockable;
import eu.siacs.conversations.ui.interfaces.OnBackendConnected;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import java.util.Collections;
-public class BlocklistActivity extends AbstractSearchableListItemActivity implements OnUpdateBlocklist {
-
- private Account account = null;
+public class BlocklistActivity extends AbstractSearchableListItemActivity
+ implements OnUpdateBlocklist {
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getListView().setOnItemLongClickListener((parent, view, position, id) -> {
- BlockContactDialog.show(BlocklistActivity.this, (Blockable) getListItems().get(position));
- return true;
- });
- this.binding.fab.show();
- this.binding.fab.setOnClickListener((v)->showEnterJidDialog());
- }
+ private Account account = null;
- @Override
- public void onBackendConnected() {
- for (final Account account : xmppConnectionService.getAccounts()) {
- if (account.getJid().toEscapedString().equals(getIntent().getStringExtra(EXTRA_ACCOUNT))) {
- this.account = account;
- break;
- }
- }
- filterContacts();
- Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DIALOG);
- if (fragment instanceof OnBackendConnected) {
- ((OnBackendConnected) fragment).onBackendConnected();
- }
- }
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getListView()
+ .setOnItemLongClickListener(
+ (parent, view, position, id) -> {
+ BlockContactDialog.show(
+ BlocklistActivity.this,
+ (Blockable) getListItems().get(position));
+ return true;
+ });
+ this.binding.fab.show();
+ this.binding.fab.setOnClickListener((v) -> showEnterJidDialog());
+ }
- @Override
- protected void filterContacts(final String needle) {
- getListItems().clear();
- if (account != null) {
- for (final Jid jid : account.getBlocklist()) {
- ListItem item;
- if (jid.isFullJid()) {
- item = new RawBlockable(account, jid);
- } else {
- item = account.getRoster().getContact(jid);
- }
- if (item.match(this, needle)) {
- getListItems().add(item);
- }
- }
- Collections.sort(getListItems());
- }
- getListItemAdapter().notifyDataSetChanged();
- }
+ @Override
+ public void onBackendConnected() {
+ for (final Account account : xmppConnectionService.getAccounts()) {
+ if (account.getJid().toString().equals(getIntent().getStringExtra(EXTRA_ACCOUNT))) {
+ this.account = account;
+ break;
+ }
+ }
+ filterContacts();
+ Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DIALOG);
+ if (fragment instanceof OnBackendConnected) {
+ ((OnBackendConnected) fragment).onBackendConnected();
+ }
+ }
- protected void showEnterJidDialog() {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
- if (prev != null) {
- ft.remove(prev);
- }
- ft.addToBackStack(null);
- EnterJidDialog dialog = EnterJidDialog.newInstance(
- null,
- getString(R.string.block_jabber_id),
- getString(R.string.block),
- null,
- null,
- account.getJid().asBareJid().toEscapedString(),
- true,
- false,
- EnterJidDialog.SanityCheck.NO
- );
+ @Override
+ protected void filterContacts(final String needle) {
+ getListItems().clear();
+ if (account != null) {
+ for (final Jid jid : account.getBlocklist()) {
+ ListItem item;
+ if (jid.isFullJid()) {
+ item = new RawBlockable(account, jid);
+ } else {
+ item = account.getRoster().getContact(jid);
+ }
+ if (item.match(this, needle)) {
+ getListItems().add(item);
+ }
+ }
+ Collections.sort(getListItems());
+ }
+ getListItemAdapter().notifyDataSetChanged();
+ }
- dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid, x, y) -> {
- Blockable blockable = new RawBlockable(account, contactJid);
- if (xmppConnectionService.sendBlockRequest(blockable, false, null)) {
- Toast.makeText(BlocklistActivity.this, R.string.corresponding_chats_closed, Toast.LENGTH_SHORT).show();
- }
- return true;
- });
+ protected void showEnterJidDialog() {
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
+ if (prev != null) {
+ ft.remove(prev);
+ }
+ ft.addToBackStack(null);
+ EnterJidDialog dialog =
+ EnterJidDialog.newInstance(
+ null,
+ getString(R.string.block_jabber_id),
+ getString(R.string.block),
+ null,
+ null,
+ account.getJid().asBareJid().toString(),
+ true,
+ false,
+ EnterJidDialog.SanityCheck.NO);
- dialog.show(ft, "dialog");
- }
+ dialog.setOnEnterJidDialogPositiveListener(
+ (accountJid, contactJid, x, y) -> {
+ Blockable blockable = new RawBlockable(account, contactJid);
+ if (xmppConnectionService.sendBlockRequest(blockable, false, null)) {
+ Toast.makeText(
+ BlocklistActivity.this,
+ R.string.corresponding_chats_closed,
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ return true;
+ });
- protected void refreshUiReal() {
- final Editable editable = getSearchEditText().getText();
- if (editable != null) {
- filterContacts(editable.toString());
- } else {
- filterContacts();
- }
- }
+ dialog.show(ft, "dialog");
+ }
- @Override
- public void OnUpdateBlocklist(final OnUpdateBlocklist.Status status) {
- refreshUi();
- }
+ protected void refreshUiReal() {
+ final Editable editable = getSearchEditText().getText();
+ if (editable != null) {
+ filterContacts(editable.toString());
+ } else {
+ filterContacts();
+ }
+ }
+ @Override
+ public void OnUpdateBlocklist(final OnUpdateBlocklist.Status status) {
+ refreshUi();
+ }
}
@@ -311,7 +311,7 @@ public class ChannelDiscoveryActivity extends XmppActivity
}
public void joinChannelSearchResult(final String selectedAccount, final Room result) {
- final Jid jid = Jid.ofEscaped(selectedAccount);
+ final Jid jid = Jid.of(selectedAccount);
final Account account = xmppConnectionService.findAccountByJid(jid);
final Conversation conversation =
xmppConnectionService.findOrCreateConversation(
@@ -4,14 +4,11 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
-
import androidx.databinding.DataBindingUtil;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.adapter.AccountAdapter;
-
import java.util.ArrayList;
import java.util.List;
@@ -29,16 +26,18 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final ActivityManageAccountsBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
+ final ActivityManageAccountsBinding binding =
+ DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar(), false);
this.mAccountAdapter = new AccountAdapter(this, accountList, false);
binding.accountList.setAdapter(this.mAccountAdapter);
- binding.accountList.setOnItemClickListener((arg0, view, position, arg3) -> {
- final Account account = accountList.get(position);
- goToProfilePictureActivity(account);
- });
+ binding.accountList.setOnItemClickListener(
+ (arg0, view, position, arg3) -> {
+ final Account account = accountList.get(position);
+ goToProfilePictureActivity(account);
+ });
}
@Override
@@ -58,7 +57,7 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity {
private void loadEnabledAccounts() {
accountList.clear();
- for(Account account : xmppConnectionService.getAccounts()) {
+ for (Account account : xmppConnectionService.getAccounts()) {
if (account.isEnabled()) {
accountList.add(account);
}
@@ -70,13 +69,17 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity {
final Uri uri = startIntent == null ? null : startIntent.getData();
if (uri != null) {
Intent intent = new Intent(this, PublishProfilePictureActivity.class);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
intent.setData(uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
startActivity(intent);
} catch (SecurityException e) {
- Toast.makeText(this, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
+ Toast.makeText(
+ this,
+ R.string.sharing_application_not_grant_permission,
+ Toast.LENGTH_SHORT)
+ .show();
return;
}
}
@@ -16,23 +16,12 @@ import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
-
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
-
import com.google.common.base.Strings;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -44,8 +33,15 @@ import eu.siacs.conversations.ui.util.ActivityResult;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
-public class ChooseContactActivity extends AbstractSearchableListItemActivity implements MultiChoiceModeListener, AdapterView.OnItemClickListener {
+public class ChooseContactActivity extends AbstractSearchableListItemActivity
+ implements MultiChoiceModeListener, AdapterView.OnItemClickListener {
public static final String EXTRA_TITLE_RES_ID = "extra_title_res_id";
public static final String EXTRA_GROUP_CHAT_NAME = "extra_group_chat_name";
public static final String EXTRA_SELECT_MULTIPLE = "extra_select_multiple";
@@ -76,11 +72,11 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
} else {
contacts.add(conversation.getJid().asBareJid().toString());
}
- intent.putExtra(EXTRA_FILTERED_CONTACTS, contacts.toArray(new String[contacts.size()]));
+ intent.putExtra(EXTRA_FILTERED_CONTACTS, contacts.toArray(new String[0]));
intent.putExtra(EXTRA_CONVERSATION, conversation.getUuid());
intent.putExtra(EXTRA_SELECT_MULTIPLE, true);
intent.putExtra(EXTRA_SHOW_ENTER_JID, true);
- intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
return intent;
}
@@ -136,7 +132,11 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
final SharedPreferences preferences = getPreferences();
- this.startSearching = intent.getBooleanExtra("direct_search", false) && preferences.getBoolean("start_searching", getResources().getBoolean(R.bool.start_searching));
+ this.startSearching =
+ intent.getBooleanExtra("direct_search", false)
+ && preferences.getBoolean(
+ "start_searching",
+ getResources().getBoolean(R.bool.start_searching));
getListItemAdapter().refreshSettings();
getListItemAdapter().setOnTagClickedListener((tag) -> {
@@ -174,9 +174,11 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
binding.fab.show();
final View view = getSearchEditText();
- final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm =
+ (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (view != null && imm != null) {
- imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
+ imm.hideSoftInputFromWindow(
+ getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
}
return true;
}
@@ -241,11 +243,14 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
}
- public @StringRes
- int getTitleFromIntent() {
+ public @StringRes int getTitleFromIntent() {
final Intent intent = getIntent();
boolean multiple = intent != null && intent.getBooleanExtra(EXTRA_SELECT_MULTIPLE, false);
- @StringRes int fallback = multiple ? R.string.title_activity_choose_contacts : R.string.title_activity_choose_contact;
+ @StringRes
+ int fallback =
+ multiple
+ ? R.string.title_activity_choose_contacts
+ : R.string.title_activity_choose_contact;
return intent != null ? intent.getIntExtra(EXTRA_TITLE_RES_ID, fallback) : fallback;
}
@@ -254,7 +259,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
super.onCreateOptionsMenu(menu);
final Intent i = getIntent();
boolean showEnterJid = i != null && i.getBooleanExtra(EXTRA_SHOW_ENTER_JID, false);
- menu.findItem(R.id.action_scan_qr_code).setVisible(isCameraFeatureAvailable() && showEnterJid);
+ menu.findItem(R.id.action_scan_qr_code)
+ .setVisible(isCameraFeatureAvailable() && showEnterJid);
MenuItem mMenuSearchView = menu.findItem(R.id.action_search);
if (startSearching) {
mMenuSearchView.expandActionView();
@@ -290,7 +296,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
final var accounts = new ArrayList<Account>();
for (final var account : xmppConnectionService.getAccounts()) {
- if (mActivatedAccounts.contains(account.getJid().asBareJid().toEscapedString())) accounts.add(account);
+ if (mActivatedAccounts.contains(account.getJid().asBareJid().toString())) accounts.add(account);
}
for (final var contact : extraContacts) {
if (!filterContacts.contains(contact.getJid().asBareJid().toString())
@@ -325,7 +331,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
public void refreshUiReal() {
- //nothing to do. This Activity doesn't implement any listeners
+ // nothing to do. This Activity doesn't implement any listeners
}
@Override
@@ -380,8 +386,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
}
- return true;
- });
+ return true;
+ });
dialog.show(ft, "dialog");
}
@@ -398,7 +404,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
private void handleActivityResult(ActivityResult activityResult) {
- if (activityResult.resultCode == RESULT_OK && activityResult.requestCode == ScanActivity.REQUEST_SCAN_QR_CODE) {
+ if (activityResult.resultCode == RESULT_OK
+ && activityResult.requestCode == ScanActivity.REQUEST_SCAN_QR_CODE) {
String result = activityResult.data.getStringExtra(ScanActivity.INTENT_EXTRA_RESULT);
XmppUri uri = new XmppUri(Strings.nullToEmpty(result));
if (uri.isValidJid()) {
@@ -412,8 +419,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
this.mActivatedAccounts.clear();
final var selected = getIntent().getStringExtra(EXTRA_ACCOUNT);
for (final Account account : xmppConnectionService.getAccounts()) {
- if (account.isEnabled() && (selected == null || selected.equals(account.getJid().asBareJid().toEscapedString()))) {
- this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
+ if (account.isEnabled() && (selected == null || selected.equals(account.getJid().asBareJid().toString()))) {
+ this.mActivatedAccounts.add(account.getJid().asBareJid().toString());
}
}
filterContacts();
@@ -421,14 +428,16 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
if (activityResult != null) {
handleActivityResult(activityResult);
}
- final Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DIALOG);
+ final Fragment fragment =
+ getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DIALOG);
if (fragment instanceof OnBackendConnected) {
((OnBackendConnected) fragment).onBackendConnected();
}
}
@Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ public void onRequestPermissionsResult(
+ int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
ScanActivity.onRequestPermissionResult(this, requestCode, grantResults);
}
@@ -456,8 +465,10 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
return;
}
- final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
+ final InputMethodManager imm =
+ (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(
+ getSearchEditText().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
final ListItem mListItem = getListItems().get(position);
onListItemClicked(mListItem);
}
@@ -468,7 +479,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
data.putExtra("contact", item.getJid().toString());
String account = request.getStringExtra(EXTRA_ACCOUNT);
if (account == null && item instanceof Contact) {
- account = ((Contact) item).getAccount().getJid().asBareJid().toEscapedString();
+ account = ((Contact) item).getAccount().getJid().asBareJid().toString();
}
data.putExtra(EXTRA_ACCOUNT, account);
data.putExtra(EXTRA_SELECT_MULTIPLE, false);
@@ -328,7 +328,7 @@ public class ConferenceDetailsActivity extends XmppActivity
});
this.binding.relatedMucs.setOnClickListener(v -> {
final Intent intent = new Intent(this, ChannelDiscoveryActivity.class);
- intent.putExtra("services", new String[]{ mConversation.getJid().getDomain().toEscapedString(), mConversation.getAccount().getJid().toEscapedString() });
+ intent.putExtra("services", new String[]{ mConversation.getJid().getDomain().toString(), mConversation.getAccount().getJid().toString() });
startActivity(intent);
});
}
@@ -518,10 +518,9 @@ public class ConferenceDetailsActivity extends XmppActivity
if (mConversation != null) {
if (http) {
return "https://conversations.im/j/"
- + XmppUri.lameUrlEncode(
- mConversation.getJid().asBareJid().toEscapedString());
+ + XmppUri.lameUrlEncode(mConversation.getJid().asBareJid().toString());
} else {
- return "xmpp:" + Uri.encode(mConversation.getJid().asBareJid().toEscapedString(), "@/+") + "?join";
+ return "xmpp:" + Uri.encode(mConversation.getJid().asBareJid().toString(), "@/+") + "?join";
}
} else {
return null;
@@ -642,7 +641,7 @@ public class ConferenceDetailsActivity extends XmppActivity
}
final MucOptions mucOptions = mConversation.getMucOptions();
final User self = mucOptions.getSelf();
- final String account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
+ final String account = mConversation.getAccount().getJid().asBareJid().toString();
setTitle(
mucOptions.isPrivateAndNonAnonymous()
? R.string.action_muc_details
@@ -655,10 +654,10 @@ public class ConferenceDetailsActivity extends XmppActivity
if (mConversation.isPrivateAndNonAnonymous()) {
this.binding.jid.setText(
getString(R.string.hosted_on, mConversation.getJid().getDomain()));
- this.binding.truejid.setText(mConversation.getJid().asBareJid().toEscapedString());
+ this.binding.truejid.setText(mConversation.getJid().asBareJid().toString());
if (mAdvancedMode) this.binding.truejid.setVisibility(View.VISIBLE);
} else {
- this.binding.jid.setText(mConversation.getJid().asBareJid().toEscapedString());
+ this.binding.jid.setText(mConversation.getJid().asBareJid().toString());
}
AvatarWorkerTask.loadAvatar(
mConversation, binding.yourPhoto, R.dimen.avatar_on_details_screen_size);
@@ -843,7 +842,7 @@ public class ConferenceDetailsActivity extends XmppActivity
@Override
public void onAffiliationChangeFailed(Jid jid, int resId) {
- displayToast(getString(resId, jid.asBareJid().toEscapedString()));
+ displayToast(getString(resId, jid.asBareJid().toString()));
}
@Override
@@ -202,7 +202,7 @@ public class ContactDetailsActivity extends OmemoActivity
if (quicksyContact) {
value = PhoneNumberUtilWrapper.toFormattedPhoneNumber(this, jid);
} else {
- value = jid.toEscapedString();
+ value = jid.toString();
}
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(getString(R.string.action_add_phone_book));
@@ -262,9 +262,9 @@ public class ContactDetailsActivity extends OmemoActivity
protected String getShareableUri(boolean http) {
if (http) {
return "https://conversations.im/i/"
- + XmppUri.lameUrlEncode(contact.getJid().asBareJid().toEscapedString());
+ + XmppUri.lameUrlEncode(contact.getJid().asBareJid().toString());
} else {
- return "xmpp:" + Uri.encode(contact.getJid().asBareJid().toEscapedString(), "@/+");
+ return "xmpp:" + Uri.encode(contact.getJid().asBareJid().toString(), "@/+");
}
}
@@ -276,11 +276,11 @@ public class ContactDetailsActivity extends OmemoActivity
&& savedInstanceState.getBoolean("show_inactive_omemo", false);
if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
try {
- this.accountJid = Jid.ofEscaped(getIntent().getExtras().getString(EXTRA_ACCOUNT));
+ this.accountJid = Jid.of(getIntent().getExtras().getString(EXTRA_ACCOUNT));
} catch (final IllegalArgumentException ignored) {
}
try {
- this.contactJid = Jid.ofEscaped(getIntent().getExtras().getString("contact"));
+ this.contactJid = Jid.of(getIntent().getExtras().getString("contact"));
} catch (final IllegalArgumentException ignored) {
}
}
@@ -370,7 +370,7 @@ public class ContactDetailsActivity extends OmemoActivity
JidDialog.style(
this,
R.string.remove_contact_text,
- contact.getJid().toEscapedString()))
+ contact.getJid().toString()))
.setPositiveButton(getString(R.string.delete), removeFromRoster)
.create()
.show();
@@ -598,7 +598,7 @@ public class ContactDetailsActivity extends OmemoActivity
}
binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid()));
- final String account = contact.getAccount().getJid().asBareJid().toEscapedString();
+ final String account = contact.getAccount().getJid().asBareJid().toString();
binding.detailsAccount.setText(getString(R.string.using_account, account));
AvatarWorkerTask.loadAvatar(
contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size);
@@ -1099,8 +1099,7 @@ public class ConversationFragment extends XmppFragment
}
intent.putExtra("contacts", contacts);
intent.putExtra(
- EXTRA_ACCOUNT,
- conversation.getAccount().getJid().asBareJid().toEscapedString());
+ EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
intent.putExtra("conversation", conversation.getUuid());
startActivityForResult(intent, requestCode);
return true;
@@ -2298,8 +2297,8 @@ public class ConversationFragment extends XmppFragment
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(
RtpSessionActivity.EXTRA_ACCOUNT,
- id.getAccount().getJid().asBareJid().toEscapedString());
- intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.getWith().toEscapedString());
+ id.getAccount().getJid().asBareJid().toString());
+ intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.getWith().toString());
if (id instanceof AbstractJingleConnection) {
intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.getSessionId());
startActivity(intent);
@@ -4742,7 +4741,7 @@ public class ConversationFragment extends XmppFragment
+ message.getContact()
.getJid()
.asBareJid()
- .toEscapedString());
+ .toString());
break;
}
return true;
@@ -29,12 +29,13 @@
package eu.siacs.conversations.ui;
+import static androidx.recyclerview.widget.ItemTouchHelper.LEFT;
+import static androidx.recyclerview.widget.ItemTouchHelper.RIGHT;
+
import android.app.Activity;
-import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Intent;
import android.graphics.Canvas;
-import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
@@ -47,23 +48,15 @@ import android.view.ViewGroup;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.PopupMenu;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-
-import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.base.Optional;
import com.google.common.collect.Collections2;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -88,471 +81,543 @@ import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
import static androidx.recyclerview.widget.ItemTouchHelper.LEFT;
import static androidx.recyclerview.widget.ItemTouchHelper.RIGHT;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
public class ConversationsOverviewFragment extends XmppFragment {
- private static final String STATE_SCROLL_POSITION = ConversationsOverviewFragment.class.getName()+".scroll_state";
-
- private final List<Conversation> conversations = new ArrayList<>();
- private final PendingItem<Conversation> swipedConversation = new PendingItem<>();
- private final PendingItem<ScrollState> pendingScrollState = new PendingItem<>();
- private FragmentConversationsOverviewBinding binding;
- private ConversationAdapter conversationsAdapter;
- private XmppActivity activity;
- private final PendingActionHelper pendingActionHelper = new PendingActionHelper();
-
- private final ItemTouchHelper.SimpleCallback callback = new ItemTouchHelper.SimpleCallback(0,LEFT|RIGHT) {
- @Override
- public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
- return false;
- }
-
- @Override
- public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder,
- float dX, float dY, int actionState, boolean isCurrentlyActive) {
- if (viewHolder instanceof ConversationAdapter.ConversationViewHolder conversationViewHolder) {
- getDefaultUIUtil().onDraw(c,recyclerView,conversationViewHolder.binding.frame,dX,dY,actionState,isCurrentlyActive);
- }
- }
-
- @Override
- public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
- if (viewHolder instanceof ConversationAdapter.ConversationViewHolder conversationViewHolder) {
- getDefaultUIUtil().clearView(conversationViewHolder.binding.frame);
- }
- }
-
- @Override
- public float getSwipeEscapeVelocity(final float defaultEscapeVelocity) {
- return 32 * defaultEscapeVelocity;
- }
-
- @Override
- public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int direction) {
- pendingActionHelper.execute();
- int position = viewHolder.getLayoutPosition();
- try {
- swipedConversation.push(conversations.get(position));
- } catch (IndexOutOfBoundsException e) {
- return;
- }
- conversationsAdapter.remove(swipedConversation.peek(), position);
- activity.xmppConnectionService.markRead(swipedConversation.peek());
-
- if (position == 0 && conversationsAdapter.getItemCount() == 0) {
- final Conversation c = swipedConversation.pop();
- activity.xmppConnectionService.archiveConversation(c);
- return;
- }
- final boolean formerlySelected = ConversationFragment.getConversation(getActivity()) == swipedConversation.peek();
- if (activity instanceof OnConversationArchived) {
- ((OnConversationArchived) activity).onConversationArchived(swipedConversation.peek());
- }
- final Conversation c = swipedConversation.peek();
- final int title;
- if (c.getMode() == Conversational.MODE_MULTI) {
- if (c.getMucOptions().isPrivateAndNonAnonymous()) {
- title = R.string.title_undo_swipe_out_group_chat;
- } else {
- title = R.string.title_undo_swipe_out_channel;
- }
- } else {
- title = R.string.title_undo_swipe_out_chat;
- }
-
- final Snackbar snackbar = Snackbar.make(binding.list, title, 5000)
- .setAction(R.string.undo, v -> {
- pendingActionHelper.undo();
- Conversation conversation = swipedConversation.pop();
- conversationsAdapter.insert(conversation, position);
- if (formerlySelected) {
- if (activity instanceof OnConversationSelected) {
- ((OnConversationSelected) activity).onConversationSelected(c);
- }
- }
- LinearLayoutManager layoutManager = (LinearLayoutManager) binding.list.getLayoutManager();
- if (position > layoutManager.findLastVisibleItemPosition()) {
- binding.list.smoothScrollToPosition(position);
- }
- })
- .addCallback(new Snackbar.Callback() {
- @Override
- public void onDismissed(Snackbar transientBottomBar, int event) {
- switch (event) {
- case DISMISS_EVENT_SWIPE:
- case DISMISS_EVENT_TIMEOUT:
- pendingActionHelper.execute();
- break;
- }
- }
- });
-
- pendingActionHelper.push(() -> {
- if (snackbar.isShownOrQueued()) {
- snackbar.dismiss();
- }
- final Conversation conversation = swipedConversation.pop();
- if(conversation != null){
- if (!conversation.isRead(activity.xmppConnectionService) && conversation.getMode() == Conversation.MODE_SINGLE) {
- return;
- }
- activity.xmppConnectionService.archiveConversation(c);
- }
- });
- snackbar.show();
- }
- };
-
- private ItemTouchHelper touchHelper = null;
-
- public static Conversation getSuggestion(Activity activity) {
- final Conversation exception;
- Fragment fragment = activity.getFragmentManager().findFragmentById(R.id.main_fragment);
- if (fragment instanceof ConversationsOverviewFragment) {
- exception = ((ConversationsOverviewFragment) fragment).swipedConversation.peek();
- } else {
- exception = null;
- }
- return getSuggestion(activity, exception);
- }
-
- public static Conversation getSuggestion(Activity activity, Conversation exception) {
- Fragment fragment = activity.getFragmentManager().findFragmentById(R.id.main_fragment);
- if (fragment instanceof ConversationsOverviewFragment) {
- List<Conversation> conversations = ((ConversationsOverviewFragment) fragment).conversations;
- if (conversations.size() > 0) {
- Conversation suggestion = conversations.get(0);
- if (suggestion == exception) {
- if (conversations.size() > 1) {
- return conversations.get(1);
- }
- } else {
- return suggestion;
- }
- }
- }
- return null;
-
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- if (savedInstanceState == null) {
- return;
- }
- pendingScrollState.push(savedInstanceState.getParcelable(STATE_SCROLL_POSITION));
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- if (activity instanceof XmppActivity) {
- this.activity = (XmppActivity) activity;
- } else {
- throw new IllegalStateException("Trying to attach fragment to activity that is not an XmppActivity");
- }
- }
- @Override
- public void onDestroyView() {
- Log.d(Config.LOGTAG,"ConversationsOverviewFragment.onDestroyView()");
- super.onDestroyView();
- this.binding = null;
- this.conversationsAdapter = null;
- this.touchHelper = null;
- }
- @Override
- public void onDestroy() {
- Log.d(Config.LOGTAG,"ConversationsOverviewFragment.onDestroy()");
- super.onDestroy();
-
- }
- @Override
- public void onPause() {
- Log.d(Config.LOGTAG,"ConversationsOverviewFragment.onPause()");
- pendingActionHelper.execute();
- super.onPause();
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- this.activity = null;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
- }
-
- @Override
- public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- this.binding = DataBindingUtil.inflate(inflater, R.layout.fragment_conversations_overview, container, false);
- this.binding.fab.setOnClickListener((view) -> activity.launchStartConversation());
-
- this.conversationsAdapter = new ConversationAdapter(this.activity, this.conversations);
- this.conversationsAdapter.setConversationClickListener((view, conversation) -> {
- if (activity instanceof OnConversationSelected) {
- ((OnConversationSelected) activity).onConversationSelected(conversation);
- } else {
- Log.w(ConversationsOverviewFragment.class.getCanonicalName(), "Activity does not implement OnConversationSelected");
- }
- });
- this.binding.list.setAdapter(this.conversationsAdapter);
- this.binding.list.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false));
- registerForContextMenu(this.binding.list);
- this.binding.list.addOnScrollListener(ExtendedFabSizeChanger.of(binding.fab));
- this.touchHelper = new ItemTouchHelper(this.callback);
- this.touchHelper.attachToRecyclerView(this.binding.list);
- return binding.getRoot();
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.fragment_conversations_overview, menu);
- AccountUtils.showHideMenuItems(menu);
- final MenuItem easyOnboardInvite = menu.findItem(R.id.action_easy_invite);
- easyOnboardInvite.setVisible(EasyOnboardingInvite.anyHasSupport(activity == null ? null : activity.xmppConnectionService));
- if (activity != null && activity.xmppConnectionService != null && activity.xmppConnectionService.isOnboarding()) {
- final MenuItem manageAccounts = menu.findItem(R.id.action_accounts);
- if (manageAccounts != null) manageAccounts.setVisible(false);
-
- final MenuItem settings = menu.findItem(R.id.action_settings);
- if (settings != null) settings.setVisible(false);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- activity.getMenuInflater().inflate(R.menu.conversations, menu);
-
- final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
- final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
- final MenuItem menuMute = menu.findItem(R.id.action_mute);
- final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
- final MenuItem menuOngoingCall = menu.findItem(R.id.action_ongoing_call);
- final MenuItem menuTogglePinned = menu.findItem(R.id.action_toggle_pinned);
- final MenuItem menuArchiveChat = menu.findItem(R.id.action_archive);
-
- if (menuInfo == null) return;
- int pos = ((AdapterContextMenuInfo) menuInfo).position;
- if (pos < 0) return;
- Conversation conversation = conversations.get(pos);
- if (conversation != null) {
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- menuContactDetails.setVisible(false);
- menuMucDetails.setTitle(conversation.getMucOptions().isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details);
- menuOngoingCall.setVisible(false);
- menuArchiveChat.setTitle("Leave " + (conversation.getMucOptions().isPrivateAndNonAnonymous() ? "group chat" : "Channel"));
- } else {
- final XmppConnectionService service = activity == null ? null : activity.xmppConnectionService;
- final Optional<OngoingRtpSession> ongoingRtpSession = service == null ? Optional.absent() : service.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact());
- if (ongoingRtpSession.isPresent()) {
- menuOngoingCall.setVisible(true);
- } else {
- menuOngoingCall.setVisible(false);
- }
- menuContactDetails.setVisible(!conversation.withSelf());
- menuMucDetails.setVisible(false);
- menuArchiveChat.setTitle(R.string.action_archive_chat);
- }
- if (conversation.isMuted()) {
- menuMute.setVisible(false);
- } else {
- menuUnmute.setVisible(false);
- }
- if (conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)) {
- menuTogglePinned.setTitle(R.string.remove_from_favorites);
- } else {
- menuTogglePinned.setTitle(R.string.add_to_favorites);
- }
- }
- super.onCreateContextMenu(menu, view, menuInfo);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- final var info = ((AdapterContextMenuInfo) item.getMenuInfo());
- if (info == null) return false;
-
- int pos = info.position;
- if (conversations == null || conversations.size() <= pos || pos < 0) return false;
-
- Conversation conversation = conversations.get(pos);
- ConversationFragment fragment = new ConversationFragment();
- fragment.setHasOptionsMenu(false);
- fragment.onAttach(activity);
- fragment.reInit(conversation, null);
- boolean r = fragment.onOptionsItemSelected(item);
- refresh();
- return r;
- }
-
- @Override
- public void onBackendConnected() {
- refresh();
- }
-
- private void setupSwipe() {
- if (this.touchHelper == null && (activity.xmppConnectionService == null || !activity.xmppConnectionService.isOnboarding())) {
- this.touchHelper = new ItemTouchHelper(this.callback);
- this.touchHelper.attachToRecyclerView(this.binding.list);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle bundle) {
- super.onSaveInstanceState(bundle);
- ScrollState scrollState = getScrollState();
- if (scrollState != null) {
- bundle.putParcelable(STATE_SCROLL_POSITION, scrollState);
- }
- }
-
- private ScrollState getScrollState() {
- if (this.binding == null) {
- return null;
- }
- LinearLayoutManager layoutManager = (LinearLayoutManager) this.binding.list.getLayoutManager();
- int position = layoutManager.findFirstVisibleItemPosition();
- final View view = this.binding.list.getChildAt(0);
- if (view != null) {
- return new ScrollState(position,view.getTop());
- } else {
- return new ScrollState(position, 0);
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onStart()");
- if (activity.xmppConnectionService != null) {
- refresh();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onResume()");
- }
-
- @Override
- public boolean onOptionsItemSelected(final MenuItem item) {
- if (MenuDoubleTabUtil.shouldIgnoreTap()) {
- return false;
- }
- switch (item.getItemId()) {
- case R.id.action_search:
- startActivity(new Intent(getActivity(), SearchActivity.class));
- return true;
- case R.id.action_easy_invite:
- selectAccountToStartEasyInvite();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void selectAccountToStartEasyInvite() {
- final List<Account> accounts = EasyOnboardingInvite.getSupportingAccounts(activity.xmppConnectionService);
- if (accounts.isEmpty()) {
- //This can technically happen if opening the menu item races with accounts reconnecting or something
- Toast.makeText(getActivity(),R.string.no_active_accounts_support_this, Toast.LENGTH_LONG).show();
- } else if (accounts.size() == 1) {
- openEasyInviteScreen(accounts.get(0));
- } else {
- final AtomicReference<Account> selectedAccount = new AtomicReference<>(accounts.get(0));
- final MaterialAlertDialogBuilder alertDialogBuilder = new MaterialAlertDialogBuilder(activity);
- alertDialogBuilder.setTitle(R.string.choose_account);
- final String[] asStrings = Collections2.transform(accounts, a -> a.getJid().asBareJid().toEscapedString()).toArray(new String[0]);
- alertDialogBuilder.setSingleChoiceItems(asStrings, 0, (dialog, which) -> selectedAccount.set(accounts.get(which)));
- alertDialogBuilder.setNegativeButton(R.string.cancel, null);
- alertDialogBuilder.setPositiveButton(R.string.ok, (dialog, which) -> openEasyInviteScreen(selectedAccount.get()));
- alertDialogBuilder.create().show();
- }
- }
-
- private void openEasyInviteScreen(final Account account) {
- EasyOnboardingInviteActivity.launch(account, activity);
- }
-
- @Override
- protected void refresh() {
- if (binding == null || this.activity == null) {
- Log.d(Config.LOGTAG,"ConversationsOverviewFragment.refresh() skipped updated because view binding or activity was null");
- return;
- }
- this.activity.populateWithOrderedConversations(this.conversations);
- Conversation removed = this.swipedConversation.peek();
- if (removed != null) {
- if (removed.isRead(activity == null ? null : activity.xmppConnectionService)) {
- this.conversations.remove(removed);
- } else {
- pendingActionHelper.execute();
- }
- }
- this.conversationsAdapter.notifyDataSetChanged();
- ScrollState scrollState = pendingScrollState.pop();
- if (scrollState != null) {
- setScrollPosition(scrollState);
- }
-
- if (activity.xmppConnectionService != null && activity.xmppConnectionService.isOnboarding()) {
- binding.fab.setVisibility(View.GONE);
-
- if (this.conversations.size() == 1) {
- if (activity instanceof OnConversationSelected) {
- ((OnConversationSelected) activity).onConversationSelected(this.conversations.get(0));
- } else {
- Log.w(ConversationsOverviewFragment.class.getCanonicalName(), "Activity does not implement OnConversationSelected");
- }
- }
- } else {
- binding.fab.setVisibility(View.VISIBLE);
- }
- setupSwipe();
-
- if (activity.xmppConnectionService == null || binding == null || binding.overviewSnackbar == null) return;
- binding.overviewSnackbar.setVisibility(View.GONE);
- for (final var account : activity.xmppConnectionService.getAccounts()) {
- if (activity.getPreferences().getBoolean("no_mam_pref_warn:" + account.getUuid(), false)) continue;
- if (account.mamPrefs() != null && !"always".equals(account.mamPrefs().getAttribute("default"))) {
- binding.overviewSnackbar.setVisibility(View.VISIBLE);
- binding.overviewSnackbarMessage.setText("Your account " + account.getJid().asBareJid().toEscapedString() + " does not have archiving fully enabled. This may result in missed messages if you use multiple devices or apps.");
- binding.overviewSnackbarAction.setOnClickListener((v) -> {
- final var prefs = account.mamPrefs();
- prefs.setAttribute("default", "always");
- activity.xmppConnectionService.pushMamPreferences(account, prefs);
- refresh();
- });
-
- binding.overviewSnackbarAction.setOnLongClickListener((v) -> {
- PopupMenu popupMenu = new PopupMenu(getActivity(), v);
- popupMenu.inflate(R.menu.mam_pref_fix);
- popupMenu.setOnMenuItemClickListener(menuItem -> {
- switch (menuItem.getItemId()) {
- case R.id.ignore:
- final var editor = activity.getPreferences().edit();
- editor.putBoolean("no_mam_pref_warn:" + account.getUuid(), true).apply();
- editor.apply();
- refresh();
- return true;
- }
- return true;
- });
- popupMenu.show();
- return true;
- });
- break;
- }
- }
- }
-
- private void setScrollPosition(ScrollState scrollPosition) {
- if (scrollPosition != null) {
- LinearLayoutManager layoutManager = (LinearLayoutManager) binding.list.getLayoutManager();
- layoutManager.scrollToPositionWithOffset(scrollPosition.position, scrollPosition.offset);
- }
- }
+ private static final String STATE_SCROLL_POSITION =
+ ConversationsOverviewFragment.class.getName() + ".scroll_state";
+
+ private final List<Conversation> conversations = new ArrayList<>();
+ private final PendingItem<Conversation> swipedConversation = new PendingItem<>();
+ private final PendingItem<ScrollState> pendingScrollState = new PendingItem<>();
+ private FragmentConversationsOverviewBinding binding;
+ private ConversationAdapter conversationsAdapter;
+ private XmppActivity activity;
+ private final PendingActionHelper pendingActionHelper = new PendingActionHelper();
+
+ private final ItemTouchHelper.SimpleCallback callback =
+ new ItemTouchHelper.SimpleCallback(0, LEFT | RIGHT) {
+ @Override
+ public boolean onMove(
+ @NonNull RecyclerView recyclerView,
+ @NonNull RecyclerView.ViewHolder viewHolder,
+ @NonNull RecyclerView.ViewHolder target) {
+ return false;
+ }
+
+ @Override
+ public void onChildDraw(
+ @NonNull Canvas c,
+ @NonNull RecyclerView recyclerView,
+ @NonNull RecyclerView.ViewHolder viewHolder,
+ float dX,
+ float dY,
+ int actionState,
+ boolean isCurrentlyActive) {
+ if (viewHolder
+ instanceof
+ ConversationAdapter.ConversationViewHolder conversationViewHolder) {
+ getDefaultUIUtil()
+ .onDraw(
+ c,
+ recyclerView,
+ conversationViewHolder.binding.frame,
+ dX,
+ dY,
+ actionState,
+ isCurrentlyActive);
+ }
+ }
+
+ @Override
+ public void clearView(
+ @NonNull RecyclerView recyclerView,
+ @NonNull RecyclerView.ViewHolder viewHolder) {
+ if (viewHolder
+ instanceof
+ ConversationAdapter.ConversationViewHolder conversationViewHolder) {
+ getDefaultUIUtil().clearView(conversationViewHolder.binding.frame);
+ }
+ }
+
+ @Override
+ public float getSwipeEscapeVelocity(final float defaultEscapeVelocity) {
+ return 32 * defaultEscapeVelocity;
+ }
+
+ @Override
+ public void onSwiped(
+ final RecyclerView.ViewHolder viewHolder, final int direction) {
+ pendingActionHelper.execute();
+ int position = viewHolder.getLayoutPosition();
+ try {
+ swipedConversation.push(conversations.get(position));
+ } catch (IndexOutOfBoundsException e) {
+ return;
+ }
+ conversationsAdapter.remove(swipedConversation.peek(), position);
+ activity.xmppConnectionService.markRead(swipedConversation.peek());
+
+ if (position == 0 && conversationsAdapter.getItemCount() == 0) {
+ final Conversation c = swipedConversation.pop();
+ activity.xmppConnectionService.archiveConversation(c);
+ return;
+ }
+ final boolean formerlySelected =
+ ConversationFragment.getConversation(getActivity())
+ == swipedConversation.peek();
+ if (activity instanceof OnConversationArchived) {
+ ((OnConversationArchived) activity)
+ .onConversationArchived(swipedConversation.peek());
+ }
+ final Conversation c = swipedConversation.peek();
+ final int title;
+ if (c.getMode() == Conversational.MODE_MULTI) {
+ if (c.getMucOptions().isPrivateAndNonAnonymous()) {
+ title = R.string.title_undo_swipe_out_group_chat;
+ } else {
+ title = R.string.title_undo_swipe_out_channel;
+ }
+ } else {
+ title = R.string.title_undo_swipe_out_chat;
+ }
+
+ final Snackbar snackbar =
+ Snackbar.make(binding.list, title, 5000)
+ .setAction(
+ R.string.undo,
+ v -> {
+ pendingActionHelper.undo();
+ Conversation conversation =
+ swipedConversation.pop();
+ conversationsAdapter.insert(conversation, position);
+ if (formerlySelected) {
+ if (activity
+ instanceof OnConversationSelected) {
+ ((OnConversationSelected) activity)
+ .onConversationSelected(c);
+ }
+ }
+ LinearLayoutManager layoutManager =
+ (LinearLayoutManager)
+ binding.list.getLayoutManager();
+ if (position
+ > layoutManager
+ .findLastVisibleItemPosition()) {
+ binding.list.smoothScrollToPosition(position);
+ }
+ })
+ .addCallback(
+ new Snackbar.Callback() {
+ @Override
+ public void onDismissed(
+ Snackbar transientBottomBar, int event) {
+ switch (event) {
+ case DISMISS_EVENT_SWIPE:
+ case DISMISS_EVENT_TIMEOUT:
+ pendingActionHelper.execute();
+ break;
+ }
+ }
+ });
+
+ pendingActionHelper.push(
+ () -> {
+ if (snackbar.isShownOrQueued()) {
+ snackbar.dismiss();
+ }
+ final Conversation conversation = swipedConversation.pop();
+ if (conversation != null) {
+ if (!conversation.isRead(activity.xmppConnectionService)
+ && conversation.getMode() == Conversation.MODE_SINGLE) {
+ return;
+ }
+ activity.xmppConnectionService.archiveConversation(c);
+ }
+ });
+ snackbar.show();
+ }
+ };
+
+ private ItemTouchHelper touchHelper;
+
+ public static Conversation getSuggestion(Activity activity) {
+ final Conversation exception;
+ Fragment fragment = activity.getFragmentManager().findFragmentById(R.id.main_fragment);
+ if (fragment instanceof ConversationsOverviewFragment) {
+ exception = ((ConversationsOverviewFragment) fragment).swipedConversation.peek();
+ } else {
+ exception = null;
+ }
+ return getSuggestion(activity, exception);
+ }
+
+ public static Conversation getSuggestion(Activity activity, Conversation exception) {
+ Fragment fragment = activity.getFragmentManager().findFragmentById(R.id.main_fragment);
+ if (fragment instanceof ConversationsOverviewFragment) {
+ List<Conversation> conversations =
+ ((ConversationsOverviewFragment) fragment).conversations;
+ if (conversations.size() > 0) {
+ Conversation suggestion = conversations.get(0);
+ if (suggestion == exception) {
+ if (conversations.size() > 1) {
+ return conversations.get(1);
+ }
+ } else {
+ return suggestion;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (savedInstanceState == null) {
+ return;
+ }
+ pendingScrollState.push(savedInstanceState.getParcelable(STATE_SCROLL_POSITION));
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ if (activity instanceof XmppActivity) {
+ this.activity = (XmppActivity) activity;
+ } else {
+ throw new IllegalStateException(
+ "Trying to attach fragment to activity that is not an XmppActivity");
+ }
+ }
+
+ @Override
+ public void onDestroyView() {
+ Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onDestroyView()");
+ super.onDestroyView();
+ this.binding = null;
+ this.conversationsAdapter = null;
+ this.touchHelper = null;
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onDestroy()");
+ super.onDestroy();
+ }
+
+ @Override
+ public void onPause() {
+ Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onPause()");
+ pendingActionHelper.execute();
+ super.onPause();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ this.activity = null;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(
+ final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ this.binding =
+ DataBindingUtil.inflate(
+ inflater, R.layout.fragment_conversations_overview, container, false);
+ this.binding.fab.setOnClickListener(
+ (view) -> StartConversationActivity.launch(getActivity()));
+
+ this.conversationsAdapter = new ConversationAdapter(this.activity, this.conversations);
+ this.conversationsAdapter.setConversationClickListener(
+ (view, conversation) -> {
+ if (activity instanceof OnConversationSelected) {
+ ((OnConversationSelected) activity).onConversationSelected(conversation);
+ } else {
+ Log.w(
+ ConversationsOverviewFragment.class.getCanonicalName(),
+ "Activity does not implement OnConversationSelected");
+ }
+ });
+ this.binding.list.setAdapter(this.conversationsAdapter);
+ this.binding.list.setLayoutManager(
+ new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
+ registerForContextMenu(this.binding.list);
+ this.binding.list.addOnScrollListener(ExtendedFabSizeChanger.of(binding.fab));
+ this.touchHelper = new ItemTouchHelper(this.callback);
+ this.touchHelper.attachToRecyclerView(this.binding.list);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.fragment_conversations_overview, menu);
+ AccountUtils.showHideMenuItems(menu);
+ final MenuItem easyOnboardInvite = menu.findItem(R.id.action_easy_invite);
+ easyOnboardInvite.setVisible(EasyOnboardingInvite.anyHasSupport(activity == null ? null : activity.xmppConnectionService));
+ if (activity != null && activity.xmppConnectionService != null && activity.xmppConnectionService.isOnboarding()) {
+ final MenuItem manageAccounts = menu.findItem(R.id.action_accounts);
+ if (manageAccounts != null) manageAccounts.setVisible(false);
+
+ final MenuItem settings = menu.findItem(R.id.action_settings);
+ if (settings != null) settings.setVisible(false);
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ activity.getMenuInflater().inflate(R.menu.conversations, menu);
+
+ final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
+ final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
+ final MenuItem menuMute = menu.findItem(R.id.action_mute);
+ final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
+ final MenuItem menuOngoingCall = menu.findItem(R.id.action_ongoing_call);
+ final MenuItem menuTogglePinned = menu.findItem(R.id.action_toggle_pinned);
+ final MenuItem menuArchiveChat = menu.findItem(R.id.action_archive);
+
+ if (menuInfo == null) return;
+ int pos = ((AdapterContextMenuInfo) menuInfo).position;
+ if (pos < 0) return;
+ Conversation conversation = conversations.get(pos);
+ if (conversation != null) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ menuContactDetails.setVisible(false);
+ menuMucDetails.setTitle(conversation.getMucOptions().isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details);
+ menuOngoingCall.setVisible(false);
+ menuArchiveChat.setTitle("Leave " + (conversation.getMucOptions().isPrivateAndNonAnonymous() ? "group chat" : "Channel"));
+ } else {
+ final XmppConnectionService service = activity == null ? null : activity.xmppConnectionService;
+ final Optional<OngoingRtpSession> ongoingRtpSession = service == null ? Optional.absent() : service.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact());
+ if (ongoingRtpSession.isPresent()) {
+ menuOngoingCall.setVisible(true);
+ } else {
+ menuOngoingCall.setVisible(false);
+ }
+ menuContactDetails.setVisible(!conversation.withSelf());
+ menuMucDetails.setVisible(false);
+ menuArchiveChat.setTitle(R.string.action_archive_chat);
+ }
+ if (conversation.isMuted()) {
+ menuMute.setVisible(false);
+ } else {
+ menuUnmute.setVisible(false);
+ }
+ if (conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false)) {
+ menuTogglePinned.setTitle(R.string.remove_from_favorites);
+ } else {
+ menuTogglePinned.setTitle(R.string.add_to_favorites);
+ }
+ }
+ super.onCreateContextMenu(menu, view, menuInfo);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final var info = ((AdapterContextMenuInfo) item.getMenuInfo());
+ if (info == null) return false;
+
+ int pos = info.position;
+ if (conversations == null || conversations.size() <= pos || pos < 0) return false;
+
+ Conversation conversation = conversations.get(pos);
+ ConversationFragment fragment = new ConversationFragment();
+ fragment.setHasOptionsMenu(false);
+ fragment.onAttach(activity);
+ fragment.reInit(conversation, null);
+ boolean r = fragment.onOptionsItemSelected(item);
+ refresh();
+ return r;
+ }
+
+ @Override
+ public void onBackendConnected() {
+ refresh();
+ }
+
+ private void setupSwipe() {
+ if (this.touchHelper == null && (activity.xmppConnectionService == null || !activity.xmppConnectionService.isOnboarding())) {
+ this.touchHelper = new ItemTouchHelper(this.callback);
+ this.touchHelper.attachToRecyclerView(this.binding.list);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle bundle) {
+ super.onSaveInstanceState(bundle);
+ ScrollState scrollState = getScrollState();
+ if (scrollState != null) {
+ bundle.putParcelable(STATE_SCROLL_POSITION, scrollState);
+ }
+ }
+
+ private ScrollState getScrollState() {
+ if (this.binding == null) {
+ return null;
+ }
+ LinearLayoutManager layoutManager =
+ (LinearLayoutManager) this.binding.list.getLayoutManager();
+ int position = layoutManager.findFirstVisibleItemPosition();
+ final View view = this.binding.list.getChildAt(0);
+ if (view != null) {
+ return new ScrollState(position, view.getTop());
+ } else {
+ return new ScrollState(position, 0);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onStart()");
+ if (activity.xmppConnectionService != null) {
+ refresh();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Log.d(Config.LOGTAG, "ConversationsOverviewFragment.onResume()");
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ if (MenuDoubleTabUtil.shouldIgnoreTap()) {
+ return false;
+ }
+ switch (item.getItemId()) {
+ case R.id.action_search:
+ startActivity(new Intent(getActivity(), SearchActivity.class));
+ return true;
+ case R.id.action_easy_invite:
+ selectAccountToStartEasyInvite();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void selectAccountToStartEasyInvite() {
+ final List<Account> accounts =
+ EasyOnboardingInvite.getSupportingAccounts(activity.xmppConnectionService);
+ if (accounts.isEmpty()) {
+ // This can technically happen if opening the menu item races with accounts reconnecting
+ // or something
+ Toast.makeText(
+ getActivity(),
+ R.string.no_active_accounts_support_this,
+ Toast.LENGTH_LONG)
+ .show();
+ } else if (accounts.size() == 1) {
+ openEasyInviteScreen(accounts.get(0));
+ } else {
+ final AtomicReference<Account> selectedAccount = new AtomicReference<>(accounts.get(0));
+ final MaterialAlertDialogBuilder alertDialogBuilder =
+ new MaterialAlertDialogBuilder(activity);
+ alertDialogBuilder.setTitle(R.string.choose_account);
+ final String[] asStrings =
+ Collections2.transform(accounts, a -> a.getJid().asBareJid().toString())
+ .toArray(new String[0]);
+ alertDialogBuilder.setSingleChoiceItems(
+ asStrings, 0, (dialog, which) -> selectedAccount.set(accounts.get(which)));
+ alertDialogBuilder.setNegativeButton(R.string.cancel, null);
+ alertDialogBuilder.setPositiveButton(
+ R.string.ok, (dialog, which) -> openEasyInviteScreen(selectedAccount.get()));
+ alertDialogBuilder.create().show();
+ }
+ }
+
+ private void openEasyInviteScreen(final Account account) {
+ EasyOnboardingInviteActivity.launch(account, activity);
+ }
+
+ @Override
+ protected void refresh() {
+ if (binding == null || this.activity == null) {
+ Log.d(Config.LOGTAG,"ConversationsOverviewFragment.refresh() skipped updated because view binding or activity was null");
+ return;
+ }
+ this.activity.populateWithOrderedConversations(this.conversations);
+ Conversation removed = this.swipedConversation.peek();
+ if (removed != null) {
+ if (removed.isRead(activity == null ? null : activity.xmppConnectionService)) {
+ this.conversations.remove(removed);
+ } else {
+ pendingActionHelper.execute();
+ }
+ }
+ this.conversationsAdapter.notifyDataSetChanged();
+ ScrollState scrollState = pendingScrollState.pop();
+ if (scrollState != null) {
+ setScrollPosition(scrollState);
+ }
+
+ if (activity.xmppConnectionService != null && activity.xmppConnectionService.isOnboarding()) {
+ binding.fab.setVisibility(View.GONE);
+
+ if (this.conversations.size() == 1) {
+ if (activity instanceof OnConversationSelected) {
+ ((OnConversationSelected) activity).onConversationSelected(this.conversations.get(0));
+ } else {
+ Log.w(ConversationsOverviewFragment.class.getCanonicalName(), "Activity does not implement OnConversationSelected");
+ }
+ }
+ } else {
+ binding.fab.setVisibility(View.VISIBLE);
+ }
+ setupSwipe();
+
+ if (activity.xmppConnectionService == null || binding == null || binding.overviewSnackbar == null) return;
+ binding.overviewSnackbar.setVisibility(View.GONE);
+ for (final var account : activity.xmppConnectionService.getAccounts()) {
+ if (activity.getPreferences().getBoolean("no_mam_pref_warn:" + account.getUuid(), false)) continue;
+ if (account.mamPrefs() != null && !"always".equals(account.mamPrefs().getAttribute("default"))) {
+ binding.overviewSnackbar.setVisibility(View.VISIBLE);
+ binding.overviewSnackbarMessage.setText("Your account " + account.getJid().asBareJid().toString() + " does not have archiving fully enabled. This may result in missed messages if you use multiple devices or apps.");
+ binding.overviewSnackbarAction.setOnClickListener((v) -> {
+ final var prefs = account.mamPrefs();
+ prefs.setAttribute("default", "always");
+ activity.xmppConnectionService.pushMamPreferences(account, prefs);
+ refresh();
+ });
+
+ binding.overviewSnackbarAction.setOnLongClickListener((v) -> {
+ PopupMenu popupMenu = new PopupMenu(getActivity(), v);
+ popupMenu.inflate(R.menu.mam_pref_fix);
+ popupMenu.setOnMenuItemClickListener(menuItem -> {
+ switch (menuItem.getItemId()) {
+ case R.id.ignore:
+ final var editor = activity.getPreferences().edit();
+ editor.putBoolean("no_mam_pref_warn:" + account.getUuid(), true).apply();
+ editor.apply();
+ refresh();
+ return true;
+ }
+ return true;
+ });
+ popupMenu.show();
+ return true;
+ });
+ break;
+ }
+ }
+ }
+
+ private void setScrollPosition(ScrollState scrollPosition) {
+ if (scrollPosition != null) {
+ LinearLayoutManager layoutManager =
+ (LinearLayoutManager) binding.list.getLayoutManager();
+ layoutManager.scrollToPositionWithOffset(
+ scrollPosition.position, scrollPosition.offset);
+ }
+ }
}
@@ -11,18 +11,11 @@ import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
-
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
-
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.DialogCreatePublicChannelBinding;
import eu.siacs.conversations.entities.Account;
@@ -33,10 +26,14 @@ import eu.siacs.conversations.ui.util.DelayedHintHelper;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
public class CreatePublicChannelDialog extends DialogFragment implements OnBackendConnected {
- private static final char[] FORBIDDEN = new char[]{'\u0022','&','\'','/',':','<','>','@'};
+ private static final char[] FORBIDDEN =
+ new char[] {'\u0022', '&', '\'', '/', ':', '<', '>', '@'};
private static final String ACCOUNTS_LIST_KEY = "activated_accounts_list";
private CreatePublicChannelDialogListener mListener;
@@ -62,48 +59,56 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- jidWasModified = savedInstanceState != null && savedInstanceState.getBoolean("jid_was_modified_false", false);
- nameEntered = savedInstanceState != null && savedInstanceState.getBoolean("name_entered", false);
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+ jidWasModified =
+ savedInstanceState != null
+ && savedInstanceState.getBoolean("jid_was_modified_false", false);
+ nameEntered =
+ savedInstanceState != null && savedInstanceState.getBoolean("name_entered", false);
+ final MaterialAlertDialogBuilder builder =
+ new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.create_public_channel);
- final DialogCreatePublicChannelBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_public_channel, null, false);
- binding.account.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- updateJidSuggestion(binding);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
-
- }
- });
- binding.jid.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
-
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (skipTetxWatcher) {
- return;
- }
- if (jidWasModified) {
- jidWasModified = !TextUtils.isEmpty(s);
- } else {
- jidWasModified = !s.toString().equals(getJidSuggestion(binding));
- }
- }
- });
- updateInputs(binding,false);
+ final DialogCreatePublicChannelBinding binding =
+ DataBindingUtil.inflate(
+ getActivity().getLayoutInflater(),
+ R.layout.dialog_create_public_channel,
+ null,
+ false);
+ binding.account.setOnItemSelectedListener(
+ new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(
+ AdapterView<?> parent, View view, int position, long id) {
+ updateJidSuggestion(binding);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {}
+ });
+ binding.jid.addTextChangedListener(
+ new TextWatcher() {
+ @Override
+ public void beforeTextChanged(
+ CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (skipTetxWatcher) {
+ return;
+ }
+ if (jidWasModified) {
+ jidWasModified = !TextUtils.isEmpty(s);
+ } else {
+ jidWasModified = !s.toString().equals(getJidSuggestion(binding));
+ }
+ }
+ });
+ updateInputs(binding, false);
ArrayList<String> mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY);
- StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account);
+ StartConversationActivity.populateAccountSpinner(
+ getActivity(), mActivatedAccounts, binding.account);
builder.setView(binding.getRoot());
builder.setPositiveButton(nameEntered ? R.string.create : R.string.next, null);
builder.setNegativeButton(nameEntered ? R.string.back : R.string.cancel, null);
@@ -111,14 +116,18 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
binding.jid.setAdapter(knownHostsAdapter);
final AlertDialog dialog = builder.create();
- binding.groupChatName.setOnEditorActionListener((v, actionId, event) -> {
- submit(dialog, binding);
- return true;
- });
- dialog.setOnShowListener(dialogInterface -> {
- dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(v -> goBack(dialog, binding));
- dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> submit(dialog, binding));
- });
+ binding.groupChatName.setOnEditorActionListener(
+ (v, actionId, event) -> {
+ submit(dialog, binding);
+ return true;
+ });
+ dialog.setOnShowListener(
+ dialogInterface -> {
+ dialog.getButton(DialogInterface.BUTTON_NEGATIVE)
+ .setOnClickListener(v -> goBack(dialog, binding));
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE)
+ .setOnClickListener(v -> submit(dialog, binding));
+ });
return dialog;
}
@@ -134,13 +143,15 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
@Override
public void onSaveInstanceState(Bundle outState) {
- outState.putBoolean("jid_was_modified",jidWasModified);
+ outState.putBoolean("jid_was_modified", jidWasModified);
outState.putBoolean("name_entered", nameEntered);
super.onSaveInstanceState(outState);
}
private static String getJidSuggestion(final DialogCreatePublicChannelBinding binding) {
- final Account account = StartConversationActivity.getSelectedAccount(binding.getRoot().getContext(), binding.account);
+ final Account account =
+ StartConversationActivity.getSelectedAccount(
+ binding.getRoot().getContext(), binding.account);
final XmppConnection connection = account == null ? null : account.getXmppConnection();
if (connection == null) {
return "";
@@ -156,18 +167,18 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
return "";
} else {
try {
- return Jid.of(localpart, domain, null).toEscapedString();
+ return Jid.of(localpart, domain, null).toString();
} catch (IllegalArgumentException e) {
- return Jid.of(CryptoHelper.pronounceable(), domain, null).toEscapedString();
+ return Jid.of(CryptoHelper.pronounceable(), domain, null).toString();
}
}
}
private static String clean(String name) {
- for(char c : FORBIDDEN) {
- name = name.replace(String.valueOf(c),"");
+ for (char c : FORBIDDEN) {
+ name = name.replace(String.valueOf(c), "");
}
- return name.replaceAll("\\s+","-");
+ return name.replaceAll("\\s+", "-");
}
private void goBack(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
@@ -189,22 +200,26 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
if (nameEntered) {
binding.nameLayout.setError(null);
if (address.isEmpty()) {
- binding.xmppAddressLayout.setError(context.getText(R.string.please_enter_xmpp_address));
+ binding.xmppAddressLayout.setError(
+ context.getText(R.string.please_enter_xmpp_address));
} else {
final Jid jid;
try {
- jid = Jid.ofEscaped(address);
- } catch (IllegalArgumentException e) {
+ jid = Jid.ofUserInput(address);
+ } catch (final IllegalArgumentException e) {
binding.xmppAddressLayout.setError(context.getText(R.string.invalid_jid));
return;
}
- final Account account = StartConversationActivity.getSelectedAccount(context, binding.account);
+ final Account account =
+ StartConversationActivity.getSelectedAccount(context, binding.account);
if (account == null) {
return;
}
- final XmppConnectionService service = ((XmppActivity )context).xmppConnectionService;
+ final XmppConnectionService service =
+ ((XmppActivity) context).xmppConnectionService;
if (service != null && service.findFirstMuc(jid) != null) {
- binding.xmppAddressLayout.setError(context.getString(R.string.channel_already_exists));
+ binding.xmppAddressLayout.setError(
+ context.getString(R.string.channel_already_exists));
return;
}
mListener.onCreatePublicChannel(account, name, jid);
@@ -214,7 +229,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
binding.xmppAddressLayout.setError(null);
if (name.isEmpty()) {
binding.nameLayout.setError(context.getText(R.string.please_enter_name));
- } else if (StartConversationActivity.isValidJid(name)){
+ } else if (StartConversationActivity.isValidJid(name)) {
binding.nameLayout.setError(context.getText(R.string.this_is_an_xmpp_address));
} else {
binding.nameLayout.setError(null);
@@ -227,8 +242,8 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
}
-
- private void updateInputs(final DialogCreatePublicChannelBinding binding, final boolean requestFocus) {
+ private void updateInputs(
+ final DialogCreatePublicChannelBinding binding, final boolean requestFocus) {
binding.xmppAddressLayout.setVisibility(nameEntered ? View.VISIBLE : View.GONE);
binding.nameLayout.setVisibility(nameEntered ? View.GONE : View.VISIBLE);
if (!requestFocus) {
@@ -256,7 +271,8 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
private void refreshKnownHosts() {
Activity activity = getActivity();
if (activity instanceof XmppActivity) {
- Collection<String> hosts = ((XmppActivity) activity).xmppConnectionService.getKnownConferenceHosts();
+ Collection<String> hosts =
+ ((XmppActivity) activity).xmppConnectionService.getKnownConferenceHosts();
this.knownHostsAdapter.refresh(hosts);
}
}
@@ -271,8 +287,8 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
try {
mListener = (CreatePublicChannelDialogListener) context;
} catch (ClassCastException e) {
- throw new ClassCastException(context.toString()
- + " must implement CreateConferenceDialogListener");
+ throw new ClassCastException(
+ context.toString() + " must implement CreateConferenceDialogListener");
}
}
@@ -280,7 +296,8 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
public void onStart() {
super.onStart();
final Activity activity = getActivity();
- if (activity instanceof XmppActivity && ((XmppActivity) activity).xmppConnectionService != null) {
+ if (activity instanceof XmppActivity
+ && ((XmppActivity) activity).xmppConnectionService != null) {
refreshKnownHosts();
}
}
@@ -32,13 +32,11 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.Lifecycle;
-
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
@@ -100,13 +98,9 @@ import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
import okhttp3.HttpUrl;
-
+import okhttp3.HttpUrl;
+import org.openintents.openpgp.util.OpenPgpUtils;
import org.openintents.openpgp.util.OpenPgpUtils;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
public class EditAccountActivity extends OmemoActivity
implements OnAccountUpdate,
@@ -165,8 +159,7 @@ public class EditAccountActivity extends OmemoActivity
new Intent(
getApplicationContext(),
PublishProfilePictureActivity.class);
- intent.putExtra(
- EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toString());
startActivity(intent);
}
}
@@ -285,12 +278,12 @@ public class EditAccountActivity extends OmemoActivity
try {
if (mUsernameMode) {
jid =
- Jid.ofEscaped(
+ Jid.of(
binding.accountJid.getText().toString(),
getUserModeDomain(),
null);
} else {
- jid = Jid.ofEscaped(binding.accountJid.getText().toString());
+ jid = Jid.ofUserInput(binding.accountJid.getText().toString());
Resolver.checkDomain(jid);
}
} catch (final NullPointerException | IllegalArgumentException e) {
@@ -564,14 +557,13 @@ public class EditAccountActivity extends OmemoActivity
getApplicationContext(), StartConversationActivity.class);
intent.putExtra("init", true);
intent.putExtra(
- EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
+ EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toString());
} else {
intent =
new Intent(
getApplicationContext(),
PublishProfilePictureActivity.class);
- intent.putExtra(
- EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toString());
intent.putExtra("setup", true);
}
if (wasFirstAccount) {
@@ -731,9 +723,9 @@ public class EditAccountActivity extends OmemoActivity
protected boolean jidEdited() {
final String unmodified;
if (mUsernameMode) {
- unmodified = this.mAccount.getJid().getEscapedLocal();
+ unmodified = this.mAccount.getJid().getLocal();
} else {
- unmodified = this.mAccount.getJid().asBareJid().toEscapedString();
+ unmodified = this.mAccount.getJid().asBareJid().toString();
}
return !unmodified.equals(this.binding.accountJid.getText().toString());
}
@@ -890,7 +882,7 @@ public class EditAccountActivity extends OmemoActivity
final Intent intent = getIntent();
if (intent != null) {
try {
- this.jidToEdit = Jid.ofEscaped(intent.getStringExtra("jid"));
+ this.jidToEdit = Jid.of(intent.getStringExtra("jid"));
} catch (final IllegalArgumentException | NullPointerException ignored) {
this.jidToEdit = null;
}
@@ -990,8 +982,7 @@ public class EditAccountActivity extends OmemoActivity
@Override
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
if (mAccount != null) {
- savedInstanceState.putString(
- "account", mAccount.getJid().asBareJid().toEscapedString());
+ savedInstanceState.putString("account", mAccount.getJid().asBareJid().toString());
savedInstanceState.putBoolean("initMode", mInitMode);
savedInstanceState.putBoolean(
"showMoreTable", binding.serverInfoMore.getVisibility() == View.VISIBLE);
@@ -1004,8 +995,7 @@ public class EditAccountActivity extends OmemoActivity
if (mSavedInstanceAccount != null) {
try {
this.mAccount =
- xmppConnectionService.findAccountByJid(
- Jid.ofEscaped(mSavedInstanceAccount));
+ xmppConnectionService.findAccountByJid(Jid.of(mSavedInstanceAccount));
this.mInitMode = mSavedInstanceInit;
init = false;
} catch (IllegalArgumentException e) {
@@ -1071,7 +1061,7 @@ public class EditAccountActivity extends OmemoActivity
break;
case R.id.action_show_block_list:
final Intent showBlocklistIntent = new Intent(this, BlocklistActivity.class);
- showBlocklistIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toEscapedString());
+ showBlocklistIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
startActivity(showBlocklistIntent);
break;
case R.id.action_server_info_show_more:
@@ -1146,7 +1136,7 @@ public class EditAccountActivity extends OmemoActivity
private void openChangePassword(boolean didUnlock) {
final Intent changePasswordIntent = new Intent(this, ChangePasswordActivity.class);
- changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toEscapedString());
+ changePasswordIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString());
changePasswordIntent.putExtra("did_unlock", didUnlock);
startActivity(changePasswordIntent);
}
@@ -1264,15 +1254,12 @@ public class EditAccountActivity extends OmemoActivity
if (init) {
this.binding.accountJid.getEditableText().clear();
if (mUsernameMode) {
- this.binding
- .accountJid
- .getEditableText()
- .append(this.mAccount.getJid().getEscapedLocal());
+ this.binding.accountJid.getEditableText().append(this.mAccount.getJid().getLocal());
} else {
this.binding
.accountJid
.getEditableText()
- .append(this.mAccount.getJid().asBareJid().toEscapedString());
+ .append(this.mAccount.getJid().asBareJid().toString());
}
this.binding.accountPassword.getEditableText().clear();
this.binding.accountPassword.getEditableText().append(this.mAccount.getPassword());
@@ -129,10 +129,15 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final var arguments = getArguments();
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+ final MaterialAlertDialogBuilder builder =
+ new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(arguments.getString(TITLE_KEY));
binding =
- DataBindingUtil.inflate(requireActivity().getLayoutInflater(), R.layout.dialog_enter_jid, null, false);
+ DataBindingUtil.inflate(
+ requireActivity().getLayoutInflater(),
+ R.layout.dialog_enter_jid,
+ null,
+ false);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
binding.jid.setAdapter(this.knownHostsAdapter);
binding.jid.addTextChangedListener(this);
@@ -162,7 +167,8 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
binding.account);
} else {
final ArrayAdapter<String> adapter =
- new ArrayAdapter<>(requireActivity(), R.layout.item_autocomplete, new String[] {account});
+ new ArrayAdapter<>(
+ requireActivity(), R.layout.item_autocomplete, new String[] {account});
binding.account.setText(account);
binding.account.setEnabled(false);
adapter.setDropDownViewResource(R.layout.item_autocomplete);
@@ -229,7 +235,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
protected Jid accountJid() {
try {
- return Jid.ofEscaped((String) binding.account.getEditableText().toString());
+ return Jid.of((String) binding.account.getEditableText().toString());
} catch (final IllegalArgumentException e) {
return null;
}
@@ -256,7 +262,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
Jid contactJid = null;
try {
- contactJid = Jid.ofEscaped(jidString);
+ contactJid = Jid.of(jidString);
} catch (final IllegalArgumentException e) {
binding.jidLayout.setError(getActivity().getString(R.string.invalid_jid));
return;
@@ -269,7 +275,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
issuedWarning = true;
return;
}
- if (sanityCheckJid != SanityCheck.ALLOW_MUC && suspiciousSubDomain(contactJid.getDomain().toEscapedString())) {
+ if (sanityCheckJid != SanityCheck.ALLOW_MUC && suspiciousSubDomain(contactJid.getDomain().toString())) {
binding.jidLayout.setError(getActivity().getString(R.string.this_looks_like_channel));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
@@ -3,11 +3,7 @@ package eu.siacs.conversations.ui;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-
import androidx.databinding.DataBindingUtil;
-
-import java.util.List;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityMediaBrowserBinding;
import eu.siacs.conversations.entities.Account;
@@ -18,6 +14,7 @@ import eu.siacs.conversations.ui.interfaces.OnMediaLoaded;
import eu.siacs.conversations.ui.util.Attachment;
import eu.siacs.conversations.ui.util.GridManager;
import eu.siacs.conversations.xmpp.Jid;
+import java.util.List;
public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded {
@@ -28,20 +25,17 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- this.binding = DataBindingUtil.setContentView(this,R.layout.activity_media_browser);
+ this.binding = DataBindingUtil.setContentView(this, R.layout.activity_media_browser);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
this.binding.media.setAdapter(mMediaAdapter);
GridManager.setupLayoutManager(this, this.binding.media, R.dimen.browser_media_size);
-
}
@Override
- protected void refreshUiReal() {
-
- }
+ protected void refreshUiReal() {}
@Override
protected void onBackendConnected() {
@@ -49,29 +43,30 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded
String account = intent == null ? null : intent.getStringExtra("account");
String jid = intent == null ? null : intent.getStringExtra("jid");
if (account != null && jid != null) {
- xmppConnectionService.getAttachments(account, Jid.ofEscaped(jid), 0, this);
+ xmppConnectionService.getAttachments(account, Jid.of(jid), 0, this);
}
}
public static void launch(Context context, Contact contact) {
- launch(context, contact.getAccount(), contact.getJid().asBareJid().toEscapedString());
+ launch(context, contact.getAccount(), contact.getJid().asBareJid().toString());
}
public static void launch(Context context, Conversation conversation) {
- launch(context, conversation.getAccount(), conversation.getJid().asBareJid().toEscapedString());
+ launch(context, conversation.getAccount(), conversation.getJid().asBareJid().toString());
}
private static void launch(Context context, Account account, String jid) {
final Intent intent = new Intent(context, MediaBrowserActivity.class);
- intent.putExtra("account",account.getUuid());
- intent.putExtra("jid",jid);
+ intent.putExtra("account", account.getUuid());
+ intent.putExtra("jid", jid);
context.startActivity(intent);
}
@Override
public void onMediaLoaded(List<Attachment> attachments) {
- runOnUiThread(()->{
- mMediaAdapter.setAttachments(attachments);
- });
+ runOnUiThread(
+ () -> {
+ mMediaAdapter.setAttachments(attachments);
+ });
}
}
@@ -64,8 +64,7 @@ public class PublishProfilePictureActivity extends XmppActivity
getApplicationContext(), StartConversationActivity.class);
StartConversationActivity.addInviteUri(intent, getIntent());
intent.putExtra("init", true);
- intent.putExtra(
- EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
startActivity(intent);
}
Toast.makeText(
@@ -119,8 +118,7 @@ public class PublishProfilePictureActivity extends XmppActivity
intent.putExtra("init", true);
StartConversationActivity.addInviteUri(intent, getIntent());
if (account != null) {
- intent.putExtra(
- EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
}
startActivity(intent);
}
@@ -16,34 +16,29 @@ import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
-
-import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
-
+import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableSet;
-
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityRecordingBinding;
+import eu.siacs.conversations.utils.TimeFrameUtils;
import java.io.File;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.Set;
-
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivityRecordingBinding;
-import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.utils.TimeFrameUtils;
public class RecordingActivity extends BaseActivity implements View.OnClickListener {
private ActivityRecordingBinding binding;
private MediaRecorder mRecorder;
- private long mStartTime = 0;
+ private Stopwatch stopwatch;
private final CountDownLatch outputFileWrittenLatch = new CountDownLatch(1);
@@ -65,17 +60,48 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_recording);
+ this.binding.timer.setOnClickListener(
+ v -> {
+ onPauseContinue();
+ });
this.binding.cancelButton.setOnClickListener(this);
this.binding.shareButton.setOnClickListener(this);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
+
+ private void onPauseContinue() {
+ final var recorder = this.mRecorder;
+ final var stopwatch = this.stopwatch;
+ if (recorder == null
+ || stopwatch == null
+ || Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ return;
+ }
+ if (stopwatch.isRunning()) {
+ try {
+ recorder.pause();
+ stopwatch.stop();
+ } catch (final IllegalStateException e) {
+ Log.d(Config.LOGTAG, "could not pause recording", e);
+ }
+ } else {
+ try {
+ recorder.resume();
+ stopwatch.start();
+ } catch (final IllegalStateException e) {
+ Log.d(Config.LOGTAG, "could not resume recording", e);
+ }
+ }
+ }
+
@Override
public void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
- this.binding.timer.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
+ this.binding.timer.setTextAppearance(
+ com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
// TODO reset font family. make red?
this.binding.timer.setText(R.string.unable_to_start_recording);
}
@@ -99,23 +125,32 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
private static final Set<String> AAC_SENSITIVE_DEVICES =
new ImmutableSet.Builder<String>()
- .add("FP4") // Fairphone 4 https://codeberg.org/monocles/monocles_chat/issues/133
- .add("ONEPLUS A6000") // OnePlus 6 https://github.com/iNPUTmice/Conversations/issues/4329
- .add("ONEPLUS A6003") // OnePlus 6 https://github.com/iNPUTmice/Conversations/issues/4329
- .add("ONEPLUS A6010") // OnePlus 6T https://codeberg.org/monocles/monocles_chat/issues/133
- .add("ONEPLUS A6013") // OnePlus 6T https://codeberg.org/monocles/monocles_chat/issues/133
- .add("Pixel 4a") // Pixel 4a https://github.com/iNPUTmice/Conversations/issues/4223
- .add("WP12 Pro") // Oukitel WP 12 Pro https://github.com/iNPUTmice/Conversations/issues/4223
- .add("Volla Phone X") // Volla Phone X https://github.com/iNPUTmice/Conversations/issues/4223
+ .add("FP4") // Fairphone 4
+ // https://codeberg.org/monocles/monocles_chat/issues/133
+ .add("ONEPLUS A6000") // OnePlus 6
+ // https://github.com/iNPUTmice/Conversations/issues/4329
+ .add("ONEPLUS A6003") // OnePlus 6
+ // https://github.com/iNPUTmice/Conversations/issues/4329
+ .add("ONEPLUS A6010") // OnePlus 6T
+ // https://codeberg.org/monocles/monocles_chat/issues/133
+ .add("ONEPLUS A6013") // OnePlus 6T
+ // https://codeberg.org/monocles/monocles_chat/issues/133
+ .add("Pixel 4a") // Pixel 4a
+ // https://github.com/iNPUTmice/Conversations/issues/4223
+ .add("WP12 Pro") // Oukitel WP 12 Pro
+ // https://github.com/iNPUTmice/Conversations/issues/4223
+ .add("Volla Phone X") // Volla Phone X
+ // https://github.com/iNPUTmice/Conversations/issues/4223
.build();
private boolean startRecording() {
mRecorder = new MediaRecorder();
final String userChosenCodec = getPreferences().getString("voice_message_codec", "");
+ stopwatch = Stopwatch.createUnstarted();
try {
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
} catch (final RuntimeException e) {
- Log.e(Config.LOGTAG,"could not set audio source", e);
+ Log.e(Config.LOGTAG, "could not set audio source", e);
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -131,8 +166,10 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
} else if ("mpeg4".equals(userChosenCodec) || !Config.USE_OPUS_VOICE_MESSAGES) {
outputFormat = MediaRecorder.OutputFormat.MPEG_4;
mRecorder.setOutputFormat(outputFormat);
- if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL) && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
- // Changing these three settings for AAC sensitive devices for Android<=13 might lead to sporadically truncated (cut-off) voice messages.
+ if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL)
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
+ // Changing these three settings for AAC sensitive devices for Android<=13 might
+ // lead to sporadically truncated (cut-off) voice messages.
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
mRecorder.setAudioSamplingRate(24_000);
mRecorder.setAudioEncodingBitRate(28_000);
@@ -154,7 +191,7 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
try {
mRecorder.prepare();
mRecorder.start();
- mStartTime = SystemClock.elapsedRealtime();
+ stopwatch.start();
mHandler.postDelayed(mTickExecutor, 100);
Log.d(Config.LOGTAG, "started recording to " + mOutputFile.getAbsolutePath());
return true;
@@ -168,14 +205,17 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
try {
mRecorder.stop();
mRecorder.release();
- } catch (Exception e) {
+ if (stopwatch.isRunning()) {
+ stopwatch.stop();
+ }
+ } catch (final Exception e) {
+ Log.d(Config.LOGTAG, "could not save recording", e);
if (saveFile) {
Toast.makeText(this, R.string.unable_to_save_recording, Toast.LENGTH_SHORT).show();
return;
}
} finally {
mRecorder = null;
- mStartTime = 0;
}
if (!saveFile && mOutputFile != null) {
if (mOutputFile.delete()) {
@@ -272,24 +312,23 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
}
private void tick() {
- this.binding.timer.setText(TimeFrameUtils.formatTimePassed(mStartTime, true));
+ this.binding.timer.setText(
+ TimeFrameUtils.formatElapsedTime(stopwatch.elapsed(TimeUnit.MILLISECONDS), true));
}
@Override
public void onClick(final View view) {
- switch (view.getId()) {
- case R.id.cancel_button:
- mHandler.removeCallbacks(mTickExecutor);
- stopRecording(false);
- setResult(RESULT_CANCELED);
- finish();
- break;
- case R.id.share_button:
- this.binding.shareButton.setEnabled(false);
- this.binding.shareButton.setText(R.string.please_wait);
- mHandler.removeCallbacks(mTickExecutor);
- mHandler.postDelayed(() -> stopRecording(true), 500);
- break;
+ if (view.getId() == R.id.cancel_button) {
+ mHandler.removeCallbacks(mTickExecutor);
+ stopRecording(false);
+ setResult(RESULT_CANCELED);
+ finish();
+ } else if (view.getId() == R.id.share_button) {
+ this.binding.timer.setOnClickListener(null);
+ this.binding.shareButton.setEnabled(false);
+ this.binding.shareButton.setText(R.string.please_wait);
+ mHandler.removeCallbacks(mTickExecutor);
+ mHandler.postDelayed(() -> stopRecording(true), 500);
}
}
}
@@ -1,7 +1,6 @@
package eu.siacs.conversations.ui;
import static eu.siacs.conversations.utils.PermissionUtils.getFirstDenied;
-
import static java.util.Arrays.asList;
import android.Manifest;
@@ -25,13 +24,11 @@ import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -78,16 +75,6 @@ import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
-import org.webrtc.RendererCommon;
-import org.webrtc.SurfaceViewRenderer;
-import org.webrtc.VideoTrack;
-
-import java.lang.ref.WeakReference;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
public class RtpSessionActivity extends XmppActivity
implements XmppConnectionService.OnJingleRtpConnectionUpdate,
eu.siacs.conversations.ui.widget.SurfaceViewRenderer.OnAspectRatioChanged {
@@ -350,7 +337,7 @@ public class RtpSessionActivity extends XmppActivity
final String action = intent.getAction();
final String lastAction = intent.getStringExtra(EXTRA_LAST_ACTION);
final Account account = extractAccount(intent);
- final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
+ final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
final String state = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE);
if (!Intent.ACTION_VIEW.equals(action)
|| state == null
@@ -554,7 +541,7 @@ public class RtpSessionActivity extends XmppActivity
Log.d(Config.LOGTAG, "initializeWithIntent(" + event + "," + action + ")");
final Account account = extractAccount(intent);
final var extraWith = intent.getStringExtra(EXTRA_WITH);
- final Jid with = Strings.isNullOrEmpty(extraWith) ? null : Jid.ofEscaped(extraWith);
+ final Jid with = Strings.isNullOrEmpty(extraWith) ? null : Jid.of(extraWith);
if (with == null || account == null) {
Log.e(Config.LOGTAG, "intent is missing extras (account or with)");
return;
@@ -623,7 +610,7 @@ public class RtpSessionActivity extends XmppActivity
binding.with.setText(contact.getDisplayName());
if (Arrays.asList(RtpEndUserState.INCOMING_CALL, RtpEndUserState.ACCEPTING_CALL)
.contains(state)) {
- binding.withJid.setText(contact.getJid().asBareJid().toEscapedString());
+ binding.withJid.setText(contact.getJid().asBareJid().toString());
binding.withJid.setVisibility(View.VISIBLE);
} else {
binding.withJid.setVisibility(View.GONE);
@@ -825,9 +812,9 @@ public class RtpSessionActivity extends XmppActivity
.getJingleConnectionManager()
.getTerminalSessionState(with, sessionId);
if (terminatedRtpSession == null) {
- Log.e(Config.LOGTAG, "failed to initialize activity with running rtp session. session not found");
- finish();
- return true;
+ throw new IllegalStateException(
+ "failed to initialize activity with running rtp session. session not"
+ + " found");
}
initializeWithTerminatedSessionState(account, with, terminatedRtpSession);
return true;
@@ -888,8 +875,8 @@ public class RtpSessionActivity extends XmppActivity
private void resetIntent(final Account account, final Jid with, final String sessionId) {
final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
- intent.putExtra(EXTRA_WITH, with.toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().toString());
+ intent.putExtra(EXTRA_WITH, with.toString());
intent.putExtra(EXTRA_SESSION_ID, sessionId);
setIntent(intent);
}
@@ -946,10 +933,12 @@ public class RtpSessionActivity extends XmppActivity
case RETRACTED -> setTitle(R.string.rtp_state_retracted);
case APPLICATION_ERROR -> setTitle(R.string.rtp_state_application_failure);
case SECURITY_ERROR -> setTitle(R.string.rtp_state_security_error);
- case ENDED -> throw new IllegalStateException(
- "Activity should have called finishAndReleaseWakeLock();");
- default -> throw new IllegalStateException(
- String.format("State %s has not been handled in UI", state));
+ case ENDED ->
+ throw new IllegalStateException(
+ "Activity should have called finishAndReleaseWakeLock();");
+ default ->
+ throw new IllegalStateException(
+ String.format("State %s has not been handled in UI", state));
}
}
@@ -983,9 +972,7 @@ public class RtpSessionActivity extends XmppActivity
final Account account = contact == null ? getWith().getAccount() : contact.getAccount();
binding.usingAccount.setVisibility(View.VISIBLE);
binding.usingAccount.setText(
- getString(
- R.string.using_account,
- account.getJid().asBareJid().toEscapedString()));
+ getString(R.string.using_account, account.getJid().asBareJid().toString()));
} else {
binding.usingAccount.setVisibility(View.GONE);
binding.contactPhoto.setVisibility(View.GONE);
@@ -1481,12 +1468,12 @@ public class RtpSessionActivity extends XmppActivity
private void retry(final View view) {
final Intent intent = getIntent();
final Account account = extractAccount(intent);
- final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
+ final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
final String lastAction = intent.getStringExtra(EXTRA_LAST_ACTION);
final String action = intent.getAction();
final Set<Media> media = actionToMedia(lastAction == null ? action : lastAction);
this.rtpConnectionReference = null;
- Log.d(Config.LOGTAG, "attempting retry with " + with.toEscapedString());
+ Log.d(Config.LOGTAG, "attempting retry with " + with.toString());
CallIntegrationConnectionService.placeCall(xmppConnectionService, account, with, media);
}
@@ -1497,7 +1484,7 @@ public class RtpSessionActivity extends XmppActivity
private void recordVoiceMail(final View view) {
final Intent intent = getIntent();
final Account account = extractAccount(intent);
- final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
+ final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
final Conversation conversation =
xmppConnectionService.findOrCreateConversation(account, with, false, true);
final Intent launchIntent = new Intent(this, ConversationsActivity.class);
@@ -1668,7 +1655,7 @@ public class RtpSessionActivity extends XmppActivity
return;
}
final Set<Media> media = actionToMedia(currentIntent.getStringExtra(EXTRA_LAST_ACTION));
- if (Jid.ofEscaped(withExtra).asBareJid().equals(with)) {
+ if (Jid.of(withExtra).asBareJid().equals(with)) {
runOnUiThread(
() -> {
updateVerifiedShield(false);
@@ -1691,11 +1678,11 @@ public class RtpSessionActivity extends XmppActivity
private void resetIntent(
final Account account, Jid with, final RtpEndUserState state, final Set<Media> media) {
final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().toString());
if (RtpCapability.jmiSupport(account.getRoster().getContact(with))) {
- intent.putExtra(EXTRA_WITH, with.asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_WITH, with.asBareJid().toString());
} else {
- intent.putExtra(EXTRA_WITH, with.toEscapedString());
+ intent.putExtra(EXTRA_WITH, with.toString());
}
intent.putExtra(EXTRA_LAST_REPORTED_STATE, state.toString());
intent.putExtra(
@@ -12,12 +12,16 @@ import androidx.annotation.NonNull;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityShareWithBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.persistance.DatabaseBackend;
+import eu.siacs.conversations.services.ShortcutService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.xmpp.Jid;
@@ -132,10 +136,28 @@ public class ShareWithActivity extends XmppActivity
if (shortcut.isPresent()) {
final var extras = shortcut.get().getExtras();
if (extras == null) {
- return null;
+ return shortcutIdToConversationFallback(shortcutId);
} else {
- return extras.getString(ConversationsActivity.EXTRA_CONVERSATION);
+ final var conversation = extras.getString(ConversationsActivity.EXTRA_CONVERSATION);
+ if (Strings.isNullOrEmpty(conversation)) {
+ return shortcutIdToConversationFallback(shortcutId);
+ } else {
+ return conversation;
+ }
}
+ } else {
+ return shortcutIdToConversationFallback(shortcutId);
+ }
+ }
+
+ private String shortcutIdToConversationFallback(final String shortcutId) {
+ final var parts =
+ Splitter.on(ShortcutService.ID_SEPARATOR).limit(2).splitToList(shortcutId);
+ if (parts.size() == 2) {
+ final var account = Jid.of(parts.get(0));
+ final var jid = Jid.of(parts.get(1));
+ final var database = DatabaseBackend.getInstance(getApplicationContext());
+ return database.findConversationUuid(account, jid);
} else {
return null;
}
@@ -228,7 +250,7 @@ public class ShareWithActivity extends XmppActivity
final Conversation conversation;
Account account;
try {
- account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
+ account = xmppConnectionService.findAccountByJid(Jid.of(share.account));
} catch (final IllegalArgumentException e) {
account = null;
}
@@ -38,7 +38,6 @@ import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
-
import androidx.annotation.MenuRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -66,7 +65,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.leinardi.android.speeddial.SpeedDialActionItem;
import com.leinardi.android.speeddial.SpeedDialView;
-
import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -289,7 +287,7 @@ public class StartConversationActivity extends XmppActivity
if (account != null) {
intent.putExtra(
EXTRA_ACCOUNT_FILTER,
- account.getJid().asBareJid().toEscapedString());
+ account.getJid().asBareJid().toString());
}
if (q != null) {
intent.putExtra(EXTRA_TEXT_FILTER, q);
@@ -410,7 +408,7 @@ public class StartConversationActivity extends XmppActivity
mSearchEditText != null ? mSearchEditText.getText().toString() : null;
final String prefilled;
if (isValidJid(searchString)) {
- prefilled = Jid.ofEscaped(searchString).toEscapedString();
+ prefilled = Jid.of(searchString).toString();
} else {
prefilled = null;
}
@@ -466,14 +464,15 @@ public class StartConversationActivity extends XmppActivity
.create();
speedDialView.addActionItem(actionItem);
}
- speedDialView.setContentDescription(getString(R.string.add_contact_or_create_or_join_group_chat));
+ speedDialView.setContentDescription(
+ getString(R.string.add_contact_or_create_or_join_group_chat));
}
- public static boolean isValidJid(String input) {
+ public static boolean isValidJid(final String input) {
try {
- Jid jid = Jid.ofEscaped(input);
+ final Jid jid = Jid.ofUserInput(input);
return !jid.isDomainJid();
- } catch (IllegalArgumentException e) {
+ } catch (final IllegalArgumentException e) {
return false;
}
}
@@ -555,12 +554,12 @@ public class StartConversationActivity extends XmppActivity
}
protected void shareBookmarkUri() {
- shareAsChannel(this, contextItem.getJid().asBareJid().toEscapedString());
+ shareAsChannel(this, contextItem.getJid().asBareJid().toString());
}
protected void shareBookmarkUri(int position) {
Bookmark bookmark = (Bookmark) conferences.get(position);
- shareAsChannel(this, bookmark.getJid().asBareJid().toEscapedString());
+ shareAsChannel(this, bookmark.getJid().asBareJid().toString());
}
public static void shareAsChannel(final Context context, final String address) {
@@ -600,7 +599,7 @@ public class StartConversationActivity extends XmppActivity
}
protected void showQrForContact() {
- showQrCode("xmpp:" + contextItem.getJid().asBareJid().toEscapedString());
+ showQrCode("xmpp:" + contextItem.getJid().asBareJid().toString());
}
protected void toggleContactBlock() {
@@ -613,8 +612,7 @@ public class StartConversationActivity extends XmppActivity
builder.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.action_delete_contact);
builder.setMessage(
- JidDialog.style(
- this, R.string.remove_contact_text, contact.getJid().toEscapedString()));
+ JidDialog.style(this, R.string.remove_contact_text, contact.getJid().toString()));
builder.setPositiveButton(
R.string.delete,
(dialog, which) -> {
@@ -636,11 +634,10 @@ public class StartConversationActivity extends XmppActivity
JidDialog.style(
this,
R.string.remove_bookmark_and_close,
- bookmark.getJid().toEscapedString()));
+ bookmark.getJid().toString()));
} else {
builder.setMessage(
- JidDialog.style(
- this, R.string.remove_bookmark, bookmark.getJid().toEscapedString()));
+ JidDialog.style(this, R.string.remove_bookmark, bookmark.getJid().toString()));
}
builder.setPositiveButton(
hasConversation ? R.string.delete_and_close : R.string.delete,
@@ -787,7 +784,7 @@ public class StartConversationActivity extends XmppActivity
if (context instanceof XmppActivity) {
final Jid jid;
try {
- jid = Jid.ofEscaped(spinner.getText().toString());
+ jid = Jid.of(spinner.getText().toString());
} catch (final IllegalArgumentException e) {
return null;
}
@@ -1160,7 +1157,7 @@ public class StartConversationActivity extends XmppActivity
if (onboardingAccount == null && account.getJid().getDomain().equals(Config.ONBOARDING_DOMAIN)) onboardingAccount = account;
if (accountJid != null) {
- if(account.getJid().asBareJid().toEscapedString().equals(accountJid)) {
+ if(account.getJid().asBareJid().toString().equals(accountJid)) {
selectedAccount = account;
} else {
continue;
@@ -1251,11 +1248,11 @@ public class StartConversationActivity extends XmppActivity
switchToConversationDoNotAppend(muc, invite.getBody());
return true;
} else {
- showJoinConferenceDialog(invite.getJid().asBareJid().toEscapedString(), invite);
+ showJoinConferenceDialog(invite.getJid().asBareJid().toString(), invite);
return false;
}
- } else if (contacts.size() == 0) {
- showCreateContactDialog(invite.getJid().toEscapedString(), invite);
+ } else if (contacts.isEmpty()) {
+ showCreateContactDialog(invite.getJid().toString(), invite);
return false;
} else if (contacts.size() == 1) {
Contact contact = contacts.get(0);
@@ -1279,10 +1276,10 @@ public class StartConversationActivity extends XmppActivity
if (mMenuSearchView != null) {
mMenuSearchView.expandActionView();
mSearchEditText.setText("");
- mSearchEditText.append(invite.getJid().toEscapedString());
- filter(invite.getJid().toEscapedString());
+ mSearchEditText.append(invite.getJid().toString());
+ filter(invite.getJid().toString());
} else {
- mInitialSearchValue.push(invite.getJid().toEscapedString());
+ mInitialSearchValue.push(invite.getJid().toString());
}
return true;
}
@@ -1298,7 +1295,7 @@ public class StartConversationActivity extends XmppActivity
JidDialog.style(
this,
R.string.verifying_omemo_keys_trusted_source,
- contact.getJid().asBareJid().toEscapedString(),
+ contact.getJid().asBareJid().toString(),
contact.getDisplayName()));
builder.setView(view);
builder.setPositiveButton(
@@ -1329,7 +1326,7 @@ public class StartConversationActivity extends XmppActivity
ArrayList<ListItem.Tag> tags = new ArrayList<>();
final var accounts = new ArrayList<Account>();
for (final var account : xmppConnectionService.getAccounts()) {
- if (mActivatedAccounts.contains(account.getJid().asBareJid().toEscapedString())) accounts.add(account);
+ if (mActivatedAccounts.contains(account.getJid().asBareJid().toString())) accounts.add(account);
}
boolean foundSopranica = false;
for (final Account account : accounts) {
@@ -1454,8 +1451,7 @@ public class StartConversationActivity extends XmppActivity
intent.putExtra(ChooseContactActivity.EXTRA_SELECT_MULTIPLE, true);
intent.putExtra(ChooseContactActivity.EXTRA_GROUP_CHAT_NAME, name.trim());
intent.putExtra(
- ChooseContactActivity.EXTRA_ACCOUNT,
- account.getJid().asBareJid().toEscapedString());
+ ChooseContactActivity.EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
intent.putExtra(ChooseContactActivity.EXTRA_TITLE_RES_ID, R.string.choose_participants);
startActivityForResult(intent, REQUEST_CREATE_CONFERENCE);
}
@@ -1477,13 +1473,13 @@ public class StartConversationActivity extends XmppActivity
final String input = jid.getText().toString().trim();
Jid conferenceJid;
try {
- conferenceJid = Jid.ofEscaped(input);
+ conferenceJid = Jid.ofUserInput(input);
} catch (final IllegalArgumentException e) {
final XmppUri xmppUri = new XmppUri(input);
if (xmppUri.isValidJid() && xmppUri.isAction(XmppUri.ACTION_JOIN)) {
final Editable editable = jid.getEditableText();
editable.clear();
- editable.append(xmppUri.getJid().toEscapedString());
+ editable.append(xmppUri.getJid().toString());
conferenceJid = xmppUri.getJid();
} else {
layout.setError(getString(R.string.invalid_jid));
@@ -1,6 +1,5 @@
package eu.siacs.conversations.ui;
-import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -10,12 +9,9 @@ import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
-
import androidx.appcompat.app.ActionBar;
import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OmemoSetting;
@@ -32,433 +28,515 @@ import eu.siacs.conversations.utils.IrregularUnicodeDetector;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
-
-import org.whispersystems.libsignal.IdentityKey;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.whispersystems.libsignal.IdentityKey;
public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdated {
- private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
- private final Map<Jid, Map<String, Boolean>> foreignKeysToTrust = new HashMap<>();
- private final OnClickListener mCancelButtonListener = v -> {
- setResult(RESULT_CANCELED);
- finish();
- };
- private List<Jid> contactJids;
- private Account mAccount;
- private Conversation mConversation;
- private final OnClickListener mSaveButtonListener = v -> {
- commitTrusts();
- finishOk(false);
- };
- private final AtomicBoolean mUseCameraHintShown = new AtomicBoolean(false);
- private AxolotlService.FetchStatus lastFetchReport = AxolotlService.FetchStatus.SUCCESS;
- private Toast mUseCameraHintToast = null;
- private ActivityTrustKeysBinding binding;
-
- @Override
- protected void refreshUiReal() {
- invalidateOptionsMenu();
- populateView();
- }
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.binding = DataBindingUtil.setContentView(this, R.layout.activity_trust_keys);
- Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
- this.contactJids = new ArrayList<>();
- final var intent = getIntent();
- final String[] contacts = intent == null ? null : intent.getStringArrayExtra("contacts");
- for (final String jid : (contacts == null ? new String[0] : contacts)) {
- try {
- this.contactJids.add(Jid.of(jid));
- } catch (final IllegalArgumentException ignored) {
- }
- }
-
- binding.cancelButton.setOnClickListener(mCancelButtonListener);
- binding.saveButton.setOnClickListener(mSaveButtonListener);
-
- setSupportActionBar(binding.toolbar);
- configureActionBar(getSupportActionBar());
-
- if (savedInstanceState != null) {
- mUseCameraHintShown.set(savedInstanceState.getBoolean("camera_hint_shown", false));
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle savedInstanceState) {
- savedInstanceState.putBoolean("camera_hint_shown", mUseCameraHintShown.get());
- super.onSaveInstanceState(savedInstanceState);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.trust_keys, menu);
- MenuItem scanQrCode = menu.findItem(R.id.action_scan_qr_code);
- scanQrCode.setVisible((!ownKeysToTrust.isEmpty() || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
- return super.onCreateOptionsMenu(menu);
- }
-
- private void showCameraToast() {
- mUseCameraHintToast = Toast.makeText(this, R.string.use_camera_icon_to_scan_barcode, Toast.LENGTH_LONG);
- ActionBar actionBar = getSupportActionBar();
- mUseCameraHintToast.setGravity(Gravity.TOP | Gravity.END, 0, actionBar == null ? 0 : actionBar.getHeight());
- mUseCameraHintToast.show();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_scan_qr_code:
- if (hasPendingKeyFetches()) {
- Toast.makeText(this, R.string.please_wait_for_keys_to_be_fetched, Toast.LENGTH_SHORT).show();
- } else {
- ScanActivity.scan(this);
- //new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
- return true;
- }
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (mUseCameraHintToast != null) {
- mUseCameraHintToast.cancel();
- }
- }
-
- @Override
- protected void processFingerprintVerification(XmppUri uri) {
- if (mConversation != null
- && mAccount != null
- && uri.hasFingerprints()
- && mAccount.getAxolotlService().getCryptoTargets(mConversation).contains(uri.getJid())) {
- boolean performedVerification = xmppConnectionService.verifyFingerprints(mAccount.getRoster().getContact(uri.getJid()), uri.getFingerprints());
- boolean keys = reloadFingerprints();
- if (performedVerification && !keys && !hasNoOtherTrustedKeys() && !hasPendingKeyFetches()) {
- Toast.makeText(this, R.string.all_omemo_keys_have_been_verified, Toast.LENGTH_SHORT).show();
- finishOk(false);
- return;
- } else if (performedVerification) {
- Toast.makeText(this, R.string.verified_fingerprints, Toast.LENGTH_SHORT).show();
- }
- } else {
- reloadFingerprints();
- Log.d(Config.LOGTAG, "xmpp uri was: " + uri.getJid() + " has Fingerprints: " + uri.hasFingerprints());
- Toast.makeText(this, R.string.barcode_does_not_contain_fingerprints_for_this_chat, Toast.LENGTH_SHORT).show();
- }
- populateView();
- }
-
- private void populateView() {
- if (this.mAccount == null) {
- return;
- }
-
- setTitle(getString(R.string.trust_omemo_fingerprints));
- binding.ownKeysDetails.removeAllViews();
- binding.foreignKeys.removeAllViews();
- boolean hasOwnKeys = false;
- boolean hasForeignKeys = false;
- for (final String fingerprint : ownKeysToTrust.keySet()) {
- hasOwnKeys = true;
- addFingerprintRowWithListeners(binding.ownKeysDetails, mAccount, fingerprint, false,
- FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)), false, false,
- (buttonView, isChecked) -> {
- ownKeysToTrust.put(fingerprint, isChecked);
- // own fingerprints have no impact on locked status.
- }
- );
- }
-
- synchronized (this.foreignKeysToTrust) {
- for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
- hasForeignKeys = true;
- KeysCardBinding keysCardBinding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.keys_card, binding.foreignKeys, false);
- final Jid jid = entry.getKey();
- keysCardBinding.foreignKeysTitle.setText(IrregularUnicodeDetector.style(this, jid));
- keysCardBinding.foreignKeysTitle.setOnClickListener(v -> switchToContactDetails(mAccount.getRoster().getContact(jid)));
- final Map<String, Boolean> fingerprints = entry.getValue();
- for (final String fingerprint : fingerprints.keySet()) {
- addFingerprintRowWithListeners(keysCardBinding.foreignKeysDetails, mAccount, fingerprint, false,
- FingerprintStatus.createActive(fingerprints.get(fingerprint)), false, false,
- (buttonView, isChecked) -> {
- fingerprints.put(fingerprint, isChecked);
- lockOrUnlockAsNeeded();
- }
- );
- }
- if (fingerprints.isEmpty()) {
- keysCardBinding.noKeysToAccept.setVisibility(View.VISIBLE);
- if (hasNoOtherTrustedKeys(jid)) {
- if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
- keysCardBinding.noKeysToAccept.setText(R.string.error_no_keys_to_trust_presence);
- } else {
- keysCardBinding.noKeysToAccept.setText(R.string.error_no_keys_to_trust_server_error);
- }
- } else {
- keysCardBinding.noKeysToAccept.setText(getString(R.string.no_keys_just_confirm, mAccount.getRoster().getContact(jid).getDisplayName()));
- }
- } else {
- keysCardBinding.noKeysToAccept.setVisibility(View.GONE);
- }
- binding.foreignKeys.addView(keysCardBinding.foreignKeysCard);
- }
- }
-
- if ((hasOwnKeys || foreignActuallyHasKeys()) && isCameraFeatureAvailable() && mUseCameraHintShown.compareAndSet(false, true)) {
- showCameraToast();
- }
-
- binding.ownKeysTitle.setText(mAccount.getJid().asBareJid().toEscapedString());
- binding.ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE);
- binding.foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE);
- if (hasPendingKeyFetches()) {
- setFetching();
- lock();
- } else {
- if (!hasForeignKeys && hasNoOtherTrustedKeys()) {
- binding.keyErrorMessageCard.setVisibility(View.VISIBLE);
- boolean lastReportWasError = lastFetchReport == AxolotlService.FetchStatus.ERROR;
- boolean errorFetchingBundle = mAccount.getAxolotlService().fetchMapHasErrors(contactJids);
- boolean errorFetchingDeviceList = mAccount.getAxolotlService().hasErrorFetchingDeviceList(contactJids);
- boolean anyWithoutMutualPresenceSubscription = anyWithoutMutualPresenceSubscription(contactJids);
- if (errorFetchingDeviceList) {
- binding.keyErrorMessage.setVisibility(View.VISIBLE);
- binding.keyErrorMessage.setText(R.string.error_trustkey_device_list);
- } else if (errorFetchingBundle || lastReportWasError) {
- binding.keyErrorMessage.setVisibility(View.VISIBLE);
- binding.keyErrorMessage.setText(R.string.error_trustkey_bundle);
- } else {
- binding.keyErrorMessage.setVisibility(View.GONE);
- }
- this.binding.keyErrorHintMutual.setVisibility(anyWithoutMutualPresenceSubscription ? View.VISIBLE : View.GONE);
- Contact contact = mAccount.getRoster().getContact(contactJids.get(0));
- binding.keyErrorGeneral.setText(getString(R.string.error_trustkey_general, getString(R.string.app_name), contact.getDisplayName()));
- binding.ownKeysDetails.removeAllViews();
- if (OmemoSetting.isAlways()) {
- binding.disableButton.setVisibility(View.GONE);
- } else {
- binding.disableButton.setVisibility(View.VISIBLE);
- binding.disableButton.setOnClickListener(this::disableEncryptionDialog);
- }
- binding.ownKeysCard.setVisibility(View.GONE);
- binding.foreignKeys.removeAllViews();
- binding.foreignKeys.setVisibility(View.GONE);
- }
- lockOrUnlockAsNeeded();
- setDone();
- }
- }
-
- private void disableEncryptionDialog(final View view) {
- final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
- builder.setTitle(R.string.disable_encryption);
- builder.setMessage(R.string.disable_encryption_message);
- builder.setPositiveButton(R.string.disable_now, (dialog, which) -> {
- mConversation.setNextEncryption(Message.ENCRYPTION_NONE);
- xmppConnectionService.updateConversation(mConversation);
- finishOk(true);
- });
- builder.setNegativeButton(R.string.cancel, null);
- builder.create().show();
- }
-
- private boolean anyWithoutMutualPresenceSubscription(List<Jid> contactJids) {
- for (Jid jid : contactJids) {
- if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean foreignActuallyHasKeys() {
- synchronized (this.foreignKeysToTrust) {
- for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
- if (!entry.getValue().isEmpty()) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean reloadFingerprints() {
- List<Jid> acceptedTargets = mConversation == null ? new ArrayList<>() : mConversation.getAcceptedCryptoTargets();
- ownKeysToTrust.clear();
- if (this.mAccount == null) {
- return false;
- }
- AxolotlService service = this.mAccount.getAxolotlService();
- Set<IdentityKey> ownKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided());
- for (final IdentityKey identityKey : ownKeysSet) {
- final String fingerprint = CryptoHelper.bytesToHex(identityKey.getPublicKey().serialize());
- if (!ownKeysToTrust.containsKey(fingerprint)) {
- ownKeysToTrust.put(fingerprint, false);
- }
- }
- synchronized (this.foreignKeysToTrust) {
- foreignKeysToTrust.clear();
- for (Jid jid : contactJids) {
- Set<IdentityKey> foreignKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), jid);
- if (hasNoOtherTrustedKeys(jid) && ownKeysSet.isEmpty()) {
- foreignKeysSet.addAll(service.getKeysWithTrust(FingerprintStatus.createActive(false), jid));
- }
- Map<String, Boolean> foreignFingerprints = new HashMap<>();
- for (final IdentityKey identityKey : foreignKeysSet) {
- final String fingerprint = CryptoHelper.bytesToHex(identityKey.getPublicKey().serialize());
- if (!foreignFingerprints.containsKey(fingerprint)) {
- foreignFingerprints.put(fingerprint, false);
- }
- }
- if (!foreignFingerprints.isEmpty() || !acceptedTargets.contains(jid)) {
- foreignKeysToTrust.put(jid, foreignFingerprints);
- }
- }
- }
- return ownKeysSet.size() + foreignKeysToTrust.size() > 0;
- }
-
- public void onBackendConnected() {
- Intent intent = getIntent();
- this.mAccount = extractAccount(intent);
- if (this.mAccount != null && intent != null) {
- String uuid = intent.getStringExtra("conversation");
- this.mConversation = xmppConnectionService.findConversationByUuid(uuid);
- if (this.mPendingFingerprintVerificationUri != null) {
- processFingerprintVerification(this.mPendingFingerprintVerificationUri);
- this.mPendingFingerprintVerificationUri = null;
- } else {
- final boolean keysToTrust = reloadFingerprints();
- if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) {
- populateView();
- invalidateOptionsMenu();
- } else {
- finishOk(false);
- }
- }
- }
- }
-
- private boolean hasNoOtherTrustedKeys() {
- return mAccount == null || mAccount.getAxolotlService().anyTargetHasNoTrustedKeys(contactJids);
- }
-
- private boolean hasNoOtherTrustedKeys(Jid contact) {
- return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0;
- }
-
- private boolean hasPendingKeyFetches() {
- return mAccount != null && mAccount.getAxolotlService().hasPendingKeyFetches(contactJids);
- }
-
-
- @Override
- public void onKeyStatusUpdated(final AxolotlService.FetchStatus report) {
- final boolean keysToTrust = reloadFingerprints();
- if (report != null) {
- lastFetchReport = report;
- runOnUiThread(() -> {
- if (mUseCameraHintToast != null && !keysToTrust) {
- mUseCameraHintToast.cancel();
- }
- switch (report) {
- case ERROR:
- Toast.makeText(TrustKeysActivity.this, R.string.error_fetching_omemo_key, Toast.LENGTH_SHORT).show();
- break;
- case SUCCESS_TRUSTED:
- Toast.makeText(TrustKeysActivity.this, R.string.blindly_trusted_omemo_keys, Toast.LENGTH_LONG).show();
- break;
- case SUCCESS_VERIFIED:
- Toast.makeText(TrustKeysActivity.this,
- Config.X509_VERIFICATION ? R.string.verified_omemo_key_with_certificate : R.string.all_omemo_keys_have_been_verified,
- Toast.LENGTH_LONG).show();
- break;
- }
- });
-
- }
- if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) {
- refreshUi();
- } else {
- runOnUiThread(() -> finishOk(false));
-
- }
- }
-
- private void finishOk(boolean disabled) {
- Intent data = new Intent();
- data.putExtra("choice", getIntent().getIntExtra("choice", ConversationFragment.ATTACHMENT_CHOICE_INVALID));
- data.putExtra("disabled", disabled);
- setResult(RESULT_OK, data);
- finish();
- }
-
- private void commitTrusts() {
- for (final String fingerprint : ownKeysToTrust.keySet()) {
- mAccount.getAxolotlService().setFingerprintTrust(
- fingerprint,
- FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)));
- }
- List<Jid> acceptedTargets = mConversation == null ? new ArrayList<>() : mConversation.getAcceptedCryptoTargets();
- synchronized (this.foreignKeysToTrust) {
- for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
- Jid jid = entry.getKey();
- Map<String, Boolean> value = entry.getValue();
- if (!acceptedTargets.contains(jid)) {
- acceptedTargets.add(jid);
- }
- for (final String fingerprint : value.keySet()) {
- mAccount.getAxolotlService().setFingerprintTrust(
- fingerprint,
- FingerprintStatus.createActive(value.get(fingerprint)));
- }
- }
- }
- if (mConversation != null && mConversation.getMode() == Conversation.MODE_MULTI) {
- mConversation.setAcceptedCryptoTargets(acceptedTargets);
- xmppConnectionService.updateConversation(mConversation);
- }
- }
-
- private void unlock() {
- binding.saveButton.setEnabled(true);
- }
-
- private void lock() {
- binding.saveButton.setEnabled(false);
- }
-
- private void lockOrUnlockAsNeeded() {
- synchronized (this.foreignKeysToTrust) {
- for (Jid jid : contactJids) {
- Map<String, Boolean> fingerprints = foreignKeysToTrust.get(jid);
- if (hasNoOtherTrustedKeys(jid) && (fingerprints == null || !fingerprints.containsValue(true))) {
- lock();
- return;
- }
- }
- }
- unlock();
-
- }
-
- private void setDone() {
- binding.saveButton.setText(getString(R.string.done));
- }
-
- private void setFetching() {
- binding.saveButton.setText(getString(R.string.fetching_keys));
- }
+ private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
+ private final Map<Jid, Map<String, Boolean>> foreignKeysToTrust = new HashMap<>();
+ private final OnClickListener mCancelButtonListener =
+ v -> {
+ setResult(RESULT_CANCELED);
+ finish();
+ };
+ private List<Jid> contactJids;
+ private Account mAccount;
+ private Conversation mConversation;
+ private final OnClickListener mSaveButtonListener =
+ v -> {
+ commitTrusts();
+ finishOk(false);
+ };
+ private final AtomicBoolean mUseCameraHintShown = new AtomicBoolean(false);
+ private AxolotlService.FetchStatus lastFetchReport = AxolotlService.FetchStatus.SUCCESS;
+ private Toast mUseCameraHintToast = null;
+ private ActivityTrustKeysBinding binding;
+
+ @Override
+ protected void refreshUiReal() {
+ invalidateOptionsMenu();
+ populateView();
+ }
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.binding = DataBindingUtil.setContentView(this, R.layout.activity_trust_keys);
+ Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+ this.contactJids = new ArrayList<>();
+ final var intent = getIntent();
+ final String[] contacts = intent == null ? null : intent.getStringArrayExtra("contacts");
+ for (final String jid : (contacts == null ? new String[0] : contacts)) {
+ try {
+ this.contactJids.add(Jid.of(jid));
+ } catch (final IllegalArgumentException ignored) {
+ }
+ }
+
+ binding.cancelButton.setOnClickListener(mCancelButtonListener);
+ binding.saveButton.setOnClickListener(mSaveButtonListener);
+
+ setSupportActionBar(binding.toolbar);
+ configureActionBar(getSupportActionBar());
+
+ if (savedInstanceState != null) {
+ mUseCameraHintShown.set(savedInstanceState.getBoolean("camera_hint_shown", false));
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ savedInstanceState.putBoolean("camera_hint_shown", mUseCameraHintShown.get());
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.trust_keys, menu);
+ MenuItem scanQrCode = menu.findItem(R.id.action_scan_qr_code);
+ scanQrCode.setVisible(
+ (!ownKeysToTrust.isEmpty() || foreignActuallyHasKeys())
+ && isCameraFeatureAvailable());
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ private void showCameraToast() {
+ mUseCameraHintToast =
+ Toast.makeText(this, R.string.use_camera_icon_to_scan_barcode, Toast.LENGTH_LONG);
+ ActionBar actionBar = getSupportActionBar();
+ mUseCameraHintToast.setGravity(
+ Gravity.TOP | Gravity.END, 0, actionBar == null ? 0 : actionBar.getHeight());
+ mUseCameraHintToast.show();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_scan_qr_code:
+ if (hasPendingKeyFetches()) {
+ Toast.makeText(
+ this,
+ R.string.please_wait_for_keys_to_be_fetched,
+ Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ ScanActivity.scan(this);
+ // new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (mUseCameraHintToast != null) {
+ mUseCameraHintToast.cancel();
+ }
+ }
+
+ @Override
+ protected void processFingerprintVerification(XmppUri uri) {
+ if (mConversation != null
+ && mAccount != null
+ && uri.hasFingerprints()
+ && mAccount.getAxolotlService()
+ .getCryptoTargets(mConversation)
+ .contains(uri.getJid())) {
+ boolean performedVerification =
+ xmppConnectionService.verifyFingerprints(
+ mAccount.getRoster().getContact(uri.getJid()), uri.getFingerprints());
+ boolean keys = reloadFingerprints();
+ if (performedVerification
+ && !keys
+ && !hasNoOtherTrustedKeys()
+ && !hasPendingKeyFetches()) {
+ Toast.makeText(this, R.string.all_omemo_keys_have_been_verified, Toast.LENGTH_SHORT)
+ .show();
+ finishOk(false);
+ return;
+ } else if (performedVerification) {
+ Toast.makeText(this, R.string.verified_fingerprints, Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ reloadFingerprints();
+ Log.d(
+ Config.LOGTAG,
+ "xmpp uri was: "
+ + uri.getJid()
+ + " has Fingerprints: "
+ + uri.hasFingerprints());
+ Toast.makeText(
+ this,
+ R.string.barcode_does_not_contain_fingerprints_for_this_chat,
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ populateView();
+ }
+
+ private void populateView() {
+ setTitle(getString(R.string.trust_omemo_fingerprints));
+ binding.ownKeysDetails.removeAllViews();
+ binding.foreignKeys.removeAllViews();
+ boolean hasOwnKeys = false;
+ boolean hasForeignKeys = false;
+ for (final String fingerprint : ownKeysToTrust.keySet()) {
+ hasOwnKeys = true;
+ addFingerprintRowWithListeners(
+ binding.ownKeysDetails,
+ mAccount,
+ fingerprint,
+ false,
+ FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)),
+ false,
+ false,
+ (buttonView, isChecked) -> {
+ ownKeysToTrust.put(fingerprint, isChecked);
+ // own fingerprints have no impact on locked status.
+ });
+ }
+
+ synchronized (this.foreignKeysToTrust) {
+ for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
+ hasForeignKeys = true;
+ KeysCardBinding keysCardBinding =
+ DataBindingUtil.inflate(
+ getLayoutInflater(),
+ R.layout.keys_card,
+ binding.foreignKeys,
+ false);
+ final Jid jid = entry.getKey();
+ keysCardBinding.foreignKeysTitle.setText(IrregularUnicodeDetector.style(this, jid));
+ keysCardBinding.foreignKeysTitle.setOnClickListener(
+ v -> switchToContactDetails(mAccount.getRoster().getContact(jid)));
+ final Map<String, Boolean> fingerprints = entry.getValue();
+ for (final String fingerprint : fingerprints.keySet()) {
+ addFingerprintRowWithListeners(
+ keysCardBinding.foreignKeysDetails,
+ mAccount,
+ fingerprint,
+ false,
+ FingerprintStatus.createActive(fingerprints.get(fingerprint)),
+ false,
+ false,
+ (buttonView, isChecked) -> {
+ fingerprints.put(fingerprint, isChecked);
+ lockOrUnlockAsNeeded();
+ });
+ }
+ if (fingerprints.isEmpty()) {
+ keysCardBinding.noKeysToAccept.setVisibility(View.VISIBLE);
+ if (hasNoOtherTrustedKeys(jid)) {
+ if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
+ keysCardBinding.noKeysToAccept.setText(
+ R.string.error_no_keys_to_trust_presence);
+ } else {
+ keysCardBinding.noKeysToAccept.setText(
+ R.string.error_no_keys_to_trust_server_error);
+ }
+ } else {
+ keysCardBinding.noKeysToAccept.setText(
+ getString(
+ R.string.no_keys_just_confirm,
+ mAccount.getRoster().getContact(jid).getDisplayName()));
+ }
+ } else {
+ keysCardBinding.noKeysToAccept.setVisibility(View.GONE);
+ }
+ binding.foreignKeys.addView(keysCardBinding.foreignKeysCard);
+ }
+ }
+
+ if ((hasOwnKeys || foreignActuallyHasKeys())
+ && isCameraFeatureAvailable()
+ && mUseCameraHintShown.compareAndSet(false, true)) {
+ showCameraToast();
+ }
+
+ binding.ownKeysTitle.setText(mAccount.getJid().asBareJid().toString());
+ binding.ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE);
+ binding.foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE);
+ if (hasPendingKeyFetches()) {
+ setFetching();
+ lock();
+ } else {
+ if (!hasForeignKeys && hasNoOtherTrustedKeys()) {
+ binding.keyErrorMessageCard.setVisibility(View.VISIBLE);
+ boolean lastReportWasError = lastFetchReport == AxolotlService.FetchStatus.ERROR;
+ boolean errorFetchingBundle =
+ mAccount.getAxolotlService().fetchMapHasErrors(contactJids);
+ boolean errorFetchingDeviceList =
+ mAccount.getAxolotlService().hasErrorFetchingDeviceList(contactJids);
+ boolean anyWithoutMutualPresenceSubscription =
+ anyWithoutMutualPresenceSubscription(contactJids);
+ if (errorFetchingDeviceList) {
+ binding.keyErrorMessage.setVisibility(View.VISIBLE);
+ binding.keyErrorMessage.setText(R.string.error_trustkey_device_list);
+ } else if (errorFetchingBundle || lastReportWasError) {
+ binding.keyErrorMessage.setVisibility(View.VISIBLE);
+ binding.keyErrorMessage.setText(R.string.error_trustkey_bundle);
+ } else {
+ binding.keyErrorMessage.setVisibility(View.GONE);
+ }
+ this.binding.keyErrorHintMutual.setVisibility(
+ anyWithoutMutualPresenceSubscription ? View.VISIBLE : View.GONE);
+ Contact contact = mAccount.getRoster().getContact(contactJids.get(0));
+ binding.keyErrorGeneral.setText(
+ getString(
+ R.string.error_trustkey_general,
+ getString(R.string.app_name),
+ contact.getDisplayName()));
+ binding.ownKeysDetails.removeAllViews();
+ if (OmemoSetting.isAlways()) {
+ binding.disableButton.setVisibility(View.GONE);
+ } else {
+ binding.disableButton.setVisibility(View.VISIBLE);
+ binding.disableButton.setOnClickListener(this::disableEncryptionDialog);
+ }
+ binding.ownKeysCard.setVisibility(View.GONE);
+ binding.foreignKeys.removeAllViews();
+ binding.foreignKeys.setVisibility(View.GONE);
+ }
+ lockOrUnlockAsNeeded();
+ setDone();
+ }
+ }
+
+ private void disableEncryptionDialog(final View view) {
+ final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ builder.setTitle(R.string.disable_encryption);
+ builder.setMessage(R.string.disable_encryption_message);
+ builder.setPositiveButton(
+ R.string.disable_now,
+ (dialog, which) -> {
+ mConversation.setNextEncryption(Message.ENCRYPTION_NONE);
+ xmppConnectionService.updateConversation(mConversation);
+ finishOk(true);
+ });
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.create().show();
+ }
+
+ private boolean anyWithoutMutualPresenceSubscription(List<Jid> contactJids) {
+ for (Jid jid : contactJids) {
+ if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean foreignActuallyHasKeys() {
+ synchronized (this.foreignKeysToTrust) {
+ for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
+ if (!entry.getValue().isEmpty()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean reloadFingerprints() {
+ List<Jid> acceptedTargets =
+ mConversation == null
+ ? new ArrayList<>()
+ : mConversation.getAcceptedCryptoTargets();
+ ownKeysToTrust.clear();
+ if (this.mAccount == null) {
+ return false;
+ }
+ AxolotlService service = this.mAccount.getAxolotlService();
+ Set<IdentityKey> ownKeysSet =
+ service.getKeysWithTrust(FingerprintStatus.createActiveUndecided());
+ for (final IdentityKey identityKey : ownKeysSet) {
+ final String fingerprint =
+ CryptoHelper.bytesToHex(identityKey.getPublicKey().serialize());
+ if (!ownKeysToTrust.containsKey(fingerprint)) {
+ ownKeysToTrust.put(fingerprint, false);
+ }
+ }
+ synchronized (this.foreignKeysToTrust) {
+ foreignKeysToTrust.clear();
+ for (Jid jid : contactJids) {
+ Set<IdentityKey> foreignKeysSet =
+ service.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), jid);
+ if (hasNoOtherTrustedKeys(jid) && ownKeysSet.isEmpty()) {
+ foreignKeysSet.addAll(
+ service.getKeysWithTrust(FingerprintStatus.createActive(false), jid));
+ }
+ Map<String, Boolean> foreignFingerprints = new HashMap<>();
+ for (final IdentityKey identityKey : foreignKeysSet) {
+ final String fingerprint =
+ CryptoHelper.bytesToHex(identityKey.getPublicKey().serialize());
+ if (!foreignFingerprints.containsKey(fingerprint)) {
+ foreignFingerprints.put(fingerprint, false);
+ }
+ }
+ if (!foreignFingerprints.isEmpty() || !acceptedTargets.contains(jid)) {
+ foreignKeysToTrust.put(jid, foreignFingerprints);
+ }
+ }
+ }
+ return ownKeysSet.size() + foreignKeysToTrust.size() > 0;
+ }
+
+ public void onBackendConnected() {
+ Intent intent = getIntent();
+ this.mAccount = extractAccount(intent);
+ if (this.mAccount != null && intent != null) {
+ String uuid = intent.getStringExtra("conversation");
+ this.mConversation = xmppConnectionService.findConversationByUuid(uuid);
+ if (this.mPendingFingerprintVerificationUri != null) {
+ processFingerprintVerification(this.mPendingFingerprintVerificationUri);
+ this.mPendingFingerprintVerificationUri = null;
+ } else {
+ final boolean keysToTrust = reloadFingerprints();
+ if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) {
+ populateView();
+ invalidateOptionsMenu();
+ } else {
+ finishOk(false);
+ }
+ }
+ }
+ }
+
+ private boolean hasNoOtherTrustedKeys() {
+ return mAccount == null
+ || mAccount.getAxolotlService().anyTargetHasNoTrustedKeys(contactJids);
+ }
+
+ private boolean hasNoOtherTrustedKeys(Jid contact) {
+ return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0;
+ }
+
+ private boolean hasPendingKeyFetches() {
+ return mAccount != null && mAccount.getAxolotlService().hasPendingKeyFetches(contactJids);
+ }
+
+ @Override
+ public void onKeyStatusUpdated(final AxolotlService.FetchStatus report) {
+ final boolean keysToTrust = reloadFingerprints();
+ if (report != null) {
+ lastFetchReport = report;
+ runOnUiThread(
+ () -> {
+ if (mUseCameraHintToast != null && !keysToTrust) {
+ mUseCameraHintToast.cancel();
+ }
+ switch (report) {
+ case ERROR:
+ Toast.makeText(
+ TrustKeysActivity.this,
+ R.string.error_fetching_omemo_key,
+ Toast.LENGTH_SHORT)
+ .show();
+ break;
+ case SUCCESS_TRUSTED:
+ Toast.makeText(
+ TrustKeysActivity.this,
+ R.string.blindly_trusted_omemo_keys,
+ Toast.LENGTH_LONG)
+ .show();
+ break;
+ case SUCCESS_VERIFIED:
+ Toast.makeText(
+ TrustKeysActivity.this,
+ Config.X509_VERIFICATION
+ ? R.string
+ .verified_omemo_key_with_certificate
+ : R.string
+ .all_omemo_keys_have_been_verified,
+ Toast.LENGTH_LONG)
+ .show();
+ break;
+ }
+ });
+ }
+ if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) {
+ refreshUi();
+ } else {
+ runOnUiThread(() -> finishOk(false));
+ }
+ }
+
+ private void finishOk(boolean disabled) {
+ Intent data = new Intent();
+ data.putExtra(
+ "choice",
+ getIntent().getIntExtra("choice", ConversationFragment.ATTACHMENT_CHOICE_INVALID));
+ data.putExtra("disabled", disabled);
+ setResult(RESULT_OK, data);
+ finish();
+ }
+
+ private void commitTrusts() {
+ for (final String fingerprint : ownKeysToTrust.keySet()) {
+ mAccount.getAxolotlService()
+ .setFingerprintTrust(
+ fingerprint,
+ FingerprintStatus.createActive(ownKeysToTrust.get(fingerprint)));
+ }
+ List<Jid> acceptedTargets =
+ mConversation == null
+ ? new ArrayList<>()
+ : mConversation.getAcceptedCryptoTargets();
+ synchronized (this.foreignKeysToTrust) {
+ for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
+ Jid jid = entry.getKey();
+ Map<String, Boolean> value = entry.getValue();
+ if (!acceptedTargets.contains(jid)) {
+ acceptedTargets.add(jid);
+ }
+ for (final String fingerprint : value.keySet()) {
+ mAccount.getAxolotlService()
+ .setFingerprintTrust(
+ fingerprint,
+ FingerprintStatus.createActive(value.get(fingerprint)));
+ }
+ }
+ }
+ if (mConversation != null && mConversation.getMode() == Conversation.MODE_MULTI) {
+ mConversation.setAcceptedCryptoTargets(acceptedTargets);
+ xmppConnectionService.updateConversation(mConversation);
+ }
+ }
+
+ private void unlock() {
+ binding.saveButton.setEnabled(true);
+ }
+
+ private void lock() {
+ binding.saveButton.setEnabled(false);
+ }
+
+ private void lockOrUnlockAsNeeded() {
+ synchronized (this.foreignKeysToTrust) {
+ for (Jid jid : contactJids) {
+ Map<String, Boolean> fingerprints = foreignKeysToTrust.get(jid);
+ if (hasNoOtherTrustedKeys(jid)
+ && (fingerprints == null || !fingerprints.containsValue(true))) {
+ lock();
+ return;
+ }
+ }
+ }
+ unlock();
+ }
+
+ private void setDone() {
+ binding.saveButton.setText(getString(R.string.done));
+ }
+
+ private void setFetching() {
+ binding.saveButton.setText(getString(R.string.fetching_keys));
+ }
}
@@ -11,12 +11,10 @@ import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
-
import com.google.common.base.Strings;
import com.cheogram.android.DownloadDefaultStickers;
@@ -38,18 +36,12 @@ import eu.siacs.conversations.utils.ProvisioningUtils;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
-
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
-import java.io.IOException;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
public class UriHandlerActivity extends BaseActivity {
public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
@@ -68,7 +60,8 @@ public class UriHandlerActivity extends BaseActivity {
}
public static void scan(final Activity activity, final boolean provisioning) {
- if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
+ == PackageManager.PERMISSION_GRANTED) {
final Intent intent = new Intent(activity, UriHandlerActivity.class);
intent.setAction(UriHandlerActivity.ACTION_SCAN_QR_CODE);
if (provisioning) {
@@ -178,7 +171,7 @@ public class UriHandlerActivity extends BaseActivity {
final String preAuth = xmppUri.getParameter(XmppUri.PARAMETER_PRE_AUTH);
final Jid jid = xmppUri.getJid();
if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) {
- if (jid.getEscapedLocal() != null && accounts.contains(jid.asBareJid())) {
+ if (jid.getLocal() != null && accounts.contains(jid.asBareJid())) {
showError(R.string.account_already_exists);
return false;
}
@@ -227,7 +220,7 @@ public class UriHandlerActivity extends BaseActivity {
intent = new Intent(this, StartConversationActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setData(uri);
- intent.putExtra("account", accounts.get(0).toEscapedString());
+ intent.putExtra("account", accounts.get(0).toString());
}
} else {
intent = new Intent(this, ShareWithActivity.class);
@@ -258,8 +251,8 @@ public class UriHandlerActivity extends BaseActivity {
private void checkForLinkHeader(final HttpUrl url) {
Log.d(Config.LOGTAG, "checking for link header on " + url);
this.call =
- HttpConnectionManager.okHttpClient(this).newCall(
- new Request.Builder().url(url).head().build());
+ HttpConnectionManager.okHttpClient(this)
+ .newCall(new Request.Builder().url(url).head().build());
this.call.enqueue(
new Callback() {
@Override
@@ -301,7 +294,7 @@ public class UriHandlerActivity extends BaseActivity {
}
private void showErrorOnUiThread(@StringRes int error) {
- runOnUiThread(()-> showError(error));
+ runOnUiThread(() -> showError(error));
}
private static Class<?> findShareViaAccountClass() {
@@ -838,8 +838,8 @@ public abstract class XmppActivity extends ActionBarActivity {
public void switchToContactDetails(Contact contact, String messageFingerprint) {
Intent intent = new Intent(this, ContactDetailsActivity.class);
intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
- intent.putExtra(EXTRA_ACCOUNT, contact.getAccount().getJid().asBareJid().toEscapedString());
- intent.putExtra("contact", contact.getJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, contact.getAccount().getJid().asBareJid().toString());
+ intent.putExtra("contact", contact.getJid().toString());
intent.putExtra("fingerprint", messageFingerprint);
startActivity(intent);
}
@@ -854,7 +854,7 @@ public abstract class XmppActivity extends ActionBarActivity {
public void switchToAccount(Account account, boolean init, String fingerprint) {
Intent intent = new Intent(this, EditAccountActivity.class);
- intent.putExtra("jid", account.getJid().asBareJid().toEscapedString());
+ intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", init);
if (init) {
intent.setFlags(
@@ -1251,7 +1251,7 @@ public abstract class XmppActivity extends ActionBarActivity {
final AtomicReference<Account> selectedAccount = new AtomicReference<>(accounts.get(0));
final MaterialAlertDialogBuilder alertDialogBuilder = new MaterialAlertDialogBuilder(this);
alertDialogBuilder.setTitle(R.string.choose_account);
- final String[] asStrings = Collections2.transform(accounts, a -> a.getJid().asBareJid().toEscapedString()).toArray(new String[0]);
+ final String[] asStrings = Collections2.transform(accounts, a -> a.getJid().asBareJid().toString()).toArray(new String[0]);
alertDialogBuilder.setSingleChoiceItems(asStrings, 0, (dialog, which) -> selectedAccount.set(accounts.get(which)));
alertDialogBuilder.setNegativeButton(R.string.cancel, null);
alertDialogBuilder.setPositiveButton(R.string.ok, (dialog, which) -> showQrCode(selectedAccount.get().getShareableUri()));
@@ -1302,7 +1302,7 @@ public abstract class XmppActivity extends ActionBarActivity {
protected Account extractAccount(Intent intent) {
final String jid = intent != null ? intent.getStringExtra(EXTRA_ACCOUNT) : null;
try {
- return jid != null ? xmppConnectionService.findAccountByJid(Jid.ofEscaped(jid)) : null;
+ return jid != null ? xmppConnectionService.findAccountByJid(Jid.of(jid)) : null;
} catch (IllegalArgumentException e) {
return null;
}
@@ -4,14 +4,10 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
-
import androidx.annotation.NonNull;
import androidx.core.graphics.ColorUtils;
import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.color.MaterialColors;
-
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ItemAccountBinding;
import eu.siacs.conversations.entities.Account;
@@ -44,27 +40,42 @@ public class AccountAdapter extends ArrayAdapter<Account> {
final Account account = getItem(position);
final ViewHolder viewHolder;
if (view == null) {
- ItemAccountBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_account, parent, false);
+ ItemAccountBinding binding =
+ DataBindingUtil.inflate(
+ LayoutInflater.from(parent.getContext()),
+ R.layout.item_account,
+ parent,
+ false);
view = binding.getRoot();
viewHolder = new ViewHolder(binding);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
- viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
+ viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toString());
AvatarWorkerTask.loadAvatar(account, viewHolder.binding.accountImage, R.dimen.avatar);
- viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId()));
+ viewHolder.binding.accountStatus.setText(
+ getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
- viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorPrimary));
+ viewHolder.binding.accountStatus.setTextColor(
+ MaterialColors.getColor(
+ viewHolder.binding.accountStatus,
+ com.google.android.material.R.attr.colorPrimary));
break;
case DISABLED:
case LOGGED_OUT:
case CONNECTING:
- viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorOnSurfaceVariant));
+ viewHolder.binding.accountStatus.setTextColor(
+ MaterialColors.getColor(
+ viewHolder.binding.accountStatus,
+ com.google.android.material.R.attr.colorOnSurfaceVariant));
break;
default:
- viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorError));
+ viewHolder.binding.accountStatus.setTextColor(
+ MaterialColors.getColor(
+ viewHolder.binding.accountStatus,
+ com.google.android.material.R.attr.colorError));
break;
}
if (account.isOnlineAndConnected()) {
@@ -89,11 +100,12 @@ public class AccountAdapter extends ArrayAdapter<Account> {
} else {
viewHolder.binding.tglAccountStatus.setVisibility(View.GONE);
}
- viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener((compoundButton, b) -> {
- if (b == isDisabled && activity instanceof OnTglAccountState) {
- ((OnTglAccountState) activity).onClickTglAccountState(account, b);
- }
- });
+ viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener(
+ (compoundButton, b) -> {
+ if (b == isDisabled && activity instanceof OnTglAccountState) {
+ ((OnTglAccountState) activity).onClickTglAccountState(account, b);
+ }
+ });
if (activity.xmppConnectionService != null && activity.xmppConnectionService.getAccounts().size() > 1) {
viewHolder.binding.frame.setBackgroundColor(account.getColor(activity.isDark()));
}
@@ -108,10 +120,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
}
}
-
-
public interface OnTglAccountState {
void onClickTglAccountState(Account account, boolean state);
}
-
}
@@ -3,14 +3,10 @@ package eu.siacs.conversations.ui.adapter;
import android.content.Context;
import android.widget.ArrayAdapter;
import android.widget.Filter;
-
import androidx.annotation.NonNull;
-
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
-
import eu.siacs.conversations.Config;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -22,61 +18,66 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
private static final Pattern E164_PATTERN = Pattern.compile("^\\+[1-9]\\d{1,14}$");
private List<String> domains;
- private final Filter domainFilter = new Filter() {
+ private final Filter domainFilter =
+ new Filter() {
- @Override
- protected FilterResults performFiltering(final CharSequence constraint) {
- final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
- final String[] split = constraint == null ? new String[0] : constraint.toString().split("@");
- if (split.length == 1) {
- final String local = split[0].toLowerCase(Locale.ENGLISH);
- if (Config.QUICKSY_DOMAIN != null && E164_PATTERN.matcher(local).matches()) {
- builder.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
- } else {
- for (String domain : domains) {
- builder.add(local + '@' + domain);
- }
- }
- } else if (split.length == 2) {
- final String localPart = split[0].toLowerCase(Locale.ENGLISH);
- final String domainPart = split[1].toLowerCase(Locale.ENGLISH);
- if (domains.contains(domainPart)) {
- return new FilterResults();
- }
- for (final String domain : domains) {
- if (domain.contains(domainPart)) {
- builder.add(localPart + "@" + domain);
+ @Override
+ protected FilterResults performFiltering(final CharSequence constraint) {
+ final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
+ final String[] split =
+ constraint == null ? new String[0] : constraint.toString().split("@");
+ if (split.length == 1) {
+ final String local = split[0].toLowerCase(Locale.ENGLISH);
+ if (Config.QUICKSY_DOMAIN != null
+ && E164_PATTERN.matcher(local).matches()) {
+ builder.add(local + '@' + Config.QUICKSY_DOMAIN.toString());
+ } else {
+ for (String domain : domains) {
+ builder.add(local + '@' + domain);
+ }
+ }
+ } else if (split.length == 2) {
+ final String localPart = split[0].toLowerCase(Locale.ENGLISH);
+ final String domainPart = split[1].toLowerCase(Locale.ENGLISH);
+ if (domains.contains(domainPart)) {
+ return new FilterResults();
+ }
+ for (final String domain : domains) {
+ if (domain.contains(domainPart)) {
+ builder.add(localPart + "@" + domain);
+ }
+ }
+ } else {
+ return new FilterResults();
}
+ final var suggestions = builder.build();
+ final FilterResults filterResults = new FilterResults();
+ filterResults.values = suggestions;
+ filterResults.count = suggestions.size();
+ return filterResults;
}
- } else {
- return new FilterResults();
- }
- final var suggestions = builder.build();
- final FilterResults filterResults = new FilterResults();
- filterResults.values = suggestions;
- filterResults.count = suggestions.size();
- return filterResults;
- }
- @Override
- protected void publishResults(final CharSequence constraint, final FilterResults results) {
- final ImmutableList.Builder<String> suggestions = new ImmutableList.Builder<>();
- if (results.values instanceof Collection<?> collection) {
- for(final Object item : collection) {
- if (item instanceof String string) {
- suggestions.add(string);
+ @Override
+ protected void publishResults(
+ final CharSequence constraint, final FilterResults results) {
+ final ImmutableList.Builder<String> suggestions = new ImmutableList.Builder<>();
+ if (results.values instanceof Collection<?> collection) {
+ for (final Object item : collection) {
+ if (item instanceof String string) {
+ suggestions.add(string);
+ }
+ }
}
+ clear();
+ addAll(suggestions.build());
+ notifyDataSetChanged();
}
- }
- clear();
- addAll(suggestions.build());
- notifyDataSetChanged();
- }
- };
+ };
- public KnownHostsAdapter(final Context context, final int viewResourceId, final Collection<String> knownHosts) {
+ public KnownHostsAdapter(
+ final Context context, final int viewResourceId, final Collection<String> knownHosts) {
super(context, viewResourceId, new ArrayList<>());
- domains = Ordering.natural().sortedCopy(knownHosts);
+ domains = Ordering.natural().sortedCopy(knownHosts);
}
public KnownHostsAdapter(final Context context, final int viewResourceId) {
@@ -10,17 +10,14 @@ import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
-
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.core.widget.ImageViewCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
-
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ItemMediaBinding;
import eu.siacs.conversations.ui.XmppActivity;
@@ -45,6 +42,21 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"text/x-tex",
"text/plain");
+ public static final List<String> SPREAD_SHEET_MIMES =
+ Arrays.asList(
+ "text/comma-separated-values",
+ "application/vnd.ms-excel",
+ "application/vnd.stardivision.calc",
+ "application/vnd.oasis.opendocument.spreadsheet",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+
+ public static final List<String> SLIDE_SHOW_MIMES =
+ Arrays.asList(
+ "application/vnd.ms-powerpoint",
+ "application/vnd.stardivision.impress",
+ "application/vnd.oasis.opendocument.presentation",
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow");
private static final List<String> ARCHIVE_MIMES =
Arrays.asList(
@@ -112,6 +124,10 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
return R.drawable.ic_backup_48dp;
} else if (DOCUMENT_MIMES.contains(mime)) {
return R.drawable.ic_description_48dp;
+ } else if (SPREAD_SHEET_MIMES.contains(mime)) {
+ return R.drawable.ic_table_48dp;
+ } else if (SLIDE_SHOW_MIMES.contains(mime)) {
+ return R.drawable.ic_slideshow_48dp;
} else if (mime.equals("application/gpx+xml")) {
return R.drawable.ic_tour_48dp;
} else if (mime.startsWith("image/")) {
@@ -2,20 +2,16 @@ package eu.siacs.conversations.ui.fragment.settings;
import android.os.Bundle;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
-
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.receiver.UnifiedPushDistributor;
import eu.siacs.conversations.xmpp.Jid;
-
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
@@ -31,29 +27,38 @@ public class UpSettingsFragment extends XmppPreferenceFragment {
@Override
public void onBackendConnected() {
final ListPreference upAccounts = findPreference(UnifiedPushDistributor.PREFERENCE_ACCOUNT);
- final EditTextPreference pushServer = findPreference(UnifiedPushDistributor.PREFERENCE_PUSH_SERVER);
+ final EditTextPreference pushServer =
+ findPreference(UnifiedPushDistributor.PREFERENCE_PUSH_SERVER);
if (upAccounts == null || pushServer == null) {
throw new IllegalStateException();
}
- pushServer.setOnPreferenceChangeListener((preference, newValue) -> {
- if (newValue instanceof String string) {
- if (Strings.isNullOrEmpty(string) || isJidInvalid(string) || isHttpUri(string)) {
- Toast.makeText(requireActivity(),R.string.invalid_jid,Toast.LENGTH_LONG).show();
- return false;
- } else {
- return true;
- }
- } else {
- Toast.makeText(requireActivity(),R.string.invalid_jid,Toast.LENGTH_LONG).show();
- return false;
- }
- });
+ pushServer.setOnPreferenceChangeListener(
+ (preference, newValue) -> {
+ if (newValue instanceof String string) {
+ if (Strings.isNullOrEmpty(string)
+ || isJidInvalid(string)
+ || isHttpUri(string)) {
+ Toast.makeText(
+ requireActivity(),
+ R.string.invalid_jid,
+ Toast.LENGTH_LONG)
+ .show();
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ Toast.makeText(requireActivity(), R.string.invalid_jid, Toast.LENGTH_LONG)
+ .show();
+ return false;
+ }
+ });
reconfigureUpAccountPreference(upAccounts);
}
private static boolean isJidInvalid(final String input) {
try {
- final var jid = Jid.ofEscaped(input);
+ final var jid = Jid.ofUserInput(input);
return !jid.isBareJid();
} catch (final IllegalArgumentException e) {
return true;
@@ -67,16 +72,15 @@ public class UpSettingsFragment extends XmppPreferenceFragment {
} catch (final URISyntaxException e) {
return false;
}
- return Arrays.asList("http","https").contains(uri.getScheme());
+ return Arrays.asList("http", "https").contains(uri.getScheme());
}
-
private void reconfigureUpAccountPreference(final ListPreference listPreference) {
final List<CharSequence> accounts =
ImmutableList.copyOf(
Lists.transform(
requireService().getAccounts(),
- a -> a.getJid().asBareJid().toEscapedString()));
+ a -> a.getJid().asBareJid().toString()));
final ImmutableList.Builder<CharSequence> entries = new ImmutableList.Builder<>();
final ImmutableList.Builder<CharSequence> entryValues = new ImmutableList.Builder<>();
entries.add(getString(R.string.no_account_deactivated));
@@ -14,16 +14,13 @@ import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
import android.view.View;
-import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
-
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
-
+import com.google.android.material.button.MaterialButton;
import com.google.common.primitives.Ints;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Message;
@@ -33,7 +30,6 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.utils.TimeFrameUtils;
import eu.siacs.conversations.utils.WeakReferenceSet;
-
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -54,7 +50,8 @@ public class AudioPlayer
private final WeakReferenceSet<RelativeLayout> audioPlayerLayouts = new WeakReferenceSet<>();
private final SensorManager sensorManager;
private final Sensor proximitySensor;
- private final PendingItem<WeakReference<ImageButton>> pendingOnClickView = new PendingItem<>();
+ private final PendingItem<WeakReference<MaterialButton>> pendingOnClickView =
+ new PendingItem<>();
private final ExecutorService executor = Executors.newSingleThreadExecutor();
@@ -81,7 +78,7 @@ public class AudioPlayer
}
private static String formatTime(final int ms) {
- return TimeFrameUtils.formatElapsedTime(ms,false);
+ return TimeFrameUtils.formatElapsedTime(ms, false);
}
private void initializeProximityWakeLock(Context context) {
@@ -124,20 +121,17 @@ public class AudioPlayer
final Context context = viewHolder.playPause.getContext();
if (message == currentlyPlayingMessage) {
if (AudioPlayer.player != null && AudioPlayer.player.isPlaying()) {
- viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_pause_24dp);
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(R.drawable.ic_play_arrow_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_play_arrow_24dp);
viewHolder.progress.setEnabled(false);
}
return true;
} else {
- viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_play_arrow_24dp);
viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
viewHolder.progress.setProgress(0);
@@ -150,12 +144,12 @@ public class AudioPlayer
public synchronized void onClick(View v) {
if (v.getId() == R.id.play_pause) {
synchronized (LOCK) {
- startStop((ImageButton) v);
+ startStop((MaterialButton) v);
}
}
}
- private void startStop(ImageButton playPause) {
+ private void startStop(final MaterialButton playPause) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
&& ContextCompat.checkSelfPermission(
messageAdapter.getActivity(),
@@ -186,8 +180,7 @@ public class AudioPlayer
player.pause();
messageAdapter.flagScreenOff();
releaseProximityWakeLock();
- viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_play_arrow_24dp);
viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
} else {
viewHolder.progress.setEnabled(true);
@@ -195,8 +188,7 @@ public class AudioPlayer
messageAdapter.flagScreenOn();
acquireProximityWakeLock();
this.stopRefresher(true);
- viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_pause_24dp);
viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
}
return false;
@@ -222,8 +214,7 @@ public class AudioPlayer
messageAdapter.flagScreenOn();
acquireProximityWakeLock();
viewHolder.progress.setEnabled(true);
- viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_pause_24dp);
viewHolder.playPause.setContentDescription(
viewHolder.playPause.getContext().getString(R.string.pause_audio));
sensorManager.registerListener(
@@ -239,9 +230,9 @@ public class AudioPlayer
}
public void startStopPending() {
- WeakReference<ImageButton> reference = pendingOnClickView.pop();
+ final var reference = pendingOnClickView.pop();
if (reference != null) {
- ImageButton imageButton = reference.get();
+ var imageButton = reference.get();
if (imageButton != null) {
startStop(imageButton);
}
@@ -283,8 +274,7 @@ public class AudioPlayer
final Message message = (Message) audioPlayer.getTag();
viewHolder.playPause.setContentDescription(
viewHolder.playPause.getContext().getString(R.string.play_audio));
- viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
- MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
+ viewHolder.playPause.setIconResource(R.drawable.ic_play_arrow_24dp);
if (message != null) {
viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
}
@@ -309,7 +299,8 @@ public class AudioPlayer
}
@Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ public void onProgressChanged(
+ final SeekBar seekBar, final int progress, final boolean fromUser) {
synchronized (AudioPlayer.LOCK) {
final RelativeLayout audioPlayer = (RelativeLayout) seekBar.getParent();
final Message message = (Message) audioPlayer.getTag();
@@ -462,7 +453,7 @@ public class AudioPlayer
public static class ViewHolder {
private TextView runtime;
private SeekBar progress;
- private ImageButton playPause;
+ private MaterialButton playPause;
private MessageAdapter.BubbleColor bubbleColor = MessageAdapter.BubbleColor.SURFACE;
public static ViewHolder get(final RelativeLayout audioPlayer) {
@@ -5,20 +5,16 @@ import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Longs;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.XmppActivity;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
public class AccountUtils {
@@ -50,9 +46,7 @@ public class AccountUtils {
public static UUID createUuid4(long mostSigBits, long leastSigBits) {
final byte[] bytes =
- Bytes.concat(
- Longs.toByteArray(mostSigBits),
- Longs.toByteArray(leastSigBits));
+ Bytes.concat(Longs.toByteArray(mostSigBits), Longs.toByteArray(leastSigBits));
bytes[6] &= 0x0f; /* clear version */
bytes[6] |= 0x40; /* set to version 4 */
bytes[8] &= 0x3f; /* clear variant */
@@ -65,7 +59,7 @@ public class AccountUtils {
final ArrayList<String> accounts = new ArrayList<>();
for (final Account account : service.getAccounts()) {
if (account.isEnabled()) {
- accounts.add(account.getJid().asBareJid().toEscapedString());
+ accounts.add(account.getJid().asBareJid().toString());
}
}
return accounts;
@@ -1,13 +1,11 @@
package eu.siacs.conversations.utils;
import androidx.annotation.NonNull;
-
+import eu.siacs.conversations.xmpp.Jid;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-import eu.siacs.conversations.xmpp.Jid;
-
public class BackupFileHeader {
private static final int VERSION = 1;
@@ -18,17 +16,22 @@ public class BackupFileHeader {
private final byte[] iv;
private final byte[] salt;
-
@NonNull
@Override
public String toString() {
- return "BackupFileHeader{" +
- "app='" + app + '\'' +
- ", jid=" + jid +
- ", timestamp=" + timestamp +
- ", iv=" + CryptoHelper.bytesToHex(iv) +
- ", salt=" + CryptoHelper.bytesToHex(salt) +
- '}';
+ return "BackupFileHeader{"
+ + "app='"
+ + app
+ + '\''
+ + ", jid="
+ + jid
+ + ", timestamp="
+ + timestamp
+ + ", iv="
+ + CryptoHelper.bytesToHex(iv)
+ + ", salt="
+ + CryptoHelper.bytesToHex(salt)
+ + '}';
}
public BackupFileHeader(String app, Jid jid, long timestamp, byte[] iv, byte[] salt) {
@@ -42,7 +45,7 @@ public class BackupFileHeader {
public void write(DataOutputStream dataOutputStream) throws IOException {
dataOutputStream.writeInt(VERSION);
dataOutputStream.writeUTF(app);
- dataOutputStream.writeUTF(jid.asBareJid().toEscapedString());
+ dataOutputStream.writeUTF(jid.asBareJid().toString());
dataOutputStream.writeLong(timestamp);
dataOutputStream.write(iv);
dataOutputStream.write(salt);
@@ -61,10 +64,13 @@ public class BackupFileHeader {
throw new OutdatedBackupFileVersion();
}
if (version != VERSION) {
- throw new IllegalArgumentException("Backup File version was " + version + " but app only supports version " + VERSION);
+ throw new IllegalArgumentException(
+ "Backup File version was "
+ + version
+ + " but app only supports version "
+ + VERSION);
}
return new BackupFileHeader(app, Jid.of(jid), timestamp, iv, salt);
-
}
public byte[] getSalt() {
@@ -87,7 +93,5 @@ public class BackupFileHeader {
return timestamp;
}
- public static class OutdatedBackupFileVersion extends RuntimeException {
-
- }
+ public static class OutdatedBackupFileVersion extends RuntimeException {}
}
@@ -5,7 +5,6 @@ import static eu.siacs.conversations.utils.Random.SECURE_RANDOM;
import android.os.Bundle;
import android.util.Base64;
import android.util.Pair;
-
import androidx.annotation.StringRes;
import org.bouncycastle.asn1.x500.X500Name;
@@ -15,6 +14,11 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import java.io.InputStream;
import java.io.IOException;
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.xmpp.Jid;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -42,13 +46,15 @@ import eu.siacs.conversations.xmpp.Jid;
public final class CryptoHelper {
- public static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}");
- final public static byte[] ONE = new byte[]{0, 0, 0, 1};
- private static final char[] CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789+-/#$!?".toCharArray();
+ public static final Pattern UUID_PATTERN =
+ Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}");
+ public static final byte[] ONE = new byte[] {0, 0, 0, 1};
+ private static final char[] CHARS =
+ "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789+-/#$!?".toCharArray();
private static final int PW_LENGTH = 25;
private static final char[] VOWELS = "aeiou".toCharArray();
private static final char[] CONSONANTS = "bcfghjklmnpqrstvwxyz".toCharArray();
- private final static char[] hexArray = "0123456789abcdef".toCharArray();
+ private static final char[] hexArray = "0123456789abcdef".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
@@ -73,7 +79,10 @@ public final class CryptoHelper {
char[] output = new char[rand * 2 + (5 - rand)];
boolean vowel = SECURE_RANDOM.nextBoolean();
for (int i = 0; i < output.length; ++i) {
- output[i] = vowel ? VOWELS[SECURE_RANDOM.nextInt(VOWELS.length)] : CONSONANTS[SECURE_RANDOM.nextInt(CONSONANTS.length)];
+ output[i] =
+ vowel
+ ? VOWELS[SECURE_RANDOM.nextInt(VOWELS.length)]
+ : CONSONANTS[SECURE_RANDOM.nextInt(CONSONANTS.length)];
vowel = !vowel;
}
return String.valueOf(output);
@@ -83,8 +92,10 @@ public final class CryptoHelper {
int len = hexString.length();
byte[] array = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
- array[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
- .digit(hexString.charAt(i + 1), 16));
+ array[i / 2] =
+ (byte)
+ ((Character.digit(hexString.charAt(i), 16) << 4)
+ + Character.digit(hexString.charAt(i + 1), 16));
}
return array;
}
@@ -100,9 +111,7 @@ public final class CryptoHelper {
return result;
}
- /**
- * Escapes usernames or passwords for SASL.
- */
+ /** Escapes usernames or passwords for SASL. */
public static String saslEscape(final String s) {
final StringBuilder sb = new StringBuilder((int) (s.length() * 1.1));
for (int i = 0; i < s.length(); i++) {
@@ -154,7 +163,8 @@ public final class CryptoHelper {
}
public static String[] getOrderedCipherSuites(final String[] platformSupportedCipherSuites) {
- final Collection<String> cipherSuites = new LinkedHashSet<>(Arrays.asList(Config.ENABLED_CIPHERS));
+ final Collection<String> cipherSuites =
+ new LinkedHashSet<>(Arrays.asList(Config.ENABLED_CIPHERS));
final List<String> platformCiphers = Arrays.asList(platformSupportedCipherSuites);
cipherSuites.retainAll(platformCiphers);
cipherSuites.addAll(platformCiphers);
@@ -177,7 +187,10 @@ public final class CryptoHelper {
}
}
- public static Pair<Jid, String> extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, IllegalArgumentException, CertificateParsingException {
+ public static Pair<Jid, String> extractJidAndName(X509Certificate certificate)
+ throws CertificateEncodingException,
+ IllegalArgumentException,
+ CertificateParsingException {
Collection<List<?>> alternativeNames = certificate.getSubjectAlternativeNames();
List<String> emails = new ArrayList<>();
if (alternativeNames != null) {
@@ -190,9 +203,15 @@ public final class CryptoHelper {
}
X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject();
if (emails.size() == 0 && x500name.getRDNs(BCStyle.EmailAddress).length > 0) {
- emails.add(IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue()));
+ emails.add(
+ IETFUtils.valueToString(
+ x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue()));
}
- String name = x500name.getRDNs(BCStyle.CN).length > 0 ? IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue()) : null;
+ String name =
+ x500name.getRDNs(BCStyle.CN).length > 0
+ ? IETFUtils.valueToString(
+ x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue())
+ : null;
if (emails.size() >= 1) {
return new Pair<>(Jid.of(emails.get(0)), name);
} else if (name != null) {
@@ -214,26 +233,33 @@ public final class CryptoHelper {
JcaX509CertificateHolder holder = new JcaX509CertificateHolder(certificate);
X500Name subject = holder.getSubject();
try {
- information.putString("subject_cn", subject.getRDNs(BCStyle.CN)[0].getFirst().getValue().toString());
+ information.putString(
+ "subject_cn",
+ subject.getRDNs(BCStyle.CN)[0].getFirst().getValue().toString());
} catch (Exception e) {
- //ignored
+ // ignored
}
try {
- information.putString("subject_o", subject.getRDNs(BCStyle.O)[0].getFirst().getValue().toString());
+ information.putString(
+ "subject_o",
+ subject.getRDNs(BCStyle.O)[0].getFirst().getValue().toString());
} catch (Exception e) {
- //ignored
+ // ignored
}
X500Name issuer = holder.getIssuer();
try {
- information.putString("issuer_cn", issuer.getRDNs(BCStyle.CN)[0].getFirst().getValue().toString());
+ information.putString(
+ "issuer_cn",
+ issuer.getRDNs(BCStyle.CN)[0].getFirst().getValue().toString());
} catch (Exception e) {
- //ignored
+ // ignored
}
try {
- information.putString("issuer_o", issuer.getRDNs(BCStyle.O)[0].getFirst().getValue().toString());
+ information.putString(
+ "issuer_o", issuer.getRDNs(BCStyle.O)[0].getFirst().getValue().toString());
} catch (Exception e) {
- //ignored
+ // ignored
}
try {
information.putString("sha1", getFingerprintCert(certificate.getEncoded()));
@@ -253,7 +279,7 @@ public final class CryptoHelper {
}
public static String getFingerprint(Jid jid, String androidId) {
- return getFingerprint(jid.toEscapedString() + "\00" + androidId);
+ return getFingerprint(jid.toString() + "\00" + androidId);
}
public static String getAccountFingerprint(Account account, String androidId) {
@@ -273,8 +299,9 @@ public final class CryptoHelper {
return switch (encryption) {
case Message.ENCRYPTION_OTR -> R.string.encryption_choice_otr;
case Message.ENCRYPTION_AXOLOTL,
- Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE,
- Message.ENCRYPTION_AXOLOTL_FAILED -> R.string.encryption_choice_omemo;
+ Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE,
+ Message.ENCRYPTION_AXOLOTL_FAILED ->
+ R.string.encryption_choice_omemo;
case Message.ENCRYPTION_PGP -> R.string.encryption_choice_pgp;
default -> R.string.encryption_choice_unencrypted;
};
@@ -285,7 +312,9 @@ public final class CryptoHelper {
return false;
}
final String u = url.toLowerCase();
- return !u.contains(" ") && (u.startsWith("https://") || u.startsWith("http://") || u.startsWith("p1s3://")) && u.endsWith(".pgp");
+ return !u.contains(" ")
+ && (u.startsWith("https://") || u.startsWith("http://") || u.startsWith("p1s3://"))
+ && u.endsWith(".pgp");
}
public static String multihashAlgo(Multihash.Type type) throws NoSuchAlgorithmException {
@@ -37,11 +37,9 @@ import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.LruCache;
-
import androidx.annotation.ColorInt;
-
import com.google.android.material.color.MaterialColors;
-
+import eu.siacs.conversations.xmpp.Jid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -54,226 +52,234 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.xmpp.Jid;
-
public class IrregularUnicodeDetector {
- private static final Map<Character.UnicodeBlock, Character.UnicodeBlock> NORMALIZATION_MAP;
- private static final LruCache<Jid, PatternTuple> CACHE = new LruCache<>(4096);
- private static final List<String> AMBIGUOUS_CYRILLIC = Arrays.asList("а","г","е","ѕ","і","ј","ķ","ԛ","о","р","с","у","х");
-
- static {
- Map<Character.UnicodeBlock, Character.UnicodeBlock> temp = new HashMap<>();
- temp.put(Character.UnicodeBlock.LATIN_1_SUPPLEMENT, Character.UnicodeBlock.BASIC_LATIN);
- NORMALIZATION_MAP = Collections.unmodifiableMap(temp);
- }
+ private static final Map<Character.UnicodeBlock, Character.UnicodeBlock> NORMALIZATION_MAP;
+ private static final LruCache<Jid, PatternTuple> CACHE = new LruCache<>(4096);
+ private static final List<String> AMBIGUOUS_CYRILLIC =
+ Arrays.asList("а", "г", "е", "ѕ", "і", "ј", "ķ", "ԛ", "о", "р", "с", "у", "х");
- private static Character.UnicodeBlock normalize(Character.UnicodeBlock in) {
- if (NORMALIZATION_MAP.containsKey(in)) {
- return NORMALIZATION_MAP.get(in);
- } else {
- return in;
- }
- }
+ static {
+ Map<Character.UnicodeBlock, Character.UnicodeBlock> temp = new HashMap<>();
+ temp.put(Character.UnicodeBlock.LATIN_1_SUPPLEMENT, Character.UnicodeBlock.BASIC_LATIN);
+ NORMALIZATION_MAP = Collections.unmodifiableMap(temp);
+ }
- public static Spannable style(final Context context, Jid jid) {
- return style(jid, MaterialColors.getColor(context, com.google.android.material.R.attr.colorError,"colorError not found"));
- }
+ private static Character.UnicodeBlock normalize(Character.UnicodeBlock in) {
+ if (NORMALIZATION_MAP.containsKey(in)) {
+ return NORMALIZATION_MAP.get(in);
+ } else {
+ return in;
+ }
+ }
- private static Spannable style(Jid jid, @ColorInt int color) {
- PatternTuple patternTuple = find(jid);
- SpannableStringBuilder builder = new SpannableStringBuilder();
- if (jid.getEscapedLocal() != null && patternTuple.local != null) {
- SpannableString local = new SpannableString(jid.getEscapedLocal());
- colorize(local, patternTuple.local, color);
- builder.append(local);
- builder.append('@');
- }
- if (jid.getDomain() != null) {
- String[] labels = jid.getDomain().toEscapedString().split("\\.");
- for (int i = 0; i < labels.length; ++i) {
- SpannableString spannableString = new SpannableString(labels[i]);
- if (patternTuple.domain.size() > i) {
- colorize(spannableString, patternTuple.domain.get(i), color);
- }
- if (i != 0) {
- builder.append('.');
- }
- builder.append(spannableString);
- }
- }
- if (builder.length() != 0 && jid.getResource() != null) {
- builder.append('/');
- builder.append(jid.getResource());
- }
- return builder;
- }
+ public static Spannable style(final Context context, Jid jid) {
+ return style(
+ jid,
+ MaterialColors.getColor(
+ context,
+ com.google.android.material.R.attr.colorError,
+ "colorError not found"));
+ }
- private static void colorize(SpannableString spannableString, Pattern pattern, @ColorInt int color) {
- Matcher matcher = pattern.matcher(spannableString);
- while (matcher.find()) {
- if (matcher.start() < matcher.end()) {
- spannableString.setSpan(new ForegroundColorSpan(color), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- }
+ private static Spannable style(Jid jid, @ColorInt int color) {
+ PatternTuple patternTuple = find(jid);
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ if (jid.getLocal() != null && patternTuple.local != null) {
+ SpannableString local = new SpannableString(jid.getLocal());
+ colorize(local, patternTuple.local, color);
+ builder.append(local);
+ builder.append('@');
+ }
+ if (jid.getDomain() != null) {
+ String[] labels = jid.getDomain().toString().split("\\.");
+ for (int i = 0; i < labels.length; ++i) {
+ SpannableString spannableString = new SpannableString(labels[i]);
+ colorize(spannableString, patternTuple.domain.get(i), color);
+ if (i != 0) {
+ builder.append('.');
+ }
+ builder.append(spannableString);
+ }
+ }
+ if (builder.length() != 0 && jid.getResource() != null) {
+ builder.append('/');
+ builder.append(jid.getResource());
+ }
+ return builder;
+ }
- private static Map<Character.UnicodeBlock, List<String>> mapCompat(String word) {
- Map<Character.UnicodeBlock, List<String>> map = new HashMap<>();
- final int length = word.length();
- for (int offset = 0; offset < length; ) {
- final int codePoint = word.codePointAt(offset);
- offset += Character.charCount(codePoint);
- if (!Character.isLetter(codePoint)) {
- continue;
- }
- Character.UnicodeBlock block = normalize(Character.UnicodeBlock.of(codePoint));
- List<String> codePoints;
- if (map.containsKey(block)) {
- codePoints = map.get(block);
- } else {
- codePoints = new ArrayList<>();
- map.put(block, codePoints);
- }
- codePoints.add(String.copyValueOf(Character.toChars(codePoint)));
- }
- return map;
- }
+ private static void colorize(
+ SpannableString spannableString, Pattern pattern, @ColorInt int color) {
+ Matcher matcher = pattern.matcher(spannableString);
+ while (matcher.find()) {
+ if (matcher.start() < matcher.end()) {
+ spannableString.setSpan(
+ new ForegroundColorSpan(color),
+ matcher.start(),
+ matcher.end(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ }
- @TargetApi(Build.VERSION_CODES.N)
- private static Map<Character.UnicodeScript, List<String>> map(String word) {
- Map<Character.UnicodeScript, List<String>> map = new HashMap<>();
- final int length = word.length();
- for (int offset = 0; offset < length; ) {
- final int codePoint = word.codePointAt(offset);
- Character.UnicodeScript script = Character.UnicodeScript.of(codePoint);
- if (script != Character.UnicodeScript.COMMON) {
- List<String> codePoints;
- if (map.containsKey(script)) {
- codePoints = map.get(script);
- } else {
- codePoints = new ArrayList<>();
- map.put(script, codePoints);
- }
- codePoints.add(String.copyValueOf(Character.toChars(codePoint)));
- }
- offset += Character.charCount(codePoint);
- }
- return map;
- }
+ private static Map<Character.UnicodeBlock, List<String>> mapCompat(String word) {
+ Map<Character.UnicodeBlock, List<String>> map = new HashMap<>();
+ final int length = word.length();
+ for (int offset = 0; offset < length; ) {
+ final int codePoint = word.codePointAt(offset);
+ offset += Character.charCount(codePoint);
+ if (!Character.isLetter(codePoint)) {
+ continue;
+ }
+ Character.UnicodeBlock block = normalize(Character.UnicodeBlock.of(codePoint));
+ List<String> codePoints;
+ if (map.containsKey(block)) {
+ codePoints = map.get(block);
+ } else {
+ codePoints = new ArrayList<>();
+ map.put(block, codePoints);
+ }
+ codePoints.add(String.copyValueOf(Character.toChars(codePoint)));
+ }
+ return map;
+ }
- private static Set<String> eliminateFirstAndGetCodePointsCompat(Map<Character.UnicodeBlock, List<String>> map) {
- return eliminateFirstAndGetCodePoints(map, Character.UnicodeBlock.BASIC_LATIN);
- }
+ @TargetApi(Build.VERSION_CODES.N)
+ private static Map<Character.UnicodeScript, List<String>> map(String word) {
+ Map<Character.UnicodeScript, List<String>> map = new HashMap<>();
+ final int length = word.length();
+ for (int offset = 0; offset < length; ) {
+ final int codePoint = word.codePointAt(offset);
+ Character.UnicodeScript script = Character.UnicodeScript.of(codePoint);
+ if (script != Character.UnicodeScript.COMMON) {
+ List<String> codePoints;
+ if (map.containsKey(script)) {
+ codePoints = map.get(script);
+ } else {
+ codePoints = new ArrayList<>();
+ map.put(script, codePoints);
+ }
+ codePoints.add(String.copyValueOf(Character.toChars(codePoint)));
+ }
+ offset += Character.charCount(codePoint);
+ }
+ return map;
+ }
- @TargetApi(Build.VERSION_CODES.N)
- private static Set<String> eliminateFirstAndGetCodePoints(Map<Character.UnicodeScript, List<String>> map) {
- return eliminateFirstAndGetCodePoints(map, Character.UnicodeScript.COMMON);
- }
+ private static Set<String> eliminateFirstAndGetCodePointsCompat(
+ Map<Character.UnicodeBlock, List<String>> map) {
+ return eliminateFirstAndGetCodePoints(map, Character.UnicodeBlock.BASIC_LATIN);
+ }
- private static <T> Set<String> eliminateFirstAndGetCodePoints(Map<T, List<String>> map, T defaultPick) {
- T pick = defaultPick;
- int size = 0;
- for (Map.Entry<T, List<String>> entry : map.entrySet()) {
- if (entry.getValue().size() > size) {
- size = entry.getValue().size();
- pick = entry.getKey();
- }
- }
- map.remove(pick);
- Set<String> all = new HashSet<>();
- for (List<String> codePoints : map.values()) {
- all.addAll(codePoints);
- }
- return all;
- }
+ @TargetApi(Build.VERSION_CODES.N)
+ private static Set<String> eliminateFirstAndGetCodePoints(
+ Map<Character.UnicodeScript, List<String>> map) {
+ return eliminateFirstAndGetCodePoints(map, Character.UnicodeScript.COMMON);
+ }
- private static Set<String> findIrregularCodePoints(String word) {
- Set<String> codePoints;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
- final Map<Character.UnicodeBlock, List<String>> map = mapCompat(word);
- final Set<String> set = asSet(map);
- if (containsOnlyAmbiguousCyrillic(set)) {
- return set;
- }
- codePoints = eliminateFirstAndGetCodePointsCompat(map);
- } else {
- final Map<Character.UnicodeScript, List<String>> map = map(word);
- final Set<String> set = asSet(map);
- if (containsOnlyAmbiguousCyrillic(set)) {
- return set;
- }
- codePoints = eliminateFirstAndGetCodePoints(map);
- }
- return codePoints;
- }
+ private static <T> Set<String> eliminateFirstAndGetCodePoints(
+ Map<T, List<String>> map, T defaultPick) {
+ T pick = defaultPick;
+ int size = 0;
+ for (Map.Entry<T, List<String>> entry : map.entrySet()) {
+ if (entry.getValue().size() > size) {
+ size = entry.getValue().size();
+ pick = entry.getKey();
+ }
+ }
+ map.remove(pick);
+ Set<String> all = new HashSet<>();
+ for (List<String> codePoints : map.values()) {
+ all.addAll(codePoints);
+ }
+ return all;
+ }
- private static Set<String> asSet(Map<?, List<String>> map) {
- final Set<String> flat = new HashSet<>();
- for(List<String> value : map.values()) {
- flat.addAll(value);
- }
- return flat;
- }
+ private static Set<String> findIrregularCodePoints(String word) {
+ Set<String> codePoints;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ final Map<Character.UnicodeBlock, List<String>> map = mapCompat(word);
+ final Set<String> set = asSet(map);
+ if (containsOnlyAmbiguousCyrillic(set)) {
+ return set;
+ }
+ codePoints = eliminateFirstAndGetCodePointsCompat(map);
+ } else {
+ final Map<Character.UnicodeScript, List<String>> map = map(word);
+ final Set<String> set = asSet(map);
+ if (containsOnlyAmbiguousCyrillic(set)) {
+ return set;
+ }
+ codePoints = eliminateFirstAndGetCodePoints(map);
+ }
+ return codePoints;
+ }
+ private static Set<String> asSet(Map<?, List<String>> map) {
+ final Set<String> flat = new HashSet<>();
+ for (List<String> value : map.values()) {
+ flat.addAll(value);
+ }
+ return flat;
+ }
- private static boolean containsOnlyAmbiguousCyrillic(Collection<String> codePoints) {
- for (String codePoint : codePoints) {
- if (!AMBIGUOUS_CYRILLIC.contains(codePoint)) {
- return false;
- }
- }
- return true;
- }
+ private static boolean containsOnlyAmbiguousCyrillic(Collection<String> codePoints) {
+ for (String codePoint : codePoints) {
+ if (!AMBIGUOUS_CYRILLIC.contains(codePoint)) {
+ return false;
+ }
+ }
+ return true;
+ }
- private static PatternTuple find(Jid jid) {
- synchronized (CACHE) {
- PatternTuple pattern = CACHE.get(jid);
- if (pattern != null) {
- return pattern;
- }
+ private static PatternTuple find(Jid jid) {
+ synchronized (CACHE) {
+ PatternTuple pattern = CACHE.get(jid);
+ if (pattern != null) {
+ return pattern;
+ }
pattern = PatternTuple.of(jid);
- CACHE.put(jid, pattern);
- return pattern;
- }
- }
+ CACHE.put(jid, pattern);
+ return pattern;
+ }
+ }
- private static Pattern create(Set<String> codePoints) {
- final StringBuilder pattern = new StringBuilder();
- for (String codePoint : codePoints) {
- if (pattern.length() != 0) {
- pattern.append('|');
- }
- pattern.append(Pattern.quote(codePoint));
- }
- return Pattern.compile(pattern.toString());
- }
+ private static Pattern create(Set<String> codePoints) {
+ final StringBuilder pattern = new StringBuilder();
+ for (String codePoint : codePoints) {
+ if (pattern.length() != 0) {
+ pattern.append('|');
+ }
+ pattern.append(Pattern.quote(codePoint));
+ }
+ return Pattern.compile(pattern.toString());
+ }
- private static class PatternTuple {
- private final Pattern local;
- private final List<Pattern> domain;
+ private static class PatternTuple {
+ private final Pattern local;
+ private final List<Pattern> domain;
- private PatternTuple(Pattern local, List<Pattern> domain) {
- this.local = local;
- this.domain = domain;
- }
+ private PatternTuple(Pattern local, List<Pattern> domain) {
+ this.local = local;
+ this.domain = domain;
+ }
- private static PatternTuple of(Jid jid) {
- final Pattern localPattern;
- if (jid.getEscapedLocal() != null) {
- localPattern = create(findIrregularCodePoints(jid.getEscapedLocal()));
- } else {
- localPattern = null;
- }
- String domain = jid.getDomain().toEscapedString();
- final List<Pattern> domainPatterns = new ArrayList<>();
- if (domain != null) {
- for (String label : domain.split("\\.")) {
- domainPatterns.add(create(findIrregularCodePoints(label)));
- }
- }
- return new PatternTuple(localPattern, domainPatterns);
- }
- }
+ private static PatternTuple of(Jid jid) {
+ final Pattern localPattern;
+ if (jid.getLocal() != null) {
+ localPattern = create(findIrregularCodePoints(jid.getLocal()));
+ } else {
+ localPattern = null;
+ }
+ String domain = jid.getDomain().toString();
+ final List<Pattern> domainPatterns = new ArrayList<>();
+ if (domain != null) {
+ for (String label : domain.split("\\.")) {
+ domainPatterns.add(create(findIrregularCodePoints(label)));
+ }
+ }
+ return new PatternTuple(localPattern, domainPatterns);
+ }
+ }
}
@@ -29,22 +29,19 @@
package eu.siacs.conversations.utils;
-
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.xmpp.Jid;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.xmpp.InvalidJid;
-import eu.siacs.conversations.xmpp.Jid;
-
public class JidHelper {
private static final List<String> LOCAL_PART_BLACKLIST = Arrays.asList("xmpp", "jabber", "me");
public static String localPartOrFallback(Jid jid) {
if (LOCAL_PART_BLACKLIST.contains(jid.getLocal().toLowerCase(Locale.ENGLISH))) {
- final String domain = jid.getDomain().toEscapedString();
+ final String domain = jid.getDomain().toString();
final int index = domain.indexOf('.');
return index > 1 ? domain.substring(0, index) : domain;
} else {
@@ -52,16 +49,7 @@ public class JidHelper {
}
}
- public static Jid parseOrFallbackToInvalid(String jid) {
- try {
- return Jid.of(jid);
- } catch (IllegalArgumentException e) {
- return InvalidJid.of(jid, true);
- }
- }
-
public static boolean isQuicksyDomain(final Jid jid) {
return Config.QUICKSY_DOMAIN != null && Config.QUICKSY_DOMAIN.equals(jid.getDomain());
}
-
}
@@ -20,10 +20,11 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.util.Log;
-
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
-
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.worker.ExportBackupWorker;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -35,21 +36,17 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.entities.Transferable;
-import eu.siacs.conversations.worker.ExportBackupWorker;
-
/**
- * Utilities for dealing with MIME types.
- * Used to implement java.net.URLConnection and android.webkit.MimeTypeMap.
+ * Utilities for dealing with MIME types. Used to implement java.net.URLConnection and
+ * android.webkit.MimeTypeMap.
*/
public final class MimeUtils {
- public static final List<String> AMBIGUOUS_CONTAINER_FORMATS = ImmutableList.of(
- "application/ogg",
- "video/3gpp", // .3gp files can contain audio, video or both
- "video/3gpp2"
- );
+ public static final List<String> AMBIGUOUS_CONTAINER_FORMATS =
+ ImmutableList.of(
+ "application/ogg",
+ "video/3gpp", // .3gp files can contain audio, video or both
+ "video/3gpp2");
private static final Map<String, String> mimeTypeToExtensionMap = new HashMap<>();
private static final Map<String, String> extensionToMimeTypeMap = new HashMap<>();
@@ -104,6 +101,7 @@ public final class MimeUtils {
add("application/vnd.oasis.opendocument.text-master", "odm");
add("application/vnd.oasis.opendocument.text-template", "ott");
add("application/vnd.oasis.opendocument.text-web", "oth");
+ add("application/vnd.oasis.opendocument.presentation", "odp");
add("application/vnd.google-earth.kml+xml", "kml");
add("application/vnd.google-earth.kmz", "kmz");
add("application/msword", "doc");
@@ -141,7 +139,7 @@ public final class MimeUtils {
add("application/vnd.sun.xml.writer.global", "sxg");
add("application/vnd.sun.xml.writer.template", "stw");
add("application/vnd.visio", "vsd");
- add("application/x-7z-compressed","7z");
+ add("application/x-7z-compressed", "7z");
add("application/x-abiword", "abw");
add("application/x-apple-diskimage", "dmg");
add("application/x-bcpio", "bcpio");
@@ -331,8 +329,8 @@ public final class MimeUtils {
add("image/x-xbitmap", "xbm");
add("image/x-xpixmap", "xpm");
add("image/x-xwindowdump", "xwd");
- add("message/rfc822","eml");
- add("message/rfc822","mime");
+ add("message/rfc822", "eml");
+ add("message/rfc822", "mime");
add("model/iges", "igs");
add("model/iges", "iges");
add("model/mesh", "msh");
@@ -353,7 +351,7 @@ public final class MimeUtils {
add("text/plain", "asc");
add("text/plain", "text");
add("text/plain", "diff");
- add("text/plain", "po"); // reserve "pot" for vnd.ms-powerpoint
+ add("text/plain", "po"); // reserve "pot" for vnd.ms-powerpoint
add("text/richtext", "rtx");
add("text/rtf", "rtf");
add("text/text", "phps");
@@ -424,7 +422,8 @@ public final class MimeUtils {
}
// mime types that are more reliant by path
- private static final Collection<String> PATH_PRECEDENCE_MIME_TYPE = Arrays.asList("audio/x-m4b");
+ private static final Collection<String> PATH_PRECEDENCE_MIME_TYPE =
+ Arrays.asList("audio/x-m4b");
private static void add(String mimeType, String extension) {
// If we have an existing x -> y mapping, we do not want to
@@ -453,7 +452,10 @@ public final class MimeUtils {
}
}
// Standard location?
- File f = new File(System.getProperty("java.home"), "lib" + File.separator + "content-types.properties");
+ File f =
+ new File(
+ System.getProperty("java.home"),
+ "lib" + File.separator + "content-types.properties");
if (f.exists()) {
try {
return new FileInputStream(f);
@@ -464,9 +466,9 @@ public final class MimeUtils {
}
/**
- * This isn't what the RI does. The RI doesn't have hard-coded defaults, so supplying your
- * own "content.types.user.table" means you don't get any of the built-ins, and the built-ins
- * come from "$JAVA_HOME/lib/content-types.properties".
+ * This isn't what the RI does. The RI doesn't have hard-coded defaults, so supplying your own
+ * "content.types.user.table" means you don't get any of the built-ins, and the built-ins come
+ * from "$JAVA_HOME/lib/content-types.properties".
*/
private static void applyOverrides() {
// Get the appropriate InputStream to read overrides from, if any.
@@ -492,8 +494,7 @@ public final class MimeUtils {
}
}
- private MimeUtils() {
- }
+ private MimeUtils() {}
/**
* Returns true if the given MIME type has an entry in the map.
@@ -535,9 +536,8 @@ public final class MimeUtils {
}
/**
- * Returns the registered extension for the given MIME type. Note that some
- * MIME types map to multiple extensions. This call will return the most
- * common extension for the given MIME type.
+ * Returns the registered extension for the given MIME type. Note that some MIME types map to
+ * multiple extensions. This call will return the most common extension for the given MIME type.
*
* @param mimeType A MIME type (i.e. text/plain)
* @return The extension for the given MIME type or null iff there is none.
@@ -549,10 +549,11 @@ public final class MimeUtils {
return mimeTypeToExtensionMap.get(mimeType.split(";")[0]);
}
- public static String guessMimeTypeFromUriAndMime(final Context context, final Uri uri, final String mime) {
- Log.d(Config.LOGTAG, "guessMimeTypeFromUriAndMime(" + uri + "," + mime+")");
+ public static String guessMimeTypeFromUriAndMime(
+ final Context context, final Uri uri, final String mime) {
+ Log.d(Config.LOGTAG, "guessMimeTypeFromUriAndMime(" + uri + "," + mime + ")");
final String mimeFromUri = guessMimeTypeFromUri(context, uri);
- Log.d(Config.LOGTAG,"mimeFromUri:"+mimeFromUri);
+ Log.d(Config.LOGTAG, "mimeFromUri:" + mimeFromUri);
if (PATH_PRECEDENCE_MIME_TYPE.contains(mimeFromUri)) {
return mimeFromUri;
} else if (mime == null || mime.equals("application/octet-stream")) {
@@ -580,7 +581,8 @@ public final class MimeUtils {
if (PATH_PRECEDENCE_MIME_TYPE.contains(mimeTypeFromPath)) {
return mimeTypeFromPath;
}
- if (mimeTypeContentResolver != null && !"application/octet-stream".equals(mimeTypeContentResolver)) {
+ if (mimeTypeContentResolver != null
+ && !"application/octet-stream".equals(mimeTypeContentResolver)) {
return mimeTypeContentResolver;
}
if (mimeTypeFromName != null) {
@@ -601,7 +603,8 @@ public final class MimeUtils {
}
private static String getDisplayName(final Context context, final Uri uri) {
- try (final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
+ try (final Cursor cursor =
+ context.getContentResolver().query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (index == -1) {
@@ -627,7 +630,8 @@ public final class MimeUtils {
return extractRelevantExtension(path, false);
}
- public static String extractRelevantExtension(final String path, final boolean ignoreCryptoExtension) {
+ public static String extractRelevantExtension(
+ final String path, final boolean ignoreCryptoExtension) {
if (Strings.isNullOrEmpty(path)) {
return null;
}
@@ -1,14 +1,12 @@
package eu.siacs.conversations.utils;
import android.net.Uri;
-
import androidx.annotation.NonNull;
-
import com.google.common.base.CharMatcher;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-
+import eu.siacs.conversations.xmpp.Jid;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
@@ -18,8 +16,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
-import eu.siacs.conversations.xmpp.Jid;
-
public class XmppUri {
public static final String ACTION_JOIN = "join";
@@ -42,8 +38,8 @@ public class XmppUri {
parse(Uri.parse(uri));
} catch (IllegalArgumentException e) {
try {
- jid = Jid.ofEscaped(uri).asBareJid().toEscapedString();
- } catch (IllegalArgumentException e2) {
+ jid = Jid.of(uri).asBareJid().toString();
+ } catch (final IllegalArgumentException e2) {
jid = null;
}
}
@@ -60,7 +56,8 @@ public class XmppUri {
private static Map<String, String> parseParameters(final String query, final char seperator) {
final ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
- final String[] pairs = query == null ? new String[0] : query.split(String.valueOf(seperator));
+ final String[] pairs =
+ query == null ? new String[0] : query.split(String.valueOf(seperator));
for (String pair : pairs) {
final String[] parts = pair.split("=", 2);
if (parts.length == 0) {
@@ -94,7 +91,7 @@ public class XmppUri {
final int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
builder.add(new Fingerprint(FingerprintType.OMEMO, value, id));
} catch (Exception e) {
- //ignoring invalid device id
+ // ignoring invalid device id
}
} else if ("omemo".equals(key)) {
builder.add(new Fingerprint(FingerprintType.OMEMO, value, 0));
@@ -103,7 +100,8 @@ public class XmppUri {
return builder.build();
}
- public static String getFingerprintUri(final String base, final List<XmppUri.Fingerprint> fingerprints, char separator) {
+ public static String getFingerprintUri(
+ final String base, final List<XmppUri.Fingerprint> fingerprints, char separator) {
final StringBuilder builder = new StringBuilder(base);
builder.append('?');
for (int i = 0; i < fingerprints.size(); ++i) {
@@ -145,8 +143,8 @@ public class XmppUri {
if (segments.size() >= 2 && segments.get(1).contains("@")) {
// sample : https://conversations.im/i/foo@bar.com
try {
- jid = Jid.ofEscaped(lameUrlDecode(segments.get(1))).toEscapedString();
- } catch (Exception e) {
+ jid = Jid.of(lameUrlDecode(segments.get(1))).toString();
+ } catch (final Exception e) {
jid = null;
}
} else if (segments.size() >= 3) {
@@ -172,7 +170,8 @@ public class XmppUri {
}
}
this.fingerprints = parseFingerprints(parameters);
- } else if ("imto".equalsIgnoreCase(scheme) && Arrays.asList("xmpp", "jabber").contains(uri.getHost())) {
+ } else if ("imto".equalsIgnoreCase(scheme)
+ && Arrays.asList("xmpp", "jabber").contains(uri.getHost())) {
// sample: imto://xmpp/foo@bar.com
try {
jid = URLDecoder.decode(uri.getEncodedPath(), "UTF-8").split("/")[1].trim();
@@ -195,15 +194,18 @@ public class XmppUri {
public boolean isAction(final String action) {
return Collections2.transform(
- parameters.keySet(),
- s -> CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('A', 'Z')).retainFrom(s)
- ).contains(action);
+ parameters.keySet(),
+ s ->
+ CharMatcher.inRange('a', 'z')
+ .or(CharMatcher.inRange('A', 'Z'))
+ .retainFrom(s))
+ .contains(action);
}
public Jid getJid() {
try {
- return this.jid == null ? null : Jid.ofEscaped(this.jid);
- } catch (IllegalArgumentException e) {
+ return this.jid == null ? null : Jid.ofUserInput(this.jid);
+ } catch (final IllegalArgumentException e) {
return null;
}
}
@@ -213,9 +215,9 @@ public class XmppUri {
return false;
}
try {
- Jid.ofEscaped(jid);
+ Jid.ofUserInput(jid);
return true;
- } catch (IllegalArgumentException e) {
+ } catch (final IllegalArgumentException e) {
return false;
}
}
@@ -264,7 +266,7 @@ public class XmppUri {
}
public boolean hasFingerprints() {
- return fingerprints.size() > 0;
+ return !fingerprints.isEmpty();
}
public enum FingerprintType {
@@ -14,7 +14,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.SystemClock;
import android.util.Log;
-
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.work.ForegroundInfo;
@@ -27,7 +26,6 @@ import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.gson.stream.JsonWriter;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore;
@@ -38,7 +36,6 @@ import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.utils.BackupFileHeader;
import eu.siacs.conversations.utils.Compatibility;
-
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -59,7 +56,6 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.zip.GZIPOutputStream;
-
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
@@ -166,7 +162,8 @@ public class ExportBackupWorker extends Worker {
Log.d(
Config.LOGTAG,
String.format(
- "skipping backup for %s because password is empty. unable to encrypt",
+ "skipping backup for %s because password is empty. unable to"
+ + " encrypt",
account.getJid().asBareJid()));
count++;
continue;
@@ -174,7 +171,7 @@ public class ExportBackupWorker extends Worker {
final String filename =
String.format(
"%s.%s.ceb",
- account.getJid().asBareJid().toEscapedString(),
+ account.getJid().asBareJid().toString(),
DATE_FORMAT.format(new Date()));
final File file = new File(FileBackend.getBackupDirectory(context), filename);
try {
@@ -1,14 +1,15 @@
package eu.siacs.conversations.xml;
import androidx.annotation.NonNull;
-
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.base.Strings;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
-
+import eu.siacs.conversations.utils.XmlHelper;
+import eu.siacs.conversations.xmpp.Jid;
+import im.conversations.android.xmpp.model.stanza.Message;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
@@ -16,7 +17,6 @@ import java.util.List;
import java.util.stream.Collectors;
import eu.siacs.conversations.utils.XmlHelper;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.stanza.Message;
@@ -188,9 +188,9 @@ public class Element implements Node {
final String jid = this.getAttribute(name);
if (jid != null && !jid.isEmpty()) {
try {
- return Jid.ofEscaped(jid);
+ return Jid.of(jid);
} catch (final IllegalArgumentException e) {
- return InvalidJid.of(jid, this instanceof Message);
+ return Jid.ofOrInvalid(jid, this instanceof Message);
}
}
return null;
@@ -205,7 +205,7 @@ public class Element implements Node {
public Element setAttribute(String name, Jid value) {
if (name != null && value != null) {
- this.attributes.put(name, value.toEscapedString());
+ this.attributes.put(name, value.toString());
}
return this;
}
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2018, Daniel Gultsch All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors
- * may be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package eu.siacs.conversations.xmpp;
-
-import androidx.annotation.NonNull;
-
-import im.conversations.android.xmpp.model.stanza.Stanza;
-
-public class InvalidJid implements Jid {
-
- private final String value;
-
- private InvalidJid(String jid) {
- this.value = jid;
- }
-
- public static Jid of(String jid, boolean fallback) {
- final int pos = jid.indexOf('/');
- if (fallback && pos >= 0 && jid.length() >= pos + 1) {
- if (jid.substring(pos+1).trim().isEmpty()) {
- return Jid.ofEscaped(jid.substring(0,pos));
- }
- }
- return new InvalidJid(jid);
- }
-
- @Override
- @NonNull
- public String toString() {
- return value;
- }
-
- @Override
- public boolean isFullJid() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public boolean isBareJid() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public boolean isDomainJid() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public Jid asBareJid() {
- throw new AssertionError("Not implemented");
- }
-
-
- @Override
- public Jid withResource(CharSequence charSequence) {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public String getLocal() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public String getEscapedLocal() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public Jid getDomain() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public String getResource() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public String toEscapedString() {
- throw new AssertionError("Not implemented");
- }
-
- @Override
- public int length() {
- return value.length();
- }
-
- @Override
- public char charAt(int index) {
- return value.charAt(index);
- }
-
- @Override
- public CharSequence subSequence(int start, int end) {
- return value.subSequence(start, end);
- }
-
- @Override
- public int compareTo(@NonNull Jid o) {
- throw new AssertionError("Not implemented");
- }
-
- public static Jid getNullForInvalid(Jid jid) {
- if (jid instanceof InvalidJid) {
- return null;
- } else {
- return jid;
- }
- }
-
- public static boolean isValid(Jid jid) {
- return !(jid instanceof InvalidJid);
- }
-
- public static boolean hasValidFrom(Stanza stanza) {
- final String from = stanza.getAttribute("from");
- if (from == null) {
- return false;
- }
- try {
- Jid.ofEscaped(from);
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
-}
@@ -1,20 +1,19 @@
package eu.siacs.conversations.xmpp;
+import androidx.annotation.NonNull;
+import com.google.common.base.CharMatcher;
+import im.conversations.android.xmpp.model.stanza.Stanza;
+import java.io.Serializable;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Domainpart;
import org.jxmpp.jid.parts.Localpart;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
-import java.io.Serializable;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public interface Jid extends Comparable<Jid>, Serializable, CharSequence {
-
- Pattern JID = Pattern.compile("^((.*?)@)?([^/@]+)(/(.*))?$");
+public abstract class Jid implements Comparable<Jid>, Serializable, CharSequence {
- static Jid of(CharSequence local, CharSequence domain, CharSequence resource) {
+ public static Jid of(
+ final CharSequence local, final CharSequence domain, final CharSequence resource) {
if (local == null) {
if (resource == null) {
return ofDomain(domain);
@@ -26,120 +25,312 @@ public interface Jid extends Comparable<Jid>, Serializable, CharSequence {
return ofLocalAndDomain(local, domain);
}
try {
- return new WrappedJid(JidCreate.entityFullFrom(
- Localpart.fromUnescaped(local.toString()),
- Domainpart.from(domain.toString()),
- Resourcepart.from(resource.toString())
- ));
- } catch (XmppStringprepException e) {
+ return new InternalRepresentation(
+ JidCreate.entityFullFrom(
+ Localpart.from(local.toString()),
+ Domainpart.from(domain.toString()),
+ Resourcepart.from(resource.toString())));
+ } catch (final XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
}
- static Jid ofEscaped(CharSequence local, CharSequence domain, CharSequence resource) {
+ public static Jid ofDomain(final CharSequence domain) {
try {
- if (resource == null) {
- return new WrappedJid(
- JidCreate.bareFrom(
- Localpart.from(local.toString()),
- Domainpart.from(domain.toString())
- )
- );
- }
- return new WrappedJid(JidCreate.entityFullFrom(
- Localpart.from(local.toString()),
- Domainpart.from(domain.toString()),
- Resourcepart.from(resource.toString())
- ));
- } catch (XmppStringprepException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
-
- static Jid ofDomain(CharSequence domain) {
- try {
- return new WrappedJid(JidCreate.domainBareFrom(domain));
- } catch (XmppStringprepException e) {
+ return new InternalRepresentation(JidCreate.domainBareFrom(domain));
+ } catch (final XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
}
- static Jid ofLocalAndDomain(CharSequence local, CharSequence domain) {
+ public static Jid ofLocalAndDomain(final CharSequence local, final CharSequence domain) {
try {
- return new WrappedJid(
+ return new InternalRepresentation(
JidCreate.bareFrom(
- Localpart.fromUnescaped(local.toString()),
- Domainpart.from(domain.toString())
- )
- );
- } catch (XmppStringprepException e) {
+ Localpart.from(local.toString()), Domainpart.from(domain.toString())));
+ } catch (final XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
}
- static Jid ofDomainAndResource(CharSequence domain, CharSequence resource) {
+ public static Jid ofDomainAndResource(CharSequence domain, CharSequence resource) {
try {
- return new WrappedJid(
+ return new InternalRepresentation(
JidCreate.domainFullFrom(
Domainpart.from(domain.toString()),
- Resourcepart.from(resource.toString())
- ));
- } catch (XmppStringprepException e) {
+ Resourcepart.from(resource.toString())));
+ } catch (final XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
}
- static Jid ofLocalAndDomainEscaped(CharSequence local, CharSequence domain) {
+ public static Jid of(final CharSequence input) {
+ if (input instanceof Jid jid) {
+ return jid;
+ }
try {
- return new WrappedJid(
- JidCreate.bareFrom(
- Localpart.from(local.toString()),
- Domainpart.from(domain.toString())
- )
- );
- } catch (XmppStringprepException e) {
+ return new InternalRepresentation(JidCreate.from(input));
+ } catch (final XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
}
- static Jid of(CharSequence jid) {
- if (jid instanceof Jid) {
- return (Jid) jid;
- }
- Matcher matcher = JID.matcher(jid);
- if (matcher.matches()) {
- return of(matcher.group(2), matcher.group(3), matcher.group(5));
- } else {
- throw new IllegalArgumentException("Could not parse JID: " + jid);
+ public static Jid ofUserInput(final CharSequence input) {
+ final var jid = of(input);
+ if (CharMatcher.is('@').matchesAnyOf(jid.getDomain())) {
+ throw new IllegalArgumentException("Domain should not contain @");
}
+ return jid;
+ }
+
+ public static Jid ofOrInvalid(final String input) {
+ return ofOrInvalid(input, false);
}
- static Jid ofEscaped(CharSequence jid) {
+ /**
+ * @param jid a string representation of the jid to parse
+ * @param fallback indicates whether an attempt should be made to parse a bare version of the
+ * jid
+ * @return an instance of Jid; may be Jid.Invalid
+ */
+ public static Jid ofOrInvalid(final String jid, final boolean fallback) {
try {
- return new WrappedJid(JidCreate.from(jid));
- } catch (final XmppStringprepException e) {
- throw new IllegalArgumentException(e);
+ return Jid.of(jid);
+ } catch (final IllegalArgumentException e) {
+ return Jid.invalidOf(jid, fallback);
}
}
- boolean isFullJid();
+ private static Jid invalidOf(final String jid, boolean fallback) {
+ final int pos = jid.indexOf('/');
+ if (fallback && pos >= 0 && jid.length() >= pos + 1) {
+ if (jid.substring(pos + 1).trim().isEmpty()) {
+ return Jid.of(jid.substring(0, pos));
+ }
+ }
+ return new Invalid(jid);
+ }
+
+ public abstract boolean isFullJid();
+
+ public abstract boolean isBareJid();
+
+ public abstract boolean isDomainJid();
+
+ public abstract Jid asBareJid();
- boolean isBareJid();
+ public abstract Jid withResource(CharSequence resource);
- boolean isDomainJid();
+ public abstract String getLocal();
- Jid asBareJid();
+ public abstract Jid getDomain();
- Jid withResource(CharSequence resource);
+ public abstract String getResource();
- String getLocal();
+ private static class InternalRepresentation extends Jid {
+ private final org.jxmpp.jid.Jid inner;
- String getEscapedLocal();
+ private InternalRepresentation(final org.jxmpp.jid.Jid inner) {
+ this.inner = inner;
+ }
+
+ @Override
+ public boolean isFullJid() {
+ return inner.isEntityFullJid() || inner.isDomainFullJid();
+ }
- Jid getDomain();
+ @Override
+ public boolean isBareJid() {
+ return inner.isDomainBareJid() || inner.isEntityBareJid();
+ }
- String getResource();
+ @Override
+ public boolean isDomainJid() {
+ return inner.isDomainBareJid() || inner.isDomainFullJid();
+ }
+
+ @Override
+ public Jid asBareJid() {
+ return new InternalRepresentation(inner.asBareJid());
+ }
+
+ @Override
+ public Jid withResource(CharSequence resource) {
+ final Localpart localpart = inner.getLocalpartOrNull();
+ try {
+ final Resourcepart resourcepart = Resourcepart.from(resource.toString());
+ if (localpart == null) {
+ return new InternalRepresentation(
+ JidCreate.domainFullFrom(inner.getDomain(), resourcepart));
+ } else {
+ return new InternalRepresentation(
+ JidCreate.fullFrom(localpart, inner.getDomain(), resourcepart));
+ }
+ } catch (XmppStringprepException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public String getLocal() {
+ final Localpart localpart = inner.getLocalpartOrNull();
+ return localpart == null ? null : localpart.toString();
+ }
+
+ @Override
+ public Jid getDomain() {
+ return new InternalRepresentation(inner.asDomainBareJid());
+ }
+
+ @Override
+ public String getResource() {
+ final Resourcepart resourcepart = inner.getResourceOrNull();
+ return resourcepart == null ? null : resourcepart.toString();
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return inner.toString();
+ }
+
+ @Override
+ public int length() {
+ return inner.length();
+ }
- String toEscapedString();
+ @Override
+ public char charAt(int i) {
+ return inner.charAt(i);
+ }
+
+ @NonNull
+ @Override
+ public CharSequence subSequence(int i, int i1) {
+ return inner.subSequence(i, i1);
+ }
+
+ @Override
+ public int compareTo(Jid jid) {
+ if (jid instanceof InternalRepresentation) {
+ return inner.compareTo(((InternalRepresentation) jid).inner);
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ InternalRepresentation that = (InternalRepresentation) o;
+ return inner.equals(that.inner);
+ }
+
+ @Override
+ public int hashCode() {
+ return inner.hashCode();
+ }
+ }
+
+ public static class Invalid extends Jid {
+
+ private final String value;
+
+ private Invalid(final String jid) {
+ this.value = jid;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean isFullJid() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public boolean isBareJid() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public boolean isDomainJid() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public Jid asBareJid() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public Jid withResource(CharSequence charSequence) {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public String getLocal() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public Jid getDomain() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public String getResource() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public int length() {
+ return value.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ return value.charAt(index);
+ }
+
+ @NonNull
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return value.subSequence(start, end);
+ }
+
+ @Override
+ public int compareTo(@NonNull Jid o) {
+ throw new AssertionError("Not implemented");
+ }
+
+ public static Jid getNullForInvalid(final Jid jid) {
+ if (jid instanceof Invalid) {
+ return null;
+ } else {
+ return jid;
+ }
+ }
+
+ public static boolean isValid(Jid jid) {
+ return !(jid instanceof Invalid);
+ }
+
+ public static boolean hasValidFrom(final Stanza stanza) {
+ final String from = stanza.getAttribute("from");
+ if (from == null) {
+ return false;
+ }
+ try {
+ Jid.of(from);
+ return true;
+ } catch (final IllegalArgumentException e) {
+ return false;
+ }
+ }
+ }
}
@@ -1,130 +0,0 @@
-package eu.siacs.conversations.xmpp;
-
-
-import androidx.annotation.NonNull;
-
-import org.jxmpp.jid.Jid;
-import org.jxmpp.jid.impl.JidCreate;
-import org.jxmpp.jid.parts.Localpart;
-import org.jxmpp.jid.parts.Resourcepart;
-import org.jxmpp.stringprep.XmppStringprepException;
-
-
-public class WrappedJid implements eu.siacs.conversations.xmpp.Jid {
- private final Jid inner;
-
- WrappedJid(Jid inner) {
- this.inner = inner;
- }
-
- @Override
- public boolean isFullJid() {
- return inner.isEntityFullJid() || inner.isDomainFullJid();
- }
-
- @Override
- public boolean isBareJid() {
- return inner.isDomainBareJid() || inner.isEntityBareJid();
- }
-
- @Override
- public boolean isDomainJid() {
- return inner.isDomainBareJid() || inner.isDomainFullJid();
- }
-
- @Override
- public eu.siacs.conversations.xmpp.Jid asBareJid() {
- return new WrappedJid(inner.asBareJid());
- }
-
- @Override
- public eu.siacs.conversations.xmpp.Jid withResource(CharSequence resource) {
- final Localpart localpart = inner.getLocalpartOrNull();
- try {
- final Resourcepart resourcepart = Resourcepart.from(resource.toString());
- if (localpart == null) {
- return new WrappedJid(JidCreate.domainFullFrom(inner.getDomain(),resourcepart));
- } else {
- return new WrappedJid(
- JidCreate.fullFrom(
- localpart,
- inner.getDomain(),
- resourcepart
- ));
- }
- } catch (XmppStringprepException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- @Override
- public String getLocal() {
- final Localpart localpart = inner.getLocalpartOrNull();
- return localpart == null ? null : localpart.asUnescapedString();
- }
-
- @Override
- public String getEscapedLocal() {
- final Localpart localpart = inner.getLocalpartOrNull();
- return localpart == null ? null : localpart.toString();
- }
-
- @Override
- public eu.siacs.conversations.xmpp.Jid getDomain() {
- return new WrappedJid(inner.asDomainBareJid());
- }
-
- @Override
- public String getResource() {
- final Resourcepart resourcepart = inner.getResourceOrNull();
- return resourcepart == null ? null : resourcepart.toString();
- }
-
- @Override
- public String toEscapedString() {
- return inner.toString();
- }
-
- @NonNull
- @Override
- public String toString() {
- return inner.asUnescapedString();
- }
-
- @Override
- public int length() {
- return inner.length();
- }
-
- @Override
- public char charAt(int i) {
- return inner.charAt(i);
- }
-
- @Override
- public CharSequence subSequence(int i, int i1) {
- return inner.subSequence(i,i1);
- }
-
- @Override
- public int compareTo(eu.siacs.conversations.xmpp.Jid jid) {
- if (jid instanceof WrappedJid) {
- return inner.compareTo(((WrappedJid) jid).inner);
- } else {
- return 0;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- WrappedJid that = (WrappedJid) o;
- return inner.equals(that.inner);
- }
-
- @Override
- public int hashCode() {
- return inner.hashCode();
- }
-}
@@ -2357,7 +2357,7 @@ public class XmppConnection implements Runnable {
for (final Element element : elements) {
if (element.getName().equals("item")) {
final Jid jid =
- InvalidJid.getNullForInvalid(
+ Jid.Invalid.getNullForInvalid(
element.getAttributeAsJid("jid"));
if (jid != null && !jid.equals(account.getDomain())) {
items.add(jid);
@@ -2522,7 +2522,7 @@ public class XmppConnection implements Runnable {
final Tag stream = Tag.start("stream:stream");
stream.setAttribute("to", account.getServer());
if (from) {
- stream.setAttribute("from", account.getJid().asBareJid().toEscapedString());
+ stream.setAttribute("from", account.getJid().asBareJid().toString());
}
stream.setAttribute("version", "1.0");
stream.setAttribute("xml:lang", LocalizedContent.STREAM_LANGUAGE);
@@ -2759,7 +2759,7 @@ public class XmppConnection implements Runnable {
public List<String> getMucServersWithholdAccount() {
final List<String> servers = getMucServers();
- servers.remove(account.getDomain().toEscapedString());
+ servers.remove(account.getDomain().toString());
return servers;
}
@@ -4,9 +4,7 @@ import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.util.Base64;
import android.util.Log;
-
import androidx.annotation.Nullable;
-
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -40,10 +38,8 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
import eu.siacs.conversations.xmpp.jingle.transports.InbandBytestreamsTransport;
import eu.siacs.conversations.xmpp.jingle.transports.Transport;
-
import im.conversations.android.xmpp.model.jingle.Jingle;
import im.conversations.android.xmpp.model.stanza.Iq;
-
import java.lang.ref.WeakReference;
import java.security.SecureRandom;
import java.util.Arrays;
@@ -353,7 +349,8 @@ public class JingleConnectionManager extends AbstractConnectionManager {
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": updated previous busy because call got picked up by another device");
+ + ": updated previous busy because call got picked up by"
+ + " another device");
mXmppConnectionService.getNotificationService().clearMissedCall(previousBusy);
return;
}
@@ -393,15 +390,14 @@ public class JingleConnectionManager extends AbstractConnectionManager {
final String theirSessionId = id.sessionId;
if (ComparisonChain.start()
.compare(ourSessionId, theirSessionId)
- .compare(
- account.getJid().toEscapedString(),
- id.with.toEscapedString())
+ .compare(account.getJid().toString(), id.with.toString())
.result()
> 0) {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
- + ": our session lost tie break. automatically accepting their session. winning Session="
+ + ": our session lost tie break. automatically accepting"
+ + " their session. winning Session="
+ theirSessionId);
// TODO a retract for this reason should probably include some indication of
// tie break
@@ -417,7 +413,8 @@ public class JingleConnectionManager extends AbstractConnectionManager {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
- + ": our session won tie break. waiting for other party to accept. winningSession="
+ + ": our session won tie break. waiting for other party to"
+ + " accept. winningSession="
+ ourSessionId);
// TODO reject their session with <tie-break/>?
}
@@ -453,7 +450,8 @@ public class JingleConnectionManager extends AbstractConnectionManager {
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": ignoring proposal because busy on this device but there are other devices");
+ + ": ignoring proposal because busy on this device but"
+ + " there are other devices");
}
} else {
final JingleRtpConnection rtpConnection =
@@ -772,11 +770,14 @@ public class JingleConnectionManager extends AbstractConnectionManager {
if (hasMatchingRtpSession(account, with, media) != null) {
Log.d(
Config.LOGTAG,
- "ignoring request to propose jingle session because the other party already created one for us");
+ "ignoring request to propose jingle session because the other party"
+ + " already created one for us");
// TODO return something that we can parse the connection of of
return null;
}
- throw new IllegalStateException("There is already a running RTP session");
+ throw new IllegalStateException(
+ "There is already a running RTP session. This should have been caught by"
+ + " the UI");
}
final CallIntegration callIntegration =
new CallIntegration(mXmppConnectionService.getApplicationContext());
@@ -8,7 +8,6 @@ import android.os.Environment;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -25,7 +24,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
-
import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -49,7 +47,6 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Proceed;
import eu.siacs.conversations.xmpp.jingle.stanzas.Propose;
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
-
import im.conversations.android.xmpp.model.jingle.Jingle;
import im.conversations.android.xmpp.model.stanza.Iq;
@@ -72,6 +69,10 @@ import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import org.webrtc.EglBase;
+import org.webrtc.IceCandidate;
+import org.webrtc.PeerConnection;
+import org.webrtc.VideoTrack;
public class JingleRtpConnection extends AbstractJingleConnection
implements WebRTCWrapper.EventCallback, CallIntegration.Callback, OngoingRtpSession {
@@ -288,7 +289,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": PeerConnection was not initialized when processing transport info. this usually indicates a race condition that can be ignored");
+ + ": PeerConnection was not initialized when processing transport info."
+ + " this usually indicates a race condition that can be ignored");
}
}
@@ -635,7 +637,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.getAccount().getJid().asBareJid()
- + ": unable to rollback local description after receiving content-reject",
+ + ": unable to rollback local description after receiving"
+ + " content-reject",
cause);
webRTCWrapper.close();
sendSessionTerminate(Reason.FAILED_APPLICATION, cause.getMessage());
@@ -704,7 +707,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.getAccount().getJid().asBareJid()
- + ": unable to rollback local description after trying to retract content-add",
+ + ": unable to rollback local description after trying to retract"
+ + " content-add",
cause);
webRTCWrapper.close();
sendSessionTerminate(Reason.FAILED_APPLICATION, cause.getMessage());
@@ -783,14 +787,16 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": remote has accepted our upgrade to senders=both");
+ + ": remote has accepted our upgrade to"
+ + " senders=both");
acceptContentAdd(
ContentAddition.summary(modifiedSenders), modifiedSenders);
} else {
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": remote has rejected our upgrade to senders=both");
+ + ": remote has rejected our upgrade to"
+ + " senders=both");
acceptContentAdd(contentAddition, incomingContentAdd);
}
});
@@ -1082,7 +1088,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": no identification tags found in initial offer. we won't be able to calculate mLineIndices");
+ + ": no identification tags found in initial offer. we won't be able to"
+ + " calculate mLineIndices");
}
return identificationTags;
}
@@ -1179,7 +1186,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
sendSessionTerminate(
Reason.SECURITY_ERROR,
String.format(
- "Your session proposal (Jingle Message Initiation) included media %s but your session-initiate was %s",
+ "Your session proposal (Jingle Message Initiation) included media"
+ + " %s but your session-initiate was %s",
this.proposedMedia, contentMap.getMedia()));
return;
}
@@ -1264,7 +1272,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
sendSessionTerminate(
Reason.SECURITY_ERROR,
String.format(
- "Your session-included included media %s but our session-initiate was %s",
+ "Your session-included included media %s but our session-initiate was"
+ + " %s",
this.proposedMedia, contentMap.getMedia()));
return;
}
@@ -1352,7 +1361,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": ICE servers got discovered when session was already terminated. nothing to do.");
+ + ": ICE servers got discovered when session was already terminated."
+ + " nothing to do.");
return;
}
final boolean includeCandidates = remoteHasSdpOfferAnswer();
@@ -1455,7 +1465,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": preparing session accept was too slow. already terminated. nothing to do.");
+ + ": preparing session accept was too slow. already terminated. nothing"
+ + " to do.");
return;
}
transitionOrThrow(State.SESSION_ACCEPTED);
@@ -1498,10 +1509,10 @@ public class JingleRtpConnection extends AbstractJingleConnection
+ ": delivered message to JingleRtpConnection "
+ message);
switch (message.getName()) {
- case "propose" -> receivePropose(
- from, Propose.upgrade(message), serverMessageId, timestamp);
- case "proceed" -> receiveProceed(
- from, Proceed.upgrade(message), serverMessageId, timestamp);
+ case "propose" ->
+ receivePropose(from, Propose.upgrade(message), serverMessageId, timestamp);
+ case "proceed" ->
+ receiveProceed(from, Proceed.upgrade(message), serverMessageId, timestamp);
case "retract" -> receiveRetract(from, serverMessageId, timestamp);
case "reject" -> receiveReject(from, serverMessageId, timestamp);
case "accept" -> receiveAccept(from, serverMessageId, timestamp);
@@ -1615,7 +1626,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid()
- + ": received reject while in SESSION_INITIATED_PRE_APPROVED. callee reconsidered before receiving session-init");
+ + ": received reject while in SESSION_INITIATED_PRE_APPROVED. callee"
+ + " reconsidered before receiving session-init");
closeTransitionLogFinish(State.TERMINATED_DECLINED_OR_BUSY);
return;
}
@@ -1737,7 +1749,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": remote party signaled support for OMEMO verification but we have OMEMO disabled");
+ + ": remote party signaled support for OMEMO"
+ + " verification but we have OMEMO disabled");
}
this.omemoVerification.setDeviceId(null);
}
@@ -1832,7 +1845,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": ICE servers got discovered when session was already terminated. nothing to do.");
+ + ": ICE servers got discovered when session was already terminated."
+ + " nothing to do.");
return;
}
final boolean includeCandidates = remoteHasSdpOfferAnswer();
@@ -1927,7 +1941,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": preparing session was too slow. already terminated. nothing to do.");
+ + ": preparing session was too slow. already terminated. nothing to"
+ + " do.");
return;
}
this.transitionOrThrow(targetState);
@@ -1966,7 +1981,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": unable to use OMEMO DTLS verification on outgoing session initiate. falling back",
+ + ": unable to use OMEMO DTLS verification on outgoing"
+ + " session initiate. falling back",
e);
return rtpContentMap;
},
@@ -2080,9 +2096,10 @@ public class JingleRtpConnection extends AbstractJingleConnection
case CONNECTED -> RtpEndUserState.CONNECTED;
case NEW, CONNECTING -> RtpEndUserState.CONNECTING;
case CLOSED -> RtpEndUserState.ENDING_CALL;
- default -> zeroDuration()
- ? RtpEndUserState.CONNECTIVITY_ERROR
- : RtpEndUserState.RECONNECTING;
+ default ->
+ zeroDuration()
+ ? RtpEndUserState.CONNECTIVITY_ERROR
+ : RtpEndUserState.RECONNECTING;
};
}
@@ -2126,13 +2143,14 @@ public class JingleRtpConnection extends AbstractJingleConnection
}
case TERMINATED_SUCCESS -> this.callIntegration.success();
case ACCEPTED -> this.callIntegration.accepted();
- case RETRACTED, RETRACTED_RACED, TERMINATED_CANCEL_OR_TIMEOUT -> this.callIntegration
- .retracted();
+ case RETRACTED, RETRACTED_RACED, TERMINATED_CANCEL_OR_TIMEOUT ->
+ this.callIntegration.retracted();
case TERMINATED_CONNECTIVITY_ERROR,
- TERMINATED_APPLICATION_FAILURE,
- TERMINATED_SECURITY_ERROR -> this.callIntegration.error();
- default -> throw new IllegalStateException(
- String.format("%s is not handled", this.state));
+ TERMINATED_APPLICATION_FAILURE,
+ TERMINATED_SECURITY_ERROR ->
+ this.callIntegration.error();
+ default ->
+ throw new IllegalStateException(String.format("%s is not handled", this.state));
}
}
@@ -2205,14 +2223,18 @@ public class JingleRtpConnection extends AbstractJingleConnection
cancelRingingTimeout();
acceptCallFromSessionInitialized();
}
- case ACCEPTED -> Log.w(
- Config.LOGTAG,
- id.account.getJid().asBareJid()
- + ": the call has already been accepted with another client. UI was just lagging behind");
- case PROCEED, SESSION_ACCEPTED -> Log.w(
- Config.LOGTAG,
- id.account.getJid().asBareJid()
- + ": the call has already been accepted. user probably double tapped the UI");
+ case ACCEPTED ->
+ Log.w(
+ Config.LOGTAG,
+ id.account.getJid().asBareJid()
+ + ": the call has already been accepted with another client."
+ + " UI was just lagging behind");
+ case PROCEED, SESSION_ACCEPTED ->
+ Log.w(
+ Config.LOGTAG,
+ id.account.getJid().asBareJid()
+ + ": the call has already been accepted. user probably double"
+ + " tapped the UI");
default -> throw new IllegalStateException("Can not accept call from " + this.state);
}
}
@@ -2222,7 +2244,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": received rejectCall() when session has already been terminated. nothing to do");
+ + ": received rejectCall() when session has already been terminated."
+ + " nothing to do");
return;
}
switch (this.state) {
@@ -2255,7 +2278,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.w(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": received endCall() when session has already been terminated. nothing to do");
+ + ": received endCall() when session has already been terminated."
+ + " nothing to do");
return;
}
if (isInState(State.PROPOSED) && isResponder()) {
@@ -2457,7 +2481,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": not sending session-terminate after connectivity error because session is already in state "
+ + ": not sending session-terminate after connectivity error"
+ + " because session is already in state "
+ this.state);
return;
}
@@ -2659,7 +2684,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
Log.d(
Config.LOGTAG,
id.account.getJid().asBareJid()
- + ": no need to send session-terminate after failed connection. Other party already did");
+ + ": no need to send session-terminate after failed connection."
+ + " Other party already did");
return;
}
sendSessionTerminate(Reason.CONNECTIVITY_ERROR);
@@ -2714,7 +2740,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
// callback when the rtp session has already ended.
Log.w(
Config.LOGTAG,
- "CallIntegration requested incoming call UI but session was already terminated");
+ "CallIntegration requested incoming call UI but session was already"
+ + " terminated");
return;
}
// TODO apparently this can be called too early as well?
@@ -2746,8 +2773,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
// we need to start the UI to a) show it and b) be able to ask for permissions
final Intent intent = new Intent(xmppConnectionService, RtpSessionActivity.class);
intent.setAction(RtpSessionActivity.ACTION_ACCEPT_CALL);
- intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().toEscapedString());
- intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toEscapedString());
+ intent.putExtra(RtpSessionActivity.EXTRA_ACCOUNT, id.account.getJid().toString());
+ intent.putExtra(RtpSessionActivity.EXTRA_WITH, id.with.toString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(RtpSessionActivity.EXTRA_SESSION_ID, id.sessionId);
@@ -1,10 +1,8 @@
package eu.siacs.conversations.xmpp.jingle.transports;
import android.util.Log;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Optional;
@@ -22,7 +20,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.SocksSocketFactory;
import eu.siacs.conversations.xml.Element;
@@ -33,7 +30,6 @@ import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
import eu.siacs.conversations.xmpp.jingle.DirectConnectionUtils;
import eu.siacs.conversations.xmpp.jingle.stanzas.SocksByteStreamsTransportInfo;
import im.conversations.android.xmpp.model.stanza.Iq;
-
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -104,8 +100,8 @@ public class SocksByteStreamsTransport implements Transport {
.join(
Arrays.asList(
streamId,
- id.with.toEscapedString(),
- id.account.getJid().toEscapedString())),
+ id.with.toString(),
+ id.account.getJid().toString())),
StandardCharsets.UTF_8)
.toString();
final var ourDestination =
@@ -115,8 +111,8 @@ public class SocksByteStreamsTransport implements Transport {
.join(
Arrays.asList(
streamId,
- id.account.getJid().toEscapedString(),
- id.with.toEscapedString())),
+ id.account.getJid().toString(),
+ id.with.toString())),
StandardCharsets.UTF_8)
.toString();
@@ -255,7 +251,7 @@ public class SocksByteStreamsTransport implements Transport {
final Element query = proxyActivation.addChild("query", Namespace.BYTE_STREAMS);
query.setAttribute("sid", this.streamId);
final Element activate = query.addChild("activate");
- activate.setContent(id.with.toEscapedString());
+ activate.setContent(id.with.toString());
xmppConnection.sendIqPacket(
proxyActivation,
(response) -> {
@@ -731,10 +727,12 @@ public class SocksByteStreamsTransport implements Transport {
&& selectedByThemCandidatePriority > candidate.priority) {
Log.d(
Config.LOGTAG,
- "The candidate selected by peer had a higher priority then anything we could try");
+ "The candidate selected by peer had a higher priority then anything we"
+ + " could try");
connectionFuture.setException(
new CandidateErrorException(
- "The candidate selected by peer had a higher priority then anything we could try"));
+ "The candidate selected by peer had a higher priority then"
+ + " anything we could try"));
return;
}
try {
@@ -864,7 +862,7 @@ public class SocksByteStreamsTransport implements Transport {
return new Candidate(
cid,
host,
- Jid.ofEscaped(jid),
+ Jid.of(jid),
Integer.parseInt(port),
Integer.parseInt(priority),
CandidateType.valueOf(type.toUpperCase(Locale.ROOT)));
@@ -3,11 +3,8 @@ package im.conversations.android.xmpp.model;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
-
import eu.siacs.conversations.xml.Element;
-
import im.conversations.android.xmpp.ExtensionFactory;
-
import java.util.Collection;
public class Extension extends Element {
@@ -39,6 +36,14 @@ public class Extension extends Element {
return clazz.cast(extension);
}
+ public <E extends Extension> E getOnlyExtension(final Class<E> clazz) {
+ final var extensions = getExtensions(clazz);
+ if (extensions.size() == 1) {
+ return Iterables.getOnlyElement(extensions);
+ }
+ return null;
+ }
+
public <E extends Extension> Collection<E> getExtensions(final Class<E> clazz) {
return Collections2.transform(
Collections2.filter(getChildren(), clazz::isInstance), clazz::cast);
@@ -1,7 +1,6 @@
package im.conversations.android.xmpp.model.bind;
import com.google.common.base.Strings;
-
import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension;
@@ -26,7 +25,7 @@ public class Bind extends Extension {
return null;
}
try {
- return eu.siacs.conversations.xmpp.Jid.ofEscaped(content);
+ return eu.siacs.conversations.xmpp.Jid.of(content);
} catch (final IllegalArgumentException e) {
return null;
}
@@ -1,7 +1,6 @@
package im.conversations.android.xmpp.model.sasl2;
import com.google.common.base.Strings;
-
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension;
@@ -9,18 +8,17 @@ import im.conversations.android.xmpp.model.Extension;
@XmlElement
public class AuthorizationIdentifier extends Extension {
-
public AuthorizationIdentifier() {
super(AuthorizationIdentifier.class);
}
public Jid get() {
final var content = getContent();
- if ( Strings.isNullOrEmpty(content)) {
+ if (Strings.isNullOrEmpty(content)) {
return null;
}
try {
- return Jid.ofEscaped(content);
+ return Jid.of(content);
} catch (final IllegalArgumentException e) {
return null;
}
@@ -1,10 +1,7 @@
package im.conversations.android.xmpp.model.stanza;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
-
-import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.StreamElement;
import im.conversations.android.xmpp.model.error.Error;
@@ -45,7 +42,7 @@ public abstract class Stanza extends StreamElement {
public boolean isInvalid() {
final var to = getTo();
final var from = getFrom();
- if (to instanceof InvalidJid || from instanceof InvalidJid) {
+ if (to instanceof Jid.Invalid || from instanceof Jid.Invalid) {
return true;
}
return false;
@@ -1,5 +1,12 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="48dp">
-
- <path android:fillColor="@android:color/white" android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/>
-
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:tint="#FFFFFF"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z" />
+
</vector>
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:tint="@android:color/white"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10,8v8l5,-4 -5,-4zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,5h14v14z" />
+
+</vector>
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:tint="@android:color/white"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM440,600L200,600L200,760Q200,760 200,760Q200,760 200,760L440,760L440,600ZM520,600L520,760L760,760Q760,760 760,760Q760,760 760,760L760,600L520,600ZM440,520L440,360L200,360L200,520L440,520ZM520,520L760,520L760,360L520,360L520,520ZM200,280L760,280L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,280Z" />
+</vector>
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
<merge>
@@ -104,14 +105,17 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginVertical="4dp"
- android:visibility="gone">
+ android:visibility="gone"
+ tools:visibility="visible">
- <ImageButton
+ <com.google.android.material.button.MaterialButton
+ style="?attr/materialIconButtonOutlinedStyle"
android:id="@+id/play_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:background="?android:selectableItemBackgroundBorderless" />
+ app:iconSize="26dp"
+ app:icon="@drawable/ic_play_arrow_24dp" />
<TextView
android:id="@+id/runtime"
@@ -529,7 +529,7 @@
<string name="this_field_is_required">Este campo es requerido</string>
<string name="correct_message">Corregir mensaje</string>
<string name="send_corrected_message">Enviar mensaje corregido</string>
- <string name="no_keys_just_confirm">Ya has confiado la huella digital de esta persona. Al seleccionar “Listo” solo estás confirmando que %s es parte de este chat grupal.</string>
+ <string name="no_keys_just_confirm">Ya has confiado en la huella digital de esta persona. Al seleccionar “Hecho” solo estás confirmando que %s es parte de este chat grupal.</string>
<string name="this_account_is_disabled">Has deshabilitado esta cuenta</string>
<string name="security_error_invalid_file_access">Error de seguridad: ¡Acceso a archivo inválido!</string>
<string name="no_application_to_share_uri">No se ha encontrado ninguna aplicación para compartir la URI</string>
@@ -1011,7 +1011,7 @@
<string name="contact_uses_unverified_keys">Tu contacto utiliza dispositivos no verificados. Escanea su código QR para realizar la verificación e impedir ataques MITM activos.</string>
<string name="log_out">Desconectarse</string>
<string name="account_state_logged_out">Desconectado</string>
- <string name="unverified_devices">Está utilizando dispositivos no verificados. Escanea el código QR en tus otros dispositivos para realizar la verificación e impedir ataques MITM activos.</string>
+ <string name="unverified_devices">Estás utilizando dispositivos no verificados. Escanea el código QR de tus otros dispositivos para realizar la verificación e impedir ataques MITM activos.</string>
<string name="report_spam_and_block">Informar de spam y bloquear al spammer</string>
<string name="report_spam">Informar sobre spam</string>
<string name="welcome_header_quicksy">¡Bienvenido a Quicksy!</string>
@@ -1059,7 +1059,7 @@
<string name="pref_title_trust_system_ca_store">Organismos de certificación</string>
<string name="pref_title_trust_system_ca_store_summary">Confiar en los certificados CA del sistema</string>
<string name="detect_mim">Requerir enlace al canal</string>
- <string name="detect_mim_summary">La vinculación de canales puede detectar algunos ataques al intermediario</string>
+ <string name="detect_mim_summary">La vinculación de canales puede detectar algunos ataques de intermediario</string>
<string name="pref_category_server_connection">Conexión al servidor</string>
<string name="pref_category_operating_system">Sistema operativo</string>
<string name="pref_category_on_this_device">En el dispositivo</string>
@@ -1103,7 +1103,7 @@
<string name="call_is_using_speaker">La llamada está usando el altavoz.</string>
<string name="call_is_using_bluetooth">La llamada está usando bluetooth.</string>
<string name="video_is_disabled_tap_to_enable">Video desactivado. Toca para activar.</string>
- <string name="server_info_login_mechanism">Apartado de inicio de sesión</string>
+ <string name="server_info_login_mechanism">Método de acceso</string>
<string name="could_not_add_reaction">No se pudo agregar la reacción</string>
<string name="add_reaction">Agregar reacción…</string>
<string name="add_reaction_title">Agregar reacción</string>
@@ -319,12 +319,12 @@
<string name="notification_restored_backup_title">Varmuuskopiosi on palautettu</string>
<string name="notification_restored_backup_subtitle">Älä unohda ottaa tiliä käyttöön.</string>
<string name="choose_file">Valitse tiedosto</string>
- <string name="receiving_x_file">Vastaanotetaan %1$s (%2$d%% valmis)</string>
+ <string name="receiving_x_file">Vastaanotetaan %1$s (%2$d% % valmiina)</string>
<string name="download_x_file">Lataa %s</string>
<string name="delete_x_file">Poista %s</string>
<string name="file">tiedosto</string>
<string name="open_x_file">Avaa %s</string>
- <string name="sending_file">Lähetetään (%1$d%% valmis)</string>
+ <string name="sending_file">lähetetään (%1$d% % valmiina)</string>
<string name="preparing_file">Valmistellaan tiedoston lähettämistä</string>
<string name="x_file_offered_for_download">%s tarjottu ladattavaksi</string>
<string name="cancel_transmission">Peru siirto</string>
@@ -454,7 +454,7 @@
<string name="download_failed_invalid_file">ダウンロード失敗: 無効なファイル</string>
<string name="account_status_tor_unavailable">Tor ネットワークが利用できません</string>
<string name="account_status_bind_failure">バインド失敗</string>
- <string name="account_status_host_unknown">そのサーバーはこのドメインに責任を持ちません</string>
+ <string name="account_status_host_unknown">このドメインに責任を持ちません</string>
<string name="server_info_broken">壊れています</string>
<string name="pref_presence_settings">在席状況</string>
<string name="pref_away_when_screen_off">デバイスがロックされているときは離席</string>
@@ -1089,4 +1089,5 @@
<string name="pref_chat_bubbles">ふきだし</string>
<string name="pref_chat_bubbles_summary">背景色、文字サイズ、プロフィール画像など</string>
<string name="pref_title_bubbles">ふきだし</string>
+ <string name="account_status_connection_timeout">接続タイムアウト</string>
</resources>
@@ -27,7 +27,7 @@
<string name="minutes_ago">%d minutos atrás</string>
<plurals name="x_unread_conversations">
<item quantity="one">%d conversa não lida</item>
- <item quantity="many">%d conversas não lidas</item>
+ <item quantity="many">%d de conversas não lidas</item>
<item quantity="other">%d conversas não lidas</item>
</plurals>
<string name="sending">enviando…</string>
@@ -444,7 +444,7 @@
<string name="dialog_manage_certs_positivebutton">Excluir a seleção</string>
<plurals name="toast_delete_certificates">
<item quantity="one">%d certificado cancelado</item>
- <item quantity="many">%d certificados cancelados</item>
+ <item quantity="many">%d de certificados cancelados</item>
<item quantity="other">%d certificados cancelados</item>
</plurals>
<string name="pref_quick_action_summary">Troca o botão \"Enviar\" pelo de ação rápida</string>
@@ -502,7 +502,7 @@
<string name="connected_accounts">%1$d de %2$d contas conectadas</string>
<plurals name="x_messages">
<item quantity="one">%d mensagem</item>
- <item quantity="many">%d mensagens</item>
+ <item quantity="many">%d de mensagens</item>
<item quantity="other">%d mensagens</item>
</plurals>
<string name="load_more_messages">Carregar mais mensagens</string>
@@ -628,32 +628,32 @@
<string name="distrust_omemo_key_text">Tem certeza que deseja remover a verificação para este dispositivo?\nEste dispositivo e as mensagens oriundas dele serão marcadas como \"não confiáveis\".</string>
<plurals name="seconds">
<item quantity="one">%d segundo</item>
- <item quantity="many">%d segundos</item>
+ <item quantity="many">%d de segundos</item>
<item quantity="other">%d segundos</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d minuto</item>
- <item quantity="many">%d minutos</item>
+ <item quantity="many">%d de minutos</item>
<item quantity="other">%d minutos</item>
</plurals>
<plurals name="hours">
<item quantity="one">%d hora</item>
- <item quantity="many">%d horas</item>
+ <item quantity="many">%d de horas</item>
<item quantity="other">%d horas</item>
</plurals>
<plurals name="days">
<item quantity="one">%d dia</item>
- <item quantity="many">%d dias</item>
+ <item quantity="many">%d de dias</item>
<item quantity="other">%d dias</item>
</plurals>
<plurals name="weeks">
<item quantity="one">%d semana</item>
- <item quantity="many">%d semanas</item>
+ <item quantity="many">%d de semanas</item>
<item quantity="other">%d semanas</item>
</plurals>
<plurals name="months">
<item quantity="one">%d mês</item>
- <item quantity="many">%d meses</item>
+ <item quantity="many">%d de meses</item>
<item quantity="other">%d meses</item>
</plurals>
<string name="pref_automatically_delete_messages">Exclusão automática de mensagens</string>
@@ -928,18 +928,18 @@
<string name="outgoing_call">Chamada realizada</string>
<string name="missed_call">Chamada perdida</string>
<plurals name="n_missed_calls_from_x">
- <item quantity="one">%1$d chamada perdida para %2$s</item>
- <item quantity="many">%1$d chamadas perdidas para %2$s</item>
- <item quantity="other">%1$d chamadas perdidas para %2$s</item>
+ <item quantity="one">%1$d chamada perdida de %2$s</item>
+ <item quantity="many">%1$d de chamadas perdidas de %2$s</item>
+ <item quantity="other">%1$d chamadas perdidas de %2$s</item>
</plurals>
<plurals name="n_missed_calls">
<item quantity="one">%d chamada perdida</item>
- <item quantity="many">%d chamadas perdidas</item>
+ <item quantity="many">%d de chamadas perdidas</item>
<item quantity="other">%d chamadas perdidas</item>
</plurals>
<plurals name="n_missed_calls_from_m_contacts">
<item quantity="one">%1$d chamadas perdidas de %2$d contato</item>
- <item quantity="many">%1$d chamadas perdidas de %2$d contatos</item>
+ <item quantity="many">%1$d de chamadas perdidas de %2$d contatos</item>
<item quantity="other">%1$d chamadas perdidas de %2$d contatos</item>
</plurals>
<string name="audio_call">Chamada de áudio</string>
@@ -967,7 +967,7 @@
<string name="add_contact_or_create_or_join_group_chat">Adicionar contato, criar ou associar-se a uma conversa em grupo ou descobrir canais</string>
<plurals name="view_users">
<item quantity="one">Ver %1$d participante</item>
- <item quantity="many">Ver %1$d participantes</item>
+ <item quantity="many">Ver %1$d de participantes</item>
<item quantity="other">Ver %1$d participantes</item>
</plurals>
<plurals name="some_messages_could_not_be_delivered">
@@ -1,11 +1,9 @@
package eu.siacs.conversations.services;
import android.util.Log;
-
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailabilityLight;
import com.google.firebase.messaging.FirebaseMessaging;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -15,7 +13,6 @@ import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.forms.Data;
-
import im.conversations.android.xmpp.model.stanza.Iq;
public class PushManagementService {
@@ -53,7 +50,7 @@ public class PushManagementService {
if (response.getType() == Iq.Type.RESULT && data != null) {
final Jid jid;
try {
- jid = Jid.ofEscaped(data.getValue("jid"));
+ jid = Jid.of(data.getValue("jid"));
} catch (final IllegalArgumentException e) {
Log.d(
Config.LOGTAG,
@@ -70,7 +67,8 @@ public class PushManagementService {
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
- + ": failed to enable push. invalid response from app server "
+ + ": failed to enable push. invalid response"
+ + " from app server "
+ response);
}
});
@@ -123,7 +121,8 @@ public class PushManagementService {
} catch (Exception e) {
Log.d(
Config.LOGTAG,
- "unable to get Firebase instance token due to bug in library ",
+ "unable to get Firebase instance token due to bug in"
+ + " library ",
e);
return;
}
@@ -1,21 +1,16 @@
package eu.siacs.conversations.entities;
import android.util.Base64;
-
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import eu.siacs.conversations.android.PhoneNumberContact;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.Jid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import eu.siacs.conversations.android.PhoneNumberContact;
-import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.Jid;
-
public class Entry implements Comparable<Entry> {
private final List<Jid> jids;
private final String number;
@@ -47,23 +42,25 @@ public class Entry implements Comparable<Entry> {
return entries;
}
- public static String statusQuo(final Collection<PhoneNumberContact> phoneNumberContacts, Collection<Contact> systemContacts) {
+ public static String statusQuo(
+ final Collection<PhoneNumberContact> phoneNumberContacts,
+ Collection<Contact> systemContacts) {
return statusQuo(ofPhoneNumberContactsAndContacts(phoneNumberContacts, systemContacts));
}
private static String statusQuo(final List<Entry> entries) {
Collections.sort(entries);
StringBuilder builder = new StringBuilder();
- for(Entry entry : entries) {
+ for (Entry entry : entries) {
if (builder.length() != 0) {
builder.append('\u001d');
}
builder.append(entry.getNumber());
List<Jid> jids = entry.getJids();
Collections.sort(jids);
- for(Jid jid : jids) {
+ for (Jid jid : jids) {
builder.append('\u001e');
- builder.append(jid.asBareJid().toEscapedString());
+ builder.append(jid.asBareJid().toString());
}
}
@SuppressWarnings("deprecation")
@@ -71,12 +68,16 @@ public class Entry implements Comparable<Entry> {
return new String(Base64.encode(sha1, Base64.DEFAULT)).trim();
}
- private static List<Entry> ofPhoneNumberContactsAndContacts(final Collection<PhoneNumberContact> phoneNumberContacts, Collection<Contact> systemContacts) {
+ private static List<Entry> ofPhoneNumberContactsAndContacts(
+ final Collection<PhoneNumberContact> phoneNumberContacts,
+ Collection<Contact> systemContacts) {
final ArrayList<Entry> entries = new ArrayList<>();
- for(Contact contact : systemContacts) {
- final PhoneNumberContact phoneNumberContact = PhoneNumberContact.findByUri(phoneNumberContacts, contact.getSystemAccount());
+ for (Contact contact : systemContacts) {
+ final PhoneNumberContact phoneNumberContact =
+ PhoneNumberContact.findByUri(phoneNumberContacts, contact.getSystemAccount());
if (phoneNumberContact != null && phoneNumberContact.getPhoneNumber() != null) {
- Entry entry = findOrCreateByPhoneNumber(entries, phoneNumberContact.getPhoneNumber());
+ Entry entry =
+ findOrCreateByPhoneNumber(entries, phoneNumberContact.getPhoneNumber());
entry.jids.add(contact.getJid().asBareJid());
}
}
@@ -84,7 +85,7 @@ public class Entry implements Comparable<Entry> {
}
private static Entry findOrCreateByPhoneNumber(final List<Entry> entries, String number) {
- for(Entry entry : entries) {
+ for (Entry entry : entries) {
if (entry.number.equals(number)) {
return entry;
}
@@ -3,16 +3,13 @@ package eu.siacs.conversations.ui;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
-
import androidx.databinding.DataBindingUtil;
-
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityEnterNameBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.AbstractQuickConversationsService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.AccountUtils;
-
import java.util.concurrent.atomic.AtomicBoolean;
public class EnterNameActivity extends XmppActivity
@@ -46,18 +43,18 @@ public class EnterNameActivity extends XmppActivity
if (AbstractQuickConversationsService.isQuicksyPlayStore()) {
intent = new Intent(getApplicationContext(), StartConversationActivity.class);
intent.putExtra("init", true);
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
} else {
intent = new Intent(this, PublishProfilePictureActivity.class);
intent.putExtra("setup", true);
}
- intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toString());
startActivity(intent);
finish();
}
@Override
- public void onSaveInstanceState(Bundle savedInstanceState) {
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
savedInstanceState.putBoolean("set_nick", this.setNick.get());
super.onSaveInstanceState(savedInstanceState);
}
@@ -1,22 +1,18 @@
package eu.siacs.conversations.utils;
import android.content.Context;
-import android.telephony.TelephonyManager;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
import eu.siacs.conversations.xmpp.Jid;
import io.michaelrocks.libphonenumber.android.NumberParseException;
import io.michaelrocks.libphonenumber.android.PhoneNumberUtil;
import io.michaelrocks.libphonenumber.android.Phonenumber;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
public class PhoneNumberUtilWrapper {
private static volatile PhoneNumberUtil instance;
-
public static String getCountryForCode(String code) {
Locale locale = new Locale("", code);
return locale.getDisplayCountry();
@@ -24,20 +20,28 @@ public class PhoneNumberUtilWrapper {
public static String toFormattedPhoneNumber(Context context, Jid jid) {
try {
- return getInstance(context).format(toPhoneNumber(context, jid), PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL).replace(' ','\u202F');
+ return getInstance(context)
+ .format(
+ toPhoneNumber(context, jid),
+ PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL)
+ .replace(' ', '\u202F');
} catch (Exception e) {
- return jid.getEscapedLocal();
+ return jid.getLocal();
}
}
- public static Phonenumber.PhoneNumber toPhoneNumber(Context context, Jid jid) throws NumberParseException {
- return getInstance(context).parse(jid.getEscapedLocal(), "de");
+ public static Phonenumber.PhoneNumber toPhoneNumber(Context context, Jid jid)
+ throws NumberParseException {
+ return getInstance(context).parse(jid.getLocal(), "de");
}
- public static String normalize(Context context, String input) throws IllegalArgumentException, NumberParseException {
- final Phonenumber.PhoneNumber number = getInstance(context).parse(input, LocationProvider.getUserCountry(context));
+ public static String normalize(Context context, String input)
+ throws IllegalArgumentException, NumberParseException {
+ final Phonenumber.PhoneNumber number =
+ getInstance(context).parse(input, LocationProvider.getUserCountry(context));
if (!getInstance(context).isValidNumber(number)) {
- throw new IllegalArgumentException(String.format("%s is not a valid phone number", input));
+ throw new IllegalArgumentException(
+ String.format("%s is not a valid phone number", input));
}
return normalize(context, number);
}
@@ -54,7 +58,6 @@ public class PhoneNumberUtilWrapper {
if (localInstance == null) {
instance = localInstance = PhoneNumberUtil.createInstance(context);
}
-
}
}
return localInstance;
@@ -63,10 +66,10 @@ public class PhoneNumberUtilWrapper {
public static List<Country> getCountries(final Context context) {
List<Country> countries = new ArrayList<>();
for (String region : getInstance(context).getSupportedRegions()) {
- countries.add(new Country(region, getInstance(context).getCountryCodeForRegion(region)));
+ countries.add(
+ new Country(region, getInstance(context).getCountryCodeForRegion(region)));
}
return countries;
-
}
public static class Country implements Comparable<Country> {
@@ -97,5 +100,4 @@ public class PhoneNumberUtilWrapper {
return name.compareTo(o.name);
}
}
-
}
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources></resources>