| LEFT | RIGHT | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <http://adblockplus.org/>, | 2  * This file is part of Adblock Plus <http://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2014 Eyeo GmbH | 3  * Copyright (C) 2006-2014 Eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 52 import android.os.StrictMode; | 52 import android.os.StrictMode; | 
| 53 import android.preference.PreferenceManager; | 53 import android.preference.PreferenceManager; | 
| 54 import android.support.v4.app.NotificationCompat; | 54 import android.support.v4.app.NotificationCompat; | 
| 55 import android.util.Log; | 55 import android.util.Log; | 
| 56 | 56 | 
| 57 import com.stericson.RootTools.RootTools; | 57 import com.stericson.RootTools.RootTools; | 
| 58 import com.stericson.RootTools.RootToolsException; | 58 import com.stericson.RootTools.RootToolsException; | 
| 59 | 59 | 
| 60 public class ProxyService extends Service implements OnSharedPreferenceChangeLis
     tener | 60 public class ProxyService extends Service implements OnSharedPreferenceChangeLis
     tener | 
| 61 { | 61 { | 
|  | 62   private static final String LOCALHOST = "127.0.0.1"; | 
|  | 63   /** | 
|  | 64    * Indicates that system supports native proxy configuration. | 
|  | 65    */ | 
|  | 66   public static final boolean NATIVE_PROXY_SUPPORTED = Build.VERSION.SDK_INT >= 
     12; // Honeycomb 3.1 | 
|  | 67 | 
| 62   static | 68   static | 
| 63   { | 69   { | 
| 64     RootTools.debugMode = false; | 70     RootTools.debugMode = false; | 
| 65   } | 71   } | 
| 66 | 72 | 
| 67   private final static String TAG = Utils.getTag(ProxyService.class); | 73   private static final String TAG = Utils.getTag(ProxyService.class); | 
| 68 | 74   private static final boolean logRequests = false; | 
| 69   private final static String LOCALHOST = "127.0.0.1"; | 75 | 
| 70   /** | 76   // Do not use 8080 because it is a "dirty" port, Android uses it if something 
     goes wrong | 
| 71    * Indicates that system supports native proxy configuration. |  | 
| 72    */ |  | 
| 73   private final static boolean logRequests = false; |  | 
| 74 |  | 
| 75   public static final boolean NATIVE_PROXY_SUPPORTED = Build.VERSION.SDK_INT >= 
     12; // Honeycomb |  | 
| 76   private final static int NOTRAFFIC_NOTIFICATION_ID = R.string.app_name + 3; |  | 
| 77   final static int ONGOING_NOTIFICATION_ID = R.string.app_name; |  | 
| 78 |  | 
| 79   private final static long POSITION_RIGHT = Build.VERSION.SDK_INT >= Build.VERS
     ION_CODES.GINGERBREAD ? Long.MIN_VALUE : Long.MAX_VALUE; |  | 
| 80 |  | 
| 81   private final static int DEFAULT_TIMEOUT = 3000; |  | 
| 82   private final static int NO_TRAFFIC_TIMEOUT = 5 * 60 * 1000; // 5 minutes |  | 
| 83 |  | 
| 84   // Do not use 8080 because it is a "dirty" port, Android uses it if something |  | 
| 85   // goes wrong |  | 
| 86   // first element is reserved for previously used port | 77   // first element is reserved for previously used port | 
| 87   private final static int[] portVariants = new int[] { -1, 2020, 3030, 4040, 50
     50, 6060, 7070, 9090, 1234, 12345, 4321, 0 }; | 78   private static final int[] portVariants = new int[] {-1, 2020, 3030, 4040, 505
     0, 6060, 7070, 9090, 1234, 12345, 4321, 0}; | 
|  | 79 | 
|  | 80   private static final int DEFAULT_TIMEOUT = 3000; | 
|  | 81   private static final int NO_TRAFFIC_TIMEOUT = 5 * 60 * 1000; // 5 minutes | 
|  | 82 | 
|  | 83   static final int ONGOING_NOTIFICATION_ID = R.string.app_name; | 
|  | 84   private static final long POSITION_RIGHT = Build.VERSION.SDK_INT >= Build.VERS
     ION_CODES.GINGERBREAD ? Long.MIN_VALUE : Long.MAX_VALUE; | 
|  | 85   private static final int NOTRAFFIC_NOTIFICATION_ID = R.string.app_name + 3; | 
| 88 | 86 | 
| 89   /** | 87   /** | 
| 90    * Broadcasted when service starts or stops. | 88    * Broadcasted when service starts or stops. | 
| 91    */ | 89    */ | 
| 92   public final static String BROADCAST_STATE_CHANGED = "org.adblockplus.android.
     service.state"; | 90   public static final String BROADCAST_STATE_CHANGED = "org.adblockplus.android.
     service.state"; | 
| 93   /** | 91   /** | 
| 94    * Broadcasted if proxy fails to start. | 92    * Broadcasted if proxy fails to start. | 
| 95    */ | 93    */ | 
| 96   public final static String BROADCAST_PROXY_FAILED = "org.adblockplus.android.p
     roxy.failure"; | 94   public static final String BROADCAST_PROXY_FAILED = "org.adblockplus.android.p
     roxy.failure"; | 
| 97 | 95 | 
| 98   private final static String IPTABLES_RETURN = " -t nat -m owner --uid-owner {{
     UID}} -A OUTPUT -p tcp -j RETURN\n"; | 96   private static final String IPTABLES_RETURN = " -t nat -m owner --uid-owner {{
     UID}} -A OUTPUT -p tcp -j RETURN\n"; | 
| 99   private final static String IPTABLES_ADD_HTTP = " -t nat -A OUTPUT -p tcp --dp
     ort 80 -j REDIRECT --to {{PORT}}\n"; | 97   private static final String IPTABLES_ADD_HTTP = " -t nat -A OUTPUT -p tcp --dp
     ort 80 -j REDIRECT --to {{PORT}}\n"; | 
| 100 | 98 | 
| 101   boolean hideIcon; | 99   boolean hideIcon; | 
| 102   private Handler notrafficHandler; | 100   private Handler notrafficHandler; | 
| 103 | 101 | 
| 104   protected ProxyServer proxy = null; | 102   protected ProxyServer proxy = null; | 
| 105   protected int port; | 103   protected int port; | 
| 106   private final Properties proxyConfiguration = new Properties(); | 104   private final Properties proxyConfiguration = new Properties(); | 
| 107 | 105 | 
| 108   /** | 106   /** | 
| 109    * Indicates that service is working with root privileges. | 107    * Indicates that service is working with root privileges. | 
| 110    */ | 108    */ | 
| 111   private boolean transparent = false; | 109   private boolean transparent = false; | 
| 112   /** | 110   /** | 
| 113    * Indicates that service has autoconfigured Android proxy settings (version | 111    * Indicates that service has autoconfigured Android proxy settings (version 3
     .1+). | 
| 114    * 3.1+). |  | 
| 115    */ | 112    */ | 
| 116   private boolean nativeProxyAutoConfigured = false; | 113   private boolean nativeProxyAutoConfigured = false; | 
| 117   /** | 114   /** | 
| 118    * Indicates that Android proxy settings are correctly configured (version | 115    * Indicates that Android proxy settings are correctly configured (version 4.1
     .2+ 4.2.2+). | 
| 119    * 4.1.2+ 4.2.2+). |  | 
| 120    */ | 116    */ | 
| 121   private boolean proxyManualyConfigured = false; | 117   private boolean proxyManualyConfigured = false; | 
| 122 | 118 | 
| 123   private String iptables = null; | 119   private String iptables = null; | 
| 124 | 120 | 
| 125   @SuppressLint("NewApi") | 121   @SuppressLint("NewApi") | 
| 126   @Override | 122   @Override | 
| 127   public void onCreate() | 123   public void onCreate() | 
| 128   { | 124   { | 
| 129     super.onCreate(); | 125     super.onCreate(); | 
| 130 | 126 | 
| 131     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) | 127     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) | 
| 132     { | 128     { | 
| 133       // Proxy is running in separate thread, it's just some resolution request | 129       // Proxy is running in separate thread, it's just some resolution request 
     during initialization. | 
| 134       // during initialization. |  | 
| 135       // Not worth spawning a separate thread for this. | 130       // Not worth spawning a separate thread for this. | 
| 136       final StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder
     ().permitNetwork().build(); | 131       final StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder
     ().permitNetwork().build(); | 
| 137       StrictMode.setThreadPolicy(policy); | 132       StrictMode.setThreadPolicy(policy); | 
| 138     } | 133     } | 
| 139 | 134 | 
| 140     // Get port for local proxy | 135     // Get port for local proxy | 
| 141     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreference
     s(this); | 136     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreference
     s(this); | 
| 142     final Resources resources = this.getResources(); | 137     final Resources resources = getResources(); | 
| 143 | 138 | 
| 144     // Try to read user proxy settings | 139     // Try to read user proxy settings | 
| 145     String proxyHost = null; | 140     String proxyHost = null; | 
| 146     String proxyPort = null; | 141     String proxyPort = null; | 
| 147     String proxyExcl = null; | 142     String proxyExcl = null; | 
| 148     String proxyUser = null; | 143     String proxyUser = null; | 
| 149     String proxyPass = null; | 144     String proxyPass = null; | 
| 150 | 145 | 
| 151     if (NATIVE_PROXY_SUPPORTED) | 146     if (NATIVE_PROXY_SUPPORTED) | 
| 152     { | 147     { | 
| 153       // Read system settings | 148       // Read system settings | 
| 154       proxyHost = System.getProperty("http.proxyHost"); | 149       proxyHost = System.getProperty("http.proxyHost"); | 
| 155       proxyPort = System.getProperty("http.proxyPort"); | 150       proxyPort = System.getProperty("http.proxyPort"); | 
| 156       proxyExcl = System.getProperty("http.nonProxyHosts"); | 151       proxyExcl = System.getProperty("http.nonProxyHosts"); | 
| 157 | 152 | 
| 158       Log.d(TAG, "PRX: " + proxyHost + ":" + proxyPort + "(" + proxyExcl + ")"); | 153       Log.d(TAG, "PRX: " + proxyHost + ":" + proxyPort + "(" + proxyExcl + ")"); | 
| 159       // not used but left for future reference | 154       // not used but left for future reference | 
| 160       final String[] px = ProxySettings.getUserProxy(this.getApplicationContext(
     )); | 155       final String[] px = ProxySettings.getUserProxy(getApplicationContext()); | 
| 161       if (px != null) | 156       if (px != null) | 
| 162       { |  | 
| 163         Log.d(TAG, "PRX: " + px[0] + ":" + px[1] + "(" + px[2] + ")"); | 157         Log.d(TAG, "PRX: " + px[0] + ":" + px[1] + "(" + px[2] + ")"); | 
| 164       } |  | 
| 165     } | 158     } | 
| 166     else | 159     else | 
| 167     { | 160     { | 
| 168       // Read application settings | 161       // Read application settings | 
| 169       proxyHost = prefs.getString(this.getString(R.string.pref_proxyhost), null)
     ; | 162       proxyHost = prefs.getString(getString(R.string.pref_proxyhost), null); | 
| 170       proxyPort = prefs.getString(this.getString(R.string.pref_proxyport), null)
     ; | 163       proxyPort = prefs.getString(getString(R.string.pref_proxyport), null); | 
| 171       proxyUser = prefs.getString(this.getString(R.string.pref_proxyuser), null)
     ; | 164       proxyUser = prefs.getString(getString(R.string.pref_proxyuser), null); | 
| 172       proxyPass = prefs.getString(this.getString(R.string.pref_proxypass), null)
     ; | 165       proxyPass = prefs.getString(getString(R.string.pref_proxypass), null); | 
| 173     } | 166     } | 
| 174 | 167 | 
| 175     // Check for root privileges and try to install transparent proxy | 168     // Check for root privileges and try to install transparent proxy | 
| 176     if (RootTools.isAccessGiven()) | 169     if (RootTools.isAccessGiven()) | 
| 177     { | 170     { | 
| 178       try | 171       try | 
| 179       { | 172       { | 
| 180         this.initIptables(); | 173         initIptables(); | 
| 181 | 174 | 
| 182         final StringBuffer cmd = new StringBuffer(); | 175         final StringBuffer cmd = new StringBuffer(); | 
| 183         final int uid = this.getPackageManager().getPackageInfo(this.getPackageN
     ame(), 0).applicationInfo.uid; | 176         final int uid = getPackageManager().getPackageInfo(getPackageName(), 0).
     applicationInfo.uid; | 
| 184         cmd.append(this.iptables); | 177         cmd.append(iptables); | 
| 185         cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid))); | 178         cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid))); | 
| 186         final String rules = cmd.toString(); | 179         final String rules = cmd.toString(); | 
| 187         RootTools.sendShell(rules, DEFAULT_TIMEOUT); | 180         RootTools.sendShell(rules, DEFAULT_TIMEOUT); | 
| 188         this.transparent = true; | 181         transparent = true; | 
| 189       } | 182       } | 
| 190       catch (final FileNotFoundException e) | 183       catch (final FileNotFoundException e) | 
| 191       { | 184       { | 
| 192         // ignore - this is "normal" case | 185         // ignore - this is "normal" case | 
| 193       } | 186       } | 
| 194       catch (final NameNotFoundException e) | 187       catch (final NameNotFoundException e) | 
| 195       { | 188       { | 
| 196         Log.e(TAG, "Failed to initialize iptables", e); | 189         Log.e(TAG, "Failed to initialize iptables", e); | 
| 197       } | 190       } | 
| 198       catch (final IOException e) | 191       catch (final IOException e) | 
| 199       { | 192       { | 
| 200         Log.e(TAG, "Failed to initialize iptables", e); | 193         Log.e(TAG, "Failed to initialize iptables", e); | 
| 201       } | 194       } | 
| 202       catch (final RootToolsException e) | 195       catch (final RootToolsException e) | 
| 203       { | 196       { | 
| 204         Log.e(TAG, "Failed to initialize iptables", e); | 197         Log.e(TAG, "Failed to initialize iptables", e); | 
| 205       } | 198       } | 
| 206       catch (final TimeoutException e) | 199       catch (final TimeoutException e) | 
| 207       { | 200       { | 
| 208         Log.e(TAG, "Failed to initialize iptables", e); | 201         Log.e(TAG, "Failed to initialize iptables", e); | 
| 209       } | 202       } | 
| 210     } | 203     } | 
| 211 | 204 | 
| 212     if (!this.transparent) | 205     if (!transparent) | 
| 213     { | 206     { | 
| 214       // Try to set native proxy | 207       // Try to set native proxy | 
| 215       this.nativeProxyAutoConfigured = ProxySettings.setConnectionProxy(this.get
     ApplicationContext(), LOCALHOST, this.port, ""); | 208       nativeProxyAutoConfigured = ProxySettings.setConnectionProxy(getApplicatio
     nContext(), LOCALHOST, port, ""); | 
| 216 | 209 | 
| 217       if (NATIVE_PROXY_SUPPORTED) | 210       if (NATIVE_PROXY_SUPPORTED) | 
| 218       { | 211       { | 
| 219         this.registerReceiver(this.connectionReceiver, new IntentFilter(Connecti
     vityManager.CONNECTIVITY_ACTION)); | 212         registerReceiver(connectionReceiver, new IntentFilter(ConnectivityManage
     r.CONNECTIVITY_ACTION)); | 
| 220         this.registerReceiver(this.connectionReceiver, new IntentFilter(Proxy.PR
     OXY_CHANGE_ACTION)); | 213         registerReceiver(connectionReceiver, new IntentFilter(Proxy.PROXY_CHANGE
     _ACTION)); | 
| 221       } | 214       } | 
| 222     } | 215     } | 
| 223 | 216 | 
| 224     // Save current native proxy situation. The service is always started on the | 217     // Save current native proxy situation. The service is always started on the
      first run so | 
| 225     // first run so |  | 
| 226     // we will always have a correct value from the box | 218     // we will always have a correct value from the box | 
| 227     final SharedPreferences.Editor editor = prefs.edit(); | 219     final SharedPreferences.Editor editor = prefs.edit(); | 
| 228     editor.putBoolean(this.getString(R.string.pref_proxyautoconfigured), this.tr
     ansparent || this.nativeProxyAutoConfigured); | 220     editor.putBoolean(getString(R.string.pref_proxyautoconfigured), transparent 
     || nativeProxyAutoConfigured); | 
| 229     editor.commit(); | 221     editor.commit(); | 
| 230 | 222 | 
| 231     this.registerReceiver(this.proxyReceiver, new IntentFilter(ProxyService.BROA
     DCAST_PROXY_FAILED)); | 223     registerReceiver(proxyReceiver, new IntentFilter(ProxyService.BROADCAST_PROX
     Y_FAILED)); | 
| 232     this.registerReceiver(this.filterReceiver, new IntentFilter(AdblockPlus.BROA
     DCAST_FILTERING_CHANGE)); | 224     registerReceiver(filterReceiver, new IntentFilter(AdblockPlus.BROADCAST_FILT
     ERING_CHANGE)); | 
| 233     this.registerReceiver(this.filterReceiver, new IntentFilter(AdblockPlus.BROA
     DCAST_FILTER_MATCHES)); | 225     registerReceiver(filterReceiver, new IntentFilter(AdblockPlus.BROADCAST_FILT
     ER_MATCHES)); | 
| 234 | 226 | 
| 235     // Start proxy | 227     // Start proxy | 
| 236     if (this.proxy == null) | 228     if (proxy == null) | 
| 237     { | 229     { | 
| 238       // Select available port and bind to it, use previously selected port by | 230       // Select available port and bind to it, use previously selected port by d
     efault | 
| 239       // default | 231       portVariants[0] = prefs.getInt(getString(R.string.pref_lastport), -1); | 
| 240       portVariants[0] = prefs.getInt(this.getString(R.string.pref_lastport), -1)
     ; |  | 
| 241       ServerSocket listen = null; | 232       ServerSocket listen = null; | 
| 242       String msg = null; | 233       String msg = null; | 
| 243       for (final int p : portVariants) | 234       for (final int p : portVariants) | 
| 244       { | 235       { | 
| 245         if (p < 0) | 236         if (p < 0) | 
| 246         { |  | 
| 247           continue; | 237           continue; | 
| 248         } |  | 
| 249         try | 238         try | 
| 250         { | 239         { | 
| 251           // Fix for #232, bind proxy socket to loopback only | 240           // Fix for #232, bind proxy socket to loopback only | 
| 252           listen = new ServerSocket(p, 1024, InetAddress.getByName(LOCALHOST)); | 241           listen = new ServerSocket(p, 1024, InetAddress.getByName(LOCALHOST)); | 
| 253           this.port = p; | 242           port = p; | 
| 254           break; | 243           break; | 
| 255         } | 244         } | 
| 256         catch (final IOException e) | 245         catch (final IOException e) | 
| 257         { | 246         { | 
| 258           Log.e(TAG, null, e); | 247           Log.e(TAG, null, e); | 
| 259           msg = e.getMessage(); | 248           msg = e.getMessage(); | 
| 260         } | 249         } | 
| 261       } | 250       } | 
| 262       if (listen == null) | 251       if (listen == null) | 
| 263       { | 252       { | 
| 264         this.sendBroadcast(new Intent(BROADCAST_PROXY_FAILED).putExtra("msg", ms
     g)); | 253         sendBroadcast(new Intent(BROADCAST_PROXY_FAILED).putExtra("msg", msg)); | 
| 265         return; | 254         return; | 
| 266       } | 255       } | 
| 267 | 256 | 
| 268       // Save selected port | 257       // Save selected port | 
| 269       editor.putInt(this.getString(R.string.pref_lastport), this.port); | 258       editor.putInt(getString(R.string.pref_lastport), port); | 
| 270       editor.commit(); | 259       editor.commit(); | 
| 271 | 260 | 
| 272       // Initialize proxy | 261       // Initialize proxy | 
| 273       this.proxyConfiguration.put("handler", "main"); | 262       proxyConfiguration.put("handler", "main"); | 
| 274       this.proxyConfiguration.put("main.prefix", ""); | 263       proxyConfiguration.put("main.prefix", ""); | 
| 275       this.proxyConfiguration.put("main.class", "sunlabs.brazil.server.ChainHand
     ler"); | 264       proxyConfiguration.put("main.class", "sunlabs.brazil.server.ChainHandler")
     ; | 
| 276       if (this.transparent) | 265       if (transparent) | 
| 277       { | 266       { | 
| 278         this.proxyConfiguration.put("main.handlers", "urlmodifier adblock"); | 267         proxyConfiguration.put("main.handlers", "urlmodifier adblock"); | 
| 279         this.proxyConfiguration.put("urlmodifier.class", "org.adblockplus.brazil
     .TransparentProxyHandler"); | 268         proxyConfiguration.put("urlmodifier.class", "org.adblockplus.brazil.Tran
     sparentProxyHandler"); | 
| 280       } | 269       } | 
| 281       else | 270       else | 
| 282       { | 271       { | 
| 283         this.proxyConfiguration.put("main.handlers", "https adblock"); | 272         proxyConfiguration.put("main.handlers", "https adblock"); | 
| 284         this.proxyConfiguration.put("https.class", "org.adblockplus.brazil.SSLCo
     nnectionHandler"); | 273         proxyConfiguration.put("https.class", "org.adblockplus.brazil.SSLConnect
     ionHandler"); | 
| 285       } | 274       } | 
| 286       this.proxyConfiguration.put("adblock.class", "org.adblockplus.brazil.Reque
     stHandler"); | 275       proxyConfiguration.put("adblock.class", "org.adblockplus.brazil.RequestHan
     dler"); | 
| 287       if (logRequests) | 276       if (logRequests) | 
| 288       { | 277         proxyConfiguration.put("adblock.proxylog", "yes"); | 
| 289         this.proxyConfiguration.put("adblock.proxylog", "yes"); | 278 | 
| 290       } | 279       configureUserProxy(proxyConfiguration, proxyHost, proxyPort, proxyExcl, pr
     oxyUser, proxyPass); | 
| 291 | 280 | 
| 292       this.configureUserProxy(this.proxyConfiguration, proxyHost, proxyPort, pro
     xyExcl, proxyUser, proxyPass); | 281       proxy = new ProxyServer(); | 
| 293 | 282       proxy.logLevel = Server.LOG_DIAGNOSTIC; | 
| 294       this.proxy = new ProxyServer(); | 283       proxy.setup(listen, proxyConfiguration.getProperty("handler"), proxyConfig
     uration); | 
| 295       this.proxy.logLevel = Server.LOG_DIAGNOSTIC; | 284       proxy.start(); | 
| 296       this.proxy.setup(listen, this.proxyConfiguration.getProperty("handler"), t
     his.proxyConfiguration); | 285     } | 
| 297       this.proxy.start(); | 286 | 
| 298     } | 287     if (transparent) | 
| 299 |  | 
| 300     if (this.transparent) |  | 
| 301     { | 288     { | 
| 302       // Redirect traffic via iptables | 289       // Redirect traffic via iptables | 
| 303       try | 290       try | 
| 304       { | 291       { | 
| 305         final StringBuffer cmd = new StringBuffer(); | 292         final StringBuffer cmd = new StringBuffer(); | 
| 306         cmd.append(this.iptables); | 293         cmd.append(iptables); | 
| 307         cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(this.por
     t))); | 294         cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port))); | 
| 308         final String rules = cmd.toString(); | 295         final String rules = cmd.toString(); | 
| 309         RootTools.sendShell(rules, DEFAULT_TIMEOUT); | 296         RootTools.sendShell(rules, DEFAULT_TIMEOUT); | 
| 310       } | 297       } | 
| 311       catch (final FileNotFoundException e) | 298       catch (final FileNotFoundException e) | 
| 312       { | 299       { | 
| 313         // ignore - this is "normal" case | 300         // ignore - this is "normal" case | 
| 314       } | 301       } | 
| 315       catch (final IOException e) | 302       catch (final IOException e) | 
| 316       { | 303       { | 
| 317         Log.e(TAG, "Failed to initialize iptables", e); | 304         Log.e(TAG, "Failed to initialize iptables", e); | 
| 318       } | 305       } | 
| 319       catch (final RootToolsException e) | 306       catch (final RootToolsException e) | 
| 320       { | 307       { | 
| 321         Log.e(TAG, "Failed to initialize iptables", e); | 308         Log.e(TAG, "Failed to initialize iptables", e); | 
| 322       } | 309       } | 
| 323       catch (final TimeoutException e) | 310       catch (final TimeoutException e) | 
| 324       { | 311       { | 
| 325         Log.e(TAG, "Failed to initialize iptables", e); | 312         Log.e(TAG, "Failed to initialize iptables", e); | 
| 326       } | 313       } | 
| 327     } | 314     } | 
| 328 | 315 | 
| 329     prefs.registerOnSharedPreferenceChangeListener(this); | 316     prefs.registerOnSharedPreferenceChangeListener(this); | 
| 330 | 317 | 
| 331     // Lock service | 318     // Lock service | 
| 332     this.hideIcon = prefs.getBoolean(this.getString(R.string.pref_hideicon), res
     ources.getBoolean(R.bool.def_hideicon)); | 319     hideIcon = prefs.getBoolean(getString(R.string.pref_hideicon), resources.get
     Boolean(R.bool.def_hideicon)); | 
| 333     this.startForeground(ONGOING_NOTIFICATION_ID, this.getNotification()); | 320     startForeground(ONGOING_NOTIFICATION_ID, getNotification()); | 
| 334 | 321 | 
| 335     // If automatic setting of proxy was blocked, check if user has set it | 322     // If automatic setting of proxy was blocked, check if user has set it manua
     lly | 
| 336     // manually | 323     final boolean manual = isManual(); | 
| 337     final boolean manual = this.isManual(); |  | 
| 338     if (manual && NATIVE_PROXY_SUPPORTED) | 324     if (manual && NATIVE_PROXY_SUPPORTED) | 
| 339     { | 325     { | 
| 340       final ConnectivityManager connectivityManager = (ConnectivityManager)this.
     getSystemService(Context.CONNECTIVITY_SERVICE); | 326       final ConnectivityManager connectivityManager = (ConnectivityManager) getS
     ystemService(Context.CONNECTIVITY_SERVICE); | 
| 341       this.updateNoTrafficCheck(connectivityManager); | 327       updateNoTrafficCheck(connectivityManager); | 
| 342     } | 328     } | 
| 343 | 329 | 
| 344     this.sendStateChangedBroadcast(); | 330     sendStateChangedBroadcast(); | 
| 345     Log.i(TAG, "Service started"); | 331     Log.i(TAG, "Service started"); | 
| 346   } | 332   } | 
| 347 | 333 | 
| 348   @Override | 334   @Override | 
| 349   public int onStartCommand(final Intent intent, final int flags, final int star
     tId) | 335   public int onStartCommand(final Intent intent, final int flags, final int star
     tId) | 
| 350   { | 336   { | 
| 351     return START_STICKY; | 337     return START_STICKY; | 
| 352   } | 338   } | 
| 353 | 339 | 
| 354   @Override | 340   @Override | 
| 355   public void onDestroy() | 341   public void onDestroy() | 
| 356   { | 342   { | 
| 357     super.onDestroy(); | 343     super.onDestroy(); | 
| 358 | 344 | 
| 359     this.stopNoTrafficCheck(); | 345     stopNoTrafficCheck(); | 
| 360 | 346 | 
| 361     this.unregisterReceiver(this.filterReceiver); | 347     unregisterReceiver(filterReceiver); | 
| 362     this.unregisterReceiver(this.proxyReceiver); | 348     unregisterReceiver(proxyReceiver); | 
| 363 | 349 | 
| 364     // Stop IP redirecting | 350     // Stop IP redirecting | 
| 365     if (this.transparent) | 351     if (transparent) | 
| 366     { | 352     { | 
| 367       new Thread() | 353       new Thread() | 
| 368       { | 354       { | 
| 369         @Override | 355         @Override | 
| 370         public void run() | 356         public void run() | 
| 371         { | 357         { | 
| 372           try | 358           try | 
| 373           { | 359           { | 
| 374             RootTools.sendShell(ProxyService.this.iptables + " -t nat -F OUTPUT"
     , DEFAULT_TIMEOUT); | 360             RootTools.sendShell(iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT)
     ; | 
| 375           } | 361           } | 
| 376           catch (final Exception e) | 362           catch (final Exception e) | 
| 377           { | 363           { | 
| 378             Log.e(TAG, "Failed to clear iptables", e); | 364             Log.e(TAG, "Failed to clear iptables", e); | 
| 379           } | 365           } | 
| 380         } | 366         } | 
| 381       }.start(); | 367       }.start(); | 
| 382     } | 368     } | 
| 383 | 369 | 
| 384     if (!this.transparent && NATIVE_PROXY_SUPPORTED) | 370     if (!transparent && NATIVE_PROXY_SUPPORTED) | 
| 385     { | 371       unregisterReceiver(connectionReceiver); | 
| 386       this.unregisterReceiver(this.connectionReceiver); |  | 
| 387     } |  | 
| 388 | 372 | 
| 389     // Clear native proxy | 373     // Clear native proxy | 
| 390     if (this.nativeProxyAutoConfigured) | 374     if (nativeProxyAutoConfigured) | 
| 391     { | 375     { | 
| 392       this.clearConnectionProxy(); | 376       clearConnectionProxy(); | 
| 393     } | 377     } | 
| 394 | 378 | 
| 395     this.sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", f
     alse)); | 379     sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", false)
     ); | 
| 396 | 380 | 
| 397     // Stop proxy server | 381     // Stop proxy server | 
| 398     if (this.proxy != null) | 382     if (proxy != null) | 
| 399     { | 383       proxy.close(); | 
| 400       this.proxy.close(); |  | 
| 401     } |  | 
| 402 | 384 | 
| 403     // Release service lock | 385     // Release service lock | 
| 404     this.stopForeground(true); | 386     stopForeground(true); | 
| 405 | 387 | 
| 406     Log.i(TAG, "Service stopped"); | 388     Log.i(TAG, "Service stopped"); | 
| 407   } | 389   } | 
| 408 | 390 | 
| 409   /** | 391   /** | 
| 410    * Restores system proxy settings via native call on Android 3.1+ devices | 392    * Restores system proxy settings via native call on Android 3.1+ devices | 
| 411    * using Java reflection. | 393    * using Java reflection. | 
| 412    */ | 394    */ | 
| 413   private void clearConnectionProxy() | 395   private void clearConnectionProxy() | 
| 414   { | 396   { | 
| 415     final String proxyHost = this.proxyConfiguration.getProperty("adblock.proxyH
     ost"); | 397     final String proxyHost = proxyConfiguration.getProperty("adblock.proxyHost")
     ; | 
| 416     final String proxyPort = this.proxyConfiguration.getProperty("adblock.proxyP
     ort"); | 398     final String proxyPort = proxyConfiguration.getProperty("adblock.proxyPort")
     ; | 
| 417     final String proxyExcl = this.proxyConfiguration.getProperty("adblock.proxyE
     xcl"); | 399     final String proxyExcl = proxyConfiguration.getProperty("adblock.proxyExcl")
     ; | 
| 418     int port = 0; | 400     int port = 0; | 
| 419     try | 401     try | 
| 420     { | 402     { | 
| 421       if (proxyHost != null) | 403       if (proxyHost != null) | 
| 422       { |  | 
| 423         port = Integer.valueOf(proxyPort); | 404         port = Integer.valueOf(proxyPort); | 
| 424       } |  | 
| 425     } | 405     } | 
| 426     catch (final NumberFormatException e) | 406     catch (final NumberFormatException e) | 
| 427     { | 407     { | 
| 428       Log.e(TAG, "Bad port setting", e); | 408       Log.e(TAG, "Bad port setting", e); | 
| 429     } | 409     } | 
| 430     ProxySettings.setConnectionProxy(this.getApplicationContext(), proxyHost, po
     rt, proxyExcl); | 410     ProxySettings.setConnectionProxy(getApplicationContext(), proxyHost, port, p
     roxyExcl); | 
| 431   } | 411   } | 
| 432 | 412 | 
| 433   /** | 413   /** | 
| 434    * Sets user proxy settings in proxy service properties. | 414    * Sets user proxy settings in proxy service properties. | 
| 435    */ | 415    */ | 
| 436   private void configureUserProxy(final Properties config, final String proxyHos
     t, final String proxyPort, final String proxyExcl, | 416   private void configureUserProxy(final Properties config, final String proxyHos
     t, final String proxyPort, final String proxyExcl, final String proxyUser, final
      String proxyPass) | 
| 437       final String proxyUser, final String proxyPass) |  | 
| 438   { | 417   { | 
| 439     // Clean previous settings | 418     // Clean previous settings | 
| 440     config.remove("adblock.proxyHost"); | 419     config.remove("adblock.proxyHost"); | 
| 441     config.remove("adblock.proxyPort"); | 420     config.remove("adblock.proxyPort"); | 
| 442     config.remove("adblock.auth"); | 421     config.remove("adblock.auth"); | 
| 443     config.remove("adblock.proxyExcl"); | 422     config.remove("adblock.proxyExcl"); | 
| 444     if (!this.transparent) | 423     if (!transparent) | 
| 445     { | 424     { | 
| 446       config.remove("https.proxyHost"); | 425       config.remove("https.proxyHost"); | 
| 447       config.remove("https.proxyPort"); | 426       config.remove("https.proxyPort"); | 
| 448       config.remove("https.auth"); | 427       config.remove("https.auth"); | 
| 449     } | 428     } | 
| 450 | 429 | 
| 451     if (this.nativeProxyAutoConfigured) | 430     if (nativeProxyAutoConfigured) | 
| 452     { | 431       passProxySettings(proxyHost, proxyPort, proxyExcl); | 
| 453       this.passProxySettings(proxyHost, proxyPort, proxyExcl); |  | 
| 454     } |  | 
| 455 | 432 | 
| 456     // Check if there are any settings | 433     // Check if there are any settings | 
| 457     if (proxyHost == null || "".equals(proxyHost)) | 434     if (proxyHost == null || "".equals(proxyHost)) | 
| 458     { |  | 
| 459       return; | 435       return; | 
| 460     } |  | 
| 461 | 436 | 
| 462     // Check for dirty proxy settings - this indicated previous crash: | 437     // Check for dirty proxy settings - this indicated previous crash: | 
| 463     // proxy points to ourselves | 438     // proxy points to ourselves | 
| 464     // proxy port is null, 0 or not a number | 439     // proxy port is null, 0 or not a number | 
| 465     // proxy is 127.0.0.1:8080 | 440     // proxy is 127.0.0.1:8080 | 
| 466     if (proxyPort == null) | 441     if (proxyPort == null) | 
| 467     { |  | 
| 468       return; | 442       return; | 
| 469     } |  | 
| 470     int p = 0; | 443     int p = 0; | 
| 471     try | 444     try | 
| 472     { | 445     { | 
| 473       p = Integer.valueOf(proxyPort); | 446       p = Integer.valueOf(proxyPort); | 
| 474     } | 447     } | 
| 475     catch (final NumberFormatException e) | 448     catch (final NumberFormatException e) | 
| 476     { | 449     { | 
| 477       return; | 450       return; | 
| 478     } | 451     } | 
| 479     if (p == 0 || isLocalHost(proxyHost) && (p == this.port || p == 8080)) | 452     if (p == 0 || isLocalHost(proxyHost) && (p == port || p == 8080)) | 
| 480     { | 453     { | 
| 481       if (this.nativeProxyAutoConfigured) | 454       if (nativeProxyAutoConfigured) | 
| 482       { | 455         passProxySettings(null, null, null); | 
| 483         this.passProxySettings(null, null, null); |  | 
| 484       } |  | 
| 485       return; | 456       return; | 
| 486     } | 457     } | 
| 487 | 458 | 
| 488     config.put("adblock.proxyHost", proxyHost); | 459     config.put("adblock.proxyHost", proxyHost); | 
| 489     config.put("adblock.proxyPort", proxyPort); | 460     config.put("adblock.proxyPort", proxyPort); | 
| 490     if (!this.transparent) | 461     if (!transparent) | 
| 491     { | 462     { | 
| 492       config.put("https.proxyHost", proxyHost); | 463       config.put("https.proxyHost", proxyHost); | 
| 493       config.put("https.proxyPort", proxyPort); | 464       config.put("https.proxyPort", proxyPort); | 
| 494     } | 465     } | 
| 495 | 466 | 
| 496     // TODO Not implemented in our proxy but needed to restore settings | 467     // TODO Not implemented in our proxy but needed to restore settings | 
| 497     if (proxyExcl != null) | 468     if (proxyExcl != null) | 
| 498     { |  | 
| 499       config.put("adblock.proxyExcl", proxyExcl); | 469       config.put("adblock.proxyExcl", proxyExcl); | 
| 500     } |  | 
| 501 | 470 | 
| 502     if (proxyUser != null && !"".equals(proxyUser) && proxyPass != null && !"".e
     quals(proxyPass)) | 471     if (proxyUser != null && !"".equals(proxyUser) && proxyPass != null && !"".e
     quals(proxyPass)) | 
| 503     { | 472     { | 
| 504       // Base64 encode user:password | 473       // Base64 encode user:password | 
| 505       final String proxyAuth = "Basic " + new String(Base64.encode(proxyUser + "
     :" + proxyPass)); | 474       final String proxyAuth = "Basic " + new String(Base64.encode(proxyUser + "
     :" + proxyPass)); | 
| 506       config.put("adblock.auth", proxyAuth); | 475       config.put("adblock.auth", proxyAuth); | 
| 507       if (!this.transparent) | 476       if (!transparent) | 
| 508       { |  | 
| 509         config.put("https.auth", proxyAuth); | 477         config.put("https.auth", proxyAuth); | 
| 510       } |  | 
| 511     } | 478     } | 
| 512   } | 479   } | 
| 513 | 480 | 
| 514   private void passProxySettings(final String proxyHost, final String proxyPort,
      final String proxyExcl) | 481   private void passProxySettings(final String proxyHost, final String proxyPort,
      final String proxyExcl) | 
| 515   { | 482   { | 
| 516     try | 483     try | 
| 517     { | 484     { | 
| 518       final CrashHandler handler = (CrashHandler)Thread.getDefaultUncaughtExcept
     ionHandler(); | 485       final CrashHandler handler = (CrashHandler) Thread.getDefaultUncaughtExcep
     tionHandler(); | 
| 519       handler.saveProxySettings(proxyHost, proxyPort, proxyExcl); | 486       handler.saveProxySettings(proxyHost, proxyPort, proxyExcl); | 
| 520     } | 487     } | 
| 521     catch (final ClassCastException e) | 488     catch (final ClassCastException e) | 
| 522     { | 489     { | 
| 523       // ignore - default handler in use | 490       // ignore - default handler in use | 
| 524     } | 491     } | 
| 525   } | 492   } | 
| 526 | 493 | 
| 527   @Override | 494   @Override | 
| 528   public void onSharedPreferenceChanged(final SharedPreferences sharedPreference
     s, final String key) | 495   public void onSharedPreferenceChanged(final SharedPreferences sharedPreference
     s, final String key) | 
| 529   { | 496   { | 
| 530     if (!NATIVE_PROXY_SUPPORTED) | 497     if (!NATIVE_PROXY_SUPPORTED) | 
| 531     { | 498     { | 
| 532       final String ketHost = this.getString(R.string.pref_proxyhost); | 499       final String ketHost = getString(R.string.pref_proxyhost); | 
| 533       final String keyPort = this.getString(R.string.pref_proxyport); | 500       final String keyPort = getString(R.string.pref_proxyport); | 
| 534       final String keyUser = this.getString(R.string.pref_proxyuser); | 501       final String keyUser = getString(R.string.pref_proxyuser); | 
| 535       final String keyPass = this.getString(R.string.pref_proxypass); | 502       final String keyPass = getString(R.string.pref_proxypass); | 
| 536       if (key.equals(ketHost) || key.equals(keyPort) || key.equals(keyUser) || k
     ey.equals(keyPass)) | 503       if (key.equals(ketHost) || key.equals(keyPort) || key.equals(keyUser) || k
     ey.equals(keyPass)) | 
| 537       { | 504       { | 
| 538         final String proxyHost = sharedPreferences.getString(ketHost, null); | 505         final String proxyHost = sharedPreferences.getString(ketHost, null); | 
| 539         final String proxyPort = sharedPreferences.getString(keyPort, null); | 506         final String proxyPort = sharedPreferences.getString(keyPort, null); | 
| 540         final String proxyUser = sharedPreferences.getString(keyUser, null); | 507         final String proxyUser = sharedPreferences.getString(keyUser, null); | 
| 541         final String proxyPass = sharedPreferences.getString(keyPass, null); | 508         final String proxyPass = sharedPreferences.getString(keyPass, null); | 
| 542         if (this.proxy != null) | 509         if (proxy != null) | 
| 543         { | 510         { | 
| 544           this.configureUserProxy(this.proxyConfiguration, proxyHost, proxyPort,
      null, proxyUser, proxyPass); | 511           configureUserProxy(proxyConfiguration, proxyHost, proxyPort, null, pro
     xyUser, proxyPass); | 
| 545           this.proxy.restart(this.proxyConfiguration.getProperty("handler")); | 512           proxy.restart(proxyConfiguration.getProperty("handler")); | 
| 546         } | 513         } | 
| 547       } | 514       } | 
| 548     } | 515     } | 
| 549   } | 516   } | 
| 550 | 517 | 
| 551   public boolean isTransparent() | 518   public boolean isTransparent() | 
| 552   { | 519   { | 
| 553     return this.transparent; | 520     return transparent; | 
| 554   } | 521   } | 
| 555 | 522 | 
| 556   public boolean isNativeProxyAutoConfigured() | 523   public boolean isNativeProxyAutoConfigured() | 
| 557   { | 524   { | 
| 558     return this.nativeProxyAutoConfigured; | 525     return nativeProxyAutoConfigured; | 
| 559   } | 526   } | 
| 560 | 527 | 
| 561   /** | 528   /** | 
| 562    * Checks if user has to set proxy settings manually | 529    * Checks if user has to set proxy settings manually | 
| 563    */ | 530    */ | 
| 564   public boolean isManual() | 531   public boolean isManual() | 
| 565   { | 532   { | 
| 566     return !this.transparent && !this.nativeProxyAutoConfigured; | 533     return !transparent && !nativeProxyAutoConfigured; | 
| 567   } | 534   } | 
| 568 | 535 | 
| 569   /** | 536   /** | 
| 570    * Checks whether traffic check is pending | 537    * Checks whether traffic check is pending | 
| 571    */ | 538    */ | 
| 572   public boolean noTraffic() | 539   public boolean noTraffic() | 
| 573   { | 540   { | 
| 574     return this.notrafficHandler != null; | 541     return notrafficHandler != null; | 
| 575   } | 542   } | 
| 576 | 543 | 
| 577   /** | 544   /** | 
| 578    * Checks if specified host is local. | 545    * Checks if specified host is local. | 
| 579    */ | 546    */ | 
| 580   private static final boolean isLocalHost(final String host) | 547   private static final boolean isLocalHost(final String host) | 
| 581   { | 548   { | 
| 582     if (host == null) | 549     if (host == null) | 
| 583     { |  | 
| 584       return false; | 550       return false; | 
| 585     } |  | 
| 586 | 551 | 
| 587     try | 552     try | 
| 588     { | 553     { | 
| 589       if (host.equalsIgnoreCase("localhost")) | 554       if (host.equalsIgnoreCase("localhost")) | 
| 590       { |  | 
| 591         return true; | 555         return true; | 
| 592       } |  | 
| 593 | 556 | 
| 594       final String className = "android.net.NetworkUtils"; | 557       final String className = "android.net.NetworkUtils"; | 
| 595       final Class<?> c = Class.forName(className); | 558       final Class<?> c = Class.forName(className); | 
| 596       /* | 559       /* | 
| 597        * InetAddress address = NetworkUtils.numericToInetAddress(host); | 560        * InetAddress address = NetworkUtils.numericToInetAddress(host); | 
| 598        */ | 561        */ | 
| 599       final Method method = c.getMethod("numericToInetAddress", String.class); | 562       final Method method = c.getMethod("numericToInetAddress", String.class); | 
| 600       final InetAddress address = (InetAddress)method.invoke(null, host); | 563       final InetAddress address = (InetAddress) method.invoke(null, host); | 
| 601 | 564 | 
| 602       if (address.isLoopbackAddress()) | 565       if (address.isLoopbackAddress()) | 
| 603       { |  | 
| 604         return true; | 566         return true; | 
| 605       } |  | 
| 606     } | 567     } | 
| 607     catch (final Exception e) | 568     catch (final Exception e) | 
| 608     { | 569     { | 
| 609       Log.w(TAG, null, e); | 570       Log.w(TAG, null, e); | 
| 610     } | 571     } | 
| 611     return false; | 572     return false; | 
| 612   } | 573   } | 
| 613 | 574 | 
| 614   /** | 575   /** | 
| 615    * Initializes iptables executable. | 576    * Initializes iptables executable. | 
| 616    * | 577    * | 
| 617    * @throws FileNotFoundException | 578    * @throws FileNotFoundException | 
| 618    *           If iptables initialization failed due to provided reasons. | 579    *           If iptables initialization failed due to provided reasons. | 
| 619    */ | 580    */ | 
| 620   private void initIptables() throws IOException, RootToolsException, TimeoutExc
     eption, FileNotFoundException | 581   private void initIptables() throws IOException, RootToolsException, TimeoutExc
     eption, FileNotFoundException | 
| 621   { | 582   { | 
| 622     if (!RootTools.isAccessGiven()) | 583     if (!RootTools.isAccessGiven()) | 
| 623     { |  | 
| 624       throw new FileNotFoundException("No root access"); | 584       throw new FileNotFoundException("No root access"); | 
| 625     } | 585 | 
| 626 | 586     final File ipt = getFileStreamPath("iptables"); | 
| 627     final File ipt = this.getFileStreamPath("iptables"); |  | 
| 628 | 587 | 
| 629     if (!ipt.exists()) | 588     if (!ipt.exists()) | 
| 630     { | 589     { | 
| 631       Log.e(TAG, "No iptables excutable found"); | 590       Log.e(TAG, "No iptables excutable found"); | 
| 632       throw new FileNotFoundException("No iptables executable"); | 591       throw new FileNotFoundException("No iptables executable"); | 
| 633     } | 592     } | 
| 634 | 593 | 
| 635     final String path = ipt.getAbsolutePath(); | 594     final String path = ipt.getAbsolutePath(); | 
| 636 | 595 | 
| 637     RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); | 596     RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT); | 
| 638 | 597 | 
| 639     boolean compatible = false; | 598     boolean compatible = false; | 
| 640     boolean version = false; | 599     boolean version = false; | 
| 641 | 600 | 
| 642     final String command = path + " --version\n" + path + " -L -t nat -n\n"; | 601     final String command = path + " --version\n" + path + " -L -t nat -n\n"; | 
| 643 | 602 | 
| 644     final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); | 603     final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT); | 
| 645     for (final String line : result) | 604     for (final String line : result) | 
| 646     { | 605     { | 
| 647       if (line.contains("OUTPUT")) | 606       if (line.contains("OUTPUT")) | 
| 648       { |  | 
| 649         compatible = true; | 607         compatible = true; | 
| 650       } |  | 
| 651       if (line.contains("v1.4.")) | 608       if (line.contains("v1.4.")) | 
| 652       { |  | 
| 653         version = true; | 609         version = true; | 
| 654       } |  | 
| 655     } | 610     } | 
| 656 | 611 | 
| 657     if (!compatible || !version) | 612     if (!compatible || !version) | 
| 658     { | 613     { | 
| 659       Log.e(TAG, "Incompatible iptables excutable"); | 614       Log.e(TAG, "Incompatible iptables excutable"); | 
| 660       throw new FileNotFoundException("Incompatible iptables excutable"); | 615       throw new FileNotFoundException("Incompatible iptables excutable"); | 
| 661     } | 616     } | 
| 662 | 617 | 
| 663     this.iptables = path; | 618     iptables = path; | 
| 664   } | 619   } | 
| 665 | 620 | 
| 666   public List<String> getIptablesOutput() | 621   public List<String> getIptablesOutput() | 
| 667   { | 622   { | 
| 668     if (this.iptables == null) | 623     if (iptables == null) | 
| 669     { |  | 
| 670       return null; | 624       return null; | 
| 671     } | 625 | 
| 672 | 626     final String command = iptables + " -L -t nat -n\n"; | 
| 673     final String command = this.iptables + " -L -t nat -n\n"; |  | 
| 674     try | 627     try | 
| 675     { | 628     { | 
| 676       return RootTools.sendShell(command, DEFAULT_TIMEOUT); | 629       return RootTools.sendShell(command, DEFAULT_TIMEOUT); | 
| 677     } | 630     } | 
| 678     catch (final Exception e) | 631     catch (final Exception e) | 
| 679     { | 632     { | 
| 680       Log.e(TAG, "Failed to get iptables configuration", e); | 633       Log.e(TAG, "Failed to get iptables configuration", e); | 
| 681       return null; | 634       return null; | 
| 682     } | 635     } | 
| 683   } | 636   } | 
| 684 | 637 | 
| 685   /** | 638   /** | 
| 686    * Raises or removes no traffic notification based on current link proxy | 639    * Raises or removes no traffic notification based on current link proxy | 
| 687    * settings | 640    * settings | 
| 688    */ | 641    */ | 
| 689   private void updateNoTrafficCheck(final ConnectivityManager connectivityManage
     r) | 642   private void updateNoTrafficCheck(final ConnectivityManager connectivityManage
     r) | 
| 690   { | 643   { | 
| 691     try | 644     try | 
| 692     { | 645     { | 
| 693       final Object pp = ProxySettings.getActiveLinkProxy(connectivityManager); | 646       final Object pp = ProxySettings.getActiveLinkProxy(connectivityManager); | 
| 694       final String[] userProxy = ProxySettings.getUserProxy(pp); | 647       final String[] userProxy = ProxySettings.getUserProxy(pp); | 
| 695       if (userProxy != null) | 648       if (userProxy != null) | 
| 696       { |  | 
| 697         Log.i(TAG, "Proxy settings: " + userProxy[0] + ":" + userProxy[1] + "(" 
     + userProxy[2] + ")"); | 649         Log.i(TAG, "Proxy settings: " + userProxy[0] + ":" + userProxy[1] + "(" 
     + userProxy[2] + ")"); | 
| 698       } | 650       updateNoTrafficCheck(userProxy); | 
| 699       this.updateNoTrafficCheck(userProxy); |  | 
| 700     } | 651     } | 
| 701     catch (final Exception e) | 652     catch (final Exception e) | 
| 702     { | 653     { | 
| 703       // This should not happen | 654       // This should not happen | 
| 704       Log.e(TAG, null, e); | 655       Log.e(TAG, null, e); | 
| 705     } | 656     } | 
| 706   } | 657   } | 
| 707 | 658 | 
| 708   /** | 659   /** | 
| 709    * Raises or removes no traffic notification based on the user proxy settings | 660    * Raises or removes no traffic notification based on the user proxy settings | 
| 710    */ | 661    */ | 
| 711   private void updateNoTrafficCheck(final String[] userProxy) | 662   private void updateNoTrafficCheck(final String[] userProxy) | 
| 712   { | 663   { | 
| 713     final boolean ourProxy = userProxy != null && isLocalHost(userProxy[0]) && I
     nteger.valueOf(userProxy[1]) == this.port; | 664     final boolean ourProxy = userProxy != null && isLocalHost(userProxy[0]) && I
     nteger.valueOf(userProxy[1]) == port; | 
| 714     if (ourProxy != this.proxyManualyConfigured) | 665     if (ourProxy != proxyManualyConfigured) | 
| 715     { | 666     { | 
| 716       this.proxyManualyConfigured = ourProxy; | 667       proxyManualyConfigured = ourProxy; | 
| 717       this.sendStateChangedBroadcast(); | 668       sendStateChangedBroadcast(); | 
| 718     } | 669     } | 
| 719     if (ourProxy) | 670     if (ourProxy) | 
| 720     { | 671     { | 
| 721       this.stopNoTrafficCheck(); | 672       stopNoTrafficCheck(); | 
| 722     } | 673     } | 
| 723     else | 674     else | 
| 724     { | 675     { | 
| 725       // Initiate no traffic check | 676       // Initiate no traffic check | 
| 726       this.notrafficHandler = new Handler(); | 677       notrafficHandler = new Handler(); | 
| 727       this.notrafficHandler.postDelayed(this.noTraffic, NO_TRAFFIC_TIMEOUT); | 678       notrafficHandler.postDelayed(noTraffic, NO_TRAFFIC_TIMEOUT); | 
| 728     } | 679     } | 
| 729     final NotificationManager notificationManager = (NotificationManager)this.ge
     tSystemService(NOTIFICATION_SERVICE); | 680     final NotificationManager notificationManager = (NotificationManager) getSys
     temService(NOTIFICATION_SERVICE); | 
| 730     notificationManager.notify(ONGOING_NOTIFICATION_ID, this.getNotification()); | 681     notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()); | 
| 731   } | 682   } | 
| 732 | 683 | 
| 733   /** | 684   /** | 
| 734    * Stops no traffic check and resets notification message. | 685    * Stops no traffic check and resets notification message. | 
| 735    */ | 686    */ | 
| 736   private void stopNoTrafficCheck() | 687   private void stopNoTrafficCheck() | 
| 737   { | 688   { | 
| 738     if (this.notrafficHandler != null) | 689     if (notrafficHandler != null) | 
| 739     { | 690     { | 
| 740       this.notrafficHandler.removeCallbacks(this.noTraffic); | 691       notrafficHandler.removeCallbacks(noTraffic); | 
| 741       this.sendStateChangedBroadcast(); | 692       sendStateChangedBroadcast(); | 
| 742       final NotificationManager notificationManager = (NotificationManager)this.
     getSystemService(NOTIFICATION_SERVICE); | 693       final NotificationManager notificationManager = (NotificationManager) getS
     ystemService(NOTIFICATION_SERVICE); | 
| 743       notificationManager.notify(ONGOING_NOTIFICATION_ID, this.getNotification()
     ); | 694       notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()); | 
| 744       notificationManager.cancel(NOTRAFFIC_NOTIFICATION_ID); | 695       notificationManager.cancel(NOTRAFFIC_NOTIFICATION_ID); | 
| 745     } | 696     } | 
| 746     this.notrafficHandler = null; | 697     notrafficHandler = null; | 
| 747   } | 698   } | 
| 748 | 699 | 
| 749   @SuppressLint("NewApi") | 700   @SuppressLint("NewApi") | 
| 750   private Notification getNotification() | 701   private Notification getNotification() | 
| 751   { | 702   { | 
| 752     final boolean filtering = AdblockPlus.getApplication().isFilteringEnabled(); | 703     final boolean filtering = AdblockPlus.getApplication().isFilteringEnabled(); | 
| 753 | 704 | 
| 754     int msgId = R.string.notif_waiting; | 705     int msgId = R.string.notif_waiting; | 
| 755     if (this.nativeProxyAutoConfigured || this.proxyManualyConfigured) | 706     if (nativeProxyAutoConfigured || proxyManualyConfigured) | 
| 756     { |  | 
| 757       msgId = filtering ? R.string.notif_wifi : R.string.notif_wifi_nofiltering; | 707       msgId = filtering ? R.string.notif_wifi : R.string.notif_wifi_nofiltering; | 
| 758     } | 708     if (transparent) | 
| 759     if (this.transparent) |  | 
| 760     { |  | 
| 761       msgId = R.string.notif_all; | 709       msgId = R.string.notif_all; | 
| 762     } |  | 
| 763 | 710 | 
| 764     final NotificationCompat.Builder builder = new NotificationCompat.Builder(th
     is); | 711     final NotificationCompat.Builder builder = new NotificationCompat.Builder(th
     is); | 
| 765     if (this.hideIcon && msgId != R.string.notif_waiting) | 712     if (hideIcon && msgId != R.string.notif_waiting) | 
| 766     { | 713     { | 
| 767       builder.setWhen(POSITION_RIGHT); | 714       builder.setWhen(POSITION_RIGHT); | 
| 768       builder.setSmallIcon(R.drawable.transparent); | 715       builder.setSmallIcon(R.drawable.transparent); | 
| 769       // builder.setContent(new RemoteViews(getPackageName(), | 716       // builder.setContent(new RemoteViews(getPackageName(), R.layout.notif_hid
     den)); | 
| 770       // R.layout.notif_hidden)); |  | 
| 771     } | 717     } | 
| 772     else | 718     else | 
| 773     { | 719     { | 
| 774       builder.setWhen(0); | 720       builder.setWhen(0); | 
| 775       builder.setSmallIcon(R.drawable.ic_stat_blocking); | 721       builder.setSmallIcon(R.drawable.ic_stat_blocking); | 
| 776     } | 722     } | 
| 777     final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, | 723     final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new I
     ntent(this, Preferences.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.
     FLAG_ACTIVITY_NEW_TASK), 0); | 
| 778         new Intent(this, Preferences.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_
     TOP | Intent.FLAG_ACTIVITY_NEW_TASK), 0); |  | 
| 779     builder.setContentIntent(contentIntent); | 724     builder.setContentIntent(contentIntent); | 
| 780     builder.setContentTitle(this.getText(R.string.app_name)); | 725     builder.setContentTitle(getText(R.string.app_name)); | 
| 781     builder.setContentText(this.getString(msgId, this.port)); | 726     builder.setContentText(getString(msgId, port)); | 
| 782     builder.setOngoing(true); | 727     builder.setOngoing(true); | 
| 783 | 728 | 
| 784     final Notification notification = builder.getNotification(); | 729     final Notification notification = builder.getNotification(); | 
| 785     return notification; | 730     return notification; | 
| 786   } | 731   } | 
| 787 | 732 | 
| 788   public void setEmptyIcon(final boolean hide) | 733   public void setEmptyIcon(final boolean hide) | 
| 789   { | 734   { | 
| 790     this.hideIcon = hide; | 735     hideIcon = hide; | 
| 791     final NotificationManager notificationManager = (NotificationManager)this.ge
     tSystemService(NOTIFICATION_SERVICE); | 736     final NotificationManager notificationManager = (NotificationManager) getSys
     temService(NOTIFICATION_SERVICE); | 
| 792     notificationManager.notify(ONGOING_NOTIFICATION_ID, this.getNotification()); | 737     notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()); | 
| 793   } | 738   } | 
| 794 | 739 | 
| 795   public void sendStateChangedBroadcast() | 740   public void sendStateChangedBroadcast() | 
| 796   { | 741   { | 
| 797     Log.i(TAG, "Broadcasting " + BROADCAST_STATE_CHANGED); | 742     Log.i(TAG, "Broadcasting " + BROADCAST_STATE_CHANGED); | 
| 798     final boolean manual = this.isManual(); | 743     final boolean manual = isManual(); | 
| 799     final Intent stateIntent = new Intent(BROADCAST_STATE_CHANGED).putExtra("ena
     bled", true).putExtra("port", this.port).putExtra("manual", manual); | 744     final Intent stateIntent = new Intent(BROADCAST_STATE_CHANGED).putExtra("ena
     bled", true).putExtra("port", port).putExtra("manual", manual); | 
| 800     if (manual) | 745     if (manual) | 
| 801     { | 746       stateIntent.putExtra("configured", proxyManualyConfigured); | 
| 802       stateIntent.putExtra("configured", this.proxyManualyConfigured); | 747     sendBroadcast(stateIntent); | 
| 803     } |  | 
| 804     this.sendBroadcast(stateIntent); |  | 
| 805   } | 748   } | 
| 806 | 749 | 
| 807   private final IBinder binder = new LocalBinder(); | 750   private final IBinder binder = new LocalBinder(); | 
| 808 | 751 | 
| 809   public final class LocalBinder extends Binder | 752   public final class LocalBinder extends Binder | 
| 810   { | 753   { | 
| 811     public ProxyService getService() | 754     public ProxyService getService() | 
| 812     { | 755     { | 
| 813       return ProxyService.this; | 756       return ProxyService.this; | 
| 814     } | 757     } | 
| 815   } | 758   } | 
| 816 | 759 | 
| 817   @Override | 760   @Override | 
| 818   public IBinder onBind(final Intent intent) | 761   public IBinder onBind(final Intent intent) | 
| 819   { | 762   { | 
| 820     return this.binder; | 763     return binder; | 
| 821   } | 764   } | 
| 822 | 765 | 
| 823   /** | 766   /** | 
| 824    * Executed if no traffic is detected after a period of time. Notifies user | 767    * Executed if no traffic is detected after a period of time. Notifies user | 
| 825    * about possible configuration problems. | 768    * about possible configuration problems. | 
| 826    */ | 769    */ | 
| 827   private final Runnable noTraffic = new Runnable() | 770   private final Runnable noTraffic = new Runnable() | 
| 828   { | 771   { | 
| 829     @Override | 772     @Override | 
| 830     public void run() | 773     public void run() | 
| 831     { | 774     { | 
| 832       // It's weird but notrafficHandler.removeCallbacks(noTraffic) does not | 775       // It's weird but notrafficHandler.removeCallbacks(noTraffic) does not rem
     ove this callback | 
| 833       // remove this callback | 776       if (notrafficHandler == null) | 
| 834       if (ProxyService.this.notrafficHandler == null) |  | 
| 835       { |  | 
| 836         return; | 777         return; | 
| 837       } |  | 
| 838       // Show warning notification | 778       // Show warning notification | 
| 839       final NotificationCompat.Builder builder = new NotificationCompat.Builder(
     ProxyService.this); | 779       final NotificationCompat.Builder builder = new NotificationCompat.Builder(
     ProxyService.this); | 
| 840       builder.setSmallIcon(R.drawable.ic_stat_warning); | 780       builder.setSmallIcon(R.drawable.ic_stat_warning); | 
| 841       builder.setWhen(System.currentTimeMillis()); | 781       builder.setWhen(System.currentTimeMillis()); | 
| 842       builder.setAutoCancel(true); | 782       builder.setAutoCancel(true); | 
| 843       final Intent intent = new Intent(ProxyService.this, ConfigurationActivity.
     class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | 783       final Intent intent = new Intent(ProxyService.this, ConfigurationActivity.
     class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | 
| 844       intent.putExtra("port", ProxyService.this.port); | 784       intent.putExtra("port", port); | 
| 845       final PendingIntent contentIntent = PendingIntent.getActivity(ProxyService
     .this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); | 785       final PendingIntent contentIntent = PendingIntent.getActivity(ProxyService
     .this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); | 
| 846       builder.setContentIntent(contentIntent); | 786       builder.setContentIntent(contentIntent); | 
| 847       builder.setContentTitle(ProxyService.this.getText(R.string.app_name)); | 787       builder.setContentTitle(getText(R.string.app_name)); | 
| 848       builder.setContentText(ProxyService.this.getText(R.string.notif_notraffic)
     ); | 788       builder.setContentText(getText(R.string.notif_notraffic)); | 
| 849       final NotificationManager notificationManager = (NotificationManager)Proxy
     Service.this.getSystemService(NOTIFICATION_SERVICE); | 789       final NotificationManager notificationManager = (NotificationManager) getS
     ystemService(NOTIFICATION_SERVICE); | 
| 850       notificationManager.notify(NOTRAFFIC_NOTIFICATION_ID, builder.getNotificat
     ion()); | 790       notificationManager.notify(NOTRAFFIC_NOTIFICATION_ID, builder.getNotificat
     ion()); | 
| 851     } | 791     } | 
| 852   }; | 792   }; | 
| 853 | 793 | 
| 854   /** | 794   /** | 
| 855    * Stops no traffic check if traffic is detected by proxy service. | 795    * Stops no traffic check if traffic is detected by proxy service. | 
| 856    */ | 796    */ | 
| 857   private final BroadcastReceiver filterReceiver = new BroadcastReceiver() | 797   private final BroadcastReceiver filterReceiver = new BroadcastReceiver() | 
| 858   { | 798   { | 
| 859     @Override | 799     @Override | 
| 860     public void onReceive(final Context context, final Intent intent) | 800     public void onReceive(final Context context, final Intent intent) | 
| 861     { | 801     { | 
| 862       if (intent.getAction().equals(AdblockPlus.BROADCAST_FILTERING_CHANGE)) | 802       if (intent.getAction().equals(AdblockPlus.BROADCAST_FILTERING_CHANGE)) | 
| 863       { | 803       { | 
| 864         // It's rather a hack but things are happening simultaneously and we | 804         // It's rather a hack but things are happening simultaneously and we | 
| 865         // receive this broadcast despite the fact we have unsubscribed from | 805         // receive this broadcast despite the fact we have unsubscribed from | 
| 866         // it and notification is not removed because it is changed to new one | 806         // it and notification is not removed because it is changed to new one | 
| 867         // during removal. | 807         // during removal. | 
| 868         if (!ProxyService.this.isNativeProxyAutoConfigured()) | 808         if (!isNativeProxyAutoConfigured()) | 
| 869         { | 809         { | 
| 870           final NotificationManager notificationManager = (NotificationManager)P
     roxyService.this.getSystemService(NOTIFICATION_SERVICE); | 810           final NotificationManager notificationManager = (NotificationManager) 
     getSystemService(NOTIFICATION_SERVICE); | 
| 871           notificationManager.notify(ONGOING_NOTIFICATION_ID, ProxyService.this.
     getNotification()); | 811           notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification())
     ; | 
| 872         } | 812         } | 
| 873       } | 813       } | 
| 874       if (intent.getAction().equals(AdblockPlus.BROADCAST_FILTER_MATCHES)) | 814       if (intent.getAction().equals(AdblockPlus.BROADCAST_FILTER_MATCHES)) | 
| 875       { | 815       { | 
| 876         ProxyService.this.proxyManualyConfigured = true; | 816         proxyManualyConfigured = true; | 
| 877         ProxyService.this.stopNoTrafficCheck(); | 817         stopNoTrafficCheck(); | 
| 878       } | 818       } | 
| 879     } | 819     } | 
| 880   }; | 820   }; | 
| 881 | 821 | 
| 882   /** | 822   /** | 
| 883    * Stops service if proxy fails. | 823    * Stops service if proxy fails. | 
| 884    */ | 824    */ | 
| 885   private final BroadcastReceiver proxyReceiver = new BroadcastReceiver() | 825   private final BroadcastReceiver proxyReceiver = new BroadcastReceiver() | 
| 886   { | 826   { | 
| 887     @Override | 827     @Override | 
| 888     public void onReceive(final Context context, final Intent intent) | 828     public void onReceive(final Context context, final Intent intent) | 
| 889     { | 829     { | 
| 890       if (intent.getAction().equals(ProxyService.BROADCAST_PROXY_FAILED)) | 830       if (intent.getAction().equals(ProxyService.BROADCAST_PROXY_FAILED)) | 
| 891       { | 831       { | 
| 892         ProxyService.this.stopSelf(); | 832         stopSelf(); | 
| 893       } | 833       } | 
| 894     } | 834     } | 
| 895   }; | 835   }; | 
| 896 | 836 | 
| 897   /** | 837   /** | 
| 898    * Monitors system network connection settings changes and updates proxy | 838    * Monitors system network connection settings changes and updates proxy | 
| 899    * settings accordingly. | 839    * settings accordingly. | 
| 900    */ | 840    */ | 
| 901   private final BroadcastReceiver connectionReceiver = new BroadcastReceiver() | 841   private final BroadcastReceiver connectionReceiver = new BroadcastReceiver() | 
| 902   { | 842   { | 
| 903     @Override | 843     @Override | 
| 904     public void onReceive(final Context ctx, final Intent intent) | 844     public void onReceive(final Context ctx, final Intent intent) | 
| 905     { | 845     { | 
| 906       final String action = intent.getAction(); | 846       final String action = intent.getAction(); | 
| 907       Log.i(TAG, "Action: " + action); | 847       Log.i(TAG, "Action: " + action); | 
| 908       // Connectivity change | 848       // Connectivity change | 
| 909       if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) | 849       if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) | 
| 910       { | 850       { | 
| 911         final ConnectivityManager connectivityManager = (ConnectivityManager)Pro
     xyService.this.getSystemService(Context.CONNECTIVITY_SERVICE); | 851         final ConnectivityManager connectivityManager = (ConnectivityManager) ge
     tSystemService(Context.CONNECTIVITY_SERVICE); | 
| 912         // TODO Should we use | 852         // TODO Should we use ConnectivityManagerCompat.getNetworkInfoFromBroadc
     ast() instead? | 
| 913         // ConnectivityManagerCompat.getNetworkInfoFromBroadcast() instead? |  | 
| 914         final NetworkInfo info = connectivityManager.getActiveNetworkInfo(); | 853         final NetworkInfo info = connectivityManager.getActiveNetworkInfo(); | 
| 915         if (info == null) | 854         if (info == null) | 
| 916         { |  | 
| 917           return; | 855           return; | 
| 918         } |  | 
| 919         final String typeName = info.getTypeName(); | 856         final String typeName = info.getTypeName(); | 
| 920         final String subtypeName = info.getSubtypeName(); | 857         final String subtypeName = info.getSubtypeName(); | 
| 921         final boolean available = info.isAvailable(); | 858         final boolean available = info.isAvailable(); | 
| 922 | 859 | 
| 923         Log.i(TAG, "Network Type: " + typeName + ", subtype: " + subtypeName + "
     , available: " + available); | 860         Log.i(TAG, "Network Type: " + typeName + ", subtype: " + subtypeName + "
     , available: " + available); | 
| 924         if (info.getType() == ConnectivityManager.TYPE_WIFI) | 861         if (info.getType() == ConnectivityManager.TYPE_WIFI) | 
| 925         { | 862         { | 
| 926           if (ProxyService.this.nativeProxyAutoConfigured) | 863           if (nativeProxyAutoConfigured) | 
| 927           { | 864           { | 
| 928             ProxySettings.setConnectionProxy(ProxyService.this.getApplicationCon
     text(), LOCALHOST, ProxyService.this.port, ""); | 865             ProxySettings.setConnectionProxy(getApplicationContext(), LOCALHOST,
      port, ""); | 
| 929           } | 866           } | 
| 930           else | 867           else | 
| 931           { | 868           { | 
| 932             ProxyService.this.updateNoTrafficCheck(connectivityManager); | 869             updateNoTrafficCheck(connectivityManager); | 
| 933           } | 870           } | 
| 934         } | 871         } | 
| 935       } | 872       } | 
| 936       // Proxy change | 873       // Proxy change | 
| 937       else if (Proxy.PROXY_CHANGE_ACTION.equals(action)) | 874       else if (Proxy.PROXY_CHANGE_ACTION.equals(action)) | 
| 938       { | 875       { | 
| 939         final Object pp = intent.getParcelableExtra("proxy"); | 876         final Object pp = intent.getParcelableExtra("proxy"); | 
| 940         try | 877         try | 
| 941         { | 878         { | 
| 942           final String[] userProxy = ProxySettings.getUserProxy(pp); | 879           final String[] userProxy = ProxySettings.getUserProxy(pp); | 
| 943           if (ProxyService.this.nativeProxyAutoConfigured) | 880           if (nativeProxyAutoConfigured) | 
| 944           { | 881           { | 
| 945             if (userProxy != null && Integer.valueOf(userProxy[1]) != ProxyServi
     ce.this.port) | 882             if (userProxy != null && Integer.valueOf(userProxy[1]) != port) | 
| 946             { | 883             { | 
| 947               Log.i(TAG, "User has set new proxy: " + userProxy[0] + ":" + userP
     roxy[1] + "(" + userProxy[2] + ")"); | 884               Log.i(TAG, "User has set new proxy: " + userProxy[0] + ":" + userP
     roxy[1] + "(" + userProxy[2] + ")"); | 
| 948               if (ProxyService.this.proxy != null) | 885               if (proxy != null) | 
| 949               { | 886               { | 
| 950                 ProxyService.this.configureUserProxy(ProxyService.this.proxyConf
     iguration, userProxy[0], userProxy[1], userProxy[2], null, null); | 887                 configureUserProxy(proxyConfiguration, userProxy[0], userProxy[1
     ], userProxy[2], null, null); | 
| 951                 ProxyService.this.proxy.restart(ProxyService.this.proxyConfigura
     tion.getProperty("handler")); | 888                 proxy.restart(proxyConfiguration.getProperty("handler")); | 
| 952               } | 889               } | 
| 953             } | 890             } | 
| 954           } | 891           } | 
| 955           else | 892           else | 
| 956           { | 893           { | 
| 957             Log.i(TAG, "User has set proxy: " + userProxy[0] + ":" + userProxy[1
     ] + "(" + userProxy[2] + ")"); | 894             Log.i(TAG, "User has set proxy: " + userProxy[0] + ":" + userProxy[1
     ] + "(" + userProxy[2] + ")"); | 
| 958             ProxyService.this.updateNoTrafficCheck(userProxy); | 895             updateNoTrafficCheck(userProxy); | 
| 959           } | 896           } | 
| 960         } | 897         } | 
| 961         catch (final Exception e) | 898         catch (final Exception e) | 
| 962         { | 899         { | 
| 963           // This should not happen | 900           // This should not happen | 
| 964           Log.e(TAG, null, e); | 901           Log.e(TAG, null, e); | 
| 965         } | 902         } | 
| 966       } | 903       } | 
| 967     } | 904     } | 
| 968   }; | 905   }; | 
| 969 | 906 | 
| 970   final class ProxyServer extends Server | 907   final class ProxyServer extends Server | 
| 971   { | 908   { | 
| 972     @Override | 909     @Override | 
| 973     public void close() | 910     public void close() | 
| 974     { | 911     { | 
| 975       try | 912       try | 
| 976       { | 913       { | 
| 977         this.listen.close(); | 914         listen.close(); | 
| 978         this.interrupt(); | 915         this.interrupt(); | 
| 979         this.join(); | 916         this.join(); | 
| 980       } | 917       } | 
| 981       catch (final Exception e) | 918       catch (final Exception e) | 
| 982       { | 919       { | 
| 983         // ignore - it always happens | 920         // ignore - it always happens | 
| 984       } | 921       } | 
| 985       this.log(LOG_WARNING, null, "server stopped"); | 922       log(LOG_WARNING, null, "server stopped"); | 
| 986     } | 923     } | 
| 987 | 924 | 
| 988     @Override | 925     @Override | 
| 989     public void log(final int level, final Object obj, final String message) | 926     public void log(final int level, final Object obj, final String message) | 
| 990     { | 927     { | 
| 991       if (level <= this.logLevel) | 928       if (level <= logLevel) | 
| 992       { | 929       { | 
| 993         Log.println(7 - level, obj != null ? obj.toString() : TAG, message); | 930         Log.println(7 - level, obj != null ? obj.toString() : TAG, message); | 
| 994       } | 931       } | 
| 995     } | 932     } | 
| 996   } | 933   } | 
| 997 } | 934 } | 
| LEFT | RIGHT | 
|---|