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 {
return Integer.parseInt(port);
} 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);
}
);
}
}