Compare commits

...

1 Commits

Author SHA1 Message Date
Daniel Lublin
d3692b2a97 WIP add removabledrive test ui 2021-06-09 13:44:20 +02:00
7 changed files with 251 additions and 1 deletions

View File

@@ -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"

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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));
}
}

View File

@@ -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>

View File

@@ -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>