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:
akwizgran
2022-12-14 12:20:43 +00:00
7 changed files with 128 additions and 32 deletions

View File

@@ -2,10 +2,27 @@ package org.briarproject.bramble.api.mailbox;
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 {

View File

@@ -52,6 +52,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
private final MailboxApi api;
private final MailboxSettingsManager mailboxSettingsManager;
private final MailboxUpdateManager mailboxUpdateManager;
private final long timeStarted;
private final Object lock = new Object();
@GuardedBy("lock")
@@ -77,7 +78,8 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
this.api = api;
this.mailboxSettingsManager = mailboxSettingsManager;
this.mailboxUpdateManager = mailboxUpdateManager;
state = new MailboxPairingState.QrCodeReceived();
timeStarted = clock.currentTimeMillis();
state = new MailboxPairingState.QrCodeReceived(timeStarted);
}
@Override
@@ -114,7 +116,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
private void pairMailbox() throws IOException, ApiException, DbException {
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
setState(new MailboxPairingState.Pairing());
setState(new MailboxPairingState.Pairing(timeStarted));
MailboxProperties ownerProperties = api.setup(mailboxProperties);
long time = clock.currentTimeMillis();
db.transaction(false, txn -> {

View File

@@ -68,8 +68,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
@Test
public void testInitialQrCodeReceivedState() {
MailboxPairingTask task =
factory.createPairingTask(getRandomString(42));
MailboxPairingTask task = createPairingTask(getRandomString(42));
task.addObserver(state ->
assertTrue(state instanceof MailboxPairingState.QrCodeReceived)
);
@@ -77,15 +76,14 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
@Test
public void testInvalidQrCode() {
MailboxPairingTask task1 =
factory.createPairingTask(getRandomString(42));
MailboxPairingTask task1 = createPairingTask(getRandomString(42));
task1.run();
task1.addObserver(state ->
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
);
String goodLength = "00" + getRandomString(63);
MailboxPairingTask task2 = factory.createPairingTask(goodLength);
MailboxPairingTask task2 = createPairingTask(goodLength);
task2.run();
task2.addObserver(state ->
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
@@ -121,7 +119,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
}});
AtomicInteger i = new AtomicInteger(0);
MailboxPairingTask task = factory.createPairingTask(validPayload);
MailboxPairingTask task = createPairingTask(validPayload);
task.addObserver(state -> {
if (i.get() == 0) {
assertEquals(MailboxPairingState.QrCodeReceived.class,
@@ -165,7 +163,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
will(throwException(e));
}});
MailboxPairingTask task = factory.createPairingTask(validPayload);
MailboxPairingTask task = createPairingTask(validPayload);
task.run();
task.addObserver(state -> assertEquals(state.getClass(), s));
}
@@ -188,7 +186,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
will(throwException(new DbException()));
}});
MailboxPairingTask task = factory.createPairingTask(validPayload);
MailboxPairingTask task = createPairingTask(validPayload);
task.run();
task.addObserver(state -> assertEquals(state.getClass(),
MailboxPairingState.UnexpectedError.class));
@@ -202,4 +200,12 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
p1.getServerSupports().equals(p2.getServerSupports()));
}
private MailboxPairingTask createPairingTask(String qrCodePayload) {
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(time));
}});
return factory.createPairingTask(qrCodePayload);
}
}

View File

@@ -158,11 +158,9 @@ public class MailboxActivity extends BriarActivity {
}
Fragment f;
String tag;
if (s instanceof MailboxPairingState.QrCodeReceived) {
f = new MailboxConnectingFragment();
tag = MailboxConnectingFragment.TAG;
} else if (s instanceof MailboxPairingState.Pairing) {
f = new MailboxConnectingFragment();
if (s instanceof MailboxPairingState.Pending) {
long timeStarted = ((MailboxPairingState.Pending) s).timeStarted;
f = MailboxConnectingFragment.newInstance(timeStarted);
tag = MailboxConnectingFragment.TAG;
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
f = ErrorFragment.newInstance(

View File

@@ -1,10 +1,15 @@
package org.briarproject.briar.android.mailbox;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
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.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
@@ -12,25 +17,71 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import static org.briarproject.briar.android.util.UiUtils.formatDuration;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class MailboxConnectingFragment extends Fragment {
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
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_mailbox_connecting,
View v = inflater.inflate(R.layout.fragment_mailbox_connecting,
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
public void onStart() {
super.onStart();
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);
}
}

View File

@@ -1,31 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
<TextView
android:id="@+id/title"
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:layout_constraintBottom_toTopOf="@+id/textView"
android:layout_marginHorizontal="@dimen/margin_xlarge"
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_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/textView"
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="wrap_content"
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/mailbox_setup_connecting"
android:layout_marginHorizontal="@dimen/margin_xlarge"
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_constraintEnd_toEndOf="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>

View File

@@ -633,7 +633,9 @@
<string name="mailbox_setup_download_link">Share Download Link</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="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_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>