From c49ea5173e5790c2dc56b3e297cda397cb566676 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 1 Mar 2022 09:30:06 +0100 Subject: [PATCH 1/4] Improve strings for threshold selector screen --- briar-android/src/main/res/values/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index c1dcd03fb..51b671713 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -653,19 +653,19 @@ - Select Trusted Contacts: + Select Trusted Contacts Please select at least %d contacts Please select at least %d more contacts Too many! Please select no more than %d contacts - Choose the minimum number of trusted contacts needed to restore your account + Set the minimum number of trusted contacts needed Two trusted contacts will be needed to restore your account Secure Secure - recommended threshold Insecure – higher threshold recommended Danger of loss – lower threshold recommended - Choose Threshold + Choose Minimum Needed %d of %d contacts needed to recover your account Social Backup created @@ -706,7 +706,7 @@ Social Backup Select Trusted Contacts - Threshold + Minimum Needed Recovery Mode Help recover account From c0932b4df1bbf14f44cec093f6fd82becdeb5b22 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 3 Mar 2022 10:47:31 +0100 Subject: [PATCH 2/4] Improve existing backup fragment --- .../socialbackup/ExistingBackupFragment.java | 86 +++++++++++++------ .../SocialBackupSetupActivity.java | 3 +- .../SocialBackupSetupViewModel.java | 61 ++++++++++--- .../ThresholdSelectorFragment.java | 1 - .../res/layout/fragment_existing_backup.xml | 22 +++-- briar-android/src/main/res/values/strings.xml | 7 +- 6 files changed, 134 insertions(+), 46 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java index 7b3cd6300..35bfe339f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java @@ -2,32 +2,37 @@ package org.briarproject.briar.android.socialbackup; import android.content.Context; import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ImageSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.identity.Author; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.contact.ContactListAdapter; +import org.briarproject.briar.android.contact.ContactListItem; +import org.briarproject.briar.android.contact.OnContactClickListener; import org.briarproject.briar.android.fragment.BaseFragment; -import org.briarproject.briar.api.socialbackup.BackupMetadata; +import org.briarproject.briar.android.view.BriarRecyclerView; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; -public class ExistingBackupFragment extends BaseFragment { +public class ExistingBackupFragment extends BaseFragment implements + OnContactClickListener { - private static final String THRESHOLD = "threshold"; - private static final String CUSTODIANS = "custodians"; public static final String TAG = ExistingBackupFragment.class.getName(); + private final ContactListAdapter adapter = new ContactListAdapter(this); + private BriarRecyclerView list; @Inject ViewModelProvider.Factory viewModelFactory; @@ -52,32 +57,42 @@ public class ExistingBackupFragment extends BaseFragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + // change toolbar text (relevant when navigating back to this fragment) + requireActivity().setTitle(R.string.social_backup_trusted_contacts); + View view = inflater.inflate(R.layout.fragment_existing_backup, container, false); - BackupMetadata backupMetadata = viewModel.getBackupMetadata(); - List custodians = backupMetadata.getCustodians(); + viewModel.loadCustodianList(); + list = view.findViewById(R.id.custodianList); + list.setLayoutManager(new LinearLayoutManager(getActivity())); + list.setAdapter(adapter); + list.setEmptyText(R.string.no_contacts); - StringBuilder custodianNamesString = new StringBuilder(); - for (Author custodian : custodians) { - custodianNamesString - .append("• ") - .append(custodian.getName()) - .append("\n"); - } + viewModel.getContactListItems().observe(getViewLifecycleOwner(), + result -> result.onError(this::handleException) + .onSuccess(adapter::submitList) + ); - TextView textViewThreshold = view.findViewById(R.id.textViewThreshold); - textViewThreshold.setText(getString(R.string.existing_backup_explain, - backupMetadata.getThreshold())); - TextView textViewCustodians = - view.findViewById(R.id.textViewCustodians); - textViewCustodians.setText(custodianNamesString); + int threshold = viewModel.getThresholdFromExistingBackup(); + int numberOfCustodians = + viewModel.getNumberOfCustodiansFromExistingBackup(); + + TextView mOfn = view.findViewById(R.id.textViewThreshold); + mOfn.setText(String.format( + getString(R.string.threshold_m_of_n), threshold, + numberOfCustodians)); + + TextView thresholdRepresentation = + view.findViewById(R.id.textViewThresholdRepresentation); + thresholdRepresentation.setText( + buildThresholdRepresentationString(threshold, + numberOfCustodians)); return view; } @Override public void onAttach(Context context) { super.onAttach(context); -// listener = (ShardsSentDismissedListener) context; } @Override @@ -85,4 +100,27 @@ public class ExistingBackupFragment extends BaseFragment { return TAG; } + @Override + public void onItemClick(View view, ContactListItem item) { + } + + private SpannableStringBuilder buildThresholdRepresentationString( + int threshold, int numberOfCustodians) { + char[] charArray = new char[numberOfCustodians]; + Arrays.fill(charArray, ' '); + SpannableStringBuilder string = + new SpannableStringBuilder(new String(charArray)); + + for (int i = 0; i < numberOfCustodians; i++) { + int drawable = i < threshold + ? R.drawable.ic_custodian_required + : R.drawable.ic_custodian_optional; + string.setSpan(new ImageSpan(getContext(), drawable), i, + i + 1, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + // If we have more than 6, split it on two lines + if (numberOfCustodians > 6) string.insert(4, "\n"); + return string; + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java index 0c616cb88..134fc0f8f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java @@ -12,6 +12,7 @@ import org.briarproject.briar.android.contactselection.ContactSelectorListener; import org.briarproject.briar.android.fragment.BaseFragment; import java.util.Collection; +import java.util.List; import javax.inject.Inject; @@ -84,7 +85,7 @@ public class SocialBackupSetupActivity extends BriarActivity implements Toast.makeText(this, String.format("Selected %d contacts", contacts.size()), Toast.LENGTH_SHORT).show(); - viewModel.setCustodians(contacts); + viewModel.setCustodians((List) contacts); ThresholdSelectorFragment fragment = ThresholdSelectorFragment.newInstance(contacts.size()); showNextFragment(fragment); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java index 1b80dfa2e..b9050d4e5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java @@ -2,29 +2,37 @@ package org.briarproject.briar.android.socialbackup; import android.app.Application; +import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.briar.android.contact.ContactsViewModel; +import org.briarproject.briar.api.conversation.ConversationManager; +import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.socialbackup.BackupMetadata; import org.briarproject.briar.api.socialbackup.SocialBackupManager; -import java.util.Collection; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; import javax.inject.Inject; import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.MutableLiveData; -public class SocialBackupSetupViewModel extends AndroidViewModel { +public class SocialBackupSetupViewModel extends ContactsViewModel { private final SocialBackupManager socialBackupManager; private final DatabaseComponent db; private final ContactManager contactManager; private BackupMetadata backupMetadata; - private Collection custodians; + private List custodians; private int threshold; @@ -38,20 +46,39 @@ public class SocialBackupSetupViewModel extends AndroidViewModel { private final MutableLiveData state = new MutableLiveData<>(); - @Inject public SocialBackupSetupViewModel( @NonNull Application app, DatabaseComponent db, + @DatabaseExecutor Executor dbExecutor, + LifecycleManager lifecycleManager, + AuthorManager authorManager, + ConversationManager conversationManager, + ConnectionRegistry connectionRegistry, + EventBus eventBus, + AndroidExecutor androidExecutor, SocialBackupManager socialBackupManager, ContactManager contactManager ) { - super(app); + super(app, dbExecutor, lifecycleManager, db, androidExecutor, + contactManager, authorManager, conversationManager, + connectionRegistry, eventBus); + this.socialBackupManager = socialBackupManager; this.db = db; this.contactManager = contactManager; } + public void loadCustodianList() { + try { + custodians = db.transactionWithResult(true, + socialBackupManager::getCustodianContactIds); + } catch (DbException e) { + custodians = new ArrayList<>(); + } + loadContacts(); + } + public boolean haveExistingBackup() { try { backupMetadata = db.transactionWithNullableResult(true, @@ -62,15 +89,15 @@ public class SocialBackupSetupViewModel extends AndroidViewModel { return (backupMetadata != null); } - public BackupMetadata getBackupMetadata() { - return backupMetadata; - } +// public BackupMetadata getBackupMetadata() { +// return backupMetadata; +// } public boolean haveEnoughContacts() throws DbException { return (contactManager.getContacts().size() > 1); } - public void setCustodians(Collection contacts) { + public void setCustodians(List contacts) { custodians = contacts; } @@ -102,5 +129,19 @@ public class SocialBackupSetupViewModel extends AndroidViewModel { public void onExplainerDismissed() { state.postValue(State.CHOOSING_CUSTODIANS); } + + @Override + protected boolean displayContact(ContactId contactId) { + // Check if contact holds a backup piece + return custodians.contains(contactId); + } + + public int getThresholdFromExistingBackup() { + return backupMetadata.getThreshold(); + } + + public int getNumberOfCustodiansFromExistingBackup() { + return backupMetadata.getCustodians().size(); + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java index b61126d8a..c124c8227 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java @@ -123,7 +123,6 @@ public class ThresholdSelectorFragment extends BaseFragment { super.onAttach(context); } - @Override public String getUniqueTag() { return TAG; diff --git a/briar-android/src/main/res/layout/fragment_existing_backup.xml b/briar-android/src/main/res/layout/fragment_existing_backup.xml index 4b4c79e81..6fc28568a 100644 --- a/briar-android/src/main/res/layout/fragment_existing_backup.xml +++ b/briar-android/src/main/res/layout/fragment_existing_backup.xml @@ -11,25 +11,35 @@ android:paddingBottom="@dimen/margin_medium" android:layout_height="match_parent"> + + app:layout_constraintTop_toBottomOf="@+id/textViewThresholdRepresentation" /> + + + \ No newline at end of file diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 51b671713..d9d74fad8 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -719,10 +719,6 @@ Create new account Restore account from backup - - \u25CF - \u25CB - Social Backup Restore Account @@ -738,4 +734,7 @@ To make a social backup, you need at least 2 contacts in your contacts list There was an error reading your contacts list + + + Trusted Contacts From b7bdad4b67d1f50d4eed0f27b5aa039c2a4c66ef Mon Sep 17 00:00:00 2001 From: ameba23 Date: Thu, 3 Mar 2022 10:48:23 +0100 Subject: [PATCH 3/4] Add method to get contact ids of existing custodians --- .../api/socialbackup/SocialBackupManager.java | 7 +++++ .../socialbackup/SocialBackupManagerImpl.java | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackupManager.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackupManager.java index f8f4522ac..d3fa8e486 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackupManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackupManager.java @@ -78,4 +78,11 @@ public interface SocialBackupManager extends */ byte[] getReturnShardPayloadBytes(Transaction txn, ContactId contactId) throws DbException; + + + /** + * Get a list of the contact ids of your custodians, or an empty + * list if no backup exists. + */ + List getCustodianContactIds(Transaction txn); } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java index 530542d00..60b4cab03 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java @@ -612,4 +612,30 @@ class SocialBackupManagerImpl extends ConversationClientImpl results.entrySet().iterator().next(); return new Pair<>(e.getKey(), e.getValue()); } + + public List getCustodianContactIds(Transaction txn) { + ArrayList contactIds = new ArrayList<>(); + try { + BackupMetadata b = getBackupMetadata(txn); + if (b == null) throw new DbException(); + List custodians = b.getCustodians(); + for (Author custodian : custodians) { + contactIds.add(authorToContactId(txn, custodian)); + } + } catch (DbException ignored) { + // Will return an empty list + } + return contactIds; + } + + private ContactId authorToContactId(Transaction txn, Author author) + throws DbException { + ArrayList contacts = + (ArrayList) contactManager.getContacts(txn); + for (Contact c : contacts) { + if (c.getAuthor().equals(author)) return c.getId(); + } + throw new DbException(); + } + } From 7df10d9324fdd76da41d3451232b8d4acd0c34e2 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 4 Mar 2022 10:09:57 +0100 Subject: [PATCH 4/4] Improve existing backup fragment --- .../briar/android/socialbackup/ExistingBackupFragment.java | 5 ++--- .../src/main/res/layout/fragment_existing_backup.xml | 1 - briar-android/src/main/res/values/strings.xml | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java index 35bfe339f..7962f04d1 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java @@ -58,7 +58,7 @@ public class ExistingBackupFragment extends BaseFragment implements public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // change toolbar text (relevant when navigating back to this fragment) - requireActivity().setTitle(R.string.social_backup_trusted_contacts); +// requireActivity().setTitle(R.string.social_backup_trusted_contacts); View view = inflater.inflate(R.layout.fragment_existing_backup, container, false); @@ -79,8 +79,7 @@ public class ExistingBackupFragment extends BaseFragment implements TextView mOfn = view.findViewById(R.id.textViewThreshold); mOfn.setText(String.format( - getString(R.string.threshold_m_of_n), threshold, - numberOfCustodians)); + getString(R.string.existing_backup_explain), threshold)); TextView thresholdRepresentation = view.findViewById(R.id.textViewThresholdRepresentation); diff --git a/briar-android/src/main/res/layout/fragment_existing_backup.xml b/briar-android/src/main/res/layout/fragment_existing_backup.xml index 6fc28568a..68efc37eb 100644 --- a/briar-android/src/main/res/layout/fragment_existing_backup.xml +++ b/briar-android/src/main/res/layout/fragment_existing_backup.xml @@ -1,7 +1,6 @@ Create new account or recover existing account Recover Account Help recover account - %d of the following contacts are needed to restore your account: + Any %d of the following contacts are needed to restore your Briar account, should you lose access to it. To make a social backup, you need at least 2 contacts in your contacts list There was an error reading your contacts list