summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java41
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java14
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java11
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java11
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java8
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java15
-rw-r--r--app/src/main/res/layout/d_obfuscation_proxy.xml32
9 files changed, 89 insertions, 47 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 6df26169..b953df1f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -66,7 +66,8 @@ android {
buildConfigField "String", "obfsvpn_port", '"4431"'
buildConfigField "String", "obfsvpn_ip", '"37.218.241.208"'
buildConfigField "String", "obfsvpn_cert", '"k0L4LFg0Wk98v7P66xvgAx2ud+kggvjZX/qul3iFTJGH5X7xSHT+vVL4UZR0WI3SkmDzUg"'
- buildConfigField 'boolean', 'obfsvpn_use_kcp', 'true'
+ // obfsvpn_transport_protocol can be any of "tcp", "kcp" or "quic"
+ buildConfigField "String", 'obfsvpn_transport_protocol', '"kcp"'
// default to UDP usage
buildConfigField 'boolean', 'prefer_udp', 'false'
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java
index 7d12ca70..2e4eec8a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java
@@ -2,11 +2,16 @@ package se.leap.bitmaskclient.base.fragments;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
+import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.KCP;
+import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.QUIC;
+import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.TCP;
import android.app.Dialog;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -14,10 +19,10 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDialogFragment;
import androidx.appcompat.widget.AppCompatButton;
import androidx.appcompat.widget.AppCompatEditText;
+import androidx.appcompat.widget.AppCompatSpinner;
import se.leap.bitmaskclient.base.utils.BuildConfigHelper;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
-import se.leap.bitmaskclient.base.views.IconSwitchEntry;
import se.leap.bitmaskclient.databinding.DObfuscationProxyBinding;
import se.leap.bitmaskclient.eip.GatewaysManager;
@@ -30,7 +35,9 @@ public class ObfuscationProxyDialog extends AppCompatDialogFragment {
AppCompatButton saveButton;
AppCompatButton useDefaultsButton;
AppCompatButton cancelButton;
- IconSwitchEntry kcpSwitch;
+ AppCompatSpinner protocolSpinner;
+ private final String[] protocols = { TCP.toString(), KCP.toString(), QUIC.toString() };
+
@NonNull
@Override
@@ -46,15 +53,29 @@ public class ObfuscationProxyDialog extends AppCompatDialogFragment {
saveButton = binding.buttonSave;
useDefaultsButton = binding.buttonDefaults;
cancelButton = binding.buttonCancel;
- kcpSwitch = binding.kcpSwitch;
+ protocolSpinner = binding.protocolSpinner;
ipField.setText(PreferenceHelper.getObfuscationPinningIP());
portField.setText(PreferenceHelper.getObfuscationPinningPort());
certificateField.setText(PreferenceHelper.getObfuscationPinningCert());
- kcpSwitch.setChecked(PreferenceHelper.getObfuscationPinningKCP());
GatewaysManager gatewaysManager = new GatewaysManager(getContext());
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(binding.getRoot().getContext(), android.R.layout.simple_spinner_item, protocols);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ protocolSpinner.setAdapter(adapter);
+
+ protocolSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ PreferenceHelper.setObfuscationPinningProtocol(protocols[position]);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {}
+ });
+
saveButton.setOnClickListener(v -> {
String ip = TextUtils.isEmpty(ipField.getText()) ? null : ipField.getText().toString();
PreferenceHelper.setObfuscationPinningIP(ip);
@@ -62,7 +83,6 @@ public class ObfuscationProxyDialog extends AppCompatDialogFragment {
PreferenceHelper.setObfuscationPinningPort(port);
String cert = TextUtils.isEmpty(certificateField.getText()) ? null : certificateField.getText().toString();
PreferenceHelper.setObfuscationPinningCert(cert);
- PreferenceHelper.setObfuscationPinningKCP(kcpSwitch.isChecked());
PreferenceHelper.setUseObfuscationPinning(ip != null && port != null && cert != null);
PreferenceHelper.setObfuscationPinningGatewayLocation(gatewaysManager.getLocationNameForIP(ip, v.getContext()));
dismiss();
@@ -73,7 +93,7 @@ public class ObfuscationProxyDialog extends AppCompatDialogFragment {
ipField.setText(BuildConfigHelper.obfsvpnIP());
portField.setText(BuildConfigHelper.obfsvpnPort());
certificateField.setText(BuildConfigHelper.obfsvpnCert());
- kcpSwitch.setChecked(BuildConfigHelper.useKcp());
+ protocolSpinner.setSelection(getIndexForProtocol(BuildConfigHelper.obfsvpnTransportProtocol()));
});
cancelButton.setOnClickListener(v -> {
@@ -85,6 +105,15 @@ public class ObfuscationProxyDialog extends AppCompatDialogFragment {
return builder.create();
}
+ private int getIndexForProtocol(String protocol) {
+ for (int i = 0; i < protocols.length; i++) {
+ if (protocols[i].equals(protocol)) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
@Override
public void onDestroyView() {
super.onDestroyView();
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
index cc6f3077..b8849c4d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
@@ -53,6 +53,7 @@ public interface Constants {
String OBFUSCATION_PINNING_PORT = "obfuscation_pinning_port";
String OBFUSCATION_PINNING_CERT = "obfuscation_pinning_cert";
String OBFUSCATION_PINNING_KCP = "obfuscation_pinning_udp";
+ String OBFUSCATION_PINNING_PROTOCOL = "obfuscation_pinning_protocol";
String OBFUSCATION_PINNING_LOCATION = "obfuscation_pinning_location";
String USE_SYSTEM_PROXY = "usesystemproxy";
String CUSTOM_PROVIDER_DOMAINS = "custom_provider_domains";
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java
index 22af1bfb..22939611 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java
@@ -15,7 +15,7 @@ public class BuildConfigHelper {
String obfsvpnIP();
String obfsvpnPort();
String obfsvpnCert();
- boolean useKcp();
+ String obfsvpnTransportProtocol();
boolean isDefaultBitmask();
}
@@ -26,9 +26,11 @@ public class BuildConfigHelper {
return BuildConfig.obfsvpn_ip != null &&
BuildConfig.obfsvpn_port != null &&
BuildConfig.obfsvpn_cert != null &&
+ BuildConfig.obfsvpn_transport_protocol != null &&
!BuildConfig.obfsvpn_ip.isEmpty() &&
!BuildConfig.obfsvpn_port.isEmpty() &&
- !BuildConfig.obfsvpn_cert.isEmpty();
+ !BuildConfig.obfsvpn_cert.isEmpty() &&
+ !BuildConfig.obfsvpn_transport_protocol.isEmpty();
}
@Override
@@ -47,8 +49,8 @@ public class BuildConfigHelper {
}
@Override
- public boolean useKcp() {
- return BuildConfig.obfsvpn_use_kcp;
+ public String obfsvpnTransportProtocol() {
+ return BuildConfig.obfsvpn_transport_protocol;
}
@Override
@@ -79,8 +81,8 @@ public class BuildConfigHelper {
public static String obfsvpnCert() {
return instance.obfsvpnCert();
}
- public static boolean useKcp() {
- return instance.useKcp();
+ public static String obfsvpnTransportProtocol() {
+ return instance.obfsvpnTransportProtocol();
}
public static boolean isDefaultBitmask() {
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 d2bb4d1b..ba644b91 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
@@ -1,6 +1,7 @@
package se.leap.bitmaskclient.base.utils;
import static android.content.Context.MODE_PRIVATE;
+import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.TCP;
import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_AUTOMATICALLY;
import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_OBFS4;
import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_OBFS4_KCP;
@@ -24,9 +25,9 @@ import static se.leap.bitmaskclient.base.models.Constants.LAST_UPDATE_CHECK;
import static se.leap.bitmaskclient.base.models.Constants.LAST_USED_PROFILE;
import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_CERT;
import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_IP;
-import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_KCP;
import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_LOCATION;
import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_PORT;
+import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_PROTOCOL;
import static se.leap.bitmaskclient.base.models.Constants.PREFERENCES_APP_VERSION;
import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY;
import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP;
@@ -588,12 +589,12 @@ public class PreferenceHelper {
return getString(OBFUSCATION_PINNING_LOCATION, null);
}
- public static Boolean getObfuscationPinningKCP() {
- return getBoolean(OBFUSCATION_PINNING_KCP, false);
+ public static String getObfuscationPinningProtocol() {
+ return getString(OBFUSCATION_PINNING_PROTOCOL, TCP.toString());
}
- public static void setObfuscationPinningKCP(boolean isKCP) {
- putBoolean(OBFUSCATION_PINNING_KCP, isKCP);
+ public static void setObfuscationPinningProtocol(String protocol) {
+ putString(OBFUSCATION_PINNING_PROTOCOL, protocol);
}
public static void setUseIPv6Firewall(boolean useFirewall) {
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 d1ae7c43..783f9124 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -29,15 +29,6 @@ import static se.leap.bitmaskclient.base.models.Constants.OVERLOAD;
import static se.leap.bitmaskclient.base.models.Constants.TIMEZONE;
import static se.leap.bitmaskclient.base.models.Constants.VERSION;
import static se.leap.bitmaskclient.base.models.Transport.createTransportsFrom;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningGatewayLocation;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -294,7 +285,7 @@ public class Gateway {
* In case the transport type is an obfuscation transport, you can pass a Vector of required transport layer protocols.
* This way you can filter for TCP based obfs4 traffic versus KCP based obfs4 traffic.
* @param transportType transport type, e.g. openvpn or obfs4
- * @param obfuscationTransportLayerProtocols filters for _any_ of these transport layer protocols (e.g. TCP or KCP) of a given obfuscation transportType, can be omitted if transportType is OPENVPN.
+ * @param obfuscationTransportLayerProtocols filters for _any_ of these transport layer protocols (e.g. TCP, KCP, QUIC) of a given obfuscation transportType, can be omitted if transportType is OPENVPN.
*
* @return
*/
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 76aece23..16f12e02 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -31,14 +31,14 @@ import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS;
import static se.leap.bitmaskclient.base.models.Constants.TCP;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningProtocol;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseObfs4;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseObfs4Kcp;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePortHopping;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseObfs4Quic;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePortHopping;
import android.content.Context;
import android.util.Log;
@@ -436,7 +436,7 @@ public class GatewaysManager {
try {
Transport[] transports = new Transport[]{
new Transport(OBFS4.toString(),
- new String[]{getObfuscationPinningKCP() ? "kcp" : "tcp"},
+ new String[]{getObfuscationPinningProtocol()},
new String[]{getObfuscationPinningPort()},
getObfuscationPinningCert())};
GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false);
@@ -496,7 +496,7 @@ public class GatewaysManager {
options.put(CERT, getObfuscationPinningCert());
options.put(IAT_MODE, "0");
modelsBridge.options(options);
- modelsBridge.transport(getObfuscationPinningKCP() ? KCP : TCP);
+ modelsBridge.transport(getObfuscationPinningProtocol());
modelsBridge.type(OBFS4.toString());
modelsBridge.host(PINNED_OBFUSCATION_PROXY);
Gateway gateway = new Gateway(modelsEIPService, secrets, modelsBridge, provider.getApiVersion());
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
index f988dfa0..0288ab25 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -21,6 +21,7 @@ import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_H
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
import static se.leap.bitmaskclient.base.models.Constants.KCP;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.base.models.Constants.QUIC;
import static se.leap.bitmaskclient.base.models.Constants.REMOTE;
import static se.leap.bitmaskclient.base.models.Constants.TCP;
import static se.leap.bitmaskclient.base.models.Constants.UDP;
@@ -29,8 +30,8 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningGatewayLocation;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningProtocol;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;
import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning;
@@ -69,7 +70,7 @@ public class VpnConfigGenerator {
private final String obfuscationPinningIP;
private final String obfuscationPinningPort;
private final String obfuscationPinningCert;
- private final boolean obfuscationPinningKCP;
+ private final String obfuscationPinningTransportProtocol;
private final String remoteGatewayIP;
private final String remoteGatewayIPv6;
private final String profileName;
@@ -89,7 +90,7 @@ public class VpnConfigGenerator {
Set<String> excludedApps = null;
boolean useObfuscationPinning;
- boolean obfuscationProxyKCP;
+ String obfuscationProxyTransportProtocol = "";
String obfuscationProxyIP = "";
String obfuscationProxyPort = "";
String obfuscationProxyCert = "";
@@ -110,7 +111,7 @@ public class VpnConfigGenerator {
config.obfuscationProxyIP = getObfuscationPinningIP();
config.obfuscationProxyPort = getObfuscationPinningPort();
config.obfuscationProxyCert = getObfuscationPinningCert();
- config.obfuscationProxyKCP = getObfuscationPinningKCP();
+ config.obfuscationProxyTransportProtocol = getObfuscationPinningProtocol();
}
config.transports = transports;
return config;
@@ -128,7 +129,7 @@ public class VpnConfigGenerator {
this.obfuscationPinningIP = config.obfuscationProxyIP;
this.obfuscationPinningPort = config.obfuscationProxyPort;
this.obfuscationPinningCert = config.obfuscationProxyCert;
- this.obfuscationPinningKCP = config.obfuscationProxyKCP;
+ this.obfuscationPinningTransportProtocol = config.obfuscationProxyTransportProtocol;
this.remoteGatewayIP = config.remoteGatewayIP;
this.remoteGatewayIPv6 = config.remoteGatewayIPv6;
this.transports = config.transports;
@@ -196,7 +197,7 @@ public class VpnConfigGenerator {
String ip = remoteGatewayIP;
if (useObfuscationPinning) {
transport = new Transport(OBFS4.toString(),
- new String[]{obfuscationPinningKCP ? KCP : TCP},
+ new String[]{obfuscationPinningTransportProtocol},
new String[]{obfuscationPinningPort},
obfuscationPinningCert);
ip = obfuscationPinningIP;
@@ -326,7 +327,7 @@ public class VpnConfigGenerator {
return TCP.equals(protocol) || UDP.equals(protocol);
case OBFS4_HOP:
case OBFS4:
- return TCP.equals(protocol) || KCP.equals(protocol);
+ return TCP.equals(protocol) || KCP.equals(protocol) || QUIC.equals(protocol);
}
return false;
}
diff --git a/app/src/main/res/layout/d_obfuscation_proxy.xml b/app/src/main/res/layout/d_obfuscation_proxy.xml
index 7b8fcaa7..03ffb61f 100644
--- a/app/src/main/res/layout/d_obfuscation_proxy.xml
+++ b/app/src/main/res/layout/d_obfuscation_proxy.xml
@@ -57,16 +57,32 @@
android:id="@+id/cert_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
- <se.leap.bitmaskclient.base.views.IconSwitchEntry
- android:id="@+id/kcp_switch"
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:text="KCP"
- app:subtitle="UDP based network protocol"
- app:icon="@drawable/ic_multiple_stop"
- >
-
- </se.leap.bitmaskclient.base.views.IconSwitchEntry>
+ android:text="Network protocol"
+ android:textStyle="bold"
+ android:paddingTop="@dimen/activity_margin"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault" />
+ <androidx.appcompat.widget.LinearLayoutCompat
+ android:id="@+id/protocol_spinner_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="?android:attr/listPreferredItemHeightSmall"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:src="@drawable/ic_multiple_stop"
+ android:padding="@dimen/stdpadding"/>
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/protocol_spinner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:tooltipText="select nework protocol"/>
+ </androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"