From 6e67c1dfbfc8c2497ea1a972d2a3763a44f92cb5 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 31 Aug 2021 12:39:52 +0200 Subject: [PATCH] Add revoke remote wipe status option to conversation actions menu --- briar-android/src/main/AndroidManifest.xml | 9 +++ .../android/activity/ActivityComponent.java | 7 ++ .../conversation/ConversationActivity.java | 14 ++++ .../conversation/ConversationViewModel.java | 9 +++ .../ActivateRemoteWipeSuccessFragment.java | 6 +- .../revoke/RevokeRemoteWipeActivity.java | 67 +++++++++++++++++++ .../revoke/RevokeRemoteWipeState.java | 7 ++ .../RevokeRemoteWipeSuccessFragment.java | 55 +++++++++++++++ .../revoke/RevokeRemoteWipeViewModel.java | 60 +++++++++++++++++ .../socialbackup/CustodianStatusAdapter.java | 27 ++++++++ .../main/res/menu/conversation_actions.xml | 7 ++ briar-android/src/main/res/values/strings.xml | 4 ++ 12 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeActivity.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeState.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeSuccessFragment.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeViewModel.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianStatusAdapter.java diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 3452e6873..76f00e6c4 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -499,6 +499,15 @@ android:value="org.briarproject.briar.android.conversation.ConversationActivity" /> + + + + 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 178df5d3d..2c88bbf79 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 @@ -73,6 +73,9 @@ import org.briarproject.briar.android.remotewipe.WiperSelectorFragment; import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeActivity; import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeExplainerFragment; import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeSuccessFragment; +import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeActivity; +import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeState; +import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeSuccessFragment; import org.briarproject.briar.android.reporting.CrashFragment; import org.briarproject.briar.android.reporting.CrashReportActivity; import org.briarproject.briar.android.reporting.ReportFormFragment; @@ -229,6 +232,8 @@ public interface ActivityComponent { void inject(RemoteWipeActivatedActivity remoteWipeActivatedActivity); + void inject(RevokeRemoteWipeActivity revokeRemoteWipeActivity); + // Fragments void inject(AuthorNameFragment fragment); @@ -330,4 +335,6 @@ public interface ActivityComponent { void inject(ActivateRemoteWipeExplainerFragment activateRemoteWipeExplainerFragment); void inject(ActivateRemoteWipeSuccessFragment activateRemoteWipeSuccessFragment); + + void inject(RevokeRemoteWipeSuccessFragment revokeRemoteWipeSuccessFragment); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index c7f3a6385..c43c91b7a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -53,6 +53,7 @@ import org.briarproject.briar.android.forum.ForumActivity; import org.briarproject.briar.android.introduction.IntroductionActivity; import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeActivity; +import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeActivity; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity; import org.briarproject.briar.android.util.BriarSnackbarBuilder; import org.briarproject.briar.android.view.BriarRecyclerView; @@ -379,6 +380,13 @@ public class ConversationActivity extends BriarActivity } }); + // enable revoke remote wipe action if available + observeOnce(viewModel.isRemoteWiper(), this, isWiper -> { + if (isWiper != null && isWiper) { + menu.findItem(R.id.action_revoke_remote_wipe).setEnabled(true); + } + }); + return super.onCreateOptionsMenu(menu); } @@ -417,6 +425,12 @@ public class ConversationActivity extends BriarActivity r.putExtra(CONTACT_ID, contactId.getInt()); startActivity(r); return true; + case R.id.action_revoke_remote_wipe: + if (contactId == null) return false; + Intent s = new Intent(this, RevokeRemoteWipeActivity.class); + s.putExtra(CONTACT_ID, contactId.getInt()); + startActivity(s); + return true; default: return super.onOptionsItemSelected(item); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java index c90c789d6..398799980 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java @@ -107,6 +107,7 @@ public class ConversationViewModel extends DbViewModel private final MutableLiveEvent addedHeader = new MutableLiveEvent<>(); private final MutableLiveData amRemoteWiper = new MutableLiveData<>(); + private final MutableLiveData isRemoteWiper = new MutableLiveData<>(); @Inject ConversationViewModel(Application application, @@ -306,6 +307,10 @@ public class ConversationViewModel extends DbViewModel boolean amWiper = db.transactionWithResult(true, txn -> remoteWipeManager.amWiper(txn, c)); amRemoteWiper.postValue(amWiper); + + boolean isWiper = db.transactionWithResult(true, + txn -> remoteWipeManager.isWiper(txn, c)); + isRemoteWiper.postValue(isWiper); } @DatabaseExecutor @@ -395,6 +400,10 @@ public class ConversationViewModel extends DbViewModel return amRemoteWiper; } + LiveData isRemoteWiper() { + return isRemoteWiper; + } + @UiThread void recheckFeaturesAndOnboarding(ContactId contactId) { runOnDbThread(() -> { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/activate/ActivateRemoteWipeSuccessFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/activate/ActivateRemoteWipeSuccessFragment.java index d5d3ad343..8daec0124 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/activate/ActivateRemoteWipeSuccessFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/activate/ActivateRemoteWipeSuccessFragment.java @@ -9,6 +9,7 @@ import android.widget.Button; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.fragment.BaseFragment; +import org.briarproject.briar.android.remotewipe.revoke.RevokeRemoteWipeViewModel; import javax.inject.Inject; @@ -24,13 +25,13 @@ public class ActivateRemoteWipeSuccessFragment extends BaseFragment { @Inject ViewModelProvider.Factory viewModelFactory; - private ActivateRemoteWipeViewModel viewModel; + private RevokeRemoteWipeViewModel viewModel; @Override public void injectFragment(ActivityComponent component) { component.inject(this); viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) - .get(ActivateRemoteWipeViewModel.class); + .get(RevokeRemoteWipeViewModel.class); } @Nullable @@ -38,6 +39,7 @@ public class ActivateRemoteWipeSuccessFragment extends BaseFragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + // TODO change layout View view = inflater.inflate(R.layout.fragment_activate_remote_wipe_success, container, false); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeActivity.java new file mode 100644 index 000000000..819b88f41 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeActivity.java @@ -0,0 +1,67 @@ +package org.briarproject.briar.android.remotewipe.revoke; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.Toast; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.fragment.BaseFragment; + +import javax.inject.Inject; + +import androidx.lifecycle.ViewModelProvider; + +import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID; + +public class RevokeRemoteWipeActivity extends BriarActivity implements + BaseFragment.BaseFragmentListener { + + @Inject + ViewModelProvider.Factory viewModelFactory; + RevokeRemoteWipeViewModel viewModel; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + + viewModel = new ViewModelProvider(this, viewModelFactory) + .get(RevokeRemoteWipeViewModel.class); + + viewModel.getState().observe(this, this::onStateChanged); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_distributed_backup); + + if (savedInstanceState == null) { + Intent intent = getIntent(); + int id = intent.getIntExtra(CONTACT_ID, -1); + if (id == -1) throw new IllegalStateException("No ContactId"); + ContactId contactId = new ContactId(id); + viewModel.revokeRemoteWipeStatus(contactId); +// showInitialFragment(new ActivateRemoteWipeExplainerFragment()); + } + } + + private void onStateChanged(RevokeRemoteWipeState state) { + switch(state) { + case FAILED: + // TODO change text + Toast.makeText(this, + R.string.remote_wipe_activate_failure, + Toast.LENGTH_LONG).show(); + break; + case SUCCESS: + showNextFragment(new RevokeRemoteWipeSuccessFragment()); + break; + default: // FINISHED or CANCELLED + finish(); + break; + } + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeState.java b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeState.java new file mode 100644 index 000000000..f18fe2e84 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeState.java @@ -0,0 +1,7 @@ +package org.briarproject.briar.android.remotewipe.revoke; + +public enum RevokeRemoteWipeState { + FAILED, + SUCCESS, + FINISHED +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeSuccessFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeSuccessFragment.java new file mode 100644 index 000000000..666bc7ea9 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeSuccessFragment.java @@ -0,0 +1,55 @@ +package org.briarproject.briar.android.remotewipe.revoke; + +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 org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeSuccessFragment; +import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeViewModel; + +import javax.inject.Inject; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; + +public class RevokeRemoteWipeSuccessFragment extends BaseFragment { + + public static final String TAG = + ActivateRemoteWipeSuccessFragment.class.getName(); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private ActivateRemoteWipeViewModel viewModel; + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(ActivateRemoteWipeViewModel.class); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_activate_remote_wipe_success, + 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/remotewipe/revoke/RevokeRemoteWipeViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeViewModel.java new file mode 100644 index 000000000..31f6d4cf2 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/remotewipe/revoke/RevokeRemoteWipeViewModel.java @@ -0,0 +1,60 @@ +package org.briarproject.briar.android.remotewipe.revoke; + +import android.app.Application; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.briar.android.remotewipe.activate.ActivateRemoteWipeState; +import org.briarproject.briar.api.remotewipe.RemoteWipeManager; + +import javax.inject.Inject; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.MutableLiveData; + +public class RevokeRemoteWipeViewModel extends AndroidViewModel { + + private final RemoteWipeManager remoteWipeManager; + private final DatabaseComponent db; + private final MutableLiveData state = new MutableLiveData<>(); + private ContactId contactId; + + @Inject + public RevokeRemoteWipeViewModel( + @NonNull Application application, + RemoteWipeManager remoteWipeManager, + DatabaseComponent db) { + super(application); + this.remoteWipeManager = remoteWipeManager; + this.db = db; + } + + public MutableLiveData getState() { + return state; + } + + public void revokeRemoteWipeStatus(ContactId c) { + contactId = c; + try { + db.transaction(false, txn -> { + remoteWipeManager.revoke(txn, contactId); + }); + } catch (DbException e) { + state.postValue(RevokeRemoteWipeState.FAILED); + } catch (FormatException e) { + state.postValue(RevokeRemoteWipeState.FAILED); + } + state.postValue(RevokeRemoteWipeState.SUCCESS); + } + + public void onCancelClicked() { +// state.postValue(ActivateRemoteWipeState.CANCELLED); + } + + public void onSuccessDismissed() { + state.postValue(RevokeRemoteWipeState.FINISHED); + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianStatusAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianStatusAdapter.java new file mode 100644 index 000000000..0e6922aea --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianStatusAdapter.java @@ -0,0 +1,27 @@ +package org.briarproject.briar.android.socialbackup; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.briar.R; +import org.briarproject.briar.android.contact.BaseContactListAdapter; +import org.briarproject.briar.android.contact.ContactItem; +import org.briarproject.briar.android.contact.ContactItemViewHolder; + +public class CustodianStatusAdapter extends BaseContactListAdapter> { + + CustodianStatusAdapter(Context context) { + super(context, ContactItem.class, null); + } + + @Override + public ContactItemViewHolder onCreateViewHolder( + ViewGroup viewGroup, int i) { + View v = LayoutInflater.from(viewGroup.getContext()).inflate( + R.layout.list_item_contact_small, viewGroup, false); + return new ContactItemViewHolder<>(v); + } + +} diff --git a/briar-android/src/main/res/menu/conversation_actions.xml b/briar-android/src/main/res/menu/conversation_actions.xml index 589564aa1..5c699cac1 100644 --- a/briar-android/src/main/res/menu/conversation_actions.xml +++ b/briar-android/src/main/res/menu/conversation_actions.xml @@ -39,4 +39,11 @@ android:title="@string/activate_remote_wipe" android:enabled="false" app:showAsAction="never"/> + + \ No newline at end of file diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 30f5feaee..3a3c9aed1 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -760,5 +760,9 @@ Activate a remote wipe of this contact\'s device If confirmed by a second contact, sending this signal will remove all briar contacts and messages from this contact\s device. + + Revoke Remote Wipe + Revoke remote wipe status + Ok