| 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(); | 
| +        } | 
| +      } | 
| +    } | 
| +  } | 
| +} | 
|  |