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 --- app/src/androidTest/legacy/VpnTestController.java | 2 +- .../bitmaskclient/base/fragments/EipFragment.java | 66 +++++++++---------- .../bitmaskclient/base/views/LocationButton.java | 44 +++++++++++++ .../base/views/LocationIndicator.java | 76 ++++++++++++++++++++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 50 ++++++++++++++ .../res/drawable/cust_button_primary_hard_rect.xml | 21 ++++++ .../main/res/drawable/cust_button_primary_rect.xml | 3 - app/src/main/res/layout-xlarge/f_eip.xml | 46 ++----------- app/src/main/res/layout/f_eip.xml | 46 ++----------- app/src/main/res/layout/v_location_button.xml | 38 +++++++++++ .../res/layout/v_location_status_indicator.xml | 49 ++++++++++++++ app/src/main/res/values/strings.xml | 4 +- 12 files changed, 327 insertions(+), 118 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 create mode 100644 app/src/main/res/drawable/cust_button_primary_hard_rect.xml create mode 100644 app/src/main/res/layout/v_location_button.xml create mode 100644 app/src/main/res/layout/v_location_status_indicator.xml diff --git a/app/src/androidTest/legacy/VpnTestController.java b/app/src/androidTest/legacy/VpnTestController.java index e39ebae3..035ca2b0 100644 --- a/app/src/androidTest/legacy/VpnTestController.java +++ b/app/src/androidTest/legacy/VpnTestController.java @@ -35,7 +35,7 @@ public class VpnTestController { } protected Button getVpnButton() { - View button_view = solo.getView(R.id.vpn_main_button); + View button_view = solo.getView(R.id.gateway_location_button); if (button_view != null) return (Button) button_view; else 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 { } } + + } diff --git a/app/src/main/res/drawable/cust_button_primary_hard_rect.xml b/app/src/main/res/drawable/cust_button_primary_hard_rect.xml new file mode 100644 index 00000000..93be5c18 --- /dev/null +++ b/app/src/main/res/drawable/cust_button_primary_hard_rect.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/cust_button_primary_rect.xml b/app/src/main/res/drawable/cust_button_primary_rect.xml index c83d4e62..93be5c18 100644 --- a/app/src/main/res/drawable/cust_button_primary_rect.xml +++ b/app/src/main/res/drawable/cust_button_primary_rect.xml @@ -2,21 +2,18 @@ - - - diff --git a/app/src/main/res/layout-xlarge/f_eip.xml b/app/src/main/res/layout-xlarge/f_eip.xml index d4a51b8d..bef2d635 100644 --- a/app/src/main/res/layout-xlarge/f_eip.xml +++ b/app/src/main/res/layout-xlarge/f_eip.xml @@ -80,53 +80,21 @@ app:layout_constraintTop_toTopOf="@+id/guideline_horizontal_top" app:layout_constraintDimensionRatio="1:1" /> - - - - - + tools:text="SEATTLE" + android:gravity="center_vertical" /> diff --git a/app/src/main/res/layout/f_eip.xml b/app/src/main/res/layout/f_eip.xml index 3309eb5d..8dc1e33b 100644 --- a/app/src/main/res/layout/f_eip.xml +++ b/app/src/main/res/layout/f_eip.xml @@ -82,54 +82,20 @@ app:layout_constraintDimensionRatio="1:1" /> - - - - - + tools:text="SEATTLE" + android:gravity="center_vertical" /> diff --git a/app/src/main/res/layout/v_location_button.xml b/app/src/main/res/layout/v_location_button.xml new file mode 100644 index 00000000..7425231e --- /dev/null +++ b/app/src/main/res/layout/v_location_button.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/v_location_status_indicator.xml b/app/src/main/res/layout/v_location_status_indicator.xml new file mode 100644 index 00000000..97b55917 --- /dev/null +++ b/app/src/main/res/layout/v_location_status_indicator.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 22696c12..b6bdafa8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -155,7 +155,8 @@ Location with best connection Automatic Your traffic is currently routed through: - + Finding best connection… + Reconnecting… Starting bridges for censorship circumvention… Stopping bridges. Using bridges for censorship circumvention. @@ -181,5 +182,4 @@ Hide connection details %s has no internet connection. Please check your WiFi and cellular data settings. - -- cgit v1.2.3