diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index 76f00e6c4..576288372 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -139,16 +139,7 @@
-
-
-
-
+
+ android:parentActivityName="org.briarproject.briar.android.account.SetupActivity">
+ android:value="org.briarproject.briar.android.account.SetupActivity" />
viewModel.recoverClicked());
+
return v;
}
@@ -75,6 +79,8 @@ public class AuthorNameFragment extends SetupFragment {
boolean enabled = authorNameLength > 0 && !error;
authorNameInput.setOnEditorActionListener(enabled ? this : null);
nextButton.setEnabled(enabled);
+ recoverButton.setEnabled(!enabled);
+// recoverButton.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
}
@Override
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/NewOrRecoverActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/account/NewOrRecoverActivity.java
deleted file mode 100644
index 7c8a9a5b0..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/account/NewOrRecoverActivity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.briarproject.briar.android.account;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-import org.briarproject.briar.R;
-import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.activity.BaseActivity;
-import org.briarproject.briar.android.fragment.BaseFragment;
-import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
-
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
-
-public class NewOrRecoverActivity extends BaseActivity implements
- BaseFragment.BaseFragmentListener, SetupNewAccountChosenListener,
- RecoverAccountListener {
-
- @Override
- public void injectActivity(ActivityComponent component) {
- component.inject(this);
- }
-
- @Override
- public void onCreate(Bundle state) {
- super.onCreate(state);
- // fade-in after splash screen instead of default animation
- // TODO the fade in is not working
- overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
- setContentView(R.layout.activity_fragment_container);
- NewOrRecoverFragment fragment = NewOrRecoverFragment.newInstance();
- showInitialFragment(fragment);
- }
-
- @Override
- public void setupNewAccountChosen() {
- finish();
- Intent i = new Intent(this, SetupActivity.class);
- i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
- FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
- startActivity(i);
- }
-
- @Override
- public void recoverAccountChosen() {
- finish();
- Intent i = new Intent(this, OwnerReturnShardActivity.class);
- i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
- FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
- startActivity(i);
- }
-
- @Override
- @Deprecated
- public void runOnDbThread(Runnable runnable) {
- throw new RuntimeException("Don't use this deprecated method here.");
- }
-}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/NewOrRecoverFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/NewOrRecoverFragment.java
deleted file mode 100644
index a6055afac..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/account/NewOrRecoverFragment.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.briarproject.briar.android.account;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-
-import org.briarproject.briar.R;
-import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.fragment.BaseFragment;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-public class NewOrRecoverFragment extends BaseFragment {
-
- public static final String TAG = NewOrRecoverFragment.class.getName();
-
- protected SetupNewAccountChosenListener setupNewAccountListener;
- protected RecoverAccountListener recoverAccountListener;
-
- public static NewOrRecoverFragment newInstance() {
- Bundle bundle = new Bundle();
- NewOrRecoverFragment fragment = new NewOrRecoverFragment();
- fragment.setArguments(bundle);
- return fragment;
- }
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requireActivity().setTitle(R.string.setup_title);
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
- ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_new_or_recover,
- container, false);
- Button newAccountButton = view.findViewById(R.id.buttonSetupNewAccount);
- newAccountButton.setOnClickListener(e -> {
- setupNewAccountListener.setupNewAccountChosen();
- });
-
- Button recoverAccountButton = view.findViewById(R.id.buttonRestoreAccount);
- recoverAccountButton.setOnClickListener(e -> {
- recoverAccountListener.recoverAccountChosen();
- });
- return view;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- setupNewAccountListener = (SetupNewAccountChosenListener) context;
- recoverAccountListener = (RecoverAccountListener) context;
- }
-
- @Override
- public String getUniqueTag() {
- return TAG;
- }
-
- @Override
- public void injectFragment(ActivityComponent component) {
- component.inject(this);
- }
-}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
index 68d90ad95..793e57369 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
@@ -10,6 +10,7 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
+import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
import javax.annotation.Nullable;
import javax.inject.Inject;
@@ -25,6 +26,7 @@ import static org.briarproject.briar.android.account.SetupViewModel.State.AUTHOR
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
import static org.briarproject.briar.android.account.SetupViewModel.State.DOZE;
import static org.briarproject.briar.android.account.SetupViewModel.State.FAILED;
+import static org.briarproject.briar.android.account.SetupViewModel.State.RECOVER;
import static org.briarproject.briar.android.account.SetupViewModel.State.SET_PASSWORD;
@MethodsNotNullByDefault
@@ -60,6 +62,8 @@ public class SetupActivity extends BaseActivity
showPasswordFragment();
} else if (state == DOZE) {
showDozeFragment();
+ } else if (state == RECOVER) {
+ recover();
} else if (state == CREATED || state == FAILED) {
// TODO: Show an error if failed
showApp();
@@ -84,6 +88,13 @@ public class SetupActivity extends BaseActivity
overridePendingTransition(R.anim.screen_new_in, R.anim.screen_old_out);
}
+ void recover () {
+// finish();
+ Intent i = new Intent(this, OwnerReturnShardActivity.class);
+ i.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ startActivity(i);
+ }
+
@Override
@Deprecated
public void runOnDbThread(Runnable runnable) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/SetupViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupViewModel.java
index 845075e8d..1ccdde55d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/account/SetupViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupViewModel.java
@@ -25,13 +25,14 @@ import static org.briarproject.briar.android.account.SetupViewModel.State.AUTHOR
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
import static org.briarproject.briar.android.account.SetupViewModel.State.DOZE;
import static org.briarproject.briar.android.account.SetupViewModel.State.FAILED;
+import static org.briarproject.briar.android.account.SetupViewModel.State.RECOVER;
import static org.briarproject.briar.android.account.SetupViewModel.State.SET_PASSWORD;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public
class SetupViewModel extends AndroidViewModel {
- enum State {AUTHOR_NAME, SET_PASSWORD, DOZE, CREATED, FAILED}
+ enum State {AUTHOR_NAME, SET_PASSWORD, DOZE, CREATED, FAILED, RECOVER}
private static final Logger LOG =
getLogger(SetupActivity.class.getName());
@@ -117,4 +118,9 @@ class SetupViewModel extends AndroidViewModel {
}
});
}
+
+ public void recoverClicked() {
+ LOG.info("RECOVER CLICKED ***");
+ state.postEvent(RECOVER);
+ }
}
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 7b3b9a2ad..4bb9c0caf 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
@@ -7,8 +7,6 @@ import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.StartupFailureActivity;
import org.briarproject.briar.android.account.AuthorNameFragment;
import org.briarproject.briar.android.account.DozeFragment;
-import org.briarproject.briar.android.account.NewOrRecoverActivity;
-import org.briarproject.briar.android.account.NewOrRecoverFragment;
import org.briarproject.briar.android.account.SetPasswordFragment;
import org.briarproject.briar.android.account.SetupActivity;
import org.briarproject.briar.android.account.UnlockActivity;
@@ -92,20 +90,19 @@ import org.briarproject.briar.android.sharing.ShareBlogFragment;
import org.briarproject.briar.android.sharing.ShareForumActivity;
import org.briarproject.briar.android.sharing.ShareForumFragment;
import org.briarproject.briar.android.sharing.SharingModule;
+import org.briarproject.briar.android.socialbackup.SetupExplainerFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianRecoveryModeExplainerFragment;
import org.briarproject.briar.android.socialbackup.CustodianSelectorFragment;
-import org.briarproject.briar.android.socialbackup.DistributedBackupActivity;
+import org.briarproject.briar.android.socialbackup.SocialBackupSetupActivity;
import org.briarproject.briar.android.socialbackup.ExistingBackupFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardErrorFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment;
-import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardSuccessFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeErrorFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeMainFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment;
-import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment;
import org.briarproject.briar.android.socialbackup.creation.CreateBackupModule;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardSuccessFragment;
@@ -114,7 +111,6 @@ import org.briarproject.briar.android.socialbackup.recover.RestoreAccountDozeFra
import org.briarproject.briar.android.socialbackup.recover.RestoreAccountSetPasswordFragment;
import org.briarproject.briar.android.splash.SplashScreenActivity;
import org.briarproject.briar.android.test.TestDataActivity;
-import org.briarproject.briar.api.socialbackup.recovery.RestoreAccount;
import dagger.Component;
@@ -217,8 +213,6 @@ public interface ActivityComponent {
void inject(CrashReportActivity crashReportActivity);
- void inject(NewOrRecoverActivity newOrRecoverActivity);
-
void inject(CustodianReturnShardActivity custodianReturnShardActivity);
void inject(OwnerReturnShardActivity ownerReturnShardActivity);
@@ -295,28 +289,22 @@ public interface ActivityComponent {
void inject(ThresholdSelectorFragment thresholdSelectorFragment);
- void inject(DistributedBackupActivity distributedBackupActivity);
+ void inject(SocialBackupSetupActivity distributedBackupActivity);
void inject(DatabaseComponent databaseComponent);
void inject(CustodianSelectorFragment custodianSelectorFragment);
- void inject(ShardsSentFragment shardsSentFragment);
-
void inject(OwnerRecoveryModeExplainerFragment ownerRecoveryModeExplainerFragment);
void inject(ExistingBackupFragment existingBackupFragment);
- void inject(NewOrRecoverFragment newOrRecoverFragment);
-
void inject(CustodianRecoveryModeExplainerFragment custodianRecoveryModeExplainerFragment);
void inject(CustodianReturnShardFragment custodianReturnShardFragment);
void inject(OwnerReturnShardFragment ownerReturnShardFragment);
- void inject(CustodianReturnShardSuccessFragment custodianReturnShardSuccessFragment);
-
void inject(RestoreAccountSetPasswordFragment restoreAccountSetPasswordFragment);
void inject(RestoreAccountDozeFragment restoreAccountDozeFragment);
@@ -340,4 +328,6 @@ public interface ActivityComponent {
void inject(RevokeRemoteWipeSuccessFragment revokeRemoteWipeSuccessFragment);
void inject(RemoteWipeSetupExplainerFragment remoteWipeSetupExplainerFragment);
+
+ void inject(SetupExplainerFragment setupExplainerFragment);
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java
index 0303d7447..faf469c28 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java
@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarService;
-import org.briarproject.briar.android.account.NewOrRecoverActivity;
import org.briarproject.briar.android.account.SetupActivity;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
@@ -108,7 +107,7 @@ public class StartupActivity extends BaseActivity implements
private void onAccountDeleted() {
setResult(RESULT_CANCELED);
finish();
- Intent i = new Intent(this, NewOrRecoverActivity.class);
+ Intent i = new Intent(this, SetupActivity.class);
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(i);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java
index 68c70ccaa..4434e484d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java
@@ -159,7 +159,8 @@ public class NavDrawerActivity extends BriarActivity implements
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
- navDrawerViewModel.checkTransportsOnboarding();
+// navDrawerViewModel.checkTransportsOnboarding();
+ navDrawerViewModel.checkSocialBackupOnboarding();
}
};
drawerLayout.addDrawerListener(drawerToggle);
@@ -168,9 +169,12 @@ public class NavDrawerActivity extends BriarActivity implements
initializeTransports();
transportsView.setAdapter(transportsAdapter);
- observeOnce(navDrawerViewModel.showTransportsOnboarding(), this, show ->
- observeOnce(torIcon, this, imageView ->
- showTransportsOnboarding(show, imageView)));
+// observeOnce(navDrawerViewModel.showTransportsOnboarding(), this, show ->
+// observeOnce(torIcon, this, imageView ->
+// showTransportsOnboarding(show, imageView)));
+
+ observeOnce(navDrawerViewModel.showSocialBackupOnboarding(), this,
+ this::showSocialBackupOnboarding);
lockManager.isLockable().observe(this, this::setLockVisible);
@@ -469,6 +473,22 @@ public class NavDrawerActivity extends BriarActivity implements
}
}
+ private void showSocialBackupOnboarding(boolean show) {
+ if (show) {
+ new MaterialTapTargetPrompt.Builder(NavDrawerActivity.this,
+ R.style.OnboardingDialogTheme)
+ .setTarget(R.id.nav_btn_settings)
+ .setPrimaryText(R.string.social_backup_onboarding_title)
+ .setSecondaryText(R.string.social_backup_onboarding_long)
+ .setFocalRadius((float) 350)
+ .setFocalPadding((float) 100)
+ .setBackgroundColour(
+ ContextCompat.getColor(this, R.color.briar_primary))
+ .show();
+ navDrawerViewModel.socialBackupOnboardingShown();
+ }
+ }
+
private static class Transport {
private final TransportId id;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerViewModel.java
index 132cc0b9f..d38dac6ba 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerViewModel.java
@@ -39,6 +39,8 @@ public class NavDrawerViewModel extends DbViewModel {
private static final String EXPIRY_DATE_WARNING = "expiryDateWarning";
private static final String SHOW_TRANSPORTS_ONBOARDING =
"showTransportsOnboarding";
+ private static final String SHOW_SOCIAL_BACKUP_ONBOARDING =
+ "showSocialBackupOnboarding";
private final SettingsManager settingsManager;
@@ -48,6 +50,8 @@ public class NavDrawerViewModel extends DbViewModel {
new MutableLiveData<>();
private final MutableLiveData showTransportsOnboarding =
new MutableLiveData<>();
+ private final MutableLiveData showSocialBackupOnboarding =
+ new MutableLiveData<>();
@Inject
NavDrawerViewModel(Application app,
@@ -142,6 +146,11 @@ public class NavDrawerViewModel extends DbViewModel {
return showTransportsOnboarding;
}
+ @UiThread
+ LiveData showSocialBackupOnboarding() {
+ return showSocialBackupOnboarding;
+ }
+
@UiThread
void checkTransportsOnboarding() {
if (showTransportsOnboarding.getValue() != null) return;
@@ -171,4 +180,35 @@ public class NavDrawerViewModel extends DbViewModel {
}
});
}
+
+ @UiThread
+ void checkSocialBackupOnboarding() {
+ if (showSocialBackupOnboarding.getValue() != null) return;
+ runOnDbThread(() -> {
+ try {
+ Settings settings =
+ settingsManager.getSettings(SETTINGS_NAMESPACE);
+ boolean show =
+ settings.getBoolean(SHOW_SOCIAL_BACKUP_ONBOARDING,
+ true);
+ showSocialBackupOnboarding.postValue(show);
+ } catch (DbException e) {
+ logException(LOG, WARNING, e);
+ }
+ });
+ }
+
+ @UiThread
+ void socialBackupOnboardingShown() {
+ showSocialBackupOnboarding.setValue(false);
+ runOnDbThread(() -> {
+ try {
+ Settings settings = new Settings();
+ settings.putBoolean(SHOW_SOCIAL_BACKUP_ONBOARDING, false);
+ settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
+ } catch (DbException e) {
+ logException(LOG, WARNING, e);
+ }
+ });
+ }
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java
index 747bc9895..8225f479b 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsActivity.java
@@ -1,10 +1,12 @@
package org.briarproject.briar.android.settings;
import android.content.Intent;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
+import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
@@ -12,6 +14,7 @@ import org.briarproject.bramble.api.FeatureFlags;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
+import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.android.view.AuthorView;
@@ -19,11 +22,15 @@ import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
+import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
+import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import de.hdodenhof.circleimageview.CircleImageView;
+import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
import static android.widget.Toast.LENGTH_LONG;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_AVATAR_IMAGE;
+import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
public class SettingsActivity extends BriarActivity {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianSelectorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianSelectorFragment.java
index 6cfedd9a3..6f05c0d0f 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianSelectorFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianSelectorFragment.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import javax.inject.Inject;
import androidx.annotation.Nullable;
+import androidx.lifecycle.ViewModelProvider;
import static java.util.Objects.requireNonNull;
@@ -32,6 +33,18 @@ public class CustodianSelectorFragment extends ContactSelectorFragment {
public static final String TAG = CustodianSelectorFragment.class.getName();
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ private SocialBackupSetupViewModel viewModel;
+
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
+ .get(SocialBackupSetupViewModel.class);
+ }
+
@Inject
CreateBackupController controller;
@@ -44,11 +57,6 @@ public class CustodianSelectorFragment extends ContactSelectorFragment {
return fragment;
}
- @Override
- public void injectFragment(ActivityComponent component) {
- component.inject(this);
- }
-
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,15 +86,19 @@ public class CustodianSelectorFragment extends ContactSelectorFragment {
int n = selectedContacts.size();
int min = 2;
- boolean enough = n >= min;
+ int max = 7;
+ boolean amountIsValid = (n >= min) && (n <= max);
- item.setVisible(enough);
+ item.setVisible(amountIsValid);
if (n == 0) {
Toast.makeText(getContext(), String.format(getString(R.string.select_at_least_n_contacts), min),
Toast.LENGTH_SHORT).show();
} else if (n < min) {
Toast.makeText(getContext(), String.format(getString(R.string.select_at_least_n_more_contacts), min - n),
Toast.LENGTH_SHORT).show();
+ } else if (n > max) {
+ Toast.makeText(getContext(), String.format(getString(R.string.select_no_more_than_n_contacts), max),
+ Toast.LENGTH_SHORT).show();
}
}
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
deleted file mode 100644
index aa9f48275..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.briarproject.briar.android.socialbackup;
-
-import android.os.Bundle;
-import android.widget.Toast;
-
-import org.briarproject.bramble.api.contact.ContactId;
-import org.briarproject.bramble.api.contact.ContactManager;
-import org.briarproject.bramble.api.db.DatabaseComponent;
-import org.briarproject.bramble.api.db.DbException;
-import org.briarproject.briar.R;
-import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.activity.BriarActivity;
-import org.briarproject.briar.android.contactselection.ContactSelectorListener;
-import org.briarproject.briar.android.fragment.BaseFragment;
-import org.briarproject.briar.api.socialbackup.BackupMetadata;
-import org.briarproject.briar.api.socialbackup.SocialBackupManager;
-
-import java.util.Collection;
-import java.util.List;
-
-import javax.inject.Inject;
-
-public class DistributedBackupActivity extends BriarActivity implements
- BaseFragment.BaseFragmentListener, ContactSelectorListener,
- ThresholdDefinedListener,
- ShardsSentFragment.ShardsSentDismissedListener {
-
- private Collection custodians;
-
- @Inject
- public SocialBackupManager socialBackupManager;
-
- @Inject
- public ContactManager contactManager;
-
- @Inject
- public DatabaseComponent db;
-
- @Override
- public void injectActivity(ActivityComponent component) {
- component.inject(this);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_distributed_backup);
-
- try {
- db.transaction(false, txn -> {
- BackupMetadata backupMetadata =
- socialBackupManager.getBackupMetadata(txn);
- if (backupMetadata == null) throw new DbException();
- ExistingBackupFragment fragment =
- ExistingBackupFragment.newInstance(backupMetadata);
- showInitialFragment(fragment);
- });
- } catch (DbException e) {
- // Check the number of contacts in the contacts list > 1
- try {
- if (contactManager.getContacts().size() < 2) {
- Toast.makeText(this,
- R.string.social_backup_not_enough_contacts,
- Toast.LENGTH_LONG).show();
- finish();
- }
- } catch (DbException dbException) {
- Toast.makeText(this,
- R.string.reading_contacts_error,
- Toast.LENGTH_LONG).show();
- finish();
- }
- CustodianSelectorFragment fragment =
- CustodianSelectorFragment.newInstance();
- showInitialFragment(fragment);
- }
- }
-
- @Override
- public void contactsSelected(Collection contacts) {
- Toast.makeText(this,
- String.format("Selected %d contacts", contacts.size()),
- Toast.LENGTH_SHORT).show();
- custodians = contacts;
- ThresholdSelectorFragment fragment =
- ThresholdSelectorFragment.newInstance(contacts.size());
- showNextFragment(fragment);
- }
-
- @Override
- public void thresholdDefined(int threshold) {
- try {
- db.transaction(false, txn -> {
- socialBackupManager
- .createBackup(txn, (List) custodians,
- threshold);
- ShardsSentFragment fragment = new ShardsSentFragment();
- showNextFragment(fragment);
- });
- } catch (DbException e) {
- Toast.makeText(this,
- "There was an error when creating the backup",
- Toast.LENGTH_LONG).show();
- finish();
- }
- }
-
- @Override
- public void shardsSentDismissed() {
- finish();
- }
-}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java
index c5f7f0912..7b3cd6300 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ExistingBackupFragment.java
@@ -7,6 +7,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
@@ -16,8 +17,11 @@ import org.briarproject.briar.api.socialbackup.BackupMetadata;
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.lifecycle.ViewModelProvider;
public class ExistingBackupFragment extends BaseFragment {
@@ -25,19 +29,16 @@ public class ExistingBackupFragment extends BaseFragment {
private static final String CUSTODIANS = "custodians";
public static final String TAG = ExistingBackupFragment.class.getName();
- public static ExistingBackupFragment newInstance(
- BackupMetadata backupMetadata) {
- Bundle bundle = new Bundle();
- List custodians = backupMetadata.getCustodians();
- ArrayList custodianNames = new ArrayList();
- for (Author custodian : custodians) {
- custodianNames.add(custodian.getName());
- }
- bundle.putStringArrayList(CUSTODIANS, custodianNames);
- bundle.putInt(THRESHOLD, backupMetadata.getThreshold());
- ExistingBackupFragment fragment = new ExistingBackupFragment();
- fragment.setArguments(bundle);
- return fragment;
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ private SocialBackupSetupViewModel viewModel;
+
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
+ .get(SocialBackupSetupViewModel.class);
}
@Override
@@ -53,20 +54,20 @@ public class ExistingBackupFragment extends BaseFragment {
ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_existing_backup,
container, false);
- Bundle args = requireArguments();
- ArrayList custodianNames = args.getStringArrayList(CUSTODIANS);
+ BackupMetadata backupMetadata = viewModel.getBackupMetadata();
+ List custodians = backupMetadata.getCustodians();
StringBuilder custodianNamesString = new StringBuilder();
- for (String custodianName : custodianNames) {
+ for (Author custodian : custodians) {
custodianNamesString
.append("• ")
- .append(custodianName)
+ .append(custodian.getName())
.append("\n");
}
TextView textViewThreshold = view.findViewById(R.id.textViewThreshold);
textViewThreshold.setText(getString(R.string.existing_backup_explain,
- args.getInt(THRESHOLD)));
+ backupMetadata.getThreshold()));
TextView textViewCustodians =
view.findViewById(R.id.textViewCustodians);
textViewCustodians.setText(custodianNamesString);
@@ -79,15 +80,9 @@ public class ExistingBackupFragment extends BaseFragment {
// listener = (ShardsSentDismissedListener) context;
}
-
@Override
public String getUniqueTag() {
return TAG;
}
- @Override
- public void injectFragment(ActivityComponent component) {
- component.inject(this);
- }
-
}
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/SetupExplainerFragment.java
similarity index 53%
rename from briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SetupExplainerFragment.java
index b058d1bb7..a5ab84a8b 100644
--- 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/SetupExplainerFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.socialbackup.recover;
+package org.briarproject.briar.android.socialbackup;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -6,8 +6,6 @@ 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;
@@ -18,37 +16,33 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
-@MethodsNotNullByDefault
-@ParametersNotNullByDefault
-public class CustodianReturnShardSuccessFragment extends
- BaseFragment {
+public class SetupExplainerFragment extends BaseFragment {
public static final String TAG =
- CustodianReturnShardFragment.class.getName();
+ SetupExplainerFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
- private CustodianReturnShardViewModel viewModel;
+ private SocialBackupSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
- .get(CustodianReturnShardViewModel.class);
+ .get(SocialBackupSetupViewModel.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);
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
+ ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view =
+ inflater.inflate(R.layout.fragment_social_backup_setup_explainer,
+ container, false);
Button button = view.findViewById(R.id.button);
- button.setOnClickListener(e -> viewModel.onSuccessDismissed());
-
+ button.setOnClickListener(e -> viewModel.onExplainerDismissed());
return view;
}
@@ -57,3 +51,4 @@ public class CustodianReturnShardSuccessFragment extends
return TAG;
}
}
+
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ShardsSentFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ShardsSentFragment.java
deleted file mode 100644
index c6ad906d6..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ShardsSentFragment.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.briarproject.briar.android.socialbackup;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-
-import org.briarproject.briar.R;
-import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.fragment.BaseFragment;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-
-public class ShardsSentFragment extends BaseFragment {
-
- public static final String TAG = ShardsSentFragment.class.getName();
-
- interface ShardsSentDismissedListener {
-
- @UiThread
- void shardsSentDismissed();
-
- }
-
- protected ShardsSentDismissedListener listener;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requireActivity().setTitle(R.string.title_distributed_backup);
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_shards_sent,
- container, false);
-
- Button button = view.findViewById(R.id.button);
- button.setOnClickListener(e -> {
- listener.shardsSentDismissed();
- });
-
- return view;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- listener = (ShardsSentDismissedListener) context;
- }
-
-
- @Override
- public String getUniqueTag() {
- return TAG;
- }
-
- @Override
- public void injectFragment(ActivityComponent component) {
- component.inject(this);
- }
-
- public void onBackPressed() {
- listener.shardsSentDismissed();
- }
-
-}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java
new file mode 100644
index 000000000..0c616cb88
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupActivity.java
@@ -0,0 +1,93 @@
+package org.briarproject.briar.android.socialbackup;
+
+import android.os.Bundle;
+import android.widget.Toast;
+
+import org.briarproject.bramble.api.contact.ContactId;
+import org.briarproject.bramble.api.db.DbException;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.activity.BriarActivity;
+import org.briarproject.briar.android.contactselection.ContactSelectorListener;
+import org.briarproject.briar.android.fragment.BaseFragment;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import androidx.lifecycle.ViewModelProvider;
+
+public class SocialBackupSetupActivity extends BriarActivity implements
+ BaseFragment.BaseFragmentListener, ContactSelectorListener {
+
+ private SocialBackupSetupViewModel viewModel;
+
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ @Override
+ public void injectActivity(ActivityComponent component) {
+ component.inject(this);
+ viewModel = new ViewModelProvider(this, viewModelFactory)
+ .get(SocialBackupSetupViewModel.class);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_distributed_backup);
+
+ if (viewModel.haveExistingBackup()) {
+ showInitialFragment(new ExistingBackupFragment());
+ } else {
+ try {
+ if (!viewModel.haveEnoughContacts()) {
+ Toast.makeText(this,
+ R.string.social_backup_not_enough_contacts,
+ Toast.LENGTH_LONG).show();
+ finish();
+ }
+ } catch (DbException dbException) {
+ Toast.makeText(this,
+ R.string.reading_contacts_error,
+ Toast.LENGTH_LONG).show();
+ finish();
+ }
+ showInitialFragment(new SetupExplainerFragment());
+ }
+
+ viewModel.getState()
+ .observe(this, this::onStateChanged);
+ }
+
+ private void onStateChanged(SocialBackupSetupViewModel.State state) {
+ switch (state) {
+ case SUCCESS:
+ finish();
+ break;
+ case FAILURE:
+ Toast.makeText(this,
+ "There was an error when creating the backup",
+ Toast.LENGTH_LONG).show();
+ finish();
+ break;
+ case CHOOSING_CUSTODIANS:
+ CustodianSelectorFragment fragment =
+ CustodianSelectorFragment.newInstance();
+ showNextFragment(fragment);
+ break;
+ }
+ }
+
+ @Override
+ public void contactsSelected(Collection contacts) {
+ Toast.makeText(this,
+ String.format("Selected %d contacts", contacts.size()),
+ Toast.LENGTH_SHORT).show();
+ viewModel.setCustodians(contacts);
+ ThresholdSelectorFragment fragment =
+ ThresholdSelectorFragment.newInstance(contacts.size());
+ showNextFragment(fragment);
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupModule.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupModule.java
new file mode 100644
index 000000000..7d7f8f7b2
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupModule.java
@@ -0,0 +1,20 @@
+package org.briarproject.briar.android.socialbackup;
+
+import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardViewModel;
+import org.briarproject.briar.android.viewmodel.ViewModelKey;
+
+import androidx.lifecycle.ViewModel;
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.IntoMap;
+
+@Module
+public abstract class SocialBackupSetupModule {
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(SocialBackupSetupViewModel.class)
+ abstract ViewModel bindSocialBackupSetupViewModel(
+ SocialBackupSetupViewModel socialBackupSetupViewModel);
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java
new file mode 100644
index 000000000..1b80dfa2e
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/SocialBackupSetupViewModel.java
@@ -0,0 +1,106 @@
+package org.briarproject.briar.android.socialbackup;
+
+import android.app.Application;
+
+import org.briarproject.bramble.api.contact.ContactId;
+import org.briarproject.bramble.api.contact.ContactManager;
+import org.briarproject.bramble.api.db.DatabaseComponent;
+import org.briarproject.bramble.api.db.DbException;
+import org.briarproject.briar.api.socialbackup.BackupMetadata;
+import org.briarproject.briar.api.socialbackup.SocialBackupManager;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.MutableLiveData;
+
+public class SocialBackupSetupViewModel extends AndroidViewModel {
+
+ private final SocialBackupManager socialBackupManager;
+ private final DatabaseComponent db;
+ private final ContactManager contactManager;
+ private BackupMetadata backupMetadata;
+ private Collection custodians;
+ private int threshold;
+
+
+ public enum State {
+ EXPLAINING,
+ CHOOSING_CUSTODIANS,
+ GETTING_THRESHOLD,
+ SUCCESS,
+ FAILURE
+ }
+
+ private final MutableLiveData state =
+ new MutableLiveData<>();
+
+ @Inject
+ public SocialBackupSetupViewModel(
+ @NonNull Application app,
+ DatabaseComponent db,
+ SocialBackupManager socialBackupManager,
+ ContactManager contactManager
+ ) {
+ super(app);
+ this.socialBackupManager = socialBackupManager;
+ this.db = db;
+ this.contactManager = contactManager;
+ }
+
+ public boolean haveExistingBackup() {
+ try {
+ backupMetadata = db.transactionWithNullableResult(true,
+ socialBackupManager::getBackupMetadata);
+ } catch (DbException e) {
+ return false;
+ }
+ return (backupMetadata != null);
+ }
+
+ public BackupMetadata getBackupMetadata() {
+ return backupMetadata;
+ }
+
+ public boolean haveEnoughContacts() throws DbException {
+ return (contactManager.getContacts().size() > 1);
+ }
+
+ public void setCustodians(Collection contacts) {
+ custodians = contacts;
+ }
+
+ public void createBackup() {
+ try {
+ db.transaction(false, txn -> {
+ socialBackupManager
+ .createBackup(txn, (List) custodians,
+ threshold);
+ });
+ } catch (DbException e) {
+ state.postValue(State.FAILURE);
+ }
+ }
+
+ public void setThreshold(int threshold) {
+ this.threshold = threshold;
+ createBackup();
+ }
+
+ public void onSuccessDismissed() {
+ state.postValue(State.SUCCESS);
+ }
+
+ public MutableLiveData getState() {
+ return state;
+ }
+
+ public void onExplainerDismissed() {
+ state.postValue(State.CHOOSING_CUSTODIANS);
+ }
+}
+
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdDefinedListener.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdDefinedListener.java
deleted file mode 100644
index ee99b999a..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdDefinedListener.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.briarproject.briar.android.socialbackup;
-
-import org.briarproject.bramble.api.db.DbException;
-
-import androidx.annotation.UiThread;
-
-public interface ThresholdDefinedListener {
-
- @UiThread
- void thresholdDefined(int threshold) throws DbException;
-
-}
\ No newline at end of file
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java
index c4b689f39..716a448e9 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/ThresholdSelectorFragment.java
@@ -2,6 +2,10 @@ package org.briarproject.briar.android.socialbackup;
import android.content.Context;
import android.os.Bundle;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -11,22 +15,25 @@ import android.view.ViewGroup;
import android.widget.SeekBar;
import android.widget.TextView;
-import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.magmacollective.darkcrystal.secretsharingwrapper.SecretSharingWrapper;
+import java.util.Arrays;
+
+import javax.inject.Inject;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.lifecycle.ViewModelProvider;
public class ThresholdSelectorFragment extends BaseFragment {
public static final String TAG = ThresholdSelectorFragment.class.getName();
private static final String NUMBER_CUSTODIANS = "numberCustodians";
- protected ThresholdDefinedListener listener;
-
private int numberOfCustodians;
private int threshold;
private int recommendedThreshold;
@@ -35,6 +42,18 @@ public class ThresholdSelectorFragment extends BaseFragment {
private TextView message;
private TextView mOfn;
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ private SocialBackupSetupViewModel viewModel;
+
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
+ .get(SocialBackupSetupViewModel.class);
+ }
+
public static ThresholdSelectorFragment newInstance(int numberCustodians) {
Bundle bundle = new Bundle();
bundle.putInt(NUMBER_CUSTODIANS, numberCustodians);
@@ -94,7 +113,6 @@ public class ThresholdSelectorFragment extends BaseFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
- listener = (ThresholdDefinedListener) context;
}
@@ -103,11 +121,6 @@ public class ThresholdSelectorFragment extends BaseFragment {
return TAG;
}
- @Override
- public void injectFragment(ActivityComponent component) {
- component.inject(this);
- }
-
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.define_threshold_actions, menu);
@@ -118,26 +131,42 @@ public class ThresholdSelectorFragment extends BaseFragment {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_threshold_defined:
- try {
- listener.thresholdDefined(threshold);
- } catch (DbException e) {
- e.printStackTrace();
- }
+ viewModel.setThreshold(threshold);
+ showSuccessDialog();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
- private String buildThresholdRepresentationString() {
- String thresholdRepresentationText = "";
- for (int i = 0; i < threshold; i++) {
- thresholdRepresentationText += getString(R.string.filled_bullet);
+ private void showSuccessDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
+ R.style.BriarDialogTheme);
+ builder.setTitle(R.string.backup_created);
+ builder.setMessage(R.string.backup_done_info);
+ builder.setPositiveButton(R.string.ok,
+ (dialog, which) -> viewModel.onSuccessDismissed());
+ builder.setIcon(R.drawable.ic_baseline_done_outline_24);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ private SpannableStringBuilder buildThresholdRepresentationString() {
+ char[] charArray = new char[numberOfCustodians];
+ Arrays.fill(charArray, ' ');
+ SpannableStringBuilder string = new SpannableStringBuilder(new String(charArray));
+
+ for (int i = 0; i < numberOfCustodians; i++) {
+ int drawable = i < threshold
+ ? R.drawable.ic_custodian_required
+ : R.drawable.ic_custodian_optional;
+ string.setSpan(new ImageSpan(getContext(), drawable), i,
+ i+1,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- for (int i = 0; i < (numberOfCustodians - threshold); i++) {
- thresholdRepresentationText += getString(R.string.linear_bullet);
- }
- return thresholdRepresentationText;
+ // If we have more than 6, split it on two lines
+ if (numberOfCustodians > 6) string.insert(4, "\n");
+ return string;
}
private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianRecoveryModeExplainerFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianRecoveryModeExplainerFragment.java
index 49df13ebf..9cd889fd4 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianRecoveryModeExplainerFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianRecoveryModeExplainerFragment.java
@@ -32,11 +32,6 @@ public class CustodianRecoveryModeExplainerFragment extends BaseFragment {
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(CustodianReturnShardViewModel.class);
}
-// @Override
-// public void onCreate(@Nullable Bundle savedInstanceState) {
-// super.onCreate(savedInstanceState);
-// requireActivity().setTitle(R.string.title_help_recover);
-// }
@Nullable
@Override
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 976ed8581..93315f914 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
@@ -13,7 +13,6 @@ import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.api.socialbackup.recovery.CustodianTask;
import java.io.IOException;
-import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
@@ -21,17 +20,12 @@ import javax.inject.Inject;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
-import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
public class CustodianReturnShardActivity extends BriarActivity
implements BaseFragment.BaseFragmentListener {
private CustodianReturnShardViewModel viewModel;
- private static final Logger LOG =
- getLogger(CustodianReturnShardActivity.class.getName());
- private ContactId contactId;
@Inject
ViewModelProvider.Factory viewModelFactory;
@@ -52,7 +46,7 @@ public class CustodianReturnShardActivity extends BriarActivity
Intent intent = getIntent();
int id = intent.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException("No ContactId");
- contactId = new ContactId(id);
+ ContactId contactId = new ContactId(id);
try {
viewModel.start(contactId);
@@ -96,7 +90,8 @@ public class CustodianReturnShardActivity extends BriarActivity
"It looks like you are not connected to a Wifi network",
Toast.LENGTH_SHORT).show();
FragmentManager fm = getSupportFragmentManager();
- if (fm.findFragmentByTag(CustodianReturnShardFragment.TAG) == null) {
+ if (fm.findFragmentByTag(CustodianReturnShardFragment.TAG) ==
+ null) {
BaseFragment f = new CustodianReturnShardErrorFragment();
fm.beginTransaction()
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
@@ -106,19 +101,15 @@ public class CustodianReturnShardActivity extends BriarActivity
}
}
-
private void onReturnShardStateChanged(CustodianTask.State state) {
- if (state instanceof CustodianTask.State.Success) {
- CustodianReturnShardSuccessFragment fragment = new CustodianReturnShardSuccessFragment();
- showNextFragment(fragment);
- } else if (state instanceof CustodianTask.State.Failure) {
- // TODO error fragment here
- // TODO handle reason
- Toast.makeText(this,
- "Backup piece transfer failed",
- Toast.LENGTH_SHORT).show();
- finish();
- }
+ if (state instanceof CustodianTask.State.Failure) {
+ // TODO error fragment here
+ // TODO handle reason
+ Toast.makeText(this,
+ "Backup piece transfer failed",
+ Toast.LENGTH_SHORT).show();
+ finish();
+ }
}
private void showCameraFragment() {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java
index d893b5b0b..5c64cb44a 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java
@@ -5,6 +5,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -24,6 +25,7 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.annotation.UiThread;
+import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
@@ -53,6 +55,7 @@ public class CustodianReturnShardFragment extends BaseFragment
private LinearLayout cameraOverlay;
private View statusView;
private TextView status;
+ private ProgressBar bottomSpinner;
public static CustodianReturnShardFragment newInstance() {
Bundle args = new Bundle();
@@ -84,6 +87,7 @@ public class CustodianReturnShardFragment extends BaseFragment
cameraOverlay = view.findViewById(R.id.camera_overlay);
statusView = view.findViewById(R.id.status_container);
status = view.findViewById(R.id.connect_status);
+ bottomSpinner = view.findViewById(R.id.qr_code_progress_bar);
viewModel.getState().observe(getViewLifecycleOwner(),
this::onReturnShardStateChanged);
@@ -141,7 +145,6 @@ public class CustodianReturnShardFragment extends BaseFragment
@UiThread
private void onReturnShardStateChanged(@Nullable CustodianTask.State state) {
- LOG.info("State changed");
// if (state instanceof CustodianTask.State.Connecting) {
// try {
// cameraView.stop();
@@ -163,8 +166,9 @@ public class CustodianReturnShardFragment extends BaseFragment
} else if (state instanceof CustodianTask.State.ReceivingAck) {
status.setText("Receiving Ack");
} else if (state instanceof CustodianTask.State.Success) {
- // TODO
- status.setText(R.string.exchanging_contact_details);
+ statusView.setVisibility(INVISIBLE);
+ bottomSpinner.setVisibility(INVISIBLE);
+ showSuccessDialog();
} else if (state instanceof CustodianTask.State.Failure) {
// the activity will replace this fragment with an error fragment
statusView.setVisibility(INVISIBLE);
@@ -190,4 +194,15 @@ public class CustodianReturnShardFragment extends BaseFragment
requireActivity().getSupportFragmentManager().popBackStack();
}
+ private void showSuccessDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
+ R.style.BriarDialogTheme);
+ builder.setTitle(R.string.custodian_shard_sent);
+ //builder.setMessage();
+ builder.setPositiveButton(R.string.ok,
+ (dialog, which) -> viewModel.onSuccessDismissed());
+ builder.setIcon(R.drawable.ic_baseline_done_outline_24);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
}
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 cad5dd495..7a23c78ff 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
@@ -53,7 +53,7 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
final QrCodeDecoder qrCodeDecoder;
private boolean qrCodeRead = false;
private WifiManager wifiManager;
- private final MutableLiveEvent continueClicked = new MutableLiveEvent<>();
+ private final MutableLiveEvent continueClicked = new MutableLiveEvent<>();
private final MutableLiveEvent showCameraFragment =
new MutableLiveEvent<>();
private final MutableLiveEvent successDismissed =
@@ -177,7 +177,6 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
successDismissed.setEvent(true);
}
-
QrCodeDecoder getQrCodeDecoder() {
return qrCodeDecoder;
}
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 3ea98fcc4..fc38b9a2a 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
@@ -44,13 +44,6 @@ public class OwnerReturnShardActivity extends BaseActivity
private OwnerReturnShardViewModel viewModel;
-// private final ActivityResultLauncher permissionLauncher =
-// registerForActivityResult(
-// new ActivityResultContracts.RequestMultiplePermissions(),
-// r ->
-// permissionManager.onRequestPermissionResult(r,
-// viewModel::showQrCodeFragmentIfAllowed));
-
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
@@ -154,7 +147,8 @@ public class OwnerReturnShardActivity extends BaseActivity
"WARNING: Mismatched backup piece!",
Toast.LENGTH_LONG).show();
}
- boolean added = (result != RestoreAccount.AddReturnShardPayloadResult.DUPLICATE) ? true : false;
+ boolean added = result !=
+ RestoreAccount.AddReturnShardPayloadResult.DUPLICATE;
Toast.makeText(this,
"Success - got backup piece" + (added ? "" : " duplicate"),
Toast.LENGTH_SHORT).show();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java
index d66043907..b2bc2297d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java
@@ -27,7 +27,6 @@ import androidx.lifecycle.ViewModelProvider;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.widget.LinearLayout.HORIZONTAL;
@@ -158,5 +157,4 @@ public class OwnerReturnShardFragment extends BaseFragment
protected void finish() {
requireActivity().getSupportFragmentManager().popBackStack();
}
-
}
diff --git a/briar-android/src/main/res/drawable/button_positive_tiny_disable.xml b/briar-android/src/main/res/drawable/button_positive_tiny_disable.xml
new file mode 100644
index 000000000..a39d5afef
--- /dev/null
+++ b/briar-android/src/main/res/drawable/button_positive_tiny_disable.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/briar-android/src/main/res/drawable/ic_custodian_optional.xml b/briar-android/src/main/res/drawable/ic_custodian_optional.xml
new file mode 100644
index 000000000..12e93057b
--- /dev/null
+++ b/briar-android/src/main/res/drawable/ic_custodian_optional.xml
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/briar-android/src/main/res/drawable/ic_custodian_required.xml b/briar-android/src/main/res/drawable/ic_custodian_required.xml
new file mode 100644
index 000000000..65c59ea9f
--- /dev/null
+++ b/briar-android/src/main/res/drawable/ic_custodian_required.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/briar-android/src/main/res/drawable/ic_social_backup_group.xml b/briar-android/src/main/res/drawable/ic_social_backup_group.xml
new file mode 100644
index 000000000..b056737ab
--- /dev/null
+++ b/briar-android/src/main/res/drawable/ic_social_backup_group.xml
@@ -0,0 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/briar-android/src/main/res/layout/activity_preview_welcome.xml b/briar-android/src/main/res/layout/activity_preview_welcome.xml
index 293518b6b..fa59fb005 100644
--- a/briar-android/src/main/res/layout/activity_preview_welcome.xml
+++ b/briar-android/src/main/res/layout/activity_preview_welcome.xml
@@ -16,6 +16,7 @@
app:title="@string/setup_title"
app:titleTextColor="@android:color/white" />
-
+
+
\ No newline at end of file
diff --git a/briar-android/src/main/res/layout/fragment_new_or_recover.xml b/briar-android/src/main/res/layout/fragment_new_or_recover.xml
index ad5ec624b..5a2bf34f1 100644
--- a/briar-android/src/main/res/layout/fragment_new_or_recover.xml
+++ b/briar-android/src/main/res/layout/fragment_new_or_recover.xml
@@ -13,22 +13,38 @@
-
+ app:layout_constraintTop_toTopOf="parent"
+ android:drawableStart="@drawable/ic_contacts" />
+
+ app:layout_constraintTop_toBottomOf="@+id/textViewExplain"
+ tools:enabled="true"
+ android:drawableStart="@drawable/ic_repeat" />
diff --git a/briar-android/src/main/res/layout/fragment_setup_author_name.xml b/briar-android/src/main/res/layout/fragment_setup_author_name.xml
index 2b644cd45..35f225da5 100644
--- a/briar-android/src/main/res/layout/fragment_setup_author_name.xml
+++ b/briar-android/src/main/res/layout/fragment_setup_author_name.xml
@@ -47,14 +47,28 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_activity_horizontal"
android:enabled="false"
- android:text="@string/setup_next"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:text="@string/setup_new_account"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/nickname_entry_wrapper"
app:layout_constraintVertical_bias="1.0"
tools:enabled="true" />
+
+
diff --git a/briar-android/src/main/res/layout/fragment_shards_sent.xml b/briar-android/src/main/res/layout/fragment_shards_sent.xml
deleted file mode 100644
index 06be9a80a..000000000
--- a/briar-android/src/main/res/layout/fragment_shards_sent.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml b/briar-android/src/main/res/layout/fragment_social_backup_setup_explainer.xml
similarity index 51%
rename from briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml
rename to briar-android/src/main/res/layout/fragment_social_backup_setup_explainer.xml
index 8daec3c6b..84b779de5 100644
--- a/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml
+++ b/briar-android/src/main/res/layout/fragment_social_backup_setup_explainer.xml
@@ -8,43 +8,52 @@
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
- android:paddingBottom="@dimen/margin_medium">
+ android:paddingBottom="@dimen/margin_medium"
+ tools:ignore="VectorDrawableCompat">
+
+
+
+
+
+
-
-
-
-
+ app:layout_constraintTop_toBottomOf="@+id/textViewExplain" />
+
diff --git a/briar-android/src/main/res/layout/qr_code_view.xml b/briar-android/src/main/res/layout/qr_code_view.xml
index 603549056..97df526c0 100644
--- a/briar-android/src/main/res/layout/qr_code_view.xml
+++ b/briar-android/src/main/res/layout/qr_code_view.xml
@@ -6,6 +6,7 @@
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index f30886fd8..935f68e2a 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -653,6 +653,8 @@
Select Trusted Contacts:
Please select at least %d contacts
Please select at least %d more contacts
+ Too many! Please select no more than %d contacts
+
Choose the minimum number of trusted contacts needed to restore your account
Two trusted contacts will be needed to restore your account
Secure
@@ -661,9 +663,21 @@
Danger of loss – lower threshold recommended
Choose Threshold
%d of %d contacts needed to recover your account
- Backup pieces sent to trusted contacts
+
+ Social Backup created
+ Backup pieces sent to trusted contacts
+
+ Backup your Briar identity and contacts list
+ Choose a set of trusted contacts to send backup pieces to.\n\nYou decide how many of these contacts must help you recover your account.\n\nFor example, you can choose three trusted contacts and that any two of them are needed to recover.
+ Choose trusted contacts
+
+ Backup your Briar account
+ Social backup feature allows you to recover your account with the help of trusted contacts
+
+
+
You need to meet your trusted contacts in-person to receive pieces
Your trusted contact must scan a QR code to initiate the transfer.\n\nYou must both be connected to the same wifi network
Begin
diff --git a/briar-android/src/main/res/xml/settings.xml b/briar-android/src/main/res/xml/settings.xml
index a57771c52..43571518c 100644
--- a/briar-android/src/main/res/xml/settings.xml
+++ b/briar-android/src/main/res/xml/settings.xml
@@ -96,7 +96,7 @@
app:iconSpaceReserved="false">