Remote Contact Adding: Rename methods and add more exception handling

This commit is contained in:
Torsten Grote
2019-05-01 10:58:31 -03:00
parent 2c014b4e46
commit bec1f117ba
10 changed files with 107 additions and 55 deletions

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.contact; package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
@@ -60,16 +61,16 @@ public interface ContactManager {
/** /**
* Returns the static link that needs to be sent to the contact to be added. * Returns the static link that needs to be sent to the contact to be added.
*/ */
String getRemoteContactLink() throws DbException; String getHandshakeLink() throws DbException;
/** /**
* Requests a new contact to be added via the given {@code link}. * Requests a new contact to be added via the given {@code link}.
* *
* @param link The link received from the contact we want to add. * @param link The link received from the contact we want to add.
* @param alias The alias the user has given this contact. * @param alias The alias the user has given this contact.
* @return A PendingContact representing the contact to be added.
*/ */
void addRemoteContactRequest(String link, String alias); void addPendingContact(String link, String alias)
throws DbException, FormatException;
/** /**
* Returns a list of {@link PendingContact}s. * Returns a list of {@link PendingContact}s.
@@ -81,7 +82,7 @@ public interface ContactManager {
* {@link PendingContactState FAILED}. * {@link PendingContactState FAILED}.
* @param commitAction an action to run on the main thread after removing. * @param commitAction an action to run on the main thread after removing.
*/ */
void removePendingContact(PendingContact pendingContact, void removePendingContact(PendingContactId pendingContact,
Runnable commitAction) throws DbException; Runnable commitAction) throws DbException;
/** /**

View File

@@ -116,7 +116,7 @@ class ContactManagerImpl implements ContactManager {
} }
@Override @Override
public String getRemoteContactLink() { public String getHandshakeLink() {
// TODO replace with real implementation // TODO replace with real implementation
try { try {
Thread.sleep(1500); Thread.sleep(1500);
@@ -139,27 +139,23 @@ class ContactManagerImpl implements ContactManager {
} }
@Override @Override
public void addRemoteContactRequest(String link, String alias) { public void addPendingContact(String link, String alias)
throws DbException {
// TODO replace with real implementation // TODO replace with real implementation
try {
Thread.sleep(1500);
} catch (InterruptedException ignored) {
}
PendingContactId id = new PendingContactId( PendingContactId id = new PendingContactId(
link.substring(0, PendingContactId.LENGTH).getBytes()); link.substring(0, PendingContactId.LENGTH).getBytes());
PendingContact pendingContact = PendingContact pendingContact =
new PendingContact(id, new byte[MAX_PUBLIC_KEY_LENGTH], new PendingContact(id, new byte[MAX_PUBLIC_KEY_LENGTH],
alias, WAITING_FOR_CONNECTION, currentTimeMillis()); alias, WAITING_FOR_CONNECTION, currentTimeMillis());
dbExecutor.execute(() -> { getLogger("TMP").warning("WAITING_FOR_CONNECTION");
try { pendingContacts.add(pendingContact);
Thread.sleep(1500); Event event = new PendingContactStateChangedEvent(id,
} catch (InterruptedException ignored) { WAITING_FOR_CONNECTION);
} db.transaction(true, txn -> txn.attach(event));
try {
getLogger("TMP").warning("WAITING_FOR_CONNECTION");
pendingContacts.add(pendingContact);
Event e = new PendingContactStateChangedEvent(id,
WAITING_FOR_CONNECTION);
db.transaction(true, txn -> txn.attach(e));
} catch (DbException ignored) {
}
});
scheduler.schedule(() -> dbExecutor.execute(() -> { scheduler.schedule(() -> dbExecutor.execute(() -> {
getLogger("TMP").warning("CONNECTED"); getLogger("TMP").warning("CONNECTED");
@@ -222,10 +218,15 @@ class ContactManagerImpl implements ContactManager {
} }
@Override @Override
public void removePendingContact(PendingContact pendingContact, public void removePendingContact(PendingContactId id,
Runnable commitAction) throws DbException { Runnable commitAction) throws DbException {
// TODO replace with real implementation // TODO replace with real implementation
pendingContacts.remove(pendingContact); for (PendingContact pc : pendingContacts) {
if (pc.getId().equals(id)) {
pendingContacts.remove(pc);
break;
}
}
try { try {
Thread.sleep(250); Thread.sleep(250);
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {

View File

@@ -63,7 +63,7 @@ public class AddContactActivity extends BriarActivity implements
String text = i.getStringExtra(EXTRA_TEXT); String text = i.getStringExtra(EXTRA_TEXT);
if (text != null) { if (text != null) {
if (viewModel.isValidRemoteContactLink(text)) { if (viewModel.isValidRemoteContactLink(text)) {
viewModel.setRemoteContactLink(text); viewModel.setRemoteHandshakeLink(text);
} else { } else {
Toast.makeText(this, R.string.invalid_link, LENGTH_LONG) Toast.makeText(this, R.string.invalid_link, LENGTH_LONG)
.show(); .show();
@@ -72,7 +72,7 @@ public class AddContactActivity extends BriarActivity implements
String uri = i.getDataString(); String uri = i.getDataString();
if (uri != null) { if (uri != null) {
if (viewModel.isValidRemoteContactLink(uri)) { if (viewModel.isValidRemoteContactLink(uri)) {
viewModel.setRemoteContactLink(uri); viewModel.setRemoteHandshakeLink(uri);
} else { } else {
Toast.makeText(this, R.string.invalid_link, LENGTH_LONG) Toast.makeText(this, R.string.invalid_link, LENGTH_LONG)
.show(); .show();

View File

@@ -7,6 +7,7 @@ import android.arch.lifecycle.MutableLiveData;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
@@ -32,11 +33,14 @@ public class AddContactViewModel extends AndroidViewModel {
@DatabaseExecutor @DatabaseExecutor
private final Executor dbExecutor; private final Executor dbExecutor;
private final MutableLiveData<String> ourLink = new MutableLiveData<>(); private final MutableLiveData<String> handshakeLink =
new MutableLiveData<>();
private final MutableLiveData<Boolean> remoteLinkEntered = private final MutableLiveData<Boolean> remoteLinkEntered =
new MutableLiveData<>(); new MutableLiveData<>();
private final MutableLiveData<Boolean> addContactResult =
new MutableLiveData<>();
@Nullable @Nullable
private String remoteContactLink; private String remoteHandshakeLink;
@Inject @Inject
public AddContactViewModel(@NonNull Application application, public AddContactViewModel(@NonNull Application application,
@@ -45,13 +49,13 @@ public class AddContactViewModel extends AndroidViewModel {
super(application); super(application);
this.contactManager = contactManager; this.contactManager = contactManager;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
loadOurLink(); loadHandshakeLink();
} }
private void loadOurLink() { private void loadHandshakeLink() {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
ourLink.postValue(contactManager.getRemoteContactLink()); handshakeLink.postValue(contactManager.getHandshakeLink());
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
// the UI should stay disable in this case, // the UI should stay disable in this case,
@@ -60,12 +64,12 @@ public class AddContactViewModel extends AndroidViewModel {
}); });
} }
LiveData<String> getOurLink() { LiveData<String> getHandshakeLink() {
return ourLink; return handshakeLink;
} }
void setRemoteContactLink(String link) { void setRemoteHandshakeLink(String link) {
remoteContactLink = link; remoteHandshakeLink = link;
} }
boolean isValidRemoteContactLink(@Nullable CharSequence link) { boolean isValidRemoteContactLink(@Nullable CharSequence link) {
@@ -77,14 +81,26 @@ public class AddContactViewModel extends AndroidViewModel {
} }
void onRemoteLinkEntered() { void onRemoteLinkEntered() {
if (remoteContactLink == null) throw new IllegalStateException(); if (remoteHandshakeLink == null) throw new IllegalStateException();
remoteLinkEntered.setValue(true); remoteLinkEntered.setValue(true);
remoteLinkEntered.postValue(false); // reset, so we can navigate back remoteLinkEntered.postValue(false); // reset, so we can navigate back
} }
void addContact(String nickname) { void addContact(String nickname) {
if (remoteContactLink == null) throw new IllegalStateException(); if (remoteHandshakeLink == null) throw new IllegalStateException();
contactManager.addRemoteContactRequest(remoteContactLink, nickname); dbExecutor.execute(() -> {
try {
contactManager.addPendingContact(remoteHandshakeLink, nickname);
addContactResult.postValue(true);
} catch (DbException | FormatException e) {
logException(LOG, WARNING, e);
addContactResult.postValue(false);
}
});
}
public LiveData<Boolean> getAddContactResult() {
return addContactResult;
} }
} }

View File

@@ -83,12 +83,13 @@ public class LinkExchangeFragment extends BaseFragment {
linkInput.setText(clipData.getItemAt(0).getText()); linkInput.setText(clipData.getItemAt(0).getText());
}); });
observeOnce(viewModel.getOurLink(), this, this::onOwnLinkLoaded); observeOnce(viewModel.getHandshakeLink(), this,
this::onHandshakeLinkLoaded);
return v; return v;
} }
private void onOwnLinkLoaded(String link) { private void onHandshakeLinkLoaded(String link) {
View v = requireNonNull(getView()); View v = requireNonNull(getView());
TextView linkView = v.findViewById(R.id.linkView); TextView linkView = v.findViewById(R.id.linkView);
@@ -118,10 +119,10 @@ public class LinkExchangeFragment extends BaseFragment {
} }
/** /**
* Requires {@link AddContactViewModel#getOurLink()} to be loaded. * Requires {@link AddContactViewModel#getHandshakeLink()} to be loaded.
*/ */
@Nullable @Nullable
private String getEnteredLinkOrNull() { private String getRemoteHandshakeLinkOrNull() {
CharSequence link = linkInput.getText(); CharSequence link = linkInput.getText();
if (link == null || link.length() == 0) { if (link == null || link.length() == 0) {
linkInputLayout.setError(getString(R.string.missing_link)); linkInputLayout.setError(getString(R.string.missing_link));
@@ -135,7 +136,7 @@ public class LinkExchangeFragment extends BaseFragment {
// Check also if this is our own link. This was loaded already, // Check also if this is our own link. This was loaded already,
// because it enables the Continue button which is the only caller. // because it enables the Continue button which is the only caller.
if (("briar://" + linkWithoutSchema) if (("briar://" + linkWithoutSchema)
.equals(viewModel.getOurLink().getValue())) { .equals(viewModel.getHandshakeLink().getValue())) {
linkInputLayout.setError(getString(R.string.own_link_error)); linkInputLayout.setError(getString(R.string.own_link_error));
linkInput.requestFocus(); linkInput.requestFocus();
return null; return null;
@@ -149,10 +150,10 @@ public class LinkExchangeFragment extends BaseFragment {
} }
private void onContinueButtonClicked() { private void onContinueButtonClicked() {
String link = getEnteredLinkOrNull(); String link = getRemoteHandshakeLinkOrNull();
if (link == null) return; // invalid link if (link == null) return; // invalid link
viewModel.setRemoteContactLink(link); viewModel.setRemoteHandshakeLink(link);
viewModel.onRemoteLinkEntered(); viewModel.onRemoteLinkEntered();
} }

View File

@@ -11,6 +11,8 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -21,6 +23,9 @@ import org.briarproject.briar.android.fragment.BaseFragment;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_LONG;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong; import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong;
@@ -37,6 +42,8 @@ public class NicknameFragment extends BaseFragment {
private TextInputLayout contactNameLayout; private TextInputLayout contactNameLayout;
private TextInputEditText contactNameInput; private TextInputEditText contactNameInput;
private Button addButton;
private ProgressBar progressBar;
@Override @Override
public String getUniqueTag() { public String getUniqueTag() {
@@ -61,12 +68,14 @@ public class NicknameFragment extends BaseFragment {
viewModel = ViewModelProviders.of(getActivity(), viewModelFactory) viewModel = ViewModelProviders.of(getActivity(), viewModelFactory)
.get(AddContactViewModel.class); .get(AddContactViewModel.class);
Button addButton = v.findViewById(R.id.addButton);
addButton.setOnClickListener(view -> onAddButtonClicked());
contactNameLayout = v.findViewById(R.id.contactNameLayout); contactNameLayout = v.findViewById(R.id.contactNameLayout);
contactNameInput = v.findViewById(R.id.contactNameInput); contactNameInput = v.findViewById(R.id.contactNameInput);
addButton = v.findViewById(R.id.addButton);
addButton.setOnClickListener(view -> onAddButtonClicked());
progressBar = v.findViewById(R.id.progressBar);
return v; return v;
} }
@@ -91,12 +100,22 @@ public class NicknameFragment extends BaseFragment {
String name = getNicknameOrNull(); String name = getNicknameOrNull();
if (name == null) return; // invalid nickname if (name == null) return; // invalid nickname
viewModel.addContact(name); addButton.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE);
Intent intent = viewModel.getAddContactResult().observe(this, success -> {
new Intent(getActivity(), PendingContactListActivity.class); if (success == null) return;
startActivity(intent); if (success) {
finish(); Intent intent = new Intent(getActivity(),
PendingContactListActivity.class);
startActivity(intent);
} else {
Toast.makeText(getContext(), R.string.adding_contact_error,
LENGTH_LONG).show();
}
finish();
});
viewModel.addContact(name);
} }
} }

View File

@@ -86,7 +86,7 @@ public class PendingContactListActivity extends BriarActivity
@Override @Override
public void onFailedPendingContactRemoved(PendingContact pendingContact) { public void onFailedPendingContactRemoved(PendingContact pendingContact) {
viewModel.removePendingContact(pendingContact, viewModel.removePendingContact(pendingContact.getId(),
() -> adapter.remove(pendingContact)); () -> adapter.remove(pendingContact));
} }

View File

@@ -7,6 +7,7 @@ import android.arch.lifecycle.MutableLiveData;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent; import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent; import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
@@ -81,12 +82,11 @@ public class PendingContactListViewModel extends AndroidViewModel
return pendingContacts; return pendingContacts;
} }
void removePendingContact(PendingContact pendingContact, void removePendingContact(PendingContactId id, Runnable commitAction) {
Runnable commitAction) {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
contactManager contactManager
.removePendingContact(pendingContact, commitAction); .removePendingContact(id, commitAction);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }

View File

@@ -145,6 +145,19 @@
app:layout_constraintTop_toBottomOf="@+id/contactNameLayout" app:layout_constraintTop_toBottomOf="@+id/contactNameLayout"
app:layout_constraintVertical_bias="1.0"/> app:layout_constraintVertical_bias="1.0"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/contactNameLayout"
app:layout_constraintVertical_bias="1.0"/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</ScrollView> </ScrollView>

View File

@@ -188,6 +188,7 @@
<string name="your_link">Give this link to the contact you want to add</string> <string name="your_link">Give this link to the contact you want to add</string>
<string name="link_clip_label">Briar link</string> <string name="link_clip_label">Briar link</string>
<string name="link_copied_toast">Link copied</string> <string name="link_copied_toast">Link copied</string>
<string name="adding_contact_error">There was an error adding the contact.</string>
<string name="pending_contact_requests_snackbar">There are pending contact requests</string> <string name="pending_contact_requests_snackbar">There are pending contact requests</string>
<string name="pending_contact_requests">Pending Contact Requests</string> <string name="pending_contact_requests">Pending Contact Requests</string>
<string name="no_pending_contacts">No pending contacts</string> <string name="no_pending_contacts">No pending contacts</string>