From 4d9018316fa5a9af714de44224a440e0fa78be57 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 31 Jul 2023 17:50:04 +0200 Subject: add cancel button, call provider stetup command in ConfigureProviderFragment and listen to the result, implementing happy path --- app/src/main/AndroidManifest.xml | 2 + .../se/leap/bitmaskclient/base/StartActivity.java | 1 - .../bitmaskclient/base/views/ProgressSpinner.java | 12 ++- .../providersetup/activities/CancelCallback.java | 5 + .../providersetup/activities/SetupActivity.java | 43 ++++++++- .../activities/SetupActivityCallback.java | 29 ++++++ .../providersetup/activities/SetupInterface.java | 20 ---- .../fragments/ConfigureProviderFragment.java | 88 ++++++++++++----- .../fragments/ProviderSelectionFragment.java | 42 ++++++-- app/src/main/res/layout/activity_setup.xml | 10 ++ app/src/main/res/layout/f_configure_provider.xml | 107 +++++++++++++++------ 11 files changed, 275 insertions(+), 84 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CancelCallback.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivityCallback.java delete mode 100644 app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupInterface.java (limited to 'app/src/main') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a9971904..091fa0b6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + @@ -28,6 +29,7 @@ android:theme="@style/BitmaskTheme"> 0) { + if ((progress / 10) == 0) { + text = text + " "; + } + if ((progress / 100) == 0) { + text = text + " "; + } + text = text + progress + "%"; + } + textView.setText(text); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CancelCallback.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CancelCallback.java new file mode 100644 index 00000000..a3f387d8 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CancelCallback.java @@ -0,0 +1,5 @@ +package se.leap.bitmaskclient.providersetup.activities; + +public interface CancelCallback { + void onCanceled(); +} diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java index f62f959d..33e9cbbd 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java @@ -4,6 +4,8 @@ import static android.view.View.GONE; import static android.view.View.VISIBLE; import static androidx.appcompat.app.ActionBar.DISPLAY_SHOW_CUSTOM; +import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; + import androidx.annotation.ColorInt; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; @@ -13,22 +15,29 @@ import androidx.viewpager2.widget.ViewPager2; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; +import android.util.Log; import android.view.Gravity; import android.view.View; -import android.widget.Button; import android.widget.Toast; +import java.util.HashSet; +import java.util.Iterator; + import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.views.ActionBarTitle; import se.leap.bitmaskclient.databinding.ActivitySetupBinding; import se.leap.bitmaskclient.providersetup.SetupViewPagerAdapter; +import se.leap.bitmaskclient.tor.TorServiceCommand; +import se.leap.bitmaskclient.tor.TorStatusObservable; -public class SetupActivity extends AppCompatActivity implements SetupInterface { +public class SetupActivity extends AppCompatActivity implements SetupActivityCallback { + private static final String TAG = SetupActivity.class.getSimpleName(); ActivitySetupBinding binding; Provider provider; + private final HashSet cancelCallbacks = new HashSet<>(); @SuppressLint("ClickableViewAccessibility") @Override @@ -66,6 +75,17 @@ public class SetupActivity extends AppCompatActivity implements SetupInterface { } binding.viewPager.setCurrentItem(newPos); }); + binding.setupCancelButton.setOnClickListener(v -> { + binding.viewPager.setCurrentItem(0, false); + if (TorStatusObservable.getStatus() != OFF) { + Log.d(TAG, "SHUTDOWN - cancelSettingUpProvider"); + TorServiceCommand.stopTorServiceAsync(this); + } + provider = null; + for (CancelCallback cancelCallback : cancelCallbacks) { + cancelCallback.onCanceled(); + } + }); setupActionBar(); } @@ -115,14 +135,24 @@ public class SetupActivity extends AppCompatActivity implements SetupInterface { binding.viewPager.unregisterOnPageChangeCallback(callback); } + @Override + public void registerCancelCallback(CancelCallback cancelCallback) { + cancelCallbacks.add(cancelCallback); + } + + @Override + public void removeCancelCallback(CancelCallback cancelCallback) { + cancelCallbacks.remove(cancelCallback); + } + @Override public void setNavigationButtonHidden(boolean isHidden) { binding.setupNextButton.setVisibility(isHidden ? GONE : VISIBLE); } @Override - public void onCanceled() { - binding.viewPager.setCurrentItem(0); + public void setCancelButtonHidden(boolean isHidden) { + binding.setupCancelButton.setVisibility(isHidden ? GONE : VISIBLE); } @Override @@ -130,6 +160,11 @@ public class SetupActivity extends AppCompatActivity implements SetupInterface { this.provider = provider; } + @Override + public void onConfigurationSuccess() { + binding.viewPager.setCurrentItem(binding.viewPager.getCurrentItem() + 1); + } + @Override public Provider getSelectedProvider() { return provider; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivityCallback.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivityCallback.java new file mode 100644 index 00000000..8fe4118d --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivityCallback.java @@ -0,0 +1,29 @@ +package se.leap.bitmaskclient.providersetup.activities; + +import androidx.viewpager2.widget.ViewPager2; + +import se.leap.bitmaskclient.base.models.Provider; + +public interface SetupActivityCallback { + + void onSetupStepValidationChanged(boolean isValid); + void registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback); + void removeOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback); + + void registerCancelCallback(CancelCallback cancelCallback); + + void removeCancelCallback(CancelCallback cancelCallback); + + + void setNavigationButtonHidden(boolean isHidden); + + void setCancelButtonHidden(boolean isHidden); + + void onProviderSelected(Provider provider); + + void onConfigurationSuccess(); + + Provider getSelectedProvider(); + +} + diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupInterface.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupInterface.java deleted file mode 100644 index 1438ee5d..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupInterface.java +++ /dev/null @@ -1,20 +0,0 @@ -package se.leap.bitmaskclient.providersetup.activities; - -import androidx.viewpager2.widget.ViewPager2; - -import se.leap.bitmaskclient.base.models.Provider; - -public interface SetupInterface { - - void onSetupStepValidationChanged(boolean isValid); - void registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback); - void removeOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback); - void setNavigationButtonHidden(boolean isHidden); - void onCanceled(); - - void onProviderSelected(Provider provider); - - Provider getSelectedProvider(); - -} - diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index ceed2c3c..42d516a0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -1,9 +1,14 @@ package se.leap.bitmaskclient.providersetup.fragments; +import static android.app.Activity.RESULT_CANCELED; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.utils.ViewHelper.animateContainerVisibility; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.tor.TorStatusObservable.getBootstrapProgress; import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastLogs; @@ -12,6 +17,7 @@ import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastTorLog; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -28,21 +34,27 @@ import java.util.List; import java.util.Observable; import java.util.Observer; +import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.databinding.FConfigureProviderBinding; +import se.leap.bitmaskclient.eip.EipSetupListener; +import se.leap.bitmaskclient.eip.EipSetupObserver; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; import se.leap.bitmaskclient.providersetup.TorLogAdapter; -import se.leap.bitmaskclient.providersetup.activities.SetupInterface; +import se.leap.bitmaskclient.providersetup.activities.CancelCallback; +import se.leap.bitmaskclient.providersetup.activities.SetupActivityCallback; import se.leap.bitmaskclient.tor.TorStatusObservable; -public class ConfigureProviderFragment extends Fragment implements Observer { +public class ConfigureProviderFragment extends Fragment implements Observer, CancelCallback, EipSetupListener { + + private static final String TAG = ConfigureProviderFragment.class.getSimpleName(); public static ConfigureProviderFragment newInstance(int position) { return new ConfigureProviderFragment(position); } FConfigureProviderBinding binding; - private SetupInterface setupInterface; + private SetupActivityCallback setupActivityCallback; private boolean isExpanded = false; private final int position; private ViewPager2.OnPageChangeCallback viewPagerCallback; @@ -56,6 +68,7 @@ public class ConfigureProviderFragment extends Fragment implements Observer { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + torLogAdapter = new TorLogAdapter(getLastLogs()); } @Override @@ -64,13 +77,16 @@ public class ConfigureProviderFragment extends Fragment implements Observer { binding = FConfigureProviderBinding.inflate(inflater, container, false); binding.detailContainer.setVisibility(PreferenceHelper.getUseSnowflake(getContext()) ? VISIBLE : GONE); binding.detailHeaderContainer.setOnClickListener(v -> { - binding.ivExpand.animate().setDuration(250).rotation(isExpanded ? 0 : 270); + binding.ivExpand.animate().setDuration(250).rotation(isExpanded ? -90 : 0); showConnectionDetails(); animateContainerVisibility(binding.expandableDetailContainer, isExpanded); isExpanded = !isExpanded; }); binding.ivExpand.animate().setDuration(0).rotation(270); + LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); + binding.connectionDetailLogs.setLayoutManager(layoutManager); + binding.connectionDetailLogs.setAdapter(torLogAdapter); return binding.getRoot(); } @@ -85,35 +101,40 @@ public class ConfigureProviderFragment extends Fragment implements Observer { @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - setupInterface = (SetupInterface) getActivity(); - viewPagerCallback = new ViewPager2.OnPageChangeCallback() { - @Override - public void onPageSelected(int position) { - super.onPageSelected(position); - if (position == ConfigureProviderFragment.this.position) { - binding.detailContainer.setVisibility(PreferenceHelper.getUseSnowflake(getContext()) ? VISIBLE : GONE); - setupInterface.setNavigationButtonHidden(true); - ProviderAPICommand.execute(context, SET_UP_PROVIDER, setupInterface.getSelectedProvider()); + if (getActivity() instanceof SetupActivityCallback) { + setupActivityCallback = (SetupActivityCallback) getActivity(); + viewPagerCallback = new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + if (position == ConfigureProviderFragment.this.position) { + binding.detailContainer.setVisibility(PreferenceHelper.getUseSnowflake(getContext()) ? VISIBLE : GONE); + setupActivityCallback.setNavigationButtonHidden(true); + setupActivityCallback.setCancelButtonHidden(false); + ProviderAPICommand.execute(context, SET_UP_PROVIDER, setupActivityCallback.getSelectedProvider()); + } } - } - }; - setupInterface.registerOnPageChangeCallback(viewPagerCallback); + }; + setupActivityCallback.registerOnPageChangeCallback(viewPagerCallback); + setupActivityCallback.registerCancelCallback(this); + } TorStatusObservable.getInstance().addObserver(this); + EipSetupObserver.addListener(this); } @Override public void onDetach() { super.onDetach(); TorStatusObservable.getInstance().deleteObserver(this); - setupInterface.removeOnPageChangeCallback(viewPagerCallback); - setupInterface = null; + if (setupActivityCallback != null) { + setupActivityCallback.removeOnPageChangeCallback(viewPagerCallback); + setupActivityCallback.removeCancelCallback(this); + setupActivityCallback = null; + } + EipSetupObserver.removeListener(this); } protected void showConnectionDetails() { - LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); - binding.connectionDetailLogs.setLayoutManager(layoutManager); - torLogAdapter = new TorLogAdapter(getLastLogs()); - binding.connectionDetailLogs.setAdapter(torLogAdapter); binding.connectionDetailLogs.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -150,6 +171,7 @@ public class ConfigureProviderFragment extends Fragment implements Observer { setLogs(getLastTorLog(), getLastSnowflakeLog(), getLastLogs()); } } + binding.tvProgressStatus.setText(TorStatusObservable.getStringForCurrentStatus(activity)); binding.progressSpinner.update(getBootstrapProgress()); }); } @@ -160,4 +182,26 @@ public class ConfigureProviderFragment extends Fragment implements Observer { binding.torState.setText(torLog); binding.snowflakeState.setText(snowflakeLog); } + + @Override + public void onCanceled() { + + } + + @Override + public void handleEipEvent(Intent intent) {} + + @Override + public void handleProviderApiEvent(Intent intent) { + int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED); + Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); + if (resultData == null) { + resultData = Bundle.EMPTY; + } + if (resultCode == PROVIDER_OK) { + Provider provider = resultData.getParcelable(PROVIDER_KEY); + setupActivityCallback.onProviderSelected(provider); + setupActivityCallback.onConfigurationSuccess(); + } + } } \ No newline at end of file diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java index 45ba73dc..6ebb149c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java @@ -16,21 +16,39 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; import java.util.ArrayList; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.databinding.FProviderSelectionBinding; -import se.leap.bitmaskclient.providersetup.activities.SetupInterface; +import se.leap.bitmaskclient.providersetup.activities.CancelCallback; +import se.leap.bitmaskclient.providersetup.activities.SetupActivityCallback; import se.leap.bitmaskclient.providersetup.fragments.viewmodel.ProviderSelectionViewModel; import se.leap.bitmaskclient.providersetup.fragments.viewmodel.ProviderSelectionViewModelFactory; -public class ProviderSelectionFragment extends Fragment { +public class ProviderSelectionFragment extends Fragment implements CancelCallback { private ProviderSelectionViewModel viewModel; private ArrayList radioButtons; - private SetupInterface setupCallback; + private SetupActivityCallback setupCallback; + + private FProviderSelectionBinding binding; + + private final ViewPager2.OnPageChangeCallback onPageChangeCallback = new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + if (position == 0) { + if (setupCallback != null) { + setupCallback.setCancelButtonHidden(!ProviderObservable.getInstance().getCurrentProvider().isConfigured()); + setupCallback.setNavigationButtonHidden(false); + } + } + } + }; public static ProviderSelectionFragment newInstance() { return new ProviderSelectionFragment(); @@ -49,7 +67,7 @@ public class ProviderSelectionFragment extends Fragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - FProviderSelectionBinding binding = FProviderSelectionBinding.inflate(inflater, container, false); + binding = FProviderSelectionBinding.inflate(inflater, container, false); radioButtons = new ArrayList<>(); for (int i = 0; i < viewModel.size(); i++) { @@ -108,20 +126,27 @@ public class ProviderSelectionFragment extends Fragment { @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - if (getActivity() instanceof SetupInterface) { - setupCallback = (SetupInterface) getActivity(); + if (getActivity() instanceof SetupActivityCallback) { + setupCallback = (SetupActivityCallback) getActivity(); + setupCallback.registerOnPageChangeCallback(onPageChangeCallback); + setupCallback.registerCancelCallback(this); } } @Override public void onDetach() { super.onDetach(); + if (setupCallback != null) { + setupCallback.removeOnPageChangeCallback(onPageChangeCallback); + setupCallback.removeCancelCallback(this); + } setupCallback = null; } @Override public void onDestroyView() { super.onDestroyView(); + binding = null; radioButtons = null; } @@ -135,4 +160,9 @@ public class ProviderSelectionFragment extends Fragment { super.onResume(); setupCallback.onSetupStepValidationChanged(viewModel.isValidConfig()); } + + @Override + public void onCanceled() { + binding.providerRadioGroup.check(0); + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_setup.xml b/app/src/main/res/layout/activity_setup.xml index fe302bb1..770b8ab3 100644 --- a/app/src/main/res/layout/activity_setup.xml +++ b/app/src/main/res/layout/activity_setup.xml @@ -114,5 +114,15 @@ android:layout_alignParentBottom="true" android:text="@string/next" /> + +