Skip to content

Commit

Permalink
Add support for manual initiation of GV1->GV2 migrations.
Browse files Browse the repository at this point in the history
  • Loading branch information
greyson-signal committed Nov 12, 2020
1 parent 4eaa6eb commit 7e347f5
Show file tree
Hide file tree
Showing 27 changed files with 1,159 additions and 422 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.thoughtcrime.securesms.components.reminder;

import android.content.Context;

import androidx.annotation.NonNull;

import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.RecipientId;

import java.util.List;

/**
* Shows a reminder to upgrade a group to GV2.
*/
public class GroupsV1MigrationInitiationReminder extends Reminder {

public GroupsV1MigrationInitiationReminder(@NonNull Context context) {
super(null, context.getString(R.string.GroupsV1MigrationInitiationReminder_to_access_new_features_like_mentions));
addAction(new Action(context.getString(R.string.GroupsV1MigrationInitiationReminder_update_group), R.id.reminder_action_gv1_initiation_update_group));
addAction(new Action(context.getResources().getString(R.string.GroupsV1MigrationInitiationReminder_not_now), R.id.reminder_action_gv1_initiation_not_now));
}

@Override
public boolean isDismissable() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
import org.thoughtcrime.securesms.components.location.SignalPlace;
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
import org.thoughtcrime.securesms.components.reminder.GroupsV1MigrationInitiationReminder;
import org.thoughtcrime.securesms.components.reminder.GroupsV1MigrationSuggestionsReminder;
import org.thoughtcrime.securesms.components.reminder.PendingGroupJoinRequestsReminder;
import org.thoughtcrime.securesms.components.reminder.Reminder;
Expand Down Expand Up @@ -167,6 +168,7 @@
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity;
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationInitiationBottomSheetDialogFragment;
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationSuggestionsDialog;
import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.invites.InviteReminderModel;
Expand Down Expand Up @@ -455,7 +457,7 @@ protected void onCreate(Bundle state, boolean ready) {
initializeMentionsViewModel();
initializeEnabledCheck();
initializePendingRequestsBanner();
initializeGroupV1MigrationSuggestionsBanner();
initializeGroupV1MigrationsBanners();
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
Expand Down Expand Up @@ -1550,11 +1552,14 @@ private void initializePendingRequestsBanner() {
.observe(this, actionablePendingGroupRequests -> updateReminders());
}

private void initializeGroupV1MigrationSuggestionsBanner() {
private void initializeGroupV1MigrationsBanners() {
groupViewModel.getGroupV1MigrationSuggestions()
.observe(this, s -> updateReminders());
groupViewModel.getShowGroupsV1MigrationBanner()
.observe(this, b -> updateReminders());
}


private ListenableFuture<Boolean> initializeDraftFromDatabase() {
SettableFuture<Boolean> future = new SettableFuture<>();

Expand Down Expand Up @@ -1711,6 +1716,7 @@ protected void updateReminders() {
Optional<Reminder> inviteReminder = inviteReminderModel.getReminder();
Integer actionableRequestingMembers = groupViewModel.getActionableRequestingMembers().getValue();
List<RecipientId> gv1MigrationSuggestions = groupViewModel.getGroupV1MigrationSuggestions().getValue();
Boolean gv1MigrationBanner = groupViewModel.getShowGroupsV1MigrationBanner().getValue();

if (UnauthorizedReminder.isEligible(this)) {
reminderView.get().showReminder(new UnauthorizedReminder(this));
Expand All @@ -1735,6 +1741,15 @@ protected void updateReminders() {
startActivity(ManagePendingAndRequestingMembersActivity.newIntent(this, getRecipient().getGroupId().get().requireV2()));
}
});
} else if (gv1MigrationBanner == Boolean.TRUE && recipient.get().isPushV1Group()) {
reminderView.get().showReminder(new GroupsV1MigrationInitiationReminder(this));
reminderView.get().setOnActionClickListener(actionId -> {
if (actionId == R.id.reminder_action_gv1_initiation_update_group) {
GroupsV1MigrationInitiationBottomSheetDialogFragment.showForInitiation(getSupportFragmentManager(), recipient.getId());
} else if (actionId == R.id.reminder_action_gv1_initiation_not_now) {
groupViewModel.onMigrationInitiationReminderBannerDismissed(recipient.getId());
}
});
} else if (gv1MigrationSuggestions != null && gv1MigrationSuggestions.size() > 0 && recipient.get().isPushV2Group()) {
reminderView.get().showReminder(new GroupsV1MigrationSuggestionsReminder(this, gv1MigrationSuggestions));
reminderView.get().setOnActionClickListener(actionId -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationBottomSheetDialogFragment;
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationInfoBottomSheetDialogFragment;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
Expand Down Expand Up @@ -1427,7 +1427,7 @@ public boolean onUrlClicked(@NonNull String url) {

@Override
public void onGroupMigrationLearnMoreClicked(@NonNull List<RecipientId> pendingRecipients) {
GroupsV1MigrationBottomSheetDialogFragment.showForLearnMore(requireFragmentManager(), pendingRecipients);
GroupsV1MigrationInfoBottomSheetDialogFragment.showForLearnMore(requireFragmentManager(), pendingRecipients);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.conversation;

import android.app.Application;
import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -16,13 +17,13 @@
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.groups.GroupsV1MigrationUtil;
import org.thoughtcrime.securesms.profiles.spoofing.ReviewRecipient;
import org.thoughtcrime.securesms.profiles.spoofing.ReviewUtil;
import org.thoughtcrime.securesms.recipients.Recipient;
Expand All @@ -37,15 +38,19 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

final class ConversationGroupViewModel extends ViewModel {

private static final long GV1_MIGRATION_REMINDER_INTERVAL = TimeUnit.DAYS.toMillis(1);

private final MutableLiveData<Recipient> liveRecipient;
private final LiveData<GroupActiveState> groupActiveState;
private final LiveData<GroupDatabase.MemberLevel> selfMembershipLevel;
private final LiveData<Integer> actionableRequestingMembers;
private final LiveData<ReviewState> reviewState;
private final LiveData<List<RecipientId>> gv1MigrationSuggestions;
private final LiveData<Boolean> gv1MigrationReminder;

private ConversationGroupViewModel() {
this.liveRecipient = new MutableLiveData<>();
Expand All @@ -65,6 +70,7 @@ private ConversationGroupViewModel() {
this.selfMembershipLevel = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToSelfMembershipLevel));
this.actionableRequestingMembers = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToActionableRequestingMemberCount));
this.gv1MigrationSuggestions = Transformations.distinctUntilChanged(LiveDataUtil.mapAsync(groupRecord, ConversationGroupViewModel::mapToGroupV1MigrationSuggestions));
this.gv1MigrationReminder = Transformations.distinctUntilChanged(LiveDataUtil.mapAsync(groupRecord, ConversationGroupViewModel::mapToGroupV1MigrationReminder));
this.reviewState = LiveDataUtil.combineLatest(groupRecord,
duplicates,
(record, dups) -> dups.isEmpty()
Expand All @@ -86,6 +92,13 @@ void onSuggestedMembersBannerDismissed(@NonNull GroupId groupId) {
});
}

void onMigrationInitiationReminderBannerDismissed(@NonNull RecipientId recipientId) {
SignalExecutors.BOUNDED.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).markGroupsV1MigrationReminderSeen(recipientId, System.currentTimeMillis());
liveRecipient.postValue(liveRecipient.getValue());
});
}

/**
* The number of pending group join requests that can be actioned by this client.
*/
Expand All @@ -109,6 +122,10 @@ public LiveData<ReviewState> getReviewState() {
return gv1MigrationSuggestions;
}

@NonNull LiveData<Boolean> getShowGroupsV1MigrationBanner() {
return gv1MigrationReminder;
}

private static @Nullable GroupRecord getGroupRecordForRecipient(@Nullable Recipient recipient) {
if (recipient != null && recipient.isGroup()) {
Application context = ApplicationDependencies.getApplication();
Expand Down Expand Up @@ -156,15 +173,30 @@ private static List<RecipientId> mapToGroupV1MigrationSuggestions(@Nullable Grou
Set<RecipientId> difference = SetUtil.difference(record.getFormerV1Members(), record.getMembers());

return Stream.of(Recipient.resolvedList(difference))
.filter(r -> r.hasUuid() &&
r.getGroupsV1MigrationCapability() == Recipient.Capability.SUPPORTED &&
r.getGroupsV2Capability() == Recipient.Capability.SUPPORTED &&
r.getProfileKey() != null &&
r.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED)
.filter(GroupsV1MigrationUtil::isAutoMigratable)
.map(Recipient::getId)
.toList();
}

@WorkerThread
private static boolean mapToGroupV1MigrationReminder(@Nullable GroupRecord record) {
if (record == null || !record.isV1Group() || !record.isActive() || !FeatureFlags.groupsV1ManualMigration()) {
return false;
}

boolean canAutoMigrate = Stream.of(Recipient.resolvedList(record.getMembers()))
.allMatch(GroupsV1MigrationUtil::isAutoMigratable);

if (canAutoMigrate) {
return false;
}

Context context = ApplicationDependencies.getApplication();
long lastReminderTime = DatabaseFactory.getRecipientDatabase(context).getGroupsV1MigrationReminderLastSeen(record.getRecipientId());

return System.currentTimeMillis() - lastReminderTime > GV1_MIGRATION_REMINDER_INTERVAL;
}

public static void onCancelJoinRequest(@NonNull Recipient recipient,
@NonNull AsynchronousCallback.WorkerThread<Void, GroupChangeFailureReason> callback)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public Cursor getIdentityConflictMessagesForThread(long threadId) {

public Cursor getConversationSnippet(long threadId) {
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND (" + SmsDatabase.TYPE + " IS NULL OR " + SmsDatabase.TYPE + " != " + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ")";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND (" + SmsDatabase.TYPE + " IS NULL OR " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + "))";

return queryTables(PROJECTION, selection, order, "1");
}
Expand Down

0 comments on commit 7e347f5

Please sign in to comment.