WIP begin RemovableDriveViewModel

Adding an activity in the front to have something to see through.

Wiring up in the back what we have in terms of manager and plugin.
parent 4a2e372c
Pipeline #6695 passed with stages
in 11 minutes and 45 seconds
......@@ -437,6 +437,15 @@
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.conversation.RemovableDriveActivity"
android:label="TODO Removable Drive"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" />
</activity>
<activity
android:name=".android.contact.add.remote.PendingContactListActivity"
android:label="@string/pending_contact_requests"
......
......@@ -24,6 +24,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.reporting.DevConfig;
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
import org.briarproject.bramble.plugin.file.RemovableDrivePluginFactory;
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
import org.briarproject.bramble.util.AndroidUtils;
......@@ -67,7 +68,6 @@ import dagger.Provides;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
......@@ -151,7 +151,9 @@ public class AppModule {
@Provides
@Singleton
PluginConfig providePluginConfig(AndroidBluetoothPluginFactory bluetooth,
AndroidTorPluginFactory tor, AndroidLanTcpPluginFactory lan) {
AndroidTorPluginFactory tor, AndroidLanTcpPluginFactory lan,
RemovableDrivePluginFactory drive) {
// TODO removabledrive: wiring up what we have for now
@NotNullByDefault
PluginConfig pluginConfig = new PluginConfig() {
......@@ -162,7 +164,7 @@ public class AppModule {
@Override
public Collection<SimplexPluginFactory> getSimplexFactories() {
return emptyList();
return singletonList(drive);
}
@Override
......
......@@ -34,6 +34,7 @@ import org.briarproject.briar.android.conversation.ConversationActivity;
import org.briarproject.briar.android.conversation.ConversationSettingsDialog;
import org.briarproject.briar.android.conversation.ImageActivity;
import org.briarproject.briar.android.conversation.ImageFragment;
import org.briarproject.briar.android.conversation.RemovableDriveActivity;
import org.briarproject.briar.android.forum.CreateForumActivity;
import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.forum.ForumListFragment;
......@@ -176,6 +177,8 @@ public interface ActivityComponent {
void inject(CrashReportActivity crashReportActivity);
void inject(RemovableDriveActivity activity);
// Fragments
void inject(SetupFragment fragment);
......
......@@ -14,5 +14,6 @@ public interface RequestCodes {
int REQUEST_ATTACH_IMAGE = 13;
int REQUEST_SAVE_ATTACHMENT = 14;
int REQUEST_AVATAR_IMAGE = 15;
int REQUEST_REMOVABLE_DRIVE_WRITE = 16;
}
......@@ -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;
......@@ -421,6 +420,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);
}
......
package org.briarproject.briar.android.conversation;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
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.util.Locale;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import static android.app.Notification.EXTRA_TITLE;
import static android.content.Intent.ACTION_CREATE_DOCUMENT;
import static android.content.Intent.CATEGORY_OPENABLE;
import static android.os.Build.VERSION.SDK_INT;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_REMOVABLE_DRIVE_WRITE;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class RemovableDriveActivity extends BriarActivity
implements BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
private RemovableDriveViewModel viewModel;
private TextView text;
@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);
// if (savedInstanceState == null) {
// showInitialFragment(RemovableDriveFragment.newInstance());
// }
text = findViewById(R.id.sneakertext);
Intent intent = getIntent();
int contactId = intent.getIntExtra(CONTACT_ID, -1);
if (contactId == -1) {
say("no specific contact");
} else {
say("contactId: " + contactId);
askWrite(contactId);
}
}
private void askWrite(int contactId) {
if (SDK_INT >= 19) {
Intent intent = getCreationIntent(contactId);
// TODO should use registerForActivityResult?
startActivityForResult(intent, REQUEST_REMOVABLE_DRIVE_WRITE);
} else {
// TODO we're only going to support 4.4+ right? so then no SDK_INT < 19
}
}
@RequiresApi(api = 19)
private Intent getCreationIntent(int contactId) {
Intent intent = new Intent(ACTION_CREATE_DOCUMENT);
intent.addCategory(CATEGORY_OPENABLE);
intent.setType("application/octet-stream");
// TODO eh, this doesn't put the filename in the save dialog
intent.putExtra(EXTRA_TITLE, viewModel.getFileName());
intent.putExtra(CONTACT_ID, contactId);
return intent;
}
@Override
protected void onActivityResult(int request, int result,
@Nullable Intent data) {
super.onActivityResult(request, result, data);
if (request == REQUEST_REMOVABLE_DRIVE_WRITE && result == RESULT_OK &&
data != null) {
// TODO can getData() be null?
write(getIntent().getIntExtra(CONTACT_ID, -1), data.getData());
}
}
private void write(int contactId, Uri uri) {
if (contactId == -1) {
throw new IllegalStateException();
}
say("uri: " + uri);
LiveData<State> state = viewModel.write(new ContactId(contactId), uri);
if (state == null) {
say("fail start write");
return;
}
state.observe(this, (taskState) -> {
say(String.format(Locale.getDefault(), "done:%d total:%d %s %s",
taskState.getDone(), taskState.getTotal(),
taskState.isFinished() ? "FINISHED" : "",
taskState.isSuccess() ? "SUCCESS" : "FAIL"));
});
}
private void say(String txt) {
String current = text.getText().toString();
text.setText(
String.format(Locale.getDefault(), "%s%s\n", current, txt));
}
}
package org.briarproject.briar.android.conversation;
import android.app.Application;
import android.net.Uri;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.file.RemovableDriveManager;
import org.briarproject.bramble.api.plugin.file.RemovableDriveTask;
import org.briarproject.bramble.api.plugin.file.RemovableDriveTask.State;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.logging.Logger;
import javax.inject.Inject;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Logger.getLogger;
@NotNullByDefault
public class RemovableDriveViewModel extends AndroidViewModel {
private static final Logger LOG =
getLogger(RemovableDriveViewModel.class.getName());
private final RemovableDriveManager manager;
@Inject
RemovableDriveViewModel(Application app,
RemovableDriveManager removableDriveManager) {
super(app);
this.manager = removableDriveManager;
}
LiveData<State> write(ContactId contactId, Uri uri) {
// TODO create a tempfile for now, the task will be able to deal with Uris
// later when there is an android extension of AbstractRemovableDrivePlugin
File f;
try {
f = File.createTempFile("sync", ".tmp");
} catch (IOException e) {
e.printStackTrace();
return null;
}
if (f == null) {
return null;
}
TransportProperties p = new TransportProperties();
LOG.info("write path: " + f.getAbsolutePath());
RemovableDriveTask task = manager.startWriterTask(contactId, p);
MutableLiveData<State> state = new MutableLiveData<>();
task.addObserver((taskState) -> {
state.postValue(taskState);
});
return state;
}
String getFileName() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS",
Locale.getDefault());
return sdf.format(new Date());
}
}
......@@ -4,6 +4,7 @@ import org.briarproject.briar.android.contact.add.remote.AddContactViewModel;
import org.briarproject.briar.android.contact.add.remote.PendingContactListViewModel;
import org.briarproject.briar.android.conversation.ConversationViewModel;
import org.briarproject.briar.android.conversation.ImageViewModel;
import org.briarproject.briar.android.conversation.RemovableDriveViewModel;
import javax.inject.Singleton;
......@@ -40,8 +41,15 @@ public abstract class ViewModelModule {
abstract ViewModel bindPendingRequestsViewModel(
PendingContactListViewModel pendingContactListViewModel);
@Binds
@IntoMap
@ViewModelKey(RemovableDriveViewModel.class)
abstract ViewModel bindRemovableDriveViewModel(
RemovableDriveViewModel removableDriveViewModel);
@Binds
@Singleton
abstract ViewModelProvider.Factory bindViewModelFactory(
ViewModelFactory viewModelFactory);
......
<?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.conversation.RemovableDriveActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/margin_large">
<TextView
android:id="@+id/sneakertext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/margin_large"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</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>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment