diff --git a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java
index 5473114ee..b6e994231 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/keyagreement/KeyAgreementTaskImpl.java
@@ -102,6 +102,7 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
KeyAgreementTransport transport =
connector.connect(remotePayload, alice);
if (transport == null) {
+ LOG.warning("Key agreement failed. Transport was null.");
// Notify caller that the connection failed
eventBus.broadcast(new KeyAgreementFailedEvent());
return;
diff --git a/briar-android/artwork/qr_code_error.svg b/briar-android/artwork/qr_code_error.svg
new file mode 100644
index 000000000..cfd12461e
--- /dev/null
+++ b/briar-android/artwork/qr_code_error.svg
@@ -0,0 +1,52 @@
+
+
\ No newline at end of file
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
index 8a8abb9f8..c327d64ae 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
@@ -27,6 +27,7 @@ import org.briarproject.briar.android.introduction.ContactChooserFragment;
import org.briarproject.briar.android.introduction.IntroductionActivity;
import org.briarproject.briar.android.introduction.IntroductionMessageFragment;
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
+import org.briarproject.briar.android.keyagreement.ContactExchangeErrorFragment;
import org.briarproject.briar.android.keyagreement.IntroFragment;
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment;
@@ -208,4 +209,6 @@ public interface ActivityComponent {
void inject(SettingsFragment fragment);
void inject(ScreenFilterDialogFragment fragment);
+
+ void inject(ContactExchangeErrorFragment fragment);
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java
index e053c50c1..b6acf79c1 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java
@@ -14,7 +14,6 @@ import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
-import org.briarproject.briar.R.string;
import org.briarproject.briar.android.activity.ActivityComponent;
import java.util.logging.Logger;
@@ -48,7 +47,7 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
@Override
public void onCreate(@Nullable Bundle state) {
super.onCreate(state);
- getSupportActionBar().setTitle(string.add_contact_title);
+ getSupportActionBar().setTitle(R.string.add_contact_title);
}
private void startContactExchange(KeyAgreementResult result) {
@@ -75,7 +74,7 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
public void contactExchangeSucceeded(Author remoteAuthor) {
runOnUiThreadUnlessDestroyed(() -> {
String contactName = remoteAuthor.getName();
- String format = getString(string.contact_added_toast);
+ String format = getString(R.string.contact_added_toast);
String text = String.format(format, contactName);
Toast.makeText(ContactExchangeActivity.this, text, LENGTH_LONG)
.show();
@@ -87,7 +86,7 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
public void duplicateContact(Author remoteAuthor) {
runOnUiThreadUnlessDestroyed(() -> {
String contactName = remoteAuthor.getName();
- String format = getString(string.contact_already_exists);
+ String format = getString(R.string.contact_already_exists);
String text = String.format(format, contactName);
Toast.makeText(ContactExchangeActivity.this, text, LENGTH_LONG)
.show();
@@ -98,18 +97,14 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
@Override
public void contactExchangeFailed() {
runOnUiThreadUnlessDestroyed(() -> {
- Toast.makeText(ContactExchangeActivity.this,
- string.contact_exchange_failed, LENGTH_LONG).show();
- finish();
+ showErrorFragment(R.string.connection_error_explanation);
});
}
@UiThread
@Override
public void keyAgreementFailed() {
- // TODO show failure somewhere persistent?
- Toast.makeText(this, R.string.connection_failed,
- LENGTH_LONG).show();
+ showErrorFragment(R.string.connection_error_explanation);
}
@UiThread
@@ -126,19 +121,14 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
@UiThread
@Override
- public String keyAgreementAborted(boolean remoteAborted) {
- // TODO show abort somewhere persistent?
- Toast.makeText(this,
- remoteAborted ? R.string.connection_aborted_remote :
- R.string.connection_aborted_local, LENGTH_LONG)
- .show();
- return null;
+ public void keyAgreementAborted(boolean remoteAborted) {
+ showErrorFragment(R.string.connection_error_explanation);
}
@UiThread
@Override
public String keyAgreementFinished(KeyAgreementResult result) {
startContactExchange(result);
- return getString(string.exchanging_contact_details);
+ return getString(R.string.exchanging_contact_details);
}
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java
new file mode 100644
index 000000000..447ec63a3
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java
@@ -0,0 +1,87 @@
+package org.briarproject.briar.android.keyagreement;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.bramble.api.system.AndroidExecutor;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.fragment.BaseFragment;
+import org.briarproject.briar.android.util.UiUtils;
+
+import javax.inject.Inject;
+
+import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class ContactExchangeErrorFragment extends BaseFragment {
+
+ public static final String TAG =
+ ContactExchangeErrorFragment.class.getName();
+ private static final String ERROR_MSG = "errorMessage";
+
+ public static ContactExchangeErrorFragment newInstance(String errorMsg) {
+ ContactExchangeErrorFragment f = new ContactExchangeErrorFragment();
+ Bundle args = new Bundle();
+ args.putString(ERROR_MSG, errorMsg);
+ f.setArguments(args);
+ return f;
+ }
+
+ @Inject
+ AndroidExecutor androidExecutor;
+
+ @Override
+ public String getUniqueTag() {
+ return TAG;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_error_contact_exchange,
+ container, false);
+
+ // set humanized error message
+ TextView explanation = v.findViewById(R.id.errorMessage);
+ Bundle args = getArguments();
+ if (args == null) {
+ throw new IllegalArgumentException("Use newInstance()");
+ }
+ explanation.setText(args.getString(ERROR_MSG));
+
+ // make feedback link clickable
+ TextView sendFeedback = v.findViewById(R.id.sendFeedback);
+ onSingleLinkClick(sendFeedback, this::triggerFeedback);
+
+ // buttons
+ Button tryAgain = v.findViewById(R.id.tryAgainButton);
+ tryAgain.setOnClickListener(view -> {
+ if (getActivity() != null) getActivity().onBackPressed();
+ });
+ Button cancel = v.findViewById(R.id.cancelButton);
+ cancel.setOnClickListener(view -> finish());
+ return v;
+ }
+
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ private void triggerFeedback() {
+ finish();
+ UiUtils.triggerFeedback(androidExecutor);
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java
index 189ca1771..d74c3e248 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java
@@ -7,6 +7,7 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
@@ -28,6 +29,7 @@ import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.keyagreement.IntroFragment.IntroScreenSeenListener;
+import org.briarproject.briar.android.keyagreement.KeyAgreementFragment.KeyAgreementEventListener;
import org.briarproject.briar.android.util.UiUtils;
import java.util.logging.Logger;
@@ -50,7 +52,7 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMI
@ParametersNotNullByDefault
public abstract class KeyAgreementActivity extends BriarActivity implements
BaseFragmentListener, IntroScreenSeenListener,
- KeyAgreementFragment.KeyAgreementEventListener {
+ KeyAgreementEventListener {
private enum BluetoothState {
UNKNOWN, NO_ADAPTER, WAITING, REFUSED, ENABLED
@@ -185,6 +187,12 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
}
}
+ protected void showErrorFragment(@StringRes int errorResId) {
+ String errorMsg = getString(errorResId);
+ BaseFragment f = ContactExchangeErrorFragment.newInstance(errorMsg);
+ showNextFragment(f);
+ }
+
private boolean checkPermissions() {
if (ContextCompat.checkSelfPermission(this, CAMERA) !=
PERMISSION_GRANTED) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementFragment.java
index 2d35510de..86831fdab 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementFragment.java
@@ -36,7 +36,6 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseEventFragment;
-import org.briarproject.briar.android.fragment.ErrorFragment;
import org.briarproject.briar.android.view.QrCodeView;
import java.io.IOException;
@@ -247,7 +246,7 @@ public class KeyAgreementFragment extends BaseEventFragment
reset();
String msg = getString(R.string.qr_code_unsupported,
getString(R.string.app_name));
- showNextFragment(ErrorFragment.newInstance(msg));
+ showNextFragment(ContactExchangeErrorFragment.newInstance(msg));
} catch (CameraException e) {
logCameraExceptionAndFinish(e);
} catch (IOException | IllegalArgumentException e) {
@@ -301,9 +300,7 @@ public class KeyAgreementFragment extends BaseEventFragment
private void keyAgreementAborted(boolean remoteAborted) {
runOnUiThreadUnlessDestroyed(() -> {
reset();
- qrCodeView.setVisibility(VISIBLE);
- statusView.setVisibility(INVISIBLE);
- status.setText(listener.keyAgreementAborted(remoteAborted));
+ listener.keyAgreementAborted(remoteAborted);
});
}
@@ -362,10 +359,9 @@ public class KeyAgreementFragment extends BaseEventFragment
@Nullable
String keyAgreementStarted();
- // Should return a string to be displayed as status.
+ // Will show an error fragment.
@UiThread
- @Nullable
- String keyAgreementAborted(boolean remoteAborted);
+ void keyAgreementAborted(boolean remoteAborted);
// Should return a string to be displayed as status.
@UiThread
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
index 8ab4208ca..8337194f7 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
@@ -23,7 +23,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
-import org.acra.ACRA;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
@@ -43,7 +42,6 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.Localizer;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.util.UiUtils;
-import org.briarproject.briar.android.util.UserFeedback;
import java.util.ArrayList;
import java.util.List;
@@ -86,6 +84,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE;
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT;
import static org.briarproject.briar.android.util.UiUtils.hasScreenLock;
+import static org.briarproject.briar.android.util.UiUtils.triggerFeedback;
import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_CHANNEL_ID;
@@ -219,7 +218,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
findPreference("pref_key_send_feedback").setOnPreferenceClickListener(
preference -> {
- triggerFeedback();
+ triggerFeedback(androidExecutor);
return true;
});
@@ -517,11 +516,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
return true;
}
- private void triggerFeedback() {
- androidExecutor.runOnBackgroundThread(() -> ACRA.getErrorReporter()
- .handleException(new UserFeedback(), false));
- }
-
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == language) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
index 60c6db311..7fb316a62 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
@@ -21,6 +21,7 @@ import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.format.DateUtils;
+import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.URLSpan;
@@ -28,9 +29,11 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
+import org.acra.ACRA;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.view.ArticleMovementMethod;
import org.briarproject.briar.android.widget.LinkDialogFragment;
@@ -147,6 +150,32 @@ public class UiUtils {
v.setMovementMethod(ArticleMovementMethod.getInstance());
}
+ /**
+ * Executes the runnable when clicking the link in the textView's text.
+ *
+ * Attention: This assumes that there's only one link in the text.
+ */
+ public static void onSingleLinkClick(TextView textView, Runnable runnable) {
+ SpannableStringBuilder ssb =
+ new SpannableStringBuilder(textView.getText());
+ ClickableSpan[] spans =
+ ssb.getSpans(0, ssb.length(), ClickableSpan.class);
+ if (spans.length != 1) throw new AssertionError();
+ ClickableSpan span = spans[0];
+ int start = ssb.getSpanStart(span);
+ int end = ssb.getSpanEnd(span);
+ ssb.removeSpan(span);
+ ClickableSpan cSpan = new ClickableSpan() {
+ @Override
+ public void onClick(View v) {
+ runnable.run();
+ }
+ };
+ ssb.setSpan(cSpan, start + 1, end, 0);
+ textView.setText(ssb);
+ textView.setMovementMethod(new LinkMovementMethod());
+ }
+
public static String getAvatarTransitionName(ContactId c) {
return "avatar" + c.getInt();
}
@@ -242,4 +271,10 @@ public class UiUtils {
(SDK_INT >= 23 && keyguardManager.isDeviceSecure());
}
+ public static void triggerFeedback(AndroidExecutor androidExecutor) {
+ androidExecutor.runOnBackgroundThread(
+ () -> ACRA.getErrorReporter()
+ .handleException(new UserFeedback(), false));
+ }
+
}
diff --git a/briar-android/src/main/res/drawable/qr_code_error.xml b/briar-android/src/main/res/drawable/qr_code_error.xml
new file mode 100644
index 000000000..f866e6389
--- /dev/null
+++ b/briar-android/src/main/res/drawable/qr_code_error.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/briar-android/src/main/res/layout/fragment_error_contact_exchange.xml b/briar-android/src/main/res/layout/fragment_error_contact_exchange.xml
new file mode 100644
index 000000000..48a563ca1
--- /dev/null
+++ b/briar-android/src/main/res/layout/fragment_error_contact_exchange.xml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 3b92a01ca..bdc04d792 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -135,20 +135,19 @@
Add a Contact
You must meet up with the person you want to add as a contact.\n\nThis will prevent anyone from impersonating you or reading your messages in future.
Continue
- Connection failed
Try Again
Waiting for contact to scan and connect\u2026
Exchanging contact details\u2026
Contact added: %s
Contact %s already exists
- Contact exchange failed
The QR code is invalid
The QR code you are trying to scan belongs to an old version of %s which is no longer supported.\n\nPlease ensure that both of you are running the latest version and then try again.
Camera error
Connecting to device\u2026
Authenticating with device\u2026
- Connection aborted! This could mean that someone is trying to interfere with your connection
- Connection aborted by your contact! This could mean that someone is trying to interfere with your connection
+ Could not connect to your contact
+ Please check that you\'re both connected to the same Wi-Fi network.
+ If this problem persists, please send feedback to help us improve the app.
Introduce your contacts