mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
Scan Mailbox QR code for setup and show progress screen
This commit is contained in:
@@ -44,6 +44,7 @@ import org.briarproject.briar.android.hotspot.ManualHotspotFragment;
|
||||
import org.briarproject.briar.android.hotspot.QrHotspotFragment;
|
||||
import org.briarproject.briar.android.logging.CachingLogHandler;
|
||||
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||
import org.briarproject.briar.android.mailbox.MailboxScanFragment;
|
||||
import org.briarproject.briar.android.removabledrive.ChooserFragment;
|
||||
import org.briarproject.briar.android.removabledrive.ReceiveFragment;
|
||||
import org.briarproject.briar.android.removabledrive.SendFragment;
|
||||
@@ -239,4 +240,6 @@ public interface AndroidComponent
|
||||
void inject(ReceiveFragment receiveFragment);
|
||||
|
||||
void inject(BluetoothIntroFragment bluetoothIntroFragment);
|
||||
|
||||
void inject(MailboxScanFragment mailboxScanFragment);
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@ package org.briarproject.briar.android.contact.add.nearby;
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.util.Permission;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
@@ -17,16 +16,13 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
|
||||
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||
import static org.briarproject.briar.android.util.UiUtils.getGoToSettingsListener;
|
||||
import static org.briarproject.briar.android.util.UiUtils.isLocationEnabled;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showDenialDialog;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showLocationDialog;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showRationale;
|
||||
|
||||
class AddNearbyContactPermissionManager {
|
||||
|
||||
private enum Permission {
|
||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||
}
|
||||
|
||||
private Permission cameraPermission = Permission.UNKNOWN;
|
||||
private Permission locationPermission = Permission.UNKNOWN;
|
||||
|
||||
@@ -68,27 +64,30 @@ class AddNearbyContactPermissionManager {
|
||||
// If an essential permission has been permanently denied, ask the
|
||||
// user to change the setting
|
||||
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
||||
showDenialDialog(R.string.permission_camera_title,
|
||||
showDenialDialog(ctx, R.string.permission_camera_title,
|
||||
R.string.permission_camera_denied_body);
|
||||
return false;
|
||||
}
|
||||
if (isBluetoothSupported &&
|
||||
locationPermission == Permission.PERMANENTLY_DENIED) {
|
||||
showDenialDialog(R.string.permission_location_title,
|
||||
showDenialDialog(ctx, R.string.permission_location_title,
|
||||
R.string.permission_location_denied_body);
|
||||
return false;
|
||||
}
|
||||
// Should we show the rationale for one or both permissions?
|
||||
if (cameraPermission == Permission.SHOW_RATIONALE &&
|
||||
locationPermission == Permission.SHOW_RATIONALE) {
|
||||
showRationale(R.string.permission_camera_location_title,
|
||||
R.string.permission_camera_location_request_body);
|
||||
showRationale(ctx, R.string.permission_camera_location_title,
|
||||
R.string.permission_camera_location_request_body,
|
||||
this::requestPermissions);
|
||||
} else if (cameraPermission == Permission.SHOW_RATIONALE) {
|
||||
showRationale(R.string.permission_camera_title,
|
||||
R.string.permission_camera_request_body);
|
||||
showRationale(ctx, R.string.permission_camera_title,
|
||||
R.string.permission_camera_request_body,
|
||||
this::requestPermissions);
|
||||
} else if (locationPermission == Permission.SHOW_RATIONALE) {
|
||||
showRationale(R.string.permission_location_title,
|
||||
R.string.permission_location_request_body);
|
||||
showRationale(ctx, R.string.permission_location_title,
|
||||
R.string.permission_location_request_body,
|
||||
this::requestPermissions);
|
||||
} else if (locationEnabled) {
|
||||
requestPermissions();
|
||||
} else {
|
||||
@@ -97,27 +96,6 @@ class AddNearbyContactPermissionManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void showDenialDialog(@StringRes int title, @StringRes int body) {
|
||||
AlertDialog.Builder builder =
|
||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(body);
|
||||
builder.setPositiveButton(R.string.ok, getGoToSettingsListener(ctx));
|
||||
builder.setNegativeButton(R.string.cancel,
|
||||
(dialog, which) -> ctx.supportFinishAfterTransition());
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void showRationale(@StringRes int title, @StringRes int body) {
|
||||
AlertDialog.Builder builder =
|
||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(body);
|
||||
builder.setNeutralButton(R.string.continue_button,
|
||||
(dialog, which) -> requestPermissions());
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void requestPermissions() {
|
||||
String[] permissions;
|
||||
if (isBluetoothSupported) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.util.Permission;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -19,10 +20,6 @@ import static org.briarproject.briar.android.util.UiUtils.showLocationDialog;
|
||||
|
||||
class BluetoothConditionManager {
|
||||
|
||||
private enum Permission {
|
||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||
}
|
||||
|
||||
private Permission locationPermission = Permission.UNKNOWN;
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,11 +20,7 @@ import static android.content.Context.WIFI_SERVICE;
|
||||
*/
|
||||
abstract class AbstractConditionManager {
|
||||
|
||||
enum Permission {
|
||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||
}
|
||||
|
||||
protected final Consumer<Boolean> permissionUpdateCallback;
|
||||
final Consumer<Boolean> permissionUpdateCallback;
|
||||
protected FragmentActivity ctx;
|
||||
WifiManager wifiManager;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.util.Permission;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.briarproject.briar.android.mailbox;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.util.Permission;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import static android.Manifest.permission.CAMERA;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
|
||||
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showDenialDialog;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showRationale;
|
||||
|
||||
class CameraPermissionManager {
|
||||
|
||||
private Permission cameraPermission = Permission.UNKNOWN;
|
||||
|
||||
private final FragmentActivity ctx;
|
||||
private final Consumer<String[]> requestPermissions;
|
||||
|
||||
CameraPermissionManager(FragmentActivity ctx,
|
||||
Consumer<String[]> requestPermissions) {
|
||||
this.ctx = ctx;
|
||||
this.requestPermissions = requestPermissions;
|
||||
}
|
||||
|
||||
void resetPermissions() {
|
||||
cameraPermission = Permission.UNKNOWN;
|
||||
}
|
||||
|
||||
private static boolean areEssentialPermissionsGranted(Context ctx) {
|
||||
return checkSelfPermission(ctx, CAMERA) == PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
private boolean areEssentialPermissionsGranted() {
|
||||
return cameraPermission == Permission.GRANTED;
|
||||
}
|
||||
|
||||
boolean checkPermissions() {
|
||||
if (areEssentialPermissionsGranted()) return true;
|
||||
// If an essential permission has been permanently denied, ask the
|
||||
// user to change the setting
|
||||
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
||||
showDenialDialog(ctx, R.string.permission_camera_title,
|
||||
R.string.permission_camera_qr_denied_body);
|
||||
} else if (cameraPermission == Permission.SHOW_RATIONALE) {
|
||||
showRationale(ctx, R.string.permission_camera_title,
|
||||
R.string.permission_camera_request_body,
|
||||
this::requestPermissions);
|
||||
} else {
|
||||
requestPermissions();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void requestPermissions() {
|
||||
String[] permissions = new String[] {CAMERA};
|
||||
requestPermissions.accept(permissions);
|
||||
}
|
||||
|
||||
void onRequestPermissionResult(Map<String, Boolean> result) {
|
||||
if (gotPermission(result)) {
|
||||
cameraPermission = Permission.GRANTED;
|
||||
} else if (shouldShowRequestPermissionRationale(ctx, CAMERA)) {
|
||||
cameraPermission = Permission.SHOW_RATIONALE;
|
||||
} else {
|
||||
cameraPermission = Permission.PERMANENTLY_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean gotPermission(Map<String, Boolean> result) {
|
||||
Boolean permissionResult = result.get(CAMERA);
|
||||
return permissionResult == null ? areEssentialPermissionsGranted(ctx) :
|
||||
permissionResult;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -46,13 +47,13 @@ public class MailboxActivity extends BriarActivity {
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
viewModel.getState().observe(this, state -> {
|
||||
if (state instanceof MailboxState.NotSetup) {
|
||||
onNotSetup();
|
||||
}
|
||||
});
|
||||
}
|
||||
viewModel.getState().observe(this, state -> {
|
||||
if (state instanceof MailboxState.NotSetup) {
|
||||
if (savedInstanceState == null) onNotSetup();
|
||||
} else if (state instanceof MailboxState.SettingUp) {
|
||||
onCodeScanned();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,6 +65,17 @@ public class MailboxActivity extends BriarActivity {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (viewModel.getState()
|
||||
.getValue() instanceof MailboxState.SettingUp) {
|
||||
// don't go back in flow if we are already setting up mailbox
|
||||
supportFinishAfterTransition();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
private void onNotSetup() {
|
||||
progressBar.setVisibility(INVISIBLE);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
@@ -72,4 +84,10 @@ public class MailboxActivity extends BriarActivity {
|
||||
.commit();
|
||||
}
|
||||
|
||||
private void onCodeScanned() {
|
||||
showFragment(getSupportFragmentManager(),
|
||||
new MailboxConnectingFragment(),
|
||||
MailboxConnectingFragment.TAG, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.briarproject.briar.android.mailbox;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
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;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class MailboxConnectingFragment extends Fragment {
|
||||
|
||||
static final String TAG = MailboxConnectingFragment.class.getName();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_mailbox_connecting,
|
||||
container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
requireActivity().setTitle(R.string.mailbox_setup_title);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.briarproject.briar.android.mailbox;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
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.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.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class MailboxScanFragment extends Fragment {
|
||||
|
||||
static final String TAG = MailboxScanFragment.class.getName();
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(TAG);
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private MailboxViewModel viewModel;
|
||||
|
||||
private CameraView cameraView;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
FragmentActivity activity = requireActivity();
|
||||
getAndroidComponent(activity).inject(this);
|
||||
viewModel = new ViewModelProvider(activity, viewModelFactory)
|
||||
.get(MailboxViewModel.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_mailbox_scan, 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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
requireActivity().setTitle(R.string.mailbox_setup_button_scan);
|
||||
try {
|
||||
cameraView.start();
|
||||
} catch (CameraException e) {
|
||||
logCameraExceptionAndFinish(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
try {
|
||||
cameraView.stop();
|
||||
} catch (CameraException e) {
|
||||
logCameraExceptionAndFinish(e);
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void logCameraExceptionAndFinish(CameraException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
Toast.makeText(requireContext(), R.string.camera_error,
|
||||
LENGTH_LONG).show();
|
||||
requireActivity().getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,9 @@ class MailboxState {
|
||||
static class NotSetup extends MailboxState {
|
||||
}
|
||||
|
||||
static class SettingUp extends MailboxState {
|
||||
}
|
||||
|
||||
// TODO add other states
|
||||
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.TransactionManager;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
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;
|
||||
@@ -23,7 +24,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
@@ -47,11 +47,6 @@ class MailboxViewModel extends DbViewModel
|
||||
|
||||
private final MutableLiveData<MailboxState> state = new MutableLiveData<>();
|
||||
|
||||
@Nullable
|
||||
private String onionAddress = null;
|
||||
@Nullable
|
||||
private String setupToken = null;
|
||||
|
||||
@Inject
|
||||
MailboxViewModel(
|
||||
Application app,
|
||||
@@ -80,11 +75,6 @@ class MailboxViewModel extends DbViewModel
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
LiveData<MailboxState> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@IoExecutor
|
||||
public void onQrCodeDecoded(Result result) {
|
||||
@@ -105,15 +95,25 @@ class MailboxViewModel extends DbViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
||||
onionAddress = crypto.encodeOnionAddress(onionPubKey);
|
||||
setupToken = StringUtils.toHexString(Arrays.copyOfRange(bytes, 33, 65))
|
||||
.toLowerCase();
|
||||
LOG.info("QR code is valid");
|
||||
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
||||
String onionAddress = crypto.encodeOnionAddress(onionPubKey);
|
||||
byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65);
|
||||
MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes);
|
||||
MailboxProperties props =
|
||||
new MailboxProperties(onionAddress, setupToken, true);
|
||||
// TODO pass props to core (maybe even do payload parsing there)
|
||||
state.postValue(new MailboxState.SettingUp());
|
||||
}
|
||||
|
||||
@UiThread
|
||||
QrCodeDecoder getQrCodeDecoder() {
|
||||
return qrCodeDecoder;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
LiveData<MailboxState> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,12 +14,16 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import static android.content.Intent.ACTION_SEND;
|
||||
import static android.content.Intent.EXTRA_TEXT;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -27,6 +31,16 @@ public class SetupDownloadFragment extends Fragment {
|
||||
|
||||
static final String TAG = SetupDownloadFragment.class.getName();
|
||||
|
||||
private CameraPermissionManager permissionManager;
|
||||
|
||||
private final ActivityResultLauncher<String[]> permissionLauncher =
|
||||
registerForActivityResult(new RequestMultiplePermissions(), r -> {
|
||||
permissionManager.onRequestPermissionResult(r);
|
||||
if (permissionManager.checkPermissions()) {
|
||||
scanCode();
|
||||
}
|
||||
});
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@@ -34,10 +48,19 @@ public class SetupDownloadFragment extends Fragment {
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_mailbox_setup_download,
|
||||
container, false);
|
||||
|
||||
permissionManager = new CameraPermissionManager(requireActivity(),
|
||||
permissionLauncher::launch);
|
||||
|
||||
Button shareLinkButton = v.findViewById(R.id.shareLinkButton);
|
||||
Button scanButton = v.findViewById(R.id.scanButton);
|
||||
shareLinkButton.setOnClickListener(this::shareLink);
|
||||
scanButton.setOnClickListener(this::scanCode);
|
||||
|
||||
Button scanButton = v.findViewById(R.id.scanButton);
|
||||
scanButton.setOnClickListener(view -> {
|
||||
if (permissionManager.checkPermissions()) {
|
||||
scanCode();
|
||||
}
|
||||
});
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -45,6 +68,8 @@ public class SetupDownloadFragment extends Fragment {
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
requireActivity().setTitle(R.string.mailbox_setup_title);
|
||||
// Permissions may have been granted manually while we were stopped
|
||||
permissionManager.resetPermissions();
|
||||
}
|
||||
|
||||
private void shareLink(View v) {
|
||||
@@ -69,8 +94,10 @@ public class SetupDownloadFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void scanCode(View v) {
|
||||
Toast.makeText(requireContext(), "TODO", LENGTH_LONG).show();
|
||||
private void scanCode() {
|
||||
FragmentManager fm = getParentFragmentManager();
|
||||
Fragment f = new MailboxScanFragment();
|
||||
showFragment(fm, f, MailboxScanFragment.TAG);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.briarproject.briar.android.util;
|
||||
|
||||
public enum Permission {
|
||||
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||
}
|
||||
@@ -52,6 +52,7 @@ import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
@@ -574,4 +575,26 @@ public class UiUtils {
|
||||
SOFT_INPUT_STATE_HIDDEN);
|
||||
}
|
||||
|
||||
public static void showDenialDialog(FragmentActivity ctx,
|
||||
@StringRes int title, @StringRes int body) {
|
||||
AlertDialog.Builder builder =
|
||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(body);
|
||||
builder.setPositiveButton(R.string.ok, getGoToSettingsListener(ctx));
|
||||
builder.setNegativeButton(R.string.cancel,
|
||||
(dialog, which) -> ctx.supportFinishAfterTransition());
|
||||
builder.show();
|
||||
}
|
||||
|
||||
public static void showRationale(FragmentActivity ctx, @StringRes int title,
|
||||
@StringRes int body, Runnable requestPermissions) {
|
||||
AlertDialog.Builder builder =
|
||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||
builder.setTitle(title);
|
||||
builder.setMessage(body);
|
||||
builder.setNeutralButton(R.string.continue_button,
|
||||
(dialog, which) -> requestPermissions.run());
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
14
briar-android/src/main/res/drawable/border_qr_scanner.xml
Normal file
14
briar-android/src/main/res/drawable/border_qr_scanner.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:dither="true"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners android:radius="32dp" />
|
||||
|
||||
<solid android:color="@android:color/transparent" />
|
||||
|
||||
<stroke
|
||||
android:width="4dp"
|
||||
android:color="#ffffff" />
|
||||
|
||||
</shape>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/textView"
|
||||
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"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/mailbox_setup_connecting"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
27
briar-android/src/main/res/layout/fragment_mailbox_scan.xml
Normal file
27
briar-android/src/main/res/layout/fragment_mailbox_scan.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.briarproject.briar.android.qrcode.CameraView
|
||||
android:id="@+id/camera_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@drawable/border_qr_scanner"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1,1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -628,6 +628,8 @@
|
||||
<string name="mailbox_share_fdroid" translatable="false">https://f-droid.org/packages/org.briarproject.mailbox/</string>
|
||||
<string name="mailbox_share_gplay" translatable="false">https://play.google.com/store/apps/details?id=org.briarproject.mailbox</string>
|
||||
<string name="mailbox_share_download" translatable="false">https://briarproject.org/apk</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>
|
||||
|
||||
<!-- Conversation Settings -->
|
||||
<string name="disappearing_messages_title">Disappearing messages</string>
|
||||
|
||||
Reference in New Issue
Block a user