From 39f5c390072cc51a60ab17264963c33f55528e46 Mon Sep 17 00:00:00 2001 From: Norbel AMBANUMBEN Date: Sat, 12 Oct 2024 21:21:23 +0100 Subject: chore: bootstrap censorship circumvention fragment. --- .../fragments/CensorshipCircumventionFragment.java | 128 +++++++++++++++++++++ .../base/fragments/SettingsFragment.java | 36 +++--- app/src/main/res/drawable/bridge_automatic.xml | 10 ++ app/src/main/res/drawable/bridge_manual.xml | 10 ++ .../main/res/layout/f_censorship_circumvention.xml | 65 +++++++++++ app/src/main/res/layout/f_settings.xml | 64 ++++++----- app/src/main/res/values/strings.xml | 12 ++ app/src/main/res/values/untranslatable.xml | 2 + 8 files changed, 279 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java create mode 100644 app/src/main/res/drawable/bridge_automatic.xml create mode 100644 app/src/main/res/drawable/bridge_manual.xml create mode 100644 app/src/main/res/layout/f_censorship_circumvention.xml (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java new file mode 100644 index 00000000..cecf98da --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java @@ -0,0 +1,128 @@ +package se.leap.bitmaskclient.base.fragments; + +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RadioButton; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.databinding.FCensorshipCircumventionBinding; + +public class CensorshipCircumventionFragment extends Fragment { + public static int DISCOVERY_NONE = 100200000; + public static int DISCOVERY_SNOWFLAKE = 100200001; + public static int DISCOVERY_INVITE_PROXY = 100200002; + + public static int TUNNELING_NONE = 100300000; + public static int TUNNELING_OBFS4 = 100300001; + public static int TUNNELING_OBFS4_KCP = 100300002; + + private @NonNull FCensorshipCircumventionBinding binding; + + public static CensorshipCircumventionFragment newInstance() { + CensorshipCircumventionFragment fragment = new CensorshipCircumventionFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = FCensorshipCircumventionBinding.inflate(getLayoutInflater(), container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setActionBarSubtitle(this, R.string.censorship_circumvention); + initDiscovery(); + initTunneling(); + initPortHopping(); + } + + + private void initDiscovery() { + + RadioButton noneRadioButton = new RadioButton(binding.getRoot().getContext()); + noneRadioButton.setText(getText(R.string.none)); + noneRadioButton.setId(DISCOVERY_NONE); + binding.discoveryRadioGroup.addView(noneRadioButton); + + if (hasSnowflakePrefs()) { + + RadioButton snowflakeRadioButton = new RadioButton(binding.getRoot().getContext()); + snowflakeRadioButton.setText(getText(R.string.snowflake)); + snowflakeRadioButton.setId(DISCOVERY_SNOWFLAKE); + snowflakeRadioButton.setChecked(hasSnowflakePrefs() && getUseSnowflake()); + binding.discoveryRadioGroup.addView(snowflakeRadioButton); + + } + + RadioButton inviteProxyRadioButton = new RadioButton(binding.getRoot().getContext()); + inviteProxyRadioButton.setText(getText(R.string.invite_proxy)); + inviteProxyRadioButton.setId(DISCOVERY_INVITE_PROXY); + binding.discoveryRadioGroup.addView(inviteProxyRadioButton); + + binding.discoveryRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == DISCOVERY_NONE) { + useSnowflake(false); + } else if (checkedId == DISCOVERY_SNOWFLAKE) { + useSnowflake(true); + } else if (checkedId == DISCOVERY_INVITE_PROXY) { + useSnowflake(false); + } + }); + } + + + private void initTunneling() { + RadioButton noneRadioButton = new RadioButton(binding.getRoot().getContext()); + noneRadioButton.setText(getText(R.string.none)); + noneRadioButton.setId(TUNNELING_NONE); + binding.tunnelingRadioGroup.addView(noneRadioButton); + + RadioButton obfs4RadioButton = new RadioButton(binding.getRoot().getContext()); + obfs4RadioButton.setText(getText(R.string.tunnelling_obfs4)); + obfs4RadioButton.setId(TUNNELING_OBFS4); + binding.tunnelingRadioGroup.addView(obfs4RadioButton); + + RadioButton obfs4KcpRadioButton = new RadioButton(binding.getRoot().getContext()); + obfs4KcpRadioButton.setText(getText(R.string.tunnelling_obfs4_kcp)); + obfs4KcpRadioButton.setId(TUNNELING_OBFS4_KCP); + binding.tunnelingRadioGroup.addView(obfs4KcpRadioButton); + + binding.tunnelingRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == TUNNELING_NONE) { + // TODO set up none + } else if (checkedId == TUNNELING_OBFS4) { + // TODO set up obfs4 + } else if (checkedId == TUNNELING_OBFS4_KCP) { + // TODO set up obfs4 + kcp + } + + }); + } + + private void initPortHopping() { + binding.portHoppingSwitch.findViewById(R.id.material_icon).setVisibility(View.GONE); + binding.portHoppingSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + // TODO set up port hopping + }); + } +} \ No newline at end of file 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 index 51bce6d4..4aed0643 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java @@ -14,14 +14,11 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP; 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.getUseSnowflake; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.preferUDP; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setAllowExperimentalTransports; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseObfuscationPinning; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; import android.app.AlertDialog; @@ -79,7 +76,8 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh initExcludeAppsEntry(view); initPreferUDPEntry(view); initUseBridgesEntry(view); - initUseSnowflakeEntry(view); + initAutomaticCircumventionEntry(view); + initManualCircumventionEntry(view); initFirewallEntry(view); initTetheringEntry(view); initGatewayPinningEntry(view); @@ -89,6 +87,22 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh return view; } + private void initAutomaticCircumventionEntry(View rootView) { + IconSwitchEntry automaticCircumvention = rootView.findViewById(R.id.bridge_automatic_switch); + automaticCircumvention.setOnCheckedChangeListener((buttonView, isChecked) -> { + + }); + } + + private void initManualCircumventionEntry(View rootView) { + FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); + IconSwitchEntry manualConfiguration = rootView.findViewById(R.id.bridge_manual_switch); + manualConfiguration.setOnClickListener((buttonView) -> { + Fragment fragment = CensorshipCircumventionFragment.newInstance(); + fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); + }); + } + @Override public void onDestroy() { PreferenceHelper.unregisterOnSharedPreferenceChangeListener(this); @@ -121,18 +135,6 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh } } - private void initUseSnowflakeEntry(View rootView) { - IconSwitchEntry useSnowflake = rootView.findViewById(R.id.snowflake_switch); - useSnowflake.setVisibility(VISIBLE); - useSnowflake.setChecked(hasSnowflakePrefs() && getUseSnowflake()); - useSnowflake.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (!buttonView.isPressed()) { - return; - } - useSnowflake(isChecked); - }); - } - private void initAlwaysOnVpnEntry(View rootView) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { IconTextEntry alwaysOnVpn = rootView.findViewById(R.id.always_on_vpn); @@ -350,7 +352,7 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh return; } if (key.equals(USE_BRIDGES) || key.equals(PREFER_UDP)) { - initUseBridgesEntry(rootView); + //initUseBridgesEntry(rootView); initPreferUDPEntry(rootView); } else if (key.equals(USE_IPv6_FIREWALL)) { initFirewallEntry(getView()); diff --git a/app/src/main/res/drawable/bridge_automatic.xml b/app/src/main/res/drawable/bridge_automatic.xml new file mode 100644 index 00000000..28c288f0 --- /dev/null +++ b/app/src/main/res/drawable/bridge_automatic.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/bridge_manual.xml b/app/src/main/res/drawable/bridge_manual.xml new file mode 100644 index 00000000..cec55dab --- /dev/null +++ b/app/src/main/res/drawable/bridge_manual.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/f_censorship_circumvention.xml b/app/src/main/res/layout/f_censorship_circumvention.xml new file mode 100644 index 00000000..907b3b02 --- /dev/null +++ b/app/src/main/res/layout/f_censorship_circumvention.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/f_settings.xml b/app/src/main/res/layout/f_settings.xml index 3ce19797..70b43dbb 100644 --- a/app/src/main/res/layout/f_settings.xml +++ b/app/src/main/res/layout/f_settings.xml @@ -5,8 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" - android:padding="@dimen/stdpadding" - tools:viewBindingIgnore="true"> + android:padding="@dimen/stdpadding"> + + + android:visibility="visible" /> - - + android:visibility="visible" /> + android:paddingTop="@dimen/activity_margin" /> + + app:text="@string/automatic_bridge" + app:subtitle="@string/automatic_bridge_description" + app:icon="@drawable/bridge_automatic" + app:singleLine="false" /> + app:text="@string/manual_bridge" + app:subtitle="@string/manual_bridge_description" + app:icon="@drawable/bridge_manual" + app:singleLine="false" /> + + Enter invite Code Scan QR Code Invalid code + Automatic (recommended) + Connection wil be attemptd using the best available birdges and protocols. + Manual Configuration + Select private bridges and specific protocols + Manual configuration requires technical understanding. Proceed with caution. + Discovery + Censors can block the discovery of critical configuration information from your provider. Choose a circumvention option to bypass blocks. + None + Invite Proxy + Tunneling + Censors can block access to the open internet. Choose a circumvention option to bypass blocks. + Port Hopping diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml index f326e756..aab5adbd 100644 --- a/app/src/main/res/values/untranslatable.xml +++ b/app/src/main/res/values/untranslatable.xml @@ -92,4 +92,6 @@ zh zh-TW + Obfs4 + Obfs4+KCP -- cgit v1.2.3