mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 13:49:53 +01:00
Simple version of Connect via Bluetooth UI
This commit is contained in:
@@ -0,0 +1,120 @@
|
|||||||
|
package org.briarproject.briar.android.conversation;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
||||||
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.contact.ContactItem;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
class BluetoothConnecter {
|
||||||
|
|
||||||
|
private final Logger LOG = getLogger(BluetoothConnecter.class.getName());
|
||||||
|
|
||||||
|
private final Application app;
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final AndroidExecutor androidExecutor;
|
||||||
|
|
||||||
|
private final BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
private final Plugin bluetoothPlugin;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BluetoothConnecter(Application app,
|
||||||
|
PluginManager pluginManager,
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
|
AndroidExecutor androidExecutor) {
|
||||||
|
this.app = app;
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.androidExecutor = androidExecutor;
|
||||||
|
this.bluetoothPlugin = pluginManager.getPlugin(BluetoothConstants.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showDialog(Context ctx,
|
||||||
|
ActivityResultLauncher<String> permissionRequest) {
|
||||||
|
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme)
|
||||||
|
.setTitle(R.string.dialog_title_connect_via_bluetooth)
|
||||||
|
.setMessage(R.string.dialog_message_connect_via_bluetooth)
|
||||||
|
.setPositiveButton(R.string.start, (dialog, which) ->
|
||||||
|
permissionRequest.launch(ACCESS_FINE_LOCATION))
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void onLocationPermissionResult(boolean result,
|
||||||
|
ActivityResultLauncher<Integer> bluetoothDiscoverableRequest) {
|
||||||
|
if (result) {
|
||||||
|
if (isBluetoothSupported()) {
|
||||||
|
bluetoothDiscoverableRequest.launch(120);
|
||||||
|
} else {
|
||||||
|
showToast(R.string.toast_connect_via_bluetooth_error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// could also show the same dialog as KeyAgreementActivity
|
||||||
|
showToast(R.string.permission_location_denied_body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBluetoothSupported() {
|
||||||
|
return bt != null && bluetoothPlugin != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void onBluetoothDiscoverable(boolean result, ContactItem contact) {
|
||||||
|
if (result) {
|
||||||
|
connect(contact);
|
||||||
|
} else {
|
||||||
|
showToast(R.string.toast_connect_via_bluetooth_not_discoverable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect(ContactItem contact) {
|
||||||
|
// TODO
|
||||||
|
// * enable bluetooth connections setting, if not enabled
|
||||||
|
// * wait for plugin to become active
|
||||||
|
ioExecutor.execute(() -> {
|
||||||
|
Random r = new Random();
|
||||||
|
try {
|
||||||
|
showToast(R.string.toast_connect_via_bluetooth_start);
|
||||||
|
// TODO do real work here
|
||||||
|
Thread.sleep(r.nextInt(3000) + 3000);
|
||||||
|
if (r.nextBoolean()) {
|
||||||
|
showToast(R.string.toast_connect_via_bluetooth_success);
|
||||||
|
} else {
|
||||||
|
showToast(R.string.toast_connect_via_bluetooth_error);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showToast(@StringRes int res) {
|
||||||
|
androidExecutor.runOnUiThread(() ->
|
||||||
|
Toast.makeText(app, res, Toast.LENGTH_LONG).show()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ import org.briarproject.briar.android.activity.BriarActivity;
|
|||||||
import org.briarproject.briar.android.attachment.AttachmentItem;
|
import org.briarproject.briar.android.attachment.AttachmentItem;
|
||||||
import org.briarproject.briar.android.attachment.AttachmentRetriever;
|
import org.briarproject.briar.android.attachment.AttachmentRetriever;
|
||||||
import org.briarproject.briar.android.blog.BlogActivity;
|
import org.briarproject.briar.android.blog.BlogActivity;
|
||||||
|
import org.briarproject.briar.android.contact.ContactItem;
|
||||||
import org.briarproject.briar.android.conversation.ConversationVisitor.AttachmentCache;
|
import org.briarproject.briar.android.conversation.ConversationVisitor.AttachmentCache;
|
||||||
import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache;
|
import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache;
|
||||||
import org.briarproject.briar.android.forum.ForumActivity;
|
import org.briarproject.briar.android.forum.ForumActivity;
|
||||||
@@ -91,6 +92,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@@ -211,6 +214,21 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
private volatile ContactId contactId;
|
private volatile ContactId contactId;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Integer> bluetoothDiscoverableRequest =
|
||||||
|
registerForActivityResult(new RequestBluetoothDiscoverable(), r -> {
|
||||||
|
// MenuItem only gets enabled after contactItem has loaded
|
||||||
|
ContactItem contact =
|
||||||
|
requireNonNull(viewModel.getContactItem().getValue());
|
||||||
|
BluetoothConnecter bc = viewModel.getBluetoothConnecter();
|
||||||
|
bc.onBluetoothDiscoverable(r, contact);
|
||||||
|
});
|
||||||
|
private final ActivityResultLauncher<String> permissionRequest =
|
||||||
|
registerForActivityResult(new RequestPermission(), result -> {
|
||||||
|
BluetoothConnecter bc = viewModel.getBluetoothConnecter();
|
||||||
|
bc.onLocationPermissionResult(result,
|
||||||
|
bluetoothDiscoverableRequest);
|
||||||
|
});
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
if (SDK_INT >= 21) {
|
if (SDK_INT >= 21) {
|
||||||
@@ -370,9 +388,11 @@ public class ConversationActivity extends BriarActivity
|
|||||||
this::showIntroductionOnboarding);
|
this::showIntroductionOnboarding);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// enable alias action if available
|
// enable alias and bluetooth action once available
|
||||||
observeOnce(viewModel.getContactItem(), this, contact ->
|
observeOnce(viewModel.getContactItem(), this, contact -> {
|
||||||
menu.findItem(R.id.action_set_alias).setEnabled(true));
|
menu.findItem(R.id.action_set_alias).setEnabled(true);
|
||||||
|
menu.findItem(R.id.action_connect_via_bluetooth).setEnabled(true);
|
||||||
|
});
|
||||||
// Show auto-delete menu item if feature is enabled
|
// Show auto-delete menu item if feature is enabled
|
||||||
if (featureFlags.shouldEnableDisappearingMessages()) {
|
if (featureFlags.shouldEnableDisappearingMessages()) {
|
||||||
MenuItem item = menu.findItem(R.id.action_conversation_settings);
|
MenuItem item = menu.findItem(R.id.action_conversation_settings);
|
||||||
@@ -381,40 +401,39 @@ public class ConversationActivity extends BriarActivity
|
|||||||
viewModel.getPrivateMessageFormat().observe(this, format ->
|
viewModel.getPrivateMessageFormat().observe(this, format ->
|
||||||
item.setEnabled(format == TEXT_IMAGES_AUTO_DELETE));
|
item.setEnabled(format == TEXT_IMAGES_AUTO_DELETE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
// Handle presses on the action bar items
|
// contactId gets set before in onCreate()
|
||||||
switch (item.getItemId()) {
|
int itemId = item.getItemId();
|
||||||
case android.R.id.home:
|
if (itemId == android.R.id.home) {
|
||||||
onBackPressed();
|
onBackPressed();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_introduction:
|
} else if (itemId == R.id.action_introduction) {
|
||||||
if (contactId == null) return false;
|
Intent intent = new Intent(this, IntroductionActivity.class);
|
||||||
Intent intent = new Intent(this, IntroductionActivity.class);
|
intent.putExtra(CONTACT_ID, contactId.getInt());
|
||||||
intent.putExtra(CONTACT_ID, contactId.getInt());
|
startActivityForResult(intent, REQUEST_INTRODUCTION);
|
||||||
startActivityForResult(intent, REQUEST_INTRODUCTION);
|
return true;
|
||||||
return true;
|
} else if (itemId == R.id.action_set_alias) {
|
||||||
case R.id.action_set_alias:
|
AliasDialogFragment.newInstance().show(
|
||||||
AliasDialogFragment.newInstance().show(
|
getSupportFragmentManager(), AliasDialogFragment.TAG);
|
||||||
getSupportFragmentManager(), AliasDialogFragment.TAG);
|
return true;
|
||||||
return true;
|
} else if (itemId == R.id.action_conversation_settings) {
|
||||||
case R.id.action_conversation_settings:
|
onAutoDeleteTimerNoticeClicked();
|
||||||
if (contactId == null) return false;
|
return true;
|
||||||
onAutoDeleteTimerNoticeClicked();
|
} else if (itemId == R.id.action_connect_via_bluetooth) {
|
||||||
return true;
|
BluetoothConnecter.showDialog(this, permissionRequest);
|
||||||
case R.id.action_delete_all_messages:
|
return true;
|
||||||
askToDeleteAllMessages();
|
} else if (itemId == R.id.action_delete_all_messages) {
|
||||||
return true;
|
askToDeleteAllMessages();
|
||||||
case R.id.action_social_remove_person:
|
return true;
|
||||||
askToRemoveContact();
|
} else if (itemId == R.id.action_social_remove_person) {
|
||||||
return true;
|
askToRemoveContact();
|
||||||
default:
|
return true;
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ public class ConversationViewModel extends DbViewModel
|
|||||||
private final AttachmentCreator attachmentCreator;
|
private final AttachmentCreator attachmentCreator;
|
||||||
private final AutoDeleteManager autoDeleteManager;
|
private final AutoDeleteManager autoDeleteManager;
|
||||||
private final ConversationManager conversationManager;
|
private final ConversationManager conversationManager;
|
||||||
|
private final BluetoothConnecter bluetoothConnecter;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ContactId contactId = null;
|
private ContactId contactId = null;
|
||||||
@@ -139,7 +140,8 @@ public class ConversationViewModel extends DbViewModel
|
|||||||
AttachmentRetriever attachmentRetriever,
|
AttachmentRetriever attachmentRetriever,
|
||||||
AttachmentCreator attachmentCreator,
|
AttachmentCreator attachmentCreator,
|
||||||
AutoDeleteManager autoDeleteManager,
|
AutoDeleteManager autoDeleteManager,
|
||||||
ConversationManager conversationManager) {
|
ConversationManager conversationManager,
|
||||||
|
BluetoothConnecter bluetoothConnecter) {
|
||||||
super(application, dbExecutor, lifecycleManager, db, androidExecutor);
|
super(application, dbExecutor, lifecycleManager, db, androidExecutor);
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
@@ -152,6 +154,7 @@ public class ConversationViewModel extends DbViewModel
|
|||||||
this.attachmentCreator = attachmentCreator;
|
this.attachmentCreator = attachmentCreator;
|
||||||
this.autoDeleteManager = autoDeleteManager;
|
this.autoDeleteManager = autoDeleteManager;
|
||||||
this.conversationManager = conversationManager;
|
this.conversationManager = conversationManager;
|
||||||
|
this.bluetoothConnecter = bluetoothConnecter;
|
||||||
messagingGroupId = map(contactItem, c ->
|
messagingGroupId = map(contactItem, c ->
|
||||||
messagingManager.getContactGroup(c.getContact()).getId());
|
messagingManager.getContactGroup(c.getContact()).getId());
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
@@ -411,6 +414,10 @@ public class ConversationViewModel extends DbViewModel
|
|||||||
return attachmentRetriever;
|
return attachmentRetriever;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BluetoothConnecter getBluetoothConnecter() {
|
||||||
|
return bluetoothConnecter;
|
||||||
|
}
|
||||||
|
|
||||||
LiveData<ContactItem> getContactItem() {
|
LiveData<ContactItem> getContactItem() {
|
||||||
return contactItem;
|
return contactItem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.briarproject.briar.android.conversation;
|
||||||
|
|
||||||
|
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
|
||||||
|
class RequestBluetoothDiscoverable
|
||||||
|
extends ActivityResultContract<Integer, Boolean> {
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,12 @@
|
|||||||
app:showAsAction="never"
|
app:showAsAction="never"
|
||||||
tools:visible="true" />
|
tools:visible="true" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_connect_via_bluetooth"
|
||||||
|
android:enabled="false"
|
||||||
|
android:title="@string/menu_item_connect_via_bluetooth"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_delete_all_messages"
|
android:id="@+id/action_delete_all_messages"
|
||||||
android:title="@string/delete_all_messages"
|
android:title="@string/delete_all_messages"
|
||||||
|
|||||||
@@ -142,6 +142,7 @@
|
|||||||
<string name="allow">Allow</string>
|
<string name="allow">Allow</string>
|
||||||
<string name="open">Open</string>
|
<string name="open">Open</string>
|
||||||
<string name="change">Change</string>
|
<string name="change">Change</string>
|
||||||
|
<string name="start">Start</string>
|
||||||
<string name="no_data">No data</string>
|
<string name="no_data">No data</string>
|
||||||
<string name="ellipsis">…</string>
|
<string name="ellipsis">…</string>
|
||||||
<string name="text_too_long">The entered text is too long</string>
|
<string name="text_too_long">The entered text is too long</string>
|
||||||
@@ -168,6 +169,13 @@
|
|||||||
<string name="set_contact_alias">Change contact name</string>
|
<string name="set_contact_alias">Change contact name</string>
|
||||||
<string name="set_contact_alias_hint">Contact name</string>
|
<string name="set_contact_alias_hint">Contact name</string>
|
||||||
<string name="menu_item_disappearing_messages">Disappearing messages</string>
|
<string name="menu_item_disappearing_messages">Disappearing messages</string>
|
||||||
|
<string name="menu_item_connect_via_bluetooth">Connect via Bluetooth</string>
|
||||||
|
<string name="dialog_title_connect_via_bluetooth">Connect via Bluetooth</string>
|
||||||
|
<string name="dialog_message_connect_via_bluetooth">Your contact needs to be in close proximity for this to work. They need to press start at the same time as you and confirm the following system dialog.</string>
|
||||||
|
<string name="toast_connect_via_bluetooth_not_discoverable">Can not continue without Bluetooth</string>
|
||||||
|
<string name="toast_connect_via_bluetooth_start">Connecting via Bluetooth…</string>
|
||||||
|
<string name="toast_connect_via_bluetooth_success">Successfully connected via Bluetooth</string>
|
||||||
|
<string name="toast_connect_via_bluetooth_error">Could not connect via Bluetooth</string>
|
||||||
<!-- The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more." -->
|
<!-- The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more." -->
|
||||||
<string name="auto_delete_msg_you_enabled">Your messages will disappear after %1$s. %2$s</string>
|
<string name="auto_delete_msg_you_enabled">Your messages will disappear after %1$s. %2$s</string>
|
||||||
<!-- The placeholder at the end will add "Tap to learn more." -->
|
<!-- The placeholder at the end will add "Tap to learn more." -->
|
||||||
|
|||||||
Reference in New Issue
Block a user