WIP Add an activity to try out mailbox qr decoding

This commit is contained in:
Daniel Lublin
2021-11-03 11:42:20 +01:00
parent 407ddad0a8
commit fc3fcf120f
9 changed files with 294 additions and 0 deletions

View File

@@ -452,6 +452,15 @@
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.mailbox.MailboxActivity"
android:label="@string/mailbox_menu_title"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" />
</activity>
<activity
android:name=".android.contact.add.remote.PendingContactListActivity"
android:label="@string/pending_contact_requests"

View File

@@ -46,6 +46,8 @@ 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.mailbox.MailboxPairFragment;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.navdrawer.TransportsActivity;
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
@@ -182,6 +184,8 @@ public interface ActivityComponent {
void inject(RemovableDriveActivity activity);
void inject(MailboxActivity activity);
// Fragments
void inject(SetupFragment fragment);
@@ -247,4 +251,6 @@ public interface ActivityComponent {
void inject(RssFeedDeleteFeedDialogFragment fragment);
void inject(ConnectViaBluetoothActivity connectViaBluetoothActivity);
void inject(MailboxPairFragment fragment);
}

View File

@@ -0,0 +1,57 @@
package org.briarproject.briar.android.mailbox;
import android.os.Bundle;
import android.view.MenuItem;
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 org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.lifecycle.ViewModelProvider;
@RequiresApi(19)
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class MailboxActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
private MailboxPairViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(MailboxPairViewModel.class);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_container);
showInitialFragment(new MailboxPairFragment());
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@@ -0,0 +1,139 @@
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.TextView;
import android.widget.Toast;
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.fragment.BaseFragment;
import org.briarproject.briar.android.qrcode.CameraException;
import org.briarproject.briar.android.qrcode.CameraView;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.annotation.UiThread;
import androidx.lifecycle.ViewModelProvider;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
// TODO have to get camera permission somewhere
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class MailboxPairFragment extends BaseFragment {
static final String TAG = MailboxPairFragment.class.getName();
private static final Logger LOG = Logger.getLogger(TAG);
@Inject
ViewModelProvider.Factory viewModelFactory;
private MailboxPairViewModel viewModel;
private CameraView cameraView;
private View statusView;
private TextView status;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(MailboxPairViewModel.class);
viewModel.getState().observeEvent(this, this::onStateChanged);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_mailbox_qr, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
cameraView = view.findViewById(R.id.camera_view);
cameraView.setPreviewConsumer(viewModel.getQrCodeDecoder());
statusView = view.findViewById(R.id.status_container);
status = view.findViewById(R.id.connect_status);
requireActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
}
private void onStateChanged(MailboxPairViewModel.State state) {
if (state == MailboxPairViewModel.State.QRCODE_VALID ||
state == MailboxPairViewModel.State.QRCODE_INVALID) {
tryStopCamera();
cameraView.setVisibility(INVISIBLE);
statusView.setVisibility(VISIBLE);
CharSequence text = "That's not a valid Mailbox QR code.";
if (state == MailboxPairViewModel.State.QRCODE_VALID) {
String fmt =
"curl -v --socks5-hostname 127.0.0.1:9050" +
" -H \"Authorization: Bearer %s\"" +
" -X PUT http://%s.onion/setup";
text = String.format(fmt, viewModel.getSetupToken(),
viewModel.getOnionAddress());
}
status.setText(text);
}
}
@Override
public void onStart() {
super.onStart();
try {
cameraView.start();
} catch (CameraException e) {
logCameraExceptionAndFinish(e);
}
}
@Override
public void onStop() {
super.onStop();
tryStopCamera();
}
void tryStopCamera() {
try {
cameraView.stop();
} catch (CameraException e) {
logCameraExceptionAndFinish(e);
}
}
@Override
public String getUniqueTag() {
return TAG;
}
@UiThread
private void logCameraExceptionAndFinish(CameraException e) {
logException(LOG, WARNING, e);
Toast.makeText(getActivity(), R.string.camera_error,
LENGTH_LONG).show();
finish();
}
@Override
protected void finish() {
requireActivity().getSupportFragmentManager().popBackStack();
}
}

View File

@@ -14,6 +14,8 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import java.nio.charset.Charset;
import java.util.Arrays;
@@ -32,6 +34,8 @@ import static java.util.logging.Logger.getLogger;
@NotNullByDefault
class MailboxPairViewModel extends DbViewModel
implements QrCodeDecoder.ResultCallback {
enum State {QRCODE_VALID, QRCODE_INVALID}
private static final Logger LOG =
getLogger(MailboxPairViewModel.class.getName());
@@ -41,6 +45,8 @@ class MailboxPairViewModel extends DbViewModel
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
private final CryptoComponent crypto;
private final MutableLiveEvent<State> state = new MutableLiveEvent<>();
private final QrCodeDecoder qrCodeDecoder;
@Nullable
@@ -71,6 +77,7 @@ class MailboxPairViewModel extends DbViewModel
LOG.info("QR code length in bytes: " + bytes.length);
if (bytes.length != 65) {
LOG.info("QR code has wrong length");
state.postEvent(State.QRCODE_INVALID);
return;
}
@@ -78,6 +85,7 @@ class MailboxPairViewModel extends DbViewModel
LOG.info("QR code version: " + bytes[0]);
if (bytes[0] != VERSION_REQUIRED) {
LOG.info("QR code has wrong version");
state.postEvent(State.QRCODE_INVALID);
return;
}
@@ -86,10 +94,29 @@ class MailboxPairViewModel extends DbViewModel
setupToken = StringUtils.toHexString(Arrays.copyOfRange(bytes, 33, 65))
.toLowerCase();
LOG.info("QR code is valid");
state.postEvent(State.QRCODE_VALID);
}
LiveEvent<State> getState() {
return state;
}
QrCodeDecoder getQrCodeDecoder() {
return qrCodeDecoder;
}
String getOnionAddress() {
if (onionAddress == null) {
throw new IllegalStateException();
}
return onionAddress;
}
String getSetupToken() {
if (setupToken == null) {
throw new IllegalStateException();
}
return setupToken;
}
}

View File

@@ -38,6 +38,7 @@ import org.briarproject.briar.android.forum.ForumListFragment;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.logout.SignOutFragment;
import org.briarproject.briar.android.mailbox.MailboxActivity;
import org.briarproject.briar.android.privategroup.list.GroupListFragment;
import org.briarproject.briar.android.settings.SettingsActivity;
@@ -277,6 +278,8 @@ public class NavDrawerActivity extends BriarActivity implements
startActivity(new Intent(this, SettingsActivity.class));
} else if (fragmentId == R.id.nav_btn_signout) {
signOut();
} else if (fragmentId == R.id.nav_btn_mailbox) {
startActivity(new Intent(this, MailboxActivity.class));
}
}

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<org.briarproject.briar.android.qrcode.CameraView
android:id="@+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/camera_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="vertical">
<LinearLayout
android:id="@+id/status_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/margin_medium"
android:visibility="invisible"
tools:visibility="visible">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/connect_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="@dimen/margin_large"
android:textIsSelectable="true"
tools:text="@string/waiting_for_contact_to_scan" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -37,6 +37,10 @@
android:id="@+id/nav_btn_signout"
android:icon="@drawable/ic_signout"
android:title="@string/sign_out_button" />
<item
android:id="@+id/nav_btn_mailbox"
android:icon="@drawable/ic_crash"
android:title="@string/mailbox_menu_title" />
</group>
</menu>

View File

@@ -805,5 +805,6 @@
<string name="screenshot_message_2">Hi Alice! Thanks for telling me about Briar!</string>
<!-- This is a message to be used in screenshots. -->
<string name="screenshot_message_3">No problem, hope you like it 😀</string>
<string name="mailbox_menu_title">Mailbox</string>
</resources>