mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
WIP add removabledrive test ui
This commit is contained in:
@@ -437,6 +437,15 @@
|
||||
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="org.briarproject.briar.android.removabledrive.RemovableDriveActivity"
|
||||
android:label="TODO Removable Drive"
|
||||
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".android.contact.add.remote.PendingContactListActivity"
|
||||
android:label="@string/pending_contact_requests"
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.briarproject.briar.android.privategroup.memberlist.GroupMemberModule;
|
||||
import org.briarproject.briar.android.privategroup.reveal.GroupRevealModule;
|
||||
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
|
||||
import org.briarproject.briar.android.privategroup.reveal.RevealContactsFragment;
|
||||
import org.briarproject.briar.android.removabledrive.RemovableDriveActivity;
|
||||
import org.briarproject.briar.android.reporting.CrashFragment;
|
||||
import org.briarproject.briar.android.reporting.CrashReportActivity;
|
||||
import org.briarproject.briar.android.reporting.ReportFormFragment;
|
||||
@@ -176,6 +177,8 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(CrashReportActivity crashReportActivity);
|
||||
|
||||
void inject(RemovableDriveActivity activity);
|
||||
|
||||
// Fragments
|
||||
|
||||
void inject(SetupFragment fragment);
|
||||
|
||||
@@ -14,5 +14,7 @@ public interface RequestCodes {
|
||||
int REQUEST_ATTACH_IMAGE = 13;
|
||||
int REQUEST_SAVE_ATTACHMENT = 14;
|
||||
int REQUEST_AVATAR_IMAGE = 15;
|
||||
int REQUEST_REMOVABLE_DRIVE_WRITE = 16;
|
||||
int REQUEST_REMOVABLE_DRIVE_READ = 17;
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
||||
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
|
||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
@@ -54,6 +53,7 @@ import org.briarproject.briar.android.forum.ForumActivity;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||
import org.briarproject.briar.android.removabledrive.RemovableDriveActivity;
|
||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.android.view.ImagePreview;
|
||||
@@ -421,6 +421,11 @@ public class ConversationActivity extends BriarActivity
|
||||
} else if (itemId == R.id.action_social_remove_person) {
|
||||
askToRemoveContact();
|
||||
return true;
|
||||
} else if (itemId == R.id.action_removable_drive_write) {
|
||||
Intent intent = new Intent(this, RemovableDriveActivity.class);
|
||||
intent.putExtra(CONTACT_ID, contactId.getInt());
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
package org.briarproject.briar.android.removabledrive;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.file.RemovableDriveTask.State;
|
||||
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.BaseFragmentListener;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
|
||||
|
||||
// TODO 19 will be our requirement for sneakernet support, right. The file apis
|
||||
// used require this.
|
||||
@RequiresApi(api = 19)
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class RemovableDriveActivity extends BriarActivity
|
||||
implements BaseFragmentListener {
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
private RemovableDriveViewModel viewModel;
|
||||
private TextView text;
|
||||
private Button writeButton;
|
||||
private Button readButton;
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
|
||||
viewModel = new ViewModelProvider(this, viewModelFactory)
|
||||
.get(RemovableDriveViewModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_removable_drive);
|
||||
text = findViewById(R.id.sneaker_text);
|
||||
writeButton = findViewById(R.id.sneaker_write);
|
||||
readButton = findViewById(R.id.sneaker_read);
|
||||
|
||||
Intent intent = getIntent();
|
||||
int contactId = intent.getIntExtra(CONTACT_ID, -1);
|
||||
if (contactId == -1) {
|
||||
writeButton.setEnabled(false);
|
||||
readButton.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO we can pass an extra named DocumentsContract.EXTRA_INITIAL_URI
|
||||
// to have the filepicker start on the usb-stick -- if get hold of URI
|
||||
// of the same. USB manager API?
|
||||
// Overall, passing this extra requires extending the ready-made
|
||||
// contracts and overriding createIntent.
|
||||
|
||||
writeButton.setText("Write for contactId " + contactId);
|
||||
ActivityResultLauncher<String> createDocument =
|
||||
registerForActivityResult(
|
||||
new ActivityResultContracts.CreateDocument(),
|
||||
uri -> write(contactId, uri));
|
||||
writeButton.setOnClickListener(
|
||||
v -> createDocument.launch(viewModel.getFileName()));
|
||||
|
||||
readButton.setText("Read for contactId " + contactId);
|
||||
ActivityResultLauncher<String> getContent =
|
||||
registerForActivityResult(
|
||||
new ActivityResultContracts.GetContent(),
|
||||
uri -> read(contactId, uri));
|
||||
readButton.setOnClickListener(
|
||||
v -> getContent.launch("application/octet-stream"));
|
||||
|
||||
LiveData<State> state;
|
||||
state = viewModel.ongoingWrite(new ContactId(contactId));
|
||||
if (state == null) {
|
||||
writeButton.setEnabled(true);
|
||||
} else {
|
||||
say("\nOngoing write:");
|
||||
writeButton.setEnabled(false);
|
||||
state.observe(this, (taskState) -> handleState("write", taskState));
|
||||
}
|
||||
state = viewModel.ongoingRead(new ContactId(contactId));
|
||||
if (state == null) {
|
||||
readButton.setEnabled(true);
|
||||
} else {
|
||||
say("\nOngoing read:");
|
||||
readButton.setEnabled(false);
|
||||
state.observe(this, (taskState) -> handleState("read", taskState));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void write(int contactId, @Nullable Uri uri) {
|
||||
if (contactId == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (uri == null) {
|
||||
say("no URI picked for write");
|
||||
return;
|
||||
}
|
||||
say("\nWriting to URI: " + uri);
|
||||
writeButton.setEnabled(false);
|
||||
LiveData<State> state = viewModel.write(new ContactId(contactId), uri);
|
||||
state.observe(this, (taskState) -> handleState("write", taskState));
|
||||
}
|
||||
|
||||
private void read(int contactId, @Nullable Uri uri) {
|
||||
if (contactId == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (uri == null) {
|
||||
say("no URI picked for read");
|
||||
return;
|
||||
}
|
||||
say("\nReading from URI: " + uri);
|
||||
readButton.setEnabled(false);
|
||||
LiveData<State> state = viewModel.read(new ContactId(contactId), uri);
|
||||
state.observe(this, (taskState) -> handleState("read", taskState));
|
||||
}
|
||||
|
||||
private void handleState(String action, State taskState) {
|
||||
say(String.format(Locale.getDefault(),
|
||||
"%s: bytes done: %d of %d. %s. %s.",
|
||||
action, taskState.getDone(), taskState.getTotal(),
|
||||
taskState.isFinished() ? "Finished" : "Ongoing",
|
||||
taskState.isFinished() ?
|
||||
(taskState.isSuccess() ? "Success" : "Failed") : ".."));
|
||||
if (taskState.isFinished()) {
|
||||
if (action.equals("write")) {
|
||||
writeButton.setEnabled(true);
|
||||
} else if (action.equals("read")) {
|
||||
readButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void say(String txt) {
|
||||
String time = new SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
||||
.format(new Date());
|
||||
txt = String.format("%s %s\n", time, txt);
|
||||
text.setText(text.getText().toString().concat(txt));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".android.removabledrive.RemovableDriveActivity">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/margin_large">
|
||||
|
||||
<Button
|
||||
android:id="@+id/sneaker_write"
|
||||
style="@style/BriarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/margin_medium"
|
||||
android:enabled="false"
|
||||
android:text=""
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:enabled="true" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/sneaker_read"
|
||||
style="@style/BriarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/margin_medium"
|
||||
android:enabled="false"
|
||||
android:text=""
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sneaker_write"
|
||||
tools:enabled="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sneaker_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/margin_large"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sneaker_read" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
@@ -40,4 +40,9 @@
|
||||
android:title="@string/delete_contact"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_removable_drive_write"
|
||||
android:title="Transfer via removable drive"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
||||
Reference in New Issue
Block a user