summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap/bitmaskclient/providersetup/activities
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/providersetup/activities')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CancelCallback.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java52
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java328
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivityCallback.java33
4 files changed, 367 insertions, 51 deletions
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/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java
index caba1436..1bf66d7d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java
@@ -11,11 +11,9 @@ import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastSnowflakeLog;
import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastTorLog;
import static se.leap.bitmaskclient.tor.TorStatusObservable.getStringForCurrentStatus;
-import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -40,8 +38,8 @@ import java.util.Observer;
import butterknife.BindView;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.models.Provider;
-import se.leap.bitmaskclient.base.utils.PreferenceHelper;
import se.leap.bitmaskclient.base.views.ProviderHeaderView;
+import se.leap.bitmaskclient.providersetup.TorLogAdapter;
import se.leap.bitmaskclient.tor.TorStatusObservable;
/**
@@ -54,7 +52,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple
private static final String TAG = ConfigWizardBaseActivity.class.getName();
public static final float GUIDE_LINE_COMPACT_DELTA = 0.1f;
- protected SharedPreferences preferences;
@BindView(R.id.header)
ProviderHeaderView providerHeaderView;
@@ -133,7 +130,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- preferences = PreferenceHelper.getSharedPreferences(this);
provider = getIntent().getParcelableExtra(PROVIDER_KEY);
}
@@ -431,50 +427,4 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple
snowflakeState.setText(snowflakeLog);
}
- static class TorLogAdapter extends RecyclerView.Adapter<TorLogAdapter.ViewHolder> {
- private List<String> values;
- private boolean postponeUpdate;
-
- static class ViewHolder extends RecyclerView.ViewHolder {
- public AppCompatTextView logTextLabel;
- public View layout;
-
- public ViewHolder(View v) {
- super(v);
- layout = v;
- logTextLabel = v.findViewById(android.R.id.text1);
- }
- }
-
- public void updateData(List<String> data) {
- values = data;
- if (!postponeUpdate) {
- notifyDataSetChanged();
- }
- }
-
- public TorLogAdapter(List<String> data) {
- values = data;
- }
-
- @NonNull
- @Override
- public TorLogAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- LayoutInflater inflater = LayoutInflater.from(
- parent.getContext());
- View v = inflater.inflate(R.layout.v_log_item, parent, false);
- return new TorLogAdapter.ViewHolder(v);
- }
-
- @Override
- public void onBindViewHolder(TorLogAdapter.ViewHolder holder, final int position) {
- final String log = values.get(position);
- holder.logTextLabel.setText(log);
- }
-
- @Override
- public int getItemCount() {
- return values.size();
- }
- }
}
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
new file mode 100644
index 00000000..27ca6658
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java
@@ -0,0 +1,328 @@
+package se.leap.bitmaskclient.providersetup.activities;
+
+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.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences;
+import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CONFIGURE_PROVIDER_FRAGMENT;
+import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.net.VpnService;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
+import androidx.core.content.res.ResourcesCompat;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.viewpager2.widget.ViewPager2;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import se.leap.bitmaskclient.BuildConfig;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.base.utils.ViewHelper;
+import se.leap.bitmaskclient.base.views.ActionBarTitle;
+import se.leap.bitmaskclient.databinding.ActivitySetupBinding;
+import se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog;
+import se.leap.bitmaskclient.providersetup.SetupViewPagerAdapter;
+import se.leap.bitmaskclient.tor.TorServiceCommand;
+import se.leap.bitmaskclient.tor.TorStatusObservable;
+
+public class SetupActivity extends AppCompatActivity implements SetupActivityCallback, ProviderSetupFailedDialog.DownloadFailedDialogInterface {
+
+ public static final String EXTRA_PROVIDER = "EXTRA_PROVIDER";
+ public static final String EXTRA_CURRENT_POSITION = "EXTRA_CURRENT_POSITION";
+ private static final String TAG = SetupActivity.class.getSimpleName();
+ ActivitySetupBinding binding;
+ Provider provider;
+ private int currentPosition = 0;
+
+ private final HashSet<CancelCallback> cancelCallbacks = new HashSet<>();
+ private FragmentManagerEnhanced fragmentManager;
+ SetupViewPagerAdapter adapter;
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ provider = savedInstanceState.getParcelable(EXTRA_PROVIDER);
+ currentPosition = savedInstanceState.getInt(EXTRA_CURRENT_POSITION);
+ }
+
+ binding = ActivitySetupBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager());
+ ArrayList<View> indicatorViews = new ArrayList<>();
+
+ for (int i = 0; i < 4; i++) {
+ addIndicatorView(indicatorViews);
+ }
+
+ Intent requestVpnPermission = VpnService.prepare(this);
+ if (requestVpnPermission != null) {
+ addIndicatorView(indicatorViews);
+ addIndicatorView(indicatorViews);
+ }
+
+ boolean showNotificationPermissionFragments = false;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ if (ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
+ showNotificationPermissionFragments = shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS);
+ if (showNotificationPermissionFragments) {
+ addIndicatorView(indicatorViews);
+ addIndicatorView(indicatorViews);
+ }
+ }
+ }
+
+ adapter = new SetupViewPagerAdapter(getSupportFragmentManager(), getLifecycle(), requestVpnPermission, showNotificationPermissionFragments);
+
+ binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
+ @Override
+ public void onPageSelected(int position) {
+ super.onPageSelected(position);
+ currentPosition = position;
+ for (int i = 0; i < indicatorViews.size(); i++) {
+ ((ViewGroup) indicatorViews.get(i)).
+ getChildAt(0).
+ setBackgroundColor(ContextCompat.getColor(SetupActivity.this, (i == position) ? R.color.colorPrimaryDark : R.color.colorDisabled));
+ }
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(position == 0 && ProviderObservable.getInstance().getCurrentProvider().isConfigured());
+ }
+ }
+ });
+ binding.viewPager.setAdapter(adapter);
+ binding.viewPager.setUserInputEnabled(false);
+ binding.viewPager.setCurrentItem(currentPosition, false);
+
+ binding.setupNextButton.setOnClickListener(v -> {
+ int currentPos = binding.viewPager.getCurrentItem();
+ int newPos = currentPos + 1;
+ if (newPos >= binding.viewPager.getAdapter().getItemCount()) {
+ Toast.makeText(SetupActivity.this, "SetupFinished \\o/", Toast.LENGTH_LONG).show();
+ return;
+ }
+ binding.viewPager.setCurrentItem(newPos);
+ });
+ binding.setupCancelButton.setOnClickListener(v -> {
+ cancel();
+ });
+ setupActionBar();
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (provider != null) {
+ outState.putParcelable(EXTRA_PROVIDER, provider);
+ outState.putInt(EXTRA_CURRENT_POSITION, currentPosition);
+ }
+ }
+
+ private void cancel() {
+ 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();
+ }
+ }
+
+ private void addIndicatorView(ArrayList<View> indicatorViews) {
+ // FIXME: we have to work around a bug in our usage of CardView, that
+ // doesn't let us programmatically add new indicator views as needed.
+ // for some reason the cardBackgroundColor property is ignored if we add
+ // the card view dynamically
+ View v = binding.indicatorContainer.getChildAt(indicatorViews.size());
+ if (v == null) {
+ throw new IllegalStateException("Too few indicator views in layout hard-coded");
+ }
+ v.setVisibility(VISIBLE);
+ indicatorViews.add(v);
+ }
+
+ private void setupActionBar() {
+ setSupportActionBar(binding.toolbar);
+ final ActionBar actionBar = getSupportActionBar();
+ Context context = actionBar.getThemedContext();
+ actionBar.setDisplayOptions(DISPLAY_SHOW_CUSTOM);
+
+ ActionBarTitle actionBarTitle = new ActionBarTitle(context);
+ actionBarTitle.setTitleCaps(BuildConfig.actionbar_capitalize_title);
+ actionBarTitle.setTitle(getString(R.string.app_name));
+
+ final Drawable upArrow = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_back, getTheme());
+ actionBar.setHomeAsUpIndicator(upArrow);
+
+ actionBar.setDisplayHomeAsUpEnabled(currentPosition == 0 && ProviderObservable.getInstance().getCurrentProvider().isConfigured());
+ ViewHelper.setActivityBarColor(this, R.color.bg_setup_status_bar, R.color.bg_setup_action_bar, R.color.colorActionBarTitleFont);
+ @ColorInt int titleColor = ContextCompat.getColor(context, R.color.colorActionBarTitleFont);
+ actionBarTitle.setTitleTextColor(titleColor);
+
+ actionBarTitle.setCentered(BuildConfig.actionbar_center_title);
+ actionBarTitle.setSingleBoldTitle();
+ if (BuildConfig.actionbar_center_title) {
+ ActionBar.LayoutParams params = new ActionBar.LayoutParams(
+ ActionBar.LayoutParams.WRAP_CONTENT,
+ ActionBar.LayoutParams.MATCH_PARENT,
+ Gravity.CENTER);
+ actionBar.setCustomView(actionBarTitle, params);
+ } else {
+ actionBar.setCustomView(actionBarTitle);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onSetupStepValidationChanged(boolean isValid) {
+ binding.setupNextButton.setEnabled(isValid);
+ }
+
+ @Override
+ public void registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) {
+ binding.viewPager.registerOnPageChangeCallback(callback);
+ }
+
+ @Override
+ public void removeOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) {
+ 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 setCancelButtonHidden(boolean isHidden) {
+ binding.setupCancelButton.setVisibility(isHidden ? GONE : VISIBLE);
+ }
+
+ @Override
+ public void onProviderSelected(Provider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public void onConfigurationSuccess() {
+ binding.viewPager.setCurrentItem(binding.viewPager.getCurrentItem() + 1);
+ }
+
+ @Override
+ public Provider getSelectedProvider() {
+ return provider;
+ }
+
+ @Override
+ public int getCurrentPosition() {
+ return currentPosition;
+ }
+
+ @Override
+ public void onSetupFinished() {
+ Intent intent = getIntent();
+ intent.putExtra(Provider.KEY, provider);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public void onError(String reasonToFail) {
+ binding.viewPager.setCurrentItem(0, false);
+ try {
+ FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG);
+ DialogFragment newFragment;
+ try {
+ JSONObject errorJson = new JSONObject(reasonToFail);
+ newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson, false);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ newFragment = ProviderSetupFailedDialog.newInstance(provider, reasonToFail);
+ } catch (NullPointerException e) {
+ //reasonToFail was null
+ return;
+ }
+ newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG);
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void retrySetUpProvider(@NonNull Provider provider) {
+ onProviderSelected(provider);
+ binding.viewPager.setCurrentItem(adapter.getFragmentPostion(CONFIGURE_PROVIDER_FRAGMENT));
+ }
+
+ @Override
+ public void cancelSettingUpProvider() {
+ cancel();
+ }
+
+ @Override
+ public void updateProviderDetails() {
+ provider.reset();
+ deleteProviderDetailsFromPreferences(provider.getDomain());
+ binding.viewPager.setCurrentItem(adapter.getFragmentPostion(CONFIGURE_PROVIDER_FRAGMENT));
+ }
+
+ @Override
+ public void addAndSelectNewProvider(String url) {
+ // ignore, not implemented anymore in new setup flow
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ adapter = null;
+ }
+} \ No newline at end of file
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..2c77dfd0
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivityCallback.java
@@ -0,0 +1,33 @@
+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();
+
+ int getCurrentPosition();
+
+ void onSetupFinished();
+
+ void onError(String reasonToFail);
+}
+