diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java index 58ab2ef0c..de989877f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java @@ -11,7 +11,6 @@ public interface RequestCodes { int REQUEST_RINGTONE = 7; int REQUEST_PERMISSION_CAMERA_LOCATION = 8; int REQUEST_DOZE_WHITELISTING = 9; - int REQUEST_BLUETOOTH_DISCOVERABLE = 10; int REQUEST_UNLOCK = 11; int REQUEST_KEYGUARD_UNLOCK = 12; int REQUEST_ATTACH_IMAGE = 13; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java index eb56baeeb..126590ae1 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java @@ -1,16 +1,12 @@ package org.briarproject.briar.android.contact.add.nearby; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.Bundle; import android.view.MenuItem; import android.widget.Toast; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; -import org.briarproject.bramble.api.nullsafety.NullSafety; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; @@ -21,25 +17,25 @@ import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; +import org.briarproject.briar.android.util.RequestBluetoothDiscoverable; import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; +import androidx.activity.result.ActivityResultLauncher; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; -import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.widget.Toast.LENGTH_LONG; import static java.util.Objects.requireNonNull; import static java.util.logging.Logger.getLogger; -import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_BLUETOOTH_DISCOVERABLE; import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.ACCEPTED; import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED; -import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.UNKNOWN; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -55,14 +51,9 @@ public class AddNearbyContactActivity extends BriarActivity private AddNearbyContactViewModel viewModel; private AddNearbyContactPermissionManager permissionManager; - /** - * Set to true in onPostResume() and false in onPause(). This prevents the - * QR code fragment from being shown if onRequestPermissionsResult() is - * called while the activity is paused, which could cause a crash due to - * https://issuetracker.google.com/issues/37067655. - */ - private boolean isResumed = false; - private BroadcastReceiver bluetoothReceiver = null; + private final ActivityResultLauncher bluetoothLauncher = + registerForActivityResult(new RequestBluetoothDiscoverable(), + this::onBluetoothDiscoverableResult); @Override public void injectActivity(ActivityComponent component) { @@ -79,21 +70,14 @@ public class AddNearbyContactActivity extends BriarActivity setContentView(R.layout.activity_fragment_container_toolbar); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - NullSafety.requireNonNull(getSupportActionBar()) - .setDisplayHomeAsUpEnabled(true); + requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); if (state == null) { showInitialFragment(AddNearbyContactIntroFragment.newInstance()); } - IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); - bluetoothReceiver = new BluetoothStateReceiver(); - registerReceiver(bluetoothReceiver, filter); - viewModel.getWasContinueClicked().observe(this, clicked -> { - if (clicked && permissionManager.checkPermissions()) { - showQrCodeFragmentIfAllowed(); - } - }); - viewModel.getTransportStateChanged().observeEvent(this, - t -> showQrCodeFragmentIfAllowed()); + viewModel.getCheckPermissions().observeEvent(this, check -> + permissionManager.checkPermissions()); // never false + viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> + requestBluetoothDiscoverable()); // never false viewModel.getShowQrCodeFragment().observeEvent(this, show -> { if (show) showQrCodeFragment(); }); @@ -113,37 +97,23 @@ public class AddNearbyContactActivity extends BriarActivity @Override protected void onPostResume() { super.onPostResume(); - isResumed = true; - // Workaround for - // https://code.google.com/p/android/issues/detail?id=190966 - showQrCodeFragmentIfAllowed(); + viewModel.setIsActivityResumed(true); } @Override protected void onPause() { super.onPause(); - isResumed = false; + viewModel.setIsActivityResumed(false); } - @Override - public void onDestroy() { - super.onDestroy(); - if (bluetoothReceiver != null) unregisterReceiver(bluetoothReceiver); - } - - @Override - public void onActivityResult(int request, int result, - @Nullable Intent data) { - if (request == REQUEST_BLUETOOTH_DISCOVERABLE) { - if (result == RESULT_CANCELED) { - LOG.info("Bluetooth discoverability was refused"); - viewModel.bluetoothDecision = REFUSED; - } else { - LOG.info("Bluetooth discoverability was accepted"); - viewModel.bluetoothDecision = ACCEPTED; - } - showQrCodeFragmentIfAllowed(); - } else super.onActivityResult(request, result, data); + private void onBluetoothDiscoverableResult(boolean discoverable) { + if (discoverable) { + LOG.info("Bluetooth discoverability was accepted"); + viewModel.setBluetoothDecision(ACCEPTED); + } else { + LOG.info("Bluetooth discoverability was refused"); + viewModel.setBluetoothDecision(REFUSED); + } } @Override @@ -161,14 +131,16 @@ public class AddNearbyContactActivity extends BriarActivity super.onRequestPermissionsResult(requestCode, permissions, grantResults); permissionManager.onRequestPermissionsResult(requestCode, permissions, - grantResults, this::showQrCodeFragmentIfAllowed); + grantResults, viewModel::showQrCodeFragmentIfAllowed); } @Override public void onBackPressed() { if (viewModel.getState().getValue() instanceof Failed) { - // finish this activity when going back in failed state - supportFinishAfterTransition(); + // re-create this activity when going back in failed state + Intent i = new Intent(this, AddNearbyContactActivity.class); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); + startActivity(i); } else { super.onBackPressed(); } @@ -176,41 +148,15 @@ public class AddNearbyContactActivity extends BriarActivity private void requestBluetoothDiscoverable() { if (!viewModel.isBluetoothSupported()) { - viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER; - showQrCodeFragmentIfAllowed(); + viewModel.setBluetoothDecision(BluetoothDecision.NO_ADAPTER); } else { Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE); if (i.resolveActivity(getPackageManager()) != null) { LOG.info("Asking for Bluetooth discoverability"); - viewModel.bluetoothDecision = BluetoothDecision.WAITING; - startActivityForResult(i, REQUEST_BLUETOOTH_DISCOVERABLE); + viewModel.setBluetoothDecision(BluetoothDecision.WAITING); + bluetoothLauncher.launch(120); // 2min discoverable } else { - viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER; - showQrCodeFragmentIfAllowed(); - } - } - } - - @SuppressWarnings("StatementWithEmptyBody") - private void showQrCodeFragmentIfAllowed() { - boolean continueClicked = // never set to null - NullSafety.requireNonNull( - viewModel.getWasContinueClicked().getValue()); - boolean permissionsGranted = - permissionManager.areEssentialPermissionsGranted(); - if (isResumed && continueClicked && permissionsGranted) { - if (viewModel.isWifiReady() && viewModel.isBluetoothReady()) { - LOG.info("Wifi and Bluetooth are ready"); - viewModel.startAddingContact(); - } else { - viewModel.enableWifiIfWeShould(); - if (viewModel.bluetoothDecision == UNKNOWN) { - requestBluetoothDiscoverable(); - } else if (viewModel.bluetoothDecision == REFUSED) { - // Ask again when the user clicks "continue" - } else { - viewModel.enableBluetoothIfWeShould(); - } + viewModel.setBluetoothDecision(BluetoothDecision.NO_ADAPTER); } } } @@ -233,11 +179,6 @@ public class AddNearbyContactActivity extends BriarActivity ((ContactExchangeFinished) state).result; onContactExchangeResult(result); } else if (state instanceof Failed) { - // Remove navigation icon, so user can't go back when failed - // ErrorFragment will finish or relaunch this activity - Toolbar toolbar = findViewById(R.id.toolbar); - toolbar.setNavigationIcon(null); - Boolean qrCodeTooOld = ((Failed) state).qrCodeTooOld; onAddingContactFailed(qrCodeTooOld); } @@ -286,11 +227,4 @@ public class AddNearbyContactActivity extends BriarActivity showNextFragment(new AddNearbyContactErrorFragment()); } - private class BluetoothStateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - LOG.info("Bluetooth scan mode changed"); - showQrCodeFragmentIfAllowed(); - } - } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java index c08a8cdc9..6f0a841cb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java @@ -171,10 +171,8 @@ public class AddNearbyContactFragment extends BaseFragment status.setText(R.string.waiting_for_contact_to_scan); } else if (state instanceof KeyAgreementStarted) { qrCodeView.setVisibility(INVISIBLE); - statusView.setVisibility(VISIBLE); status.setText(R.string.authenticating_with_device); } else if (state instanceof ContactExchangeStarted) { - statusView.setVisibility(VISIBLE); status.setText(R.string.exchanging_contact_details); } else if (state instanceof Failed) { // the activity will replace this fragment with an error fragment diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactPermissionManager.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactPermissionManager.java index 1244da3ae..937799e10 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactPermissionManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactPermissionManager.java @@ -1,5 +1,7 @@ package org.briarproject.briar.android.contact.add.nearby; +import android.content.Context; + import org.briarproject.briar.R; import org.briarproject.briar.android.activity.BaseActivity; @@ -11,6 +13,8 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.CAMERA; 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.activity.RequestCodes.REQUEST_PERMISSION_CAMERA_LOCATION; import static org.briarproject.briar.android.util.UiUtils.getGoToSettingsListener; @@ -37,6 +41,15 @@ class AddNearbyContactPermissionManager { locationPermission = Permission.UNKNOWN; } + static boolean areEssentialPermissionsGranted(Context ctx, + boolean isBluetoothSupported) { + int ok = PERMISSION_GRANTED; + return checkSelfPermission(ctx, CAMERA) == ok && + (SDK_INT < 23 || + checkSelfPermission(ctx, ACCESS_FINE_LOCATION) == ok || + !isBluetoothSupported); + } + boolean areEssentialPermissionsGranted() { return cameraPermission == Permission.GRANTED && (SDK_INT < 23 || locationPermission == Permission.GRANTED || @@ -147,8 +160,7 @@ class AddNearbyContactPermissionManager { } private boolean shouldShowRationale(String permission) { - return ActivityCompat - .shouldShowRequestPermissionRationale(ctx, permission); + return shouldShowRequestPermissionRationale(ctx, permission); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java index f5f9da9ee..46182ce29 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java @@ -2,6 +2,10 @@ package org.briarproject.briar.android.contact.add.nearby; import android.app.Application; import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.graphics.Bitmap; import android.util.DisplayMetrics; import android.widget.Toast; @@ -39,6 +43,7 @@ import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.event.TransportStateEvent; +import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.briar.R; import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished; import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Error; @@ -64,6 +69,7 @@ import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; import static android.widget.Toast.LENGTH_LONG; import static java.util.Objects.requireNonNull; @@ -75,6 +81,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager.areEssentialPermissionsGranted; import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED; import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.UNKNOWN; @@ -116,6 +123,7 @@ class AddNearbyContactViewModel extends AndroidViewModel private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); private final EventBus eventBus; + private final AndroidExecutor androidExecutor; private final Executor ioExecutor; private final PluginManager pluginManager; private final PayloadEncoder payloadEncoder; @@ -124,28 +132,28 @@ class AddNearbyContactViewModel extends AndroidViewModel private final ContactExchangeManager contactExchangeManager; private final ConnectionManager connectionManager; - /** - * Set to true when the continue button is clicked, and false when the QR - * code fragment is shown. This prevents the QR code fragment from being - * shown automatically before the continue button has been clicked. - */ - private final MutableLiveData wasContinueClicked = - new MutableLiveData<>(false); - private final MutableLiveEvent showQrCodeFragment = + private final MutableLiveEvent checkPermissions = new MutableLiveEvent<>(); - private final MutableLiveEvent transportStateChanged = + private final MutableLiveEvent requestBluetoothDiscoverable = + new MutableLiveEvent<>(); + private final MutableLiveEvent showQrCodeFragment = new MutableLiveEvent<>(); private final MutableLiveData state = new MutableLiveData<>(); final QrCodeDecoder qrCodeDecoder; + final BroadcastReceiver bluetoothReceiver = new BluetoothStateReceiver(); @Nullable private final BluetoothAdapter bt; @Nullable private final Plugin wifiPlugin, bluetoothPlugin; + // UiThread - BluetoothDecision bluetoothDecision = BluetoothDecision.UNKNOWN; + private BluetoothDecision bluetoothDecision = BluetoothDecision.UNKNOWN; + + private boolean wasContinueClicked = false; + private boolean isActivityResumed = false; /** * Records whether we've enabled the wifi plugin so we don't enable it more @@ -166,6 +174,7 @@ class AddNearbyContactViewModel extends AndroidViewModel @Inject AddNearbyContactViewModel(Application app, EventBus eventBus, + AndroidExecutor androidExecutor, @IoExecutor Executor ioExecutor, PluginManager pluginManager, PayloadEncoder payloadEncoder, @@ -175,6 +184,7 @@ class AddNearbyContactViewModel extends AndroidViewModel ConnectionManager connectionManager) { super(app); this.eventBus = eventBus; + this.androidExecutor = androidExecutor; this.ioExecutor = ioExecutor; this.pluginManager = pluginManager; this.payloadEncoder = payloadEncoder; @@ -185,13 +195,16 @@ class AddNearbyContactViewModel extends AndroidViewModel bt = BluetoothAdapter.getDefaultAdapter(); wifiPlugin = pluginManager.getPlugin(LanTcpConstants.ID); bluetoothPlugin = pluginManager.getPlugin(BluetoothConstants.ID); - qrCodeDecoder = new QrCodeDecoder(ioExecutor, this); + qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this); eventBus.addListener(this); + IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); + getApplication().registerReceiver(bluetoothReceiver, filter); } @Override protected void onCleared() { super.onCleared(); + getApplication().unregisterReceiver(bluetoothReceiver); eventBus.removeListener(this); stopListening(); } @@ -201,7 +214,9 @@ class AddNearbyContactViewModel extends AndroidViewModel if (bluetoothDecision == REFUSED) { bluetoothDecision = UNKNOWN; // Ask again } - wasContinueClicked.setValue(true); + wasContinueClicked = true; + checkPermissions.setEvent(true); + showQrCodeFragmentIfAllowed(); } @UiThread @@ -266,7 +281,7 @@ class AddNearbyContactViewModel extends AndroidViewModel void startAddingContact() { // If we return to the intro fragment, the continue button needs to be // clicked again before showing the QR code fragment - wasContinueClicked.setValue(false); + wasContinueClicked = false; // If we return to the intro fragment, ask for Bluetooth // discoverability again before showing the QR code fragment bluetoothDecision = UNKNOWN; @@ -310,12 +325,12 @@ class AddNearbyContactViewModel extends AndroidViewModel if (LOG.isLoggable(INFO)) { LOG.info("Bluetooth state changed to " + t.getState()); } - transportStateChanged.setEvent(t.getTransportId()); + showQrCodeFragmentIfAllowed(); } else if (t.getTransportId().equals(LanTcpConstants.ID)) { if (LOG.isLoggable(INFO)) { LOG.info("Wifi state changed to " + t.getState()); } - transportStateChanged.setEvent(t.getTransportId()); + showQrCodeFragmentIfAllowed(); } } else if (e instanceof KeyAgreementListeningEvent) { LOG.info("KeyAgreementListeningEvent received"); @@ -344,6 +359,28 @@ class AddNearbyContactViewModel extends AndroidViewModel } } + @SuppressWarnings("StatementWithEmptyBody") + @UiThread + void showQrCodeFragmentIfAllowed() { + boolean permissionsGranted = areEssentialPermissionsGranted( + getApplication(), isBluetoothSupported()); + if (isActivityResumed && wasContinueClicked && permissionsGranted) { + if (isWifiReady() && isBluetoothReady()) { + LOG.info("Wifi and Bluetooth are ready"); + startAddingContact(); + } else { + enableWifiIfWeShould(); + if (bluetoothDecision == UNKNOWN) { + requestBluetoothDiscoverable.setEvent(true); + } else if (bluetoothDecision == REFUSED) { + // Ask again when the user clicks "continue" + } else { + enableBluetoothIfWeShould(); + } + } + } + } + /** * This sets the QR code by setting the state to KeyAgreementListening. */ @@ -383,8 +420,8 @@ class AddNearbyContactViewModel extends AndroidViewModel state.postValue(new AddContactState.Failed(e.isTooOld())); } catch (IOException | IllegalArgumentException e) { LOG.log(WARNING, "QR Code Invalid", e); - Toast.makeText(getApplication(), R.string.qr_code_invalid, - LENGTH_LONG).show(); + androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(), + R.string.qr_code_invalid, LENGTH_LONG).show()); resetPayloadFlags(); state.postValue(new AddContactState.Failed()); } @@ -423,6 +460,15 @@ class AddNearbyContactViewModel extends AndroidViewModel }); } + private class BluetoothStateReceiver extends BroadcastReceiver { + @UiThread + @Override + public void onReceive(Context context, Intent intent) { + LOG.info("Bluetooth scan mode changed"); + showQrCodeFragmentIfAllowed(); + } + } + private void tryToClose(DuplexTransportConnection conn) { try { conn.getReader().dispose(true, true); @@ -432,16 +478,33 @@ class AddNearbyContactViewModel extends AndroidViewModel } } - LiveData getWasContinueClicked() { - return wasContinueClicked; + /** + * Set to true in onPostResume() and false in onPause(). This prevents the + * QR code fragment from being shown if onRequestPermissionsResult() is + * called while the activity is paused, which could cause a crash due to + * https://issuetracker.google.com/issues/37067655. + * TODO check if this is still happening when using new permission requesting + */ + @UiThread + void setIsActivityResumed(boolean resumed) { + isActivityResumed = resumed; + // Workaround for + // https://code.google.com/p/android/issues/detail?id=190966 + showQrCodeFragmentIfAllowed(); } - /** - * Receives an event when the transport state of the WiFi or Bluetooth - * plugins changes. - */ - LiveEvent getTransportStateChanged() { - return transportStateChanged; + @UiThread + void setBluetoothDecision(BluetoothDecision decision) { + bluetoothDecision = decision; + showQrCodeFragmentIfAllowed(); + } + + LiveEvent getCheckPermissions() { + return checkPermissions; + } + + LiveEvent getRequestBluetoothDiscoverable() { + return requestBluetoothDiscoverable; } LiveEvent getShowQrCodeFragment() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/QrCodeDecoder.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/QrCodeDecoder.java index ad61baa3c..bbb9dc875 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/QrCodeDecoder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/QrCodeDecoder.java @@ -18,6 +18,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.system.AndroidExecutor; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -35,6 +36,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback { private static final Logger LOG = getLogger(QrCodeDecoder.class.getName()); + private final AndroidExecutor androidExecutor; private final Executor ioExecutor; private final Reader reader = new QRCodeReader(); private final ResultCallback callback; @@ -42,7 +44,9 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback { private Camera camera = null; private int cameraIndex = 0; - QrCodeDecoder(@IoExecutor Executor ioExecutor, ResultCallback callback) { + QrCodeDecoder(AndroidExecutor androidExecutor, + @IoExecutor Executor ioExecutor, ResultCallback callback) { + this.androidExecutor = androidExecutor; this.ioExecutor = ioExecutor; this.callback = callback; } @@ -104,9 +108,9 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback { LOG.warning("Invalid preview frame"); } finally { reader.reset(); + androidExecutor.runOnUiThread(this::askForPreviewFrame); } }); - askForPreviewFrame(); } private static BinaryBitmap binarize(byte[] data, int width, int height, diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java b/briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java new file mode 100644 index 000000000..8288aedac --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java @@ -0,0 +1,31 @@ +package org.briarproject.briar.android.util; + + +import android.content.Context; +import android.content.Intent; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import androidx.activity.result.contract.ActivityResultContract; +import androidx.annotation.Nullable; + +import static android.app.Activity.RESULT_CANCELED; +import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; +import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION; + +@NotNullByDefault +public class RequestBluetoothDiscoverable + extends ActivityResultContract { + + @Override + public Intent createIntent(Context context, Integer duration) { + Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE); + i.putExtra(EXTRA_DISCOVERABLE_DURATION, duration); + return i; + } + + @Override + public Boolean parseResult(int resultCode, @Nullable Intent intent) { + return resultCode != RESULT_CANCELED; + } +} diff --git a/briar-android/src/main/res/layout/activity_fragment_container_toolbar.xml b/briar-android/src/main/res/layout/activity_fragment_container_toolbar.xml index c9867a627..bab5a0b80 100644 --- a/briar-android/src/main/res/layout/activity_fragment_container_toolbar.xml +++ b/briar-android/src/main/res/layout/activity_fragment_container_toolbar.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".android.contact.add.nearby.KeyAgreementActivity"> + tools:context=".android.contact.add.nearby.AddNearbyContactActivity">