From 1e9202c3d929083220924f7c76ea01a2b6f6af9f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 22 Jul 2021 15:31:08 +0200 Subject: first implementation of the gateway button, started to remove labels from EipFragment, implement method to get the avearage load of a location as an enum value --- .../bitmaskclient/base/fragments/EipFragment.java | 66 +++++++++---------- .../bitmaskclient/base/views/LocationButton.java | 44 +++++++++++++ .../base/views/LocationIndicator.java | 76 ++++++++++++++++++++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 50 ++++++++++++++ 4 files changed, 203 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 615221ae..cc822463 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -38,9 +38,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -60,9 +58,11 @@ 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.views.LocationButton; import se.leap.bitmaskclient.base.views.VpnStateImage; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; +import se.leap.bitmaskclient.eip.GatewaysManager; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; import se.leap.bitmaskclient.providersetup.ProviderListActivity; import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity; @@ -86,6 +86,7 @@ import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx; import static se.leap.bitmaskclient.eip.EipSetupObserver.gatewayOrder; import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway; +import static se.leap.bitmaskclient.eip.GatewaysManager.Load.UNKNOWN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; @@ -104,18 +105,14 @@ public class EipFragment extends Fragment implements Observer { @BindView(R.id.vpn_state_image) VpnStateImage vpnStateImage; - @BindView(R.id.vpn_main_button) - AppCompatButton mainButton; - - @BindView(R.id.routed_text) - AppCompatTextView routedText; - - @BindView(R.id.vpn_route) - AppCompatTextView vpnRoute; + @BindView(R.id.gateway_location_button) + LocationButton locationButton; private Unbinder unbinder; private EipStatus eipStatus; + private GatewaysManager gatewaysManager; + //---saved Instance ------- private final String KEY_SHOW_PENDING_START_CANCELLATION = "KEY_SHOW_PENDING_START_CANCELLATION"; private final String KEY_SHOW_ASK_TO_STOP_EIP = "KEY_SHOW_ASK_TO_STOP_EIP"; @@ -168,6 +165,9 @@ public class EipFragment extends Fragment implements Observer { } else { Log.e(TAG, "activity is null in onCreate - no preferences set!"); } + + gatewaysManager = new GatewaysManager(getContext()); + } @Override @@ -252,7 +252,7 @@ public class EipFragment extends Fragment implements Observer { preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, restartOnBoot).apply(); } - @OnClick(R.id.vpn_main_button) + @OnClick(R.id.gateway_location_button) void onButtonClick() { handleIcon(); } @@ -307,7 +307,7 @@ public class EipFragment extends Fragment implements Observer { } private void setMainButtonEnabled(boolean enabled) { - mainButton.setEnabled(enabled); + locationButton.setEnabled(enabled); vpnStateImage.setEnabled(enabled); } @@ -408,32 +408,35 @@ public class EipFragment extends Fragment implements Observer { setMainButtonEnabled(true); showConnectingLayout(activity); if (eipStatus.isReconnecting()) { - //Log.d(TAG, "eip show reconnecting toast!"); - //showReconnectToast(activity); + locationButton.setText(getString(R.string.reconnecting)); + } else { + locationButton.setText(getString(R.string.finding_best_connection)); } + locationButton.setVisibility(VISIBLE); + locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isConnected() ) { - mainButton.setText(activity.getString(R.string.vpn_button_turn_off)); + locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_connected); vpnStateImage.stopProgress(false); - routedText.setText(R.string.vpn_securely_routed); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(VISIBLE); - setVpnRouteText(); + locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); + locationButton.setText(VpnStatus.getLastConnectedVpnName()); + locationButton.setVisibility(VISIBLE); colorBackground(); } else if(isOpenVpnRunningWithoutNetwork()){ - mainButton.setText(activity.getString(R.string.vpn_button_turn_off)); + locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); vpnStateImage.stopProgress(false); - routedText.setText(R.string.vpn_securely_routed_no_internet); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(VISIBLE); + locationButton.setVisibility(VISIBLE); setVpnRouteText(); colorBackgroundALittle(); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { showConnectingLayout(activity); // showRetryToast(activity); + locationButton.setText(getString(R.string.finding_best_connection)); + locationButton.setVisibility(VISIBLE); + locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); showDisconnectingLayout(activity); @@ -441,18 +444,18 @@ public class EipFragment extends Fragment implements Observer { setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_blocking); vpnStateImage.stopProgress(false); - routedText.setText(getString(R.string.void_vpn_establish, getString(R.string.app_name))); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(GONE); colorBackgroundALittle(); + locationButton.setText(getString(R.string.finding_best_connection)); + locationButton.setVisibility(VISIBLE); + locationButton.setLocationLoad(UNKNOWN); } else { - mainButton.setText(activity.getString(R.string.vpn_button_turn_on)); + locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); vpnStateImage.stopProgress(false); - routedText.setVisibility(GONE); - vpnRoute.setVisibility(GONE); greyscaleBackground(); + locationButton.setLocationLoad(UNKNOWN); + locationButton.setVisibility(GONE); } } @@ -494,11 +497,8 @@ public class EipFragment extends Fragment implements Observer { } private void showConnectionTransitionLayout(Context activity, boolean isConnecting) { - mainButton.setText(activity.getString(android.R.string.cancel)); vpnStateImage.setStateIcon(R.drawable.vpn_connecting); vpnStateImage.showProgress(); - routedText.setVisibility(GONE); - vpnRoute.setVisibility(GONE); if (isConnecting) { colorBackgroundALittle(); } else { @@ -574,7 +574,7 @@ public class EipFragment extends Fragment implements Observer { if (!TextUtils.isEmpty(profileName)) { vpnRouteString += " (" + profileName + ")"; } - vpnRoute.setText(vpnRouteString); + // vpnRoute.setText(vpnRouteString); } private class EipFragmentServiceConnection implements ServiceConnection { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java new file mode 100644 index 00000000..1d7f0d18 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java @@ -0,0 +1,44 @@ +package se.leap.bitmaskclient.base.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.LinearLayoutCompat; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.eip.GatewaysManager; + +public class LocationButton extends LinearLayoutCompat { + private LocationIndicator locationIndicator; + private AppCompatTextView textView; + public LocationButton(@NonNull Context context) { + super(context); + initLayout(context); + } + + public LocationButton(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + private void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_location_button, this, true); + locationIndicator = rootview.findViewById(R.id.load_indicator); + textView = rootview.findViewById(R.id.text_location); + } + + public void setLocationLoad(GatewaysManager.Load load) { + locationIndicator.setLoad(load); + } + + public void setText(CharSequence text) { + textView.setText(text); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java new file mode 100644 index 00000000..f5e3dbe2 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java @@ -0,0 +1,76 @@ +package se.leap.bitmaskclient.base.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.Nullable; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.eip.GatewaysManager; + +public class LocationIndicator extends LinearLayout { + + private View level1; + private View level2; + private View level3; + + public LocationIndicator(Context context) { + super(context); + initLayout(context); + } + + public LocationIndicator(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initLayout(context); + + } + + public LocationIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + + void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_location_status_indicator, this, true); + level1 = rootview.findViewById(R.id.level1); + level2 = rootview.findViewById(R.id.level2); + level3 = rootview.findViewById(R.id.level3); + } + + public void setLoad(GatewaysManager.Load load) { + switch (load) { + case GOOD: + level1.setBackgroundColor(getResources().getColor(R.color.green200)); + level2.setBackgroundColor(getResources().getColor(R.color.green200)); + level3.setBackgroundColor(getResources().getColor(R.color.green200)); + level1.setVisibility(VISIBLE); + level2.setVisibility(VISIBLE); + level3.setVisibility(VISIBLE); + break; + case AVERAGE: + level1.setBackgroundColor(getResources().getColor(R.color.yellow200)); + level2.setBackgroundColor(getResources().getColor(R.color.yellow200)); + level1.setVisibility(VISIBLE); + level2.setVisibility(VISIBLE); + level3.setVisibility(INVISIBLE); + break; + case CRITICAL: + level1.setBackgroundColor(getResources().getColor(R.color.red200)); + level1.setVisibility(VISIBLE); + level2.setVisibility(INVISIBLE); + level3.setVisibility(INVISIBLE); + break; + default: + level1.setVisibility(INVISIBLE); + level2.setVisibility(INVISIBLE); + level3.setVisibility(INVISIBLE); + break; + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 05775d13..b311315c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Random; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; @@ -59,6 +60,37 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; */ public class GatewaysManager { + public enum Load { + UNKNOWN(0), + GOOD(0.25), + AVERAGE(0.75), + CRITICAL(1.0); + + private final double value; + + Load(double i) { + value = i; + } + + public static Load getLoadByValue(double value) { + if (value == UNKNOWN.value) { + return UNKNOWN; + } else if (value <= GOOD.value) { + return GOOD; + } else if (value <= AVERAGE.value) { + return AVERAGE; + } else if (value <= CRITICAL.value) { + return CRITICAL; + } else { + return UNKNOWN; + } + } + + public double getValue() { + return value; + } + } + private static final String TAG = GatewaysManager.class.getSimpleName(); private Context context; @@ -117,6 +149,22 @@ public class GatewaysManager { return locations; } + public Load getLoadForLocation(@Nullable String name) { + List locations = getGatewayLocations(); + for (Location location : locations) { + if (location.name.equals(name)) { + + // fake values for now + Random rand = new Random(); + double averageLoad = rand.nextDouble(); //location.averageLoad; + return Load.getLoadByValue(averageLoad); + } + } + + // location not found + return Load.UNKNOWN; + } + private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType, @Nullable String city) { List list = new ArrayList<>(gateways.values()); GatewaySelector gatewaySelector = new GatewaySelector(list); @@ -326,4 +374,6 @@ public class GatewaysManager { } } + + } -- cgit v1.2.3 From ff427f2863dd2c3c46030968f4d034553f09d0bf Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 23 Jul 2021 23:50:02 +0200 Subject: add click listener to gateway selection button, open the gateway selection fragment --- .../java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index cc822463..af34b7a5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -56,6 +56,7 @@ import de.blinkt.openvpn.core.OpenVPNService; 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.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.views.LocationButton; @@ -168,6 +169,7 @@ public class EipFragment extends Fragment implements Observer { gatewaysManager = new GatewaysManager(getContext()); + } @Override @@ -189,6 +191,11 @@ public class EipFragment extends Fragment implements Observer { } restoreFromSavedInstance(savedInstanceState); + locationButton.setOnClickListener(v -> { + FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); + Fragment fragment = new GatewaySelectionFragment(); + fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); + }); return view; } -- cgit v1.2.3 From 05934715fec39cb22937e82acecd4add4fccd724 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 29 Jul 2021 18:23:55 +0200 Subject: implement location load indicator in gateway selection cell --- .../base/fragments/GatewaySelectionFragment.java | 7 ++++--- .../java/se/leap/bitmaskclient/eip/GatewaysManager.java | 14 ++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index d1222cd7..e4d8ca8b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -46,6 +46,7 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.IconSwitchEntry; +import se.leap.bitmaskclient.base.views.LocationIndicator; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; @@ -189,7 +190,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen static class ViewHolder extends RecyclerView.ViewHolder { public AppCompatTextView locationLabel; - public AppCompatTextView qualityLabel; + public LocationIndicator locationIndicator; public AppCompatImageView checkedIcon; public View layout; @@ -197,7 +198,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen super(v); layout = v; locationLabel = (AppCompatTextView) v.findViewById(R.id.location); - qualityLabel = (AppCompatTextView) v.findViewById(R.id.quality); + locationIndicator = (LocationIndicator) v.findViewById(R.id.quality); checkedIcon = (AppCompatImageView) v.findViewById(R.id.checked_icon); } } @@ -263,7 +264,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen DrawableCompat.setTint(checkIcon, ContextCompat.getColor(holder.layout.getContext(), R.color.colorSuccess)); holder.checkedIcon.setImageDrawable(checkIcon); holder.checkedIcon.setVisibility(location.selected ? VISIBLE : INVISIBLE); - holder.qualityLabel.setText(getQualityString(location.averageLoad)); + holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); if (location.selected) { selectedLocation = location; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index b311315c..24e9c323 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -130,9 +130,15 @@ public class GatewaysManager { while ((gateway = select(n, null)) != null) { if (!locationNames.containsKey(gateway.getName())) { locationNames.put(gateway.getName(), locations.size()); + // fake values for now + Random rand = new Random(); + double averageLoad = rand.nextDouble(); //location.averageLoad; + + Location location = new Location( gateway.getName(), - gateway.getFullness(), + averageLoad + /*gateway.getFullness()*/, 1, gateway.getName().equals(selectedCity)); locations.add(location); @@ -153,11 +159,7 @@ public class GatewaysManager { List locations = getGatewayLocations(); for (Location location : locations) { if (location.name.equals(name)) { - - // fake values for now - Random rand = new Random(); - double averageLoad = rand.nextDouble(); //location.averageLoad; - return Load.getLoadByValue(averageLoad); + return Load.getLoadByValue(location.averageLoad); } } -- cgit v1.2.3 From 645545a86bdd1bc832ad2d14f17f5727e352356c Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 30 Jul 2021 15:46:40 +0200 Subject: draft gateway selection UI according to simlpy secure's proposals --- .../base/fragments/GatewaySelectionFragment.java | 158 ++++++++------------- .../base/fragments/MainActivityErrorDialog.java | 6 +- .../base/fragments/NavigationDrawerFragment.java | 2 +- .../leap/bitmaskclient/base/models/Location.java | 6 +- .../bitmaskclient/base/utils/PreferenceHelper.java | 10 +- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 20 ++- 6 files changed, 89 insertions(+), 113 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index e4d8ca8b..ee4aea74 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -19,7 +19,6 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -29,23 +28,21 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatButton; -import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import java.lang.ref.WeakReference; import java.util.List; import java.util.Observable; import java.util.Observer; +import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import se.leap.bitmaskclient.base.views.IconSwitchEntry; import se.leap.bitmaskclient.base.views.LocationIndicator; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; @@ -55,21 +52,23 @@ import static android.content.Context.MODE_PRIVATE; import static android.view.View.INVISIBLE; 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.PREFERRED_CITY; 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.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; -public class GatewaySelectionFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer { +interface LocationListSelectionListener { + void onLocationSelected(String name); +} + +public class GatewaySelectionFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer, LocationListSelectionListener { private static final String TAG = GatewaySelectionFragment.class.getSimpleName(); private RecyclerView recyclerView; private LocationListAdapter locationListAdapter; - private IconSwitchEntry autoSelectionSwitch; - private AppCompatButton vpnButton; + private AppCompatTextView currentLocationDescription; + private AppCompatTextView currentLocation; + private AppCompatButton autoSelectionButton; private GatewaysManager gatewaysManager; private SharedPreferences preferences; private EipStatus eipStatus; @@ -97,8 +96,8 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initRecyclerView(); - initAutoSelectionSwitch(); - initVpnButton(); + initAutoSelectionButton(); + initCurrentLocationInfoPanel(); eipStatus.addObserver(this); preferences.registerOnSharedPreferenceChangeListener(this); } @@ -113,93 +112,94 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen private void initRecyclerView() { - recyclerView = (RecyclerView) getActivity().findViewById(R.id.gatewaySelection_list); + recyclerView = getActivity().findViewById(R.id.gatewaySelection_list); recyclerView.setHasFixedSize(true); LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); recyclerView.setLayoutManager(layoutManager); - locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations()); + locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations(), this); recyclerView.setAdapter(locationListAdapter); - recyclerView.setVisibility(getPreferredCity(getContext()) == null ? INVISIBLE : VISIBLE); + recyclerView.setVisibility(VISIBLE); } - private void initAutoSelectionSwitch() { - autoSelectionSwitch = getActivity().findViewById(R.id.automatic_gateway_switch); - autoSelectionSwitch.setSingleLine(false); - autoSelectionSwitch.setSubtitle(getString(R.string.gateway_selection_warning, getString(R.string.app_name))); - autoSelectionSwitch.setChecked(getPreferredCity(getContext()) == null); - autoSelectionSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { - recyclerView.setVisibility(!isChecked ? VISIBLE : View.GONE); - Log.d(TAG, "autoselection enabled: " + isChecked); - if (isChecked) { - PreferenceHelper.setPreferredCity(getContext(), null); - locationListAdapter.resetSelection(); - } - setVpnButtonState(); + private void initAutoSelectionButton() { + autoSelectionButton = getActivity().findViewById(R.id.automatic_gateway_selection_btn); + autoSelectionButton.setOnClickListener(v -> { + startEipService(null); }); } - private void initVpnButton() { - vpnButton = getActivity().findViewById(R.id.vpn_button); - setVpnButtonState(); - vpnButton.setOnClickListener(v -> { + private void initCurrentLocationInfoPanel() { + currentLocationDescription = getActivity().findViewById(R.id.current_location_description); + currentLocation = getActivity().findViewById(R.id.current_location); + setLocationDescription(EipStatus.getInstance(), PreferenceHelper.getPreferredCity(getContext())); + } + + private void setLocationDescription(EipStatus eipStatus, String preferredCity) { + if (eipStatus.isConnected()) { + currentLocationDescription.setText(preferredCity == null ? + R.string.gateway_selection_automatic_location : + R.string.gateway_selection_manual_location); + currentLocation.setText(VpnStatus.getLastConnectedVpnName()); + currentLocation.setVisibility(VISIBLE); + } else if (preferredCity == null) { + currentLocationDescription.setText(R.string.gateway_selection_automatic_not_connected); + currentLocation.setVisibility(INVISIBLE); + } else { + currentLocationDescription.setText(R.string.gateway_selection_manual_not_connected); + currentLocation.setText(preferredCity); + currentLocation.setVisibility(VISIBLE); + } + } + + protected void startEipService(String preferredCity) { + new Thread(() -> { + PreferenceHelper.setPreferredCity(getContext(), preferredCity); EipCommand.startVPN(getContext(), false); 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 setVpnButtonState() { - if (eipStatus.isDisconnected()) { - vpnButton.setText(R.string.vpn_button_turn_on); - } else { - vpnButton.setText(R.string.reconnect); - } - vpnButton.setEnabled( - (locationListAdapter.selectedLocation != null && locationListAdapter.selectedLocation.selected) || - autoSelectionSwitch.isChecked()); + }).start(); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (USE_BRIDGES.equals(key)) { locationListAdapter.updateData(gatewaysManager.getGatewayLocations()); - setVpnButtonState(); - } else if (PREFERRED_CITY.equals(key)) { - setVpnButtonState(); } } + @Override + public void onLocationSelected(String name) { + startEipService(name); + } + @Override public void update(Observable o, Object arg) { if (o instanceof EipStatus) { - eipStatus = (EipStatus) o; Activity activity = getActivity(); if (activity != null) { - activity.runOnUiThread(this::setVpnButtonState); + activity.runOnUiThread(() -> setLocationDescription((EipStatus) o, PreferenceHelper.getPreferredCity(getContext()))); } } - } + static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); private List values; - private Location selectedLocation = null; + private final WeakReference callback; static class ViewHolder extends RecyclerView.ViewHolder { public AppCompatTextView locationLabel; public LocationIndicator locationIndicator; - public AppCompatImageView checkedIcon; public View layout; public ViewHolder(View v) { super(v); layout = v; - locationLabel = (AppCompatTextView) v.findViewById(R.id.location); - locationIndicator = (LocationIndicator) v.findViewById(R.id.quality); - checkedIcon = (AppCompatImageView) v.findViewById(R.id.checked_icon); + locationLabel = v.findViewById(R.id.location); + locationIndicator = v.findViewById(R.id.quality); } } @@ -213,20 +213,14 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen notifyItemRemoved(position); } - public void resetSelection() { - if (selectedLocation != null) { - selectedLocation.selected = false; - notifyDataSetChanged(); - } - } - public void updateData(List data) { values = data; notifyDataSetChanged(); } - public LocationListAdapter(List data) { + public LocationListAdapter(List data, LocationListSelectionListener selectionListener) { values = data; + callback = new WeakReference<>(selectionListener); } @NonNull @@ -246,42 +240,12 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen holder.locationLabel.setText(location.name); holder.layout.setOnClickListener(v -> { Log.d(TAG, "view at position clicked: " + position); - if (selectedLocation == null) { - selectedLocation = location; - selectedLocation.selected = true; - } else if (selectedLocation.name.equals(location.name)){ - selectedLocation.selected = !selectedLocation.selected; - } else { - selectedLocation.selected = false; - selectedLocation = location; - selectedLocation.selected = true; + LocationListSelectionListener listener = callback.get(); + if (listener != null) { + listener.onLocationSelected(location.name); } - setPreferredCity(holder.layout.getContext(), selectedLocation.selected ? selectedLocation.name : null); - holder.checkedIcon.setVisibility(selectedLocation.selected ? VISIBLE : INVISIBLE); - notifyDataSetChanged(); }); - Drawable checkIcon = DrawableCompat.wrap(holder.layout.getContext().getResources().getDrawable(R.drawable.ic_check_bold)).mutate(); - DrawableCompat.setTint(checkIcon, ContextCompat.getColor(holder.layout.getContext(), R.color.colorSuccess)); - holder.checkedIcon.setImageDrawable(checkIcon); - holder.checkedIcon.setVisibility(location.selected ? VISIBLE : INVISIBLE); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); - if (location.selected) { - selectedLocation = location; - } - } - - public String getQualityString(double quality) { - if (quality == 0) { - return ""; - } else if (quality < 0.25) { - return "BAD"; - } else if (quality < 0.6) { - return "AVERAGE"; - } else if (quality < 0.8){ - return "GOOD"; - } else { - return "EXCELLENT"; - } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java index 86f8471c..da48effc 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java @@ -124,8 +124,10 @@ public class MainActivityErrorDialog extends DialogFragment { builder.setNegativeButton(R.string.cancel, (dialog, id) -> {}); if (getPreferredCity(applicationContext) != null) { builder.setPositiveButton(R.string.warning_option_try_best, (dialog, which) -> { - setPreferredCity(applicationContext, null); - EipCommand.startVPN(applicationContext, false); + new Thread(() -> { + setPreferredCity(applicationContext, null); + EipCommand.startVPN(applicationContext, false); + }).start(); }); } else if (provider.supportsPluggableTransports()) { if (getUseBridges(applicationContext)) { 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 a13692a5..1f4d0b17 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 @@ -425,7 +425,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen } manualGatewaySelection = drawerView.findViewById(R.id.manualGatewaySelection); String preferredGateway = getPreferredCity(getContext()); - String subtitle = preferredGateway != null ? preferredGateway : getString(R.string.gateway_selection_best_location); + String subtitle = preferredGateway != null ? preferredGateway : getString(R.string.gateway_selection_recommended_location); manualGatewaySelection.setSubtitle(subtitle); boolean show = ProviderObservable.getInstance().getCurrentProvider().hasGatewaysInDifferentLocations(); manualGatewaySelection.setVisibility(show ? VISIBLE : GONE); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index ae7818ba..8e032d18 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -6,13 +6,11 @@ public class Location { @NonNull public String name; public double averageLoad; public int numberOfGateways; - public boolean selected; - public Location(@NonNull String name, double averageLoad, int numberOfGateways, boolean selected) { + public Location(@NonNull String name, double averageLoad, int numberOfGateways) { this.name = name; this.averageLoad = averageLoad; this.numberOfGateways = numberOfGateways; - this.selected = selected; } @Override @@ -24,7 +22,6 @@ public class Location { if (Double.compare(location.averageLoad, averageLoad) != 0) return false; if (numberOfGateways != location.numberOfGateways) return false; - if (selected != location.selected) return false; return name.equals(location.name); } @@ -36,7 +33,6 @@ public class Location { temp = Double.doubleToLongBits(averageLoad); result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + numberOfGateways; - result = 31 * result + (selected ? 1 : 0); return result; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index 06fb25e9..93284968 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -3,6 +3,7 @@ package se.leap.bitmaskclient.base.utils; import android.content.Context; import android.content.SharedPreferences; import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; import org.json.JSONException; import org.json.JSONObject; @@ -229,8 +230,9 @@ public class PreferenceHelper { return getString(context, PREFERRED_CITY, null); } + @WorkerThread public static void setPreferredCity(Context context, String city) { - putString(context, PREFERRED_CITY, city); + putStringSync(context, PREFERRED_CITY, city); } public static JSONObject getEipDefinitionFromPreferences(SharedPreferences preferences) { @@ -277,6 +279,12 @@ public class PreferenceHelper { return preferences.getString(key, defValue); } + @WorkerThread + public static void putStringSync(Context context, String key, String value) { + SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().putString(key, value).commit(); + } + public static void putString(Context context, String key, String value) { SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); preferences.edit().putString(key, value).apply(); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 24e9c323..0819e9b6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -93,10 +93,10 @@ public class GatewaysManager { private static final String TAG = GatewaysManager.class.getSimpleName(); - private Context context; - private LinkedHashMap gateways = new LinkedHashMap<>(); - private Type listType = new TypeToken>() {}.getType(); - private ArrayList presortedList = new ArrayList<>(); + private final Context context; + private final LinkedHashMap gateways = new LinkedHashMap<>(); + private final Type listType = new TypeToken>() {}.getType(); + private final ArrayList presortedList = new ArrayList<>(); public GatewaysManager(Context context) { this.context = context; @@ -128,24 +128,30 @@ public class GatewaysManager { int n = 0; Gateway gateway; while ((gateway = select(n, null)) != null) { + String name = gateway.getName(); + if (name == null) { + Log.e(TAG, "Gateway without location name found. This should never happen. Provider misconfigured?"); + continue; + } + if (!locationNames.containsKey(gateway.getName())) { locationNames.put(gateway.getName(), locations.size()); // fake values for now Random rand = new Random(); double averageLoad = rand.nextDouble(); //location.averageLoad; - + Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + "): " + averageLoad); Location location = new Location( gateway.getName(), averageLoad /*gateway.getFullness()*/, - 1, - gateway.getName().equals(selectedCity)); + 1); locations.add(location); } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); location.averageLoad = (location.numberOfGateways * location.averageLoad + gateway.getFullness()) / (location.numberOfGateways + 1); + Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + "): " + location.averageLoad); location.numberOfGateways += 1; locations.set(index, location); } -- cgit v1.2.3 From d366b98aafdb0b211ed7b3870354477ffc250462 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 30 Jul 2021 18:22:12 +0200 Subject: show bridges icon in gateway selector for locations supporting them --- .../base/fragments/GatewaySelectionFragment.java | 25 +++++--------------- .../leap/bitmaskclient/base/models/Location.java | 27 ++++++++++++++++++++-- .../java/se/leap/bitmaskclient/eip/Gateway.java | 4 ++++ .../se/leap/bitmaskclient/eip/GatewaySelector.java | 10 ++++++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 26 +++++++++++++-------- 5 files changed, 62 insertions(+), 30 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index ee4aea74..450cba4d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -18,7 +18,6 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Activity; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -28,6 +27,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; @@ -39,6 +39,7 @@ import java.util.Observable; import java.util.Observer; import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; @@ -48,18 +49,15 @@ import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; -import static android.content.Context.MODE_PRIVATE; import static android.view.View.INVISIBLE; 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; interface LocationListSelectionListener { void onLocationSelected(String name); } -public class GatewaySelectionFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer, LocationListSelectionListener { +public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener { private static final String TAG = GatewaySelectionFragment.class.getSimpleName(); @@ -70,7 +68,6 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen private AppCompatTextView currentLocation; private AppCompatButton autoSelectionButton; private GatewaysManager gatewaysManager; - private SharedPreferences preferences; private EipStatus eipStatus; public GatewaySelectionFragment() { @@ -81,7 +78,6 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gatewaysManager = new GatewaysManager(getContext()); - preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); eipStatus = EipStatus.getInstance(); } @@ -98,19 +94,14 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen initRecyclerView(); initAutoSelectionButton(); initCurrentLocationInfoPanel(); - eipStatus.addObserver(this); - preferences.registerOnSharedPreferenceChangeListener(this); } @Override public void onDestroyView() { super.onDestroyView(); - preferences.unregisterOnSharedPreferenceChangeListener(this); eipStatus.deleteObserver(this); } - - private void initRecyclerView() { recyclerView = getActivity().findViewById(R.id.gatewaySelection_list); recyclerView.setHasFixedSize(true); @@ -162,13 +153,6 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen }).start(); } - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (USE_BRIDGES.equals(key)) { - locationListAdapter.updateData(gatewaysManager.getGatewayLocations()); - } - } - @Override public void onLocationSelected(String name) { startEipService(name); @@ -193,6 +177,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen static class ViewHolder extends RecyclerView.ViewHolder { public AppCompatTextView locationLabel; public LocationIndicator locationIndicator; + public AppCompatImageView bridgeView; public View layout; public ViewHolder(View v) { @@ -200,6 +185,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen layout = v; locationLabel = v.findViewById(R.id.location); locationIndicator = v.findViewById(R.id.quality); + bridgeView = v.findViewById(R.id.bridge_image); } } @@ -246,6 +232,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen } }); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); + holder.bridgeView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : View.GONE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index 8e032d18..3ec7d38c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -1,16 +1,37 @@ +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package se.leap.bitmaskclient.base.models; import androidx.annotation.NonNull; +import java.util.HashSet; +import de.blinkt.openvpn.core.connection.Connection; public class Location { @NonNull public String name; + @NonNull public HashSet supportedTransports; public double averageLoad; public int numberOfGateways; - public Location(@NonNull String name, double averageLoad, int numberOfGateways) { + public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet supportedTransports) { this.name = name; this.averageLoad = averageLoad; this.numberOfGateways = numberOfGateways; + this.supportedTransports = supportedTransports; } @Override @@ -22,7 +43,8 @@ public class Location { if (Double.compare(location.averageLoad, averageLoad) != 0) return false; if (numberOfGateways != location.numberOfGateways) return false; - return name.equals(location.name); + if (!name.equals(location.name)) return false; + return supportedTransports.equals(location.supportedTransports); } @Override @@ -30,6 +52,7 @@ public class Location { int result; long temp; result = name.hashCode(); + result = 31 * result + supportedTransports.hashCode(); temp = Double.doubleToLongBits(averageLoad); result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + numberOfGateways; diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 78b33355..8a48684f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -195,6 +195,10 @@ public class Gateway { return vpnProfiles.get(transportType) != null; } + public HashSet getSupportedTransports() { + return new HashSet<>(vpnProfiles.keySet()); + } + public int getTimezone() { return timezone; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java index 33fd3c21..a48cc6d5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java @@ -2,6 +2,8 @@ package se.leap.bitmaskclient.eip; import android.util.Log; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -18,7 +20,15 @@ public class GatewaySelector { public GatewaySelector(List gateways) { this.gateways = gateways; this.offsets = calculateOffsets(); + } + public ArrayList getGatewaysSortedByDistance() { + ArrayList list = new ArrayList<>(); + int i = 0; + for (Collection gatewayCollection : offsets.values()) { + list.addAll(gatewayCollection); + } + return list; } public Gateway select() { diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 0819e9b6..0b2c2030 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -43,7 +43,6 @@ import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; @@ -121,13 +120,20 @@ public class GatewaysManager { return getGatewayFromTimezoneCalculation(nClosest, transportType, city); } + public ArrayList getSortedGateways() { + if (presortedList.size() > 0) { + return presortedList; + } else { + GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); + return gatewaySelector.getGatewaysSortedByDistance(); + } + } + public List getGatewayLocations() { - String selectedCity = PreferenceHelper.getPreferredCity(context); HashMap locationNames = new HashMap<>(); ArrayList locations = new ArrayList<>(); - int n = 0; - Gateway gateway; - while ((gateway = select(n, null)) != null) { + ArrayList gateways = getSortedGateways(); + for (Gateway gateway : gateways) { String name = gateway.getName(); if (name == null) { Log.e(TAG, "Gateway without location name found. This should never happen. Provider misconfigured?"); @@ -139,23 +145,25 @@ public class GatewaysManager { // fake values for now Random rand = new Random(); double averageLoad = rand.nextDouble(); //location.averageLoad; - Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + "): " + averageLoad); + Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + " - " + gateway.getHost()+ "): " + averageLoad); Location location = new Location( gateway.getName(), averageLoad /*gateway.getFullness()*/, - 1); + 1, + gateway.getSupportedTransports() + ); locations.add(location); } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); location.averageLoad = (location.numberOfGateways * location.averageLoad + gateway.getFullness()) / (location.numberOfGateways + 1); - Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + "): " + location.averageLoad); + Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + " - " + gateway.getHost()+ "): " + location.averageLoad); location.numberOfGateways += 1; + location.supportedTransports.addAll(gateway.getSupportedTransports()); locations.set(index, location); } - n++; } return locations; -- cgit v1.2.3 From 5ab54104c6c701789e59963fcdfda05da5a83a45 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 30 Jul 2021 20:38:23 +0200 Subject: ask user to change location or disable bridges if manually selected location doesn't support bridges --- .../se/leap/bitmaskclient/base/MainActivity.java | 13 +++++++-- .../base/fragments/GatewaySelectionFragment.java | 32 ++++++++++++++++++---- .../base/fragments/MainActivityErrorDialog.java | 25 ++++++++++++++++- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 3 +- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 19 +++++++++++-- 5 files changed, 80 insertions(+), 12 deletions(-) (limited to 'app/src/main/java/se/leap') 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 18ac8b7c..54977f0a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -60,6 +60,7 @@ import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST; +import static se.leap.bitmaskclient.base.models.Constants.LOCATION; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; @@ -85,6 +86,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, public final static String ACTION_SHOW_VPN_FRAGMENT = "action_show_vpn_fragment"; public final static String ACTION_SHOW_LOG_FRAGMENT = "action_show_log_fragment"; + public final static String ACTION_SHOW_DIALOG_FRAGMENT = "action_show_dialog_fragment"; /** * Fragment managing the behaviors, interactions and presentation of the navigation drawer. @@ -152,6 +154,13 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, fragment = new LogFragment(); setActionBarTitle(R.string.log_fragment_title); break; + case ACTION_SHOW_DIALOG_FRAGMENT: + if (intent.hasExtra(EIP.ERRORID)) { + String errorId = intent.getStringExtra(EIP.ERRORID); + String error = intent.getStringExtra(EIP.ERRORS); + String args = intent.getStringExtra(LOCATION); + showMainActivityErrorDialog(error, EIP.EIPErrors.valueOf(errorId), args); + } default: break; } @@ -324,12 +333,12 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, /** * Shows an error dialog */ - public void showMainActivityErrorDialog(String reasonToFail, EIP.EIPErrors error) { + public void showMainActivityErrorDialog(String reasonToFail, EIP.EIPErrors error, String... args) { try { FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced( this.getSupportFragmentManager()).removePreviousFragment( MainActivityErrorDialog.TAG); - DialogFragment newFragment = MainActivityErrorDialog.newInstance(provider, reasonToFail, error); + DialogFragment newFragment = MainActivityErrorDialog.newInstance(provider, reasonToFail, error, args); newFragment.show(fragmentTransaction, MainActivityErrorDialog.TAG); } catch (IllegalStateException | NullPointerException e) { e.printStackTrace(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 450cba4d..2dcb0ec9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -45,16 +45,21 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.LocationIndicator; +import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_DIALOG_FRAGMENT; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; +import static se.leap.bitmaskclient.base.models.Constants.LOCATION; interface LocationListSelectionListener { - void onLocationSelected(String name); + void onLocationSelected(Location location); } public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener { @@ -154,8 +159,24 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } @Override - public void onLocationSelected(String name) { - startEipService(name); + public void onLocationSelected(Location location) { + String name = location.name; + Connection.TransportType selectedTransport = PreferenceHelper.getUsePluggableTransports(getContext()) ? OBFS4 : OPENVPN; + if (location.supportedTransports.contains(selectedTransport)) { + startEipService(name); + } else { + askToChangeTransport(name); + } + } + + private void askToChangeTransport(String name) { + Intent intent = new Intent(getContext(), MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.setAction(ACTION_SHOW_DIALOG_FRAGMENT); + intent.putExtra(EIP.ERRORID, EIP.EIPErrors.TRANSPORT_NOT_SUPPORTED.toString()); + intent.putExtra(EIP.ERRORS, getString(R.string.warning_bridges_not_supported, name)); + intent.putExtra(LOCATION, name); + startActivity(intent); } @Override @@ -168,7 +189,6 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } } - static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); private List values; @@ -228,11 +248,11 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca Log.d(TAG, "view at position clicked: " + position); LocationListSelectionListener listener = callback.get(); if (listener != null) { - listener.onLocationSelected(location.name); + listener.onLocationSelected(location); } }); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); - holder.bridgeView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : View.GONE); + holder.bridgeView.setVisibility(location.supportedTransports.contains(OBFS4) ? VISIBLE : View.GONE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java index da48effc..f7805002 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java @@ -18,6 +18,8 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -27,11 +29,15 @@ import androidx.appcompat.app.AlertDialog; import org.json.JSONObject; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.MainActivity; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_DIALOG_FRAGMENT; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; @@ -56,6 +62,7 @@ public class MainActivityErrorDialog extends DialogFragment { final private static String KEY_REASON_TO_FAIL = "key reason to fail"; final private static String KEY_PROVIDER = "key provider"; private String reasonToFail; + private String[] args; private EIP.EIPErrors downloadError = UNKNOWN; private Provider provider; @@ -70,11 +77,12 @@ public class MainActivityErrorDialog extends DialogFragment { /** * @return a new instance of this DialogFragment. */ - public static DialogFragment newInstance(Provider provider, String reasonToFail, EIP.EIPErrors error) { + public static DialogFragment newInstance(Provider provider, String reasonToFail, EIP.EIPErrors error, String... args) { MainActivityErrorDialog dialogFragment = new MainActivityErrorDialog(); dialogFragment.reasonToFail = reasonToFail; dialogFragment.provider = provider; dialogFragment.downloadError = error; + dialogFragment.args = args; return dialogFragment; } @@ -150,6 +158,21 @@ public class MainActivityErrorDialog extends DialogFragment { case ERROR_VPN_PREPARE: builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { }); break; + case TRANSPORT_NOT_SUPPORTED: + + builder.setPositiveButton(R.string.option_different_location, (dialog, which) -> { }); + builder.setNegativeButton(R.string.option_disable_bridges, (dialog, which) -> { + PreferenceHelper.useBridges(applicationContext, false); + PreferenceHelper.setPreferredCity(applicationContext, args[0]); + + EipCommand.startVPN(applicationContext, false); + // at this point the gateway selection dialog is shown, let's switch to the main view + 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); + }); + break; default: break; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index dd9054f1..a7e08bd7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -127,7 +127,8 @@ public final class EIP extends JobIntentService implements Observer { ERROR_INVALID_VPN_CERTIFICATE, NO_MORE_GATEWAYS, ERROR_VPN_PREPARE, - ERROR_INVALID_PROFILE + ERROR_INVALID_PROFILE, + TRANSPORT_NOT_SUPPORTED, } /** diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 0b2c2030..dbb2a914 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -96,6 +96,7 @@ public class GatewaysManager { private final LinkedHashMap gateways = new LinkedHashMap<>(); private final Type listType = new TypeToken>() {}.getType(); private final ArrayList presortedList = new ArrayList<>(); + private ArrayList locations = new ArrayList<>(); public GatewaysManager(Context context) { this.context = context; @@ -130,6 +131,10 @@ public class GatewaysManager { } public List getGatewayLocations() { + if (locations.size() > 0) { + return locations; + } + HashMap locationNames = new HashMap<>(); ArrayList locations = new ArrayList<>(); ArrayList gateways = getSortedGateways(); @@ -166,16 +171,26 @@ public class GatewaysManager { } } + this.locations = locations; return locations; } - public Load getLoadForLocation(@Nullable String name) { + @Nullable + public Location getLocation(String name) { List locations = getGatewayLocations(); for (Location location : locations) { if (location.name.equals(name)) { - return Load.getLoadByValue(location.averageLoad); + return location; } } + return null; + } + + public Load getLoadForLocation(@Nullable String name) { + Location location = getLocation(name); + if (location != null) { + return Load.getLoadByValue(location.averageLoad); + } // location not found return Load.UNKNOWN; -- cgit v1.2.3 From 6d3c122bebf0ad4f7dc22d4963dc73dea4248251 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 16:34:09 +0200 Subject: adapt EIP main screen and strings to simply secure proposals --- .../bitmaskclient/base/fragments/EipFragment.java | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index af34b7a5..e9402468 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -39,6 +39,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -50,6 +51,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; +import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; @@ -84,6 +86,7 @@ import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; 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.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx; import static se.leap.bitmaskclient.eip.EipSetupObserver.gatewayOrder; import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway; @@ -109,6 +112,12 @@ public class EipFragment extends Fragment implements Observer { @BindView(R.id.gateway_location_button) LocationButton locationButton; + @BindView(R.id.main_description) + AppCompatTextView mainDescription; + + @BindView(R.id.sub_description) + AppCompatTextView subDescription; + private Unbinder unbinder; private EipStatus eipStatus; @@ -408,21 +417,20 @@ public class EipFragment extends Fragment implements Observer { return; } - //Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); - - + Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); if (eipStatus.isConnecting() ) { setMainButtonEnabled(true); showConnectingLayout(activity); if (eipStatus.isReconnecting()) { - locationButton.setText(getString(R.string.reconnecting)); + subDescription.setText(getString(R.string.reconnecting)); } else { - locationButton.setText(getString(R.string.finding_best_connection)); + subDescription.setText(R.string.connection_not_connected); } + locationButton.setText(getString(R.string.finding_best_connection)); + mainDescription.setText(R.string.eip_state_insecure); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); - } else if (eipStatus.isConnected() ) { - locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); + } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_connected); vpnStateImage.stopProgress(false); @@ -430,23 +438,34 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.setVisibility(VISIBLE); colorBackground(); + mainDescription.setText(R.string.eip_state_connected); + subDescription.setText(getPreferredCity(getContext()) == null ? + R.string.eip_state_connected_recommended : + R.string.eip_state_connected_manual); } else if(isOpenVpnRunningWithoutNetwork()){ - locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); + Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); vpnStateImage.stopProgress(false); locationButton.setVisibility(VISIBLE); + locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); setVpnRouteText(); colorBackgroundALittle(); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.eip_state_no_network); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { showConnectingLayout(activity); // showRetryToast(activity); locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.reconnecting); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); showDisconnectingLayout(activity); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_blocking); @@ -455,6 +474,8 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + mainDescription.setText(R.string.eip_state_connected); + subDescription.setText(R.string.eip_state_blocking); } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); @@ -463,6 +484,8 @@ public class EipFragment extends Fragment implements Observer { greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); locationButton.setVisibility(GONE); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.connection_not_connected); } } -- cgit v1.2.3 From 033ac24155bf9b56fbf8a247ab582ecd2b934e9a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:32:01 +0200 Subject: initial implementation of classic on-off push button --- .../bitmaskclient/base/fragments/EipFragment.java | 27 +++++++--------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index e9402468..3650804f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -27,7 +27,6 @@ import android.graphics.ColorMatrixColorFilter; import android.os.Bundle; import android.os.IBinder; import android.os.Vibrator; -import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -51,7 +50,6 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; -import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; @@ -420,7 +418,7 @@ public class EipFragment extends Fragment implements Observer { Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); if (eipStatus.isConnecting() ) { setMainButtonEnabled(true); - showConnectingLayout(activity); + showConnectionTransitionLayout(true); if (eipStatus.isReconnecting()) { subDescription.setText(getString(R.string.reconnecting)); } else { @@ -432,7 +430,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_connected); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); vpnStateImage.stopProgress(false); locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); @@ -445,16 +443,15 @@ public class EipFragment extends Fragment implements Observer { } else if(isOpenVpnRunningWithoutNetwork()){ Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); vpnStateImage.stopProgress(false); locationButton.setVisibility(VISIBLE); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); - setVpnRouteText(); colorBackgroundALittle(); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.eip_state_no_network); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { - showConnectingLayout(activity); + showConnectionTransitionLayout(true); // showRetryToast(activity); locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); @@ -463,12 +460,12 @@ public class EipFragment extends Fragment implements Observer { subDescription.setText(R.string.reconnecting); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); - showDisconnectingLayout(activity); + showConnectionTransitionLayout(false); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_blocking); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); vpnStateImage.stopProgress(false); colorBackgroundALittle(); locationButton.setText(getString(R.string.finding_best_connection)); @@ -518,16 +515,8 @@ public class EipFragment extends Fragment implements Observer { showToast(activity, message, true ); } - private void showConnectingLayout(Context activity) { - showConnectionTransitionLayout(activity, true); - } - - private void showDisconnectingLayout(Activity activity) { - showConnectionTransitionLayout(activity, false); - } - - private void showConnectionTransitionLayout(Context activity, boolean isConnecting) { - vpnStateImage.setStateIcon(R.drawable.vpn_connecting); + private void showConnectionTransitionLayout(boolean isConnecting) { + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_connecting); vpnStateImage.showProgress(); if (isConnecting) { colorBackgroundALittle(); -- cgit v1.2.3 From a82d85c3f8ed72597c4a8da77c816501f5f6d47d Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:33:39 +0200 Subject: avoid layout jumping --- .../main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 3650804f..7456fcc9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -70,7 +70,7 @@ import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivit import se.leap.bitmaskclient.providersetup.activities.LoginActivity; import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; -import static android.view.View.GONE; +import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; @@ -480,7 +480,7 @@ public class EipFragment extends Fragment implements Observer { vpnStateImage.stopProgress(false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); - locationButton.setVisibility(GONE); + locationButton.setVisibility(INVISIBLE); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } -- cgit v1.2.3 From 5eef2b3f995b48d0f993947dc28876c29f86421b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:34:08 +0200 Subject: add missing vpn button state --- app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 7456fcc9..2f50d258 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -476,7 +476,7 @@ public class EipFragment extends Fragment implements Observer { } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_disabled); vpnStateImage.stopProgress(false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); -- cgit v1.2.3 From a874ed7362f124900b9c8ea325f80393f0ba680e Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:34:26 +0200 Subject: cleanup --- .../java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 9 --------- 1 file changed, 9 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 2f50d258..ef16d085 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -587,15 +587,6 @@ public class EipFragment extends Fragment implements Observer { } } - private void setVpnRouteText() { - String vpnRouteString = provider.getName(); - String profileName = VpnStatus.getLastConnectedVpnName(); - if (!TextUtils.isEmpty(profileName)) { - vpnRouteString += " (" + profileName + ")"; - } - // vpnRoute.setText(vpnRouteString); - } - private class EipFragmentServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName className, -- cgit v1.2.3 From 1f8b9f9c65a60de9813c77344bdba0fa8153cb62 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:48:06 +0200 Subject: add missing eip status observer registration in GatewaySelectionFragment --- .../se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 2dcb0ec9..c0b9d2d4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -84,6 +84,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca super.onCreate(savedInstanceState); gatewaysManager = new GatewaysManager(getContext()); eipStatus = EipStatus.getInstance(); + eipStatus.addObserver(this); } @Override -- cgit v1.2.3 From a2067cd5b56387405cb653de8940e7afc448449d Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 19:30:54 +0200 Subject: Add BuildConfig to disable color filtering of the main screen background, if VPN is turned off. Make EipFragment's text colors customizable --- .../bitmaskclient/base/fragments/EipFragment.java | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index ef16d085..d8be1cc5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -54,6 +54,7 @@ import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; 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; @@ -552,21 +553,27 @@ public class EipFragment extends Fragment implements Observer { } private void greyscaleBackground() { - ColorMatrix matrix = new ColorMatrix(); - matrix.setSaturation(0); - ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); - background.setColorFilter(cf); - background.setImageAlpha(255); + if (BuildConfig.use_color_filter) { + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0); + ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); + background.setColorFilter(cf); + background.setImageAlpha(255); + } } private void colorBackgroundALittle() { - background.setColorFilter(null); - background.setImageAlpha(144); + if (BuildConfig.use_color_filter) { + background.setColorFilter(null); + background.setImageAlpha(144); + } } private void colorBackground() { - background.setColorFilter(null); - background.setImageAlpha(210); + if (BuildConfig.use_color_filter) { + background.setColorFilter(null); + background.setImageAlpha(210); + } } private void updateInvalidVpnCertificate() { -- cgit v1.2.3 From aeadefa699db964b1a4ca3ee2bbd45a80ae847a7 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 14 Nov 2021 20:02:16 +0100 Subject: fix preference renaming --- .../se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index c0b9d2d4..4a431dff 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -162,7 +162,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca @Override public void onLocationSelected(Location location) { String name = location.name; - Connection.TransportType selectedTransport = PreferenceHelper.getUsePluggableTransports(getContext()) ? OBFS4 : OPENVPN; + Connection.TransportType selectedTransport = PreferenceHelper.getUseBridges(getContext()) ? OBFS4 : OPENVPN; if (location.supportedTransports.contains(selectedTransport)) { startEipService(name); } else { -- cgit v1.2.3 From 580c97e368cd0d9fa47691f70cc31e9b711581ec Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 15 Nov 2021 14:09:17 +0100 Subject: implement a new fancy on-off-button --- .../bitmaskclient/base/fragments/EipFragment.java | 25 ++- .../leap/bitmaskclient/base/views/MainButton.java | 189 +++++++++++++++++++++ 2 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index d8be1cc5..813daac5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -61,7 +61,7 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.views.LocationButton; -import se.leap.bitmaskclient.base.views.VpnStateImage; +import se.leap.bitmaskclient.base.views.MainButton; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; @@ -105,8 +105,8 @@ public class EipFragment extends Fragment implements Observer { @BindView(R.id.background) AppCompatImageView background; - @BindView(R.id.vpn_state_image) - VpnStateImage vpnStateImage; + @BindView(R.id.main_button) + MainButton mainButton; @BindView(R.id.gateway_location_button) LocationButton locationButton; @@ -272,7 +272,7 @@ public class EipFragment extends Fragment implements Observer { handleIcon(); } - @OnClick(R.id.vpn_state_image) + @OnClick(R.id.main_button) void onVpnStateImageClick() { handleIcon(); } @@ -323,7 +323,7 @@ public class EipFragment extends Fragment implements Observer { private void setMainButtonEnabled(boolean enabled) { locationButton.setEnabled(enabled); - vpnStateImage.setEnabled(enabled); + mainButton.setEnabled(enabled); } public void startEipFromScratch() { @@ -431,8 +431,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); - vpnStateImage.stopProgress(false); + mainButton.updateState(true, false, false); locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.setVisibility(VISIBLE); @@ -444,8 +443,7 @@ public class EipFragment extends Fragment implements Observer { } else if(isOpenVpnRunningWithoutNetwork()){ Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); - vpnStateImage.stopProgress(false); + mainButton.updateState(true, false, true); locationButton.setVisibility(VISIBLE); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); colorBackgroundALittle(); @@ -466,8 +464,7 @@ public class EipFragment extends Fragment implements Observer { subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); - vpnStateImage.stopProgress(false); + mainButton.updateState(true, false, true); colorBackgroundALittle(); locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); @@ -477,8 +474,7 @@ public class EipFragment extends Fragment implements Observer { } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_disabled); - vpnStateImage.stopProgress(false); + mainButton.updateState(false, false, false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); locationButton.setVisibility(INVISIBLE); @@ -517,8 +513,7 @@ public class EipFragment extends Fragment implements Observer { } private void showConnectionTransitionLayout(boolean isConnecting) { - vpnStateImage.setStateIcon(R.drawable.ic_btn_on_connecting); - vpnStateImage.showProgress(); + mainButton.updateState(true, true, false); if (isConnecting) { colorBackgroundALittle(); } else { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java new file mode 100644 index 00000000..586eb321 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -0,0 +1,189 @@ +package se.leap.bitmaskclient.base.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.RelativeLayout; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; + +import java.lang.ref.WeakReference; + +import se.leap.bitmaskclient.R; + +public class MainButton extends RelativeLayout { + + private static final String TAG = MainButton.class.getSimpleName(); + + interface MainButtonListener { + void onButtonClicked(); + } + + AppCompatImageView glow; + AppCompatImageView shadowDark; + AppCompatImageView shadowLight; + AnimationDrawable glowAnimation; + WeakReference callback; + + private boolean isOn = false; + private boolean isProcessing = false; + private boolean isError = true; + + + + public MainButton(Context context) { + super(context); + initLayout(context); + } + + public MainButton(Context context, AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + public MainButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + + @TargetApi(21) + public MainButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initLayout(context); + } + + public void setMainButtonListener(MainButtonListener callback) { + this.callback = new WeakReference<>(callback); + } + + private void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_main_btn, this, true); + + glow = rootview.findViewById(R.id.vpn_btn_glow); + glowAnimation = (AnimationDrawable) glow.getBackground(); + shadowDark = rootview.findViewById(R.id.vpn_btn_shadow_dark); + shadowLight = rootview.findViewById(R.id.vpn_btn_shadow_light); + + rootview.setOnGenericMotionListener(new OnGenericMotionListener() { + @Override + public boolean onGenericMotion(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_BUTTON_PRESS: + Log.d(TAG, "onbuttonPrees"); + break; + case MotionEvent.ACTION_BUTTON_RELEASE: + Log.d(TAG, "onButtonRelease"); + break; + } + return false; + } + }); + rootview.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + Log.d(TAG, "motion down"); + Drawable drawableDown = context.getResources().getDrawable(R.drawable.on_off_btn_start_2_pressed); + shadowDark.setImageDrawable(drawableDown); + break; + case MotionEvent.ACTION_UP: + Log.d(TAG, "motion up"); + Drawable drawableUp = isOn ? + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled) : + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled); + shadowDark.setImageDrawable(drawableUp); + break; + case MotionEvent.ACTION_CANCEL: + Log.d(TAG, "motion cancelled"); + Drawable drawableRestoreState = isOn ? + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled) : + context.getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled); + shadowDark.setImageDrawable(drawableRestoreState); + break; + } + return false; + } + }); + + } + + + private void stopGlowAnimation() { + AlphaAnimation fadeOutAnimation = new AlphaAnimation(1.0f, 0.0f); + fadeOutAnimation.setDuration(300); + fadeOutAnimation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} + + @Override + public void onAnimationEnd(Animation animation) { + glow.setVisibility(GONE); + glowAnimation.stop(); + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }); + glow.startAnimation(fadeOutAnimation); + } + + private void startGlowAnimation() { + glow.setAlpha(1.0f); + glow.setVisibility(VISIBLE); + glowAnimation.start(); + } + + public void updateState(boolean isOn, boolean isProcessing, boolean isError) { + if (this.isOn != isOn) { + this.isOn = isOn; + Drawable drawableRestoreState = isOn ? + getContext().getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled) : + getContext().getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled); + shadowDark.setImageDrawable(drawableRestoreState); + shadowLight.setVisibility(isOn ? VISIBLE : GONE); + } + + if (this.isProcessing != isProcessing) { + if (!isProcessing) { + stopGlowAnimation(); + } else { + startGlowAnimation(); + } + this.isProcessing = isProcessing; + } + + if (this.isError != isError) { + @DrawableRes int drawableResource = isOn ? R.drawable.on_off_btn_start_2_enabled : R.drawable.on_off_btn_start_2_disabled; + if (!isError) { + setImageWithTint(shadowLight, drawableResource, R.color.colorSecondary); + } else { + setImageWithTint(shadowLight, drawableResource, R.color.colorWarning); + } + this.isError = isError; + } + } + + private void setImageWithTint(AppCompatImageView view, @DrawableRes int resourceId, @ColorRes int color) { + view.setImageDrawable(ContextCompat.getDrawable(getContext(), resourceId)); + view.setColorFilter(ContextCompat.getColor(getContext(), color), PorterDuff.Mode.SRC_ATOP); + } + + + +} -- cgit v1.2.3 From 78b06a47b6c7e3de5706893eeebb01bef89060d8 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 15 Nov 2021 14:23:23 +0100 Subject: only use two button pressed states --- .../leap/bitmaskclient/base/views/MainButton.java | 36 ---------------------- 1 file changed, 36 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java index 586eb321..1a8fa09b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -4,7 +4,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.graphics.PorterDuff; import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -18,7 +17,6 @@ import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.appcompat.widget.AppCompatImageView; import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableCompat; import java.lang.ref.WeakReference; @@ -33,7 +31,6 @@ public class MainButton extends RelativeLayout { } AppCompatImageView glow; - AppCompatImageView shadowDark; AppCompatImageView shadowLight; AnimationDrawable glowAnimation; WeakReference callback; @@ -76,7 +73,6 @@ public class MainButton extends RelativeLayout { glow = rootview.findViewById(R.id.vpn_btn_glow); glowAnimation = (AnimationDrawable) glow.getBackground(); - shadowDark = rootview.findViewById(R.id.vpn_btn_shadow_dark); shadowLight = rootview.findViewById(R.id.vpn_btn_shadow_light); rootview.setOnGenericMotionListener(new OnGenericMotionListener() { @@ -93,34 +89,6 @@ public class MainButton extends RelativeLayout { return false; } }); - rootview.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - Log.d(TAG, "motion down"); - Drawable drawableDown = context.getResources().getDrawable(R.drawable.on_off_btn_start_2_pressed); - shadowDark.setImageDrawable(drawableDown); - break; - case MotionEvent.ACTION_UP: - Log.d(TAG, "motion up"); - Drawable drawableUp = isOn ? - context.getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled) : - context.getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled); - shadowDark.setImageDrawable(drawableUp); - break; - case MotionEvent.ACTION_CANCEL: - Log.d(TAG, "motion cancelled"); - Drawable drawableRestoreState = isOn ? - context.getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled) : - context.getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled); - shadowDark.setImageDrawable(drawableRestoreState); - break; - } - return false; - } - }); - } @@ -152,10 +120,6 @@ public class MainButton extends RelativeLayout { public void updateState(boolean isOn, boolean isProcessing, boolean isError) { if (this.isOn != isOn) { this.isOn = isOn; - Drawable drawableRestoreState = isOn ? - getContext().getResources().getDrawable(R.drawable.on_off_btn_start_2_enabled) : - getContext().getResources().getDrawable(R.drawable.on_off_btn_start_2_disabled); - shadowDark.setImageDrawable(drawableRestoreState); shadowLight.setVisibility(isOn ? VISIBLE : GONE); } -- cgit v1.2.3 From 79c01db669fc68b1071f0c2e62eae1e4be66bbb8 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 15 Nov 2021 16:00:50 +0100 Subject: remove unused code --- .../leap/bitmaskclient/base/views/MainButton.java | 29 ---------------------- 1 file changed, 29 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java index 1a8fa09b..b12f2b00 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -5,9 +5,7 @@ import android.content.Context; import android.graphics.PorterDuff; import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -18,29 +16,21 @@ import androidx.annotation.DrawableRes; import androidx.appcompat.widget.AppCompatImageView; import androidx.core.content.ContextCompat; -import java.lang.ref.WeakReference; - import se.leap.bitmaskclient.R; public class MainButton extends RelativeLayout { private static final String TAG = MainButton.class.getSimpleName(); - interface MainButtonListener { - void onButtonClicked(); - } - AppCompatImageView glow; AppCompatImageView shadowLight; AnimationDrawable glowAnimation; - WeakReference callback; private boolean isOn = false; private boolean isProcessing = false; private boolean isError = true; - public MainButton(Context context) { super(context); initLayout(context); @@ -63,10 +53,6 @@ public class MainButton extends RelativeLayout { initLayout(context); } - public void setMainButtonListener(MainButtonListener callback) { - this.callback = new WeakReference<>(callback); - } - private void initLayout(Context context) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rootview = inflater.inflate(R.layout.v_main_btn, this, true); @@ -74,21 +60,6 @@ public class MainButton extends RelativeLayout { glow = rootview.findViewById(R.id.vpn_btn_glow); glowAnimation = (AnimationDrawable) glow.getBackground(); shadowLight = rootview.findViewById(R.id.vpn_btn_shadow_light); - - rootview.setOnGenericMotionListener(new OnGenericMotionListener() { - @Override - public boolean onGenericMotion(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_BUTTON_PRESS: - Log.d(TAG, "onbuttonPrees"); - break; - case MotionEvent.ACTION_BUTTON_RELEASE: - Log.d(TAG, "onButtonRelease"); - break; - } - return false; - } - }); } -- cgit v1.2.3 From 427a41a35205b1948da37727eb21b66e2c518b0c Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 15 Nov 2021 16:02:09 +0100 Subject: tweak an rename main button higlight colores --- app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java index b12f2b00..c5ac4544 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -106,9 +106,9 @@ public class MainButton extends RelativeLayout { if (this.isError != isError) { @DrawableRes int drawableResource = isOn ? R.drawable.on_off_btn_start_2_enabled : R.drawable.on_off_btn_start_2_disabled; if (!isError) { - setImageWithTint(shadowLight, drawableResource, R.color.colorSecondary); + setImageWithTint(shadowLight, drawableResource, R.color.colorMainBtnHighlight); } else { - setImageWithTint(shadowLight, drawableResource, R.color.colorWarning); + setImageWithTint(shadowLight, drawableResource, R.color.colorMainBtnError); } this.isError = isError; } -- cgit v1.2.3 From 551ee22aafae99c1f0802ec48f43d448cc77db37 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 22 Jul 2021 15:31:08 +0200 Subject: first implementation of the gateway button, started to remove labels from EipFragment, implement method to get the avearage load of a location as an enum value --- .../bitmaskclient/base/fragments/EipFragment.java | 66 +++++++++---------- .../bitmaskclient/base/views/LocationButton.java | 44 +++++++++++++ .../base/views/LocationIndicator.java | 76 ++++++++++++++++++++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 50 ++++++++++++++ 4 files changed, 203 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 615221ae..cc822463 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -38,9 +38,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -60,9 +58,11 @@ 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.views.LocationButton; import se.leap.bitmaskclient.base.views.VpnStateImage; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; +import se.leap.bitmaskclient.eip.GatewaysManager; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; import se.leap.bitmaskclient.providersetup.ProviderListActivity; import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity; @@ -86,6 +86,7 @@ import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx; import static se.leap.bitmaskclient.eip.EipSetupObserver.gatewayOrder; import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway; +import static se.leap.bitmaskclient.eip.GatewaysManager.Load.UNKNOWN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; @@ -104,18 +105,14 @@ public class EipFragment extends Fragment implements Observer { @BindView(R.id.vpn_state_image) VpnStateImage vpnStateImage; - @BindView(R.id.vpn_main_button) - AppCompatButton mainButton; - - @BindView(R.id.routed_text) - AppCompatTextView routedText; - - @BindView(R.id.vpn_route) - AppCompatTextView vpnRoute; + @BindView(R.id.gateway_location_button) + LocationButton locationButton; private Unbinder unbinder; private EipStatus eipStatus; + private GatewaysManager gatewaysManager; + //---saved Instance ------- private final String KEY_SHOW_PENDING_START_CANCELLATION = "KEY_SHOW_PENDING_START_CANCELLATION"; private final String KEY_SHOW_ASK_TO_STOP_EIP = "KEY_SHOW_ASK_TO_STOP_EIP"; @@ -168,6 +165,9 @@ public class EipFragment extends Fragment implements Observer { } else { Log.e(TAG, "activity is null in onCreate - no preferences set!"); } + + gatewaysManager = new GatewaysManager(getContext()); + } @Override @@ -252,7 +252,7 @@ public class EipFragment extends Fragment implements Observer { preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, restartOnBoot).apply(); } - @OnClick(R.id.vpn_main_button) + @OnClick(R.id.gateway_location_button) void onButtonClick() { handleIcon(); } @@ -307,7 +307,7 @@ public class EipFragment extends Fragment implements Observer { } private void setMainButtonEnabled(boolean enabled) { - mainButton.setEnabled(enabled); + locationButton.setEnabled(enabled); vpnStateImage.setEnabled(enabled); } @@ -408,32 +408,35 @@ public class EipFragment extends Fragment implements Observer { setMainButtonEnabled(true); showConnectingLayout(activity); if (eipStatus.isReconnecting()) { - //Log.d(TAG, "eip show reconnecting toast!"); - //showReconnectToast(activity); + locationButton.setText(getString(R.string.reconnecting)); + } else { + locationButton.setText(getString(R.string.finding_best_connection)); } + locationButton.setVisibility(VISIBLE); + locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isConnected() ) { - mainButton.setText(activity.getString(R.string.vpn_button_turn_off)); + locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_connected); vpnStateImage.stopProgress(false); - routedText.setText(R.string.vpn_securely_routed); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(VISIBLE); - setVpnRouteText(); + locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); + locationButton.setText(VpnStatus.getLastConnectedVpnName()); + locationButton.setVisibility(VISIBLE); colorBackground(); } else if(isOpenVpnRunningWithoutNetwork()){ - mainButton.setText(activity.getString(R.string.vpn_button_turn_off)); + locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); vpnStateImage.stopProgress(false); - routedText.setText(R.string.vpn_securely_routed_no_internet); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(VISIBLE); + locationButton.setVisibility(VISIBLE); setVpnRouteText(); colorBackgroundALittle(); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { showConnectingLayout(activity); // showRetryToast(activity); + locationButton.setText(getString(R.string.finding_best_connection)); + locationButton.setVisibility(VISIBLE); + locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); showDisconnectingLayout(activity); @@ -441,18 +444,18 @@ public class EipFragment extends Fragment implements Observer { setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_blocking); vpnStateImage.stopProgress(false); - routedText.setText(getString(R.string.void_vpn_establish, getString(R.string.app_name))); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(GONE); colorBackgroundALittle(); + locationButton.setText(getString(R.string.finding_best_connection)); + locationButton.setVisibility(VISIBLE); + locationButton.setLocationLoad(UNKNOWN); } else { - mainButton.setText(activity.getString(R.string.vpn_button_turn_on)); + locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); vpnStateImage.stopProgress(false); - routedText.setVisibility(GONE); - vpnRoute.setVisibility(GONE); greyscaleBackground(); + locationButton.setLocationLoad(UNKNOWN); + locationButton.setVisibility(GONE); } } @@ -494,11 +497,8 @@ public class EipFragment extends Fragment implements Observer { } private void showConnectionTransitionLayout(Context activity, boolean isConnecting) { - mainButton.setText(activity.getString(android.R.string.cancel)); vpnStateImage.setStateIcon(R.drawable.vpn_connecting); vpnStateImage.showProgress(); - routedText.setVisibility(GONE); - vpnRoute.setVisibility(GONE); if (isConnecting) { colorBackgroundALittle(); } else { @@ -574,7 +574,7 @@ public class EipFragment extends Fragment implements Observer { if (!TextUtils.isEmpty(profileName)) { vpnRouteString += " (" + profileName + ")"; } - vpnRoute.setText(vpnRouteString); + // vpnRoute.setText(vpnRouteString); } private class EipFragmentServiceConnection implements ServiceConnection { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java new file mode 100644 index 00000000..1d7f0d18 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java @@ -0,0 +1,44 @@ +package se.leap.bitmaskclient.base.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.LinearLayoutCompat; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.eip.GatewaysManager; + +public class LocationButton extends LinearLayoutCompat { + private LocationIndicator locationIndicator; + private AppCompatTextView textView; + public LocationButton(@NonNull Context context) { + super(context); + initLayout(context); + } + + public LocationButton(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + private void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_location_button, this, true); + locationIndicator = rootview.findViewById(R.id.load_indicator); + textView = rootview.findViewById(R.id.text_location); + } + + public void setLocationLoad(GatewaysManager.Load load) { + locationIndicator.setLoad(load); + } + + public void setText(CharSequence text) { + textView.setText(text); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java new file mode 100644 index 00000000..f5e3dbe2 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java @@ -0,0 +1,76 @@ +package se.leap.bitmaskclient.base.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.Nullable; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.eip.GatewaysManager; + +public class LocationIndicator extends LinearLayout { + + private View level1; + private View level2; + private View level3; + + public LocationIndicator(Context context) { + super(context); + initLayout(context); + } + + public LocationIndicator(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initLayout(context); + + } + + public LocationIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + + void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_location_status_indicator, this, true); + level1 = rootview.findViewById(R.id.level1); + level2 = rootview.findViewById(R.id.level2); + level3 = rootview.findViewById(R.id.level3); + } + + public void setLoad(GatewaysManager.Load load) { + switch (load) { + case GOOD: + level1.setBackgroundColor(getResources().getColor(R.color.green200)); + level2.setBackgroundColor(getResources().getColor(R.color.green200)); + level3.setBackgroundColor(getResources().getColor(R.color.green200)); + level1.setVisibility(VISIBLE); + level2.setVisibility(VISIBLE); + level3.setVisibility(VISIBLE); + break; + case AVERAGE: + level1.setBackgroundColor(getResources().getColor(R.color.yellow200)); + level2.setBackgroundColor(getResources().getColor(R.color.yellow200)); + level1.setVisibility(VISIBLE); + level2.setVisibility(VISIBLE); + level3.setVisibility(INVISIBLE); + break; + case CRITICAL: + level1.setBackgroundColor(getResources().getColor(R.color.red200)); + level1.setVisibility(VISIBLE); + level2.setVisibility(INVISIBLE); + level3.setVisibility(INVISIBLE); + break; + default: + level1.setVisibility(INVISIBLE); + level2.setVisibility(INVISIBLE); + level3.setVisibility(INVISIBLE); + break; + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 05775d13..b311315c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Random; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; @@ -59,6 +60,37 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; */ public class GatewaysManager { + public enum Load { + UNKNOWN(0), + GOOD(0.25), + AVERAGE(0.75), + CRITICAL(1.0); + + private final double value; + + Load(double i) { + value = i; + } + + public static Load getLoadByValue(double value) { + if (value == UNKNOWN.value) { + return UNKNOWN; + } else if (value <= GOOD.value) { + return GOOD; + } else if (value <= AVERAGE.value) { + return AVERAGE; + } else if (value <= CRITICAL.value) { + return CRITICAL; + } else { + return UNKNOWN; + } + } + + public double getValue() { + return value; + } + } + private static final String TAG = GatewaysManager.class.getSimpleName(); private Context context; @@ -117,6 +149,22 @@ public class GatewaysManager { return locations; } + public Load getLoadForLocation(@Nullable String name) { + List locations = getGatewayLocations(); + for (Location location : locations) { + if (location.name.equals(name)) { + + // fake values for now + Random rand = new Random(); + double averageLoad = rand.nextDouble(); //location.averageLoad; + return Load.getLoadByValue(averageLoad); + } + } + + // location not found + return Load.UNKNOWN; + } + private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType, @Nullable String city) { List list = new ArrayList<>(gateways.values()); GatewaySelector gatewaySelector = new GatewaySelector(list); @@ -326,4 +374,6 @@ public class GatewaysManager { } } + + } -- cgit v1.2.3 From a45f69a96ccdcc0f1d1aae18c9dcf17bf9d15e73 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 23 Jul 2021 23:50:02 +0200 Subject: add click listener to gateway selection button, open the gateway selection fragment --- .../java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index cc822463..af34b7a5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -56,6 +56,7 @@ import de.blinkt.openvpn.core.OpenVPNService; 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.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.views.LocationButton; @@ -168,6 +169,7 @@ public class EipFragment extends Fragment implements Observer { gatewaysManager = new GatewaysManager(getContext()); + } @Override @@ -189,6 +191,11 @@ public class EipFragment extends Fragment implements Observer { } restoreFromSavedInstance(savedInstanceState); + locationButton.setOnClickListener(v -> { + FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); + Fragment fragment = new GatewaySelectionFragment(); + fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); + }); return view; } -- cgit v1.2.3 From 9818a16e510d42fec32aef5a6efcd6d2ae4aa110 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 29 Jul 2021 18:23:55 +0200 Subject: implement location load indicator in gateway selection cell --- .../base/fragments/GatewaySelectionFragment.java | 7 ++++--- .../java/se/leap/bitmaskclient/eip/GatewaysManager.java | 14 ++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index d1222cd7..e4d8ca8b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -46,6 +46,7 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.IconSwitchEntry; +import se.leap.bitmaskclient.base.views.LocationIndicator; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; @@ -189,7 +190,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen static class ViewHolder extends RecyclerView.ViewHolder { public AppCompatTextView locationLabel; - public AppCompatTextView qualityLabel; + public LocationIndicator locationIndicator; public AppCompatImageView checkedIcon; public View layout; @@ -197,7 +198,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen super(v); layout = v; locationLabel = (AppCompatTextView) v.findViewById(R.id.location); - qualityLabel = (AppCompatTextView) v.findViewById(R.id.quality); + locationIndicator = (LocationIndicator) v.findViewById(R.id.quality); checkedIcon = (AppCompatImageView) v.findViewById(R.id.checked_icon); } } @@ -263,7 +264,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen DrawableCompat.setTint(checkIcon, ContextCompat.getColor(holder.layout.getContext(), R.color.colorSuccess)); holder.checkedIcon.setImageDrawable(checkIcon); holder.checkedIcon.setVisibility(location.selected ? VISIBLE : INVISIBLE); - holder.qualityLabel.setText(getQualityString(location.averageLoad)); + holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); if (location.selected) { selectedLocation = location; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index b311315c..24e9c323 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -130,9 +130,15 @@ public class GatewaysManager { while ((gateway = select(n, null)) != null) { if (!locationNames.containsKey(gateway.getName())) { locationNames.put(gateway.getName(), locations.size()); + // fake values for now + Random rand = new Random(); + double averageLoad = rand.nextDouble(); //location.averageLoad; + + Location location = new Location( gateway.getName(), - gateway.getFullness(), + averageLoad + /*gateway.getFullness()*/, 1, gateway.getName().equals(selectedCity)); locations.add(location); @@ -153,11 +159,7 @@ public class GatewaysManager { List locations = getGatewayLocations(); for (Location location : locations) { if (location.name.equals(name)) { - - // fake values for now - Random rand = new Random(); - double averageLoad = rand.nextDouble(); //location.averageLoad; - return Load.getLoadByValue(averageLoad); + return Load.getLoadByValue(location.averageLoad); } } -- cgit v1.2.3 From 5c4c3cde26fafbd763e4a879dc46ca959b1a7d27 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 30 Jul 2021 15:46:40 +0200 Subject: draft gateway selection UI according to simlpy secure's proposals --- .../base/fragments/GatewaySelectionFragment.java | 158 ++++++++------------- .../base/fragments/MainActivityErrorDialog.java | 6 +- .../base/fragments/NavigationDrawerFragment.java | 2 +- .../leap/bitmaskclient/base/models/Location.java | 6 +- .../bitmaskclient/base/utils/PreferenceHelper.java | 10 +- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 20 ++- 6 files changed, 89 insertions(+), 113 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index e4d8ca8b..ee4aea74 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -19,7 +19,6 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -29,23 +28,21 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatButton; -import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import java.lang.ref.WeakReference; import java.util.List; import java.util.Observable; import java.util.Observer; +import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import se.leap.bitmaskclient.base.views.IconSwitchEntry; import se.leap.bitmaskclient.base.views.LocationIndicator; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; @@ -55,21 +52,23 @@ import static android.content.Context.MODE_PRIVATE; import static android.view.View.INVISIBLE; 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.PREFERRED_CITY; 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.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; -public class GatewaySelectionFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer { +interface LocationListSelectionListener { + void onLocationSelected(String name); +} + +public class GatewaySelectionFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer, LocationListSelectionListener { private static final String TAG = GatewaySelectionFragment.class.getSimpleName(); private RecyclerView recyclerView; private LocationListAdapter locationListAdapter; - private IconSwitchEntry autoSelectionSwitch; - private AppCompatButton vpnButton; + private AppCompatTextView currentLocationDescription; + private AppCompatTextView currentLocation; + private AppCompatButton autoSelectionButton; private GatewaysManager gatewaysManager; private SharedPreferences preferences; private EipStatus eipStatus; @@ -97,8 +96,8 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initRecyclerView(); - initAutoSelectionSwitch(); - initVpnButton(); + initAutoSelectionButton(); + initCurrentLocationInfoPanel(); eipStatus.addObserver(this); preferences.registerOnSharedPreferenceChangeListener(this); } @@ -113,93 +112,94 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen private void initRecyclerView() { - recyclerView = (RecyclerView) getActivity().findViewById(R.id.gatewaySelection_list); + recyclerView = getActivity().findViewById(R.id.gatewaySelection_list); recyclerView.setHasFixedSize(true); LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); recyclerView.setLayoutManager(layoutManager); - locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations()); + locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations(), this); recyclerView.setAdapter(locationListAdapter); - recyclerView.setVisibility(getPreferredCity(getContext()) == null ? INVISIBLE : VISIBLE); + recyclerView.setVisibility(VISIBLE); } - private void initAutoSelectionSwitch() { - autoSelectionSwitch = getActivity().findViewById(R.id.automatic_gateway_switch); - autoSelectionSwitch.setSingleLine(false); - autoSelectionSwitch.setSubtitle(getString(R.string.gateway_selection_warning, getString(R.string.app_name))); - autoSelectionSwitch.setChecked(getPreferredCity(getContext()) == null); - autoSelectionSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { - recyclerView.setVisibility(!isChecked ? VISIBLE : View.GONE); - Log.d(TAG, "autoselection enabled: " + isChecked); - if (isChecked) { - PreferenceHelper.setPreferredCity(getContext(), null); - locationListAdapter.resetSelection(); - } - setVpnButtonState(); + private void initAutoSelectionButton() { + autoSelectionButton = getActivity().findViewById(R.id.automatic_gateway_selection_btn); + autoSelectionButton.setOnClickListener(v -> { + startEipService(null); }); } - private void initVpnButton() { - vpnButton = getActivity().findViewById(R.id.vpn_button); - setVpnButtonState(); - vpnButton.setOnClickListener(v -> { + private void initCurrentLocationInfoPanel() { + currentLocationDescription = getActivity().findViewById(R.id.current_location_description); + currentLocation = getActivity().findViewById(R.id.current_location); + setLocationDescription(EipStatus.getInstance(), PreferenceHelper.getPreferredCity(getContext())); + } + + private void setLocationDescription(EipStatus eipStatus, String preferredCity) { + if (eipStatus.isConnected()) { + currentLocationDescription.setText(preferredCity == null ? + R.string.gateway_selection_automatic_location : + R.string.gateway_selection_manual_location); + currentLocation.setText(VpnStatus.getLastConnectedVpnName()); + currentLocation.setVisibility(VISIBLE); + } else if (preferredCity == null) { + currentLocationDescription.setText(R.string.gateway_selection_automatic_not_connected); + currentLocation.setVisibility(INVISIBLE); + } else { + currentLocationDescription.setText(R.string.gateway_selection_manual_not_connected); + currentLocation.setText(preferredCity); + currentLocation.setVisibility(VISIBLE); + } + } + + protected void startEipService(String preferredCity) { + new Thread(() -> { + PreferenceHelper.setPreferredCity(getContext(), preferredCity); EipCommand.startVPN(getContext(), false); 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 setVpnButtonState() { - if (eipStatus.isDisconnected()) { - vpnButton.setText(R.string.vpn_button_turn_on); - } else { - vpnButton.setText(R.string.reconnect); - } - vpnButton.setEnabled( - (locationListAdapter.selectedLocation != null && locationListAdapter.selectedLocation.selected) || - autoSelectionSwitch.isChecked()); + }).start(); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (USE_BRIDGES.equals(key)) { locationListAdapter.updateData(gatewaysManager.getGatewayLocations()); - setVpnButtonState(); - } else if (PREFERRED_CITY.equals(key)) { - setVpnButtonState(); } } + @Override + public void onLocationSelected(String name) { + startEipService(name); + } + @Override public void update(Observable o, Object arg) { if (o instanceof EipStatus) { - eipStatus = (EipStatus) o; Activity activity = getActivity(); if (activity != null) { - activity.runOnUiThread(this::setVpnButtonState); + activity.runOnUiThread(() -> setLocationDescription((EipStatus) o, PreferenceHelper.getPreferredCity(getContext()))); } } - } + static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); private List values; - private Location selectedLocation = null; + private final WeakReference callback; static class ViewHolder extends RecyclerView.ViewHolder { public AppCompatTextView locationLabel; public LocationIndicator locationIndicator; - public AppCompatImageView checkedIcon; public View layout; public ViewHolder(View v) { super(v); layout = v; - locationLabel = (AppCompatTextView) v.findViewById(R.id.location); - locationIndicator = (LocationIndicator) v.findViewById(R.id.quality); - checkedIcon = (AppCompatImageView) v.findViewById(R.id.checked_icon); + locationLabel = v.findViewById(R.id.location); + locationIndicator = v.findViewById(R.id.quality); } } @@ -213,20 +213,14 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen notifyItemRemoved(position); } - public void resetSelection() { - if (selectedLocation != null) { - selectedLocation.selected = false; - notifyDataSetChanged(); - } - } - public void updateData(List data) { values = data; notifyDataSetChanged(); } - public LocationListAdapter(List data) { + public LocationListAdapter(List data, LocationListSelectionListener selectionListener) { values = data; + callback = new WeakReference<>(selectionListener); } @NonNull @@ -246,42 +240,12 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen holder.locationLabel.setText(location.name); holder.layout.setOnClickListener(v -> { Log.d(TAG, "view at position clicked: " + position); - if (selectedLocation == null) { - selectedLocation = location; - selectedLocation.selected = true; - } else if (selectedLocation.name.equals(location.name)){ - selectedLocation.selected = !selectedLocation.selected; - } else { - selectedLocation.selected = false; - selectedLocation = location; - selectedLocation.selected = true; + LocationListSelectionListener listener = callback.get(); + if (listener != null) { + listener.onLocationSelected(location.name); } - setPreferredCity(holder.layout.getContext(), selectedLocation.selected ? selectedLocation.name : null); - holder.checkedIcon.setVisibility(selectedLocation.selected ? VISIBLE : INVISIBLE); - notifyDataSetChanged(); }); - Drawable checkIcon = DrawableCompat.wrap(holder.layout.getContext().getResources().getDrawable(R.drawable.ic_check_bold)).mutate(); - DrawableCompat.setTint(checkIcon, ContextCompat.getColor(holder.layout.getContext(), R.color.colorSuccess)); - holder.checkedIcon.setImageDrawable(checkIcon); - holder.checkedIcon.setVisibility(location.selected ? VISIBLE : INVISIBLE); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); - if (location.selected) { - selectedLocation = location; - } - } - - public String getQualityString(double quality) { - if (quality == 0) { - return ""; - } else if (quality < 0.25) { - return "BAD"; - } else if (quality < 0.6) { - return "AVERAGE"; - } else if (quality < 0.8){ - return "GOOD"; - } else { - return "EXCELLENT"; - } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java index 86f8471c..da48effc 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java @@ -124,8 +124,10 @@ public class MainActivityErrorDialog extends DialogFragment { builder.setNegativeButton(R.string.cancel, (dialog, id) -> {}); if (getPreferredCity(applicationContext) != null) { builder.setPositiveButton(R.string.warning_option_try_best, (dialog, which) -> { - setPreferredCity(applicationContext, null); - EipCommand.startVPN(applicationContext, false); + new Thread(() -> { + setPreferredCity(applicationContext, null); + EipCommand.startVPN(applicationContext, false); + }).start(); }); } else if (provider.supportsPluggableTransports()) { if (getUseBridges(applicationContext)) { 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 a13692a5..1f4d0b17 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 @@ -425,7 +425,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen } manualGatewaySelection = drawerView.findViewById(R.id.manualGatewaySelection); String preferredGateway = getPreferredCity(getContext()); - String subtitle = preferredGateway != null ? preferredGateway : getString(R.string.gateway_selection_best_location); + String subtitle = preferredGateway != null ? preferredGateway : getString(R.string.gateway_selection_recommended_location); manualGatewaySelection.setSubtitle(subtitle); boolean show = ProviderObservable.getInstance().getCurrentProvider().hasGatewaysInDifferentLocations(); manualGatewaySelection.setVisibility(show ? VISIBLE : GONE); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index ae7818ba..8e032d18 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -6,13 +6,11 @@ public class Location { @NonNull public String name; public double averageLoad; public int numberOfGateways; - public boolean selected; - public Location(@NonNull String name, double averageLoad, int numberOfGateways, boolean selected) { + public Location(@NonNull String name, double averageLoad, int numberOfGateways) { this.name = name; this.averageLoad = averageLoad; this.numberOfGateways = numberOfGateways; - this.selected = selected; } @Override @@ -24,7 +22,6 @@ public class Location { if (Double.compare(location.averageLoad, averageLoad) != 0) return false; if (numberOfGateways != location.numberOfGateways) return false; - if (selected != location.selected) return false; return name.equals(location.name); } @@ -36,7 +33,6 @@ public class Location { temp = Double.doubleToLongBits(averageLoad); result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + numberOfGateways; - result = 31 * result + (selected ? 1 : 0); return result; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index 06fb25e9..93284968 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -3,6 +3,7 @@ package se.leap.bitmaskclient.base.utils; import android.content.Context; import android.content.SharedPreferences; import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; import org.json.JSONException; import org.json.JSONObject; @@ -229,8 +230,9 @@ public class PreferenceHelper { return getString(context, PREFERRED_CITY, null); } + @WorkerThread public static void setPreferredCity(Context context, String city) { - putString(context, PREFERRED_CITY, city); + putStringSync(context, PREFERRED_CITY, city); } public static JSONObject getEipDefinitionFromPreferences(SharedPreferences preferences) { @@ -277,6 +279,12 @@ public class PreferenceHelper { return preferences.getString(key, defValue); } + @WorkerThread + public static void putStringSync(Context context, String key, String value) { + SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().putString(key, value).commit(); + } + public static void putString(Context context, String key, String value) { SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); preferences.edit().putString(key, value).apply(); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 24e9c323..0819e9b6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -93,10 +93,10 @@ public class GatewaysManager { private static final String TAG = GatewaysManager.class.getSimpleName(); - private Context context; - private LinkedHashMap gateways = new LinkedHashMap<>(); - private Type listType = new TypeToken>() {}.getType(); - private ArrayList presortedList = new ArrayList<>(); + private final Context context; + private final LinkedHashMap gateways = new LinkedHashMap<>(); + private final Type listType = new TypeToken>() {}.getType(); + private final ArrayList presortedList = new ArrayList<>(); public GatewaysManager(Context context) { this.context = context; @@ -128,24 +128,30 @@ public class GatewaysManager { int n = 0; Gateway gateway; while ((gateway = select(n, null)) != null) { + String name = gateway.getName(); + if (name == null) { + Log.e(TAG, "Gateway without location name found. This should never happen. Provider misconfigured?"); + continue; + } + if (!locationNames.containsKey(gateway.getName())) { locationNames.put(gateway.getName(), locations.size()); // fake values for now Random rand = new Random(); double averageLoad = rand.nextDouble(); //location.averageLoad; - + Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + "): " + averageLoad); Location location = new Location( gateway.getName(), averageLoad /*gateway.getFullness()*/, - 1, - gateway.getName().equals(selectedCity)); + 1); locations.add(location); } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); location.averageLoad = (location.numberOfGateways * location.averageLoad + gateway.getFullness()) / (location.numberOfGateways + 1); + Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + "): " + location.averageLoad); location.numberOfGateways += 1; locations.set(index, location); } -- cgit v1.2.3 From 84d604de74d46c9d29d8d8ae20467c0320d2ffb3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 30 Jul 2021 18:22:12 +0200 Subject: show bridges icon in gateway selector for locations supporting them --- .../base/fragments/GatewaySelectionFragment.java | 25 +++++--------------- .../leap/bitmaskclient/base/models/Location.java | 27 ++++++++++++++++++++-- .../java/se/leap/bitmaskclient/eip/Gateway.java | 4 ++++ .../se/leap/bitmaskclient/eip/GatewaySelector.java | 10 ++++++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 26 +++++++++++++-------- 5 files changed, 62 insertions(+), 30 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index ee4aea74..450cba4d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -18,7 +18,6 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Activity; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -28,6 +27,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; @@ -39,6 +39,7 @@ import java.util.Observable; import java.util.Observer; import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; @@ -48,18 +49,15 @@ import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; -import static android.content.Context.MODE_PRIVATE; import static android.view.View.INVISIBLE; 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; interface LocationListSelectionListener { void onLocationSelected(String name); } -public class GatewaySelectionFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer, LocationListSelectionListener { +public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener { private static final String TAG = GatewaySelectionFragment.class.getSimpleName(); @@ -70,7 +68,6 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen private AppCompatTextView currentLocation; private AppCompatButton autoSelectionButton; private GatewaysManager gatewaysManager; - private SharedPreferences preferences; private EipStatus eipStatus; public GatewaySelectionFragment() { @@ -81,7 +78,6 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gatewaysManager = new GatewaysManager(getContext()); - preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); eipStatus = EipStatus.getInstance(); } @@ -98,19 +94,14 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen initRecyclerView(); initAutoSelectionButton(); initCurrentLocationInfoPanel(); - eipStatus.addObserver(this); - preferences.registerOnSharedPreferenceChangeListener(this); } @Override public void onDestroyView() { super.onDestroyView(); - preferences.unregisterOnSharedPreferenceChangeListener(this); eipStatus.deleteObserver(this); } - - private void initRecyclerView() { recyclerView = getActivity().findViewById(R.id.gatewaySelection_list); recyclerView.setHasFixedSize(true); @@ -162,13 +153,6 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen }).start(); } - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (USE_BRIDGES.equals(key)) { - locationListAdapter.updateData(gatewaysManager.getGatewayLocations()); - } - } - @Override public void onLocationSelected(String name) { startEipService(name); @@ -193,6 +177,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen static class ViewHolder extends RecyclerView.ViewHolder { public AppCompatTextView locationLabel; public LocationIndicator locationIndicator; + public AppCompatImageView bridgeView; public View layout; public ViewHolder(View v) { @@ -200,6 +185,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen layout = v; locationLabel = v.findViewById(R.id.location); locationIndicator = v.findViewById(R.id.quality); + bridgeView = v.findViewById(R.id.bridge_image); } } @@ -246,6 +232,7 @@ public class GatewaySelectionFragment extends Fragment implements SharedPreferen } }); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); + holder.bridgeView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : View.GONE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index 8e032d18..3ec7d38c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -1,16 +1,37 @@ +/** + * Copyright (c) 2021 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package se.leap.bitmaskclient.base.models; import androidx.annotation.NonNull; +import java.util.HashSet; +import de.blinkt.openvpn.core.connection.Connection; public class Location { @NonNull public String name; + @NonNull public HashSet supportedTransports; public double averageLoad; public int numberOfGateways; - public Location(@NonNull String name, double averageLoad, int numberOfGateways) { + public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet supportedTransports) { this.name = name; this.averageLoad = averageLoad; this.numberOfGateways = numberOfGateways; + this.supportedTransports = supportedTransports; } @Override @@ -22,7 +43,8 @@ public class Location { if (Double.compare(location.averageLoad, averageLoad) != 0) return false; if (numberOfGateways != location.numberOfGateways) return false; - return name.equals(location.name); + if (!name.equals(location.name)) return false; + return supportedTransports.equals(location.supportedTransports); } @Override @@ -30,6 +52,7 @@ public class Location { int result; long temp; result = name.hashCode(); + result = 31 * result + supportedTransports.hashCode(); temp = Double.doubleToLongBits(averageLoad); result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + numberOfGateways; diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 78b33355..8a48684f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -195,6 +195,10 @@ public class Gateway { return vpnProfiles.get(transportType) != null; } + public HashSet getSupportedTransports() { + return new HashSet<>(vpnProfiles.keySet()); + } + public int getTimezone() { return timezone; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java index 33fd3c21..a48cc6d5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java @@ -2,6 +2,8 @@ package se.leap.bitmaskclient.eip; import android.util.Log; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -18,7 +20,15 @@ public class GatewaySelector { public GatewaySelector(List gateways) { this.gateways = gateways; this.offsets = calculateOffsets(); + } + public ArrayList getGatewaysSortedByDistance() { + ArrayList list = new ArrayList<>(); + int i = 0; + for (Collection gatewayCollection : offsets.values()) { + list.addAll(gatewayCollection); + } + return list; } public Gateway select() { diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 0819e9b6..0b2c2030 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -43,7 +43,6 @@ import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; @@ -121,13 +120,20 @@ public class GatewaysManager { return getGatewayFromTimezoneCalculation(nClosest, transportType, city); } + public ArrayList getSortedGateways() { + if (presortedList.size() > 0) { + return presortedList; + } else { + GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); + return gatewaySelector.getGatewaysSortedByDistance(); + } + } + public List getGatewayLocations() { - String selectedCity = PreferenceHelper.getPreferredCity(context); HashMap locationNames = new HashMap<>(); ArrayList locations = new ArrayList<>(); - int n = 0; - Gateway gateway; - while ((gateway = select(n, null)) != null) { + ArrayList gateways = getSortedGateways(); + for (Gateway gateway : gateways) { String name = gateway.getName(); if (name == null) { Log.e(TAG, "Gateway without location name found. This should never happen. Provider misconfigured?"); @@ -139,23 +145,25 @@ public class GatewaysManager { // fake values for now Random rand = new Random(); double averageLoad = rand.nextDouble(); //location.averageLoad; - Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + "): " + averageLoad); + Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + " - " + gateway.getHost()+ "): " + averageLoad); Location location = new Location( gateway.getName(), averageLoad /*gateway.getFullness()*/, - 1); + 1, + gateway.getSupportedTransports() + ); locations.add(location); } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); location.averageLoad = (location.numberOfGateways * location.averageLoad + gateway.getFullness()) / (location.numberOfGateways + 1); - Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + "): " + location.averageLoad); + Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + " - " + gateway.getHost()+ "): " + location.averageLoad); location.numberOfGateways += 1; + location.supportedTransports.addAll(gateway.getSupportedTransports()); locations.set(index, location); } - n++; } return locations; -- cgit v1.2.3 From d8b11c392a492ef05b1a454c298f5244a694553b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 30 Jul 2021 20:38:23 +0200 Subject: ask user to change location or disable bridges if manually selected location doesn't support bridges --- .../se/leap/bitmaskclient/base/MainActivity.java | 13 +++++++-- .../base/fragments/GatewaySelectionFragment.java | 32 ++++++++++++++++++---- .../base/fragments/MainActivityErrorDialog.java | 25 ++++++++++++++++- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 3 +- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 19 +++++++++++-- 5 files changed, 80 insertions(+), 12 deletions(-) (limited to 'app/src/main/java/se/leap') 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 18ac8b7c..54977f0a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -60,6 +60,7 @@ import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST; +import static se.leap.bitmaskclient.base.models.Constants.LOCATION; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; @@ -85,6 +86,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, public final static String ACTION_SHOW_VPN_FRAGMENT = "action_show_vpn_fragment"; public final static String ACTION_SHOW_LOG_FRAGMENT = "action_show_log_fragment"; + public final static String ACTION_SHOW_DIALOG_FRAGMENT = "action_show_dialog_fragment"; /** * Fragment managing the behaviors, interactions and presentation of the navigation drawer. @@ -152,6 +154,13 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, fragment = new LogFragment(); setActionBarTitle(R.string.log_fragment_title); break; + case ACTION_SHOW_DIALOG_FRAGMENT: + if (intent.hasExtra(EIP.ERRORID)) { + String errorId = intent.getStringExtra(EIP.ERRORID); + String error = intent.getStringExtra(EIP.ERRORS); + String args = intent.getStringExtra(LOCATION); + showMainActivityErrorDialog(error, EIP.EIPErrors.valueOf(errorId), args); + } default: break; } @@ -324,12 +333,12 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, /** * Shows an error dialog */ - public void showMainActivityErrorDialog(String reasonToFail, EIP.EIPErrors error) { + public void showMainActivityErrorDialog(String reasonToFail, EIP.EIPErrors error, String... args) { try { FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced( this.getSupportFragmentManager()).removePreviousFragment( MainActivityErrorDialog.TAG); - DialogFragment newFragment = MainActivityErrorDialog.newInstance(provider, reasonToFail, error); + DialogFragment newFragment = MainActivityErrorDialog.newInstance(provider, reasonToFail, error, args); newFragment.show(fragmentTransaction, MainActivityErrorDialog.TAG); } catch (IllegalStateException | NullPointerException e) { e.printStackTrace(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 450cba4d..2dcb0ec9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -45,16 +45,21 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.LocationIndicator; +import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_DIALOG_FRAGMENT; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; +import static se.leap.bitmaskclient.base.models.Constants.LOCATION; interface LocationListSelectionListener { - void onLocationSelected(String name); + void onLocationSelected(Location location); } public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener { @@ -154,8 +159,24 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } @Override - public void onLocationSelected(String name) { - startEipService(name); + public void onLocationSelected(Location location) { + String name = location.name; + Connection.TransportType selectedTransport = PreferenceHelper.getUsePluggableTransports(getContext()) ? OBFS4 : OPENVPN; + if (location.supportedTransports.contains(selectedTransport)) { + startEipService(name); + } else { + askToChangeTransport(name); + } + } + + private void askToChangeTransport(String name) { + Intent intent = new Intent(getContext(), MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.setAction(ACTION_SHOW_DIALOG_FRAGMENT); + intent.putExtra(EIP.ERRORID, EIP.EIPErrors.TRANSPORT_NOT_SUPPORTED.toString()); + intent.putExtra(EIP.ERRORS, getString(R.string.warning_bridges_not_supported, name)); + intent.putExtra(LOCATION, name); + startActivity(intent); } @Override @@ -168,7 +189,6 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } } - static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); private List values; @@ -228,11 +248,11 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca Log.d(TAG, "view at position clicked: " + position); LocationListSelectionListener listener = callback.get(); if (listener != null) { - listener.onLocationSelected(location.name); + listener.onLocationSelected(location); } }); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); - holder.bridgeView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : View.GONE); + holder.bridgeView.setVisibility(location.supportedTransports.contains(OBFS4) ? VISIBLE : View.GONE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java index da48effc..f7805002 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java @@ -18,6 +18,8 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -27,11 +29,15 @@ import androidx.appcompat.app.AlertDialog; import org.json.JSONObject; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.MainActivity; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_DIALOG_FRAGMENT; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; @@ -56,6 +62,7 @@ public class MainActivityErrorDialog extends DialogFragment { final private static String KEY_REASON_TO_FAIL = "key reason to fail"; final private static String KEY_PROVIDER = "key provider"; private String reasonToFail; + private String[] args; private EIP.EIPErrors downloadError = UNKNOWN; private Provider provider; @@ -70,11 +77,12 @@ public class MainActivityErrorDialog extends DialogFragment { /** * @return a new instance of this DialogFragment. */ - public static DialogFragment newInstance(Provider provider, String reasonToFail, EIP.EIPErrors error) { + public static DialogFragment newInstance(Provider provider, String reasonToFail, EIP.EIPErrors error, String... args) { MainActivityErrorDialog dialogFragment = new MainActivityErrorDialog(); dialogFragment.reasonToFail = reasonToFail; dialogFragment.provider = provider; dialogFragment.downloadError = error; + dialogFragment.args = args; return dialogFragment; } @@ -150,6 +158,21 @@ public class MainActivityErrorDialog extends DialogFragment { case ERROR_VPN_PREPARE: builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { }); break; + case TRANSPORT_NOT_SUPPORTED: + + builder.setPositiveButton(R.string.option_different_location, (dialog, which) -> { }); + builder.setNegativeButton(R.string.option_disable_bridges, (dialog, which) -> { + PreferenceHelper.useBridges(applicationContext, false); + PreferenceHelper.setPreferredCity(applicationContext, args[0]); + + EipCommand.startVPN(applicationContext, false); + // at this point the gateway selection dialog is shown, let's switch to the main view + 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); + }); + break; default: break; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index dd9054f1..a7e08bd7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -127,7 +127,8 @@ public final class EIP extends JobIntentService implements Observer { ERROR_INVALID_VPN_CERTIFICATE, NO_MORE_GATEWAYS, ERROR_VPN_PREPARE, - ERROR_INVALID_PROFILE + ERROR_INVALID_PROFILE, + TRANSPORT_NOT_SUPPORTED, } /** diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 0b2c2030..dbb2a914 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -96,6 +96,7 @@ public class GatewaysManager { private final LinkedHashMap gateways = new LinkedHashMap<>(); private final Type listType = new TypeToken>() {}.getType(); private final ArrayList presortedList = new ArrayList<>(); + private ArrayList locations = new ArrayList<>(); public GatewaysManager(Context context) { this.context = context; @@ -130,6 +131,10 @@ public class GatewaysManager { } public List getGatewayLocations() { + if (locations.size() > 0) { + return locations; + } + HashMap locationNames = new HashMap<>(); ArrayList locations = new ArrayList<>(); ArrayList gateways = getSortedGateways(); @@ -166,16 +171,26 @@ public class GatewaysManager { } } + this.locations = locations; return locations; } - public Load getLoadForLocation(@Nullable String name) { + @Nullable + public Location getLocation(String name) { List locations = getGatewayLocations(); for (Location location : locations) { if (location.name.equals(name)) { - return Load.getLoadByValue(location.averageLoad); + return location; } } + return null; + } + + public Load getLoadForLocation(@Nullable String name) { + Location location = getLocation(name); + if (location != null) { + return Load.getLoadByValue(location.averageLoad); + } // location not found return Load.UNKNOWN; -- cgit v1.2.3 From 546b823b0c1694657e6b63f23d8b72015b00d282 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 16:34:09 +0200 Subject: adapt EIP main screen and strings to simply secure proposals --- .../bitmaskclient/base/fragments/EipFragment.java | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index af34b7a5..e9402468 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -39,6 +39,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -50,6 +51,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; +import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; @@ -84,6 +86,7 @@ import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; 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.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx; import static se.leap.bitmaskclient.eip.EipSetupObserver.gatewayOrder; import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway; @@ -109,6 +112,12 @@ public class EipFragment extends Fragment implements Observer { @BindView(R.id.gateway_location_button) LocationButton locationButton; + @BindView(R.id.main_description) + AppCompatTextView mainDescription; + + @BindView(R.id.sub_description) + AppCompatTextView subDescription; + private Unbinder unbinder; private EipStatus eipStatus; @@ -408,21 +417,20 @@ public class EipFragment extends Fragment implements Observer { return; } - //Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); - - + Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); if (eipStatus.isConnecting() ) { setMainButtonEnabled(true); showConnectingLayout(activity); if (eipStatus.isReconnecting()) { - locationButton.setText(getString(R.string.reconnecting)); + subDescription.setText(getString(R.string.reconnecting)); } else { - locationButton.setText(getString(R.string.finding_best_connection)); + subDescription.setText(R.string.connection_not_connected); } + locationButton.setText(getString(R.string.finding_best_connection)); + mainDescription.setText(R.string.eip_state_insecure); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); - } else if (eipStatus.isConnected() ) { - locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); + } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_connected); vpnStateImage.stopProgress(false); @@ -430,23 +438,34 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.setVisibility(VISIBLE); colorBackground(); + mainDescription.setText(R.string.eip_state_connected); + subDescription.setText(getPreferredCity(getContext()) == null ? + R.string.eip_state_connected_recommended : + R.string.eip_state_connected_manual); } else if(isOpenVpnRunningWithoutNetwork()){ - locationButton.setText(activity.getString(R.string.vpn_button_turn_off)); + Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); vpnStateImage.stopProgress(false); locationButton.setVisibility(VISIBLE); + locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); setVpnRouteText(); colorBackgroundALittle(); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.eip_state_no_network); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { showConnectingLayout(activity); // showRetryToast(activity); locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.reconnecting); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); showDisconnectingLayout(activity); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); vpnStateImage.setStateIcon(R.drawable.vpn_blocking); @@ -455,6 +474,8 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + mainDescription.setText(R.string.eip_state_connected); + subDescription.setText(R.string.eip_state_blocking); } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); @@ -463,6 +484,8 @@ public class EipFragment extends Fragment implements Observer { greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); locationButton.setVisibility(GONE); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(R.string.connection_not_connected); } } -- cgit v1.2.3 From d7d890edeee2d6fc6cb6cc08fe29b5089ad7513b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:32:01 +0200 Subject: initial implementation of classic on-off push button --- .../bitmaskclient/base/fragments/EipFragment.java | 27 +++++++--------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index e9402468..3650804f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -27,7 +27,6 @@ import android.graphics.ColorMatrixColorFilter; import android.os.Bundle; import android.os.IBinder; import android.os.Vibrator; -import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -51,7 +50,6 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; -import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; @@ -420,7 +418,7 @@ public class EipFragment extends Fragment implements Observer { Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); if (eipStatus.isConnecting() ) { setMainButtonEnabled(true); - showConnectingLayout(activity); + showConnectionTransitionLayout(true); if (eipStatus.isReconnecting()) { subDescription.setText(getString(R.string.reconnecting)); } else { @@ -432,7 +430,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setLocationLoad(UNKNOWN); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_connected); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); vpnStateImage.stopProgress(false); locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); @@ -445,16 +443,15 @@ public class EipFragment extends Fragment implements Observer { } else if(isOpenVpnRunningWithoutNetwork()){ Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); vpnStateImage.stopProgress(false); locationButton.setVisibility(VISIBLE); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); - setVpnRouteText(); colorBackgroundALittle(); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.eip_state_no_network); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { - showConnectingLayout(activity); + showConnectionTransitionLayout(true); // showRetryToast(activity); locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); @@ -463,12 +460,12 @@ public class EipFragment extends Fragment implements Observer { subDescription.setText(R.string.reconnecting); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); - showDisconnectingLayout(activity); + showConnectionTransitionLayout(false); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_blocking); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_primary_color); vpnStateImage.stopProgress(false); colorBackgroundALittle(); locationButton.setText(getString(R.string.finding_best_connection)); @@ -518,16 +515,8 @@ public class EipFragment extends Fragment implements Observer { showToast(activity, message, true ); } - private void showConnectingLayout(Context activity) { - showConnectionTransitionLayout(activity, true); - } - - private void showDisconnectingLayout(Activity activity) { - showConnectionTransitionLayout(activity, false); - } - - private void showConnectionTransitionLayout(Context activity, boolean isConnecting) { - vpnStateImage.setStateIcon(R.drawable.vpn_connecting); + private void showConnectionTransitionLayout(boolean isConnecting) { + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_connecting); vpnStateImage.showProgress(); if (isConnecting) { colorBackgroundALittle(); -- cgit v1.2.3 From 6c09f3663ad1acce76a9e91af31ad3a7bb87045b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:33:39 +0200 Subject: avoid layout jumping --- .../main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 3650804f..7456fcc9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -70,7 +70,7 @@ import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivit import se.leap.bitmaskclient.providersetup.activities.LoginActivity; import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; -import static android.view.View.GONE; +import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; @@ -480,7 +480,7 @@ public class EipFragment extends Fragment implements Observer { vpnStateImage.stopProgress(false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); - locationButton.setVisibility(GONE); + locationButton.setVisibility(INVISIBLE); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } -- cgit v1.2.3 From 287d402adea49f3938c26304877a1a32b67f1dfe Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:34:08 +0200 Subject: add missing vpn button state --- app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 7456fcc9..2f50d258 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -476,7 +476,7 @@ public class EipFragment extends Fragment implements Observer { } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); - vpnStateImage.setStateIcon(R.drawable.vpn_disconnected); + vpnStateImage.setStateIcon(R.drawable.ic_btn_on_disabled); vpnStateImage.stopProgress(false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); -- cgit v1.2.3 From 9f5faf390d23a81cc07fe20b32e191631d192280 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:34:26 +0200 Subject: cleanup --- .../java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 9 --------- 1 file changed, 9 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 2f50d258..ef16d085 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -587,15 +587,6 @@ public class EipFragment extends Fragment implements Observer { } } - private void setVpnRouteText() { - String vpnRouteString = provider.getName(); - String profileName = VpnStatus.getLastConnectedVpnName(); - if (!TextUtils.isEmpty(profileName)) { - vpnRouteString += " (" + profileName + ")"; - } - // vpnRoute.setText(vpnRouteString); - } - private class EipFragmentServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName className, -- cgit v1.2.3 From 7b9a2f0a807fb6e5782888f444efb1142da1f20b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 18:48:06 +0200 Subject: add missing eip status observer registration in GatewaySelectionFragment --- .../se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 2dcb0ec9..c0b9d2d4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -84,6 +84,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca super.onCreate(savedInstanceState); gatewaysManager = new GatewaysManager(getContext()); eipStatus = EipStatus.getInstance(); + eipStatus.addObserver(this); } @Override -- cgit v1.2.3 From edb4b900ab1d1113492e98c28f12133c97721818 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 31 Jul 2021 19:30:54 +0200 Subject: Add BuildConfig to disable color filtering of the main screen background, if VPN is turned off. Make EipFragment's text colors customizable --- .../bitmaskclient/base/fragments/EipFragment.java | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index ef16d085..d8be1cc5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -54,6 +54,7 @@ import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; 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; @@ -552,21 +553,27 @@ public class EipFragment extends Fragment implements Observer { } private void greyscaleBackground() { - ColorMatrix matrix = new ColorMatrix(); - matrix.setSaturation(0); - ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); - background.setColorFilter(cf); - background.setImageAlpha(255); + if (BuildConfig.use_color_filter) { + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0); + ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); + background.setColorFilter(cf); + background.setImageAlpha(255); + } } private void colorBackgroundALittle() { - background.setColorFilter(null); - background.setImageAlpha(144); + if (BuildConfig.use_color_filter) { + background.setColorFilter(null); + background.setImageAlpha(144); + } } private void colorBackground() { - background.setColorFilter(null); - background.setImageAlpha(210); + if (BuildConfig.use_color_filter) { + background.setColorFilter(null); + background.setImageAlpha(210); + } } private void updateInvalidVpnCertificate() { -- cgit v1.2.3 From f3e23d06d8bee4c4212e606621b92a50dd7034ae Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 14 Nov 2021 20:02:16 +0100 Subject: fix preference renaming --- .../se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index c0b9d2d4..4a431dff 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -162,7 +162,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca @Override public void onLocationSelected(Location location) { String name = location.name; - Connection.TransportType selectedTransport = PreferenceHelper.getUsePluggableTransports(getContext()) ? OBFS4 : OPENVPN; + Connection.TransportType selectedTransport = PreferenceHelper.getUseBridges(getContext()) ? OBFS4 : OPENVPN; if (location.supportedTransports.contains(selectedTransport)) { startEipService(name); } else { -- cgit v1.2.3 From 96a397b01da596204e3e9d1ff2dd2c176f76e5b3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 15 Nov 2021 20:42:58 +0100 Subject: improve location status indicator, adapt according to desktop --- .../base/views/LocationIndicator.java | 51 ++++++++++++++-------- 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java index f5e3dbe2..8245893d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationIndicator.java @@ -7,15 +7,21 @@ import android.view.View; import android.widget.LinearLayout; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.eip.GatewaysManager; +import static androidx.core.content.ContextCompat.getColor; + public class LocationIndicator extends LinearLayout { private View level1; + private View level1_2; private View level2; + private View level2_2; private View level3; + private View level3_2; public LocationIndicator(Context context) { super(context); @@ -39,37 +45,46 @@ public class LocationIndicator extends LinearLayout { .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rootview = inflater.inflate(R.layout.v_location_status_indicator, this, true); level1 = rootview.findViewById(R.id.level1); + level1_2 = rootview.findViewById(R.id.level1_2); level2 = rootview.findViewById(R.id.level2); + level2_2 = rootview.findViewById(R.id.level2_2); level3 = rootview.findViewById(R.id.level3); + level3_2 = rootview.findViewById(R.id.level3_2); } public void setLoad(GatewaysManager.Load load) { switch (load) { case GOOD: - level1.setBackgroundColor(getResources().getColor(R.color.green200)); - level2.setBackgroundColor(getResources().getColor(R.color.green200)); - level3.setBackgroundColor(getResources().getColor(R.color.green200)); - level1.setVisibility(VISIBLE); - level2.setVisibility(VISIBLE); - level3.setVisibility(VISIBLE); + level1.setBackgroundColor(getColor(getContext(), R.color.green200)); + level1_2.setBackgroundColor(getColor(getContext(), R.color.green200)); + level2.setBackgroundColor(getColor(getContext(), R.color.green200)); + level2_2.setBackgroundColor(getColor(getContext(), R.color.green200)); + level3.setBackgroundColor(getColor(getContext(), R.color.green200)); + level3_2.setBackgroundColor(getColor(getContext(), R.color.green200)); break; case AVERAGE: - level1.setBackgroundColor(getResources().getColor(R.color.yellow200)); - level2.setBackgroundColor(getResources().getColor(R.color.yellow200)); - level1.setVisibility(VISIBLE); - level2.setVisibility(VISIBLE); - level3.setVisibility(INVISIBLE); + level1.setBackgroundColor(getColor(getContext(), R.color.yellow200)); + level1_2.setBackgroundColor(getColor(getContext(), R.color.yellow200)); + level2.setBackgroundColor(getColor(getContext(), R.color.yellow200)); + level2_2.setBackgroundColor(getColor(getContext(), R.color.yellow200)); + level3.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level3_2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); break; case CRITICAL: - level1.setBackgroundColor(getResources().getColor(R.color.red200)); - level1.setVisibility(VISIBLE); - level2.setVisibility(INVISIBLE); - level3.setVisibility(INVISIBLE); + level1.setBackgroundColor(getColor(getContext(), R.color.red200)); + level1_2.setBackgroundColor(getColor(getContext(), R.color.red200)); + level2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level2_2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level3.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level3_2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); break; default: - level1.setVisibility(INVISIBLE); - level2.setVisibility(INVISIBLE); - level3.setVisibility(INVISIBLE); + level1.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level1_2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level2_2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level3.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent)); + level3_2.setBackgroundColor(getColor(getContext(), R.color.black800_high_transparent));; break; } } -- cgit v1.2.3 From 7436008db89d4ddf4f918fc220dc813b3289d0d7 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 16 Nov 2021 00:12:38 +0100 Subject: add bridge indicator to bottom panel --- .../se/leap/bitmaskclient/base/fragments/EipFragment.java | 6 ++++++ .../java/se/leap/bitmaskclient/base/views/LocationButton.java | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 18e97411..b2e91fd5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -426,11 +426,13 @@ public class EipFragment extends Fragment implements Observer { mainDescription.setText(R.string.eip_state_insecure); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + locationButton.showBridgeIndicator(false); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); mainButton.updateState(true, false, false); locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); + locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); locationButton.setVisibility(VISIBLE); colorBackground(); mainDescription.setText(R.string.eip_state_connected); @@ -443,6 +445,7 @@ public class EipFragment extends Fragment implements Observer { mainButton.updateState(true, false, true); locationButton.setVisibility(VISIBLE); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); + locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); colorBackgroundALittle(); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.eip_state_no_network); @@ -452,6 +455,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + locationButton.showBridgeIndicator(false); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.reconnecting); } else if (eipStatus.isDisconnecting()) { @@ -466,6 +470,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); + locationButton.showBridgeIndicator(false); mainDescription.setText(R.string.eip_state_connected); subDescription.setText(R.string.eip_state_blocking); } else { @@ -474,6 +479,7 @@ public class EipFragment extends Fragment implements Observer { mainButton.updateState(false, false, false); greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); + locationButton.showBridgeIndicator(false); locationButton.setVisibility(INVISIBLE); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java index 1d7f0d18..11ea198c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java @@ -4,18 +4,22 @@ import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; +import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.LinearLayoutCompat; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.eip.GatewaysManager; -public class LocationButton extends LinearLayoutCompat { +public class LocationButton extends RelativeLayout { private LocationIndicator locationIndicator; private AppCompatTextView textView; + private AppCompatImageView bridgeView; + public LocationButton(@NonNull Context context) { super(context); initLayout(context); @@ -32,6 +36,7 @@ public class LocationButton extends LinearLayoutCompat { View rootview = inflater.inflate(R.layout.v_location_button, this, true); locationIndicator = rootview.findViewById(R.id.load_indicator); textView = rootview.findViewById(R.id.text_location); + bridgeView = rootview.findViewById(R.id.bridge_icn); } public void setLocationLoad(GatewaysManager.Load load) { @@ -41,4 +46,8 @@ public class LocationButton extends LinearLayoutCompat { public void setText(CharSequence text) { textView.setText(text); } + + public void showBridgeIndicator(boolean show) { + bridgeView.setVisibility(show ? VISIBLE : GONE); + } } -- cgit v1.2.3 From ca00d7454ad412bc3cf54159a87caa0ffb349502 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 16 Nov 2021 03:51:55 +0100 Subject: replace all TextViews with AppCompatTextViews --- .../base/fragments/AboutFragment.java | 6 +++--- .../bitmaskclient/base/fragments/EipFragment.java | 2 +- .../base/fragments/ExcludeAppsFragment.java | 11 +++++----- .../bitmaskclient/base/fragments/LogFragment.java | 25 +++++++++++----------- .../base/fragments/NavigationDrawerFragment.java | 7 +++--- .../base/views/IconCheckboxEntry.java | 4 ++-- .../bitmaskclient/base/views/IconSwitchEntry.java | 5 +++-- .../bitmaskclient/base/views/IconTextEntry.java | 15 +++++++------ .../providersetup/ProviderRenderer.java | 7 +++--- .../activities/AbstractProviderDetailActivity.java | 2 +- 10 files changed, 45 insertions(+), 39 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java index c269c872..dbdd008a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java @@ -6,8 +6,8 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; +import androidx.appcompat.widget.AppCompatTextView; import androidx.fragment.app.Fragment; import butterknife.BindView; @@ -25,10 +25,10 @@ public class AboutFragment extends Fragment { private Unbinder unbinder; @BindView(R.id.version) - TextView versionTextView; + AppCompatTextView versionTextView; @BindView(R.id.terms_of_service) - TextView termsOfService; + AppCompatTextView termsOfService; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index b2e91fd5..11cab7e5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -491,7 +491,7 @@ public class EipFragment extends Fragment implements Observer { View layout = inflater.inflate(R.layout.custom_toast, activity.findViewById(R.id.custom_toast_container)); - TextView text = layout.findViewById(R.id.text); + AppCompatTextView text = layout.findViewById(R.id.text); text.setText(message); Vibrator v = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); 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 18000171..db5057cc 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 @@ -11,7 +11,6 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; -import androidx.fragment.app.Fragment; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; @@ -27,7 +26,9 @@ import android.widget.Filterable; import android.widget.ImageView; import android.widget.ListView; import android.widget.SearchView; -import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatTextView; +import androidx.fragment.app.Fragment; import java.util.Collections; import java.util.List; @@ -77,10 +78,10 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC static class AppViewHolder { public ApplicationInfo mInfo; public View rootView; - public TextView appName; + public AppCompatTextView appName; public ImageView appIcon; - //public TextView appSize; - //public TextView disabled; + //public AppCompatTextView appSize; + //public AppCompatTextView disabled; public CompoundButton checkBox; static public AppViewHolder createOrRecycle(LayoutInflater inflater, View convertView, ViewGroup parent) { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java index d788b9e6..a5a5e555 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java @@ -19,8 +19,6 @@ import android.os.Handler; import android.os.Handler.Callback; import android.os.Message; import android.preference.PreferenceManager; -import androidx.annotation.Nullable; -import androidx.fragment.app.ListFragment; import android.text.SpannableString; import android.text.format.DateFormat; import android.view.LayoutInflater; @@ -37,9 +35,12 @@ import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RadioGroup; import android.widget.SeekBar; -import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.fragment.app.ListFragment; + import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; @@ -55,8 +56,8 @@ import de.blinkt.openvpn.core.Preferences; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.VpnStatus.LogListener; import de.blinkt.openvpn.core.VpnStatus.StateListener; -import se.leap.bitmaskclient.base.models.Constants; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.models.Constants; import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount; @@ -70,9 +71,9 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. private SeekBar mLogLevelSlider; private LinearLayout mOptionsLayout; private RadioGroup mTimeRadioGroup; - private TextView mUpStatus; - private TextView mDownStatus; - private TextView mConnectStatus; + private AppCompatTextView mUpStatus; + private AppCompatTextView mDownStatus; + private AppCompatTextView mConnectStatus; private boolean mShowOptionsLayout; private CheckBox mClearLogCheckBox; @@ -219,11 +220,11 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. @Override public View getView(int position, View convertView, ViewGroup parent) { - TextView v; + AppCompatTextView v; if (convertView == null) - v = new TextView(getActivity()); + v = new AppCompatTextView(getActivity()); else - v = (TextView) convertView; + v = (AppCompatTextView) convertView; LogItem le = currentLevelEntries.get(position); String msg = le.getString(getActivity()); @@ -380,7 +381,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. private LogWindowListAdapter ladapter; - private TextView mSpeedView; + private AppCompatTextView mSpeedView; @Override @@ -474,7 +475,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. int position, long id) { ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Log Entry", ((TextView) view).getText()); + ClipData clip = ClipData.newPlainText("Log Entry", ((AppCompatTextView) view).getText()); clipboard.setPrimaryClip(clip); Toast.makeText(getActivity(), R.string.copied_entry, Toast.LENGTH_SHORT).show(); return true; 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 1f4d0b17..020a48a4 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 @@ -27,6 +27,7 @@ import android.os.Bundle; import android.os.Handler; 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; @@ -380,7 +381,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen } private void initShowExperimentalHint() { - TextView textView = drawerLayout.findViewById(R.id.show_experimental_features); + 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()); @@ -388,12 +389,12 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen tethering.setVisibility(GONE); firewall.setVisibility(GONE); experimentalFeatureFooter.setVisibility(GONE); - ((TextView) v).setText(R.string.show_experimental); + ((AppCompatTextView) v).setText(R.string.show_experimental); } else { tethering.setVisibility(VISIBLE); firewall.setVisibility(VISIBLE); experimentalFeatureFooter.setVisibility(VISIBLE); - ((TextView) v).setText(R.string.hide_experimental); + ((AppCompatTextView) v).setText(R.string.hide_experimental); } PreferenceHelper.setShowExperimentalFeatures(getContext(), !shown); }); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java index 977056f7..0957712b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/IconCheckboxEntry.java @@ -7,10 +7,10 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; -import android.widget.TextView; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; @@ -23,7 +23,7 @@ import se.leap.bitmaskclient.base.fragments.TetheringDialog; public class IconCheckboxEntry extends LinearLayout { @BindView(android.R.id.text1) - TextView textView; + AppCompatTextView textView; @BindView(R.id.material_icon) AppCompatImageView iconView; 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 b6d72ab6..a499cdd1 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 @@ -24,6 +24,7 @@ import androidx.annotation.DrawableRes; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.SwitchCompat; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -36,8 +37,8 @@ import se.leap.bitmaskclient.R; public class IconSwitchEntry extends LinearLayout { - private TextView textView; - private TextView subtitleView; + private AppCompatTextView textView; + private AppCompatTextView subtitleView; private AppCompatImageView iconView; private SwitchCompat switchView; private CompoundButton.OnCheckedChangeListener checkedChangeListener; 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 6b9bd760..2d9525ed 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 @@ -4,25 +4,26 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import androidx.annotation.ColorRes; -import androidx.annotation.DrawableRes; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatTextView; import se.leap.bitmaskclient.R; public class IconTextEntry extends LinearLayout { - private TextView textView; + private AppCompatTextView textView; private ImageView iconView; - private TextView subtitleView; + private AppCompatTextView subtitleView; public IconTextEntry(Context context) { super(context); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java index 339199e0..8aba4941 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderRenderer.java @@ -4,7 +4,8 @@ import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatTextView; import com.pedrogomez.renderers.Renderer; @@ -20,9 +21,9 @@ public class ProviderRenderer extends Renderer { private final Context context; @BindView(R.id.provider_name) - TextView name; + AppCompatTextView name; @BindView(R.id.provider_domain) - TextView domain; + AppCompatTextView domain; public ProviderRenderer(Context context) { this.context = context; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java index ba84ed9a..66999580 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/AbstractProviderDetailActivity.java @@ -62,7 +62,7 @@ public abstract class AbstractProviderDetailActivity extends ConfigWizardBaseAct optionsList.toArray(new String[optionsList.size()]) )); options.setOnItemClickListener((parent, view, position, id) -> { - String text = ((TextView) view).getText().toString(); + String text = ((AppCompatTextView) view).getText().toString(); Intent intent; if (text.equals(getString(R.string.login_to_profile))) { Log.d(TAG, "login selected"); -- cgit v1.2.3 From 038da31d493e526c8c861caf0313f065e133cc36 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 19 Nov 2021 16:22:59 +0100 Subject: fix blocking vpn hint on eip fragment --- .../main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index b2e91fd5..eae84439 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -462,17 +462,15 @@ public class EipFragment extends Fragment implements Observer { setMainButtonEnabled(false); showConnectionTransitionLayout(false); mainDescription.setText(R.string.eip_state_insecure); - subDescription.setText(R.string.connection_not_connected); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); mainButton.updateState(true, false, true); colorBackgroundALittle(); locationButton.setText(getString(R.string.finding_best_connection)); - locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); mainDescription.setText(R.string.eip_state_connected); - subDescription.setText(R.string.eip_state_blocking); + subDescription.setText(getString(R.string.eip_state_blocking, getString(R.string.app_name))); } else { locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); setMainButtonEnabled(true); -- cgit v1.2.3 From d705c5cd224dedab5daadcaef0af4e2287f2bf74 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 19 Nov 2021 16:29:09 +0100 Subject: always show the location selector button, just as on Desktop --- .../main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 5 ----- 1 file changed, 5 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index eae84439..95d52628 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -424,7 +424,6 @@ public class EipFragment extends Fragment implements Observer { } locationButton.setText(getString(R.string.finding_best_connection)); mainDescription.setText(R.string.eip_state_insecure); - locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); } else if (eipStatus.isConnected()) { @@ -433,7 +432,6 @@ public class EipFragment extends Fragment implements Observer { locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); - locationButton.setVisibility(VISIBLE); colorBackground(); mainDescription.setText(R.string.eip_state_connected); subDescription.setText(getPreferredCity(getContext()) == null ? @@ -443,7 +441,6 @@ public class EipFragment extends Fragment implements Observer { Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); mainButton.updateState(true, false, true); - locationButton.setVisibility(VISIBLE); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); colorBackgroundALittle(); @@ -453,7 +450,6 @@ public class EipFragment extends Fragment implements Observer { showConnectionTransitionLayout(true); // showRetryToast(activity); locationButton.setText(getString(R.string.finding_best_connection)); - locationButton.setVisibility(VISIBLE); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); mainDescription.setText(R.string.eip_state_insecure); @@ -478,7 +474,6 @@ public class EipFragment extends Fragment implements Observer { greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); - locationButton.setVisibility(INVISIBLE); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } -- cgit v1.2.3 From bf9f3086aa8d0e9cf3a8969b7596cc395848eab9 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 19 Nov 2021 16:30:54 +0100 Subject: show connection secure if vpn is running, but no internet connection is available --- app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 95d52628..f1a5a914 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -444,7 +444,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); colorBackgroundALittle(); - mainDescription.setText(R.string.eip_state_insecure); + mainDescription.setText(R.string.eip_state_connected); subDescription.setText(R.string.eip_state_no_network); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { showConnectionTransitionLayout(true); -- cgit v1.2.3 From bdabe7aa19f4cf2a37a399a49b4d15f249486636 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 19 Nov 2021 16:32:02 +0100 Subject: make UI less noisy on (re-)connects --- .../main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index f1a5a914..58214a77 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -417,13 +417,9 @@ public class EipFragment extends Fragment implements Observer { if (eipStatus.isConnecting() ) { setMainButtonEnabled(true); showConnectionTransitionLayout(true); - if (eipStatus.isReconnecting()) { - subDescription.setText(getString(R.string.reconnecting)); - } else { - subDescription.setText(R.string.connection_not_connected); - } locationButton.setText(getString(R.string.finding_best_connection)); mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(null); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); } else if (eipStatus.isConnected()) { -- cgit v1.2.3 From 329800842ae9a1be97335f7de9c766b6ed728530 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 19 Nov 2021 16:39:50 +0100 Subject: show select location on location selector button if vpn is off --- app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 58214a77..983db3ec 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -470,6 +470,7 @@ public class EipFragment extends Fragment implements Observer { greyscaleBackground(); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); + locationButton.setText(getString(R.string.gateway_selection_title)); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } -- cgit v1.2.3 From 9cf45bbcc1e707525fecdac5e691adebf0c28cb5 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 20 Nov 2021 13:42:59 +0100 Subject: show lightning bold instead of text 'You're connected to the recommended location' --- .../leap/bitmaskclient/base/fragments/EipFragment.java | 17 +++++++++++------ .../leap/bitmaskclient/base/views/LocationButton.java | 7 ++++++- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 983db3ec..b065486a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -418,27 +418,29 @@ public class EipFragment extends Fragment implements Observer { setMainButtonEnabled(true); showConnectionTransitionLayout(true); locationButton.setText(getString(R.string.finding_best_connection)); - mainDescription.setText(R.string.eip_state_insecure); - subDescription.setText(null); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); + locationButton.showRecommendedIndicator(false); + mainDescription.setText(R.string.eip_state_insecure); + subDescription.setText(null); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); mainButton.updateState(true, false, false); locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); - colorBackground(); + locationButton.showRecommendedIndicator(getPreferredCity(getContext())== null); mainDescription.setText(R.string.eip_state_connected); - subDescription.setText(getPreferredCity(getContext()) == null ? - R.string.eip_state_connected_recommended : - R.string.eip_state_connected_manual); + subDescription.setText(null); + colorBackground(); } else if(isOpenVpnRunningWithoutNetwork()){ Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); mainButton.updateState(true, false, true); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); + locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); + locationButton.showRecommendedIndicator(getPreferredCity(getContext())== null); colorBackgroundALittle(); mainDescription.setText(R.string.eip_state_connected); subDescription.setText(R.string.eip_state_no_network); @@ -448,6 +450,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); + locationButton.showRecommendedIndicator(false); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.reconnecting); } else if (eipStatus.isDisconnecting()) { @@ -461,6 +464,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setText(getString(R.string.finding_best_connection)); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); + locationButton.showRecommendedIndicator(false); mainDescription.setText(R.string.eip_state_connected); subDescription.setText(getString(R.string.eip_state_blocking, getString(R.string.app_name))); } else { @@ -471,6 +475,7 @@ public class EipFragment extends Fragment implements Observer { locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); locationButton.setText(getString(R.string.gateway_selection_title)); + locationButton.showRecommendedIndicator(false); mainDescription.setText(R.string.eip_state_insecure); subDescription.setText(R.string.connection_not_connected); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java index 11ea198c..b2182d61 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java @@ -10,7 +10,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.LinearLayoutCompat; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.eip.GatewaysManager; @@ -19,6 +18,7 @@ public class LocationButton extends RelativeLayout { private LocationIndicator locationIndicator; private AppCompatTextView textView; private AppCompatImageView bridgeView; + private AppCompatImageView recommendedView; public LocationButton(@NonNull Context context) { super(context); @@ -37,6 +37,7 @@ public class LocationButton extends RelativeLayout { locationIndicator = rootview.findViewById(R.id.load_indicator); textView = rootview.findViewById(R.id.text_location); bridgeView = rootview.findViewById(R.id.bridge_icn); + recommendedView = rootview.findViewById(R.id.recommended_icn); } public void setLocationLoad(GatewaysManager.Load load) { @@ -50,4 +51,8 @@ public class LocationButton extends RelativeLayout { public void showBridgeIndicator(boolean show) { bridgeView.setVisibility(show ? VISIBLE : GONE); } + + public void showRecommendedIndicator(boolean show) { + recommendedView.setVisibility(show? VISIBLE : GONE ); + } } -- cgit v1.2.3 From e4cd4773651ef4080a2e8853c5e348e24153467d Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 20 Nov 2021 16:35:30 +0100 Subject: implement a selection indicator for location list --- .../base/fragments/GatewaySelectionFragment.java | 12 +++++++++++- .../java/se/leap/bitmaskclient/base/models/Location.java | 4 +++- .../main/java/se/leap/bitmaskclient/eip/GatewaysManager.java | 11 +++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 4a431dff..c98abd74 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -29,6 +29,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.view.LayoutInflaterCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -50,6 +51,7 @@ import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; +import static android.view.View.GONE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; @@ -199,6 +201,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca public AppCompatTextView locationLabel; public LocationIndicator locationIndicator; public AppCompatImageView bridgeView; + public AppCompatImageView selectedView; public View layout; public ViewHolder(View v) { @@ -207,6 +210,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca locationLabel = v.findViewById(R.id.location); locationIndicator = v.findViewById(R.id.quality); bridgeView = v.findViewById(R.id.bridge_image); + selectedView = v.findViewById(R.id.selected); } } @@ -249,11 +253,17 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca Log.d(TAG, "view at position clicked: " + position); LocationListSelectionListener listener = callback.get(); if (listener != null) { + for (Location l : values) { + l.selected = false; + } + location.selected = !location.selected; + notifyDataSetChanged(); listener.onLocationSelected(location); } }); holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); - holder.bridgeView.setVisibility(location.supportedTransports.contains(OBFS4) ? VISIBLE : View.GONE); + holder.bridgeView.setVisibility(location.supportedTransports.contains(OBFS4) ? VISIBLE : GONE); + holder.selectedView.setVisibility(location.selected ? VISIBLE : INVISIBLE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index 3ec7d38c..3eb82f22 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -26,12 +26,14 @@ public class Location { @NonNull public HashSet supportedTransports; public double averageLoad; public int numberOfGateways; + public boolean selected; - public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet supportedTransports) { + public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet supportedTransports, boolean selected) { this.name = name; this.averageLoad = averageLoad; this.numberOfGateways = numberOfGateways; this.supportedTransports = supportedTransports; + this.selected = selected; } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index dbb2a914..8e3e20df 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -43,6 +43,7 @@ import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; @@ -138,6 +139,7 @@ public class GatewaysManager { HashMap locationNames = new HashMap<>(); ArrayList locations = new ArrayList<>(); ArrayList gateways = getSortedGateways(); + String preferredCity = PreferenceHelper.getPreferredCity(context); for (Gateway gateway : gateways) { String name = gateway.getName(); if (name == null) { @@ -145,19 +147,20 @@ public class GatewaysManager { continue; } - if (!locationNames.containsKey(gateway.getName())) { - locationNames.put(gateway.getName(), locations.size()); + if (!locationNames.containsKey(name)) { + locationNames.put(name, locations.size()); // fake values for now Random rand = new Random(); double averageLoad = rand.nextDouble(); //location.averageLoad; - Log.d(TAG, "getGatewayLocations - new averageLoad (" + gateway.getName() + " - " + gateway.getHost()+ "): " + averageLoad); + Log.d(TAG, "getGatewayLocations - new averageLoad (" + name + " - " + gateway.getHost()+ "): " + averageLoad); Location location = new Location( gateway.getName(), averageLoad /*gateway.getFullness()*/, 1, - gateway.getSupportedTransports() + gateway.getSupportedTransports(), + name.equals(preferredCity) ); locations.add(location); } else { -- cgit v1.2.3 From a6cd31ae8624f830454adc627ac3a6be323a5333 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 21 Nov 2021 19:36:46 +0100 Subject: implement new gateway selection UI, using same UX principles as for desktop --- .../base/fragments/GatewaySelectionFragment.java | 120 +++++++++------------ .../leap/bitmaskclient/base/models/Location.java | 25 ++++- .../base/views/SelectLocationEntry.java | 90 ++++++++++++++++ .../bitmaskclient/base/views/SimpleCheckBox.java | 50 +++++++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 2 +- 5 files changed, 213 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index c98abd74..12aedb12 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -17,6 +17,7 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; @@ -26,10 +27,6 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.widget.AppCompatButton; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.view.LayoutInflaterCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -45,14 +42,12 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import se.leap.bitmaskclient.base.views.LocationIndicator; +import se.leap.bitmaskclient.base.views.SelectLocationEntry; import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; -import static android.view.View.GONE; -import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; @@ -61,7 +56,7 @@ import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.base.models.Constants.LOCATION; interface LocationListSelectionListener { - void onLocationSelected(Location location); + void onLocationManuallySelected(Location location); } public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener { @@ -71,9 +66,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca private RecyclerView recyclerView; private LocationListAdapter locationListAdapter; - private AppCompatTextView currentLocationDescription; - private AppCompatTextView currentLocation; - private AppCompatButton autoSelectionButton; + private SelectLocationEntry recommendedLocation; private GatewaysManager gatewaysManager; private EipStatus eipStatus; @@ -100,8 +93,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initRecyclerView(); - initAutoSelectionButton(); - initCurrentLocationInfoPanel(); + initRecommendedLocationEntry(); } @Override @@ -120,40 +112,40 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca recyclerView.setVisibility(VISIBLE); } - private void initAutoSelectionButton() { - autoSelectionButton = getActivity().findViewById(R.id.automatic_gateway_selection_btn); - autoSelectionButton.setOnClickListener(v -> { + private void initRecommendedLocationEntry() { + recommendedLocation = getActivity().findViewById(R.id.recommended_location); + recommendedLocation.setTitle(getString(R.string.gateway_selection_automatic_location)); + recommendedLocation.showDivider(true); + recommendedLocation.setOnClickListener(v -> { + recommendedLocation.setSelected(true); + locationListAdapter.unselectAll(); startEipService(null); }); + updateRecommendedLocation(); } - private void initCurrentLocationInfoPanel() { - currentLocationDescription = getActivity().findViewById(R.id.current_location_description); - currentLocation = getActivity().findViewById(R.id.current_location); - setLocationDescription(EipStatus.getInstance(), PreferenceHelper.getPreferredCity(getContext())); - } - - private void setLocationDescription(EipStatus eipStatus, String preferredCity) { - if (eipStatus.isConnected()) { - currentLocationDescription.setText(preferredCity == null ? - R.string.gateway_selection_automatic_location : - R.string.gateway_selection_manual_location); - currentLocation.setText(VpnStatus.getLastConnectedVpnName()); - currentLocation.setVisibility(VISIBLE); - } else if (preferredCity == null) { - currentLocationDescription.setText(R.string.gateway_selection_automatic_not_connected); - currentLocation.setVisibility(INVISIBLE); - } else { - currentLocationDescription.setText(R.string.gateway_selection_manual_not_connected); - currentLocation.setText(preferredCity); - currentLocation.setVisibility(VISIBLE); + private void updateRecommendedLocation() { + Location location = new Location(); + boolean isManualSelection = PreferenceHelper.getPreferredCity(getContext()) != null; + if (!isManualSelection && eipStatus.isConnected()) { + try { + location = gatewaysManager.getLocation(VpnStatus.getCurrentlyConnectingVpnName()).clone(); + } catch (NullPointerException | CloneNotSupportedException e) { + e.printStackTrace(); + } } + location.selected = !isManualSelection; + recommendedLocation.setLocation(location); } protected void startEipService(String preferredCity) { new Thread(() -> { - PreferenceHelper.setPreferredCity(getContext(), preferredCity); - EipCommand.startVPN(getContext(), false); + Context context = getContext(); + if (context == null) { + return; + } + PreferenceHelper.setPreferredCity(context, preferredCity); + EipCommand.startVPN(context, false); 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); @@ -162,7 +154,8 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } @Override - public void onLocationSelected(Location location) { + public void onLocationManuallySelected(Location location) { + recommendedLocation.setSelected(false); String name = location.name; Connection.TransportType selectedTransport = PreferenceHelper.getUseBridges(getContext()) ? OBFS4 : OPENVPN; if (location.supportedTransports.contains(selectedTransport)) { @@ -185,32 +178,25 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca @Override public void update(Observable o, Object arg) { if (o instanceof EipStatus) { + eipStatus = (EipStatus) o; Activity activity = getActivity(); if (activity != null) { - activity.runOnUiThread(() -> setLocationDescription((EipStatus) o, PreferenceHelper.getPreferredCity(getContext()))); + activity.runOnUiThread(this::updateRecommendedLocation); } } } static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); - private List values; + private final List values; private final WeakReference callback; static class ViewHolder extends RecyclerView.ViewHolder { - public AppCompatTextView locationLabel; - public LocationIndicator locationIndicator; - public AppCompatImageView bridgeView; - public AppCompatImageView selectedView; - public View layout; + public SelectLocationEntry entry; - public ViewHolder(View v) { + public ViewHolder(SelectLocationEntry v) { super(v); - layout = v; - locationLabel = v.findViewById(R.id.location); - locationIndicator = v.findViewById(R.id.quality); - bridgeView = v.findViewById(R.id.bridge_image); - selectedView = v.findViewById(R.id.selected); + entry = v; } } @@ -224,8 +210,10 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca notifyItemRemoved(position); } - public void updateData(List data) { - values = data; + public void unselectAll() { + for (Location l : values) { + l.selected = false; + } notifyDataSetChanged(); } @@ -238,35 +226,27 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca @Override public LocationListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - LayoutInflater inflater = LayoutInflater.from( - parent.getContext()); - View v = inflater.inflate(R.layout.v_select_text_list_item, parent, false); - return new ViewHolder(v); + SelectLocationEntry entry = new SelectLocationEntry(parent.getContext()); + return new ViewHolder(entry); } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, final int position) { final Location location = values.get(position); - holder.locationLabel.setText(location.name); - holder.layout.setOnClickListener(v -> { - Log.d(TAG, "view at position clicked: " + position); + holder.entry.setLocation(location); + holder.entry.setOnClickListener(v -> { + Log.d(TAG, "onClick view at position clicked: " + position); LocationListSelectionListener listener = callback.get(); if (listener != null) { - for (Location l : values) { - l.selected = false; - } - location.selected = !location.selected; + unselectAll(); + location.selected = true; + listener.onLocationManuallySelected(location); notifyDataSetChanged(); - listener.onLocationSelected(location); } }); - holder.locationIndicator.setLoad(GatewaysManager.Load.getLoadByValue(location.averageLoad)); - holder.bridgeView.setVisibility(location.supportedTransports.contains(OBFS4) ? VISIBLE : GONE); - holder.selectedView.setVisibility(location.selected ? VISIBLE : INVISIBLE); } - @Override public int getItemCount() { return values.size(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index 3eb82f22..599a358a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -18,16 +18,20 @@ package se.leap.bitmaskclient.base.models; import androidx.annotation.NonNull; + import java.util.HashSet; + import de.blinkt.openvpn.core.connection.Connection; -public class Location { - @NonNull public String name; - @NonNull public HashSet supportedTransports; +public class Location implements Cloneable { + @NonNull public String name = ""; + @NonNull public HashSet supportedTransports = new HashSet<>(); public double averageLoad; public int numberOfGateways; public boolean selected; + public Location() {} + public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet supportedTransports, boolean selected) { this.name = name; this.averageLoad = averageLoad; @@ -36,6 +40,10 @@ public class Location { this.selected = selected; } + public boolean hasLocationInfo() { + return numberOfGateways != 0 && supportedTransports.size() != 0 && !name.isEmpty(); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -60,4 +68,15 @@ public class Location { result = 31 * result + numberOfGateways; return result; } + + @Override + public Location clone() throws CloneNotSupportedException { + Location copy = (Location) super.clone(); + copy.name = this.name; + copy.supportedTransports = (HashSet) this.supportedTransports.clone(); + copy.numberOfGateways = this.numberOfGateways; + copy.averageLoad = this.averageLoad; + return copy; + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java new file mode 100644 index 00000000..f85df4ca --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java @@ -0,0 +1,90 @@ +package se.leap.bitmaskclient.base.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.RelativeLayout; + +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; + +import de.blinkt.openvpn.core.connection.Connection; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.models.Location; +import se.leap.bitmaskclient.eip.GatewaysManager.Load; + +public class SelectLocationEntry extends RelativeLayout { + + private static final String TAG = SelectLocationEntry.class.getSimpleName(); + AppCompatTextView title; + AppCompatTextView locationText; + SimpleCheckBox selectedView; + AppCompatImageView bridgesView; + LocationIndicator locationIndicator; + View divider; + + // private OnClickListener onClickListener; + + public SelectLocationEntry(Context context) { + super(context); + initLayout(context); + } + + public SelectLocationEntry(Context context, AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + public SelectLocationEntry(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + @TargetApi(21) + public SelectLocationEntry(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initLayout(context); + } + + private void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_select_text_list_item, this, true); + title = rootview.findViewById(R.id.title); + locationIndicator = rootview.findViewById(R.id.quality); + locationText = rootview.findViewById(R.id.location); + bridgesView = rootview.findViewById(R.id.bridge_image); + selectedView = rootview.findViewById(R.id.selected); + divider = rootview.findViewById(R.id.divider); + } + + public void setTitle(String text) { + title.setText(text); + title.setVisibility(text != null ? VISIBLE : GONE); + } + public void setLocation(Location location) { + boolean valid = location.hasLocationInfo(); + locationText.setVisibility(valid ? VISIBLE : GONE); + locationIndicator.setVisibility(valid ? VISIBLE : GONE); + bridgesView.setVisibility(valid ? VISIBLE : GONE); + locationText.setText(location.name); + locationIndicator.setLoad(Load.getLoadByValue(location.averageLoad)); + bridgesView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : GONE); + selectedView.setChecked(location.selected); + } + + public void showDivider(boolean show) { + divider.setVisibility(show ? VISIBLE : GONE); + } + + public void setSelected(boolean selected) { + selectedView.setChecked(selected); + } + + public boolean isSelected() { + return selectedView.checkView.getVisibility() == VISIBLE; + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java new file mode 100644 index 00000000..7cd790db --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java @@ -0,0 +1,50 @@ +package se.leap.bitmaskclient.base.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.RelativeLayout; + +import androidx.appcompat.widget.AppCompatImageView; + +import se.leap.bitmaskclient.R; + +public class SimpleCheckBox extends RelativeLayout { + + AppCompatImageView checkView; + + + public SimpleCheckBox(Context context) { + super(context); + initLayout(context); + } + + public SimpleCheckBox(Context context, AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + public SimpleCheckBox(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + @TargetApi(21) + public SimpleCheckBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initLayout(context); + } + + private void initLayout(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View rootview = inflater.inflate(R.layout.v_simple_checkbox, this, true); + this.checkView = rootview.findViewById(R.id.check_view); + } + + public void setChecked(boolean checked) { + this.checkView.setVisibility(checked ? VISIBLE : INVISIBLE); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 8e3e20df..92a6af5a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -155,7 +155,7 @@ public class GatewaysManager { Log.d(TAG, "getGatewayLocations - new averageLoad (" + name + " - " + gateway.getHost()+ "): " + averageLoad); Location location = new Location( - gateway.getName(), + name, averageLoad /*gateway.getFullness()*/, 1, -- cgit v1.2.3 From b7817e7d65e390f6e3291e856b3a69333f8f3758 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sun, 21 Nov 2021 19:37:58 +0100 Subject: make PreferenceHelper null safe --- .../bitmaskclient/base/utils/PreferenceHelper.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index 93284968..40b7fc05 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -2,6 +2,7 @@ package se.leap.bitmaskclient.base.utils; import android.content.Context; import android.content.SharedPreferences; + import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; @@ -34,8 +35,8 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICA import static se.leap.bitmaskclient.base.models.Constants.RESTART_ON_UPDATE; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL; -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.base.models.Constants.USE_IPv6_FIREWALL; import static se.leap.bitmaskclient.base.models.Constants.USE_TOR; /** @@ -265,27 +266,42 @@ public class PreferenceHelper { } public static long getLong(Context context, String key, long defValue) { + if (context == null) { + return defValue; + } SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); return preferences.getLong(key, defValue); } public static void putLong(Context context, String key, long value) { + if (context == null) { + return; + } SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); preferences.edit().putLong(key, value).apply(); } public static String getString(Context context, String key, String defValue) { + if (context == null) { + return defValue; + } SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); return preferences.getString(key, defValue); } @WorkerThread public static void putStringSync(Context context, String key, String value) { + if (context == null) { + return; + } SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); preferences.edit().putString(key, value).commit(); } public static void putString(Context context, String key, String value) { + if (context == null) { + return; + } SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); preferences.edit().putString(key, value).apply(); } -- cgit v1.2.3 From 9bf787465a3ae22c76249317496c8927b22ffdb4 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 23 Nov 2021 12:32:07 +0100 Subject: calculate and show gateway load related to transport --- .../bitmaskclient/base/fragments/EipFragment.java | 5 +- .../base/fragments/GatewaySelectionFragment.java | 44 +++++++++++--- .../leap/bitmaskclient/base/models/Location.java | 68 +++++++++++++++------- .../bitmaskclient/base/utils/ConfigHelper.java | 9 +++ .../base/views/SelectLocationEntry.java | 8 +-- .../se/leap/bitmaskclient/eip/GatewaySelector.java | 9 +-- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 61 ++++++++++--------- 7 files changed, 136 insertions(+), 68 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index f8053f5e..e9300584 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -56,12 +56,14 @@ import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.connection.Connection; 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.base.models.ProviderObservable; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.LocationButton; import se.leap.bitmaskclient.base.views.MainButton; import se.leap.bitmaskclient.eip.EipCommand; @@ -426,7 +428,8 @@ public class EipFragment extends Fragment implements Observer { } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); mainButton.updateState(true, false, false); - locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName())); + Connection.TransportType transportType = PreferenceHelper.getUseBridges(getContext()) ? Connection.TransportType.OBFS4 : Connection.TransportType.OPENVPN; + locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName(), transportType)); locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); locationButton.showRecommendedIndicator(getPreferredCity(getContext())== null); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 12aedb12..51ebe359 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -19,6 +19,7 @@ package se.leap.bitmaskclient.base.fragments; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -48,18 +49,21 @@ import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; +import static android.content.Context.MODE_PRIVATE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_DIALOG_FRAGMENT; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.base.models.Constants.LOCATION; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; interface LocationListSelectionListener { void onLocationManuallySelected(Location location); } -public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener { +public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener, SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = GatewaySelectionFragment.class.getSimpleName(); @@ -69,6 +73,8 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca private SelectLocationEntry recommendedLocation; private GatewaysManager gatewaysManager; private EipStatus eipStatus; + private SharedPreferences preferences; + private Connection.TransportType selectedTransport; public GatewaySelectionFragment() { // Required empty public constructor @@ -80,6 +86,9 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca gatewaysManager = new GatewaysManager(getContext()); eipStatus = EipStatus.getInstance(); eipStatus.addObserver(this); + preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + selectedTransport = PreferenceHelper.getUseBridges(preferences) ? OBFS4 : OPENVPN; + preferences.registerOnSharedPreferenceChangeListener(this); } @Override @@ -100,6 +109,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca public void onDestroyView() { super.onDestroyView(); eipStatus.deleteObserver(this); + preferences.unregisterOnSharedPreferenceChangeListener(this); } private void initRecyclerView() { @@ -107,7 +117,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca recyclerView.setHasFixedSize(true); LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); recyclerView.setLayoutManager(layoutManager); - locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations(), this); + locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations(), this, selectedTransport); recyclerView.setAdapter(locationListAdapter); recyclerView.setVisibility(VISIBLE); } @@ -135,7 +145,10 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } } location.selected = !isManualSelection; - recommendedLocation.setLocation(location); + if (!isManualSelection) { + locationListAdapter.unselectAll(); + } + recommendedLocation.setLocation(location, selectedTransport); } protected void startEipService(String preferredCity) { @@ -156,11 +169,11 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca @Override public void onLocationManuallySelected(Location location) { recommendedLocation.setSelected(false); - String name = location.name; - Connection.TransportType selectedTransport = PreferenceHelper.getUseBridges(getContext()) ? OBFS4 : OPENVPN; - if (location.supportedTransports.contains(selectedTransport)) { + String name = location.getName(); + if (location.supportsTransport(selectedTransport)) { startEipService(name); } else { + locationListAdapter.unselectAll(); askToChangeTransport(name); } } @@ -186,8 +199,17 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } } + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(USE_BRIDGES)) { + selectedTransport = PreferenceHelper.getUseBridges(sharedPreferences) ? OBFS4 : OPENVPN; + locationListAdapter.updateTransport(selectedTransport); + } + } + static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); + private Connection.TransportType transport; private final List values; private final WeakReference callback; @@ -210,6 +232,11 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca notifyItemRemoved(position); } + public void updateTransport(Connection.TransportType transportType) { + transport = transportType; + notifyDataSetChanged(); + } + public void unselectAll() { for (Location l : values) { l.selected = false; @@ -217,9 +244,10 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca notifyDataSetChanged(); } - public LocationListAdapter(List data, LocationListSelectionListener selectionListener) { + public LocationListAdapter(List data, LocationListSelectionListener selectionListener, Connection.TransportType selectedTransport) { values = data; callback = new WeakReference<>(selectionListener); + transport = selectedTransport; } @NonNull @@ -234,7 +262,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca @Override public void onBindViewHolder(ViewHolder holder, final int position) { final Location location = values.get(position); - holder.entry.setLocation(location); + holder.entry.setLocation(location, transport); holder.entry.setOnClickListener(v -> { Log.d(TAG, "onClick view at position clicked: " + position); LocationListSelectionListener listener = callback.get(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index 599a358a..e0ce9e8b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -19,29 +19,62 @@ package se.leap.bitmaskclient.base.models; import androidx.annotation.NonNull; +import java.util.HashMap; import java.util.HashSet; import de.blinkt.openvpn.core.connection.Connection; public class Location implements Cloneable { - @NonNull public String name = ""; - @NonNull public HashSet supportedTransports = new HashSet<>(); - public double averageLoad; - public int numberOfGateways; + @NonNull private String name = ""; + @NonNull private HashMap averageLoad = new HashMap<>(); + @NonNull private HashMap numberOfGateways = new HashMap<>(); public boolean selected; public Location() {} - public Location(@NonNull String name, double averageLoad, int numberOfGateways, @NonNull HashSet supportedTransports, boolean selected) { + public Location(@NonNull String name, + @NonNull HashMap averageLoad, + @NonNull HashMap numberOfGateways, + boolean selected) { this.name = name; this.averageLoad = averageLoad; this.numberOfGateways = numberOfGateways; - this.supportedTransports = supportedTransports; this.selected = selected; } public boolean hasLocationInfo() { - return numberOfGateways != 0 && supportedTransports.size() != 0 && !name.isEmpty(); + return !numberOfGateways.isEmpty() && !averageLoad.isEmpty() && !name.isEmpty(); + } + + public boolean supportsTransport(Connection.TransportType transportType) { + return numberOfGateways.containsKey(transportType); + } + + public void setAverageLoad(Connection.TransportType transportType, double load) { + averageLoad.put(transportType, load); + } + + public double getAverageLoad(Connection.TransportType transportType) { + if (averageLoad.containsKey(transportType)) { + return averageLoad.get(transportType); + } + return 0; + } + + public void setNumberOfGateways(Connection.TransportType transportType, int numbers) { + numberOfGateways.put(transportType, numbers); + } + + public int getNumberOfGateways(Connection.TransportType transportType) { + if (numberOfGateways.containsKey(transportType)) { + return numberOfGateways.get(transportType); + } + return 0; + } + + @NonNull + public String getName() { + return name; } @Override @@ -51,21 +84,16 @@ public class Location implements Cloneable { Location location = (Location) o; - if (Double.compare(location.averageLoad, averageLoad) != 0) return false; - if (numberOfGateways != location.numberOfGateways) return false; if (!name.equals(location.name)) return false; - return supportedTransports.equals(location.supportedTransports); + if (!averageLoad.equals(location.averageLoad)) return false; + return numberOfGateways.equals(location.numberOfGateways); } @Override public int hashCode() { - int result; - long temp; - result = name.hashCode(); - result = 31 * result + supportedTransports.hashCode(); - temp = Double.doubleToLongBits(averageLoad); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - result = 31 * result + numberOfGateways; + int result = name.hashCode(); + result = 31 * result + averageLoad.hashCode(); + result = 31 * result + numberOfGateways.hashCode(); return result; } @@ -73,10 +101,8 @@ public class Location implements Cloneable { public Location clone() throws CloneNotSupportedException { Location copy = (Location) super.clone(); copy.name = this.name; - copy.supportedTransports = (HashSet) this.supportedTransports.clone(); - copy.numberOfGateways = this.numberOfGateways; - copy.averageLoad = this.averageLoad; + copy.numberOfGateways = (HashMap) this.numberOfGateways.clone(); + copy.averageLoad = (HashMap) this.averageLoad.clone(); return copy; } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index 64b51960..92010992 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -197,6 +197,15 @@ public class ConfigHelper { return Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; } + public static int timezoneDistance(int local_timezone, int remoteTimezone) { + // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 + int dist = Math.abs(local_timezone - remoteTimezone); + // Farther than 12 timezones and it's shorter around the "back" + if (dist > 12) + dist = 12 - (dist - 12); // Well i'll be. Absolute values make equations do funny things. + return dist; + } + public static String getProviderFormattedString(Resources resources, @StringRes int resourceId) { String appName = resources.getString(R.string.app_name); return resources.getString(resourceId, appName); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java index f85df4ca..bf293a51 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java @@ -64,14 +64,14 @@ public class SelectLocationEntry extends RelativeLayout { title.setText(text); title.setVisibility(text != null ? VISIBLE : GONE); } - public void setLocation(Location location) { + public void setLocation(Location location, Connection.TransportType transportType) { boolean valid = location.hasLocationInfo(); locationText.setVisibility(valid ? VISIBLE : GONE); locationIndicator.setVisibility(valid ? VISIBLE : GONE); bridgesView.setVisibility(valid ? VISIBLE : GONE); - locationText.setText(location.name); - locationIndicator.setLoad(Load.getLoadByValue(location.averageLoad)); - bridgesView.setVisibility(location.supportedTransports.contains(Connection.TransportType.OBFS4) ? VISIBLE : GONE); + locationText.setText(location.getName()); + locationIndicator.setLoad(Load.getLoadByValue(location.getAverageLoad(transportType))); + bridgesView.setVisibility(location.supportsTransport(Connection.TransportType.OBFS4) ? VISIBLE : GONE); selectedView.setChecked(location.selected); } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java index a48cc6d5..52030ce3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.TreeMap; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getCurrentTimezone; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.timezoneDistance; public class GatewaySelector { private final static String TAG = GatewaySelector.class.getSimpleName(); @@ -67,12 +68,4 @@ public class GatewaySelector { return offsets; } - private int timezoneDistance(int local_timezone, int remote_timezone) { - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(local_timezone - remote_timezone); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist - 12); // Well i'll be. Absolute values make equations do funny things. - return dist; - } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 92a6af5a..a0867605 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -149,54 +149,63 @@ public class GatewaysManager { if (!locationNames.containsKey(name)) { locationNames.put(name, locations.size()); - // fake values for now - Random rand = new Random(); - double averageLoad = rand.nextDouble(); //location.averageLoad; - Log.d(TAG, "getGatewayLocations - new averageLoad (" + name + " - " + gateway.getHost()+ "): " + averageLoad); - - Location location = new Location( - name, - averageLoad - /*gateway.getFullness()*/, - 1, - gateway.getSupportedTransports(), - name.equals(preferredCity) - ); + Location location = initLocation(name, gateway, preferredCity); locations.add(location); } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); - location.averageLoad = (location.numberOfGateways * location.averageLoad + gateway.getFullness()) / (location.numberOfGateways + 1); - Log.d(TAG, "getGatewayLocations - updated averageLoad: (" + gateway.getName() + " - " + gateway.getHost()+ "): " + location.averageLoad); - location.numberOfGateways += 1; - location.supportedTransports.addAll(gateway.getSupportedTransports()); + updateLocation(location, gateway, OBFS4); + updateLocation(location, gateway, OPENVPN); locations.set(index, location); } } - this.locations = locations; return locations; } + private Location initLocation(String name, Gateway gateway, String preferredCity) { + HashMap averageLoadMap = new HashMap<>(); + HashMap numberOfGatewaysMap = new HashMap<>(); + if (gateway.getSupportedTransports().contains(OBFS4)) { + averageLoadMap.put(OBFS4, gateway.getFullness()); + numberOfGatewaysMap.put(OBFS4, 1); + } + if (gateway.getSupportedTransports().contains(OPENVPN)) { + averageLoadMap.put(OPENVPN, gateway.getFullness()); + numberOfGatewaysMap.put(OPENVPN, 1); + } + return new Location( + name, + averageLoadMap, + numberOfGatewaysMap, + name.equals(preferredCity)); + } + + private void updateLocation(Location location, Gateway gateway, Connection.TransportType transportType) { + if (gateway.getSupportedTransports().contains(transportType)) { + double averageLoad = location.getAverageLoad(transportType); + int numberOfGateways = location.getNumberOfGateways(transportType); + averageLoad = (numberOfGateways * averageLoad + gateway.getFullness()) / (numberOfGateways + 1); + numberOfGateways++; + location.setAverageLoad(transportType, averageLoad); + location.setNumberOfGateways(transportType, numberOfGateways); + } + } + @Nullable public Location getLocation(String name) { List locations = getGatewayLocations(); for (Location location : locations) { - if (location.name.equals(name)) { + if (location.getName().equals(name)) { return location; } } return null; } - public Load getLoadForLocation(@Nullable String name) { + public Load getLoadForLocation(@Nullable String name, Connection.TransportType transportType) { Location location = getLocation(name); - if (location != null) { - return Load.getLoadByValue(location.averageLoad); - } - - // location not found - return Load.UNKNOWN; + return Load.getLoadByValue(location.getAverageLoad(transportType)); } private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType, @Nullable String city) { -- cgit v1.2.3 From 829849c074d397ceba59c89fe4be0bd65ea49f6f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 23 Nov 2021 12:34:00 +0100 Subject: calculate fake load from timezone distance if menshen doesn't serve load info --- .../java/se/leap/bitmaskclient/base/utils/ConfigHelper.java | 11 +++++++++++ app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index 92010992..6c242e5a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -206,6 +206,17 @@ public class ConfigHelper { return dist; } + /** + * + * @param remoteTimezone + * @return a value between 0.1 and 1.0 + */ + public static double getConnectionQualityFromTimezoneDistance(int remoteTimezone) { + int localTimeZone = ConfigHelper.getCurrentTimezone(); + int distance = ConfigHelper.timezoneDistance(localTimeZone, remoteTimezone); + return Math.max(distance / 12.0, 0.1); + } + public static String getProviderFormattedString(Resources resources, @StringRes int resourceId) { String appName = resources.getString(R.string.app_name); return resources.getString(resourceId, appName); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 8a48684f..a3d3abbc 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -33,6 +33,7 @@ import java.util.Set; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.connection.Connection; +import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import static se.leap.bitmaskclient.base.models.Constants.FULLNESS; @@ -156,7 +157,7 @@ public class Gateway { try { return load.getDouble(FULLNESS); } catch (JSONException | NullPointerException e) { - return 0; + return ConfigHelper.getConnectionQualityFromTimezoneDistance(timezone); } } -- cgit v1.2.3 From f29ee8ac7378408e070be1130c9cadc8e947ddb3 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 23 Nov 2021 14:51:33 +0100 Subject: sort locations by transport --- .../base/fragments/GatewaySelectionFragment.java | 10 +++-- .../leap/bitmaskclient/base/models/Location.java | 43 ++++++++++++++++------ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 42 ++++++++++++--------- 3 files changed, 62 insertions(+), 33 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 51ebe359..e3845164 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -117,7 +117,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca recyclerView.setHasFixedSize(true); LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext()); recyclerView.setLayoutManager(layoutManager); - locationListAdapter = new LocationListAdapter(gatewaysManager.getGatewayLocations(), this, selectedTransport); + locationListAdapter = new LocationListAdapter(gatewaysManager.getSortedGatewayLocations(selectedTransport), this, selectedTransport); recyclerView.setAdapter(locationListAdapter); recyclerView.setVisibility(VISIBLE); } @@ -203,14 +203,15 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(USE_BRIDGES)) { selectedTransport = PreferenceHelper.getUseBridges(sharedPreferences) ? OBFS4 : OPENVPN; - locationListAdapter.updateTransport(selectedTransport); + gatewaysManager.updateTransport(selectedTransport); + locationListAdapter.updateTransport(selectedTransport, gatewaysManager); } } static class LocationListAdapter extends RecyclerView.Adapter { private static final String TAG = LocationListAdapter.class.getSimpleName(); private Connection.TransportType transport; - private final List values; + private List values; private final WeakReference callback; static class ViewHolder extends RecyclerView.ViewHolder { @@ -232,8 +233,9 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca notifyItemRemoved(position); } - public void updateTransport(Connection.TransportType transportType) { + public void updateTransport(Connection.TransportType transportType, GatewaysManager gatewaysManager) { transport = transportType; + values = gatewaysManager.getSortedGatewayLocations(transportType); notifyDataSetChanged(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index e0ce9e8b..064f25c0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -19,22 +19,25 @@ package se.leap.bitmaskclient.base.models; import androidx.annotation.NonNull; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.function.ToDoubleFunction; import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Connection.TransportType; public class Location implements Cloneable { @NonNull private String name = ""; - @NonNull private HashMap averageLoad = new HashMap<>(); - @NonNull private HashMap numberOfGateways = new HashMap<>(); + @NonNull private HashMap averageLoad = new HashMap<>(); + @NonNull private HashMap numberOfGateways = new HashMap<>(); public boolean selected; public Location() {} public Location(@NonNull String name, - @NonNull HashMap averageLoad, - @NonNull HashMap numberOfGateways, + @NonNull HashMap averageLoad, + @NonNull HashMap numberOfGateways, boolean selected) { this.name = name; this.averageLoad = averageLoad; @@ -46,26 +49,26 @@ public class Location implements Cloneable { return !numberOfGateways.isEmpty() && !averageLoad.isEmpty() && !name.isEmpty(); } - public boolean supportsTransport(Connection.TransportType transportType) { + public boolean supportsTransport(TransportType transportType) { return numberOfGateways.containsKey(transportType); } - public void setAverageLoad(Connection.TransportType transportType, double load) { + public void setAverageLoad(TransportType transportType, double load) { averageLoad.put(transportType, load); } - public double getAverageLoad(Connection.TransportType transportType) { + public double getAverageLoad(TransportType transportType) { if (averageLoad.containsKey(transportType)) { return averageLoad.get(transportType); } return 0; } - public void setNumberOfGateways(Connection.TransportType transportType, int numbers) { + public void setNumberOfGateways(TransportType transportType, int numbers) { numberOfGateways.put(transportType, numbers); } - public int getNumberOfGateways(Connection.TransportType transportType) { + public int getNumberOfGateways(TransportType transportType) { if (numberOfGateways.containsKey(transportType)) { return numberOfGateways.get(transportType); } @@ -101,8 +104,26 @@ public class Location implements Cloneable { public Location clone() throws CloneNotSupportedException { Location copy = (Location) super.clone(); copy.name = this.name; - copy.numberOfGateways = (HashMap) this.numberOfGateways.clone(); - copy.averageLoad = (HashMap) this.averageLoad.clone(); + copy.numberOfGateways = (HashMap) this.numberOfGateways.clone(); + copy.averageLoad = (HashMap) this.averageLoad.clone(); return copy; } + + public static class SortByAverageLoad implements Comparator { + TransportType transportType; + public SortByAverageLoad(TransportType transportType) { + this.transportType = transportType; + } + + @Override + public int compare(Location location1, Location location2) { + if (location1.supportsTransport(transportType) && location2.supportsTransport(transportType)) { + return (int) (location1.getAverageLoad(transportType) * 100) - (int) (location2.getAverageLoad(transportType) * 100); + } else if (location1.supportsTransport(transportType) && !location2.supportsTransport(transportType)) { + return -1; + } else { + return 1; + } + } + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index a0867605..060e69f2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -31,15 +31,16 @@ import org.json.JSONObject; import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; -import java.util.Random; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Connection.TransportType; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; @@ -98,6 +99,7 @@ public class GatewaysManager { private final Type listType = new TypeToken>() {}.getType(); private final ArrayList presortedList = new ArrayList<>(); private ArrayList locations = new ArrayList<>(); + private TransportType selectedTransport; public GatewaysManager(Context context) { this.context = context; @@ -114,7 +116,7 @@ public class GatewaysManager { } public Gateway select(int nClosest, String city) { - Connection.TransportType transportType = getUseBridges(context) ? OBFS4 : OPENVPN; + TransportType transportType = getUseBridges(context) ? OBFS4 : OPENVPN; if (presortedList.size() > 0) { return getGatewayFromPresortedList(nClosest, transportType, city); } @@ -122,25 +124,26 @@ public class GatewaysManager { return getGatewayFromTimezoneCalculation(nClosest, transportType, city); } - public ArrayList getSortedGateways() { - if (presortedList.size() > 0) { - return presortedList; - } else { - GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); - return gatewaySelector.getGatewaysSortedByDistance(); + public void updateTransport(TransportType transportType) { + if (this.selectedTransport == null || transportType != this.selectedTransport) { + this.selectedTransport = transportType; + locations.clear(); } } public List getGatewayLocations() { + return getSortedGatewayLocations(null); + } + + public List getSortedGatewayLocations(@Nullable TransportType selectedTransport) { if (locations.size() > 0) { return locations; } HashMap locationNames = new HashMap<>(); ArrayList locations = new ArrayList<>(); - ArrayList gateways = getSortedGateways(); String preferredCity = PreferenceHelper.getPreferredCity(context); - for (Gateway gateway : gateways) { + for (Gateway gateway : gateways.values()) { String name = gateway.getName(); if (name == null) { Log.e(TAG, "Gateway without location name found. This should never happen. Provider misconfigured?"); @@ -159,13 +162,16 @@ public class GatewaysManager { locations.set(index, location); } } - this.locations = locations; + if (selectedTransport != null) { + Collections.sort(locations, new Location.SortByAverageLoad(selectedTransport)); + this.locations = locations; + } return locations; } private Location initLocation(String name, Gateway gateway, String preferredCity) { - HashMap averageLoadMap = new HashMap<>(); - HashMap numberOfGatewaysMap = new HashMap<>(); + HashMap averageLoadMap = new HashMap<>(); + HashMap numberOfGatewaysMap = new HashMap<>(); if (gateway.getSupportedTransports().contains(OBFS4)) { averageLoadMap.put(OBFS4, gateway.getFullness()); numberOfGatewaysMap.put(OBFS4, 1); @@ -203,12 +209,12 @@ public class GatewaysManager { return null; } - public Load getLoadForLocation(@Nullable String name, Connection.TransportType transportType) { + public Load getLoadForLocation(@Nullable String name, TransportType transportType) { Location location = getLocation(name); return Load.getLoadByValue(location.getAverageLoad(transportType)); } - private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType, @Nullable String city) { + private Gateway getGatewayFromTimezoneCalculation(int nClosest, TransportType transportType, @Nullable String city) { List list = new ArrayList<>(gateways.values()); GatewaySelector gatewaySelector = new GatewaySelector(list); Gateway gateway; @@ -227,7 +233,7 @@ public class GatewaysManager { return null; } - private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType, @Nullable String city) { + private Gateway getGatewayFromPresortedList(int nClosest, TransportType transportType, @Nullable String city) { int found = 0; for (Gateway gateway : presortedList) { if ((city == null && gateway.supportsTransport(transportType)) || @@ -255,7 +261,7 @@ public class GatewaysManager { } private int getPositionFromPresortedList(VpnProfile profile) { - Connection.TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; int nClosest = 0; for (Gateway gateway : presortedList) { if (gateway.supportsTransport(transportType)) { @@ -269,7 +275,7 @@ public class GatewaysManager { } private int getPositionFromTimezoneCalculatedList(VpnProfile profile) { - Connection.TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); Gateway gateway; int nClosest = 0; -- cgit v1.2.3 From 638b2c53f00f552693cc8f425eaa862343e6cf20 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 23 Nov 2021 15:42:41 +0100 Subject: add OnCheckedChangedListener in SimpleCheckbox --- .../bitmaskclient/base/views/SimpleCheckBox.java | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java index 7cd790db..09a9132e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SimpleCheckBox.java @@ -9,11 +9,19 @@ import android.widget.RelativeLayout; import androidx.appcompat.widget.AppCompatImageView; +import java.lang.ref.WeakReference; + import se.leap.bitmaskclient.R; public class SimpleCheckBox extends RelativeLayout { AppCompatImageView checkView; + private WeakReference checkedChangeListener = new WeakReference(null); + private boolean checked; + + public interface OnCheckedChangeListener { + void onCheckedChanged(SimpleCheckBox simpleCheckBox, boolean isChecked); + } public SimpleCheckBox(Context context) { @@ -45,6 +53,21 @@ public class SimpleCheckBox extends RelativeLayout { } public void setChecked(boolean checked) { - this.checkView.setVisibility(checked ? VISIBLE : INVISIBLE); + if (this.checked != checked) { + this.checkView.setVisibility(checked ? VISIBLE : INVISIBLE); + this.checked = checked; + OnCheckedChangeListener listener = checkedChangeListener.get(); + if (listener != null) { + listener.onCheckedChanged(this, this.checked); + } + } + } + + public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { + checkedChangeListener = new WeakReference<>(listener); + } + + public void toggle() { + setChecked(!this.checked); } } -- cgit v1.2.3 From 75fabe51badee54ab1de372d0eb667342e5924d0 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 23 Nov 2021 15:44:35 +0100 Subject: use SimpleCheckBox in ExcludeAppsFragment --- .../se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'app/src/main/java/se/leap') 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 db5057cc..04745d42 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 @@ -39,11 +39,12 @@ import java.util.Vector; import de.blinkt.openvpn.VpnProfile; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.base.views.SimpleCheckBox; /** * Created by arne on 16.11.14. */ -public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemClickListener, CompoundButton.OnCheckedChangeListener, View.OnClickListener { +public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemClickListener, SimpleCheckBox.OnCheckedChangeListener, View.OnClickListener { private ListView mListView; private VpnProfile mProfile; private PackageAdapter mListAdapter; @@ -82,7 +83,7 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC public ImageView appIcon; //public AppCompatTextView appSize; //public AppCompatTextView disabled; - public CompoundButton checkBox; + public SimpleCheckBox checkBox; static public AppViewHolder createOrRecycle(LayoutInflater inflater, View convertView, ViewGroup parent) { if (convertView == null) { @@ -108,7 +109,7 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC } @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + public void onCheckedChanged(SimpleCheckBox buttonView, boolean isChecked) { String packageName = (String) buttonView.getTag(); if (isChecked) { -- cgit v1.2.3 From 6d24e0c721038bb6f7a5c34703e5cf405166bf6b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 23 Nov 2021 19:06:24 +0100 Subject: improve location selection list entry layout --- .../java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java index bf293a51..204e8692 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java @@ -5,6 +5,7 @@ import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; +import android.widget.LinearLayout; import android.widget.RelativeLayout; import androidx.appcompat.widget.AppCompatImageView; @@ -15,7 +16,7 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.eip.GatewaysManager.Load; -public class SelectLocationEntry extends RelativeLayout { +public class SelectLocationEntry extends LinearLayout { private static final String TAG = SelectLocationEntry.class.getSimpleName(); AppCompatTextView title; -- cgit v1.2.3 From e3cd28aa6ef16d9bde179a3e1117cdfa585939a4 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 24 Nov 2021 10:17:26 +0100 Subject: only show bridges icon in gateway selection list if location supports it AND bridges setting is enabled --- .../java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/se/leap') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java index 204e8692..2a082579 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java @@ -16,6 +16,8 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Location; import se.leap.bitmaskclient.eip.GatewaysManager.Load; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; + public class SelectLocationEntry extends LinearLayout { private static final String TAG = SelectLocationEntry.class.getSimpleName(); @@ -26,8 +28,6 @@ public class SelectLocationEntry extends LinearLayout { LocationIndicator locationIndicator; View divider; - // private OnClickListener onClickListener; - public SelectLocationEntry(Context context) { super(context); initLayout(context); @@ -69,10 +69,9 @@ public class SelectLocationEntry extends LinearLayout { boolean valid = location.hasLocationInfo(); locationText.setVisibility(valid ? VISIBLE : GONE); locationIndicator.setVisibility(valid ? VISIBLE : GONE); - bridgesView.setVisibility(valid ? VISIBLE : GONE); + bridgesView.setVisibility(transportType == OBFS4 && location.supportsTransport(OBFS4) ? VISIBLE : GONE); locationText.setText(location.getName()); locationIndicator.setLoad(Load.getLoadByValue(location.getAverageLoad(transportType))); - bridgesView.setVisibility(location.supportsTransport(Connection.TransportType.OBFS4) ? VISIBLE : GONE); selectedView.setChecked(location.selected); } -- cgit v1.2.3