diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt index 4bba7a023..6c507cf5c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobs.RefreshAttributesJob +import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.storage.StorageSyncHelper @@ -69,7 +70,7 @@ class PrivacySettingsViewModel( fun setPhoneNumberListingMode(phoneNumberListingMode: PhoneNumberPrivacyValues.PhoneNumberListingMode) { SignalStore.phoneNumberPrivacy().phoneNumberListingMode = phoneNumberListingMode StorageSyncHelper.scheduleSyncForDataChange() - ApplicationDependencies.getJobManager().add(RefreshAttributesJob()) + ApplicationDependencies.getJobManager().startChain(RefreshAttributesJob()).then(RefreshOwnProfileJob()).enqueue() refresh() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt index 5c982b19b..1d0d3942c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt @@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver import org.thoughtcrime.securesms.jobs.RefreshAttributesJob +import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob import org.thoughtcrime.securesms.keyvalue.SettingsValues import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter @@ -71,7 +72,7 @@ class AdvancedPrivacySettingsViewModel( fun setAllowSealedSenderFromAnyone(enabled: Boolean) { sharedPreferences.edit().putBoolean(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS, enabled).apply() - ApplicationDependencies.getJobManager().add(RefreshAttributesJob()) + ApplicationDependencies.getJobManager().startChain(RefreshAttributesJob()).then(RefreshOwnProfileJob()).enqueue() refresh() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.kt index 82718854c..e0ce7f20b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.kt @@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase.Companion.identities import org.thoughtcrime.securesms.database.SignalDatabase.Companion.messageLog import org.thoughtcrime.securesms.database.SignalDatabase.Companion.notificationProfiles import org.thoughtcrime.securesms.database.SignalDatabase.Companion.reactions +import org.thoughtcrime.securesms.database.SignalDatabase.Companion.runPostSuccessfulTransaction import org.thoughtcrime.securesms.database.SignalDatabase.Companion.sessions import org.thoughtcrime.securesms.database.SignalDatabase.Companion.threads import org.thoughtcrime.securesms.database.model.DistributionListId @@ -54,7 +55,6 @@ import org.thoughtcrime.securesms.groups.GroupId.V2 import org.thoughtcrime.securesms.groups.v2.ProfileKeySet import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor import org.thoughtcrime.securesms.jobs.RecipientChangedNumberJob -import org.thoughtcrime.securesms.jobs.RefreshAttributesJob import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob import org.thoughtcrime.securesms.jobs.RetrieveProfileJob import org.thoughtcrime.securesms.keyvalue.SignalStore @@ -69,6 +69,7 @@ import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.Bitmask import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.IdentityUtil +import org.thoughtcrime.securesms.util.ProfileUtil import org.thoughtcrime.securesms.util.SqlUtil import org.thoughtcrime.securesms.util.StringUtil import org.thoughtcrime.securesms.util.Util @@ -966,8 +967,8 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) : } if (remoteKey != localKey) { - Log.w(TAG, "Profile key changed during storage sync! Scheduling jobs to refresh things.") - ApplicationDependencies.getJobManager().add(RefreshAttributesJob()) + Log.i(TAG, "Our own profile key was changed during a storage sync.", Throwable()) + runPostSuccessfulTransaction { ProfileUtil.handleSelfProfileKeyChange() } } threads.applyStorageSyncUpdate(Recipient.self().id, update.new) @@ -1446,6 +1447,12 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) : rotateStorageId(id) ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id) StorageSyncHelper.scheduleSyncForDataChange() + + if (id == Recipient.self().id) { + Log.i(TAG, "Our own profile key was changed.", Throwable()) + runPostSuccessfulTransaction { ProfileUtil.handleSelfProfileKeyChange() } + } + return true } return false diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt index da84ba551..62440864b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt @@ -231,6 +231,11 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data instance!!.signalReadableDatabase.runPostSuccessfulTransaction(dedupeKey, task) } + @JvmStatic + fun runPostSuccessfulTransaction(task: Runnable) { + instance!!.signalReadableDatabase.runPostSuccessfulTransaction(task) + } + @JvmStatic fun databaseFileExists(context: Context): Boolean { return context.getDatabasePath(DATABASE_NAME).exists() diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java index f4c66ffe8..c0217a259 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java @@ -122,8 +122,6 @@ public class RefreshAttributesJob extends BaseJob { phoneNumberDiscoverable, encryptedDeviceName); - ApplicationDependencies.getJobManager().add(new RefreshOwnProfileJob()); - hasRefreshedThisAppCycle = true; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java index 68fe86e20..5fa82d793 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java @@ -5,14 +5,10 @@ import androidx.annotation.NonNull; import org.signal.zkgroup.profiles.ProfileKey; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.database.SignalDatabase; -import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.recipients.Recipient; -import java.util.List; - public class RotateProfileKeyJob extends BaseJob { public static String KEY = "RotateProfileKeyJob"; @@ -44,20 +40,6 @@ public class RotateProfileKeyJob extends BaseJob { Recipient self = Recipient.self(); SignalDatabase.recipients().setProfileKey(self.getId(), newProfileKey); - - ApplicationDependencies.getJobManager().add(new ProfileUploadJob()); - ApplicationDependencies.getJobManager().add(new RefreshAttributesJob()); - ApplicationDependencies.getJobManager().add(new MultiDeviceProfileKeyUpdateJob()); - - updateProfileKeyOnAllV2Groups(); - } - - private void updateProfileKeyOnAllV2Groups() { - List allGv2Groups = SignalDatabase.groups().getAllGroupV2Ids(); - - for (GroupId.V2 groupId : allGv2Groups) { - ApplicationDependencies.getJobManager().add(GroupV2UpdateSelfProfileKeyJob.withoutLimits(groupId)); - } } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/PinOptOutMigration.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/PinOptOutMigration.java index d82fb3599..8bfc672a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/PinOptOutMigration.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/PinOptOutMigration.java @@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobs.RefreshAttributesJob; +import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob; import org.thoughtcrime.securesms.jobs.StorageForcePushJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; @@ -40,8 +41,10 @@ public final class PinOptOutMigration extends MigrationJob { Log.w(TAG, "Discovered a legacy opt-out user! Resetting the state."); SignalStore.kbsValues().optOut(); - ApplicationDependencies.getJobManager().add(new RefreshAttributesJob()); - ApplicationDependencies.getJobManager().add(new StorageForcePushJob()); + ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob()) + .then(new RefreshOwnProfileJob()) + .then(new StorageForcePushJob()) + .enqueue(); } else if (SignalStore.kbsValues().hasOptedOut()) { Log.i(TAG, "Discovered an opt-out user, but they're already in a good state. No action required."); } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/StorageCapabilityMigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/StorageCapabilityMigrationJob.java index 4dbe4d36a..20482923d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/StorageCapabilityMigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/StorageCapabilityMigrationJob.java @@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobs.MultiDeviceKeysUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceStorageSyncRequestJob; import org.thoughtcrime.securesms.jobs.RefreshAttributesJob; +import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob; import org.thoughtcrime.securesms.jobs.StorageForcePushJob; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -50,7 +51,7 @@ public class StorageCapabilityMigrationJob extends MigrationJob { public void performMigration() { JobManager jobManager = ApplicationDependencies.getJobManager(); - jobManager.add(new RefreshAttributesJob()); + jobManager.startChain(new RefreshAttributesJob()).then(new RefreshOwnProfileJob()).enqueue(); if (TextSecurePreferences.isMultiDevice(context)) { Log.i(TAG, "Multi-device."); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java index 84c61b403..f3d240013 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ProfileUtil.java @@ -6,15 +6,26 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; +import com.google.protobuf.ByteString; + import org.signal.core.util.logging.Log; +import org.signal.storageservice.protos.groups.local.DecryptedMember; import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.profiles.ProfileKey; import org.thoughtcrime.securesms.badges.models.Badge; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; +import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; +import org.thoughtcrime.securesms.groups.GroupId; +import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.jobs.GroupV2UpdateSelfProfileKeyJob; +import org.thoughtcrime.securesms.jobs.MultiDeviceProfileKeyUpdateJob; +import org.thoughtcrime.securesms.jobs.ProfileUploadJob; +import org.thoughtcrime.securesms.jobs.RefreshAttributesJob; +import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.payments.MobileCoinPublicAddress; import org.thoughtcrime.securesms.payments.MobileCoinPublicAddressProfileUtil; @@ -38,6 +49,7 @@ import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.util.StreamDetails; +import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.internal.ServiceResponse; import org.whispersystems.signalservice.internal.push.SignalServiceProtos; @@ -58,6 +70,28 @@ public final class ProfileUtil { private ProfileUtil() { } + /** + * Should be called after a change to our own profile key as been persisted to the database. + */ + @WorkerThread + public static void handleSelfProfileKeyChange() { + List gv2UpdateJobs = SignalDatabase.groups() + .getAllGroupV2Ids() + .stream() + .map(GroupV2UpdateSelfProfileKeyJob::withoutLimits) + .collect(Collectors.toList()); + + Log.w(TAG, "[handleSelfProfileKeyChange] Scheduling jobs, including " + gv2UpdateJobs.size() + " group update jobs."); + + ApplicationDependencies.getJobManager() + .startChain(new RefreshAttributesJob()) + .then(new ProfileUploadJob()) + .then(new RefreshOwnProfileJob()) + .then(new MultiDeviceProfileKeyUpdateJob()) + .then(gv2UpdateJobs) + .enqueue(); + } + @WorkerThread public static @NonNull ProfileAndCredential retrieveProfileSync(@NonNull Context context, @NonNull Recipient recipient,