mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-25 03:11:10 +01:00
GV2 leave and eject operations.
This commit is contained in:
@@ -77,8 +77,44 @@ public final class GroupManager {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static boolean leaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId) {
|
||||
return GroupManagerV1.leaveGroup(context, groupId.requireV1());
|
||||
public static void leaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId)
|
||||
throws GroupChangeBusyException, GroupChangeFailedException, IOException
|
||||
{
|
||||
if (groupId.isV2()) {
|
||||
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||
edit.leaveGroup();
|
||||
Log.i(TAG, "Left group " + groupId);
|
||||
} catch (GroupInsufficientRightsException e) {
|
||||
Log.w(TAG, "Unexpected prevention from leaving " + groupId + " due to rights", e);
|
||||
throw new GroupChangeFailedException(e);
|
||||
} catch (GroupNotAMemberException e) {
|
||||
Log.w(TAG, "Already left group " + groupId, e);
|
||||
}
|
||||
} else {
|
||||
if (!GroupManagerV1.leaveGroup(context, groupId.requireV1())) {
|
||||
Log.w(TAG, "GV1 group leave failed" + groupId);
|
||||
throw new GroupChangeFailedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static boolean silentLeaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId) {
|
||||
if (groupId.isV2()) {
|
||||
throw new AssertionError("NYI"); // TODO [Alan] GV2 support silent leave for block and leave operations on GV2
|
||||
} else {
|
||||
return GroupManagerV1.silentLeaveGroup(context, groupId.requireV1());
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static void ejectFromGroup(@NonNull Context context, @NonNull GroupId.V2 groupId, @NonNull Recipient recipient)
|
||||
throws GroupChangeBusyException, GroupChangeFailedException, GroupInsufficientRightsException, GroupNotAMemberException, IOException
|
||||
{
|
||||
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||
edit.ejectMember(recipient.getId());
|
||||
Log.i(TAG, "Member removed from group " + groupId);
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
||||
@@ -171,10 +171,35 @@ final class GroupManagerV1 {
|
||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||
return true;
|
||||
} else {
|
||||
Log.i(TAG, "Group was already inactive. Skipping.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
static boolean silentLeaveGroup(@NonNull Context context, @NonNull GroupId.V1 groupId) {
|
||||
if (DatabaseFactory.getGroupDatabase(context).isActive(groupId)) {
|
||||
Recipient groupRecipient = Recipient.externalGroup(context, groupId);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||
Optional<OutgoingGroupUpdateMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);
|
||||
|
||||
if (threadId != -1 && leaveMessage.isPresent()) {
|
||||
ApplicationDependencies.getJobManager().add(LeaveGroupJob.create(groupRecipient));
|
||||
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
groupDatabase.setActive(groupId, false);
|
||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||
return true;
|
||||
} else {
|
||||
Log.w(TAG, "Failed to leave group.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "Group was already inactive. Skipping.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
static void updateGroupTimer(@NonNull Context context, @NonNull GroupId.V1 groupId, int expirationTime) {
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
|
||||
@@ -245,6 +245,27 @@ final class GroupManagerV2 {
|
||||
return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.getUuid().get(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@NonNull GroupManager.GroupActionResult leaveGroup()
|
||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||
{
|
||||
return ejectMember(Recipient.self().getId());
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@NonNull GroupManager.GroupActionResult ejectMember(@NonNull RecipientId recipientId)
|
||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||
{
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
GroupManager.GroupActionResult result = commitChangeWithConflictResolution(groupOperations.createRemoveMembersChange(Collections.singleton(recipient.getUuid().get())));
|
||||
|
||||
if (recipient.isLocalNumber()) {
|
||||
groupDatabase.setActive(groupId, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@Nullable GroupManager.GroupActionResult updateSelfProfileKeyInGroup()
|
||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.thoughtcrime.securesms.groups.ui;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public interface GroupChangeErrorCallback {
|
||||
void onError(@NonNull GroupChangeFailureReason failureReason);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.thoughtcrime.securesms.groups.ui;
|
||||
|
||||
public enum GroupChangeFailureReason {
|
||||
NO_RIGHTS,
|
||||
NOT_CAPABLE,
|
||||
NOT_A_MEMBER,
|
||||
OTHER
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.thoughtcrime.securesms.groups.ui;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public final class GroupErrors {
|
||||
private GroupErrors() {
|
||||
}
|
||||
|
||||
public static @StringRes int getUserDisplayMessage(@NonNull GroupChangeFailureReason failureReason) {
|
||||
switch (failureReason) {
|
||||
case NO_RIGHTS : return R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this;
|
||||
case NOT_CAPABLE : return R.string.ManageGroupActivity_not_capable;
|
||||
case NOT_A_MEMBER: return R.string.ManageGroupActivity_youre_not_a_member_of_the_group;
|
||||
default : return R.string.ManageGroupActivity_failed_to_update_the_group;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,19 @@ import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
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.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class LeaveGroupDialog {
|
||||
|
||||
private static final String TAG = Log.tag(LeaveGroupDialog.class);
|
||||
|
||||
private LeaveGroupDialog() {
|
||||
}
|
||||
|
||||
@@ -31,8 +38,16 @@ public final class LeaveGroupDialog {
|
||||
.setPositiveButton(R.string.yes, (dialog, which) ->
|
||||
SimpleTask.run(
|
||||
lifecycle,
|
||||
() -> GroupManager.leaveGroup(context, groupId),
|
||||
(success) -> {
|
||||
() -> {
|
||||
try {
|
||||
GroupManager.leaveGroup(context, groupId);
|
||||
return true;
|
||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
(success) -> {
|
||||
if (success) {
|
||||
if (onSuccess != null) onSuccess.run();
|
||||
} else {
|
||||
|
||||
@@ -3,11 +3,9 @@ package org.thoughtcrime.securesms.groups.ui.managegroup;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
||||
@@ -18,6 +16,8 @@ import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException;
|
||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
|
||||
import org.thoughtcrime.securesms.groups.MembershipNotSuitableForV2Exception;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
final class ManageGroupRepository {
|
||||
|
||||
@@ -57,47 +56,47 @@ final class ManageGroupRepository {
|
||||
return new GroupStateResult(threadId, groupRecipient);
|
||||
}
|
||||
|
||||
void setExpiration(int newExpirationTime, @NonNull Error error) {
|
||||
void setExpiration(int newExpirationTime, @NonNull GroupChangeErrorCallback error) {
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
GroupManager.updateGroupTimer(context, groupId.requirePush(), newExpirationTime);
|
||||
} catch (GroupInsufficientRightsException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.NO_RIGHTS);
|
||||
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||
} catch (GroupNotAMemberException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.NOT_A_MEMBER);
|
||||
error.onError(GroupChangeFailureReason.NOT_A_MEMBER);
|
||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.OTHER);
|
||||
error.onError(GroupChangeFailureReason.OTHER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void applyMembershipRightsChange(@NonNull GroupAccessControl newRights, @NonNull Error error) {
|
||||
void applyMembershipRightsChange(@NonNull GroupAccessControl newRights, @NonNull GroupChangeErrorCallback error) {
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
GroupManager.applyMembershipAdditionRightsChange(context, groupId.requireV2(), newRights);
|
||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.NO_RIGHTS);
|
||||
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.OTHER);
|
||||
error.onError(GroupChangeFailureReason.OTHER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void applyAttributesRightsChange(@NonNull GroupAccessControl newRights, @NonNull Error error) {
|
||||
void applyAttributesRightsChange(@NonNull GroupAccessControl newRights, @NonNull GroupChangeErrorCallback error) {
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
GroupManager.applyAttributesRightsChange(context, groupId.requireV2(), newRights);
|
||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.NO_RIGHTS);
|
||||
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.OTHER);
|
||||
error.onError(GroupChangeFailureReason.OTHER);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -115,19 +114,19 @@ final class ManageGroupRepository {
|
||||
});
|
||||
}
|
||||
|
||||
void addMembers(@NonNull List<RecipientId> selected, @NonNull Error error) {
|
||||
void addMembers(@NonNull List<RecipientId> selected, @NonNull GroupChangeErrorCallback error) {
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
GroupManager.addMembers(context, groupId, selected);
|
||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.NO_RIGHTS);
|
||||
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.OTHER);
|
||||
error.onError(GroupChangeFailureReason.OTHER);
|
||||
} catch (MembershipNotSuitableForV2Exception e) {
|
||||
Log.w(TAG, e);
|
||||
error.onError(FailureReason.NOT_CAPABLE);
|
||||
error.onError(GroupChangeFailureReason.NOT_CAPABLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -153,24 +152,4 @@ final class ManageGroupRepository {
|
||||
}
|
||||
}
|
||||
|
||||
public enum FailureReason {
|
||||
NO_RIGHTS(R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this),
|
||||
NOT_CAPABLE(R.string.ManageGroupActivity_not_capable),
|
||||
NOT_A_MEMBER(R.string.ManageGroupActivity_youre_not_a_member_of_the_group),
|
||||
OTHER(R.string.ManageGroupActivity_failed_to_update_the_group);
|
||||
|
||||
private final @StringRes int toastMessage;
|
||||
|
||||
FailureReason(@StringRes int toastMessage) {
|
||||
this.toastMessage = toastMessage;
|
||||
}
|
||||
|
||||
public @StringRes int getToastMessage() {
|
||||
return toastMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Error {
|
||||
void onError(@NonNull FailureReason failureReason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.LiveGroup;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
@@ -205,8 +207,8 @@ public class ManageGroupViewModel extends ViewModel {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void showErrorToast(@NonNull ManageGroupRepository.FailureReason e) {
|
||||
Util.runOnMain(() -> Toast.makeText(context, e.getToastMessage(), Toast.LENGTH_LONG).show());
|
||||
private void showErrorToast(@NonNull GroupChangeFailureReason e) {
|
||||
Util.runOnMain(() -> Toast.makeText(context, GroupErrors.getUserDisplayMessage(e), Toast.LENGTH_LONG).show());
|
||||
}
|
||||
|
||||
static final class GroupViewState {
|
||||
|
||||
Reference in New Issue
Block a user