Improve UI for shard return

This commit is contained in:
ameba23
2021-04-13 18:21:55 +02:00
parent d2abd6dcc2
commit b07206c898
8 changed files with 123 additions and 141 deletions

View File

@@ -87,6 +87,7 @@ import org.briarproject.briar.android.socialbackup.DistributedBackupActivity;
import org.briarproject.briar.android.socialbackup.ExistingBackupFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardSuccessFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment;
@@ -293,4 +294,6 @@ public interface ActivityComponent {
void inject(CustodianReturnShardFragment custodianReturnShardFragment);
void inject(OwnerReturnShardFragment ownerReturnShardFragment);
void inject(CustodianReturnShardSuccessFragment custodianReturnShardSuccessFragment);
}

View File

@@ -61,7 +61,7 @@ public class DistributedBackupActivity extends BriarActivity implements
@Override
public void contactsSelected(Collection<ContactId> contacts) {
Toast.makeText(this,
String.format("selected %d contacts", contacts.size()),
String.format("Selected %d contacts", contacts.size()),
Toast.LENGTH_SHORT).show();
custodians = contacts;
ThresholdSelectorFragment fragment =

View File

@@ -7,6 +7,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.socialbackup.CustodianRecoveryModeExplainerFragment;
import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
import org.briarproject.briar.api.socialbackup.recovery.CustodianTask;
import java.util.logging.Logger;
@@ -59,13 +60,17 @@ public class CustodianReturnShardActivity extends BriarActivity
viewModel.getShowCameraFragment().observeEvent(this, show -> {
if (show) showCameraFragment();
});
viewModel.getSuccessDismissed().observeEvent(this, dismissed -> {
if (dismissed) finish();
});
viewModel.getState()
.observe(this, this::onReturnShardStateChanged);
}
private void onReturnShardStateChanged(CustodianTask.State state) {
if (state instanceof CustodianTask.State.Success) {
CustodianReturnShardSuccessFragment fragment = new CustodianReturnShardSuccessFragment();
showNextFragment(fragment);
}
}

View File

@@ -0,0 +1,59 @@
package org.briarproject.briar.android.socialbackup.recover;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class CustodianReturnShardSuccessFragment extends
BaseFragment {
public static final String TAG =
CustodianReturnShardFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private CustodianReturnShardViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(CustodianReturnShardViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recovery_custodian_done,
container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(e -> viewModel.onSuccessDismissed());
return view;
}
@Override
public String getUniqueTag() {
return TAG;
}
}

View File

@@ -48,6 +48,8 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
private boolean qrCodeRead = false;
private final MutableLiveEvent<Boolean> showCameraFragment =
new MutableLiveEvent<>();
private final MutableLiveEvent<Boolean> successDismissed =
new MutableLiveEvent<>();
private final MutableLiveData<CustodianTask.State> state =
new MutableLiveData<>();
final QrCodeDecoder qrCodeDecoder;
@@ -100,6 +102,12 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
showCameraFragment.setEvent(true);
}
@UiThread
public void onSuccessDismissed() {
successDismissed.setEvent(true);
}
QrCodeDecoder getQrCodeDecoder() {
return qrCodeDecoder;
}
@@ -108,6 +116,9 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
return showCameraFragment;
}
LiveEvent<Boolean> getSuccessDismissed() {
return successDismissed;
}
LiveData<CustodianTask.State> getState() {
return state;
}

View File

@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask;
@@ -23,7 +22,6 @@ import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.logging.Logger.getLogger;
@MethodsNotNullByDefault
@@ -78,10 +76,6 @@ public class OwnerReturnShardActivity extends BaseActivity
if (state == null) {
showInitialFragment(new OwnerRecoveryModeExplainerFragment());
}
// viewModel.getCheckPermissions().observeEvent(this, check ->
// permissionManager.checkPermissions());
// viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r ->
// requestBluetoothDiscoverable()); // never false
viewModel.getShowQrCodeFragment().observeEvent(this, show -> {
if (show) showQrCodeFragment();
});
@@ -117,6 +111,7 @@ public class OwnerReturnShardActivity extends BaseActivity
@Override
public void onBackPressed() {
// TODO should we cancel the return shard task here?
if (viewModel.getState()
.getValue() instanceof SecretOwnerTask.State.Failure) {
// re-create this activity when going back in failed state
@@ -141,47 +136,23 @@ public class OwnerReturnShardActivity extends BaseActivity
}
private void onReturnShardStateChanged(SecretOwnerTask.State state) {
// if (state instanceof ReturnShardState.SocialBackupExchangeFinished) {
// ReturnShardState.SocialBackupExchangeResult result =
// ((ReturnShardState.SocialBackupExchangeFinished) state).result;
// onSocialBackupExchangeResult(result);
// } else if (state instanceof ReturnShardState.Failed) {
// Boolean qrCodeTooOld =
// ((ReturnShardState.Failed) state).qrCodeTooOld;
// onAddingContactFailed(qrCodeTooOld);
// }
}
private void onSocialBackupExchangeResult(
ReturnShardState.SocialBackupExchangeResult result) {
if (result instanceof ReturnShardState.SocialBackupExchangeResult.Success) {
// String text = getString(R.string.contact_added_toast, contactName);
Toast.makeText(this, "Shard return successful", LENGTH_LONG).show();
supportFinishAfterTransition();
} else if (result instanceof ReturnShardState.SocialBackupExchangeResult.Error) {
showErrorFragment();
} else throw new AssertionError();
}
private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) {
if (qrCodeTooOld == null) {
showErrorFragment();
} else {
String msg;
if (qrCodeTooOld) {
msg = getString(R.string.qr_code_too_old,
getString(R.string.app_name));
} else {
msg = getString(R.string.qr_code_too_new,
getString(R.string.app_name));
}
showNextFragment(AddNearbyContactErrorFragment.newInstance(msg));
if (state instanceof SecretOwnerTask.State.Success) {
Toast.makeText(this,
"Success - got shard",
Toast.LENGTH_SHORT).show();
finish();
} else if (state instanceof SecretOwnerTask.State.Failure) {
Toast.makeText(this,
"Shard return failed!",
Toast.LENGTH_SHORT).show();
finish();
}
}
private void showErrorFragment() {
showNextFragment(new AddNearbyContactErrorFragment());
}
// private void showErrorFragment() {
// // TODO change this for an appropriate error message fragment
// showNextFragment(new AddNearbyContactErrorFragment());
// }
@Override
@Deprecated

View File

@@ -136,91 +136,12 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT
@UiThread
private void stopListening() {
task.cancel();
// KeyAgreementTask oldTask = task;
// ioExecutor.execute(() -> {
// if (oldTask != null) oldTask.stopListening();
// });
ioExecutor.execute(() -> {
task.cancel();
});
}
// @Override
// public void eventOccurred(Event e) {
// if (e instanceof TransportStateEvent) {
// TransportStateEvent t = (TransportStateEvent) e;
// if (t.getTransportId().equals(BluetoothConstants.ID)) {
// if (LOG.isLoggable(INFO)) {
// LOG.info("Bluetooth state changed to " + t.getState());
// }
// showQrCodeFragmentIfAllowed();
// } else if (t.getTransportId().equals(LanTcpConstants.ID)) {
// if (LOG.isLoggable(INFO)) {
// LOG.info("Wifi state changed to " + t.getState());
// }
// showQrCodeFragmentIfAllowed();
// }
// } else if (e instanceof KeyAgreementListeningEvent) {
// LOG.info("KeyAgreementListeningEvent received");
// KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e;
// onLocalPayloadReceived(event.getLocalPayload());
// } else if (e instanceof KeyAgreementWaitingEvent) {
// LOG.info("KeyAgreementWaitingEvent received");
// state.setValue(new ReturnShardState.KeyAgreementWaiting());
// } else if (e instanceof KeyAgreementStartedEvent) {
// LOG.info("KeyAgreementStartedEvent received");
// state.setValue(new ReturnShardState.KeyAgreementStarted());
// } else if (e instanceof KeyAgreementFinishedEvent) {
// LOG.info("KeyAgreementFinishedEvent received");
// KeyAgreementResult result =
// ((KeyAgreementFinishedEvent) e).getResult();
// startContactExchange(result);
// state.setValue(new ReturnShardState.SocialBackupExchangeStarted());
// } else if (e instanceof KeyAgreementAbortedEvent) {
// LOG.info("KeyAgreementAbortedEvent received");
// resetPayloadFlags();
// state.setValue(new ReturnShardState.Failed());
// } else if (e instanceof KeyAgreementFailedEvent) {
// LOG.info("KeyAgreementFailedEvent received");
// resetPayloadFlags();
// state.setValue(new ReturnShardState.Failed());
// }
// }
@UiThread
// private void startContactExchange(KeyAgreementResult result) {
// TransportId t = result.getTransportId();
// DuplexTransportConnection conn = result.getConnection();
// SecretKey masterKey = result.getMasterKey();
// boolean alice = result.wasAlice();
// ioExecutor.execute(() -> {
// try {
// if (sending) {
// socialBackupExchangeManager.sendReturnShard(conn, masterKey, alice, returnShardPayload);
// } else {
// returnShardPayload = socialBackupExchangeManager.receiveReturnShard(conn, masterKey, alice);
// }
// ReturnShardState.SocialBackupExchangeResult.Success
// success =
// new ReturnShardState.SocialBackupExchangeResult.Success();
// state.postValue(
// new ReturnShardState.SocialBackupExchangeFinished(success));
// } catch (ContactExistsException e) {
// tryToClose(conn);
// ReturnShardState.SocialBackupExchangeResult.Error
// error = new ReturnShardState.SocialBackupExchangeResult.Error(
// e.getRemoteAuthor());
// state.postValue(
// new ReturnShardState.SocialBackupExchangeFinished(error));
// } catch (DbException | IOException e) {
// tryToClose(conn);
// logException(LOG, WARNING, e);
// ReturnShardState.SocialBackupExchangeResult.Error
// error =
// new ReturnShardState.SocialBackupExchangeResult.Error(null);
// state.postValue(
// new ReturnShardState.SocialBackupExchangeFinished(error));
// }
// });
// }
/**
@@ -252,18 +173,19 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT
@Override
public void onStateChanged(SecretOwnerTask.State state) {
if (state instanceof SecretOwnerTask.State.Listening) {
DisplayMetrics dm = getApplication().getResources().getDisplayMetrics();
ioExecutor.execute(() -> {
byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload();
if (LOG.isLoggable(INFO)) {
LOG.info("Local payload is " + payloadBytes.length
+ " bytes");
}
// Use ISO 8859-1 to encode bytes directly as a string
String content = new String(payloadBytes, ISO_8859_1);
qrCodeBitmap = QrCodeUtils.createQrCode(dm, content);
});
}
this.state.postValue(state);
if (state instanceof SecretOwnerTask.State.Listening) {
DisplayMetrics dm = getApplication().getResources().getDisplayMetrics();
ioExecutor.execute(() -> {
byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload();
if (LOG.isLoggable(INFO)) {
LOG.info("Local payload is " + payloadBytes.length
+ " bytes");
}
// Use ISO 8859-1 to encode bytes directly as a string
String content = new String(payloadBytes, ISO_8859_1);
qrCodeBitmap = QrCodeUtils.createQrCode(dm, content);
});
}
}
}

View File

@@ -10,6 +10,17 @@
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/backup_done_dismiss"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"