Index: src/org/adblockplus/android/configurators/NativeProxyConfigurator.java |
diff --git a/src/org/adblockplus/android/configurators/NativeProxyConfigurator.java b/src/org/adblockplus/android/configurators/NativeProxyConfigurator.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..52bf4873f67278fc3812cc25bd76fd569d9a087d |
--- /dev/null |
+++ b/src/org/adblockplus/android/configurators/NativeProxyConfigurator.java |
@@ -0,0 +1,230 @@ |
+/* |
+ * This file is part of Adblock Plus <http://adblockplus.org/>, |
+ * Copyright (C) 2006-2014 Eyeo GmbH |
+ * |
+ * Adblock Plus is free software: you can redistribute it and/or modify |
+ * it under the terms of the GNU General Public License version 3 as |
+ * published by the Free Software Foundation. |
+ * |
+ * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
+ */ |
+ |
+package org.adblockplus.android.configurators; |
+ |
+import java.net.InetAddress; |
+ |
+import org.adblockplus.android.compat.CompatibilityException; |
+import org.adblockplus.android.compat.LinkProperties; |
+import org.adblockplus.android.compat.ProxyProperties; |
+ |
+import android.content.BroadcastReceiver; |
+import android.content.Context; |
+import android.content.Intent; |
+import android.content.IntentFilter; |
+import android.net.ConnectivityManager; |
+import android.net.NetworkInfo; |
+import android.os.Parcelable; |
+ |
+/** |
+ * Proxy registrator setting native proxy using {@code android.net.LinkProperties} via reflection. |
+ */ |
+public class NativeProxyConfigurator implements ProxyConfigurator |
+{ |
+ private final Context context; |
+ private final WiFiChangeReceiver wiFiChangeReceiver; |
+ private ProxyProperties proxyProperties; |
+ private boolean isRegistered = false; |
+ |
+ public NativeProxyConfigurator(final Context context) |
+ { |
+ this.context = context; |
+ this.wiFiChangeReceiver = new WiFiChangeReceiver(this); |
+ } |
+ |
+ /** |
+ * Reliably checks for setHttpProxy hack using {@code android.net.wifi.LINK_CONFIGURATION_CHANGED}. |
+ * |
+ * @param context |
+ * The context used for querying the {@code ConnectivityManager} |
+ * @return {@code true} if we can set a WiFi proxy using this method |
+ */ |
+ public static boolean canUse(final Context context) |
+ { |
+ try |
+ { |
+ final ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
+ final NetworkInfo ni = conMan.getActiveNetworkInfo(); |
+ |
+ final Object lp; |
+ |
+ // Check if we're currently running on WiFi |
+ if (ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI) |
+ { |
+ // We're using reflection directly here to keep this method self-contained. |
+ lp = conMan.getClass() |
+ .getMethod("getActiveLinkProperties") |
+ .invoke(conMan); |
+ } |
+ else |
+ // We're not running on WiFi so get the last used WiFi link properties |
+ { |
+ // We're using reflection directly here to keep this method self-contained. |
+ lp = conMan.getClass() |
+ .getMethod("getLinkProperties", int.class) |
+ .invoke(conMan, ConnectivityManager.TYPE_WIFI); |
+ } |
+ |
+ if (lp == null) |
+ { |
+ // Is this even possible? |
+ throw new IllegalStateException("No WiFi?"); |
+ } |
+ |
+ context.sendBroadcast( |
+ new Intent("android.net.wifi.LINK_CONFIGURATION_CHANGED") |
+ .putExtra("linkProperties", (Parcelable) lp)); |
+ } |
+ catch (final Throwable t) |
+ { |
+ return false; |
+ } |
+ |
+ return true; |
+ } |
+ |
+ @Override |
+ public boolean initialize() |
+ { |
+ if (canUse(this.context)) |
+ { |
+ this.context.registerReceiver(this.wiFiChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); |
+ return true; |
+ } |
+ |
+ return false; |
+ } |
+ |
+ private boolean sendIntent(final LinkProperties lp, final ProxyProperties proxyProperties) |
+ { |
+ final ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
+ final NetworkInfo ni = conMan.getActiveNetworkInfo(); |
+ |
+ if (ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI) |
+ { |
+ final Intent intent = new Intent("android.net.wifi.LINK_CONFIGURATION_CHANGED"); |
+ |
+ if (lp.isValid()) |
+ { |
+ try |
+ { |
+ lp.setHttpProxy(proxyProperties); |
+ intent.putExtra("linkProperties", (Parcelable) lp.getLinkProperties()); |
+ context.sendBroadcast(intent); |
+ } |
+ catch (final Exception e) |
+ { |
+ // Catch all, again |
+ return false; |
+ } |
+ } |
+ } |
+ |
+ return true; |
+ } |
+ |
+ private boolean registerProxy(final ProxyProperties proxyProperties) |
+ { |
+ try |
+ { |
+ final ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
+ |
+ return this.sendIntent(LinkProperties.getActiveLinkProperties(conMan), proxyProperties); |
+ } |
+ catch (final CompatibilityException e) |
+ { |
+ return false; |
+ } |
+ } |
+ |
+ private boolean reRegisterProxy() |
+ { |
+ return this.registerProxy(this.proxyProperties); |
+ } |
+ |
+ @Override |
+ public boolean registerProxy(final InetAddress address, final int port) |
+ { |
+ this.proxyProperties = new ProxyProperties(address.getHostName(), port, ""); |
+ |
+ return this.isRegistered = this.registerProxy(this.proxyProperties); |
+ } |
+ |
+ @Override |
+ public void unregisterProxy() |
+ { |
+ this.proxyProperties = null; |
+ this.isRegistered = false; |
+ this.registerProxy(this.proxyProperties); |
+ } |
+ |
+ @Override |
+ public void shutdown() |
+ { |
+ this.context.unregisterReceiver(this.wiFiChangeReceiver); |
+ } |
+ |
+ @Override |
+ public ProxyRegistrationType getType() |
+ { |
+ return ProxyRegistrationType.NATIVE; |
+ } |
+ |
+ @Override |
+ public boolean isRegistered() |
+ { |
+ return this.isRegistered; |
+ } |
+ |
+ @Override |
+ public boolean isSticky() |
+ { |
+ return false; |
+ } |
+ |
+ @Override |
+ public String toString() |
+ { |
+ return "[ProxyConfigurator: " + this.getType() + "]"; |
+ } |
+ |
+ private final static class WiFiChangeReceiver extends BroadcastReceiver |
+ { |
+ private final NativeProxyConfigurator configurator; |
+ |
+ private WiFiChangeReceiver(final NativeProxyConfigurator configurator) |
+ { |
+ this.configurator = configurator; |
+ } |
+ |
+ @Override |
+ public void onReceive(final Context context, final Intent intent) |
+ { |
+ if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) |
+ { |
+ final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
+ final NetworkInfo ni = connectivityManager.getActiveNetworkInfo(); |
+ |
+ if (ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI && ni.isAvailable() && ni.isConnected()) |
+ { |
+ this.configurator.reRegisterProxy(); |
+ } |
+ } |
+ } |
+ } |
+} |