summaryrefslogtreecommitdiff
path: root/app/src/main/java/se
diff options
context:
space:
mode:
authorcyberta <cyberta@riseup.net>2021-11-25 02:14:08 +0000
committercyberta <cyberta@riseup.net>2021-11-25 02:14:08 +0000
commit5a2ff7c85f13fe2e875e4ca7ec4192df0e896d01 (patch)
treee74b21e0b9e24b5b8774598142b343aa56a7070c /app/src/main/java/se
parent68ca9c827da3c3fad9e70c74960f113560fd6711 (diff)
parent6fb2050aaf6e992bf96d41c5f6b19f5c1a3771c3 (diff)
Merge branch 'preferences_ui' into 'master'
Preferences ui See merge request leap/bitmask_android!145
Diffstat (limited to 'app/src/main/java/se')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java27
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java32
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java234
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java211
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java6
6 files changed, 275 insertions, 238 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java
index 54977f0a..77743eac 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java
@@ -41,6 +41,7 @@ import se.leap.bitmaskclient.base.fragments.ExcludeAppsFragment;
import se.leap.bitmaskclient.base.fragments.LogFragment;
import se.leap.bitmaskclient.base.fragments.MainActivityErrorDialog;
import se.leap.bitmaskclient.base.fragments.NavigationDrawerFragment;
+import se.leap.bitmaskclient.base.fragments.SettingsFragment;
import se.leap.bitmaskclient.base.models.Provider;
import se.leap.bitmaskclient.base.models.ProviderObservable;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
@@ -76,7 +77,7 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATE
import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE;
-public class MainActivity extends AppCompatActivity implements EipSetupListener, Observer, ExcludeAppsFragment.ExcludedAppsCallback {
+public class MainActivity extends AppCompatActivity implements EipSetupListener, Observer {
public final static String TAG = MainActivity.class.getSimpleName();
@@ -114,12 +115,18 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener,
public void onBackPressed() {
FragmentManagerEnhanced fragmentManagerEnhanced = new FragmentManagerEnhanced(getSupportFragmentManager());
Fragment fragment = fragmentManagerEnhanced.findFragmentByTag(MainActivity.TAG);
- if (fragment == null || !(fragment instanceof EipFragment)) {
- Fragment eipFragment = new EipFragment();
- Bundle bundle = new Bundle();
- bundle.putParcelable(PROVIDER_KEY, provider);
- eipFragment.setArguments(bundle);
- fragmentManagerEnhanced.replace(R.id.main_container, eipFragment, MainActivity.TAG);
+ //FIXME: use proper navigation, this is only a workaround
+ if (!(fragment instanceof EipFragment)) {
+ Fragment newFragment;
+ if (fragment instanceof ExcludeAppsFragment) {
+ newFragment = new SettingsFragment();
+ } else {
+ newFragment = new EipFragment();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(PROVIDER_KEY, provider);
+ newFragment.setArguments(bundle);
+ }
+ fragmentManagerEnhanced.replace(R.id.main_container, newFragment, MainActivity.TAG);
hideActionBarSubTitle();
} else {
super.onBackPressed();
@@ -382,10 +389,4 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener,
}
startActivityForResult(intent, REQUEST_CODE_LOG_IN);
}
-
-
- @Override
- public void onAppsExcluded(int number) {
- navigationDrawerFragment.onAppsExcluded(number);
- }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java
index 04745d42..f5d7f286 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java
@@ -20,13 +20,15 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
-import android.widget.CompoundButton;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SearchView;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.fragment.app.Fragment;
@@ -41,6 +43,8 @@ import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
import se.leap.bitmaskclient.base.views.SimpleCheckBox;
+import static se.leap.bitmaskclient.R.string.exclude_apps_fragment_title;
+
/**
* Created by arne on 16.11.14.
*/
@@ -51,20 +55,6 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC
private Set<String> apps;
- public interface ExcludedAppsCallback {
- void onAppsExcluded(int number);
- }
-
- private ExcludedAppsCallback callback;
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (context instanceof ExcludedAppsCallback) {
- callback = (ExcludedAppsCallback) context;
- }
- }
-
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AppViewHolder avh = (AppViewHolder) view.getTag();
@@ -120,10 +110,6 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC
Log.d("openvpn", "removing from allowed apps" + packageName);
apps.remove(packageName);
}
-
- if (callback != null) {
- callback.onAppsExcluded(apps.size());
- }
}
class PackageAdapter extends BaseAdapter implements Filterable {
@@ -328,10 +314,18 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC
mListView.setOnItemClickListener(this);
mListView.setEmptyView(v.findViewById(R.id.loading_container));
+ setActionBarTitle(exclude_apps_fragment_title);
new Thread(() -> mListAdapter.populateList(getActivity())).start();
return v;
}
+ private void setActionBarTitle(@StringRes int stringId) {
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setSubtitle(stringId);
+ }
+ }
+
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java
index 020a48a4..e9881094 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java
@@ -22,53 +22,48 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
-import androidx.appcompat.widget.AppCompatTextView;
-import androidx.fragment.app.DialogFragment;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.core.view.GravityCompat;
-import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
+import androidx.core.view.GravityCompat;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.fragment.app.Fragment;
import java.util.Observable;
import java.util.Observer;
-import java.util.Set;
-import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.BuildConfig;
+import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
import se.leap.bitmaskclient.base.MainActivity;
import se.leap.bitmaskclient.base.models.Provider;
-import se.leap.bitmaskclient.providersetup.ProviderListActivity;
import se.leap.bitmaskclient.base.models.ProviderObservable;
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.eip.EipCommand;
+import se.leap.bitmaskclient.base.views.IconSwitchEntry;
+import se.leap.bitmaskclient.base.views.IconTextEntry;
import se.leap.bitmaskclient.eip.EipStatus;
import se.leap.bitmaskclient.firewall.FirewallManager;
+import se.leap.bitmaskclient.providersetup.ProviderListActivity;
import se.leap.bitmaskclient.tethering.TetheringObservable;
-import se.leap.bitmaskclient.base.utils.PreferenceHelper;
-import se.leap.bitmaskclient.base.views.IconSwitchEntry;
-import se.leap.bitmaskclient.base.views.IconTextEntry;
import static android.content.Context.MODE_PRIVATE;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
+import static se.leap.bitmaskclient.R.string.about_fragment_title;
+import static se.leap.bitmaskclient.R.string.advanced_settings;
+import static se.leap.bitmaskclient.R.string.log_fragment_title;
import static se.leap.bitmaskclient.base.BitmaskApp.getRefWatcher;
import static se.leap.bitmaskclient.base.models.Constants.DONATION_URL;
import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION;
@@ -76,19 +71,10 @@ import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER;
import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL;
-import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES;
-import static se.leap.bitmaskclient.R.string.about_fragment_title;
-import static se.leap.bitmaskclient.R.string.exclude_apps_fragment_title;
-import static se.leap.bitmaskclient.R.string.log_fragment_title;
import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSaveBattery;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveBattery;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.showExperimentalFeatures;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges;
/**
* Fragment used for managing interactions for and presentation of a navigation drawer.
@@ -116,11 +102,8 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
private Toolbar toolbar;
private IconTextEntry account;
private IconSwitchEntry saveBattery;
- private IconTextEntry tethering;
- private IconSwitchEntry firewall;
- private IconTextEntry manualGatewaySelection;
- private View experimentalFeatureFooter;
+ private IconTextEntry manualGatewaySelection;
private boolean userLearnedDrawer;
private volatile boolean wasPaused;
private volatile boolean shouldCloseOnResume;
@@ -130,7 +113,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
private final static String KEY_SHOW_SAVE_BATTERY_ALERT = "KEY_SHOW_SAVE_BATTERY_ALERT";
private volatile boolean showSaveBattery = false;
AlertDialog alertDialog;
- private FirewallManager firewallManager;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -140,8 +122,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
userLearnedDrawer = preferences.getBoolean(PREF_USER_LEARNED_DRAWER, false);
preferences.registerOnSharedPreferenceChangeListener(this);
- firewallManager = new FirewallManager(getContext().getApplicationContext(), false);
-
}
@Override
@@ -187,8 +167,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
wasPaused = true;
}
-
-
/**
* Users of this fragment must call this method to set up the navigation drawer interactions.
*
@@ -256,15 +234,9 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
private void setupEntries() {
initAccountEntry();
initSwitchProviderEntry();
- initUseBridgesEntry();
initSaveBatteryEntry();
- initAlwaysOnVpnEntry();
- initExcludeAppsEntry();
initManualGatewayEntry();
- initShowExperimentalHint();
- initTetheringEntry();
- initFirewallEntry();
- initExperimentalFeatureFooter();
+ initAdvancedSettingsEntry();
initDonateEntry();
initLogEntry();
initAboutEntry();
@@ -297,26 +269,15 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
}
}
- private void initUseBridgesEntry() {
- IconSwitchEntry useBridges = drawerView.findViewById(R.id.bridges_switch);
- if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) {
- useBridges.setVisibility(VISIBLE);
- useBridges.setChecked(getUseBridges(getContext()));
- useBridges.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (!buttonView.isPressed()) {
- return;
- }
- useBridges(getContext(), isChecked);
- if (VpnStatus.isVPNActive()) {
- EipCommand.startVPN(getContext(), false);
- closeDrawer();
- }
- });
-
-
- } else {
- useBridges.setVisibility(GONE);
- }
+ private void initAdvancedSettingsEntry() {
+ IconTextEntry advancedSettings = drawerView.findViewById(R.id.advancedSettings);
+ FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager());
+ advancedSettings.setOnClickListener(v -> {
+ closeDrawer();
+ Fragment fragment = new SettingsFragment();
+ setActionBarTitle(advanced_settings);
+ fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG);
+ });
}
private void initSaveBatteryEntry() {
@@ -345,81 +306,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
saveBattery.showSubtitle(!enabled);
}
- private void initAlwaysOnVpnEntry() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- IconTextEntry alwaysOnVpn = drawerView.findViewById(R.id.always_on_vpn);
- alwaysOnVpn.setVisibility(VISIBLE);
- alwaysOnVpn.setOnClickListener((buttonView) -> {
- closeDrawer();
- if (getShowAlwaysOnDialog(getContext())) {
- showAlwaysOnDialog();
- } else {
- Intent intent = new Intent("android.net.vpn.SETTINGS");
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- }
- });
- }
- }
-
- private void initExcludeAppsEntry() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- IconTextEntry excludeApps = drawerView.findViewById(R.id.exclude_apps);
- excludeApps.setVisibility(VISIBLE);
- Set<String> apps = PreferenceHelper.getExcludedApps(this.getContext());
- if (apps != null) {
- updateExcludeAppsSubtitle(excludeApps, apps.size());
- }
- FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager());
- excludeApps.setOnClickListener((buttonView) -> {
- closeDrawer();
- Fragment fragment = new ExcludeAppsFragment();
- setActionBarTitle(exclude_apps_fragment_title);
- fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG);
- });
- }
- }
-
- private void initShowExperimentalHint() {
- AppCompatTextView textView = drawerLayout.findViewById(R.id.show_experimental_features);
- textView.setText(showExperimentalFeatures(getContext()) ? R.string.hide_experimental : R.string.show_experimental);
- textView.setOnClickListener(v -> {
- boolean shown = showExperimentalFeatures(getContext());
- if (shown) {
- tethering.setVisibility(GONE);
- firewall.setVisibility(GONE);
- experimentalFeatureFooter.setVisibility(GONE);
- ((AppCompatTextView) v).setText(R.string.show_experimental);
- } else {
- tethering.setVisibility(VISIBLE);
- firewall.setVisibility(VISIBLE);
- experimentalFeatureFooter.setVisibility(VISIBLE);
- ((AppCompatTextView) v).setText(R.string.hide_experimental);
- }
- PreferenceHelper.setShowExperimentalFeatures(getContext(), !shown);
- });
- }
-
- private void initFirewallEntry() {
- firewall = drawerView.findViewById(R.id.enableIPv6Firewall);
- boolean show = showExperimentalFeatures(getContext());
- firewall.setVisibility(show ? VISIBLE : GONE);
- firewall.setChecked(PreferenceHelper.useIpv6Firewall(getContext()));
- firewall.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (!buttonView.isPressed()) {
- return;
- }
- PreferenceHelper.setUseIPv6Firewall(getContext(), isChecked);
- if (VpnStatus.isVPNActive()) {
- if (isChecked) {
- firewallManager.startIPv6Firewall();
- } else {
- firewallManager.stopIPv6Firewall();
- }
- }
- });
- }
-
private void initManualGatewayEntry() {
if (!BuildConfig.allow_manual_gateway_selection) {
return;
@@ -440,21 +326,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
});
}
- private void initTetheringEntry() {
- tethering = drawerView.findViewById(R.id.tethering);
- boolean show = showExperimentalFeatures(getContext());
- tethering.setVisibility(show ? VISIBLE : GONE);
- tethering.setOnClickListener((buttonView) -> {
- showTetheringAlert();
- });
- }
-
- private void initExperimentalFeatureFooter() {
- experimentalFeatureFooter = drawerView.findViewById(R.id.experimental_features_footer);
- boolean show = showExperimentalFeatures(getContext());
- experimentalFeatureFooter.setVisibility(show ? VISIBLE : GONE);
- }
-
private void initDonateEntry() {
if (ENABLE_DONATION) {
IconTextEntry donate = drawerView.findViewById(R.id.donate);
@@ -566,32 +437,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
}
}
- public void showTetheringAlert() {
- try {
-
- FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced(
- getActivity().getSupportFragmentManager()).removePreviousFragment(
- TetheringDialog.TAG);
- DialogFragment newFragment = new TetheringDialog();
- newFragment.show(fragmentTransaction, TetheringDialog.TAG);
- } catch (IllegalStateException | NullPointerException e) {
- e.printStackTrace();
- }
- }
-
- public void showAlwaysOnDialog() {
- try {
-
- FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced(
- getActivity().getSupportFragmentManager()).removePreviousFragment(
- AlwaysOnDialog.TAG);
- DialogFragment newFragment = new AlwaysOnDialog();
- newFragment.show(fragmentTransaction, AlwaysOnDialog.TAG);
- } catch (IllegalStateException | NullPointerException e) {
- e.printStackTrace();
- }
-
- }
@Override
public void onConfigurationChanged(Configuration newConfig) {
@@ -654,33 +499,12 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen
public void refresh() {
Provider currentProvider = ProviderObservable.getInstance().getCurrentProvider();
account.setText(currentProvider.getName());
- initUseBridgesEntry();
initManualGatewayEntry();
}
- private void updateExcludeAppsSubtitle(IconTextEntry excludeApps, int number) {
- if (number > 0) {
- excludeApps.setSubtitle(getContext().getResources().getQuantityString(R.plurals.subtitle_exclude_apps, number, number));
- excludeApps.setSubtitleColor(R.color.colorError);
- } else {
- excludeApps.hideSubtitle();
- }
- }
-
- public void onAppsExcluded(int number) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- IconTextEntry excludeApps = drawerView.findViewById(R.id.exclude_apps);
- updateExcludeAppsSubtitle(excludeApps, number);
- }
- }
-
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(USE_BRIDGES)) {
- initUseBridgesEntry();
- } else if (key.equals(USE_IPv6_FIREWALL)) {
- initFirewallEntry();
- } else if (key.equals(PREFERRED_CITY)) {
+ if (key.equals(PREFERRED_CITY)) {
initManualGatewayEntry();
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java
new file mode 100644
index 00000000..db19b86a
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java
@@ -0,0 +1,211 @@
+package se.leap.bitmaskclient.base.fragments;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentTransaction;
+
+import java.util.Set;
+
+import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
+import se.leap.bitmaskclient.base.MainActivity;
+import se.leap.bitmaskclient.base.models.ProviderObservable;
+import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+import se.leap.bitmaskclient.base.views.IconSwitchEntry;
+import se.leap.bitmaskclient.base.views.IconTextEntry;
+import se.leap.bitmaskclient.eip.EipCommand;
+import se.leap.bitmaskclient.firewall.FirewallManager;
+
+import static android.content.Context.MODE_PRIVATE;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES;
+import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges;
+
+public class SettingsFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
+
+ private FirewallManager firewallManager;
+ private SharedPreferences preferences;
+
+ private IconTextEntry tethering;
+ private IconSwitchEntry firewall;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ preferences.registerOnSharedPreferenceChangeListener(this);
+ firewallManager = new FirewallManager(getContext().getApplicationContext(), false);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.f_settings, container, false);
+ initAlwaysOnVpnEntry(view);
+ initExcludeAppsEntry(view);
+ initFirewallEntry(view);
+ initTetheringEntry(view);
+ initUseBridgesEntry(view);
+ return view;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ preferences.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ private void initUseBridgesEntry(View rootView) {
+ IconSwitchEntry useBridges = rootView.findViewById(R.id.bridges_switch);
+ if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) {
+ useBridges.setVisibility(VISIBLE);
+ useBridges.setChecked(getUseBridges(getContext()));
+ useBridges.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ if (!buttonView.isPressed()) {
+ return;
+ }
+ useBridges(getContext(), isChecked);
+ if (VpnStatus.isVPNActive()) {
+ EipCommand.startVPN(getContext(), false);
+ showVPNFragment();
+ }
+ });
+
+
+ } else {
+ useBridges.setVisibility(GONE);
+ }
+ }
+
+
+ private void initAlwaysOnVpnEntry(View rootView) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ IconTextEntry alwaysOnVpn = rootView.findViewById(R.id.always_on_vpn);
+ alwaysOnVpn.setVisibility(VISIBLE);
+ alwaysOnVpn.setOnClickListener((buttonView) -> {
+ if (getShowAlwaysOnDialog(getContext())) {
+ showAlwaysOnDialog();
+ } else {
+ Intent intent = new Intent("android.net.vpn.SETTINGS");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+ });
+ }
+ }
+
+ private void initExcludeAppsEntry(View rootView) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ IconTextEntry excludeApps = rootView.findViewById(R.id.exclude_apps);
+ excludeApps.setVisibility(VISIBLE);
+ Set<String> apps = PreferenceHelper.getExcludedApps(this.getContext());
+ if (apps != null) {
+ updateExcludeAppsSubtitle(excludeApps, apps.size());
+ }
+ FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager());
+ excludeApps.setOnClickListener((buttonView) -> {
+ Fragment fragment = new ExcludeAppsFragment();
+ fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG);
+ });
+ }
+ }
+
+ private void updateExcludeAppsSubtitle(IconTextEntry excludeApps, int number) {
+ if (number > 0) {
+ excludeApps.setSubtitle(getContext().getResources().getQuantityString(R.plurals.subtitle_exclude_apps, number, number));
+ excludeApps.setSubtitleColor(R.color.colorError);
+ } else {
+ excludeApps.hideSubtitle();
+ }
+ }
+
+ private void initFirewallEntry(View rootView) {
+ firewall = rootView.findViewById(R.id.enableIPv6Firewall);
+ firewall.setChecked(PreferenceHelper.useIpv6Firewall(getContext()));
+ firewall.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ if (!buttonView.isPressed()) {
+ return;
+ }
+ PreferenceHelper.setUseIPv6Firewall(getContext(), isChecked);
+ if (VpnStatus.isVPNActive()) {
+ if (isChecked) {
+ firewallManager.startIPv6Firewall();
+ } else {
+ firewallManager.stopIPv6Firewall();
+ }
+ }
+ });
+ }
+
+ private void showVPNFragment() {
+ Intent intent = new Intent(getContext(), MainActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.setAction(ACTION_SHOW_VPN_FRAGMENT);
+ startActivity(intent);
+ }
+
+
+ private void initTetheringEntry(View rootView) {
+ tethering = rootView.findViewById(R.id.tethering);
+ tethering.setOnClickListener((buttonView) -> {
+ showTetheringAlert();
+ });
+ }
+
+ public void showTetheringAlert() {
+ try {
+
+ FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced(
+ getActivity().getSupportFragmentManager()).removePreviousFragment(
+ TetheringDialog.TAG);
+ DialogFragment newFragment = new TetheringDialog();
+ newFragment.show(fragmentTransaction, TetheringDialog.TAG);
+ } catch (IllegalStateException | NullPointerException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void showAlwaysOnDialog() {
+ try {
+
+ FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced(
+ getActivity().getSupportFragmentManager()).removePreviousFragment(
+ AlwaysOnDialog.TAG);
+ DialogFragment newFragment = new AlwaysOnDialog();
+ newFragment.show(fragmentTransaction, AlwaysOnDialog.TAG);
+ } catch (IllegalStateException | NullPointerException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ View rootView = getView();
+ if (rootView == null) {
+ return;
+ }
+ if (key.equals(USE_BRIDGES)) {
+ initUseBridgesEntry(rootView);
+ } else if (key.equals(USE_IPv6_FIREWALL)) {
+ initFirewallEntry(getView());
+ }
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java
index a499cdd1..79563bcf 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconSwitchEntry.java
@@ -92,6 +92,9 @@ public class IconSwitchEntry extends LinearLayout {
iconView.setImageDrawable(drawable);
}
+ boolean singleLine = typedArray.getBoolean(R.styleable.IconTextEntry_singleLine, true);
+ subtitleView.setSingleLine(singleLine);
+
typedArray.recycle();
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java
index 2d9525ed..7aefd089 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconTextEntry.java
@@ -14,6 +14,7 @@ import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
+import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.AppCompatTextView;
import se.leap.bitmaskclient.R;
@@ -22,7 +23,7 @@ import se.leap.bitmaskclient.R;
public class IconTextEntry extends LinearLayout {
private AppCompatTextView textView;
- private ImageView iconView;
+ private AppCompatImageView iconView;
private AppCompatTextView subtitleView;
public IconTextEntry(Context context) {
@@ -73,6 +74,9 @@ public class IconTextEntry extends LinearLayout {
iconView.setImageDrawable(drawable);
}
+ boolean singleLine = typedArray.getBoolean(R.styleable.IconTextEntry_singleLine, true);
+ subtitleView.setSingleLine(singleLine);
+
typedArray.recycle();
}