Support proxy

This commit is contained in:
seven332 committed 2019-02-03 19:19:50 +08:00
1 parent beeb083cb3
commit 1eaad6f669
16 files changed
+324 -251

No files matched your search

@@ -84,6 +84,7 @@ public class EhApplication extends RecordingApplication {
private final HashMap<Integer, Object> mGlobalStuffMap = new HashMap<>();
private EhCookieStore mEhCookieStore;
private EhClient mEhClient;
private EhProxySelector mEhProxySelector;
private OkHttpClient mOkHttpClient;
private ImageBitmapHelper mImageBitmapHelper;
private Conaco<ImageBitmap> mConaco;
@@ -266,6 +267,15 @@ public class EhApplication extends RecordingApplication {
return application.mEhClient;
}
@NonNull
public static EhProxySelector getEhProxySelector(@NonNull Context context) {
EhApplication application = ((EhApplication) context.getApplicationContext());
if (application.mEhProxySelector == null) {
application.mEhProxySelector = new EhProxySelector();
}
return application.mEhProxySelector;
}
@NonNull
public static OkHttpClient getOkHttpClient(@NonNull Context context) {
EhApplication application = ((EhApplication) context.getApplicationContext());
@@ -276,6 +286,7 @@ public class EhApplication extends RecordingApplication {
.writeTimeout(10, TimeUnit.SECONDS)
.cookieJar(getEhCookieStore(application))
.dns(new EhDns(application))
.proxySelector(getEhProxySelector(application))
.build();
}
return application.mOkHttpClient;
@@ -0,0 +1,106 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer;
import android.text.TextUtils;
import com.hippo.network.InetValidator;
import com.hippo.util.ExceptionUtils;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.Collections;
import java.util.List;
public class EhProxySelector extends ProxySelector {
public static final int TYPE_DIRECT = 0;
public static final int TYPE_SYSTEM = 1;
public static final int TYPE_HTTP = 2;
public static final int TYPE_SOCKS = 3;
private ProxySelector delegation;
private ProxySelector alternative;
EhProxySelector() {
alternative = ProxySelector.getDefault();
if (alternative == null) {
alternative = new NullProxySelector();
}
updateProxy();
}
public void updateProxy() {
switch (Settings.getProxyType()) {
case TYPE_DIRECT:
delegation = new NullProxySelector();
break;
default:
case TYPE_SYSTEM:
delegation = alternative;
break;
case TYPE_HTTP:
case TYPE_SOCKS:
delegation = null;
break;
}
}
@Override
public List<Proxy> select(URI uri) {
int type = Settings.getProxyType();
if (type == TYPE_HTTP || type == TYPE_SOCKS) {
try {
String ip = Settings.getProxyIp();
int port = Settings.getProxyPort();
if (!TextUtils.isEmpty(ip) && InetValidator.isValidInetPort(port)) {
InetAddress inetAddress = InetAddress.getByName(ip);
SocketAddress socketAddress = new InetSocketAddress(inetAddress, port);
return Collections.singletonList(new Proxy(type == TYPE_HTTP ? Proxy.Type.HTTP : Proxy.Type.SOCKS, socketAddress));
}
} catch (Throwable t) {
ExceptionUtils.throwIfFatal(t);
}
}
if (delegation != null) {
return delegation.select(uri);
}
return alternative.select(uri);
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
if (delegation != null) {
delegation.select(uri);
}
}
private static class NullProxySelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
return Collections.singletonList(Proxy.NO_PROXY);
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { }
}
}
@@ -386,72 +386,6 @@ public class Settings {
putString(KEY_EXCLUDED_LANGUAGES, value);
}
private static final String KEY_HATH_PROXY = "hath_proxy";
private static final boolean DEFAULT_HATH_PROXY = false;
public static boolean getHathProxy() {
return getBoolean(KEY_HATH_PROXY, DEFAULT_HATH_PROXY);
}
public static void putHathProxy(boolean value) {
if (value) {
sEhConfig.hahClientIp = Settings.getHathIp();
sEhConfig.hahClientPort = Settings.getHathPort();
sEhConfig.hahClientPasskey = Settings.getHathPasskey();
} else {
sEhConfig.hahClientIp = DEFAULT_HATH_IP;
sEhConfig.hahClientPort = DEFAULT_HATH_PORT;
sEhConfig.hahClientPasskey = DEFAULT_HATH_PASSKEY;
}
sEhConfig.setDirty();
putBoolean(KEY_HATH_PROXY, value);
}
private static final String KEY_HATH_IP = "hath_ip";
private static final String DEFAULT_HATH_IP = null;
public static String getHathIp() {
return getString(KEY_HATH_IP, DEFAULT_HATH_IP);
}
public static void putHathIp(String value) {
if (Settings.getHathProxy()) {
sEhConfig.hahClientIp = value;
sEhConfig.setDirty();
}
putString(KEY_HATH_IP, value);
}
private static final String KEY_HATH_PORT = "hath_port";
private static final int DEFAULT_HATH_PORT = -1;
public static int getHathPort() {
return getInt(KEY_HATH_PORT, DEFAULT_HATH_PORT);
}
public static void putHathPort(int value) {
if (Settings.getHathProxy()) {
sEhConfig.hahClientPort = value;
sEhConfig.setDirty();
}
putInt(KEY_HATH_PORT, value);
}
private static final String KEY_HATH_PASSKEY = "hath_passkey";
private static final String DEFAULT_HATH_PASSKEY = null;
public static String getHathPasskey() {
return getString(KEY_HATH_PASSKEY, DEFAULT_HATH_PASSKEY);
}
public static void putHathPasskey(String value) {
if (Settings.getHathProxy()) {
sEhConfig.hahClientPasskey = value;
sEhConfig.setDirty();
}
putString(KEY_HATH_PASSKEY, value);
}
private static final String KEY_CELLULAR_NETWORK_WARNING = "cellular_network_warning";
private static final boolean DEFAULT_CELLULAR_NETWORK_WARNING = false;
@@ -1066,6 +1000,39 @@ public class Settings {
putString(KEY_APP_LANGUAGE, value);
}
private static final String KEY_PROXY_TYPE = "proxy_type";
private static final int DEFAULT_PROXY_TYPE = EhProxySelector.TYPE_SYSTEM;
public static int getProxyType() {
return getInt(KEY_PROXY_TYPE, DEFAULT_PROXY_TYPE);
}
public static void putProxyType(int value) {
putInt(KEY_PROXY_TYPE, value);
}
private static final String KEY_PROXY_IP = "proxy_ip";
private static final String DEFAULT_PROXY_IP = null;
public static String getProxyIp() {
return getString(KEY_PROXY_IP, DEFAULT_PROXY_IP);
}
public static void putProxyIp(String value) {
putString(KEY_PROXY_IP, value);
}
private static final String KEY_PROXY_PORT = "proxy_port";
private static final int DEFAULT_PROXY_PORT = -1;
public static int getProxyPort() {
return getInt(KEY_PROXY_PORT, DEFAULT_PROXY_PORT);
}
public static void putProxyPort(int value) {
putInt(KEY_PROXY_PORT, value);
}
/********************
****** Guide
********************/
@@ -20,64 +20,71 @@ import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SwitchCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import android.widget.Spinner;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.EhProxySelector;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.Settings;
import com.hippo.network.InetValidator;
import com.hippo.preference.DialogPreference;
import com.hippo.yorozuya.MathUtils;
import com.hippo.yorozuya.ViewUtils;
public class HatHProxyPreference extends DialogPreference implements View.OnClickListener {
public class ProxyPreference extends DialogPreference implements View.OnClickListener {
@Nullable
private SwitchCompat mEnable;
@Nullable
private Spinner mType;
private TextInputLayout mIpInputLayout;
@Nullable
private EditText mIp;
@Nullable
private TextInputLayout mPortInputLayout;
@Nullable
private EditText mPort;
@Nullable
private TextInputLayout mPasskeyInputLayout;
@Nullable
private EditText mPasskey;
public HatHProxyPreference(Context context) {
public ProxyPreference(Context context) {
super(context);
init();
}
public HatHProxyPreference(Context context, AttributeSet attrs) {
public ProxyPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HatHProxyPreference(Context context, AttributeSet attrs, int defStyleAttr) {
public ProxyPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setDialogLayoutResource(R.layout.preference_dialog_hath_proxy);
updateSummary(Settings.getHathProxy(), Settings.getHathIp(), Settings.getHathPort());
setDialogLayoutResource(R.layout.preference_dialog_proxy);
updateSummary(Settings.getProxyType(), Settings.getProxyIp(), Settings.getProxyPort());
}
private void updateSummary(boolean hathProxy, String hathIp, int hathPort) {
if (InetValidator.isValidInet4Address(hathIp) && InetValidator.isValidInetPort(hathPort)) {
private String getProxyTypeText(Context context, int type) {
String[] array = context.getResources().getStringArray(R.array.proxy_types);
return array[MathUtils.clamp(type, 0, array.length - 1)];
}
private void updateSummary(int type, String ip, int port) {
if ((type == EhProxySelector.TYPE_HTTP || type == EhProxySelector.TYPE_SOCKS)
&& (TextUtils.isEmpty(ip) || !InetValidator.isValidInetPort(port)) ) {
type = EhProxySelector.TYPE_SYSTEM;
}
if (type == EhProxySelector.TYPE_HTTP || type == EhProxySelector.TYPE_SOCKS) {
Context context = getContext();
setSummary(context.getString(R.string.settings_eh_hath_proxy_summary_1,
context.getString(hathProxy ? R.string.enabled : R.string.disabled), hathIp, hathPort));
setSummary(context.getString(R.string.settings_advanced_proxy_summary_1,
getProxyTypeText(context, type),
ip,
port));
} else {
setSummary(R.string.settings_eh_hath_proxy_summary_2);
Context context = getContext();
setSummary(context.getString(R.string.settings_advanced_proxy_summary_2,
getProxyTypeText(context, type)));
}
}
@@ -94,73 +101,63 @@ public class HatHProxyPreference extends DialogPreference implements View.OnClic
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(this);
mEnable = (SwitchCompat) ViewUtils.$$(dialog, R.id.enable);
mType = (Spinner) ViewUtils.$$(dialog, R.id.type);
mIpInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.ip_input_layout);
mIp = (EditText) ViewUtils.$$(dialog, R.id.ip);
mPortInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.port_input_layout);
mPort = (EditText) ViewUtils.$$(dialog, R.id.port);
mPasskeyInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.passkey_input_layout);
mPasskey = (EditText) ViewUtils.$$(dialog, R.id.passkey);
mEnable.setChecked(Settings.getHathProxy());
String ip = Settings.getHathIp();
if (!InetValidator.isValidInet4Address(ip)) {
ip = null;
}
int type = Settings.getProxyType();
String[] array = getContext().getResources().getStringArray(R.array.proxy_types);
mType.setSelection(MathUtils.clamp(type, 0, array.length));
mIp.setText(Settings.getProxyIp());
String portString;
int port = Settings.getHathPort();
int port = Settings.getProxyPort();
if (!InetValidator.isValidInetPort(port)) {
portString = null;
} else {
portString = Integer.toString(Settings.getHathPort());
portString = Integer.toString(port);
}
mIp.setText(ip);
mPort.setText(portString);
mPasskey.setText(Settings.getHathPasskey());
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
mEnable = null;
mType = null;
mIpInputLayout = null;
mIp = null;
mPortInputLayout = null;
mPort = null;
mPasskeyInputLayout = null;
mPasskey = null;
}
@Override
public void onClick(View v) {
Dialog dialog = getDialog();
Context context = getContext();
if (null == dialog || null == context || null == mEnable ||
if (null == dialog || null == context || null == mType ||
null == mIpInputLayout || null == mIp ||
null == mPortInputLayout || null == mPort ||
null == mPasskeyInputLayout || null == mPasskey) {
null == mPortInputLayout || null == mPort) {
return;
}
boolean enable = mEnable.isChecked();
int type = mType.getSelectedItemPosition();
String ip = mIp.getText().toString().trim();
if (ip.isEmpty()) {
if (enable) {
if (type == EhProxySelector.TYPE_HTTP || type == EhProxySelector.TYPE_SOCKS) {
mIpInputLayout.setError(context.getString(R.string.text_is_empty));
return;
}
} else if (!InetValidator.isValidInet4Address(ip)) {
mIpInputLayout.setError(context.getString(R.string.domain_not_supported));
return;
} else {
mIpInputLayout.setError(null);
}
mIpInputLayout.setError(null);
int port;
String portString = mPort.getText().toString().trim();
if (portString.isEmpty()) {
if (enable) {
if (type == EhProxySelector.TYPE_HTTP || type == EhProxySelector.TYPE_SOCKS) {
mPortInputLayout.setError(context.getString(R.string.text_is_empty));
return;
} else {
@@ -173,19 +170,19 @@ public class HatHProxyPreference extends DialogPreference implements View.OnClic
port = -1;
}
if (!InetValidator.isValidInetPort(port)) {
mPortInputLayout.setError(context.getString(R.string.invalid_port));
mPortInputLayout.setError(context.getString(R.string.proxy_invalid_port));
return;
}
}
mPortInputLayout.setError(null);
String passkey = mPasskey.getText().toString();
Settings.putProxyType(type);
Settings.putProxyIp(ip);
Settings.putProxyPort(port);
Settings.putHathProxy(enable);
Settings.putHathIp(ip);
Settings.putHathPort(port);
Settings.putHathPasskey(passkey);
updateSummary(type, ip, port);
updateSummary(enable, ip, port);
EhApplication.getEhProxySelector(getContext()).updateProxy();
dialog.dismiss();
}