diff options
author | Martin Fietz <Martin.Fietz@gmail.com> | 2016-02-27 23:34:45 +0100 |
---|---|---|
committer | Martin Fietz <Martin.Fietz@gmail.com> | 2016-03-16 20:30:33 +0100 |
commit | 19e1e4afdba724c7b64116111c9c9538480be4f9 (patch) | |
tree | 7583c72a340be32c724feb856710105b2bdd50a0 | |
parent | bb45d82b08906718e5e2dc33d6f1724c6c9e89a2 (diff) | |
download | AntennaPod-19e1e4afdba724c7b64116111c9c9538480be4f9.zip |
Add proxy settings
8 files changed, 542 insertions, 5 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java new file mode 100644 index 000000000..d745bb51c --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java @@ -0,0 +1,323 @@ +package de.danoeh.antennapod.dialog; + +import android.app.Dialog; +import android.content.Context; +import android.content.res.TypedArray; +import android.support.v4.content.ContextCompat; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Patterns; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.afollestad.materialdialogs.internal.MDButton; +import com.squareup.okhttp.Credentials; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.SocketAddress; +import java.util.concurrent.TimeUnit; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; +import de.danoeh.antennapod.core.service.download.ProxyConfig; +import rx.Observable; +import rx.Subscriber; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; + +public class ProxyDialog { + + private static final String TAG = "ProxyDialog"; + + private Context context; + + private MaterialDialog dialog; + + private Spinner spType; + private EditText etHost; + private EditText etPort; + private EditText etUsername; + private EditText etPassword; + + private boolean testSuccessful = false; + private TextView txtvMessage; + private Subscription subscription; + + public ProxyDialog(Context context) { + this.context = context; + } + + public Dialog createDialog() { + dialog = new MaterialDialog.Builder(context) + .title(R.string.pref_proxy_title) + .customView(R.layout.proxy_settings, true) + .positiveText(R.string.proxy_test_label) + .negativeText(R.string.cancel_label) + .onPositive((dialog1, which) -> { + if(!testSuccessful) { + dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false); + test(); + return; + } + String type = (String) ((Spinner) dialog1.findViewById(R.id.spType)).getSelectedItem(); + ProxyConfig proxy; + if(Proxy.Type.valueOf(type) == Proxy.Type.DIRECT) { + proxy = ProxyConfig.direct(); + } else { + String host = etHost.getText().toString(); + String port = etPort.getText().toString(); + String username = etUsername.getText().toString(); + if(TextUtils.isEmpty(username)) { + username = null; + } + String password = etPassword.getText().toString(); + if(TextUtils.isEmpty(password)) { + password = null; + } + int portValue = 0; + if(!TextUtils.isEmpty(port)) { + portValue = Integer.valueOf(port); + } + proxy = ProxyConfig.http(host, portValue, username, password); + } + UserPreferences.setProxyConfig(proxy); + AntennapodHttpClient.reinit(); + dialog.dismiss(); + }) + .onNegative((dialog1, which) -> { + dialog1.dismiss(); + }) + .autoDismiss(false) + .build(); + View view = dialog.getCustomView(); + spType = (Spinner) view.findViewById(R.id.spType); + String[] types = { Proxy.Type.DIRECT.name(), Proxy.Type.HTTP.name() }; + ArrayAdapter<String> adapter = new ArrayAdapter<>(context, + android.R.layout.simple_spinner_item, types); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spType.setAdapter(adapter); + ProxyConfig proxyConfig = UserPreferences.getProxyConfig(); + spType.setSelection(adapter.getPosition(proxyConfig.type.name())); + etHost = (EditText) view.findViewById(R.id.etHost); + if(!TextUtils.isEmpty(proxyConfig.host)) { + etHost.setText(proxyConfig.host); + } + etHost.addTextChangedListener(requireTestOnChange); + etPort = (EditText) view.findViewById(R.id.etPort); + if(proxyConfig.port > 0) { + etPort.setText(String.valueOf(proxyConfig.port)); + } + etPort.addTextChangedListener(requireTestOnChange); + etUsername = (EditText) view.findViewById(R.id.etUsername); + if(!TextUtils.isEmpty(proxyConfig.username)) { + etUsername.setText(proxyConfig.username); + } + etUsername.addTextChangedListener(requireTestOnChange); + etPassword = (EditText) view.findViewById(R.id.etPassword); + if(!TextUtils.isEmpty(proxyConfig.password)) { + etPassword.setText(proxyConfig.username); + } + etPassword.addTextChangedListener(requireTestOnChange); + if(proxyConfig.type == Proxy.Type.DIRECT) { + enableSettings(false); + setTestRequired(false); + } + spType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + enableSettings(position > 0); + setTestRequired(position > 0); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + enableSettings(false); + } + }); + txtvMessage = (TextView) view.findViewById(R.id.txtvMessage); + checkValidity(); + return dialog; + } + + private final TextWatcher requireTestOnChange = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + setTestRequired(true); + } + }; + + private void enableSettings(boolean enable) { + etHost.setEnabled(enable); + etPort.setEnabled(enable); + etUsername.setEnabled(enable); + etPassword.setEnabled(enable); + } + + private boolean checkValidity() { + boolean valid = true; + if(spType.getSelectedItemPosition() > 0) { + valid &= checkHost(); + } + valid &= checkPort(); + return valid; + } + + private boolean checkHost() { + String host = etHost.getText().toString(); + if(host.length() == 0) { + etHost.setError(context.getString(R.string.proxy_host_empty_error)); + return false; + } + if(!"localhost".equals(host) && !Patterns.DOMAIN_NAME.matcher(host).matches()) { + etHost.setError(context.getString(R.string.proxy_host_invalid_error)); + return false; + } + return true; + } + + private boolean checkPort() { + int port = getPort(); + if(port < 0 && port > 65535) { + etPort.setError(context.getString(R.string.proxy_port_invalid_error)); + return false; + } + return true; + } + + private int getPort() { + String port = etPort.getText().toString(); + if(port.length() > 0) { + try { + int portValue = Integer.parseInt(port); + return portValue; + } catch(NumberFormatException e) { + // ignore + } + } + return 0; + } + + private void setTestRequired(boolean required) { + if(required) { + testSuccessful = false; + MDButton button = dialog.getActionButton(DialogAction.POSITIVE); + button.setText(context.getText(R.string.proxy_test_label)); + button.setEnabled(true); + } else { + testSuccessful = true; + MDButton button = dialog.getActionButton(DialogAction.POSITIVE); + button.setText(context.getText(android.R.string.ok)); + button.setEnabled(true); + } + } + + private void test() { + if(subscription != null) { + subscription.unsubscribe(); + } + if(!checkValidity()) { + setTestRequired(true); + return; + } + TypedArray res = context.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary }); + int textColorPrimary = res.getColor(0, 0); + res.recycle(); + String checking = context.getString(R.string.proxy_checking); + txtvMessage.setTextColor(textColorPrimary); + txtvMessage.setText("{fa-circle-o-notch spin} " + checking); + txtvMessage.setVisibility(View.VISIBLE); + subscription = Observable.create(new Observable.OnSubscribe<Response>() { + @Override + public void call(Subscriber<? super Response> subscriber) { + String type = (String) spType.getSelectedItem(); + String host = etHost.getText().toString(); + String port = etPort.getText().toString(); + String username = etUsername.getText().toString(); + String password = etPassword.getText().toString(); + int portValue = 8080; + if(!TextUtils.isEmpty(port)) { + portValue = Integer.valueOf(port); + } + SocketAddress address = InetSocketAddress.createUnresolved(host, portValue); + Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase()); + Proxy proxy = new Proxy(proxyType, address); + OkHttpClient client = AntennapodHttpClient.newHttpClient(); + client.setConnectTimeout(10, TimeUnit.SECONDS); + client.setProxy(proxy); + client.interceptors().clear(); + if(!TextUtils.isEmpty(username)) { + String credentials = Credentials.basic(username, password); + client.interceptors().add(chain -> { + Request request = chain.request().newBuilder() + .header("Proxy-Authorization", credentials).build(); + return chain.proceed(request); + }); + } + Request request = new Request.Builder() + .url("http://www.google.com") + .head() + .build(); + try { + Response response = client.newCall(request).execute(); + subscriber.onNext(response); + } catch(IOException e) { + subscriber.onError(e); + } + subscriber.onCompleted(); + } + }) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + response -> { + int colorId; + String icon; + String result; + if(response.isSuccessful()) { + colorId = R.color.download_success_green; + icon = "{fa-check}"; + result = context.getString(R.string.proxy_test_successful); + } else { + colorId = R.color.download_failed_red; + icon = "{fa-close}"; + result = context.getString(R.string.proxy_test_failed); + } + int color = ContextCompat.getColor(context, colorId); + txtvMessage.setTextColor(color); + String message = String.format("%s %s: %s", icon, result, response.message()); + txtvMessage.setText(message); + setTestRequired(!response.isSuccessful()); + }, + error -> { + String icon = "{fa-close}"; + String result = context.getString(R.string.proxy_test_failed); + int color = ContextCompat.getColor(context, R.color.download_failed_red); + txtvMessage.setTextColor(color); + String message = String.format("%s %s: %s", icon, result, error.getMessage()); + txtvMessage.setText(message); + setTestRequired(true); + } + ); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java index 3f7290e3e..bf9afc2c4 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -58,6 +58,7 @@ import de.danoeh.antennapod.core.util.flattr.FlattrUtils; import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog; import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog; +import de.danoeh.antennapod.dialog.ProxyDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; /** @@ -82,6 +83,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout"; public static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname"; public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify"; + public static final String PREF_PROXY = "prefProxy"; private final PreferenceUI ui; @@ -356,6 +358,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc return false; } ); + ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> { + ProxyDialog dialog = new ProxyDialog(ui.getActivity()); + dialog.createDialog().show(); + return true; + }); ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> { Intent emailIntent = new Intent(Intent.ACTION_SEND); emailIntent.setType("text/plain"); diff --git a/app/src/main/res/layout/proxy_settings.xml b/app/src/main/res/layout/proxy_settings.xml new file mode 100644 index 000000000..983325030 --- /dev/null +++ b/app/src/main/res/layout/proxy_settings.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:orientation="vertical"> + + <TextView + android:id="@+id/txtvType" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/proxy_type_label" + android:textColor="?android:attr/textColorSecondary" /> + + <Spinner + android:id="@+id/spType" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <TextView + android:id="@+id/txtvHost" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/host_label" + android:textColor="?android:attr/textColorSecondary" /> + + <EditText + android:id="@+id/etHost" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:inputType="textUri" + android:hint="www.example.com" /> + + <TextView + android:id="@+id/txtvPort" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/port_label" + android:textColor="?android:attr/textColorSecondary" /> + + <EditText + android:id="@+id/etPort" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="8080" + android:inputType="number" /> + + <TextView + android:id="@+id/txtvUsername" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:singleLine="true" + android:text="@string/username_label" + android:textColor="?android:attr/textColorSecondary" /> + + <EditText + android:id="@+id/etUsername" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/optional_hint" /> + + <TextView + android:id="@+id/txtvPassword" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/password_label" + android:textColor="?android:attr/textColorSecondary" /> + + <EditText + android:id="@+id/etPassword" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/optional_hint" + android:inputType="textPassword" /> + + <com.joanzapata.iconify.widget.IconTextView + android:id="@+id/txtvMessage" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:visibility="invisible" + android:gravity="center"/> + +</LinearLayout> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 3ecd79b1e..b994f463c 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -200,8 +200,11 @@ android:key="prefEnableAutoDownloadWifiFilter" android:title="@string/pref_autodl_wifi_filter_title" android:summary="@string/pref_autodl_wifi_filter_sum"/> - </PreferenceScreen> + <Preference + android:key="prefProxy" + android:summary="@string/pref_proxy_sum" + android:title="@string/pref_proxy_title" /> </PreferenceCategory> diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index ac042de6f..3631f881b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -17,6 +17,7 @@ import org.json.JSONException; import java.io.File; import java.io.IOException; +import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -25,6 +26,7 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver; +import de.danoeh.antennapod.core.service.download.ProxyConfig; import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; @@ -78,6 +80,11 @@ public class UserPreferences { public static final String PREF_ENABLE_AUTODL_ON_BATTERY = "prefEnableAutoDownloadOnBattery"; public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter"; public static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks"; + public static final String PREF_PROXY_TYPE = "prefProxyType"; + public static final String PREF_PROXY_HOST = "prefProxyHost"; + public static final String PREF_PROXY_PORT = "prefProxyPort"; + public static final String PREF_PROXY_USER = "prefProxyUser"; + public static final String PREF_PROXY_PASSWORD = "prefProxyPassword"; // Services public static final String PREF_AUTO_FLATTR = "pref_auto_flattr"; @@ -371,6 +378,42 @@ public class UserPreferences { return TextUtils.split(selectedNetWorks, ","); } + public static void setProxyConfig(ProxyConfig config) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(PREF_PROXY_TYPE, config.type.name()); + if(TextUtils.isEmpty(config.host)) { + editor.remove(PREF_PROXY_HOST); + } else { + editor.putString(PREF_PROXY_HOST, config.host); + } + if(config.port <= 0 || config.port > 65535) { + editor.remove(PREF_PROXY_PORT); + } else { + editor.putInt(PREF_PROXY_PORT, config.port); + } + if(TextUtils.isEmpty(config.username)) { + editor.remove(PREF_PROXY_USER); + } else { + editor.putString(PREF_PROXY_USER, config.username); + } + if(TextUtils.isEmpty(config.password)) { + editor.remove(PREF_PROXY_PASSWORD); + } else { + editor.putString(PREF_PROXY_PASSWORD, config.password); + } + editor.apply(); + } + + public static ProxyConfig getProxyConfig() { + Proxy.Type type = Proxy.Type.valueOf(prefs.getString(PREF_PROXY_TYPE, Proxy.Type.DIRECT.name())); + String host = prefs.getString(PREF_PROXY_HOST, null); + int port = prefs.getInt(PREF_PROXY_PORT, 0); + String username = prefs.getString(PREF_PROXY_USER, null); + String password = prefs.getString(PREF_PROXY_PASSWORD, null); + ProxyConfig config = new ProxyConfig(type, host, port, username, password); + return config; + } + public static boolean shouldResumeAfterCall() { return prefs.getBoolean(PREF_RESUME_AFTER_CALL, true); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java index b23819ef7..5dd1e2dfa 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java @@ -2,8 +2,10 @@ package de.danoeh.antennapod.core.service.download; import android.os.Build; import android.support.annotation.NonNull; +import android.text.TextUtils; import android.util.Log; +import com.squareup.okhttp.Credentials; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; @@ -14,7 +16,10 @@ import java.net.CookieManager; import java.net.CookiePolicy; import java.net.HttpURLConnection; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.net.Socket; +import java.net.SocketAddress; import java.net.URL; import java.security.GeneralSecurityException; import java.util.concurrent.TimeUnit; @@ -23,6 +28,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBWriter; /** @@ -44,12 +50,15 @@ public class AntennapodHttpClient { */ public static synchronized OkHttpClient getHttpClient() { if (httpClient == null) { - httpClient = newHttpClient(); } return httpClient; } + public static synchronized void reinit() { + httpClient = newHttpClient(); + } + /** * Creates a new HTTP client. Most users should just use * getHttpClient() to get the standard AntennaPod client, @@ -69,13 +78,13 @@ public class AntennapodHttpClient { client.networkInterceptors().add(chain -> { Request request = chain.request(); Response response = chain.proceed(request); - if(response.code() == HttpURLConnection.HTTP_MOVED_PERM || + if (response.code() == HttpURLConnection.HTTP_MOVED_PERM || response.code() == StatusLine.HTTP_PERM_REDIRECT) { String location = response.header("Location"); - if(location.startsWith("/")) { // URL is not absolute, but relative + if (location.startsWith("/")) { // URL is not absolute, but relative URL url = request.url(); location = url.getProtocol() + "://" + url.getHost() + location; - } else if(!location.toLowerCase().startsWith("http://") && + } else if (!location.toLowerCase().startsWith("http://") && !location.toLowerCase().startsWith("https://")) { // Reference is relative to current path URL url = request.url(); @@ -106,6 +115,21 @@ public class AntennapodHttpClient { client.setFollowRedirects(true); client.setFollowSslRedirects(true); + ProxyConfig config = UserPreferences.getProxyConfig(); + if (config.type != Proxy.Type.DIRECT) { + int port = config.port > 0 ? config.port : ProxyConfig.DEFAULT_PORT; + SocketAddress address = InetSocketAddress.createUnresolved(config.host, port); + Proxy proxy = new Proxy(config.type, address); + client.setProxy(proxy); + if (!TextUtils.isEmpty(config.username)) { + String credentials = Credentials.basic(config.username, config.password); + client.interceptors().add(chain -> { + Request request = chain.request().newBuilder() + .header("Proxy-Authorization", credentials).build(); + return chain.proceed(request); + }); + } + } if(16 <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < 21) { client.setSslSocketFactory(new CustomSslSocketFactory()); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java new file mode 100644 index 000000000..e886932f2 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java @@ -0,0 +1,32 @@ +package de.danoeh.antennapod.core.service.download; + +import android.support.annotation.Nullable; + +import java.net.Proxy; + +public class ProxyConfig { + + public final Proxy.Type type; + @Nullable public final String host; + @Nullable public final int port; + @Nullable public final String username; + @Nullable public final String password; + + public final static int DEFAULT_PORT = 8080; + + public static ProxyConfig direct() { + return new ProxyConfig(Proxy.Type.DIRECT, null, 0, null, null); + } + + public static ProxyConfig http(String host, int port, String username, String password) { + return new ProxyConfig(Proxy.Type.HTTP, host, port, username, password); + } + + public ProxyConfig(Proxy.Type type, String host, int port, String username, String password) { + this.type = type; + this.host = host; + this.port = port; + this.username = username; + this.password = password; + } +} diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 0d4518a15..f9af78d63 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -387,6 +387,8 @@ <string name="pref_sonic_title">Sonic media player</string> <string name="pref_sonic_message">Use built-in sonic media player as a replacement for Android\'s native mediaplayer and Prestissimo</string> <string name="pref_current_value">Current value: %1$s</string> + <string name="pref_proxy_title">Proxy</string> + <string name="pref_proxy_sum">Set a network proxy</string> <!-- Auto-Flattr dialog --> <string name="auto_flattr_enable">Enable automatic flattring</string> @@ -593,4 +595,17 @@ <string name="stereo_to_mono">Downmix: Stereo to mono</string> <string name="sonic_only">Sonic only</string> + <!-- proxy settings --> + <string name="proxy_type_label">Type</string> + <string name="host_label">Host</string> + <string name="port_label">Port</string> + <string name="optional_hint">(Optional)</string> + <string name="proxy_test_label">Test</string> + <string name="proxy_checking">Checking…</string> + <string name="proxy_test_successful">Test successful</string> + <string name="proxy_test_failed">Test failed</string> + <string name="proxy_host_empty_error">Host must not be empty</string> + <string name="proxy_host_invalid_error">Host not valid UP or domain</string> + <string name="proxy_port_invalid_error">Port not valid</string> + </resources> |