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 @@ + + + + + + + + + +