/*
* Tweetings - Twitter client for Android
*
* Copyright (C) 2012 Psiphon
*
* Copyright (C) 2012-2013 RBD Solutions Limited <apps@tweetings.net>
* Copyright (C) 2012 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.dwdesign.tweetings.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.apache.http.HttpHost;
import android.content.Context;
import android.util.Log;
import android.webkit.WebView;
/**
* Utility class for setting WebKit proxy used by Android WebView
*/
public class WebViewProxySettings {
public static void resetProxy(WebView webView) {
final Context context = webView.getContext();
try {
final Object requestQueueObject = getRequestQueue(context);
if (requestQueueObject != null) {
setDeclaredField(requestQueueObject, "mProxyHost", null);
}
} catch (final Exception e) {
Log.e("ProxySettings", "Exception resetting WebKit proxy: " + e.toString());
}
}
public static boolean setProxy(WebView webView, String host, int port) {
final Context context = webView.getContext();
// PSIPHON: added support for Android 4.x WebView proxy
try {
final Class<?> webViewCoreClass = Class.forName("android.webkit.WebViewCore");
final Class<?> proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
if (webViewCoreClass != null && proxyPropertiesClass != null) {
final Method m = webViewCoreClass.getDeclaredMethod("sendStaticMessage", Integer.TYPE, Object.class);
final Constructor<?> c = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE, String.class);
if (m != null && c != null) {
m.setAccessible(true);
c.setAccessible(true);
final Object properties = c.newInstance(host, port, null);
// android.webkit.WebViewCore.EventHub.PROXY_CHANGED = 193;
m.invoke(null, 193, properties);
return true;
}
}
} catch (final Exception e) {
Log.e("ProxySettings",
"Exception setting WebKit proxy through android.net.ProxyProperties: " + e.toString());
}
try {
final Object requestQueueObject = getRequestQueue(context);
if (requestQueueObject != null) {
// Create Proxy config object and set it into request Q
final HttpHost httpHost = new HttpHost(host, port, "http");
setDeclaredField(requestQueueObject, "mProxyHost", httpHost);
// Log.d("Webkit Setted Proxy to: " + host + ":" + port);
return true;
}
} catch (final Exception e) {
Log.e("ProxySettings", "Exception setting WebKit proxy through android.webkit.Network: " + e.toString());
}
return false;
}
private static Object getDeclaredField(Object obj, String name) throws SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
final Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
return f.get(obj);
}
@SuppressWarnings("rawtypes")
private static Object getNetworkInstance(Context context) throws ClassNotFoundException {
final Class networkClass = Class.forName("android.webkit.Network");
return networkClass;
}
private static Object getRequestQueue(Context context) throws Exception {
final Object networkClass = getNetworkInstance(context);
if (networkClass != null) {
final Object networkObj = invokeMethod(networkClass, "getInstance", new Object[] { context }, Context.class);
if (networkObj != null) return getDeclaredField(networkObj, "mRequestQueue");
}
return null;
}
@SuppressWarnings("rawtypes")
private static Object invokeMethod(Object object, String methodName, Object[] params, Class... types)
throws Exception {
final Class<?> c = object instanceof Class ? (Class) object : object.getClass();
if (types != null) {
final Method method = c.getMethod(methodName, types);
return method.invoke(object, params);
} else {
final Method method = c.getMethod(methodName);
return method.invoke(object);
}
}
private static void setDeclaredField(Object obj, String name, Object value) throws SecurityException,
NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
final Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
}