diff --git a/build.gradle b/build.gradle
index 1f95a139f8661c06a627c15f890fb0638ea45445..1839ee0bae642d83e5c6b25859706e5427c4c989 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,13 +42,13 @@ spotless {
dependencies {
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2'
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.3'
implementation project(':libs:annotation')
annotationProcessor project(':libs:annotation-processor')
- implementation 'androidx.viewpager:viewpager:1.0.0'
+ implementation 'androidx.viewpager:viewpager:1.1.0'
playstoreImplementation('com.google.firebase:firebase-messaging:24.1.0') {
exclude group: 'com.google.firebase', module: 'firebase-core'
@@ -59,6 +59,8 @@ dependencies {
quicksyPlaystoreImplementation 'com.google.android.gms:play-services-auth-api-phone:18.1.0'
implementation 'com.github.open-keychain.open-keychain:openpgp-api:v5.7.1'
implementation("com.github.CanHub:Android-Image-Cropper:2.0.0")
+ implementation "androidx.sharetarget:sharetarget:1.2.0"
+
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.exifinterface:exifinterface:1.3.7'
implementation 'androidx.cardview:cardview:1.0.0'
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index b621147724ca0088d4bf5aad295d37e79b867d75..ddc93f285f4393df4950420a44525b281cf870cd 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -124,14 +124,6 @@
android:name=".services.ImportBackupService"
android:exported="false"
android:foregroundServiceType="dataSync" />
-
-
-
-
-
+
-
+ android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
= 2) {
- db.execSQL("update " + Account.TABLENAME + " set "
- + Account.OPTIONS + " = " + Account.OPTIONS + " | 8");
+ db.execSQL(
+ "update "
+ + Account.TABLENAME
+ + " set "
+ + Account.OPTIONS
+ + " = "
+ + Account.OPTIONS
+ + " | 8");
}
if (oldVersion < 3 && newVersion >= 3) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.TYPE + " NUMBER");
+ db.execSQL(
+ "ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.TYPE + " NUMBER");
}
if (oldVersion < 5 && newVersion >= 5) {
db.execSQL("DROP TABLE " + Contact.TABLENAME);
db.execSQL(CREATE_CONTATCS_STATEMENT);
- db.execSQL("UPDATE " + Account.TABLENAME + " SET "
- + Account.ROSTERVERSION + " = NULL");
+ db.execSQL("UPDATE " + Account.TABLENAME + " SET " + Account.ROSTERVERSION + " = NULL");
}
if (oldVersion < 6 && newVersion >= 6) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.TRUE_COUNTERPART + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.TRUE_COUNTERPART
+ + " TEXT");
}
if (oldVersion < 7 && newVersion >= 7) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.REMOTE_MSG_ID + " TEXT");
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
- + Contact.AVATAR + " TEXT");
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN "
- + Account.AVATAR + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.REMOTE_MSG_ID
+ + " TEXT");
+ db.execSQL(
+ "ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.AVATAR + " TEXT");
+ db.execSQL(
+ "ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.AVATAR + " TEXT");
}
if (oldVersion < 8 && newVersion >= 8) {
- db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN "
- + Conversation.ATTRIBUTES + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Conversation.TABLENAME
+ + " ADD COLUMN "
+ + Conversation.ATTRIBUTES
+ + " TEXT");
}
if (oldVersion < 9 && newVersion >= 9) {
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
- + Contact.LAST_TIME + " NUMBER");
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
- + Contact.LAST_PRESENCE + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Contact.TABLENAME
+ + " ADD COLUMN "
+ + Contact.LAST_TIME
+ + " NUMBER");
+ db.execSQL(
+ "ALTER TABLE "
+ + Contact.TABLENAME
+ + " ADD COLUMN "
+ + Contact.LAST_PRESENCE
+ + " TEXT");
}
if (oldVersion < 10 && newVersion >= 10) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.RELATIVE_FILE_PATH + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.RELATIVE_FILE_PATH
+ + " TEXT");
}
if (oldVersion < 11 && newVersion >= 11) {
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
- + Contact.GROUPS + " TEXT");
+ db.execSQL(
+ "ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.GROUPS + " TEXT");
db.execSQL("delete from " + Contact.TABLENAME);
db.execSQL("update " + Account.TABLENAME + " set " + Account.ROSTERVERSION + " = NULL");
}
if (oldVersion < 12 && newVersion >= 12) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.SERVER_MSG_ID + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.SERVER_MSG_ID
+ + " TEXT");
}
if (oldVersion < 13 && newVersion >= 13) {
db.execSQL("delete from " + Contact.TABLENAME);
@@ -348,26 +602,60 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
if (oldVersion < 15 && newVersion >= 15) {
recreateAxolotlDb(db);
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.FINGERPRINT + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.FINGERPRINT
+ + " TEXT");
}
if (oldVersion < 16 && newVersion >= 16) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
- + Message.CARBON + " INTEGER");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.CARBON
+ + " INTEGER");
}
if (oldVersion < 19 && newVersion >= 19) {
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.DISPLAY_NAME + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.DISPLAY_NAME
+ + " TEXT");
}
if (oldVersion < 20 && newVersion >= 20) {
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.HOSTNAME + " TEXT");
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.PORT + " NUMBER DEFAULT 5222");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.HOSTNAME
+ + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.PORT
+ + " NUMBER DEFAULT 5222");
}
if (oldVersion < 26 && newVersion >= 26) {
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS + " TEXT");
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS_MESSAGE + " TEXT");
+ db.execSQL(
+ "ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.STATUS + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.STATUS_MESSAGE
+ + " TEXT");
}
if (oldVersion < 40 && newVersion >= 40) {
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.RESOURCE + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.RESOURCE
+ + " TEXT");
}
/* Any migrations that alter the Account table need to happen BEFORE this migration, as it
* depends on account de-serialization.
@@ -375,45 +663,67 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (oldVersion < 17 && newVersion >= 17 && newVersion < 31) {
List accounts = getAccounts(db);
for (Account account : accounts) {
- String ownDeviceIdString = account.getKey(SQLiteAxolotlStore.JSONKEY_REGISTRATION_ID);
+ String ownDeviceIdString =
+ account.getKey(SQLiteAxolotlStore.JSONKEY_REGISTRATION_ID);
if (ownDeviceIdString == null) {
continue;
}
int ownDeviceId = Integer.valueOf(ownDeviceIdString);
- SignalProtocolAddress ownAddress = new SignalProtocolAddress(account.getJid().asBareJid().toString(), ownDeviceId);
+ SignalProtocolAddress ownAddress =
+ new SignalProtocolAddress(
+ account.getJid().asBareJid().toString(), ownDeviceId);
deleteSession(db, account, ownAddress);
IdentityKeyPair identityKeyPair = loadOwnIdentityKeyPair(db, account);
if (identityKeyPair != null) {
String[] selectionArgs = {
- account.getUuid(),
- CryptoHelper.bytesToHex(identityKeyPair.getPublicKey().serialize())
+ account.getUuid(),
+ CryptoHelper.bytesToHex(identityKeyPair.getPublicKey().serialize())
};
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.TRUSTED, 2);
- db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, values,
- SQLiteAxolotlStore.ACCOUNT + " = ? AND "
- + SQLiteAxolotlStore.FINGERPRINT + " = ? ",
+ db.update(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ values,
+ SQLiteAxolotlStore.ACCOUNT
+ + " = ? AND "
+ + SQLiteAxolotlStore.FINGERPRINT
+ + " = ? ",
selectionArgs);
} else {
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not load own identity key pair");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": could not load own identity key pair");
}
}
}
if (oldVersion < 18 && newVersion >= 18) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.READ + " NUMBER DEFAULT 1");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.READ
+ + " NUMBER DEFAULT 1");
}
if (oldVersion < 21 && newVersion >= 21) {
List accounts = getAccounts(db);
for (Account account : accounts) {
account.unsetPgpSignature();
- db.update(Account.TABLENAME, account.getContentValues(), Account.UUID
- + "=?", new String[]{account.getUuid()});
+ db.update(
+ Account.TABLENAME,
+ account.getContentValues(),
+ Account.UUID + "=?",
+ new String[] {account.getUuid()});
}
}
if (oldVersion >= 15 && oldVersion < 22 && newVersion >= 22) {
- db.execSQL("ALTER TABLE " + SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore.CERTIFICATE);
+ db.execSQL(
+ "ALTER TABLE "
+ + SQLiteAxolotlStore.IDENTITIES_TABLENAME
+ + " ADD COLUMN "
+ + SQLiteAxolotlStore.CERTIFICATE);
}
if (oldVersion < 23 && newVersion >= 23) {
@@ -421,11 +731,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
if (oldVersion < 24 && newVersion >= 24) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.EDITED + " TEXT");
+ db.execSQL(
+ "ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.EDITED + " TEXT");
}
if (oldVersion < 25 && newVersion >= 25) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.OOB + " INTEGER");
+ db.execSQL(
+ "ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.OOB + " INTEGER");
}
if (oldVersion < 26 && newVersion >= 26) {
@@ -441,51 +753,116 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
if (oldVersion < 29 && newVersion >= 29) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.ERROR_MESSAGE + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.ERROR_MESSAGE
+ + " TEXT");
}
if (oldVersion >= 15 && oldVersion < 31 && newVersion >= 31) {
- db.execSQL("ALTER TABLE " + SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore.TRUST + " TEXT");
- db.execSQL("ALTER TABLE " + SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore.ACTIVE + " NUMBER");
+ db.execSQL(
+ "ALTER TABLE "
+ + SQLiteAxolotlStore.IDENTITIES_TABLENAME
+ + " ADD COLUMN "
+ + SQLiteAxolotlStore.TRUST
+ + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + SQLiteAxolotlStore.IDENTITIES_TABLENAME
+ + " ADD COLUMN "
+ + SQLiteAxolotlStore.ACTIVE
+ + " NUMBER");
HashMap migration = new HashMap<>();
- migration.put(0, createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, true));
- migration.put(1, createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, true));
- migration.put(2, createFingerprintStatusContentValues(FingerprintStatus.Trust.UNTRUSTED, true));
- migration.put(3, createFingerprintStatusContentValues(FingerprintStatus.Trust.COMPROMISED, false));
- migration.put(4, createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, false));
- migration.put(5, createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, false));
- migration.put(6, createFingerprintStatusContentValues(FingerprintStatus.Trust.UNTRUSTED, false));
- migration.put(7, createFingerprintStatusContentValues(FingerprintStatus.Trust.VERIFIED_X509, true));
- migration.put(8, createFingerprintStatusContentValues(FingerprintStatus.Trust.VERIFIED_X509, false));
+ migration.put(
+ 0, createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, true));
+ migration.put(
+ 1, createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, true));
+ migration.put(
+ 2,
+ createFingerprintStatusContentValues(FingerprintStatus.Trust.UNTRUSTED, true));
+ migration.put(
+ 3,
+ createFingerprintStatusContentValues(
+ FingerprintStatus.Trust.COMPROMISED, false));
+ migration.put(
+ 4,
+ createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, false));
+ migration.put(
+ 5,
+ createFingerprintStatusContentValues(FingerprintStatus.Trust.TRUSTED, false));
+ migration.put(
+ 6,
+ createFingerprintStatusContentValues(FingerprintStatus.Trust.UNTRUSTED, false));
+ migration.put(
+ 7,
+ createFingerprintStatusContentValues(
+ FingerprintStatus.Trust.VERIFIED_X509, true));
+ migration.put(
+ 8,
+ createFingerprintStatusContentValues(
+ FingerprintStatus.Trust.VERIFIED_X509, false));
for (Map.Entry entry : migration.entrySet()) {
String whereClause = SQLiteAxolotlStore.TRUSTED + "=?";
String[] where = {String.valueOf(entry.getKey())};
- db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, entry.getValue(), whereClause, where);
+ db.update(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ entry.getValue(),
+ whereClause,
+ where);
}
-
}
if (oldVersion >= 15 && oldVersion < 32 && newVersion >= 32) {
- db.execSQL("ALTER TABLE " + SQLiteAxolotlStore.IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore.LAST_ACTIVATION + " NUMBER");
+ db.execSQL(
+ "ALTER TABLE "
+ + SQLiteAxolotlStore.IDENTITIES_TABLENAME
+ + " ADD COLUMN "
+ + SQLiteAxolotlStore.LAST_ACTIVATION
+ + " NUMBER");
ContentValues defaults = new ContentValues();
defaults.put(SQLiteAxolotlStore.LAST_ACTIVATION, System.currentTimeMillis());
db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, defaults, null, null);
}
if (oldVersion >= 15 && oldVersion < 33 && newVersion >= 33) {
String whereClause = SQLiteAxolotlStore.OWN + "=1";
- db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, createFingerprintStatusContentValues(FingerprintStatus.Trust.VERIFIED, true), whereClause, null);
+ db.update(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ createFingerprintStatusContentValues(FingerprintStatus.Trust.VERIFIED, true),
+ whereClause,
+ null);
}
if (oldVersion < 34 && newVersion >= 34) {
db.execSQL(CREATE_MESSAGE_TIME_INDEX);
- final File oldPicturesDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/Conversations/");
- final File oldFilesDirectory = new File(Environment.getExternalStorageDirectory() + "/Conversations/");
- final File newFilesDirectory = new File(Environment.getExternalStorageDirectory() + "/Conversations/Media/Conversations Files/");
- final File newVideosDirectory = new File(Environment.getExternalStorageDirectory() + "/Conversations/Media/Conversations Videos/");
+ final File oldPicturesDirectory =
+ new File(
+ Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES)
+ + "/Conversations/");
+ final File oldFilesDirectory =
+ new File(Environment.getExternalStorageDirectory() + "/Conversations/");
+ final File newFilesDirectory =
+ new File(
+ Environment.getExternalStorageDirectory()
+ + "/Conversations/Media/Conversations Files/");
+ final File newVideosDirectory =
+ new File(
+ Environment.getExternalStorageDirectory()
+ + "/Conversations/Media/Conversations Videos/");
if (oldPicturesDirectory.exists() && oldPicturesDirectory.isDirectory()) {
- final File newPicturesDirectory = new File(Environment.getExternalStorageDirectory() + "/Conversations/Media/Conversations Images/");
+ final File newPicturesDirectory =
+ new File(
+ Environment.getExternalStorageDirectory()
+ + "/Conversations/Media/Conversations Images/");
newPicturesDirectory.getParentFile().mkdirs();
if (oldPicturesDirectory.renameTo(newPicturesDirectory)) {
- Log.d(Config.LOGTAG, "moved " + oldPicturesDirectory.getAbsolutePath() + " to " + newPicturesDirectory.getAbsolutePath());
+ Log.d(
+ Config.LOGTAG,
+ "moved "
+ + oldPicturesDirectory.getAbsolutePath()
+ + " to "
+ + newPicturesDirectory.getAbsolutePath());
}
}
if (oldFilesDirectory.exists() && oldFilesDirectory.isDirectory()) {
@@ -498,17 +875,26 @@ public class DatabaseBackend extends SQLiteOpenHelper {
for (File file : files) {
if (file.getName().equals(".nomedia")) {
if (file.delete()) {
- Log.d(Config.LOGTAG, "deleted nomedia file in " + oldFilesDirectory.getAbsolutePath());
+ Log.d(
+ Config.LOGTAG,
+ "deleted nomedia file in "
+ + oldFilesDirectory.getAbsolutePath());
}
} else if (file.isFile()) {
final String name = file.getName();
boolean isVideo = false;
int start = name.lastIndexOf('.') + 1;
if (start < name.length()) {
- String mime = MimeUtils.guessMimeTypeFromExtension(name.substring(start));
+ String mime =
+ MimeUtils.guessMimeTypeFromExtension(name.substring(start));
isVideo = mime != null && mime.startsWith("video/");
}
- File dst = new File((isVideo ? newVideosDirectory : newFilesDirectory).getAbsolutePath() + "/" + file.getName());
+ File dst =
+ new File(
+ (isVideo ? newVideosDirectory : newFilesDirectory)
+ .getAbsolutePath()
+ + "/"
+ + file.getName());
if (file.renameTo(dst)) {
Log.d(Config.LOGTAG, "moved " + file + " to " + dst);
}
@@ -524,17 +910,30 @@ public class DatabaseBackend extends SQLiteOpenHelper {
for (Account account : accounts) {
account.setOption(Account.OPTION_REQUIRES_ACCESS_MODE_CHANGE, true);
account.setOption(Account.OPTION_LOGGED_IN_SUCCESSFULLY, false);
- db.update(Account.TABLENAME, account.getContentValues(), Account.UUID
- + "=?", new String[]{account.getUuid()});
+ db.update(
+ Account.TABLENAME,
+ account.getContentValues(),
+ Account.UUID + "=?",
+ new String[] {account.getUuid()});
}
}
if (oldVersion < 37 && newVersion >= 37) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.READ_BY_MARKERS + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.READ_BY_MARKERS
+ + " TEXT");
}
if (oldVersion < 38 && newVersion >= 38) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.MARKABLE + " NUMBER DEFAULT 0");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.MARKABLE
+ + " NUMBER DEFAULT 0");
}
if (oldVersion < 39 && newVersion >= 39) {
@@ -545,13 +944,21 @@ public class DatabaseBackend extends SQLiteOpenHelper {
List accounts = getAccounts(db);
for (Account account : accounts) {
account.setOption(Account.OPTION_MAGIC_CREATE, true);
- db.update(Account.TABLENAME, account.getContentValues(), Account.UUID
- + "=?", new String[]{account.getUuid()});
+ db.update(
+ Account.TABLENAME,
+ account.getContentValues(),
+ Account.UUID + "=?",
+ new String[] {account.getUuid()});
}
}
if (oldVersion < 44 && newVersion >= 44) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.DELETED + " NUMBER DEFAULT 0");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.DELETED
+ + " NUMBER DEFAULT 0");
db.execSQL(CREATE_MESSAGE_DELETED_INDEX);
db.execSQL(CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX);
db.execSQL(CREATE_MESSAGE_TYPE_INDEX);
@@ -570,10 +977,20 @@ public class DatabaseBackend extends SQLiteOpenHelper {
Log.d(Config.LOGTAG, "deleted old edit information in " + diff + "ms");
}
if (oldVersion < 47 && newVersion >= 47) {
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.PRESENCE_NAME + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Contact.TABLENAME
+ + " ADD COLUMN "
+ + Contact.PRESENCE_NAME
+ + " TEXT");
}
if (oldVersion < 48 && newVersion >= 48) {
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.RTP_CAPABILITY + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Contact.TABLENAME
+ + " ADD COLUMN "
+ + Contact.RTP_CAPABILITY
+ + " TEXT");
}
if (oldVersion < 49 && newVersion >= 49) {
db.beginTransaction();
@@ -596,16 +1013,46 @@ public class DatabaseBackend extends SQLiteOpenHelper {
requiresMessageIndexRebuild = true;
}
if (oldVersion < 50 && newVersion >= 50) {
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.PINNED_MECHANISM + " TEXT");
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.PINNED_CHANNEL_BINDING + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.PINNED_MECHANISM
+ + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.PINNED_CHANNEL_BINDING
+ + " TEXT");
}
if (oldVersion < 51 && newVersion >= 51) {
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.FAST_MECHANISM + " TEXT");
- db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.FAST_TOKEN + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.FAST_MECHANISM
+ + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Account.TABLENAME
+ + " ADD COLUMN "
+ + Account.FAST_TOKEN
+ + " TEXT");
}
if (oldVersion < 52 && newVersion >= 52) {
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.OCCUPANT_ID + " TEXT");
- db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.REACTIONS + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.OCCUPANT_ID
+ + " TEXT");
+ db.execSQL(
+ "ALTER TABLE "
+ + Message.TABLENAME
+ + " ADD COLUMN "
+ + Message.REACTIONS
+ + " TEXT");
}
}
@@ -617,21 +1064,33 @@ public class DatabaseBackend extends SQLiteOpenHelper {
while (cursor.moveToNext()) {
String newJid;
try {
- newJid = Jid.of(cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID))).toString();
+ newJid =
+ Jid.of(cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)))
+ .toString();
} catch (IllegalArgumentException ignored) {
- Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID "
- + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID))
- + ": " + ignored + ". Skipping...");
+ Log.e(
+ Config.LOGTAG,
+ "Failed to migrate Conversation CONTACTJID "
+ + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID))
+ + ": "
+ + ignored
+ + ". Skipping...");
continue;
}
final String[] updateArgs = {
- newJid,
- cursor.getString(cursor.getColumnIndex(Conversation.UUID)),
+ newJid, cursor.getString(cursor.getColumnIndex(Conversation.UUID)),
};
- db.execSQL("update " + Conversation.TABLENAME
- + " set " + Conversation.CONTACTJID + " = ? "
- + " where " + Conversation.UUID + " = ?", updateArgs);
+ db.execSQL(
+ "update "
+ + Conversation.TABLENAME
+ + " set "
+ + Conversation.CONTACTJID
+ + " = ? "
+ + " where "
+ + Conversation.UUID
+ + " = ?",
+ updateArgs);
}
cursor.close();
@@ -642,21 +1101,33 @@ public class DatabaseBackend extends SQLiteOpenHelper {
try {
newJid = Jid.of(cursor.getString(cursor.getColumnIndex(Contact.JID))).toString();
} catch (final IllegalArgumentException e) {
- Log.e(Config.LOGTAG, "Failed to migrate Contact JID "
- + cursor.getString(cursor.getColumnIndex(Contact.JID))
- + ": Skipping...", e);
+ Log.e(
+ Config.LOGTAG,
+ "Failed to migrate Contact JID "
+ + cursor.getString(cursor.getColumnIndex(Contact.JID))
+ + ": Skipping...",
+ e);
continue;
}
final String[] updateArgs = {
- newJid,
- cursor.getString(cursor.getColumnIndex(Contact.ACCOUNT)),
- cursor.getString(cursor.getColumnIndex(Contact.JID)),
+ newJid,
+ cursor.getString(cursor.getColumnIndex(Contact.ACCOUNT)),
+ cursor.getString(cursor.getColumnIndex(Contact.JID)),
};
- db.execSQL("update " + Contact.TABLENAME
- + " set " + Contact.JID + " = ? "
- + " where " + Contact.ACCOUNT + " = ? "
- + " AND " + Contact.JID + " = ?", updateArgs);
+ db.execSQL(
+ "update "
+ + Contact.TABLENAME
+ + " set "
+ + Contact.JID
+ + " = ? "
+ + " where "
+ + Contact.ACCOUNT
+ + " = ? "
+ + " AND "
+ + Contact.JID
+ + " = ?",
+ updateArgs);
}
cursor.close();
@@ -665,25 +1136,37 @@ public class DatabaseBackend extends SQLiteOpenHelper {
while (cursor.moveToNext()) {
String newServer;
try {
- newServer = Jid.of(
- cursor.getString(cursor.getColumnIndex(Account.USERNAME)),
- cursor.getString(cursor.getColumnIndex(Account.SERVER)),
- null
- ).getDomain().toEscapedString();
+ newServer =
+ Jid.of(
+ cursor.getString(cursor.getColumnIndex(Account.USERNAME)),
+ cursor.getString(cursor.getColumnIndex(Account.SERVER)),
+ null)
+ .getDomain()
+ .toEscapedString();
} catch (IllegalArgumentException ignored) {
- Log.e(Config.LOGTAG, "Failed to migrate Account SERVER "
- + cursor.getString(cursor.getColumnIndex(Account.SERVER))
- + ": " + ignored + ". Skipping...");
+ Log.e(
+ Config.LOGTAG,
+ "Failed to migrate Account SERVER "
+ + cursor.getString(cursor.getColumnIndex(Account.SERVER))
+ + ": "
+ + ignored
+ + ". Skipping...");
continue;
}
String[] updateArgs = {
- newServer,
- cursor.getString(cursor.getColumnIndex(Account.UUID)),
+ newServer, cursor.getString(cursor.getColumnIndex(Account.UUID)),
};
- db.execSQL("update " + Account.TABLENAME
- + " set " + Account.SERVER + " = ? "
- + " where " + Account.UUID + " = ?", updateArgs);
+ db.execSQL(
+ "update "
+ + Account.TABLENAME
+ + " set "
+ + Account.SERVER
+ + " = ? "
+ + " where "
+ + Account.UUID
+ + " = ?",
+ updateArgs);
}
cursor.close();
}
@@ -711,9 +1194,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public ServiceDiscoveryResult findDiscoveryResult(final String hash, final String ver) {
SQLiteDatabase db = this.getReadableDatabase();
String[] selectionArgs = {hash, ver};
- Cursor cursor = db.query(ServiceDiscoveryResult.TABLENAME, null,
- ServiceDiscoveryResult.HASH + "=? AND " + ServiceDiscoveryResult.VER + "=?",
- selectionArgs, null, null, null);
+ Cursor cursor =
+ db.query(
+ ServiceDiscoveryResult.TABLENAME,
+ null,
+ ServiceDiscoveryResult.HASH + "=? AND " + ServiceDiscoveryResult.VER + "=?",
+ selectionArgs,
+ null,
+ null,
+ null);
if (cursor.getCount() == 0) {
cursor.close();
return null;
@@ -723,7 +1212,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
ServiceDiscoveryResult result = null;
try {
result = new ServiceDiscoveryResult(cursor);
- } catch (JSONException e) { /* result is still null */ }
+ } catch (JSONException e) {
+ /* result is still null */
+ }
cursor.close();
return result;
@@ -740,7 +1231,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getReadableDatabase();
String where = Resolver.Result.DOMAIN + "=?";
String[] whereArgs = {domain};
- final Cursor cursor = db.query(RESOLVER_RESULTS_TABLENAME, null, where, whereArgs, null, null, null);
+ final Cursor cursor =
+ db.query(RESOLVER_RESULTS_TABLENAME, null, where, whereArgs, null, null, null);
Resolver.Result result = null;
if (cursor != null) {
try {
@@ -748,7 +1240,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
result = Resolver.Result.fromCursor(cursor);
}
} catch (Exception e) {
- Log.d(Config.LOGTAG, "unable to find cached resolver result in database " + e.getMessage());
+ Log.d(
+ Config.LOGTAG,
+ "unable to find cached resolver result in database " + e.getMessage());
return null;
} finally {
cursor.close();
@@ -762,14 +1256,32 @@ public class DatabaseBackend extends SQLiteOpenHelper {
String whereToDelete = PresenceTemplate.MESSAGE + "=?";
String[] whereToDeleteArgs = {template.getStatusMessage()};
db.delete(PresenceTemplate.TABELNAME, whereToDelete, whereToDeleteArgs);
- db.delete(PresenceTemplate.TABELNAME, PresenceTemplate.UUID + " not in (select " + PresenceTemplate.UUID + " from " + PresenceTemplate.TABELNAME + " order by " + PresenceTemplate.LAST_USED + " desc limit 9)", null);
+ db.delete(
+ PresenceTemplate.TABELNAME,
+ PresenceTemplate.UUID
+ + " not in (select "
+ + PresenceTemplate.UUID
+ + " from "
+ + PresenceTemplate.TABELNAME
+ + " order by "
+ + PresenceTemplate.LAST_USED
+ + " desc limit 9)",
+ null);
db.insert(PresenceTemplate.TABELNAME, null, template.getContentValues());
}
public List getPresenceTemplates() {
ArrayList templates = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
- Cursor cursor = db.query(PresenceTemplate.TABELNAME, null, null, null, null, null, PresenceTemplate.LAST_USED + " desc");
+ Cursor cursor =
+ db.query(
+ PresenceTemplate.TABELNAME,
+ null,
+ null,
+ null,
+ null,
+ null,
+ PresenceTemplate.LAST_USED + " desc");
while (cursor.moveToNext()) {
templates.add(PresenceTemplate.fromCursor(cursor));
}
@@ -781,9 +1293,18 @@ public class DatabaseBackend extends SQLiteOpenHelper {
CopyOnWriteArrayList list = new CopyOnWriteArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String[] selectionArgs = {Integer.toString(status)};
- Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME
- + " where " + Conversation.STATUS + " = ? and " + Conversation.CONTACTJID + " is not null order by "
- + Conversation.CREATED + " desc", selectionArgs);
+ Cursor cursor =
+ db.rawQuery(
+ "select * from "
+ + Conversation.TABLENAME
+ + " where "
+ + Conversation.STATUS
+ + " = ? and "
+ + Conversation.CONTACTJID
+ + " is not null order by "
+ + Conversation.CREATED
+ + " desc",
+ selectionArgs);
while (cursor.moveToNext()) {
final Conversation conversation = Conversation.fromCursor(cursor);
if (conversation.getJid() instanceof InvalidJid) {
@@ -805,16 +1326,28 @@ public class DatabaseBackend extends SQLiteOpenHelper {
Cursor cursor;
if (timestamp == -1) {
String[] selectionArgs = {conversation.getUuid()};
- cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
- + "=?", selectionArgs, null, null, Message.TIME_SENT
- + " DESC", String.valueOf(limit));
+ cursor =
+ db.query(
+ Message.TABLENAME,
+ null,
+ Message.CONVERSATION + "=?",
+ selectionArgs,
+ null,
+ null,
+ Message.TIME_SENT + " DESC",
+ String.valueOf(limit));
} else {
- String[] selectionArgs = {conversation.getUuid(),
- Long.toString(timestamp)};
- cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
- + "=? and " + Message.TIME_SENT + "", selectionArgs,
- null, null, Message.TIME_SENT + " DESC",
- String.valueOf(limit));
+ String[] selectionArgs = {conversation.getUuid(), Long.toString(timestamp)};
+ cursor =
+ db.query(
+ Message.TABLENAME,
+ null,
+ Message.CONVERSATION + "=? and " + Message.TIME_SENT + "",
+ selectionArgs,
+ null,
+ null,
+ Message.TIME_SENT + " DESC",
+ String.valueOf(limit));
}
CursorUtils.upgradeCursorWindowSize(cursor);
while (cursor.moveToNext()) {
@@ -832,11 +1365,54 @@ public class DatabaseBackend extends SQLiteOpenHelper {
final SQLiteDatabase db = this.getReadableDatabase();
final StringBuilder SQL = new StringBuilder();
final String[] selectionArgs;
- SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + "," + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.MODE + " FROM " + Message.TABLENAME + " JOIN " + Conversation.TABLENAME + " ON " + Message.TABLENAME + "." + Message.CONVERSATION + "=" + Conversation.TABLENAME + "." + Conversation.UUID + " JOIN messages_index ON messages_index.rowid=messages.rowid WHERE " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + "," + Message.ENCRYPTION_PGP + "," + Message.ENCRYPTION_DECRYPTION_FAILED + "," + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + "," + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?");
+ SQL.append(
+ "SELECT "
+ + Message.TABLENAME
+ + ".*,"
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.CONTACTJID
+ + ","
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.ACCOUNT
+ + ","
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.MODE
+ + " FROM "
+ + Message.TABLENAME
+ + " JOIN "
+ + Conversation.TABLENAME
+ + " ON "
+ + Message.TABLENAME
+ + "."
+ + Message.CONVERSATION
+ + "="
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.UUID
+ + " JOIN messages_index ON messages_index.rowid=messages.rowid WHERE "
+ + Message.ENCRYPTION
+ + " NOT IN("
+ + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE
+ + ","
+ + Message.ENCRYPTION_PGP
+ + ","
+ + Message.ENCRYPTION_DECRYPTION_FAILED
+ + ","
+ + Message.ENCRYPTION_AXOLOTL_FAILED
+ + ") AND "
+ + Message.TYPE
+ + " IN("
+ + Message.TYPE_TEXT
+ + ","
+ + Message.TYPE_PRIVATE
+ + ") AND messages_index.body MATCH ?");
if (uuid == null) {
- selectionArgs = new String[]{FtsUtils.toMatchString(term)};
+ selectionArgs = new String[] {FtsUtils.toMatchString(term)};
} else {
- selectionArgs = new String[]{FtsUtils.toMatchString(term), uuid};
+ selectionArgs = new String[] {FtsUtils.toMatchString(term), uuid};
SQL.append(" AND " + Conversation.TABLENAME + '.' + Conversation.UUID + "=?");
}
SQL.append(" ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS);
@@ -851,18 +1427,34 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (internal) {
final String name = file.getName();
if (name.endsWith(".pgp")) {
- selection = "(" + Message.RELATIVE_FILE_PATH + " IN(?,?) OR (" + Message.RELATIVE_FILE_PATH + "=? and encryption in(1,4))) and type in (1,2,5)";
- selectionArgs = new String[]{file.getAbsolutePath(), name, name.substring(0, name.length() - 4)};
+ selection =
+ "("
+ + Message.RELATIVE_FILE_PATH
+ + " IN(?,?) OR ("
+ + Message.RELATIVE_FILE_PATH
+ + "=? and encryption in(1,4))) and type in (1,2,5)";
+ selectionArgs =
+ new String[] {
+ file.getAbsolutePath(), name, name.substring(0, name.length() - 4)
+ };
} else {
selection = Message.RELATIVE_FILE_PATH + " IN(?,?) and type in (1,2,5)";
- selectionArgs = new String[]{file.getAbsolutePath(), name};
+ selectionArgs = new String[] {file.getAbsolutePath(), name};
}
} else {
selection = Message.RELATIVE_FILE_PATH + "=? and type in (1,2,5)";
- selectionArgs = new String[]{file.getAbsolutePath()};
+ selectionArgs = new String[] {file.getAbsolutePath()};
}
final List uuids = new ArrayList<>();
- Cursor cursor = db.query(Message.TABLENAME, new String[]{Message.UUID}, selection, selectionArgs, null, null, null);
+ Cursor cursor =
+ db.query(
+ Message.TABLENAME,
+ new String[] {Message.UUID},
+ selection,
+ selectionArgs,
+ null,
+ null,
+ null);
while (cursor != null && cursor.moveToNext()) {
uuids.add(cursor.getString(0));
}
@@ -880,7 +1472,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
contentValues.put(Message.DELETED, 1);
db.beginTransaction();
for (String uuid : uuids) {
- db.update(Message.TABLENAME, contentValues, where, new String[]{uuid});
+ db.update(Message.TABLENAME, contentValues, where, new String[] {uuid});
}
db.setTransactionSuccessful();
db.endTransaction();
@@ -893,7 +1485,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
for (FilePathInfo info : files) {
final ContentValues contentValues = new ContentValues();
contentValues.put(Message.DELETED, info.deleted ? 1 : 0);
- db.update(Message.TABLENAME, contentValues, where, new String[]{info.uuid.toString()});
+ db.update(Message.TABLENAME, contentValues, where, new String[] {info.uuid.toString()});
}
db.setTransactionSuccessful();
db.endTransaction();
@@ -901,10 +1493,20 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public List getFilePathInfo() {
final SQLiteDatabase db = this.getReadableDatabase();
- final Cursor cursor = db.query(Message.TABLENAME, new String[]{Message.UUID, Message.RELATIVE_FILE_PATH, Message.DELETED}, "type in (1,2,5) and " + Message.RELATIVE_FILE_PATH + " is not null", null, null, null, null);
+ final Cursor cursor =
+ db.query(
+ Message.TABLENAME,
+ new String[] {Message.UUID, Message.RELATIVE_FILE_PATH, Message.DELETED},
+ "type in (1,2,5) and " + Message.RELATIVE_FILE_PATH + " is not null",
+ null,
+ null,
+ null,
+ null);
final List list = new ArrayList<>();
while (cursor != null && cursor.moveToNext()) {
- list.add(new FilePathInfo(cursor.getString(0), cursor.getString(1), cursor.getInt(2) > 0));
+ list.add(
+ new FilePathInfo(
+ cursor.getString(0), cursor.getString(1), cursor.getInt(2) > 0));
}
if (cursor != null) {
cursor.close();
@@ -914,7 +1516,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public List getRelativeFilePaths(String account, Jid jid, int limit) {
SQLiteDatabase db = this.getReadableDatabase();
- final String SQL = "select uuid,relativeFilePath from messages where type in (1,2,5) and deleted=0 and " + Message.RELATIVE_FILE_PATH + " is not null and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc";
+ final String SQL =
+ "select uuid,relativeFilePath from messages where type in (1,2,5) and deleted=0 and"
+ + " "
+ + Message.RELATIVE_FILE_PATH
+ + " is not null and conversationUuid=(select uuid from conversations where"
+ + " accountUuid=? and (contactJid=? or contactJid like ?)) order by"
+ + " timeSent desc";
final String[] args = {account, jid.toString(), jid.toString() + "/%"};
Cursor cursor = db.rawQuery(SQL + (limit > 0 ? " limit " + limit : ""), args);
List filesPaths = new ArrayList<>();
@@ -949,7 +1557,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
final Conversation conversation, final String messageId) {
final var db = this.getReadableDatabase();
final String sql =
- "select * from messages where conversationUuid=? and (uuid=? OR remoteMsgId=?) LIMIT 1";
+ "select * from messages where conversationUuid=? and (uuid=? OR remoteMsgId=?)"
+ + " LIMIT 1";
final String[] args = {conversation.getUuid(), messageId, messageId};
final Cursor cursor = db.rawQuery(sql, args);
if (cursor == null) {
@@ -990,15 +1599,51 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
}
+ public Conversation findConversation(final String uuid) {
+ final var db = this.getReadableDatabase();
+ final String[] selectionArgs = {uuid};
+ try (final Cursor cursor =
+ db.query(
+ Conversation.TABLENAME,
+ null,
+ Conversation.UUID + "=?",
+ selectionArgs,
+ null,
+ null,
+ null)) {
+ if (cursor.getCount() == 0) {
+ return null;
+ }
+ cursor.moveToFirst();
+ final Conversation conversation = Conversation.fromCursor(cursor);
+ if (conversation.getJid() instanceof InvalidJid) {
+ return null;
+ }
+ return conversation;
+ }
+ }
+
public Conversation findConversation(final Account account, final Jid contactJid) {
- SQLiteDatabase db = this.getReadableDatabase();
- String[] selectionArgs = {account.getUuid(),
- contactJid.asBareJid().toString() + "/%",
- contactJid.asBareJid().toString()
+ final SQLiteDatabase db = this.getReadableDatabase();
+ final String[] selectionArgs = {
+ account.getUuid(),
+ contactJid.asBareJid().toString() + "/%",
+ contactJid.asBareJid().toString()
};
- try(final Cursor cursor = db.query(Conversation.TABLENAME, null,
- Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID
- + " like ? OR " + Conversation.CONTACTJID + "=?)", selectionArgs, null, null, null)) {
+ try (final Cursor cursor =
+ db.query(
+ Conversation.TABLENAME,
+ null,
+ Conversation.ACCOUNT
+ + "=? AND ("
+ + Conversation.CONTACTJID
+ + " like ? OR "
+ + Conversation.CONTACTJID
+ + "=?)",
+ selectionArgs,
+ null,
+ null,
+ null)) {
if (cursor.getCount() == 0) {
return null;
}
@@ -1007,6 +1652,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (conversation.getJid() instanceof InvalidJid) {
return null;
}
+ conversation.setAccount(account);
return conversation;
}
}
@@ -1014,8 +1660,11 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public void updateConversation(final Conversation conversation) {
final SQLiteDatabase db = this.getWritableDatabase();
final String[] args = {conversation.getUuid()};
- db.update(Conversation.TABLENAME, conversation.getContentValues(),
- Conversation.UUID + "=?", args);
+ db.update(
+ Conversation.TABLENAME,
+ conversation.getContentValues(),
+ Conversation.UUID + "=?",
+ args);
}
public List getAccounts() {
@@ -1026,9 +1675,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public List getAccountJids(final boolean enabledOnly) {
final SQLiteDatabase db = this.getReadableDatabase();
final List jids = new ArrayList<>();
- final String[] columns = new String[]{Account.USERNAME, Account.SERVER};
+ final String[] columns = new String[] {Account.USERNAME, Account.SERVER};
final String where = enabledOnly ? "not options & (1 <<1)" : null;
- try (final Cursor cursor = db.query(Account.TABLENAME, columns, where, null, null, null, null)) {
+ try (final Cursor cursor =
+ db.query(Account.TABLENAME, columns, where, null, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
jids.add(Jid.of(cursor.getString(0), cursor.getString(1), null));
}
@@ -1101,7 +1751,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
final SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
for (Contact contact : roster.getContacts()) {
- if (contact.getOption(Contact.Options.IN_ROSTER) || contact.hasAvatarOrPresenceName() || contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) {
+ if (contact.getOption(Contact.Options.IN_ROSTER)
+ || contact.hasAvatarOrPresenceName()
+ || contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) {
db.insert(Contact.TABLENAME, null, contact.getContentValues());
} else {
String where = Contact.ACCOUNT + "=? AND " + Contact.JID + "=?";
@@ -1114,7 +1766,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
account.setRosterVersion(roster.getVersion());
updateAccount(account);
long duration = SystemClock.elapsedRealtime() - start;
- Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": persisted roster in " + duration + "ms");
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid() + ": persisted roster in " + duration + "ms");
}
public void deleteMessagesInConversation(Conversation conversation) {
@@ -1125,7 +1779,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
int num = db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args);
db.setTransactionSuccessful();
db.endTransaction();
- Log.d(Config.LOGTAG, "deleted " + num + " messages for " + conversation.getJid().asBareJid() + " in " + (SystemClock.elapsedRealtime() - start) + "ms");
+ Log.d(
+ Config.LOGTAG,
+ "deleted "
+ + num
+ + " messages for "
+ + conversation.getJid().asBareJid()
+ + " in "
+ + (SystemClock.elapsedRealtime() - start)
+ + "ms");
}
public void expireOldMessages(long timestamp) {
@@ -1141,7 +1803,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
Cursor cursor = null;
try {
SQLiteDatabase db = this.getReadableDatabase();
- String sql = "select messages.timeSent,messages.serverMsgId from accounts join conversations on accounts.uuid=conversations.accountUuid join messages on conversations.uuid=messages.conversationUuid where accounts.uuid=? and (messages.status=0 or messages.carbon=1 or messages.serverMsgId not null) and (conversations.mode=0 or (messages.serverMsgId not null and messages.type=4)) order by messages.timesent desc limit 1";
+ String sql =
+ "select messages.timeSent,messages.serverMsgId from accounts join conversations"
+ + " on accounts.uuid=conversations.accountUuid join messages on"
+ + " conversations.uuid=messages.conversationUuid where accounts.uuid=? and"
+ + " (messages.status=0 or messages.carbon=1 or messages.serverMsgId not"
+ + " null) and (conversations.mode=0 or (messages.serverMsgId not null and"
+ + " messages.type=4)) order by messages.timesent desc limit 1";
String[] args = {account.getUuid()};
cursor = db.rawQuery(sql, args);
if (cursor.getCount() == 0) {
@@ -1160,7 +1828,11 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
public long getLastTimeFingerprintUsed(Account account, String fingerprint) {
- String SQL = "select messages.timeSent from accounts join conversations on accounts.uuid=conversations.accountUuid join messages on conversations.uuid=messages.conversationUuid where accounts.uuid=? and messages.axolotl_fingerprint=? order by messages.timesent desc limit 1";
+ String SQL =
+ "select messages.timeSent from accounts join conversations on"
+ + " accounts.uuid=conversations.accountUuid join messages on"
+ + " conversations.uuid=messages.conversationUuid where accounts.uuid=? and"
+ + " messages.axolotl_fingerprint=? order by messages.timesent desc limit 1";
String[] args = {account.getUuid(), fingerprint};
Cursor cursor = getReadableDatabase().rawQuery(SQL, args);
long time;
@@ -1178,14 +1850,19 @@ public class DatabaseBackend extends SQLiteOpenHelper {
String[] columns = {Conversation.ATTRIBUTES};
String selection = Conversation.ACCOUNT + "=?";
String[] args = {account.getUuid()};
- Cursor cursor = db.query(Conversation.TABLENAME, columns, selection, args, null, null, null);
+ Cursor cursor =
+ db.query(Conversation.TABLENAME, columns, selection, args, null, null, null);
MamReference maxClearDate = new MamReference(0);
while (cursor.moveToNext()) {
try {
final JSONObject o = new JSONObject(cursor.getString(0));
- maxClearDate = MamReference.max(maxClearDate, MamReference.fromAttribute(o.getString(Conversation.ATTRIBUTE_LAST_CLEAR_HISTORY)));
+ maxClearDate =
+ MamReference.max(
+ maxClearDate,
+ MamReference.fromAttribute(
+ o.getString(Conversation.ATTRIBUTE_LAST_CLEAR_HISTORY)));
} catch (Exception e) {
- //ignored
+ // ignored
}
}
cursor.close();
@@ -1194,16 +1871,22 @@ public class DatabaseBackend extends SQLiteOpenHelper {
private Cursor getCursorForSession(Account account, SignalProtocolAddress contact) {
final SQLiteDatabase db = this.getReadableDatabase();
- String[] selectionArgs = {account.getUuid(),
- contact.getName(),
- Integer.toString(contact.getDeviceId())};
- return db.query(SQLiteAxolotlStore.SESSION_TABLENAME,
+ String[] selectionArgs = {
+ account.getUuid(), contact.getName(), Integer.toString(contact.getDeviceId())
+ };
+ return db.query(
+ SQLiteAxolotlStore.SESSION_TABLENAME,
null,
- SQLiteAxolotlStore.ACCOUNT + " = ? AND "
- + SQLiteAxolotlStore.NAME + " = ? AND "
- + SQLiteAxolotlStore.DEVICE_ID + " = ? ",
+ SQLiteAxolotlStore.ACCOUNT
+ + " = ? AND "
+ + SQLiteAxolotlStore.NAME
+ + " = ? AND "
+ + SQLiteAxolotlStore.DEVICE_ID
+ + " = ? ",
selectionArgs,
- null, null, null);
+ null,
+ null,
+ null);
}
public SessionRecord loadSession(Account account, SignalProtocolAddress contact) {
@@ -1212,7 +1895,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (cursor.getCount() != 0) {
cursor.moveToFirst();
try {
- session = new SessionRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT));
+ session =
+ new SessionRecord(
+ Base64.decode(
+ cursor.getString(
+ cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),
+ Base64.DEFAULT));
} catch (IOException e) {
cursor.close();
throw new AssertionError(e);
@@ -1227,21 +1915,23 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return getSubDeviceSessions(db, account, contact);
}
- private List getSubDeviceSessions(SQLiteDatabase db, Account account, SignalProtocolAddress contact) {
+ private List getSubDeviceSessions(
+ SQLiteDatabase db, Account account, SignalProtocolAddress contact) {
List devices = new ArrayList<>();
String[] columns = {SQLiteAxolotlStore.DEVICE_ID};
- String[] selectionArgs = {account.getUuid(),
- contact.getName()};
- Cursor cursor = db.query(SQLiteAxolotlStore.SESSION_TABLENAME,
- columns,
- SQLiteAxolotlStore.ACCOUNT + " = ? AND "
- + SQLiteAxolotlStore.NAME + " = ?",
- selectionArgs,
- null, null, null);
+ String[] selectionArgs = {account.getUuid(), contact.getName()};
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.SESSION_TABLENAME,
+ columns,
+ SQLiteAxolotlStore.ACCOUNT + " = ? AND " + SQLiteAxolotlStore.NAME + " = ?",
+ selectionArgs,
+ null,
+ null,
+ null);
while (cursor.moveToNext()) {
- devices.add(cursor.getInt(
- cursor.getColumnIndex(SQLiteAxolotlStore.DEVICE_ID)));
+ devices.add(cursor.getInt(cursor.getColumnIndex(SQLiteAxolotlStore.DEVICE_ID)));
}
cursor.close();
@@ -1252,12 +1942,16 @@ public class DatabaseBackend extends SQLiteOpenHelper {
List addresses = new ArrayList<>();
String[] colums = {"DISTINCT " + SQLiteAxolotlStore.NAME};
String[] selectionArgs = {account.getUuid()};
- Cursor cursor = getReadableDatabase().query(SQLiteAxolotlStore.SESSION_TABLENAME,
- colums,
- SQLiteAxolotlStore.ACCOUNT + " = ?",
- selectionArgs,
- null, null, null
- );
+ Cursor cursor =
+ getReadableDatabase()
+ .query(
+ SQLiteAxolotlStore.SESSION_TABLENAME,
+ colums,
+ SQLiteAxolotlStore.ACCOUNT + " = ?",
+ selectionArgs,
+ null,
+ null,
+ null);
while (cursor.moveToNext()) {
addresses.add(cursor.getString(0));
}
@@ -1272,12 +1966,14 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return count != 0;
}
- public void storeSession(Account account, SignalProtocolAddress contact, SessionRecord session) {
+ public void storeSession(
+ Account account, SignalProtocolAddress contact, SessionRecord session) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.NAME, contact.getName());
values.put(SQLiteAxolotlStore.DEVICE_ID, contact.getDeviceId());
- values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(), Base64.DEFAULT));
+ values.put(
+ SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(), Base64.DEFAULT));
values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
db.insert(SQLiteAxolotlStore.SESSION_TABLENAME, null, values);
}
@@ -1288,22 +1984,26 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
private void deleteSession(SQLiteDatabase db, Account account, SignalProtocolAddress contact) {
- String[] args = {account.getUuid(),
- contact.getName(),
- Integer.toString(contact.getDeviceId())};
- db.delete(SQLiteAxolotlStore.SESSION_TABLENAME,
- SQLiteAxolotlStore.ACCOUNT + " = ? AND "
- + SQLiteAxolotlStore.NAME + " = ? AND "
- + SQLiteAxolotlStore.DEVICE_ID + " = ? ",
+ String[] args = {
+ account.getUuid(), contact.getName(), Integer.toString(contact.getDeviceId())
+ };
+ db.delete(
+ SQLiteAxolotlStore.SESSION_TABLENAME,
+ SQLiteAxolotlStore.ACCOUNT
+ + " = ? AND "
+ + SQLiteAxolotlStore.NAME
+ + " = ? AND "
+ + SQLiteAxolotlStore.DEVICE_ID
+ + " = ? ",
args);
}
public void deleteAllSessions(Account account, SignalProtocolAddress contact) {
SQLiteDatabase db = this.getWritableDatabase();
String[] args = {account.getUuid(), contact.getName()};
- db.delete(SQLiteAxolotlStore.SESSION_TABLENAME,
- SQLiteAxolotlStore.ACCOUNT + "=? AND "
- + SQLiteAxolotlStore.NAME + " = ?",
+ db.delete(
+ SQLiteAxolotlStore.SESSION_TABLENAME,
+ SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.NAME + " = ?",
args);
}
@@ -1311,12 +2011,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SQLiteAxolotlStore.KEY};
String[] selectionArgs = {account.getUuid(), Integer.toString(preKeyId)};
- Cursor cursor = db.query(SQLiteAxolotlStore.PREKEY_TABLENAME,
- columns,
- SQLiteAxolotlStore.ACCOUNT + "=? AND "
- + SQLiteAxolotlStore.ID + "=?",
- selectionArgs,
- null, null, null);
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.PREKEY_TABLENAME,
+ columns,
+ SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.ID + "=?",
+ selectionArgs,
+ null,
+ null,
+ null);
return cursor;
}
@@ -1327,7 +2030,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (cursor.getCount() != 0) {
cursor.moveToFirst();
try {
- record = new PreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT));
+ record =
+ new PreKeyRecord(
+ Base64.decode(
+ cursor.getString(
+ cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),
+ Base64.DEFAULT));
} catch (IOException e) {
throw new AssertionError(e);
}
@@ -1347,7 +2055,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.ID, record.getId());
- values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(), Base64.DEFAULT));
+ values.put(
+ SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(), Base64.DEFAULT));
values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
db.insert(SQLiteAxolotlStore.PREKEY_TABLENAME, null, values);
}
@@ -1355,9 +2064,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public int deletePreKey(Account account, int preKeyId) {
SQLiteDatabase db = this.getWritableDatabase();
String[] args = {account.getUuid(), Integer.toString(preKeyId)};
- return db.delete(SQLiteAxolotlStore.PREKEY_TABLENAME,
- SQLiteAxolotlStore.ACCOUNT + "=? AND "
- + SQLiteAxolotlStore.ID + "=?",
+ return db.delete(
+ SQLiteAxolotlStore.PREKEY_TABLENAME,
+ SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.ID + "=?",
args);
}
@@ -1365,11 +2074,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SQLiteAxolotlStore.KEY};
String[] selectionArgs = {account.getUuid(), Integer.toString(signedPreKeyId)};
- Cursor cursor = db.query(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
- columns,
- SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.ID + "=?",
- selectionArgs,
- null, null, null);
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ columns,
+ SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.ID + "=?",
+ selectionArgs,
+ null,
+ null,
+ null);
return cursor;
}
@@ -1380,7 +2093,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (cursor.getCount() != 0) {
cursor.moveToFirst();
try {
- record = new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT));
+ record =
+ new SignedPreKeyRecord(
+ Base64.decode(
+ cursor.getString(
+ cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),
+ Base64.DEFAULT));
} catch (IOException e) {
throw new AssertionError(e);
}
@@ -1394,15 +2112,24 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SQLiteAxolotlStore.KEY};
String[] selectionArgs = {account.getUuid()};
- Cursor cursor = db.query(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
- columns,
- SQLiteAxolotlStore.ACCOUNT + "=?",
- selectionArgs,
- null, null, null);
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ columns,
+ SQLiteAxolotlStore.ACCOUNT + "=?",
+ selectionArgs,
+ null,
+ null,
+ null);
while (cursor.moveToNext()) {
try {
- prekeys.add(new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT)));
+ prekeys.add(
+ new SignedPreKeyRecord(
+ Base64.decode(
+ cursor.getString(
+ cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),
+ Base64.DEFAULT)));
} catch (IOException ignored) {
}
}
@@ -1414,11 +2141,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
String[] columns = {"count(" + SQLiteAxolotlStore.KEY + ")"};
String[] selectionArgs = {account.getUuid()};
SQLiteDatabase db = this.getReadableDatabase();
- Cursor cursor = db.query(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
- columns,
- SQLiteAxolotlStore.ACCOUNT + "=?",
- selectionArgs,
- null, null, null);
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ columns,
+ SQLiteAxolotlStore.ACCOUNT + "=?",
+ selectionArgs,
+ null,
+ null,
+ null);
final int count;
if (cursor.moveToFirst()) {
count = cursor.getInt(0);
@@ -1440,7 +2171,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.ID, record.getId());
- values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(), Base64.DEFAULT));
+ values.put(
+ SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(), Base64.DEFAULT));
values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
db.insert(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, null, values);
}
@@ -1448,9 +2180,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public void deleteSignedPreKey(Account account, int signedPreKeyId) {
SQLiteDatabase db = this.getWritableDatabase();
String[] args = {account.getUuid(), Integer.toString(signedPreKeyId)};
- db.delete(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
- SQLiteAxolotlStore.ACCOUNT + "=? AND "
- + SQLiteAxolotlStore.ID + "=?",
+ db.delete(
+ SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.ID + "=?",
args);
}
@@ -1459,7 +2191,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return getIdentityKeyCursor(db, account, name, own);
}
- private Cursor getIdentityKeyCursor(SQLiteDatabase db, Account account, String name, boolean own) {
+ private Cursor getIdentityKeyCursor(
+ SQLiteDatabase db, Account account, String name, boolean own) {
return getIdentityKeyCursor(db, account, name, own, null);
}
@@ -1472,11 +2205,14 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return getIdentityKeyCursor(db, account, null, null, fingerprint);
}
- private Cursor getIdentityKeyCursor(SQLiteDatabase db, Account account, String name, Boolean own, String fingerprint) {
- String[] columns = {SQLiteAxolotlStore.TRUST,
- SQLiteAxolotlStore.ACTIVE,
- SQLiteAxolotlStore.LAST_ACTIVATION,
- SQLiteAxolotlStore.KEY};
+ private Cursor getIdentityKeyCursor(
+ SQLiteDatabase db, Account account, String name, Boolean own, String fingerprint) {
+ String[] columns = {
+ SQLiteAxolotlStore.TRUST,
+ SQLiteAxolotlStore.ACTIVE,
+ SQLiteAxolotlStore.LAST_ACTIVATION,
+ SQLiteAxolotlStore.KEY
+ };
ArrayList selectionArgs = new ArrayList<>(4);
selectionArgs.add(account.getUuid());
String selectionString = SQLiteAxolotlStore.ACCOUNT + " = ?";
@@ -1492,11 +2228,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
selectionArgs.add(own ? "1" : "0");
selectionString += " AND " + SQLiteAxolotlStore.OWN + " = ?";
}
- Cursor cursor = db.query(SQLiteAxolotlStore.IDENTITIES_TABLENAME,
- columns,
- selectionString,
- selectionArgs.toArray(new String[selectionArgs.size()]),
- null, null, null);
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ columns,
+ selectionString,
+ selectionArgs.toArray(new String[selectionArgs.size()]),
+ null,
+ null,
+ null);
return cursor;
}
@@ -1513,9 +2253,20 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (cursor.getCount() != 0) {
cursor.moveToFirst();
try {
- identityKeyPair = new IdentityKeyPair(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT));
+ identityKeyPair =
+ new IdentityKeyPair(
+ Base64.decode(
+ cursor.getString(
+ cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),
+ Base64.DEFAULT));
} catch (InvalidKeyException e) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Encountered invalid IdentityKey in database for account" + account.getJid().asBareJid() + ", address: " + name);
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.getLogprefix(account)
+ + "Encountered invalid IdentityKey in database for account"
+ + account.getJid().asBareJid()
+ + ", address: "
+ + name);
}
}
cursor.close();
@@ -1527,7 +2278,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return loadIdentityKeys(account, name, null);
}
- public Set loadIdentityKeys(Account account, String name, FingerprintStatus status) {
+ public Set loadIdentityKeys(
+ Account account, String name, FingerprintStatus status) {
Set identityKeys = new HashSet<>();
Cursor cursor = getIdentityKeyCursor(account, name, false);
@@ -1540,10 +2292,22 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (key != null) {
identityKeys.add(new IdentityKey(Base64.decode(key, Base64.DEFAULT), 0));
} else {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Missing key (possibly preverified) in database for account" + account.getJid().asBareJid() + ", address: " + name);
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.getLogprefix(account)
+ + "Missing key (possibly preverified) in database for account"
+ + account.getJid().asBareJid()
+ + ", address: "
+ + name);
}
} catch (InvalidKeyException e) {
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Encountered invalid IdentityKey in database for account" + account.getJid().asBareJid() + ", address: " + name);
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.getLogprefix(account)
+ + "Encountered invalid IdentityKey in database for account"
+ + account.getJid().asBareJid()
+ + ", address: "
+ + name);
}
}
cursor.close();
@@ -1554,22 +2318,40 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public long numTrustedKeys(Account account, String name) {
SQLiteDatabase db = getReadableDatabase();
String[] args = {
- account.getUuid(),
- name,
- FingerprintStatus.Trust.TRUSTED.toString(),
- FingerprintStatus.Trust.VERIFIED.toString(),
- FingerprintStatus.Trust.VERIFIED_X509.toString()
+ account.getUuid(),
+ name,
+ FingerprintStatus.Trust.TRUSTED.toString(),
+ FingerprintStatus.Trust.VERIFIED.toString(),
+ FingerprintStatus.Trust.VERIFIED_X509.toString()
};
- return DatabaseUtils.queryNumEntries(db, SQLiteAxolotlStore.IDENTITIES_TABLENAME,
- SQLiteAxolotlStore.ACCOUNT + " = ?"
- + " AND " + SQLiteAxolotlStore.NAME + " = ?"
- + " AND (" + SQLiteAxolotlStore.TRUST + " = ? OR " + SQLiteAxolotlStore.TRUST + " = ? OR " + SQLiteAxolotlStore.TRUST + " = ?)"
- + " AND " + SQLiteAxolotlStore.ACTIVE + " > 0",
- args
- );
+ return DatabaseUtils.queryNumEntries(
+ db,
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ SQLiteAxolotlStore.ACCOUNT
+ + " = ?"
+ + " AND "
+ + SQLiteAxolotlStore.NAME
+ + " = ?"
+ + " AND ("
+ + SQLiteAxolotlStore.TRUST
+ + " = ? OR "
+ + SQLiteAxolotlStore.TRUST
+ + " = ? OR "
+ + SQLiteAxolotlStore.TRUST
+ + " = ?)"
+ + " AND "
+ + SQLiteAxolotlStore.ACTIVE
+ + " > 0",
+ args);
}
- private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized, FingerprintStatus status) {
+ private void storeIdentityKey(
+ Account account,
+ String name,
+ boolean own,
+ String fingerprint,
+ String base64Serialized,
+ FingerprintStatus status) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
@@ -1578,7 +2360,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
values.put(SQLiteAxolotlStore.FINGERPRINT, fingerprint);
values.put(SQLiteAxolotlStore.KEY, base64Serialized);
values.putAll(status.toContentValues());
- String where = SQLiteAxolotlStore.ACCOUNT + "=? AND " + SQLiteAxolotlStore.NAME + "=? AND " + SQLiteAxolotlStore.FINGERPRINT + " =?";
+ String where =
+ SQLiteAxolotlStore.ACCOUNT
+ + "=? AND "
+ + SQLiteAxolotlStore.NAME
+ + "=? AND "
+ + SQLiteAxolotlStore.FINGERPRINT
+ + " =?";
String[] whereArgs = {account.getUuid(), name, fingerprint};
int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, values, where, whereArgs);
if (rows == 0) {
@@ -1586,7 +2374,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
}
- public void storePreVerification(Account account, String name, String fingerprint, FingerprintStatus status) {
+ public void storePreVerification(
+ Account account, String name, String fingerprint, FingerprintStatus status) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
@@ -1610,36 +2399,43 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return status;
}
- public boolean setIdentityKeyTrust(Account account, String fingerprint, FingerprintStatus fingerprintStatus) {
+ public boolean setIdentityKeyTrust(
+ Account account, String fingerprint, FingerprintStatus fingerprintStatus) {
SQLiteDatabase db = this.getWritableDatabase();
return setIdentityKeyTrust(db, account, fingerprint, fingerprintStatus);
}
- private boolean setIdentityKeyTrust(SQLiteDatabase db, Account account, String fingerprint, FingerprintStatus status) {
- String[] selectionArgs = {
- account.getUuid(),
- fingerprint
- };
- int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, status.toContentValues(),
- SQLiteAxolotlStore.ACCOUNT + " = ? AND "
- + SQLiteAxolotlStore.FINGERPRINT + " = ? ",
- selectionArgs);
+ private boolean setIdentityKeyTrust(
+ SQLiteDatabase db, Account account, String fingerprint, FingerprintStatus status) {
+ String[] selectionArgs = {account.getUuid(), fingerprint};
+ int rows =
+ db.update(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ status.toContentValues(),
+ SQLiteAxolotlStore.ACCOUNT
+ + " = ? AND "
+ + SQLiteAxolotlStore.FINGERPRINT
+ + " = ? ",
+ selectionArgs);
return rows == 1;
}
- public boolean setIdentityKeyCertificate(Account account, String fingerprint, X509Certificate x509Certificate) {
+ public boolean setIdentityKeyCertificate(
+ Account account, String fingerprint, X509Certificate x509Certificate) {
SQLiteDatabase db = this.getWritableDatabase();
- String[] selectionArgs = {
- account.getUuid(),
- fingerprint
- };
+ String[] selectionArgs = {account.getUuid(), fingerprint};
try {
ContentValues values = new ContentValues();
values.put(SQLiteAxolotlStore.CERTIFICATE, x509Certificate.getEncoded());
- return db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, values,
- SQLiteAxolotlStore.ACCOUNT + " = ? AND "
- + SQLiteAxolotlStore.FINGERPRINT + " = ? ",
- selectionArgs) == 1;
+ return db.update(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ values,
+ SQLiteAxolotlStore.ACCOUNT
+ + " = ? AND "
+ + SQLiteAxolotlStore.FINGERPRINT
+ + " = ? ",
+ selectionArgs)
+ == 1;
} catch (CertificateEncodingException e) {
Log.d(Config.LOGTAG, "could not encode certificate");
return false;
@@ -1648,25 +2444,34 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public X509Certificate getIdentityKeyCertifcate(Account account, String fingerprint) {
SQLiteDatabase db = this.getReadableDatabase();
- String[] selectionArgs = {
- account.getUuid(),
- fingerprint
- };
+ String[] selectionArgs = {account.getUuid(), fingerprint};
String[] colums = {SQLiteAxolotlStore.CERTIFICATE};
- String selection = SQLiteAxolotlStore.ACCOUNT + " = ? AND " + SQLiteAxolotlStore.FINGERPRINT + " = ? ";
- Cursor cursor = db.query(SQLiteAxolotlStore.IDENTITIES_TABLENAME, colums, selection, selectionArgs, null, null, null);
+ String selection =
+ SQLiteAxolotlStore.ACCOUNT + " = ? AND " + SQLiteAxolotlStore.FINGERPRINT + " = ? ";
+ Cursor cursor =
+ db.query(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ colums,
+ selection,
+ selectionArgs,
+ null,
+ null,
+ null);
if (cursor.getCount() < 1) {
return null;
} else {
cursor.moveToFirst();
- byte[] certificate = cursor.getBlob(cursor.getColumnIndex(SQLiteAxolotlStore.CERTIFICATE));
+ byte[] certificate =
+ cursor.getBlob(cursor.getColumnIndex(SQLiteAxolotlStore.CERTIFICATE));
cursor.close();
if (certificate == null || certificate.length == 0) {
return null;
}
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certificate));
+ return (X509Certificate)
+ certificateFactory.generateCertificate(
+ new ByteArrayInputStream(certificate));
} catch (CertificateException e) {
Log.d(Config.LOGTAG, "certificate exception " + e.getMessage());
return null;
@@ -1674,17 +2479,31 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
}
- public void storeIdentityKey(Account account, String name, IdentityKey identityKey, FingerprintStatus status) {
- storeIdentityKey(account, name, false, CryptoHelper.bytesToHex(identityKey.getPublicKey().serialize()), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT), status);
+ public void storeIdentityKey(
+ Account account, String name, IdentityKey identityKey, FingerprintStatus status) {
+ storeIdentityKey(
+ account,
+ name,
+ false,
+ CryptoHelper.bytesToHex(identityKey.getPublicKey().serialize()),
+ Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT),
+ status);
}
public void storeOwnIdentityKeyPair(Account account, IdentityKeyPair identityKeyPair) {
- storeIdentityKey(account, account.getJid().asBareJid().toString(), true, CryptoHelper.bytesToHex(identityKeyPair.getPublicKey().serialize()), Base64.encodeToString(identityKeyPair.serialize(), Base64.DEFAULT), FingerprintStatus.createActiveVerified(false));
+ storeIdentityKey(
+ account,
+ account.getJid().asBareJid().toString(),
+ true,
+ CryptoHelper.bytesToHex(identityKeyPair.getPublicKey().serialize()),
+ Base64.encodeToString(identityKeyPair.serialize(), Base64.DEFAULT),
+ FingerprintStatus.createActiveVerified(false));
}
-
private void recreateAxolotlDb(SQLiteDatabase db) {
- Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + ">>> (RE)CREATING AXOLOTL DATABASE <<<");
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.LOGPREFIX + " : " + ">>> (RE)CREATING AXOLOTL DATABASE <<<");
db.execSQL("DROP TABLE IF EXISTS " + SQLiteAxolotlStore.SESSION_TABLENAME);
db.execSQL(CREATE_SESSIONS_STATEMENT);
db.execSQL("DROP TABLE IF EXISTS " + SQLiteAxolotlStore.PREKEY_TABLENAME);
@@ -1697,36 +2516,70 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public void wipeAxolotlDb(Account account) {
String accountName = account.getUuid();
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ">>> WIPING AXOLOTL DATABASE FOR ACCOUNT " + accountName + " <<<");
+ Log.d(
+ Config.LOGTAG,
+ AxolotlService.getLogprefix(account)
+ + ">>> WIPING AXOLOTL DATABASE FOR ACCOUNT "
+ + accountName
+ + " <<<");
SQLiteDatabase db = this.getWritableDatabase();
- String[] deleteArgs = {
- accountName
- };
- db.delete(SQLiteAxolotlStore.SESSION_TABLENAME,
+ String[] deleteArgs = {accountName};
+ db.delete(
+ SQLiteAxolotlStore.SESSION_TABLENAME,
SQLiteAxolotlStore.ACCOUNT + " = ?",
deleteArgs);
- db.delete(SQLiteAxolotlStore.PREKEY_TABLENAME,
+ db.delete(
+ SQLiteAxolotlStore.PREKEY_TABLENAME,
SQLiteAxolotlStore.ACCOUNT + " = ?",
deleteArgs);
- db.delete(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ db.delete(
+ SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
SQLiteAxolotlStore.ACCOUNT + " = ?",
deleteArgs);
- db.delete(SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ db.delete(
+ SQLiteAxolotlStore.IDENTITIES_TABLENAME,
SQLiteAxolotlStore.ACCOUNT + " = ?",
deleteArgs);
}
- public List getFrequentContacts(int days) {
- SQLiteDatabase db = this.getReadableDatabase();
- final String SQL = "select " + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + " from " + Conversation.TABLENAME + " join " + Message.TABLENAME + " on conversations.uuid=messages.conversationUuid where messages.status!=0 and carbon==0 and conversations.mode=0 and messages.timeSent>=? group by conversations.uuid order by count(body) desc limit 4;";
- String[] whereArgs = new String[]{String.valueOf(System.currentTimeMillis() - (Config.MILLISECONDS_IN_DAY * days))};
+ public List getFrequentContacts(final int days) {
+ final var db = this.getReadableDatabase();
+ final String SQL =
+ "select "
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.UUID
+ + ","
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.ACCOUNT
+ + ","
+ + Conversation.TABLENAME
+ + "."
+ + Conversation.CONTACTJID
+ + " from "
+ + Conversation.TABLENAME
+ + " join "
+ + Message.TABLENAME
+ + " on conversations.uuid=messages.conversationUuid where"
+ + " messages.status!=0 and carbon==0 and conversations.mode=0 and"
+ + " messages.timeSent>=? group by conversations.uuid order by count(body)"
+ + " desc limit 4;";
+ String[] whereArgs =
+ new String[] {
+ String.valueOf(System.currentTimeMillis() - (Config.MILLISECONDS_IN_DAY * days))
+ };
Cursor cursor = db.rawQuery(SQL, whereArgs);
ArrayList contacts = new ArrayList<>();
while (cursor.moveToNext()) {
try {
- contacts.add(new ShortcutService.FrequentContact(cursor.getString(0), Jid.of(cursor.getString(1))));
- } catch (Exception e) {
- Log.d(Config.LOGTAG, e.getMessage());
+ contacts.add(
+ new ShortcutService.FrequentContact(
+ cursor.getString(0),
+ cursor.getString(1),
+ Jid.of(cursor.getString(2))));
+ } catch (final Exception e) {
+ Log.e(Config.LOGTAG, "could not create frequent contact", e);
}
}
cursor.close();
diff --git a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java
deleted file mode 100644
index 63a9afc3fa8558f1096d47f9a4f1689e4b1cf11e..0000000000000000000000000000000000000000
--- a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package eu.siacs.conversations.services;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.graphics.drawable.Icon;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.service.chooser.ChooserTarget;
-import android.service.chooser.ChooserTargetService;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.receiver.SystemEventReceiver;
-import eu.siacs.conversations.ui.ConversationsActivity;
-import eu.siacs.conversations.utils.Compatibility;
-
-@SuppressLint("Deprecated")
-@TargetApi(Build.VERSION_CODES.M)
-public class ContactChooserTargetService extends ChooserTargetService implements ServiceConnection {
-
- private final Object lock = new Object();
- private static final int MAX_TARGETS = 5;
- private XmppConnectionService mXmppConnectionService;
-
- private static boolean textOnly(IntentFilter filter) {
- for (int i = 0; i < filter.countDataTypes(); ++i) {
- if (!"text/plain".equals(filter.getDataType(i))) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public List onGetChooserTargets(
- final ComponentName targetActivityName, final IntentFilter matchedFilter) {
- if (!SystemEventReceiver.hasEnabledAccounts(this)) {
- return Collections.emptyList();
- }
- final Intent intent = new Intent(this, XmppConnectionService.class);
- intent.setAction("contact_chooser");
- Compatibility.startService(this, intent);
- bindService(intent, this, Context.BIND_AUTO_CREATE);
- try {
- waitForService();
- if (!mXmppConnectionService.areMessagesInitialized()) {
- return Collections.emptyList();
- }
- final ArrayList conversations = new ArrayList<>();
- mXmppConnectionService.populateWithOrderedConversations(
- conversations, textOnly(matchedFilter));
- final ComponentName componentName =
- new ComponentName(this, ConversationsActivity.class);
- final int pixel = AvatarService.getSystemUiAvatarSize(this);
- final ArrayList chooserTargets = new ArrayList<>();
- for (final Conversation conversation : conversations) {
- if (conversation.sentMessagesCount() == 0) {
- continue;
- }
- final String name = conversation.getName().toString();
- final Icon icon =
- Icon.createWithBitmap(
- mXmppConnectionService.getAvatarService().get(conversation, pixel));
- final float score = 1 - (1.0f / MAX_TARGETS) * chooserTargets.size();
- final Bundle extras = new Bundle();
- extras.putString(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
- chooserTargets.add(new ChooserTarget(name, icon, score, componentName, extras));
- if (chooserTargets.size() >= MAX_TARGETS) {
- return chooserTargets;
- }
- }
- return chooserTargets;
- } catch (final InterruptedException e) {
- Log.d(
- Config.LOGTAG,
- "Thread got interrupted before binding to XmppConnectionService",
- e);
- } finally {
- unbindService(this);
- }
- return Collections.emptyList();
- }
-
- @Override
- public void onServiceConnected(final ComponentName name, final IBinder service) {
- XmppConnectionService.XmppConnectionBinder binder =
- (XmppConnectionService.XmppConnectionBinder) service;
- mXmppConnectionService = binder.getService();
- synchronized (this.lock) {
- lock.notifyAll();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mXmppConnectionService = null;
- }
-
- private void waitForService() throws InterruptedException {
- if (mXmppConnectionService == null) {
- synchronized (this.lock) {
- lock.wait();
- }
- }
- }
-}
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index 409a05d573282b2b7a677fabb6f3c8b523101090..4fd89f8a776cf6345fb96e652612ae25e9214f17 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -28,7 +28,6 @@ import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.util.DisplayMetrics;
import android.util.Log;
-
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
@@ -41,7 +40,6 @@ import androidx.core.app.RemoteInput;
import androidx.core.content.ContextCompat;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.graphics.drawable.IconCompat;
-
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
@@ -49,7 +47,6 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.primitives.Ints;
-
import eu.siacs.conversations.AppSettings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -70,7 +67,6 @@ import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
import eu.siacs.conversations.xmpp.jingle.Media;
-
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -505,7 +501,8 @@ public class NotificationService {
Log.d(
Config.LOGTAG,
message.getConversation().getAccount().getJid().asBareJid()
- + ": suppressing failed delivery notification because conversation is open");
+ + ": suppressing failed delivery notification because conversation is"
+ + " open");
return;
}
final PendingIntent pendingIntent = createContentIntent(conversation);
@@ -631,10 +628,11 @@ public class NotificationService {
.build());
modifyIncomingCall(builder);
final Notification notification = builder.build();
- notification.audioAttributes = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
- .build();
+ notification.audioAttributes =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .build();
notification.flags = notification.flags | Notification.FLAG_INSISTENT;
notify(INCOMING_CALL_NOTIFICATION_ID, notification);
}
@@ -708,7 +706,8 @@ public class NotificationService {
if (jingleRtpConnection == null) {
return false;
}
- final var notificationManager = mXmppConnectionService.getSystemService(NotificationManager.class);
+ final var notificationManager =
+ mXmppConnectionService.getSystemService(NotificationManager.class);
if (Iterables.any(
Arrays.asList(notificationManager.getActiveNotifications()),
n -> n.getId() == INCOMING_CALL_NOTIFICATION_ID)) {
@@ -820,7 +819,8 @@ public class NotificationService {
Log.d(
Config.LOGTAG,
conversational.getAccount().getJid().asBareJid()
- + ": dismissed missed call because call was picked up on other device");
+ + ": dismissed missed call because call was picked up on"
+ + " other device");
iterator.remove();
}
}
@@ -1345,12 +1345,15 @@ public class NotificationService {
if (systemAccount != null) {
notificationBuilder.addPerson(systemAccount.toString());
}
- info = mXmppConnectionService.getShortcutService().getShortcutInfoCompat(contact);
+ info =
+ mXmppConnectionService
+ .getShortcutService()
+ .getShortcutInfo(contact, conversation.getUuid());
} else {
info =
mXmppConnectionService
.getShortcutService()
- .getShortcutInfoCompat(conversation.getMucOptions());
+ .getShortcutInfo(conversation.getMucOptions());
}
notificationBuilder.setWhen(conversation.getLatestMessage().getTimeSent());
notificationBuilder.setSmallIcon(R.drawable.ic_app_icon_notification);
@@ -1384,16 +1387,16 @@ public class NotificationService {
}
final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle();
bigPictureStyle.bigPicture(bitmap);
- if (tmp.size() > 0) {
- CharSequence text = getMergedBodies(tmp);
- bigPictureStyle.setSummaryText(text);
- builder.setContentText(text);
- builder.setTicker(text);
- } else {
+ if (tmp.isEmpty()) {
final String description =
UIHelper.getFileDescriptionString(mXmppConnectionService, message);
builder.setContentText(description);
builder.setTicker(description);
+ } else {
+ final CharSequence text = getMergedBodies(tmp);
+ bigPictureStyle.setSummaryText(text);
+ builder.setContentText(text);
+ builder.setTicker(text);
}
builder.setStyle(bigPictureStyle);
} catch (final IOException e) {
diff --git a/src/main/java/eu/siacs/conversations/services/ShortcutService.java b/src/main/java/eu/siacs/conversations/services/ShortcutService.java
index c6ae77b63e1d13fabf1f8cdc751fe35f0d6e6ded..ef208d690fb174aee109ff1072f2b0c16f4cdd77 100644
--- a/src/main/java/eu/siacs/conversations/services/ShortcutService.java
+++ b/src/main/java/eu/siacs/conversations/services/ShortcutService.java
@@ -2,37 +2,38 @@ package eu.siacs.conversations.services;
import android.annotation.TargetApi;
import android.content.Intent;
-import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Bitmap;
-import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
+import android.os.PersistableBundle;
import android.util.Log;
-
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
import androidx.core.content.pm.ShortcutInfoCompat;
+import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.MucOptions;
+import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.StartConversationActivity;
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
import eu.siacs.conversations.xmpp.Jid;
+import java.util.Collection;
+import java.util.List;
public class ShortcutService {
private final XmppConnectionService xmppConnectionService;
- private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor = new ReplacingSerialSingleThreadExecutor(ShortcutService.class.getSimpleName());
+ private final ReplacingSerialSingleThreadExecutor replacingSerialSingleThreadExecutor =
+ new ReplacingSerialSingleThreadExecutor(ShortcutService.class.getSimpleName());
- public ShortcutService(XmppConnectionService xmppConnectionService) {
+ public ShortcutService(final XmppConnectionService xmppConnectionService) {
this.xmppConnectionService = xmppConnectionService;
}
@@ -42,12 +43,7 @@ public class ShortcutService {
public void refresh(final boolean forceUpdate) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
- final Runnable r = new Runnable() {
- @Override
- public void run() {
- refreshImpl(forceUpdate);
- }
- };
+ final Runnable r = () -> refreshImpl(forceUpdate);
replacingSerialSingleThreadExecutor.execute(r);
}
}
@@ -55,87 +51,88 @@ public class ShortcutService {
@TargetApi(25)
public void report(Contact contact) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
- ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
+ ShortcutManager shortcutManager =
+ xmppConnectionService.getSystemService(ShortcutManager.class);
shortcutManager.reportShortcutUsed(getShortcutId(contact));
}
}
@TargetApi(25)
- private void refreshImpl(boolean forceUpdate) {
- List frequentContacts = xmppConnectionService.databaseBackend.getFrequentContacts(30);
- HashMap accounts = new HashMap<>();
- for(Account account : xmppConnectionService.getAccounts()) {
- accounts.put(account.getUuid(),account);
- }
- List contacts = new ArrayList<>();
- for(FrequentContact frequentContact : frequentContacts) {
- Account account = accounts.get(frequentContact.account);
+ private void refreshImpl(final boolean forceUpdate) {
+ final var frequentContacts = xmppConnectionService.databaseBackend.getFrequentContacts(30);
+ final var accounts =
+ ImmutableMap.copyOf(
+ Maps.uniqueIndex(xmppConnectionService.getAccounts(), Account::getUuid));
+ final var contactBuilder = new ImmutableMap.Builder();
+ for (final var frequentContact : frequentContacts) {
+ final Account account = accounts.get(frequentContact.account);
if (account != null) {
- contacts.add(account.getRoster().getContact(frequentContact.contact));
+ final var contact = account.getRoster().getContact(frequentContact.contact);
+ contactBuilder.put(frequentContact, contact);
}
}
- ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
- boolean needsUpdate = forceUpdate || contactsChanged(contacts,shortcutManager.getDynamicShortcuts());
+ final var contacts = contactBuilder.build();
+ final var current = ShortcutManagerCompat.getDynamicShortcuts(xmppConnectionService);
+ boolean needsUpdate = forceUpdate || contactsChanged(contacts.values(), current);
if (!needsUpdate) {
- Log.d(Config.LOGTAG,"skipping shortcut update");
+ Log.d(Config.LOGTAG, "skipping shortcut update");
return;
}
- List newDynamicShortCuts = new ArrayList<>();
- for (Contact contact : contacts) {
- ShortcutInfo shortcut = getShortcutInfo(contact);
- newDynamicShortCuts.add(shortcut);
+ final var newDynamicShortcuts = new ImmutableList.Builder();
+ for (final var entry : contacts.entrySet()) {
+ final var contact = entry.getValue();
+ final var conversation = entry.getKey().conversation;
+ final var shortcut = getShortcutInfo(contact, conversation);
+ newDynamicShortcuts.add(shortcut);
}
- if (shortcutManager.setDynamicShortcuts(newDynamicShortCuts)) {
- Log.d(Config.LOGTAG,"updated dynamic shortcuts");
+ if (ShortcutManagerCompat.setDynamicShortcuts(
+ xmppConnectionService, newDynamicShortcuts.build())) {
+ Log.d(Config.LOGTAG, "updated dynamic shortcuts");
} else {
Log.d(Config.LOGTAG, "unable to update dynamic shortcuts");
}
}
- public ShortcutInfoCompat getShortcutInfoCompat(final Contact contact) {
+ public ShortcutInfoCompat getShortcutInfo(final Contact contact, final String conversation) {
final ShortcutInfoCompat.Builder builder =
new ShortcutInfoCompat.Builder(xmppConnectionService, getShortcutId(contact))
.setShortLabel(contact.getDisplayName())
.setIntent(getShortcutIntent(contact))
.setIsConversation();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- builder.setIcon(
- IconCompat.createFromIcon(
- xmppConnectionService,
- Icon.createWithBitmap(
- xmppConnectionService
- .getAvatarService()
- .getRoundedShortcut(contact))));
+ builder.setIcon(
+ IconCompat.createWithBitmap(
+ xmppConnectionService.getAvatarService().getRoundedShortcut(contact)));
+ if (conversation != null) {
+ setConversation(builder, conversation);
}
return builder.build();
}
- public ShortcutInfoCompat getShortcutInfoCompat(final MucOptions mucOptions) {
+ public ShortcutInfoCompat getShortcutInfo(final MucOptions mucOptions) {
final ShortcutInfoCompat.Builder builder =
new ShortcutInfoCompat.Builder(xmppConnectionService, getShortcutId(mucOptions))
.setShortLabel(mucOptions.getConversation().getName())
.setIntent(getShortcutIntent(mucOptions))
.setIsConversation();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- builder.setIcon(
- IconCompat.createFromIcon(
- xmppConnectionService,
- Icon.createWithBitmap(
- xmppConnectionService
- .getAvatarService()
- .getRoundedShortcut(mucOptions))));
- }
+ builder.setIcon(
+ IconCompat.createWithBitmap(
+ xmppConnectionService.getAvatarService().getRoundedShortcut(mucOptions)));
+ setConversation(builder, mucOptions.getConversation().getUuid());
return builder.build();
}
- @TargetApi(Build.VERSION_CODES.N_MR1)
- private ShortcutInfo getShortcutInfo(final Contact contact) {
- return getShortcutInfoCompat(contact).toShortcutInfo();
+ private static void setConversation(
+ final ShortcutInfoCompat.Builder builder, @NonNull final String conversation) {
+ builder.setCategories(ImmutableSet.of("eu.siacs.conversations.category.SHARE_TARGET"));
+ final var extras = new PersistableBundle();
+ extras.putString(ConversationsActivity.EXTRA_CONVERSATION, conversation);
+ builder.setExtras(extras);
}
- private static boolean contactsChanged(List needles, List haystack) {
- for(Contact needle : needles) {
- if(!contactExists(needle,haystack)) {
+ private static boolean contactsChanged(
+ final Collection needles, final List haystack) {
+ for (final Contact needle : needles) {
+ if (!contactExists(needle, haystack)) {
return true;
}
}
@@ -143,17 +140,22 @@ public class ShortcutService {
}
@TargetApi(25)
- private static boolean contactExists(Contact needle, List haystack) {
- for(ShortcutInfo shortcutInfo : haystack) {
- if (getShortcutId(needle).equals(shortcutInfo.getId()) && needle.getDisplayName().equals(shortcutInfo.getShortLabel())) {
+ private static boolean contactExists(
+ final Contact needle, final List haystack) {
+ for (final ShortcutInfoCompat shortcutInfo : haystack) {
+ final var label = shortcutInfo.getShortLabel();
+ if (getShortcutId(needle).equals(shortcutInfo.getId())
+ && needle.getDisplayName().equals(label.toString())) {
return true;
}
}
return false;
}
- private static String getShortcutId(Contact contact) {
- return contact.getAccount().getJid().asBareJid().toEscapedString()+"#"+contact.getJid().asBareJid().toEscapedString();
+ private static String getShortcutId(final Contact contact) {
+ return contact.getAccount().getJid().asBareJid().toEscapedString()
+ + "#"
+ + contact.getJid().asBareJid().toEscapedString();
}
private static String getShortcutId(final MucOptions mucOptions) {
@@ -194,12 +196,15 @@ public class ShortcutService {
}
@NonNull
- public Intent createShortcut(Contact contact, boolean legacy) {
+ public Intent createShortcut(final Contact contact, final boolean legacy) {
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !legacy) {
- ShortcutInfo shortcut = getShortcutInfo(contact);
- ShortcutManager shortcutManager = xmppConnectionService.getSystemService(ShortcutManager.class);
- intent = shortcutManager.createShortcutResultIntent(shortcut);
+ final var conversation = xmppConnectionService.find(contact);
+ final var uuid = conversation == null ? null : conversation.getUuid();
+ final var shortcut = getShortcutInfo(contact, uuid);
+ intent =
+ ShortcutManagerCompat.createShortcutResultIntent(
+ xmppConnectionService, shortcut);
} else {
intent = createShortcutResultIntent(contact);
}
@@ -207,7 +212,7 @@ public class ShortcutService {
}
@NonNull
- private Intent createShortcutResultIntent(Contact contact) {
+ private Intent createShortcutResultIntent(final Contact contact) {
AvatarService avatarService = xmppConnectionService.getAvatarService();
Bitmap icon = avatarService.getRoundedShortcutWithIcon(contact);
Intent intent = new Intent();
@@ -218,13 +223,14 @@ public class ShortcutService {
}
public static class FrequentContact {
+ private final String conversation;
private final String account;
private final Jid contact;
- public FrequentContact(String account, Jid contact) {
+ public FrequentContact(final String conversation, final String account, final Jid contact) {
+ this.conversation = conversation;
this.account = account;
this.contact = contact;
}
}
-
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 17a9a3ce9da5059469df6ed01747c2e9edbe037c..a5511bd23c0c9189fb44dd9f3883fa9a49366aff 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -55,8 +55,10 @@ import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
import eu.siacs.conversations.AppSettings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -147,7 +149,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -253,12 +254,13 @@ public class XmppConnectionService extends Service {
private final MessageGenerator mMessageGenerator = new MessageGenerator(this);
public OnContactStatusChanged onContactStatusChanged =
(contact, online) -> {
- Conversation conversation = find(getConversations(), contact);
- if (conversation != null) {
- if (online) {
- if (contact.getPresences().size() == 1) {
- sendUnsentMessages(conversation);
- }
+ final var conversation = find(contact);
+ if (conversation == null) {
+ return;
+ }
+ if (online) {
+ if (contact.getPresences().size() == 1) {
+ sendUnsentMessages(conversation);
}
}
};
@@ -998,16 +1000,17 @@ public class XmppConnectionService extends Service {
}
if (pingNow) {
for (final Account account : pingCandidates) {
+ final var connection = account.getXmppConnection();
final boolean lowTimeout = isInLowPingTimeoutMode(account);
- account.getXmppConnection().sendPing();
+ final var delta =
+ (SystemClock.elapsedRealtime() - connection.getLastPacketReceived())
+ / 1000L;
+ connection.sendPing();
Log.d(
Config.LOGTAG,
- account.getJid().asBareJid()
- + " send ping (action="
- + action
- + ",lowTimeout="
- + lowTimeout
- + ")");
+ String.format(
+ "%s: send ping (action=%s,lowTimeout=%s,interval=%s)",
+ account.getJid().asBareJid(), action, lowTimeout, delta));
scheduleWakeUpCall(
lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT,
account.getUuid().hashCode());
@@ -1485,7 +1488,7 @@ public class XmppConnectionService extends Service {
ContextCompat.RECEIVER_EXPORTED);
mForceDuringOnCreate.set(false);
toggleForegroundService();
- internalPingExecutor.scheduleAtFixedRate(
+ internalPingExecutor.scheduleWithFixedDelay(
this::manageAccountConnectionStatesInternal, 10, 10, TimeUnit.SECONDS);
final SharedPreferences sharedPreferences =
androidx.preference.PreferenceManager.getDefaultSharedPreferences(this);
@@ -2428,10 +2431,8 @@ public class XmppConnectionService extends Service {
private void restoreFromDatabase() {
synchronized (this.conversations) {
- final Map accountLookupTable = new Hashtable<>();
- for (Account account : this.accounts) {
- accountLookupTable.put(account.getUuid(), account);
- }
+ final Map accountLookupTable =
+ ImmutableMap.copyOf(Maps.uniqueIndex(this.accounts, Account::getUuid));
Log.d(Config.LOGTAG, "restoring conversations...");
final long startTimeConversationsRestore = SystemClock.elapsedRealtime();
this.conversations.addAll(
@@ -2735,8 +2736,8 @@ public class XmppConnectionService extends Service {
return results;
}
- public Conversation find(final Iterable haystack, final Contact contact) {
- for (final Conversation conversation : haystack) {
+ public Conversation find(final Contact contact) {
+ for (final Conversation conversation : this.conversations) {
if (conversation.getContact() == contact) {
return conversation;
}
@@ -2798,27 +2799,19 @@ public class XmppConnectionService extends Service {
final MessageArchiveService.Query query,
final boolean async) {
synchronized (this.conversations) {
- Conversation conversation = find(account, jid);
- if (conversation != null) {
- return conversation;
+ final var cached = find(account, jid);
+ if (cached != null) {
+ return cached;
}
- conversation = databaseBackend.findConversation(account, jid);
+ final var existing = databaseBackend.findConversation(account, jid);
+ final Conversation conversation;
final boolean loadMessagesFromDb;
- if (conversation != null) {
- conversation.setStatus(Conversation.STATUS_AVAILABLE);
- conversation.setAccount(account);
- if (muc) {
- conversation.setMode(Conversation.MODE_MULTI);
- conversation.setContactJid(jid);
- } else {
- conversation.setMode(Conversation.MODE_SINGLE);
- conversation.setContactJid(jid.asBareJid());
- }
- databaseBackend.updateConversation(conversation);
- loadMessagesFromDb = conversation.messagesLoaded.compareAndSet(true, false);
+ if (existing != null) {
+ conversation = existing;
+ loadMessagesFromDb = restoreFromArchive(conversation, jid, muc);
} else {
String conversationName;
- Contact contact = account.getRoster().getContact(jid);
+ final Contact contact = account.getRoster().getContact(jid);
if (contact != null) {
conversationName = contact.getDisplayName();
} else {
@@ -2839,35 +2832,13 @@ public class XmppConnectionService extends Service {
this.databaseBackend.createConversation(conversation);
loadMessagesFromDb = false;
}
- final Conversation c = conversation;
- final Runnable runnable =
- () -> {
- if (loadMessagesFromDb) {
- c.addAll(0, databaseBackend.getMessages(c, Config.PAGE_SIZE));
- updateConversationUi();
- c.messagesLoaded.set(true);
- }
- if (account.getXmppConnection() != null
- && !c.getContact().isBlocked()
- && account.getXmppConnection().getFeatures().mam()
- && !muc) {
- if (query == null) {
- mMessageArchiveService.query(c);
- } else {
- if (query.getConversation() == null) {
- mMessageArchiveService.query(
- c, query.getStart(), query.isCatchup());
- }
- }
- }
- if (joinAfterCreate) {
- joinMuc(c);
- }
- };
if (async) {
- mDatabaseReaderExecutor.execute(runnable);
+ mDatabaseReaderExecutor.execute(
+ () ->
+ postProcessConversation(
+ conversation, loadMessagesFromDb, joinAfterCreate, query));
} else {
- runnable.run();
+ postProcessConversation(conversation, loadMessagesFromDb, joinAfterCreate, query);
}
this.conversations.add(conversation);
updateConversationUi();
@@ -2875,6 +2846,84 @@ public class XmppConnectionService extends Service {
}
}
+ public Conversation findConversationByUuidReliable(final String uuid) {
+ final var cached = findConversationByUuid(uuid);
+ if (cached != null) {
+ return cached;
+ }
+ final var existing = databaseBackend.findConversation(uuid);
+ if (existing == null) {
+ return null;
+ }
+ Log.d(
+ Config.LOGTAG,
+ existing.getJid().asBareJid()
+ + ": restoring conversation with "
+ + existing.getJid()
+ + " from DB");
+ final Map accounts =
+ ImmutableMap.copyOf(Maps.uniqueIndex(this.accounts, Account::getUuid));
+ existing.setAccount(accounts.get(existing.getAccountUuid()));
+ final var loadMessagesFromDb = restoreFromArchive(existing);
+ mDatabaseReaderExecutor.execute(
+ () ->
+ postProcessConversation(
+ existing,
+ loadMessagesFromDb,
+ existing.getMode() == Conversational.MODE_MULTI,
+ null));
+ this.conversations.add(existing);
+ updateConversationUi();
+ return existing;
+ }
+
+ private boolean restoreFromArchive(
+ final Conversation conversation, final Jid jid, final boolean muc) {
+ if (muc) {
+ conversation.setMode(Conversation.MODE_MULTI);
+ conversation.setContactJid(jid);
+ } else {
+ conversation.setMode(Conversation.MODE_SINGLE);
+ conversation.setContactJid(jid.asBareJid());
+ }
+ return restoreFromArchive(conversation);
+ }
+
+ private boolean restoreFromArchive(final Conversation conversation) {
+ conversation.setStatus(Conversation.STATUS_AVAILABLE);
+ databaseBackend.updateConversation(conversation);
+ return conversation.messagesLoaded.compareAndSet(true, false);
+ }
+
+ private void postProcessConversation(
+ final Conversation c,
+ final boolean loadMessagesFromDb,
+ final boolean joinAfterCreate,
+ final MessageArchiveService.Query query) {
+ final var singleMode = c.getMode() == Conversational.MODE_SINGLE;
+ final var account = c.getAccount();
+ if (loadMessagesFromDb) {
+ c.addAll(0, databaseBackend.getMessages(c, Config.PAGE_SIZE));
+ updateConversationUi();
+ c.messagesLoaded.set(true);
+ }
+ if (account.getXmppConnection() != null
+ && !c.getContact().isBlocked()
+ && account.getXmppConnection().getFeatures().mam()
+ && singleMode) {
+ if (query == null) {
+ mMessageArchiveService.query(c);
+ } else {
+ if (query.getConversation() == null) {
+ mMessageArchiveService.query(c, query.getStart(), query.isCatchup());
+ }
+ }
+ }
+ if (joinAfterCreate) {
+ joinMuc(c);
+ }
+ }
+
public void archiveConversation(Conversation conversation) {
archiveConversation(conversation, true);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
index 2c7d71d79c91cbe0dd7dc700977fc8abfcf4b0a0..f90f99b8b317c22f023f42d1223585787fb0c7d2 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java
@@ -29,7 +29,6 @@
package eu.siacs.conversations.ui;
-
import static eu.siacs.conversations.ui.ConversationFragment.REQUEST_DECRYPT_PGP;
import android.Manifest;
@@ -51,22 +50,13 @@ import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.databinding.DataBindingUtil;
-
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
-import org.openintents.openpgp.util.OpenPgpApi;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OmemoSetting;
@@ -90,8 +80,22 @@ import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.openintents.openpgp.util.OpenPgpApi;
-public class ConversationsActivity extends XmppActivity implements OnConversationSelected, OnConversationArchived, OnConversationsListItemUpdated, OnConversationRead, XmppConnectionService.OnAccountUpdate, XmppConnectionService.OnConversationUpdate, XmppConnectionService.OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnAffiliationChanged {
+public class ConversationsActivity extends XmppActivity
+ implements OnConversationSelected,
+ OnConversationArchived,
+ OnConversationsListItemUpdated,
+ OnConversationRead,
+ XmppConnectionService.OnAccountUpdate,
+ XmppConnectionService.OnConversationUpdate,
+ XmppConnectionService.OnRosterUpdate,
+ OnUpdateBlocklist,
+ XmppConnectionService.OnShowErrorToast,
+ XmppConnectionService.OnAffiliationChanged {
public static final String ACTION_VIEW_CONVERSATION = "eu.siacs.conversations.action.VIEW";
public static final String EXTRA_CONVERSATION = "conversationUuid";
@@ -104,19 +108,18 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
public static final String POST_ACTION_RECORD_VOICE = "record_voice";
public static final String EXTRA_TYPE = "type";
- private static final List VIEW_AND_SHARE_ACTIONS = Arrays.asList(
- ACTION_VIEW_CONVERSATION,
- Intent.ACTION_SEND,
- Intent.ACTION_SEND_MULTIPLE
- );
+ private static final List VIEW_AND_SHARE_ACTIONS =
+ Arrays.asList(
+ ACTION_VIEW_CONVERSATION, Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE);
public static final int REQUEST_OPEN_MESSAGE = 0x9876;
public static final int REQUEST_PLAY_PAUSE = 0x5432;
-
- //secondary fragment (when holding the conversation, must be initialized before refreshing the overview fragment
- private static final @IdRes
- int[] FRAGMENT_ID_NOTIFICATION_ORDER = {R.id.secondary_fragment, R.id.main_fragment};
+ // secondary fragment (when holding the conversation, must be initialized before refreshing the
+ // overview fragment
+ private static final @IdRes int[] FRAGMENT_ID_NOTIFICATION_ORDER = {
+ R.id.secondary_fragment, R.id.main_fragment
+ };
private final PendingItem pendingViewIntent = new PendingItem<>();
private final PendingItem postponedActivityResult = new PendingItem<>();
private ActivityConversationsBinding binding;
@@ -125,7 +128,9 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
private static boolean isViewOrShareIntent(Intent i) {
Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction()));
- return i != null && VIEW_AND_SHARE_ACTIONS.contains(i.getAction()) && i.hasExtra(EXTRA_CONVERSATION);
+ return i != null
+ && VIEW_AND_SHARE_ACTIONS.contains(i.getAction())
+ && i.hasExtra(EXTRA_CONVERSATION);
}
private static Intent createLauncherIntent(Context context) {
@@ -169,7 +174,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
invalidateActionBarTitle();
- if (binding.secondaryFragment != null && ConversationFragment.getConversation(this) == null) {
+ if (binding.secondaryFragment != null
+ && ConversationFragment.getConversation(this) == null) {
Conversation conversation = ConversationsOverviewFragment.getSuggestion(this);
if (conversation != null) {
openConversation(conversation, null);
@@ -182,7 +188,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
return performRedirectIfNecessary(null, noAnimation);
}
- private boolean performRedirectIfNecessary(final Conversation ignore, final boolean noAnimation) {
+ private boolean performRedirectIfNecessary(
+ final Conversation ignore, final boolean noAnimation) {
if (xmppConnectionService == null) {
return false;
}
@@ -192,12 +199,13 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
if (noAnimation) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
}
- runOnUiThread(() -> {
- startActivity(intent);
- if (noAnimation) {
- overridePendingTransition(0, 0);
- }
- });
+ runOnUiThread(
+ () -> {
+ startActivity(intent);
+ if (noAnimation) {
+ overridePendingTransition(0, 0);
+ }
+ });
}
return mRedirectInProcess.get();
}
@@ -219,7 +227,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private String getBatteryOptimizationPreferenceKey() {
- @SuppressLint("HardwareIds") String device = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
+ @SuppressLint("HardwareIds")
+ String device = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
return "show_battery_optimization" + (device == null ? "" : device);
}
@@ -228,20 +237,31 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private boolean openBatteryOptimizationDialogIfNeeded() {
- if (isOptimizingBattery() && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
+ if (isOptimizingBattery()
+ && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.battery_optimizations_enabled);
- builder.setMessage(getString(R.string.battery_optimizations_enabled_dialog, getString(R.string.app_name)));
- builder.setPositiveButton(R.string.next, (dialog, which) -> {
- final Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- final Uri uri = Uri.parse("package:" + getPackageName());
- intent.setData(uri);
- try {
- startActivityForResult(intent, REQUEST_BATTERY_OP);
- } catch (final ActivityNotFoundException e) {
- Toast.makeText(this, R.string.device_does_not_support_battery_op, Toast.LENGTH_SHORT).show();
- }
- });
+ builder.setMessage(
+ getString(
+ R.string.battery_optimizations_enabled_dialog,
+ getString(R.string.app_name)));
+ builder.setPositiveButton(
+ R.string.next,
+ (dialog, which) -> {
+ final Intent intent =
+ new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ final Uri uri = Uri.parse("package:" + getPackageName());
+ intent.setData(uri);
+ try {
+ startActivityForResult(intent, REQUEST_BATTERY_OP);
+ } catch (final ActivityNotFoundException e) {
+ Toast.makeText(
+ this,
+ R.string.device_does_not_support_battery_op,
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ });
builder.setOnDismissListener(dialog -> setNeverAskForBatteryOptimizationsAgain());
final AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
@@ -252,8 +272,12 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private void requestNotificationPermissionIfNeeded() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_POST_NOTIFICATION);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
+ && ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(
+ new String[] {Manifest.permission.POST_NOTIFICATIONS},
+ REQUEST_POST_NOTIFICATION);
}
}
@@ -271,9 +295,10 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
}
- private boolean processViewIntent(Intent intent) {
+ private boolean processViewIntent(final Intent intent) {
final String uuid = intent.getStringExtra(EXTRA_CONVERSATION);
- final Conversation conversation = uuid != null ? xmppConnectionService.findConversationByUuid(uuid) : null;
+ final Conversation conversation =
+ uuid != null ? xmppConnectionService.findConversationByUuidReliable(uuid) : null;
if (conversation == null) {
Log.d(Config.LOGTAG, "unable to view conversation with uuid:" + uuid);
return false;
@@ -283,7 +308,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
@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);
UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
if (grantResults.length > 0) {
@@ -397,8 +423,9 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
if (qrCodeScanMenuItem != null) {
if (isCameraFeatureAvailable()) {
Fragment fragment = getFragmentManager().findFragmentById(R.id.main_fragment);
- boolean visible = getResources().getBoolean(R.bool.show_qr_code_scan)
- && fragment instanceof ConversationsOverviewFragment;
+ boolean visible =
+ getResources().getBoolean(R.bool.show_qr_code_scan)
+ && fragment instanceof ConversationsOverviewFragment;
qrCodeScanMenuItem.setVisible(visible);
} else {
qrCodeScanMenuItem.setVisible(false);
@@ -411,7 +438,9 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
public void onConversationSelected(Conversation conversation) {
clearPendingViewIntent();
if (ConversationFragment.getConversation(this) == conversation) {
- Log.d(Config.LOGTAG, "ignore onConversationSelected() because conversation is already open");
+ Log.d(
+ Config.LOGTAG,
+ "ignore onConversationSelected() because conversation is already open");
return;
}
openConversation(conversation, null);
@@ -424,13 +453,12 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private void displayToast(final String msg) {
- runOnUiThread(() -> Toast.makeText(ConversationsActivity.this, msg, Toast.LENGTH_SHORT).show());
+ runOnUiThread(
+ () -> Toast.makeText(ConversationsActivity.this, msg, Toast.LENGTH_SHORT).show());
}
@Override
- public void onAffiliationChangedSuccessful(Jid jid) {
-
- }
+ public void onAffiliationChangedSuccessful(Jid jid) {}
@Override
public void onAffiliationChangeFailed(Jid jid, int resId) {
@@ -440,7 +468,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
private void openConversation(Conversation conversation, Bundle extras) {
final FragmentManager fragmentManager = getFragmentManager();
executePendingTransactions(fragmentManager);
- ConversationFragment conversationFragment = (ConversationFragment) fragmentManager.findFragmentById(R.id.secondary_fragment);
+ ConversationFragment conversationFragment =
+ (ConversationFragment) fragmentManager.findFragmentById(R.id.secondary_fragment);
final boolean mainNeedsRefresh;
if (conversationFragment == null) {
mainNeedsRefresh = false;
@@ -456,7 +485,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
fragmentTransaction.commit();
} catch (IllegalStateException e) {
Log.w(Config.LOGTAG, "sate loss while opening conversation", e);
- //allowing state loss is probably fine since view intents et all are already stored and a click can probably be 'ignored'
+ // allowing state loss is probably fine since view intents et all are already
+ // stored and a click can probably be 'ignored'
return;
}
}
@@ -474,14 +504,15 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
try {
fragmentManager.executePendingTransactions();
} catch (final Exception e) {
- Log.e(Config.LOGTAG,"unable to execute pending fragment transactions");
+ Log.e(Config.LOGTAG, "unable to execute pending fragment transactions");
}
}
public boolean onXmppUriClicked(Uri uri) {
XmppUri xmppUri = new XmppUri(uri);
if (xmppUri.isValidJid() && !xmppUri.hasFingerprints()) {
- final Conversation conversation = xmppConnectionService.findUniqueConversationByJid(xmppUri);
+ final Conversation conversation =
+ xmppConnectionService.findUniqueConversationByJid(xmppUri);
if (conversation != null) {
openConversation(conversation, null);
return true;
@@ -540,7 +571,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
@Override
public void onSaveInstanceState(final Bundle savedInstanceState) {
final Intent pendingIntent = pendingViewIntent.peek();
- savedInstanceState.putParcelable("intent", pendingIntent != null ? pendingIntent : getIntent());
+ savedInstanceState.putParcelable(
+ "intent", pendingIntent != null ? pendingIntent : getIntent());
super.onSaveInstanceState(savedInstanceState);
}
@@ -580,7 +612,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
final FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
- final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
+ final Fragment secondaryFragment =
+ fragmentManager.findFragmentById(R.id.secondary_fragment);
if (mainFragment != null) {
if (binding.secondaryFragment != null) {
if (mainFragment instanceof ConversationFragment) {
@@ -628,13 +661,12 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
actionBar.setTitle(conversation.getName());
actionBar.setDisplayHomeAsUpEnabled(true);
ToolbarUtils.setActionBarOnClickListener(
- binding.toolbar,
- (v) -> openConversationDetails(conversation)
- );
+ binding.toolbar, (v) -> openConversationDetails(conversation));
return;
}
}
- final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
+ final Fragment secondaryFragment =
+ fragmentManager.findFragmentById(R.id.secondary_fragment);
if (secondaryFragment instanceof ConversationFragment conversationFragment) {
final Conversation conversation = conversationFragment.getConversation();
if (conversation != null) {
@@ -673,15 +705,21 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
try {
fragmentManager.popBackStack();
} catch (final IllegalStateException e) {
- Log.w(Config.LOGTAG, "state loss while popping back state after archiving conversation", e);
- //this usually means activity is no longer active; meaning on the next open we will run through this again
+ Log.w(
+ Config.LOGTAG,
+ "state loss while popping back state after archiving conversation",
+ e);
+ // this usually means activity is no longer active; meaning on the next open we will
+ // run through this again
}
return;
}
- final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
+ final Fragment secondaryFragment =
+ fragmentManager.findFragmentById(R.id.secondary_fragment);
if (secondaryFragment instanceof ConversationFragment) {
if (((ConversationFragment) secondaryFragment).getConversation() == conversation) {
- Conversation suggestion = ConversationsOverviewFragment.getSuggestion(this, conversation);
+ Conversation suggestion =
+ ConversationsOverviewFragment.getSuggestion(this, conversation);
if (suggestion != null) {
openConversation(suggestion, null);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index c33c3e6bd7ba2c7c23ba57b6dd4609fcbb2afb58..1f83d1f4546f8a027b4eec96fcc2335710aa4cc4 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -8,11 +8,11 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-
import androidx.annotation.NonNull;
+import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
-
+import com.google.common.collect.Iterables;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityShareWithBinding;
@@ -21,7 +21,6 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.xmpp.Jid;
-
import java.util.ArrayList;
import java.util.List;
@@ -112,7 +111,34 @@ public class ShareWithActivity extends XmppActivity
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
binding.chooseConversationList.setAdapter(mAdapter);
mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
+ final var intent = getIntent();
+ final var shortcutId = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID);
this.share = new Share();
+ if (shortcutId != null) {
+ final var conversation = shortcutIdToConversation(shortcutId);
+ if (conversation != null) {
+ // we have everything we need. Jump into chat
+ populateShare(intent);
+ share(conversation);
+ }
+ }
+ }
+
+ private String shortcutIdToConversation(final String shortcutId) {
+ final var shortcut =
+ Iterables.tryFind(
+ ShortcutManagerCompat.getDynamicShortcuts(this),
+ si -> si.getId().equals(shortcutId));
+ if (shortcut.isPresent()) {
+ final var extras = shortcut.get().getExtras();
+ if (extras == null) {
+ return null;
+ } else {
+ return extras.getString(ConversationsActivity.EXTRA_CONVERSATION);
+ }
+ } else {
+ return null;
+ }
}
@Override
@@ -137,10 +163,18 @@ public class ShareWithActivity extends XmppActivity
@Override
public void onStart() {
super.onStart();
- Intent intent = getIntent();
+ final Intent intent = getIntent();
if (intent == null) {
return;
}
+ populateShare(intent);
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.populateWithOrderedConversations(
+ mConversations, this.share.uris.isEmpty(), false);
+ }
+ }
+
+ private void populateShare(final Intent intent) {
final String type = intent.getType();
final String action = intent.getAction();
final Uri data = intent.getData();
@@ -165,10 +199,6 @@ public class ShareWithActivity extends XmppActivity
final ArrayList uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
this.share.uris = uris == null ? new ArrayList<>() : uris;
}
- if (xmppConnectionServiceBound) {
- xmppConnectionService.populateWithOrderedConversations(
- mConversations, this.share.uris.isEmpty(), false);
- }
}
@Override
@@ -209,8 +239,12 @@ public class ShareWithActivity extends XmppActivity
mPendingConversation = conversation;
return;
}
+ share(conversation.getUuid());
+ }
+
+ private void share(final String conversation) {
final Intent intent = new Intent(this, ConversationsActivity.class);
- intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
+ intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation);
if (!share.uris.isEmpty()) {
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, share.uris);
@@ -225,7 +259,7 @@ public class ShareWithActivity extends XmppActivity
}
try {
startActivity(intent);
- } catch (SecurityException e) {
+ } catch (final SecurityException e) {
Toast.makeText(
this,
R.string.sharing_application_not_grant_permission,
diff --git a/src/main/res/xml/shortcuts.xml b/src/main/res/xml/shortcuts.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8bb176555063882535621d602d02275994e7acea
--- /dev/null
+++ b/src/main/res/xml/shortcuts.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file