mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Merge branch '2403-show-progress-while-connecting-to-mailbox' into 'master'
Show progress while connecting to mailbox Closes #2403 See merge request briar/briar!1747
This commit is contained in:
@@ -2,10 +2,27 @@ package org.briarproject.bramble.api.mailbox;
|
|||||||
|
|
||||||
public abstract class MailboxPairingState {
|
public abstract class MailboxPairingState {
|
||||||
|
|
||||||
public static class QrCodeReceived extends MailboxPairingState {
|
public abstract static class Pending extends MailboxPairingState {
|
||||||
|
|
||||||
|
public final long timeStarted;
|
||||||
|
|
||||||
|
private Pending(long timeStarted) {
|
||||||
|
this.timeStarted = timeStarted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Pairing extends MailboxPairingState {
|
public static class QrCodeReceived extends Pending {
|
||||||
|
|
||||||
|
public QrCodeReceived(long timeStarted) {
|
||||||
|
super(timeStarted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Pairing extends Pending {
|
||||||
|
|
||||||
|
public Pairing(long timeStarted) {
|
||||||
|
super(timeStarted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Paired extends MailboxPairingState {
|
public static class Paired extends MailboxPairingState {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
private final MailboxApi api;
|
private final MailboxApi api;
|
||||||
private final MailboxSettingsManager mailboxSettingsManager;
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
private final MailboxUpdateManager mailboxUpdateManager;
|
private final MailboxUpdateManager mailboxUpdateManager;
|
||||||
|
private final long timeStarted;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
@@ -77,7 +78,8 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
this.api = api;
|
this.api = api;
|
||||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
this.mailboxUpdateManager = mailboxUpdateManager;
|
this.mailboxUpdateManager = mailboxUpdateManager;
|
||||||
state = new MailboxPairingState.QrCodeReceived();
|
timeStarted = clock.currentTimeMillis();
|
||||||
|
state = new MailboxPairingState.QrCodeReceived(timeStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -114,7 +116,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
|
|
||||||
private void pairMailbox() throws IOException, ApiException, DbException {
|
private void pairMailbox() throws IOException, ApiException, DbException {
|
||||||
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
||||||
setState(new MailboxPairingState.Pairing());
|
setState(new MailboxPairingState.Pairing(timeStarted));
|
||||||
MailboxProperties ownerProperties = api.setup(mailboxProperties);
|
MailboxProperties ownerProperties = api.setup(mailboxProperties);
|
||||||
long time = clock.currentTimeMillis();
|
long time = clock.currentTimeMillis();
|
||||||
db.transaction(false, txn -> {
|
db.transaction(false, txn -> {
|
||||||
|
|||||||
@@ -68,8 +68,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitialQrCodeReceivedState() {
|
public void testInitialQrCodeReceivedState() {
|
||||||
MailboxPairingTask task =
|
MailboxPairingTask task = createPairingTask(getRandomString(42));
|
||||||
factory.createPairingTask(getRandomString(42));
|
|
||||||
task.addObserver(state ->
|
task.addObserver(state ->
|
||||||
assertTrue(state instanceof MailboxPairingState.QrCodeReceived)
|
assertTrue(state instanceof MailboxPairingState.QrCodeReceived)
|
||||||
);
|
);
|
||||||
@@ -77,15 +76,14 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidQrCode() {
|
public void testInvalidQrCode() {
|
||||||
MailboxPairingTask task1 =
|
MailboxPairingTask task1 = createPairingTask(getRandomString(42));
|
||||||
factory.createPairingTask(getRandomString(42));
|
|
||||||
task1.run();
|
task1.run();
|
||||||
task1.addObserver(state ->
|
task1.addObserver(state ->
|
||||||
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
||||||
);
|
);
|
||||||
|
|
||||||
String goodLength = "00" + getRandomString(63);
|
String goodLength = "00" + getRandomString(63);
|
||||||
MailboxPairingTask task2 = factory.createPairingTask(goodLength);
|
MailboxPairingTask task2 = createPairingTask(goodLength);
|
||||||
task2.run();
|
task2.run();
|
||||||
task2.addObserver(state ->
|
task2.addObserver(state ->
|
||||||
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
||||||
@@ -121,7 +119,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
AtomicInteger i = new AtomicInteger(0);
|
AtomicInteger i = new AtomicInteger(0);
|
||||||
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
MailboxPairingTask task = createPairingTask(validPayload);
|
||||||
task.addObserver(state -> {
|
task.addObserver(state -> {
|
||||||
if (i.get() == 0) {
|
if (i.get() == 0) {
|
||||||
assertEquals(MailboxPairingState.QrCodeReceived.class,
|
assertEquals(MailboxPairingState.QrCodeReceived.class,
|
||||||
@@ -165,7 +163,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
will(throwException(e));
|
will(throwException(e));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
MailboxPairingTask task = createPairingTask(validPayload);
|
||||||
task.run();
|
task.run();
|
||||||
task.addObserver(state -> assertEquals(state.getClass(), s));
|
task.addObserver(state -> assertEquals(state.getClass(), s));
|
||||||
}
|
}
|
||||||
@@ -188,7 +186,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
will(throwException(new DbException()));
|
will(throwException(new DbException()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
MailboxPairingTask task = createPairingTask(validPayload);
|
||||||
task.run();
|
task.run();
|
||||||
task.addObserver(state -> assertEquals(state.getClass(),
|
task.addObserver(state -> assertEquals(state.getClass(),
|
||||||
MailboxPairingState.UnexpectedError.class));
|
MailboxPairingState.UnexpectedError.class));
|
||||||
@@ -202,4 +200,12 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
p1.getServerSupports().equals(p2.getServerSupports()));
|
p1.getServerSupports().equals(p2.getServerSupports()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MailboxPairingTask createPairingTask(String qrCodePayload) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(time));
|
||||||
|
}});
|
||||||
|
|
||||||
|
return factory.createPairingTask(qrCodePayload);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,11 +158,9 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
Fragment f;
|
Fragment f;
|
||||||
String tag;
|
String tag;
|
||||||
if (s instanceof MailboxPairingState.QrCodeReceived) {
|
if (s instanceof MailboxPairingState.Pending) {
|
||||||
f = new MailboxConnectingFragment();
|
long timeStarted = ((MailboxPairingState.Pending) s).timeStarted;
|
||||||
tag = MailboxConnectingFragment.TAG;
|
f = MailboxConnectingFragment.newInstance(timeStarted);
|
||||||
} else if (s instanceof MailboxPairingState.Pairing) {
|
|
||||||
f = new MailboxConnectingFragment();
|
|
||||||
tag = MailboxConnectingFragment.TAG;
|
tag = MailboxConnectingFragment.TAG;
|
||||||
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
|
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
|
||||||
f = ErrorFragment.newInstance(
|
f = ErrorFragment.newInstance(
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package org.briarproject.briar.android.mailbox;
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.plugin.TorConstants;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
@@ -12,25 +17,71 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.formatDuration;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class MailboxConnectingFragment extends Fragment {
|
public class MailboxConnectingFragment extends Fragment {
|
||||||
|
|
||||||
static final String TAG = MailboxConnectingFragment.class.getName();
|
static final String TAG = MailboxConnectingFragment.class.getName();
|
||||||
|
|
||||||
|
private static final String ARG_STARTED = "started";
|
||||||
|
private static final long TIMEOUT_MS = TorConstants.EXTRA_CONNECT_TIMEOUT;
|
||||||
|
private static final long REFRESH_INTERVAL_MS = 1_000;
|
||||||
|
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
// Capture a method reference so we use the same reference for posting
|
||||||
|
// and removing
|
||||||
|
private final Runnable refresher = this::updateProgressBar;
|
||||||
|
|
||||||
|
private ProgressBar progressBar;
|
||||||
|
private long timeStarted;
|
||||||
|
|
||||||
|
public static MailboxConnectingFragment newInstance(long timeStarted) {
|
||||||
|
MailboxConnectingFragment f = new MailboxConnectingFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putLong(ARG_STARTED, timeStarted);
|
||||||
|
f.setArguments(args);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater,
|
public View onCreateView(LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.fragment_mailbox_connecting,
|
View v = inflater.inflate(R.layout.fragment_mailbox_connecting,
|
||||||
container, false);
|
container, false);
|
||||||
|
|
||||||
|
progressBar = v.findViewById(R.id.progressBar);
|
||||||
|
TextView info = v.findViewById(R.id.info);
|
||||||
|
String duration = formatDuration(requireContext(), TIMEOUT_MS);
|
||||||
|
info.setText(getString(R.string.mailbox_setup_connecting_info,
|
||||||
|
duration));
|
||||||
|
|
||||||
|
timeStarted = requireArguments().getLong(ARG_STARTED);
|
||||||
|
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
requireActivity().setTitle(R.string.mailbox_setup_title);
|
requireActivity().setTitle(R.string.mailbox_setup_title);
|
||||||
|
updateProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
handler.removeCallbacks(refresher);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProgressBar() {
|
||||||
|
long elapsedMs = System.currentTimeMillis() - timeStarted;
|
||||||
|
int percent = (int) (elapsedMs * 100 / TIMEOUT_MS);
|
||||||
|
percent = Math.min(Math.max(percent, 0), 100);
|
||||||
|
progressBar.setProgress(percent);
|
||||||
|
handler.postDelayed(refresher, REFRESH_INTERVAL_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,51 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ProgressBar
|
<TextView
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/title"
|
||||||
style="?android:attr/progressBarStyleLarge"
|
style="@style/TextAppearance.AppCompat.Large"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="16dp"
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/textView"
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/mailbox_setup_connecting"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/progressBar"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_chainStyle="packed" />
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
<TextView
|
<ProgressBar
|
||||||
android:id="@+id/textView"
|
android:id="@+id/progressBar"
|
||||||
style="@style/TextAppearance.AppCompat.Large"
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="16dp"
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
android:text="@string/mailbox_setup_connecting"
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:max="100"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/info"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:layout_marginBottom="@dimen/margin_xlarge"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
|
app:layout_constraintTop_toBottomOf="@+id/progressBar"
|
||||||
|
tools:text="This may take up to 2 minutes" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -633,7 +633,9 @@
|
|||||||
<string name="mailbox_setup_download_link">Share Download Link</string>
|
<string name="mailbox_setup_download_link">Share Download Link</string>
|
||||||
<string name="mailbox_setup_button_scan">Scan Mailbox QR code</string>
|
<string name="mailbox_setup_button_scan">Scan Mailbox QR code</string>
|
||||||
<string name="permission_camera_qr_denied_body">You have denied access to the camera, but scanning a QR code requires using the camera.\n\nPlease consider granting access.</string>
|
<string name="permission_camera_qr_denied_body">You have denied access to the camera, but scanning a QR code requires using the camera.\n\nPlease consider granting access.</string>
|
||||||
<string name="mailbox_setup_connecting">Connecting…</string>
|
<string name="mailbox_setup_connecting">Connecting to Mailbox…</string>
|
||||||
|
<!-- This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes". -->
|
||||||
|
<string name="mailbox_setup_connecting_info">This may take up to %1s</string>
|
||||||
<string name="mailbox_setup_qr_code_wrong_title">Wrong QR code</string>
|
<string name="mailbox_setup_qr_code_wrong_title">Wrong QR code</string>
|
||||||
<string name="mailbox_setup_qr_code_wrong_description">The scanned code is invalid. Please open the Briar Mailbox app on your Mailbox device and scan the QR code it presents.</string>
|
<string name="mailbox_setup_qr_code_wrong_description">The scanned code is invalid. Please open the Briar Mailbox app on your Mailbox device and scan the QR code it presents.</string>
|
||||||
<string name="mailbox_setup_already_paired_title">Mailbox already linked</string>
|
<string name="mailbox_setup_already_paired_title">Mailbox already linked</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user