diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index e4859d5c8..14213dd10 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -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); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java index 4f8b29ea8..35679e565 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java @@ -61,7 +61,7 @@ public class DistributedBackupActivity extends BriarActivity implements @Override public void contactsSelected(Collection 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 = diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java index f808a37c3..1f50328dc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java @@ -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); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java new file mode 100644 index 000000000..b058d1bb7 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java @@ -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; + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java index 6cb5a01e3..78c49b3a5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java @@ -48,6 +48,8 @@ public class CustodianReturnShardViewModel extends AndroidViewModel private boolean qrCodeRead = false; private final MutableLiveEvent showCameraFragment = new MutableLiveEvent<>(); + private final MutableLiveEvent successDismissed = + new MutableLiveEvent<>(); private final MutableLiveData 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 getSuccessDismissed() { + return successDismissed; + } LiveData getState() { return state; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java index 91770a459..3a29ec53f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java @@ -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 diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index 6d9b4f130..28be28d61 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -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); + }); + } } } diff --git a/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml b/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml index eb33d3c90..25b9e72c6 100644 --- a/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml +++ b/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml @@ -10,6 +10,17 @@ android:paddingRight="@dimen/margin_large" android:paddingBottom="@dimen/margin_medium"> +