diff --git a/briar-android/artwork/mailbox_onboarding_dark.svg b/briar-android/artwork/mailbox_onboarding_dark.svg
new file mode 100644
index 000000000..ea1a19757
--- /dev/null
+++ b/briar-android/artwork/mailbox_onboarding_dark.svg
@@ -0,0 +1,105 @@
+
diff --git a/briar-android/artwork/mailbox_onboarding_light.svg b/briar-android/artwork/mailbox_onboarding_light.svg
new file mode 100644
index 000000000..988d2438d
--- /dev/null
+++ b/briar-android/artwork/mailbox_onboarding_light.svg
@@ -0,0 +1,105 @@
+
diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index edcea26a7..10559cd45 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -477,6 +477,17 @@
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
+
+
+
+
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 43baf5816..d4fb54b54 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
@@ -46,6 +46,7 @@ import org.briarproject.briar.android.login.ChangePasswordActivity;
import org.briarproject.briar.android.login.OpenDatabaseFragment;
import org.briarproject.briar.android.login.PasswordFragment;
import org.briarproject.briar.android.login.StartupActivity;
+import org.briarproject.briar.android.mailbox.MailboxActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.navdrawer.TransportsActivity;
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
@@ -250,4 +251,6 @@ public interface ActivityComponent {
void inject(RssFeedDeleteFeedDialogFragment fragment);
void inject(ConnectViaBluetoothActivity connectViaBluetoothActivity);
+
+ void inject(MailboxActivity mailboxActivity);
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java
new file mode 100644
index 000000000..739bcae3b
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java
@@ -0,0 +1,75 @@
+package org.briarproject.briar.android.mailbox;
+
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.widget.ProgressBar;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.activity.BriarActivity;
+
+import javax.inject.Inject;
+
+import androidx.annotation.Nullable;
+import androidx.lifecycle.ViewModelProvider;
+
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class MailboxActivity extends BriarActivity {
+
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ private MailboxViewModel viewModel;
+ private ProgressBar progressBar;
+
+ @Override
+ public void injectActivity(ActivityComponent component) {
+ component.inject(this);
+
+ viewModel = new ViewModelProvider(this, viewModelFactory)
+ .get(MailboxViewModel.class);
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_mailbox);
+
+ progressBar = findViewById(R.id.progressBar);
+ if (viewModel.getState().getValue() == null) {
+ progressBar.setVisibility(VISIBLE);
+ }
+
+ if (savedInstanceState == null) {
+ viewModel.getState().observe(this, state -> {
+ if (state instanceof MailboxState.NotSetup) {
+ onNotSetup();
+ }
+ });
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void onNotSetup() {
+ progressBar.setVisibility(INVISIBLE);
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.fragmentContainer, new SetupIntroFragment(),
+ SetupIntroFragment.TAG)
+ .commit();
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxModule.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxModule.java
index 196e4e151..e78b23736 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxModule.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxModule.java
@@ -12,8 +12,7 @@ public interface MailboxModule {
@Binds
@IntoMap
- @ViewModelKey(MailboxPairViewModel.class)
- ViewModel bindMailboxViewModel(
- MailboxPairViewModel mailboxPairViewModel);
+ @ViewModelKey(MailboxViewModel.class)
+ ViewModel bindMailboxViewModel(MailboxViewModel mailboxViewModel);
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java
new file mode 100644
index 000000000..13f2be94b
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java
@@ -0,0 +1,10 @@
+package org.briarproject.briar.android.mailbox;
+
+class MailboxState {
+
+ static class NotSetup extends MailboxState {
+ }
+
+ // TODO add other states
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxPairViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java
similarity index 79%
rename from briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxPairViewModel.java
rename to briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java
index 1c6023997..9750b8e87 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxPairViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java
@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.util.StringUtils;
+import org.briarproject.briar.android.mailbox.MailboxState.NotSetup;
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
import org.briarproject.briar.android.viewmodel.DbViewModel;
@@ -24,32 +25,35 @@ import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
-@UiThread
@NotNullByDefault
-class MailboxPairViewModel extends DbViewModel
+class MailboxViewModel extends DbViewModel
implements QrCodeDecoder.ResultCallback {
- private static final Logger LOG =
- getLogger(MailboxPairViewModel.class.getName());
- private static final int VERSION_REQUIRED = 32;
+ private static final Logger LOG =
+ getLogger(MailboxViewModel.class.getName());
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+ private static final int VERSION_REQUIRED = 32;
private final CryptoComponent crypto;
private final QrCodeDecoder qrCodeDecoder;
+ private final MutableLiveData state = new MutableLiveData<>();
+
@Nullable
private String onionAddress = null;
@Nullable
private String setupToken = null;
@Inject
- MailboxPairViewModel(
+ MailboxViewModel(
Application app,
@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager,
@@ -60,9 +64,29 @@ class MailboxPairViewModel extends DbViewModel
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
this.crypto = crypto;
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
+ checkIfSetup();
+ }
+
+ @UiThread
+ private void checkIfSetup() {
+ runOnDbThread(() -> {
+ // TODO really check if mailbox is setup/paired/linked
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ state.postValue(new NotSetup());
+ });
+ }
+
+ @UiThread
+ LiveData getState() {
+ return state;
}
@Override
+ @IoExecutor
public void onQrCodeDecoded(Result result) {
LOG.info("Got result from decoder");
byte[] bytes = result.getText().getBytes(ISO_8859_1);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupDownloadFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupDownloadFragment.java
new file mode 100644
index 000000000..9ecd01e51
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupDownloadFragment.java
@@ -0,0 +1,76 @@
+package org.briarproject.briar.android.mailbox;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.Toast;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import static android.content.Intent.ACTION_SEND;
+import static android.content.Intent.EXTRA_TEXT;
+import static android.widget.Toast.LENGTH_LONG;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class SetupDownloadFragment extends Fragment {
+
+ static final String TAG = SetupDownloadFragment.class.getName();
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_mailbox_setup_download,
+ container, false);
+ Button shareLinkButton = v.findViewById(R.id.shareLinkButton);
+ Button scanButton = v.findViewById(R.id.scanButton);
+ shareLinkButton.setOnClickListener(this::shareLink);
+ scanButton.setOnClickListener(this::scanCode);
+ return v;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ requireActivity().setTitle(R.string.mailbox_setup_title);
+ }
+
+ private void shareLink(View v) {
+ Context ctx = requireContext();
+ String fdroid = ctx.getString(R.string.mailbox_share_fdroid);
+ String gplay = ctx.getString(R.string.mailbox_share_gplay);
+ String download = ctx.getString(R.string.mailbox_share_download);
+ String text = ctx.getString(R.string.mailbox_share_text, fdroid, gplay,
+ download);
+
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(ACTION_SEND);
+ sendIntent.putExtra(EXTRA_TEXT, text);
+ sendIntent.setType("text/plain");
+
+ Intent shareIntent = Intent.createChooser(sendIntent, null);
+ try {
+ startActivity(shareIntent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG)
+ .show();
+ }
+ }
+
+ private void scanCode(View v) {
+ Toast.makeText(requireContext(), "TODO", LENGTH_LONG).show();
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java
new file mode 100644
index 000000000..bfb4a8cfb
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java
@@ -0,0 +1,47 @@
+package org.briarproject.briar.android.mailbox;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+
+import static org.briarproject.briar.android.util.UiUtils.showFragment;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class SetupIntroFragment extends Fragment {
+
+ static final String TAG = SetupIntroFragment.class.getName();
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_mailbox_setup_intro,
+ container, false);
+ Button button = v.findViewById(R.id.continueButton);
+ button.setOnClickListener(view -> {
+ FragmentManager fm = getParentFragmentManager();
+ Fragment f = new SetupDownloadFragment();
+ showFragment(fm, f, SetupDownloadFragment.TAG);
+ });
+ return v;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ requireActivity().setTitle(R.string.mailbox_setup_title);
+ }
+
+}
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 6b9910531..219c43891 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
@@ -1,6 +1,7 @@
package org.briarproject.briar.android.settings;
import android.content.Context;
+import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
@@ -8,6 +9,7 @@ import android.view.View;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
+import org.briarproject.briar.android.mailbox.MailboxActivity;
import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced;
import javax.inject.Inject;
@@ -74,7 +76,8 @@ public class SettingsFragment extends PreferenceFragmentCompat {
requireNonNull(findPreference(PREF_KEY_MAILBOX));
if (viewModel.shouldEnableMailbox()) {
prefMailbox.setOnPreferenceClickListener(preference -> {
- // TODO show mailbox status/onboarding
+ Intent i = new Intent(requireContext(), MailboxActivity.class);
+ startActivity(i);
return true;
});
} else {
diff --git a/briar-android/src/main/res/drawable-night/ic_mailbox_onboarding.xml b/briar-android/src/main/res/drawable-night/ic_mailbox_onboarding.xml
new file mode 100644
index 000000000..76a2beda4
--- /dev/null
+++ b/briar-android/src/main/res/drawable-night/ic_mailbox_onboarding.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/briar-android/src/main/res/drawable/ic_mailbox_onboarding.xml b/briar-android/src/main/res/drawable/ic_mailbox_onboarding.xml
new file mode 100644
index 000000000..abd0bc87b
--- /dev/null
+++ b/briar-android/src/main/res/drawable/ic_mailbox_onboarding.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/briar-android/src/main/res/layout/activity_mailbox.xml b/briar-android/src/main/res/layout/activity_mailbox.xml
new file mode 100644
index 000000000..27e3eff1c
--- /dev/null
+++ b/briar-android/src/main/res/layout/activity_mailbox.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml b/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml
new file mode 100644
index 000000000..721dc5c70
--- /dev/null
+++ b/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/briar-android/src/main/res/layout/fragment_mailbox_setup_intro.xml b/briar-android/src/main/res/layout/fragment_mailbox_setup_intro.xml
new file mode 100644
index 000000000..613287b0a
--- /dev/null
+++ b/briar-android/src/main/res/layout/fragment_mailbox_setup_intro.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 53b0ea95c..dfd702879 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -614,6 +614,20 @@
Mailbox
+ Mailbox Setup
+ Once you set up a Mailbox for Briar, you will be able to send and receive messages even if you are not online.\n
+ \nYou can install Briar Mailbox on a spare device which will act as a forwarder for your messages (for best connectivity, the Mailbox device should stay charged and online at all times).
+ Once you installed the Briar Mailbox app on a spare device, you can link it with this device by scanning the Mailbox QR code on the next screen.\n
+ \nYou can find Briar Mailbox on F-Droid or Google Play.
+ Share Download Link
+ Scan Mailbox QR code
+ You can install the Briar Mailbox app from one of those sources:\n
+ \nF-Droid: %1$s
+ \nGoogle Play: %2$s
+ \nDirect Download: %3$s
+ https://f-droid.org/packages/org.briarproject.mailbox/
+ https://play.google.com/store/apps/details?id=org.briarproject.mailbox
+ https://briarproject.org/apk
Disappearing messages