();
87 | String parseResult = this.pacScriptParser.evaluate(uri.toString(),
88 | uri.getHost());
89 | String[] proxyDefinitions = parseResult.split("[;]");
90 | for (String proxyDef : proxyDefinitions) {
91 | if (proxyDef.trim().length() > 0) {
92 | proxies.add(buildProxyFromPacResult(proxyDef));
93 | }
94 | }
95 | return proxies;
96 | } catch (ProxyEvaluationException e) {
97 | Log.e(TAG, "PAC resolving error.", e);
98 | return null;
99 | }
100 | }
101 |
102 | /*************************************************************************
103 | * The proxy evaluator will return a proxy string. This method will take
104 | * this string and build a matching Proxy for it.
105 | *
106 | * @param pacResult
107 | * the result from the PAC parser.
108 | * @return a Proxy
109 | ************************************************************************/
110 |
111 | private Proxy buildProxyFromPacResult(String pacResult) {
112 | if (pacResult == null || pacResult.trim().length() < 6) {
113 | return Proxy.NO_PROXY;
114 | }
115 | String proxyDef = pacResult.trim();
116 | if (proxyDef.toUpperCase().startsWith(PAC_DIRECT)) {
117 | return Proxy.NO_PROXY;
118 | }
119 |
120 | // Check proxy type.
121 | String type = Proxy.TYPE_HTTP;
122 | if (proxyDef.toUpperCase().startsWith(PAC_SOCKS)) {
123 | type = Proxy.TYPE_SOCKS5;
124 | }
125 | if (proxyDef.toUpperCase().startsWith(PAC_HTTPS)) {
126 | type = Proxy.TYPE_HTTPS;
127 | }
128 |
129 | String host = proxyDef.substring(6);
130 | Integer port = 80;
131 | if (type.equals(Proxy.TYPE_HTTPS)) {
132 | port = 443;
133 | }
134 |
135 | // Split port from host
136 | int indexOfPort = host.indexOf(':');
137 | if (indexOfPort != -1) {
138 | port = Integer.parseInt(host.substring(indexOfPort + 1).trim());
139 | host = host.substring(0, indexOfPort).trim();
140 | }
141 |
142 | return new Proxy(host, port, type);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/btr/proxy/selector/pac/UrlPacScriptSource.java:
--------------------------------------------------------------------------------
1 | package com.btr.proxy.selector.pac;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileReader;
6 | import java.io.IOException;
7 | import java.io.InputStreamReader;
8 | import java.net.HttpURLConnection;
9 | import java.net.Proxy;
10 | import java.net.URISyntaxException;
11 | import java.net.URL;
12 |
13 | import android.util.Log;
14 |
15 | /*****************************************************************************
16 | * Script source that will load the content of a PAC file from an webserver. The
17 | * script content is cached once it was downloaded.
18 | *
19 | * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
20 | ****************************************************************************/
21 |
22 | public class UrlPacScriptSource implements PacScriptSource {
23 |
24 | private final static String TAG = "ProxyDroid.PAC";
25 |
26 | private final String scriptUrl;
27 | private String scriptContent;
28 | private long expireAtMillis;
29 |
30 | /*************************************************************************
31 | * Constructor
32 | *
33 | * @param url
34 | * the URL to download the script from.
35 | ************************************************************************/
36 |
37 | public UrlPacScriptSource(String url) {
38 | super();
39 | this.expireAtMillis = 0;
40 | this.scriptUrl = url;
41 | }
42 |
43 | /*************************************************************************
44 | * getScriptContent
45 | *
46 | * @see com.btr.proxy.selector.pac.PacScriptSource#getScriptContent()
47 | ************************************************************************/
48 |
49 | @Override
50 | public synchronized String getScriptContent() throws IOException {
51 | if (this.scriptContent == null
52 | || (this.expireAtMillis > 0 && this.expireAtMillis > System
53 | .currentTimeMillis())) {
54 | try {
55 | if (this.scriptUrl.startsWith("file:/")
56 | || this.scriptUrl.indexOf(":/") == -1) {
57 | this.scriptContent = readPacFileContent(this.scriptUrl);
58 | } else {
59 | this.scriptContent = downloadPacContent(this.scriptUrl);
60 | }
61 | } catch (IOException e) {
62 | Log.e(TAG, "Loading script failed.", e);
63 | this.scriptContent = "";
64 | throw e;
65 | }
66 | }
67 | return this.scriptContent;
68 | }
69 |
70 | /*************************************************************************
71 | * Reads a PAC script from a local file.
72 | *
73 | * @param scriptUrl
74 | * @return the content of the script file.
75 | * @throws IOException
76 | * @throws URISyntaxException
77 | ************************************************************************/
78 |
79 | private String readPacFileContent(String scriptUrl) throws IOException {
80 | try {
81 | File file = null;
82 | if (scriptUrl.indexOf(":/") == -1) {
83 | file = new File(scriptUrl);
84 | } else {
85 | file = new File(new URL(scriptUrl).toURI());
86 | }
87 | BufferedReader r = new BufferedReader(new FileReader(file));
88 | StringBuilder result = new StringBuilder();
89 | try {
90 | String line;
91 | while ((line = r.readLine()) != null) {
92 | result.append(line).append("\n");
93 | }
94 | } finally {
95 | r.close();
96 | }
97 | return result.toString();
98 | } catch (Exception e) {
99 | Log.e(TAG, "File reading error.", e);
100 | throw new IOException(e.getMessage());
101 | }
102 | }
103 |
104 | /*************************************************************************
105 | * Downloads the script from a webserver.
106 | *
107 | * @param url
108 | * the URL to the script file.
109 | * @return the script content.
110 | * @throws IOException
111 | * on read error.
112 | ************************************************************************/
113 |
114 | private String downloadPacContent(String url) throws IOException {
115 | if (url == null) {
116 | throw new IOException("Invalid PAC script URL: null");
117 | }
118 |
119 | HttpURLConnection con = (HttpURLConnection) new URL(url)
120 | .openConnection(Proxy.NO_PROXY);
121 | con.setConnectTimeout(15 * 1000);
122 | con.setReadTimeout(20 * 1000);
123 | con.setInstanceFollowRedirects(true);
124 | con.setRequestProperty("accept",
125 | "application/x-ns-proxy-autoconfig, */*;q=0.8");
126 |
127 | if (con.getResponseCode() != 200) {
128 | throw new IOException("Server returned: " + con.getResponseCode()
129 | + " " + con.getResponseMessage());
130 | }
131 |
132 | // Read expire date.
133 | this.expireAtMillis = con.getExpiration();
134 |
135 | String charsetName = parseCharsetFromHeader(con.getContentType());
136 | BufferedReader r = new BufferedReader(new InputStreamReader(
137 | con.getInputStream(), charsetName));
138 | try {
139 | StringBuilder result = new StringBuilder();
140 | try {
141 | String line;
142 | while ((line = r.readLine()) != null) {
143 | result.append(line).append("\n");
144 | }
145 | } finally {
146 | r.close();
147 | con.disconnect();
148 | }
149 | return result.toString();
150 | } finally {
151 | r.close();
152 | }
153 | }
154 |
155 | /*************************************************************************
156 | * Response Content-Type could be something like this:
157 | * application/x-ns-proxy-autoconfig; charset=UTF-8
158 | *
159 | * @param contentType
160 | * header field.
161 | * @return the extracted charset if set else a default charset.
162 | ************************************************************************/
163 |
164 | String parseCharsetFromHeader(String contentType) {
165 | String result = "ISO-8859-1";
166 | if (contentType != null) {
167 | String[] paramList = contentType.split(";");
168 | for (String param : paramList) {
169 | if (param.toLowerCase().trim().startsWith("charset")
170 | && param.indexOf("=") != -1) {
171 | result = param.substring(param.indexOf("=") + 1).trim();
172 | }
173 | }
174 | }
175 | return result;
176 | }
177 |
178 | /***************************************************************************
179 | * @see java.lang.Object#toString()
180 | **************************************************************************/
181 | @Override
182 | public String toString() {
183 | return this.scriptUrl;
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/app/src/main/assets/pages/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | GAEProxy License
5 |
6 |
274 |
275 |
276 | ProxyDroid: Global Proxy for Android.
277 | Copyright (C) 2011-2013 Max Lv
278 | This program is free software: you can redistribute it and/or modify
279 | it under the terms of the GNU General Public License as published by
280 | the Free Software Foundation, either version 3 of the License, or
281 | (at your option) any later version.
282 | This program is distributed in the hope that it will be useful,
283 | but WITHOUT ANY WARRANTY; without even the implied warranty of
284 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
285 | GNU General Public License for more details.
286 | You should have received a copy of the GNU General Public License
287 | along with this program. If not, see http://www.gnu.org/licenses/.
288 |
289 |
290 |
291 |
292 |
--------------------------------------------------------------------------------
/app/src/main/java/org/proxydroid/utils/RegexValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.proxydroid.utils;
18 |
19 | import java.io.Serializable;
20 | import java.util.regex.Matcher;
21 | import java.util.regex.Pattern;
22 |
23 | /**
24 | * Regular Expression validation (using JDK 1.4+ regex support).
25 | *
26 | * Construct the validator either for a single regular expression or a set
27 | * (array) of regular expressions. By default validation is case
28 | * sensitive but constructors are provided to allow case in-sensitive
29 | * validation. For example to create a validator which does case
30 | * in-sensitive validation for a set of regular expressions:
31 | *
32 | *
33 | * String[] regexs = new String[] {...};
34 | * RegexValidator validator = new RegexValidator(regexs, false);
35 | *
36 | *
37 | *
38 | * - Validate
true or false:
39 | *
40 | * boolean valid = validator.isValid(value);
41 | *
42 | * - Validate returning an aggregated String of the matched groups:
43 | *
44 | * String result = validator.validate(value);
45 | *
46 | * - Validate returning the matched groups:
47 | *
48 | * String[] result = validator.match(value);
49 | *
50 | *
51 | *
52 | * Cached instances pre-compile and re-use {@link Pattern}(s) - which according
53 | * to the {@link Pattern} API are safe to use in a multi-threaded environment.
54 | *
55 | * @version $Revision$ $Date$
56 | * @since Validator 1.4
57 | */
58 | public class RegexValidator implements Serializable {
59 |
60 | private final Pattern[] patterns;
61 |
62 | /**
63 | * Construct a case sensitive validator for a single regular
64 | * expression.
65 | *
66 | * @param regex
67 | * The regular expression this validator will validate against
68 | */
69 | public RegexValidator(String regex) {
70 | this(regex, true);
71 | }
72 |
73 | /**
74 | * Construct a validator for a single regular expression with the specified
75 | * case sensitivity.
76 | *
77 | * @param regex
78 | * The regular expression this validator will validate against
79 | * @param caseSensitive
80 | * when true matching is case sensitive,
81 | * otherwise matching is case in-sensitive
82 | */
83 | public RegexValidator(String regex, boolean caseSensitive) {
84 | this(new String[] { regex }, caseSensitive);
85 | }
86 |
87 | /**
88 | * Construct a case sensitive validator that matches any one of the
89 | * set of regular expressions.
90 | *
91 | * @param regexs
92 | * The set of regular expressions this validator will validate
93 | * against
94 | */
95 | public RegexValidator(String[] regexs) {
96 | this(regexs, true);
97 | }
98 |
99 | /**
100 | * Construct a validator that matches any one of the set of regular
101 | * expressions with the specified case sensitivity.
102 | *
103 | * @param regexs
104 | * The set of regular expressions this validator will validate
105 | * against
106 | * @param caseSensitive
107 | * when true matching is case sensitive,
108 | * otherwise matching is case in-sensitive
109 | */
110 | public RegexValidator(String[] regexs, boolean caseSensitive) {
111 | if (regexs == null || regexs.length == 0) {
112 | throw new IllegalArgumentException(
113 | "Regular expressions are missing");
114 | }
115 | patterns = new Pattern[regexs.length];
116 | int flags = (caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
117 | for (int i = 0; i < regexs.length; i++) {
118 | if (regexs[i] == null || regexs[i].length() == 0) {
119 | throw new IllegalArgumentException("Regular expression[" + i
120 | + "] is missing");
121 | }
122 | patterns[i] = Pattern.compile(regexs[i], flags);
123 | }
124 | }
125 |
126 | /**
127 | * Validate a value against the set of regular expressions.
128 | *
129 | * @param value
130 | * The value to validate.
131 | * @return true if the value is valid otherwise
132 | * false.
133 | */
134 | public boolean isValid(String value) {
135 | if (value == null) {
136 | return false;
137 | }
138 | for (int i = 0; i < patterns.length; i++) {
139 | if (patterns[i].matcher(value).matches()) {
140 | return true;
141 | }
142 | }
143 | return false;
144 | }
145 |
146 | /**
147 | * Validate a value against the set of regular expressions returning the
148 | * array of matched groups.
149 | *
150 | * @param value
151 | * The value to validate.
152 | * @return String array of the groups matched if valid or
153 | * null if invalid
154 | */
155 | public String[] match(String value) {
156 | if (value == null) {
157 | return null;
158 | }
159 | for (int i = 0; i < patterns.length; i++) {
160 | Matcher matcher = patterns[i].matcher(value);
161 | if (matcher.matches()) {
162 | int count = matcher.groupCount();
163 | String[] groups = new String[count];
164 | for (int j = 0; j < count; j++) {
165 | groups[j] = matcher.group(j + 1);
166 | }
167 | return groups;
168 | }
169 | }
170 | return null;
171 | }
172 |
173 | /**
174 | * Validate a value against the set of regular expressions returning a
175 | * String value of the aggregated groups.
176 | *
177 | * @param value
178 | * The value to validate.
179 | * @return Aggregated String value comprised of the groups matched if
180 | * valid or null if invalid
181 | */
182 | public String validate(String value) {
183 | if (value == null) {
184 | return null;
185 | }
186 | for (int i = 0; i < patterns.length; i++) {
187 | Matcher matcher = patterns[i].matcher(value);
188 | if (matcher.matches()) {
189 | int count = matcher.groupCount();
190 | if (count == 1) {
191 | return matcher.group(1);
192 | }
193 | StringBuffer buffer = new StringBuffer();
194 | for (int j = 0; j < count; j++) {
195 | String component = matcher.group(j + 1);
196 | if (component != null) {
197 | buffer.append(component);
198 | }
199 | }
200 | return buffer.toString();
201 | }
202 | }
203 | return null;
204 | }
205 |
206 | /**
207 | * Provide a String representation of this validator.
208 | *
209 | * @return A String representation of this validator
210 | */
211 | @Override
212 | public String toString() {
213 | StringBuffer buffer = new StringBuffer();
214 | buffer.append("RegexValidator{");
215 | for (int i = 0; i < patterns.length; i++) {
216 | if (i > 0) {
217 | buffer.append(",");
218 | }
219 | buffer.append(patterns[i].pattern());
220 | }
221 | buffer.append("}");
222 | return buffer.toString();
223 | }
224 |
225 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/proxydroid/utils/ImageLoader.java:
--------------------------------------------------------------------------------
1 | package org.proxydroid.utils;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.drawable.BitmapDrawable;
8 | import android.widget.ImageView;
9 |
10 | import org.proxydroid.R;
11 |
12 | import java.io.File;
13 | import java.io.FileInputStream;
14 | import java.io.FileNotFoundException;
15 | import java.util.HashMap;
16 | import java.util.Stack;
17 |
18 | public class ImageLoader {
19 |
20 | // Used to display bitmap in the UI thread
21 | class BitmapDisplayer implements Runnable {
22 | Bitmap bitmap;
23 | ImageView imageView;
24 |
25 | public BitmapDisplayer(Bitmap b, ImageView i) {
26 | bitmap = b;
27 | imageView = i;
28 | }
29 |
30 | @Override
31 | public void run() {
32 | if (bitmap != null)
33 | imageView.setImageBitmap(bitmap);
34 | else
35 | imageView.setImageResource(stub_id);
36 | }
37 | }
38 |
39 | class PhotosLoader extends Thread {
40 | @Override
41 | public void run() {
42 | try {
43 | while (true) {
44 | // thread waits until there are any images to load in the
45 | // queue
46 | if (photosQueue.photosToLoad.size() == 0)
47 | synchronized (photosQueue.lock) {
48 | photosQueue.lock.wait();
49 | }
50 |
51 | synchronized (photosQueue.lock) {
52 | if (photosQueue.photosToLoad.size() != 0) {
53 | PhotoToLoad photoToLoad;
54 |
55 | photoToLoad = photosQueue.photosToLoad.pop();
56 |
57 | Bitmap bmp = getBitmap(photoToLoad.uid);
58 | cache.put(photoToLoad.uid, bmp);
59 | Object tag = photoToLoad.imageView.getTag();
60 | if (tag != null && ((Integer) tag) == photoToLoad.uid) {
61 | BitmapDisplayer bd = new BitmapDisplayer(bmp,
62 | photoToLoad.imageView);
63 | Activity a = (Activity) photoToLoad.imageView
64 | .getContext();
65 | a.runOnUiThread(bd);
66 | }
67 | }
68 | }
69 |
70 | if (Thread.interrupted())
71 | break;
72 | }
73 | } catch (InterruptedException e) {
74 | // allow thread to exit
75 | }
76 | }
77 | }
78 |
79 | // stores list of photos to download
80 | class PhotosQueue {
81 | private Stack photosToLoad = new Stack();
82 | private final Object lock = new Object();
83 |
84 | // removes all instances of this ImageView
85 | public void Clean(ImageView image) {
86 | synchronized (lock) {
87 | try {
88 | for (int j = 0; j < photosToLoad.size(); ) {
89 | if (photosToLoad.get(j).imageView == image)
90 | photosToLoad.remove(j);
91 | else
92 | ++j;
93 | }
94 | } catch (java.lang.ArrayIndexOutOfBoundsException ignore) {
95 | // Nothing
96 | }
97 | }
98 | }
99 | }
100 |
101 | // Task for the queue
102 | private class PhotoToLoad {
103 | public int uid;
104 | public ImageView imageView;
105 |
106 | public PhotoToLoad(int u, ImageView i) {
107 | uid = u;
108 | imageView = i;
109 | }
110 | }
111 |
112 | // the simplest in-memory cache implementation. This should be replaced with
113 | // something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
114 | private HashMap cache = new HashMap();
115 |
116 | private File cacheDir;
117 |
118 | private Context context;
119 |
120 | final int stub_id = R.drawable.sym_def_app_icon;
121 |
122 | PhotosQueue photosQueue = new PhotosQueue();
123 |
124 | PhotosLoader photoLoaderThread = new PhotosLoader();
125 |
126 | public ImageLoader(Context c) {
127 | // Make the background thead low priority. This way it will not affect
128 | // the UI performance
129 | photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);
130 |
131 | context = c;
132 |
133 | // Find the dir to save cached images
134 | cacheDir = context.getCacheDir();
135 |
136 | }
137 |
138 | public void clearCache() {
139 | // clear memory cache
140 | cache.clear();
141 |
142 | // clear SD cache
143 | File[] files = cacheDir.listFiles();
144 | for (File f : files)
145 | f.delete();
146 | }
147 |
148 | // decodes image and scales it to reduce memory consumption
149 | private Bitmap decodeFile(File f) {
150 | try {
151 | // decode image size
152 | BitmapFactory.Options o = new BitmapFactory.Options();
153 | o.inJustDecodeBounds = true;
154 | BitmapFactory.decodeStream(new FileInputStream(f), null, o);
155 |
156 | // Find the correct scale value. It should be the power of 2.
157 | final int REQUIRED_SIZE = 70;
158 | int width_tmp = o.outWidth, height_tmp = o.outHeight;
159 | int scale = 1;
160 | while (true) {
161 | if (width_tmp / 2 < REQUIRED_SIZE
162 | || height_tmp / 2 < REQUIRED_SIZE)
163 | break;
164 | width_tmp /= 2;
165 | height_tmp /= 2;
166 | scale *= 2;
167 | }
168 |
169 | // decode with inSampleSize
170 | BitmapFactory.Options o2 = new BitmapFactory.Options();
171 | o2.inSampleSize = scale;
172 | return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
173 | } catch (FileNotFoundException e) {
174 | }
175 | return null;
176 | }
177 |
178 | public void DisplayImage(int uid, Activity activity, ImageView imageView) {
179 | if (cache.containsKey(uid))
180 | imageView.setImageBitmap(cache.get(uid));
181 | else {
182 | queuePhoto(uid, activity, imageView);
183 | imageView.setImageResource(stub_id);
184 | }
185 | }
186 |
187 | private Bitmap getBitmap(int uid) {
188 | // I identify images by hashcode. Not a perfect solution, good for the
189 | // demo.
190 | String filename = String.valueOf(uid);
191 | File f = new File(cacheDir, filename);
192 |
193 | // from SD cache
194 | Bitmap b = decodeFile(f);
195 | if (b != null)
196 | return b;
197 |
198 | // from web
199 | try {
200 | BitmapDrawable icon = (BitmapDrawable) Utils.getAppIcon(context,
201 | uid);
202 | return icon.getBitmap();
203 | } catch (Exception ex) {
204 | return null;
205 | }
206 | }
207 |
208 | private void queuePhoto(int uid, Activity activity, ImageView imageView) {
209 | // This ImageView may be used for other images before. So there may be
210 | // some old tasks in the queue. We need to discard them.
211 | photosQueue.Clean(imageView);
212 | PhotoToLoad p = new PhotoToLoad(uid, imageView);
213 | synchronized (photosQueue.lock) {
214 | photosQueue.photosToLoad.push(p);
215 | photosQueue.lock.notifyAll();
216 | }
217 |
218 | // start thread if it's not started yet
219 | if (photoLoaderThread.getState() == Thread.State.NEW)
220 | photoLoaderThread.start();
221 | }
222 |
223 | public void stopThread() {
224 | photoLoaderThread.interrupt();
225 | }
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ProxyDroid Plus
6 | Хорошо
7 | Feedback @ofmax
8 |
9 |
10 | Необходимо указать номер порта
11 | Необходимо указать адрес узла
12 | Необходимо указать локальный порт
13 | Необходимо указать удалённый порт
14 | Пожалуйста проверьте номер порта
15 | Необходимо указать имя пользователя
16 | Номер порта должен быть больше 1024
17 | Идёт восстановление после сбоя \n\n
18 | Пожалуйста, сообщите об этой проблеме на странице проекта. \n\n
19 | (proxydroid.googlecode.com)
20 | СНАЧАЛА НЕОБХОДИМО ПОЛУЧИТЬ ПРАВА СУПЕРПОЛЬЗОВАТЕЛЯ !!!
21 | Обновление компонентов и конфигурации завершено
22 |
23 |
24 | Запущен в фоновом режиме
25 | Подключение выполнено
26 | Невозможно подключиться
27 | Служба ProxyDroid остановлена
28 | Переподключение...
29 | Соединение восстановлено
30 | Служба уже остановлена
31 | Служба уже запущена
32 | Отключение выполнено
33 | Проверьте настройки сети и учётные данные прокси
34 | Невозможно восстановить соединение. Служба остановлена
35 | Подключение
36 | Подключение...
37 | Загрузка списка приложений...
38 |
39 |
40 | Диспетчер службы
41 | Выключить
42 | Включить
43 | Вкл/Выкл
44 | Изменить состояние прокси
45 |
46 |
47 | Настройки прокси
48 |
49 | Адрес
50 | Адрес прокси-сервера
51 | URL вашего PAC-файла
52 | Автоматическая настройка
53 | Автоматически получать настройки прокси-сервера из PAC-файла
54 | URL до прокси
55 | Порт
56 | Номер порта прокси-сервера
57 | Игнорировать адреса
58 | Куда подключаться в обход прокси-сервера
59 |
60 |
61 | Включить Авторизацию
62 | Учётные данные прокси
63 | Пользователь
64 | Имя пользователя прокси-сервера
65 | Пароль
66 | Пароль прокси-сервера
67 | Авторизация NTLM
68 | Включает авторизацию по NTLM / NTLM2
69 | Домен
70 | Имя Домена для NTLM-авторизации
71 |
72 |
73 | Разное
74 | Автоподключение
75 | Автоматически запускать службу при обнаружении указанной сети
76 | Связанная сеть
77 | Связать настройки с указанным адресом 2G/3G сети
78 | или её SSID
79 |
80 | Для всех приложений
81 | Включает глобальный режим (требуются права ROOT
82 | и поддержка IPTABLES)
83 | Включает проксирование DNS-запросов (только для опытных)
84 |
85 |
86 | Для выбранных приложений
87 | Включает избирательный режим (требуются права ROOT
88 | и поддержка IPTABLES)
89 | Инверсный режим
90 | Включите чтобы НЕ проксировать выбранные приложения
91 | Выбранные приложения:
92 |
93 |
94 | Сброс
95 | \n\nProxyDroid - проект с открытым исходным кодом,
96 | выпущенный под лицензией GPL версии 3. \n\nПо всем вопросам просьба обращаться
97 | на страницу пректа в googlecode. \n\n(proxydroid.googlecode.com)
98 | О программе
99 | Переименовать
100 | OK
101 | Отмена
102 | Вернуть стандартные настройки системы
103 |
104 |
105 | Уведомления
106 | Выбрать звук
107 | Выберите мелодию уведомления
108 | Вибрация
109 | Также вибрировать при изменении состояния подключения
110 |
111 |
112 | Профили
113 | Профиль 1
114 | Новый Профиль
115 | Профиль
116 | Удалить
117 |
118 |
119 | Тип прокси-сервера
120 | Выберите тип вашего прокси
121 |
122 | Добавить
123 | Шаблоны
124 | Импорт
125 | Экспорт
126 | Диапазон адресов
127 | Подтверждение
128 | Удалить этот адрес?
129 | OK
130 | Отмена
131 | неизвестное доменное имя или неверный формат IP адреса
132 | Сброс…
133 | Импорт…
134 | Экспортировано в:
135 |
136 |
137 | - Пусто
138 | - Localhost
139 | - Intranet
140 | - Маршрут CHN
141 |
142 |
143 |
144 | Выберите файл с вашим ключом
145 | Диспетчер файлов ключей
146 | Текущая директория
147 | Родительская директория
148 | Папка
149 | Размер файла
150 | Импортировать из этого файла:
151 | Слишком много правил:
152 |
153 |
154 | Неверный или не поддерживаемый PAC-файл
155 | Неверное имя прокси сервера
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/src/main/java/org/proxydroid/ProxyDroidCLI.java:
--------------------------------------------------------------------------------
1 | /* proxydroid - Global / Individual Proxy App for Android
2 | * Copyright (C) 2011 Max Lv
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | *
17 | *
18 | * ___====-_ _-====___
19 | * _--^^^#####// \\#####^^^--_
20 | * _-^##########// ( ) \\##########^-_
21 | * -############// |\^^/| \\############-
22 | * _/############// (@::@) \\############\_
23 | * /#############(( \\// ))#############\
24 | * -###############\\ (oo) //###############-
25 | * -#################\\ / VV \ //#################-
26 | * -###################\\/ \//###################-
27 | * _#/|##########/\######( /\ )######/\##########|\#_
28 | * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \|
29 | * ` |/ V V ` V \#\| | | |/#/ V ' V V \| '
30 | * ` ` ` ` / | | | | \ ' ' ' '
31 | * ( | | | | )
32 | * __\ | | | | /__
33 | * (vvv(VVV)(VVV)vvv)
34 | *
35 | * HERE BE DRAGONS
36 | *
37 | */
38 |
39 | package org.proxydroid;
40 |
41 | import android.content.BroadcastReceiver;
42 | import android.content.Context;
43 | import android.content.Intent;
44 | import android.content.SharedPreferences;
45 | import android.content.pm.PackageInfo;
46 | import android.content.pm.PackageManager;
47 | import android.os.Build;
48 | import android.os.Bundle;
49 | import android.os.SystemClock;
50 |
51 | import androidx.preference.PreferenceManager;
52 |
53 | import org.proxydroid.utils.Utils;
54 |
55 | import java.util.ArrayList;
56 | import java.util.Arrays;
57 |
58 | public class ProxyDroidCLI extends BroadcastReceiver {
59 | public static final String TOGGLE_ACTION = "org.proxydroid.TOGGLE_STATE";
60 | public static final String CONFIG_ACTION = "org.proxydroid.PROFILE_CONFIGURE";
61 | public static final String PROFILE_ACTION = "org.proxydroid.PROFILE_CHANGE";
62 | @Override
63 | public void onReceive(Context context, Intent intent) {
64 | if(intent == null) return;
65 | if(TOGGLE_ACTION.equals(intent.getAction())) {
66 | boolean toggleStart = intent.getBooleanExtra("start", true);
67 | if (toggleStart) {
68 | if (!Utils.isWorking()) {
69 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
70 |
71 | Profile profile = new Profile();
72 | profile.getProfile(settings);
73 | try {
74 | Intent it = new Intent(context, ProxyDroidService.class);
75 | Bundle bundle = new Bundle();
76 | bundle.putString("host", profile.getHost());
77 | bundle.putString("user", profile.getUser());
78 | bundle.putString("bypassAddrs", profile.getBypassAddrs());
79 | bundle.putString("password", profile.getPassword());
80 | bundle.putString("domain", profile.getDomain());
81 | bundle.putString("certificate", profile.getCertificate());
82 |
83 | bundle.putString("proxyType", profile.getProxyType());
84 | bundle.putBoolean("isGlobalProxy", profile.isGlobalProxy());
85 | bundle.putBoolean("isBypassApps", profile.isBypassApps());
86 | bundle.putBoolean("isAuth", profile.isAuth());
87 | bundle.putBoolean("isNTLM", profile.isNTLM());
88 | bundle.putBoolean("isPAC", profile.isPAC());
89 |
90 | bundle.putInt("port", profile.getPort());
91 |
92 | it.putExtras(bundle);
93 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
94 | context.startForegroundService(it);
95 | } else {
96 | context.startService(it);
97 | }
98 | setResultData("SUCCESS");
99 |
100 | } catch (Exception ignore) {
101 | // Nothing
102 | setResultData("FAILURE");
103 | }
104 | }
105 | } else {
106 | if (Utils.isWorking() && !Utils.isConnecting()) {
107 | try {
108 | context.stopService(new Intent(context, ProxyDroidService.class));
109 | setResultData("SUCCESS");
110 | } catch (Exception e) {
111 | setResultData("FAILURE");
112 | }
113 | }
114 | }
115 | } else if(CONFIG_ACTION.equals(intent.getAction())) {
116 | if(Utils.isWorking()) {
117 | return;
118 | }
119 |
120 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
121 | Profile profile = new Profile();
122 | profile.getProfile(settings);
123 |
124 | String host = intent.getStringExtra("host");
125 | if(host == null) host = profile.getHost();
126 | profile.setHost(host);
127 |
128 | int port = intent.getIntExtra("port", profile.getPort());
129 | if(port < 1) port = profile.getPort();
130 | profile.setPort(port);
131 |
132 | String user = intent.getStringExtra("user");
133 | if(user == null) user = profile.getUser();
134 | profile.setUser(user);
135 |
136 | String password = intent.getStringExtra("password");
137 | if(password == null) password = profile.getPassword();
138 | profile.setPassword(password);
139 |
140 | String domain = intent.getStringExtra("domain");
141 | if(domain == null) domain = profile.getDomain();
142 | profile.setDomain(domain);
143 |
144 | String certificate = intent.getStringExtra("certificate");
145 | if (certificate == null) certificate = profile.getCertificate();
146 | profile.setCertificate(certificate);
147 |
148 | String bypassAddrs = intent.getStringExtra("bypassAddrs");
149 | if (bypassAddrs == null) bypassAddrs = profile.getBypassAddrs();
150 | profile.setBypassAddrs(bypassAddrs);
151 |
152 | String proxyType = intent.getStringExtra("proxyType");
153 | if (proxyType == null || !Arrays.asList("http", "https", "http-tunnel", "socks4", "socks5").contains(proxyType)) {
154 | proxyType = profile.getProxyType();
155 | }
156 | profile.setProxyType(proxyType);
157 |
158 | boolean isGlobalProxy = intent.getBooleanExtra("isGlobalProxy", profile.isGlobalProxy());
159 | profile.setGlobalProxy(isGlobalProxy);
160 |
161 | boolean isBypassApps = intent.getBooleanExtra("isBypassApps", profile.isBypassApps());
162 | profile.setBypassApps(isBypassApps);
163 |
164 | boolean isAuth = intent.getBooleanExtra("isAuth", profile.isAuth());
165 | profile.setAuth(isAuth);
166 |
167 | boolean isNTLM = intent.getBooleanExtra("isNTLM", profile.isNTLM());
168 | profile.setNTLM(isNTLM);
169 |
170 | boolean isPAC = intent.getBooleanExtra("isPAC", profile.isPAC());
171 | profile.setPAC(isPAC);
172 |
173 | String proxyedApps = intent.getStringExtra("proxyedApps");
174 | if (proxyedApps != null) {
175 | String[] packages = proxyedApps.split("//|");
176 | ArrayList validApps = new ArrayList<>();
177 | try {
178 | PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
179 | validApps.add(context.getPackageManager().getNameForUid(pi.applicationInfo.uid));
180 | } catch (PackageManager.NameNotFoundException ignored) {
181 |
182 | }
183 | proxyedApps = String.join("|", validApps);
184 |
185 | } else
186 | proxyedApps = profile.getProxyedApps();
187 | profile.setProxyedApps(proxyedApps);
188 |
189 | profile.setProfile(settings);
190 |
191 | } else if(PROFILE_ACTION.equals(intent.getAction())) {
192 | if(Utils.isWorking()) return;
193 |
194 | String action = intent.getStringExtra("action");
195 | if("switch".equals(action)) {
196 | int profileId = intent.getIntExtra("profileId", 1);
197 | if(profileId < 1) profileId = 1;
198 |
199 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
200 | String oldProfileId = settings.getString("profile", "1");
201 |
202 | settings.edit().putString("profile", Integer.toString(profileId)).commit();
203 | boolean ret = Profile.ProfileUtils.switchProfile(oldProfileId, Integer.toString(profileId), context);
204 | if(ret) {
205 | setResultData("SUCCESS");
206 | } else {
207 | setResultData("FAILURE");
208 | }
209 |
210 | } else if("rename".equals(action)) {
211 | String profileId = PreferenceManager.getDefaultSharedPreferences(context).getString("profile", "1");
212 |
213 | String newName = intent.getStringExtra("newName");
214 | if(newName == null || newName.isEmpty()) {
215 | setResultData("INVALID_NAME");
216 | return;
217 | }
218 | newName = newName.replace("|", "");
219 |
220 | Profile.ProfileUtils.renameProfile(profileId, newName, context);
221 |
222 | setResultData("SUCCESS");
223 | } else if("delete".equals(action)) {
224 | String profileId = PreferenceManager.getDefaultSharedPreferences(context).getString("profile", "1");
225 | Profile.ProfileUtils.delProfile(profileId, context);
226 | setResultData("SUCCESS");
227 |
228 | } else if("add".equals(action)) {
229 | Profile.ProfileUtils.addProfile(context);
230 | }
231 |
232 | PreferenceManager.getDefaultSharedPreferences(context).edit().putLong("profileChange", SystemClock.uptimeMillis()).commit();
233 |
234 | }
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ProxyDroid Plus
6 | OK, I know
7 | Feedback @ofmax
8 |
9 |
10 | Port should not be empty
11 | Host should not be empty
12 | Local port should not be empty
13 | Remote port should not be empty
14 | Please check your port number
15 | User name should not be empty
16 | The port number should be greater than 1024
17 | You are recovering from a crash. \n\nplease report your problem to the project page. \n\n(proxydroid.googlecode.com)
18 | PLEASE ROOT YOUR DEVICE FIRST !!!
19 | Programs and configurations have been updated
20 |
21 |
22 | Running in the background
23 | Connected
24 | Fail to connect
25 | ProxyDroid service stopped
26 | Reconnecting
27 | Reconnected
28 | Service has already been stopped
29 | Service has already been started
30 | Disconnected
31 | Please check your network and login information
32 | Cannot reconnect, service stopped
33 | Connecting
34 | Connecting...
35 | Loading app list...
36 |
37 |
38 | Service Controller
39 | Disconnect
40 | Connect
41 | Proxy Switch
42 | Enable / Disable Proxy
43 |
44 |
45 | Proxy Settings
46 | Host
47 | The host name of your proxy service
48 | PAC
49 | The URL of your PAC file
50 | Auto Setting
51 | Get proxy settings from the PAC file automatically
52 | Proxy URL
53 | Port
54 | The port number of your Proxy service
55 | Bypass Addresses
56 | Set bypass addresses
57 |
58 |
59 | Enable Authentication
60 | Account Information
61 | User
62 | Proxy User name
63 | Password
64 | Proxy Password
65 | NTLM Authentication
66 | Enable to support NTLM / NTLM2 authentication
67 | method
68 | Certificate
69 | Client Certificate for HTTPS authentication
70 | Domain
71 | Domain name for NTLM
72 |
73 |
74 | Feature Settings
75 | Auto Connect
76 | Start Proxy when specified network is available
77 | Bound Network
78 | Bind your proxy setting to 2G/3G Network or
79 | specified SSID
80 | Never Bound these WiFi SSID
81 | Never bind the proxy setting to specified SSID
82 |
83 |
84 |
85 |
86 |
87 |
88 | Global Proxy
89 | Enable the global proxy (needs ROOT permission
90 | and IPTABLES support)
91 | DNS Proxy
92 | Enable DNS Proxy for some LAN users. Turn it on
93 | only if you know what it is
94 |
95 |
96 | Individual Proxy
97 | Select apps for proxying or bypassing (needs ROOT
98 | permission and
99 | IPTABLES support)
100 | Bypass Mode
101 | Enable this option to bypass selected apps instead of proxying
102 | Select apps to use with ProxyDroid:
103 |
104 |
105 | Reset
106 | \n\nProxyDroid is an open source software
107 | published
108 | under
109 | GPLv3. \n\nIf you have any question, please visit
110 | our project
111 | site on
112 | google code. \n\n(proxydroid.googlecode.com)
113 | About
114 | ProxyDroid %s
115 | Rename
116 | OK
117 | Cancel
118 | Use system\'s iptables
119 |
120 |
121 | Notification Settings
122 | Ringtone
123 | Select the notification\'s ringtone
124 | Vibrate
125 | Also vibrate when connection status changes
126 |
127 |
128 | Profiles
129 | Profile 1
130 | New Profile
131 | Profile
132 | Delete
133 | Delete this profile?
134 |
135 |
136 | Proxy Type
137 | Choose your proxy type
138 |
139 |
140 | - http
141 | - https
142 | - http-tunnel
143 |
144 | - socks4
145 | - socks5
146 |
147 |
148 | - HTTP
149 | - HTTPS
150 | - HTTP-Tunnel
151 |
152 | - SOCKS4
153 | - SOCKS5
154 |
155 |
156 |
157 | Add
158 | Presets
159 | Import
160 | Export
161 | Address scope
162 | Confirm
163 | Remove this address?
164 | OK
165 | Cancel
166 | unknown domain name or incorrect format of IP address
167 | Reseting…
168 | Importing…
169 | Exported to:
170 |
171 |
172 | - Blank
173 | - Localhost
174 | - Intranet
175 | - CHN Route
176 |
177 |
178 |
179 | Choose your key file
180 | Key File Manager
181 | Current Directory
182 | Parent Directory
183 | Folder
184 | File Size
185 | Import from this file:
186 | Too many rules:
187 |
188 |
189 | Incorrect or unsupported PAC file
190 | Incorrect or unknown proxy host name
191 |
192 |
193 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ProxyDroid Plus
6 | OK, eu sei
7 | Feedback @ofmax
8 |
9 |
10 | A porta não deve estar vazia
11 | O anfitrião não deve estar vazio
12 | A porta local não deve estar vazia
13 | A porta remota não deve estar vazia
14 | Por favor verifique o número da porta
15 | O nome de utilizador não deve estar vazio
16 | O número da porta deve ser superior a 1024
17 | Está a recuperar de um crash. \n\npor favor reporte este problema na página do projeto. \n\n(proxydroid.googlecode.com)
18 | POR FAVOR FAÇA ROOT AO SEU DISPOSITIVO PRIMEIRO !!!
19 | Os programas e as configurações foram atualizados
20 |
21 |
22 | A correr em segundo plano
23 | Conectado
24 | Falha ao conectar
25 | Serviço do ProxyDroid parado
26 | A reconectar
27 | Reconectado
28 | O serviço já foi parado
29 | O serviço já foi iniciado
30 | Desconectado
31 | Por favor verifique a sua rede e os dados de login
32 | Não foi possível reconectar, o serviço está parado
33 | A conectar
34 | A conectar...
35 | A carregar a lista de aplicações...
36 |
37 |
38 | Controlador do Serviço
39 | Desconectar
40 | Conectar
41 | Estado
42 | Ativar / Desativar Proxy
43 |
44 |
45 | Definições do Proxy
46 | Anfitrião
47 | O nome anfitrião do serviço proxy
48 | PAC
49 | O URL do ficheiro PAC
50 | Definições automáticas
51 | Obter definições do proxy automaticamente de um ficheiro PAC
52 | URL do Proxy
53 | Porta
54 | O número da porta do serviço proxy
55 | Endereços a ignorar
56 | Defina os endereços a ignorar
57 |
58 |
59 | Ativar autenticação
60 | Dados da conta
61 | Utilizador
62 | Nome de utilizador do Proxy
63 | Palavra-passe
64 | Palavra-passe do Proxy
65 | Autenticação NTLM
66 | Ativar para suportar o método de autenticação NTLM / NTLM2
67 | Certificado
68 | Certificado Cliente para autenticação HTTPS
69 | Domínio
70 | Nome de domínio para NTLM
71 |
72 |
73 | Definições de funcionalidades
74 | Ligar Automaticamente
75 | Iniciar o Proxy quando a rede definida estiver disponível
76 | Rede associada
77 | Associar a configuração do proxy à rede 2G/3G ou ao SSID especificado
78 |
79 |
80 |
81 |
82 | Proxy Global
83 | Ativar o proxy global (necessita de acesso ROOT e suporte ao IPTABLES)
84 | Proxy DNS
85 | Ativar o Proxy DNS para alguns utilizadores de LAN. Ligar apenas se souber o que isto é
86 |
87 |
88 | Proxy Individual
89 | Selecione aplicações para intermediar ou ignorar (necessita de acesso ROOT e suporte ao IPTABLES)
90 | Ignorar
91 | Ative esta opção para ignorar as aplicações selecionadas em vez de as intermediar
92 | Selecione as aplicações que utilizarão o ProxyDroid:
93 |
94 |
95 | Repor
96 | \n\nO ProxyDroid é software open source
97 | publicado
98 | sob
99 | GPLv3. \n\nSe tiver alguma questão, por favor visite
100 | o site do nosso projeto no google code. \n\n(proxydroid.googlecode.com)
101 | Acerca
102 | ProxyDroid %s
103 | Renomear
104 | OK
105 | Cancelar
106 | Utilizar iptables do sistema
107 |
108 |
109 | Definições de Notificações
110 | Tom de toque
111 | Selecione o tom de toque da notificação
112 | Vibrar
113 | Vibrar quando o estado da ligação é alterado
114 |
115 |
116 | Perfis
117 | Perfil 1
118 | Novo Perfil
119 | Perfil
120 | Eliminar
121 | Eliminar este perfil?
122 |
123 |
124 | Tipo de Proxy
125 | Escolha o tipo de proxy
126 |
127 |
128 | - http
129 | - https
130 | - http-tunnel
131 |
132 | - socks4
133 | - socks5
134 |
135 |
136 | - HTTP
137 | - HTTPS
138 | - HTTP-Tunnel
139 |
140 | - SOCKS4
141 | - SOCKS5
142 |
143 |
144 |
145 | Adicionar
146 | Pré-definidos
147 | Importar
148 | Exportar
149 | Gama de endereços
150 | Confirmar
151 | Remover este endereço?
152 | OK
153 | Cancelar
154 | nome de domínio desconhecido ou endereço IP com formato incorreto
155 | A repor…
156 | A importar…
157 | Exportado para:
158 |
159 |
160 | - Vazio
161 | - Localhost
162 | - Intranet
163 | - Rota CHN
164 |
165 |
166 |
167 | Escolha o ficheiro chave
168 | Gestor de Ficheiros Chave
169 | Diretório Atual
170 | Diretório Pai
171 | Pasta
172 | Tamanho do ficheiro
173 | Importar deste ficheiro:
174 | Demasiadas regras:
175 |
176 |
177 | Ficheiro PAC incorreto ou não suportado
178 | Nome de anfitrião incorreto ou desconhecido
179 |
180 |
181 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ProxyDroid Plus
6 | OK, Je sais
7 | Commentaire @ofmax
8 |
9 |
10 | Le port ne devrait pas être vide
11 | L\'hôte ne devrait pas être vide
12 | Le port local ne devrait pas être vide
13 | Le port distant ne devrait pas être vide
14 | Merci de contrôler votre numéro de port
15 | Le nom d\'utilisateur ne devrait pas être vide
16 | Le numero de port devrait être plus grand que 1024
17 | Vous avez subit un crash. \n\nmerci de signaler votre problème sur la page du projet. \n\n(proxydroid.googlecode.com)
18 | MERCI DE ROOTER VOTRE TELEPHONE AVANT !!!
19 | Les programmes et configurations ont été mis à jour
20 |
21 |
22 | Fonctionne en arrière plan
23 | Connecté
24 | Connexion échouée
25 | Service ProxyDroid arrêté
26 | Reconnexion
27 | Reconnecté
28 | Le service est déjà arrêté
29 | Le service est déjà démarré
30 | Déconnecté
31 | Merci de vérifier vos informations de réseau et d\'identification
32 | Reconnexion impossible, service arrêté
33 | Connexion en cours
34 | Connexion en cours...
35 | Chargement de la liste des applications...
36 |
37 |
38 | Contrôle du Service
39 | Déconnecter
40 | Connecter
41 | Activation du Proxy
42 | Activer / Désactiver le Proxy
43 |
44 |
45 | Réglages Proxy
46 | Hôte
47 | Le nom de l\'hôte de votre service proxy
48 | PAC
49 | L\'URL de votre fichier PAC
50 | Réglage Auto
51 | Récupérer les réglages proxy depuis le fichier PAC automatiquement
52 | URL du Proxy
53 | Port
54 | Le numéro de port de votre service Proxy
55 | Adresses de Contournement
56 | Définir les adresses de contournement
57 |
58 |
59 | Activer l\'Authentication
60 | Information du compte
61 | Utilisateur
62 | Identifiant
63 | Mot de passe
64 | Mot de passe du Proxy
65 | Authentication NTLM
66 | Activer le support de la méthode d\'authentification
67 | NTLM / NTLM2
68 | Certificat
69 | Certificat Client pour l\'authentification HTTPS
70 | Domaine
71 | Nom de domaine pour NTLM
72 |
73 |
74 | Paramètres des Fonctions
75 | Connexion Auto
76 | Démarrer le Proxy quand le réseau défini est disponible
77 | Réseau lié
78 | Relier votre réglage proxy à un réseau 2G/3G où au
79 | SSID défini
80 | Ne jamais relier ces SSID WiFi
81 | Ne jamais relier le réglage proxy au SSID défini
82 |
83 |
84 |
85 |
86 |
87 |
88 | Proxy Global
89 | Activer le proxy global (nécessite les droits ROOT
90 | et le support IPTABLES)
91 | Proxy DNS
92 | Activer le Proxy DNS pour certains utilisateurs LAN. Ne l\'activez
93 | que si vous savez ce que c\'est
94 |
95 |
96 | Proxy Individuel
97 | Selectionner les applications à proxyfier où à contourner (nécessite les droits ROOT
98 | et
99 | le support IPTABLES)
100 | Mode de Contournement
101 | Activer cette option pour contourner les applications sélectionnées au lieu de les proxyfier
102 | Selectionner les applications à utiliser avec ProxyDroid :
103 |
104 |
105 | Réinitialiser
106 | \n\nProxyDroid est un logiciel open source
107 | publié sous
108 | licence
109 | GPLv3. \n\nSi vous avez des questions, merci de visiter
110 | notre site
111 | du projet sur
112 | google code. \n\n(proxydroid.googlecode.com)
113 | A propos
114 | ProxyDroid %s
115 | Renommer
116 | OK
117 | Annuler
118 | Utiliser iptables système
119 |
120 |
121 | Réglage de Notification
122 | Sonnerie
123 | Selectionner la sonnerie de notification
124 | Vibration
125 | Vibrer également quand la connectivité change
126 |
127 |
128 | Profils
129 | Profil 1
130 | Nouveau Profil
131 | Profil
132 | Supprimer
133 | Supprimer ce profil ?
134 |
135 |
136 | Type de Proxy
137 | Sélectionner votre type de proxy
138 |
139 |
140 | - http
141 | - https
142 | - http-tunnel
143 |
144 | - socks4
145 | - socks5
146 |
147 |
148 | - HTTP
149 | - HTTPS
150 | - HTTP-Tunnel
151 |
152 | - SOCKS4
153 | - SOCKS5
154 |
155 |
156 |
157 | Ajouter
158 | Preréglages
159 | Importer
160 | Exporter
161 | Liste d\'Addresses
162 | Confirmer
163 | Supprimer cette addresse ?
164 | OK
165 | Annuler
166 | Nom de domaine inconnu ou format de l\'adresse IP incorrect
167 | Réinitialisation…
168 | Import en cours…
169 | Exporté vers :
170 |
171 |
172 | - Vide
173 | - Localhost
174 | - Intranet
175 | - CHN Route
176 |
177 |
178 |
179 | Sélectionner votre fichier clé
180 | Gestionnaire de fichier Clé
181 | Répertoire Actuel
182 | Répertoire Parent
183 | Répertoire
184 | Taille du Fichier
185 | Importer depuis ce fichier :
186 | Trop de règles :
187 |
188 |
189 | Fichier PAC Incorrect ou non supporté
190 | Nom d\'hôte du proxy Incorrect ou inconnu
191 |
192 |
193 |
--------------------------------------------------------------------------------
/app/src/main/java/com/btr/proxy/selector/pac/ScriptMethods.java:
--------------------------------------------------------------------------------
1 | package com.btr.proxy.selector.pac;
2 |
3 | /***************************************************************************
4 | * Defines the public interface for PAC scripts.
5 | *
6 | * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
7 | ***************************************************************************/
8 | public interface ScriptMethods {
9 |
10 | public boolean isPlainHostName(String host);
11 |
12 | /*************************************************************************
13 | * Tests if an URL is in a given domain.
14 | *
15 | * @param host
16 | * is the host name from the URL.
17 | * @param domain
18 | * is the domain name to test the host name against.
19 | * @return true if the domain of host name matches.
20 | ************************************************************************/
21 |
22 | public boolean dnsDomainIs(String host, String domain);
23 |
24 | /*************************************************************************
25 | * Is true if the host name matches exactly the specified host name, or if
26 | * there is no domain name part in the host name, but the unqualified host
27 | * name matches.
28 | *
29 | * @param host
30 | * the host name from the URL.
31 | * @param domain
32 | * fully qualified host name with domain to match against.
33 | * @return true if matches else false.
34 | ************************************************************************/
35 |
36 | public boolean localHostOrDomainIs(String host, String domain);
37 |
38 | /*************************************************************************
39 | * Tries to resolve the host name. Returns true if succeeds.
40 | *
41 | * @param host
42 | * is the host name from the URL.
43 | * @return true if resolvable else false.
44 | ************************************************************************/
45 |
46 | public boolean isResolvable(String host);
47 |
48 | /*************************************************************************
49 | * Tries to resolve the host name. Returns true if succeeds to resolve the
50 | * host to an IPv4 or IPv6 address.
51 | *
52 | * @param host
53 | * is the host name from the URL.
54 | * @return true if resolvable else false.
55 | ************************************************************************/
56 |
57 | public boolean isResolvableEx(String host);
58 |
59 | /*************************************************************************
60 | * Returns true if the IP address of the host matches the specified IP
61 | * address pattern. Pattern and mask specification is done the same way as
62 | * for SOCKS configuration.
63 | *
64 | * Example: isInNet(host, "198.95.0.0", "255.255.0.0") is true if the IP
65 | * address of the host matches 198.95.*.*.
66 | *
67 | * @param host
68 | * a DNS host name, or IP address. If a host name is passed, it
69 | * will be resolved into an IP address by this function.
70 | * @param pattern
71 | * an IP address pattern in the dot-separated format.
72 | * @param mask
73 | * mask for the IP address pattern informing which parts of the
74 | * IP address should be matched against. 0 means ignore, 255
75 | * means match.
76 | * @return true if it matches else false.
77 | ************************************************************************/
78 |
79 | public boolean isInNet(String host, String pattern, String mask);
80 |
81 | /*************************************************************************
82 | * Extension of the isInNet method to support IPv6.
83 | *
84 | * @param ipAddress
85 | * an IP4 or IP6 address
86 | * @param ipPrefix
87 | * A string containing colon delimited IP prefix with top n bits
88 | * specified in the bit field (i.e. 3ffe:8311:ffff::/48 or
89 | * 123.112.0.0/16).
90 | * @return true if the host is in the given subnet, else false.
91 | ************************************************************************/
92 |
93 | public boolean isInNetEx(String ipAddress, String ipPrefix);
94 |
95 | /*************************************************************************
96 | * Resolves the given DNS host name into an IP address, and returns it in
97 | * the dot separated format as a string.
98 | *
99 | * @param host
100 | * the host to resolve.
101 | * @return the resolved IP, empty string if not resolvable.
102 | ************************************************************************/
103 |
104 | public String dnsResolve(String host);
105 |
106 | /*************************************************************************
107 | * @param host
108 | * the host to resolve
109 | * @return a semicolon separated list of IP6 and IP4 addresses the host name
110 | * resolves to, empty string if not resolvable.
111 | ************************************************************************/
112 |
113 | public String dnsResolveEx(String host);
114 |
115 | /*************************************************************************
116 | * Returns the IP address of the host that the process is running on, as a
117 | * string in the dot-separated integer format.
118 | *
119 | * @return an IP as string.
120 | ************************************************************************/
121 |
122 | public String myIpAddress();
123 |
124 | /*************************************************************************
125 | * Returns a list of IP4 and IP6 addresses of the host that the process is
126 | * running on. The list is separated with semicolons.
127 | *
128 | * @return the list, empty string if not available.
129 | ************************************************************************/
130 |
131 | public String myIpAddressEx();
132 |
133 | /*************************************************************************
134 | * Returns the number of DNS domain levels (number of dots) in the host
135 | * name.
136 | *
137 | * @param host
138 | * is the host name from the URL.
139 | * @return number of DNS domain levels.
140 | ************************************************************************/
141 |
142 | public int dnsDomainLevels(String host);
143 |
144 | /*************************************************************************
145 | * Returns true if the string matches the specified shell expression.
146 | * Actually, currently the patterns are shell expressions, not regular
147 | * expressions.
148 | *
149 | * @param str
150 | * is any string to compare (e.g. the URL, or the host name).
151 | * @param shexp
152 | * is a shell expression to compare against.
153 | * @return true if the string matches, else false.
154 | ************************************************************************/
155 |
156 | public boolean shExpMatch(String str, String shexp);
157 |
158 | /*************************************************************************
159 | * Only the first parameter is mandatory. Either the second, the third, or
160 | * both may be left out. If only one parameter is present, the function
161 | * yields a true value on the weekday that the parameter represents. If the
162 | * string "GMT" is specified as a second parameter, times are taken to be in
163 | * GMT, otherwise in local time zone. If both wd1 and wd2 are defined, the
164 | * condition is true if the current weekday is in between those two
165 | * weekdays. Bounds are inclusive. If the "GMT" parameter is specified,
166 | * times are taken to be in GMT, otherwise the local time zone is used.
167 | *
168 | * @param wd1
169 | * weekday 1 is one of SUN MON TUE WED THU FRI SAT
170 | * @param wd2
171 | * weekday 2 is one of SUN MON TUE WED THU FRI SAT
172 | * @param gmt
173 | * "GMT" for gmt time format else "undefined"
174 | * @return true if current day matches the criteria.
175 | ************************************************************************/
176 |
177 | public boolean weekdayRange(String wd1, String wd2, String gmt);
178 |
179 | /*************************************************************************
180 | * Only the first parameter is mandatory. All other parameters can be left
181 | * out therefore the meaning of the parameters changes. The method
182 | * definition shows the version with the most possible parameters filled.
183 | * The real meaning of the parameters is guessed from it's value. If "from"
184 | * and "to" are specified then the bounds are inclusive. If the "GMT"
185 | * parameter is specified, times are taken to be in GMT, otherwise the local
186 | * time zone is used.
187 | *
188 | * @param day1
189 | * is the day of month between 1 and 31 (as an integer).
190 | * @param month1
191 | * one of JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
192 | * @param year1
193 | * is the full year number, for example 1995 (but not 95).
194 | * Integer.
195 | * @param day2
196 | * is the day of month between 1 and 31 (as an integer).
197 | * @param month2
198 | * one of JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
199 | * @param year2
200 | * is the full year number, for example 1995 (but not 95).
201 | * Integer.
202 | * @param gmt
203 | * "GMT" for gmt time format else "undefined"
204 | * @return true if the current date matches the given range.
205 | ************************************************************************/
206 |
207 | public boolean dateRange(Object day1, Object month1, Object year1,
208 | Object day2, Object month2, Object year2, Object gmt);
209 |
210 | /*************************************************************************
211 | * Some parameters can be left out therefore the meaning of the parameters
212 | * changes. The method definition shows the version with the most possible
213 | * parameters filled. The real meaning of the parameters is guessed from
214 | * it's value. If "from" and "to" are specified then the bounds are
215 | * inclusive. If the "GMT" parameter is specified, times are taken to be in
216 | * GMT, otherwise the local time zone is used.
217 | *
218 | *
219 | * timeRange(hour)
220 | * timeRange(hour1, hour2)
221 | * timeRange(hour1, min1, hour2, min2)
222 | * timeRange(hour1, min1, sec1, hour2, min2, sec2)
223 | * timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt)
224 | *
225 | *
226 | * @param hour1
227 | * is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.)
228 | * @param min1
229 | * minutes from 0 to 59.
230 | * @param sec1
231 | * seconds from 0 to 59.
232 | * @param hour2
233 | * is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.)
234 | * @param min2
235 | * minutes from 0 to 59.
236 | * @param sec2
237 | * seconds from 0 to 59.
238 | * @param gmt
239 | * "GMT" for gmt time format else "undefined"
240 | * @return true if the current time matches the given range.
241 | ************************************************************************/
242 |
243 | public boolean timeRange(Object hour1, Object min1, Object sec1,
244 | Object hour2, Object min2, Object sec2, Object gmt);
245 |
246 | /*************************************************************************
247 | * Sorts a list of IP4 and IP6 addresses. Separated by semicolon. Dual
248 | * addresses first, then IPv6 and last IPv4.
249 | *
250 | * @param ipAddressList
251 | * the address list.
252 | * @return the sorted list, empty string if sort is not possible
253 | ************************************************************************/
254 |
255 | public String sortIpAddressList(String ipAddressList);
256 |
257 | /*************************************************************************
258 | * Gets the version of the PAC extension that is available.
259 | *
260 | * @return the extension version, currently 1.0
261 | ************************************************************************/
262 |
263 | public String getClientVersion();
264 |
265 | }
266 |
--------------------------------------------------------------------------------
/app/src/main/cpp/exec/termExec.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /*
18 | * Copyright (C) 2007 The Android Open Source Project
19 | *
20 | * Licensed under the Apache License, Version 2.0 (the "License");
21 | * you may not use this file except in compliance with the License.
22 | * You may obtain a copy of the License at
23 | *
24 | * http://www.apache.org/licenses/LICENSE-2.0
25 | *
26 | * Unless required by applicable law or agreed to in writing, software
27 | * distributed under the License is distributed on an "AS IS" BASIS,
28 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 | * See the License for the specific language governing permissions and
30 | * limitations under the License.
31 | */
32 |
33 | #define LOG_TAG "ProxyDroid"
34 |
35 | #include "jni.h"
36 | #include
37 |
38 | #define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0)
39 | #define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0)
40 | #define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0)
41 |
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include
52 | #include
53 | #include
54 |
55 | static jclass class_fileDescriptor;
56 | static jfieldID field_fileDescriptor_descriptor;
57 | static jmethodID method_fileDescriptor_init;
58 |
59 | typedef unsigned short jchar16_t;
60 |
61 | class String8 {
62 | public:
63 | String8() {
64 | mString = 0;
65 | }
66 |
67 | ~String8() {
68 | if (mString) {
69 | free(mString);
70 | }
71 | }
72 |
73 | void set(const jchar16_t* o, size_t numChars) {
74 | if (mString) {
75 | free(mString);
76 | }
77 | mString = (char*) malloc(numChars + 1);
78 | if (!mString) {
79 | return;
80 | }
81 | for (size_t i = 0; i < numChars; i++) {
82 | mString[i] = (char) o[i];
83 | }
84 | mString[numChars] = '\0';
85 | }
86 |
87 | const char* string() {
88 | return mString;
89 | }
90 | private:
91 | char* mString;
92 | };
93 |
94 | static int throwOutOfMemoryError(JNIEnv *env, const char *message)
95 | {
96 | jclass exClass;
97 | const char *className = "java/lang/OutOfMemoryError";
98 |
99 | exClass = env->FindClass(className);
100 | return env->ThrowNew(exClass, message);
101 | }
102 |
103 | static int create_subprocess(const int rdt, const char *cmd, char *const argv[],
104 | char *const envp[], const char* scripts, int* pProcessId)
105 | {
106 | pid_t pid;
107 | int pfds[2];
108 | int pfds2[2];
109 |
110 | pipe(pfds);
111 |
112 | if (rdt) {
113 | pipe(pfds2);
114 | }
115 |
116 | pid = fork();
117 |
118 | if(pid < 0) {
119 | LOGE("- fork failed: %s -\n", strerror(errno));
120 | return -1;
121 | }
122 |
123 | if(pid == 0){
124 |
125 | signal(SIGPIPE, SIG_IGN);
126 |
127 | if (envp) {
128 | for (; *envp; ++envp) {
129 | putenv(*envp);
130 | }
131 | }
132 |
133 | dup2(pfds[0], 0);
134 | close(pfds[1]);
135 |
136 | if (rdt) {
137 | close(1);
138 | close(2);
139 | dup2(pfds2[1], 1);
140 | dup2(pfds2[1], 2);
141 | close(pfds2[0]);
142 | }
143 |
144 | execv(cmd, argv);
145 |
146 | fflush(NULL);
147 |
148 | exit(0);
149 |
150 | } else {
151 |
152 | signal(SIGPIPE, SIG_IGN);
153 |
154 | *pProcessId = (int) pid;
155 |
156 | dup2(pfds[1], 1);
157 | close(pfds[0]);
158 |
159 | write(pfds[1], scripts, strlen(scripts)+1);
160 | if (rdt) {
161 | close(pfds2[1]);
162 | return pfds2[0];
163 | } else {
164 | return -1;
165 | }
166 | }
167 | }
168 |
169 |
170 | static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
171 | jint rdt, jstring cmd, jobjectArray args, jobjectArray envVars, jstring scripts,
172 | jintArray processIdArray)
173 | {
174 | const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
175 | String8 cmd_8;
176 | if (str) {
177 | cmd_8.set(str, env->GetStringLength(cmd));
178 | env->ReleaseStringCritical(cmd, str);
179 | }
180 |
181 | const jchar* str_scripts = scripts ? env->GetStringCritical(scripts, 0) : 0;
182 | String8 scripts_8;
183 | if (str_scripts) {
184 | scripts_8.set(str_scripts, env->GetStringLength(scripts));
185 | env->ReleaseStringCritical(scripts, str_scripts);
186 | }
187 |
188 | jsize size = args ? env->GetArrayLength(args) : 0;
189 | char **argv = NULL;
190 | String8 tmp_8;
191 | if (size > 0) {
192 | argv = (char **)malloc((size+1)*sizeof(char *));
193 | if (!argv) {
194 | throwOutOfMemoryError(env, "Couldn't allocate argv array");
195 | return NULL;
196 | }
197 | for (int i = 0; i < size; ++i) {
198 | jstring arg = reinterpret_cast(env->GetObjectArrayElement(args, i));
199 | str = env->GetStringCritical(arg, 0);
200 | if (!str) {
201 | throwOutOfMemoryError(env, "Couldn't get argument from array");
202 | return NULL;
203 | }
204 | tmp_8.set(str, env->GetStringLength(arg));
205 | env->ReleaseStringCritical(arg, str);
206 | argv[i] = strdup(tmp_8.string());
207 | }
208 | argv[size] = NULL;
209 | }
210 |
211 | size = envVars ? env->GetArrayLength(envVars) : 0;
212 | char **envp = NULL;
213 | if (size > 0) {
214 | envp = (char **)malloc((size+1)*sizeof(char *));
215 | if (!envp) {
216 | throwOutOfMemoryError(env, "Couldn't allocate envp array");
217 | return NULL;
218 | }
219 | for (int i = 0; i < size; ++i) {
220 | jstring var = reinterpret_cast(env->GetObjectArrayElement(envVars, i));
221 | str = env->GetStringCritical(var, 0);
222 | if (!str) {
223 | throwOutOfMemoryError(env, "Couldn't get env var from array");
224 | return NULL;
225 | }
226 | tmp_8.set(str, env->GetStringLength(var));
227 | env->ReleaseStringCritical(var, str);
228 | envp[i] = strdup(tmp_8.string());
229 | }
230 | envp[size] = NULL;
231 | }
232 |
233 | int procId;
234 | int ptm = create_subprocess(rdt, cmd_8.string(), argv, envp, scripts_8.string(),
235 | &procId);
236 |
237 | if (argv) {
238 | for (char **tmp = argv; *tmp; ++tmp) {
239 | free(*tmp);
240 | }
241 | free(argv);
242 | }
243 | if (envp) {
244 | for (char **tmp = envp; *tmp; ++tmp) {
245 | free(*tmp);
246 | }
247 | free(envp);
248 | }
249 |
250 | if (processIdArray) {
251 | int procIdLen = env->GetArrayLength(processIdArray);
252 | if (procIdLen > 0) {
253 | jboolean isCopy;
254 |
255 | int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
256 | if (pProcId) {
257 | *pProcId = procId;
258 | env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
259 | }
260 | }
261 | }
262 |
263 | jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init);
264 |
265 | if (!result) {
266 | LOGE("Couldn't create a FileDescriptor.");
267 | }
268 | else {
269 | env->SetIntField(result, field_fileDescriptor_descriptor, ptm);
270 | }
271 |
272 | return result;
273 | }
274 |
275 |
276 | static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz,
277 | jint procId) {
278 | int status;
279 | waitpid(procId, &status, 0);
280 | int result = 0;
281 | if (WIFEXITED(status)) {
282 | result = WEXITSTATUS(status);
283 | }
284 | return result;
285 | }
286 |
287 | static void android_os_Exec_close(JNIEnv *env, jobject clazz, jobject fileDescriptor)
288 | {
289 | int fd;
290 |
291 | fd = env->GetIntField(fileDescriptor, field_fileDescriptor_descriptor);
292 |
293 | if (env->ExceptionOccurred() != NULL) {
294 | return;
295 | }
296 |
297 | close(fd);
298 | }
299 |
300 | static void android_os_Exec_hangupProcessGroup(JNIEnv *env, jobject clazz,
301 | jint procId) {
302 | kill(-procId, SIGHUP);
303 | }
304 |
305 |
306 | static int register_FileDescriptor(JNIEnv *env)
307 | {
308 | jclass localRef_class_fileDescriptor = env->FindClass("java/io/FileDescriptor");
309 |
310 | if (localRef_class_fileDescriptor == NULL) {
311 | LOGE("Can't find class java/io/FileDescriptor");
312 | return -1;
313 | }
314 |
315 | class_fileDescriptor = (jclass) env->NewGlobalRef(localRef_class_fileDescriptor);
316 |
317 | env->DeleteLocalRef(localRef_class_fileDescriptor);
318 |
319 | if (class_fileDescriptor == NULL) {
320 | LOGE("Can't get global ref to class java/io/FileDescriptor");
321 | return -1;
322 | }
323 |
324 | field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I");
325 |
326 | if (field_fileDescriptor_descriptor == NULL) {
327 | LOGE("Can't find FileDescriptor.descriptor");
328 | return -1;
329 | }
330 |
331 | method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "", "()V");
332 | if (method_fileDescriptor_init == NULL) {
333 | LOGE("Can't find FileDescriptor.init");
334 | return -1;
335 | }
336 | return 0;
337 | }
338 |
339 |
340 | static const char *classPathName = "org/proxydroid/Exec";
341 |
342 | static JNINativeMethod method_table[] = {
343 | { "createSubprocess", "(ILjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
344 | (void*) android_os_Exec_createSubProcess },
345 | { "waitFor", "(I)I",
346 | (void*) android_os_Exec_waitFor},
347 | { "close", "(Ljava/io/FileDescriptor;)V",
348 | (void*) android_os_Exec_close},
349 | { "hangupProcessGroup", "(I)V",
350 | (void*) android_os_Exec_hangupProcessGroup}
351 | };
352 |
353 | /*
354 | * Register several native methods for one class.
355 | */
356 | static int registerNativeMethods(JNIEnv* env, const char* className,
357 | JNINativeMethod* gMethods, int numMethods)
358 | {
359 | jclass clazz;
360 |
361 | clazz = env->FindClass(className);
362 | if (clazz == NULL) {
363 | LOGE("Native registration unable to find class '%s'", className);
364 | return JNI_FALSE;
365 | }
366 | if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
367 | LOGE("RegisterNatives failed for '%s'", className);
368 | return JNI_FALSE;
369 | }
370 |
371 | return JNI_TRUE;
372 | }
373 |
374 | /*
375 | * Register native methods for all classes we know about.
376 | *
377 | * returns JNI_TRUE on success.
378 | */
379 | static int registerNatives(JNIEnv* env)
380 | {
381 | if (!registerNativeMethods(env, classPathName, method_table,
382 | sizeof(method_table) / sizeof(method_table[0]))) {
383 | return JNI_FALSE;
384 | }
385 |
386 | return JNI_TRUE;
387 | }
388 |
389 |
390 | // ----------------------------------------------------------------------------
391 |
392 | /*
393 | * This is called by the VM when the shared library is first loaded.
394 | */
395 |
396 | typedef union {
397 | JNIEnv* env;
398 | void* venv;
399 | } UnionJNIEnvToVoid;
400 |
401 | jint JNI_OnLoad(JavaVM* vm, void* reserved) {
402 | UnionJNIEnvToVoid uenv;
403 | uenv.venv = NULL;
404 | jint result = -1;
405 | JNIEnv* env = NULL;
406 |
407 | LOGI("JNI_OnLoad");
408 |
409 | if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
410 | LOGE("ERROR: GetEnv failed");
411 | goto bail;
412 | }
413 | env = uenv.env;
414 |
415 | if ((result = register_FileDescriptor(env)) < 0) {
416 | LOGE("ERROR: registerFileDescriptor failed");
417 | goto bail;
418 | }
419 |
420 | if (registerNatives(env) != JNI_TRUE) {
421 | LOGE("ERROR: registerNatives failed");
422 | goto bail;
423 | }
424 |
425 | result = JNI_VERSION_1_4;
426 |
427 | bail:
428 | return result;
429 | }
430 |
--------------------------------------------------------------------------------
/app/src/main/java/org/proxydroid/AppManager.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
2 | /* See LICENSE for licensing information */
3 |
4 | package org.proxydroid;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.content.SharedPreferences;
9 | import android.content.SharedPreferences.Editor;
10 | import android.content.pm.ApplicationInfo;
11 | import android.content.pm.PackageManager;
12 | import android.graphics.PixelFormat;
13 | import android.os.Bundle;
14 | import android.os.Handler;
15 | import android.os.Looper;
16 | import android.os.Message;
17 | import androidx.preference.PreferenceManager;
18 | import android.view.LayoutInflater;
19 | import android.view.MenuItem;
20 | import android.view.View;
21 | import android.view.View.OnClickListener;
22 | import android.view.ViewGroup;
23 | import android.view.ViewGroup.LayoutParams;
24 | import android.view.WindowManager;
25 | import android.widget.AbsListView;
26 | import android.widget.AbsListView.OnScrollListener;
27 | import android.widget.ArrayAdapter;
28 | import android.widget.CheckBox;
29 | import android.widget.CompoundButton;
30 | import android.widget.CompoundButton.OnCheckedChangeListener;
31 | import android.widget.ImageView;
32 | import android.widget.ListAdapter;
33 | import android.widget.ListView;
34 | import android.widget.TextView;
35 |
36 | import androidx.appcompat.app.AlertDialog;
37 | import androidx.appcompat.app.AppCompatActivity;
38 |
39 | import com.google.firebase.analytics.FirebaseAnalytics;
40 |
41 | import org.proxydroid.utils.ImageLoader;
42 | import org.proxydroid.utils.ImageLoaderFactory;
43 |
44 | import java.util.Arrays;
45 | import java.util.Comparator;
46 | import java.util.Iterator;
47 | import java.util.List;
48 | import java.util.StringTokenizer;
49 | import java.util.Vector;
50 |
51 | public class AppManager extends AppCompatActivity implements OnCheckedChangeListener,
52 | OnClickListener {
53 |
54 | private ProxyedApp[] apps = null;
55 |
56 | private ListView listApps;
57 |
58 | private AppManager mAppManager;
59 |
60 | private TextView overlay;
61 |
62 | private AlertDialog ad = null;
63 | private ListAdapter adapter;
64 |
65 | private ImageLoader dm;
66 |
67 | private static final int MSG_LOAD_START = 1;
68 | private static final int MSG_LOAD_FINISH = 2;
69 |
70 | public final static String PREFS_KEY_PROXYED = "Proxyed";
71 |
72 | private boolean appsLoaded = false;
73 |
74 | final Handler handler = new Handler(Looper.getMainLooper()) {
75 | @Override
76 | public void handleMessage(Message msg) {
77 | switch (msg.what) {
78 | case MSG_LOAD_START:
79 | ad = new AlertDialog.Builder(AppManager.this)
80 | .setMessage(R.string.loading)
81 | .setCancelable(true).create();
82 | ad.show();
83 | break;
84 | case MSG_LOAD_FINISH:
85 |
86 | listApps.setAdapter(adapter);
87 |
88 | listApps.setOnScrollListener(new OnScrollListener() {
89 |
90 | boolean visible;
91 |
92 | @Override
93 | public void onScrollStateChanged(AbsListView view,
94 | int scrollState) {
95 | visible = true;
96 | if (scrollState == ListView.OnScrollListener.SCROLL_STATE_IDLE) {
97 | overlay.setVisibility(View.INVISIBLE);
98 | }
99 | }
100 |
101 | @Override
102 | public void onScroll(AbsListView view,
103 | int firstVisibleItem, int visibleItemCount,
104 | int totalItemCount) {
105 | if (visible) {
106 | String name = apps[firstVisibleItem].getName();
107 | if (name != null && name.length() > 1)
108 | overlay.setText(apps[firstVisibleItem]
109 | .getName().substring(0, 1));
110 | else
111 | overlay.setText("*");
112 | overlay.setVisibility(View.VISIBLE);
113 | }
114 | }
115 | });
116 |
117 | if (ad != null) {
118 | ad.dismiss();
119 | ad = null;
120 | }
121 | break;
122 | }
123 | super.handleMessage(msg);
124 | }
125 | };
126 |
127 | @Override
128 | public boolean onOptionsItemSelected(MenuItem item) {
129 | switch (item.getItemId()) {
130 | case android.R.id.home:
131 | // app icon in action bar clicked; go home
132 | // Intent intent = new Intent(this, ProxyDroid.class);
133 | // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
134 | // startActivity(intent);
135 | finish();
136 | return true;
137 | default:
138 | return super.onOptionsItemSelected(item);
139 | }
140 | }
141 |
142 | @Override
143 | protected void onCreate(Bundle savedInstanceState) {
144 | super.onCreate(savedInstanceState);
145 |
146 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
147 |
148 | this.setContentView(R.layout.layout_apps);
149 |
150 | dm = ImageLoaderFactory.getImageLoader(this);
151 |
152 | this.overlay = (TextView) View.inflate(this, R.layout.overlay, null);
153 | getWindowManager()
154 | .addView(
155 | overlay,
156 | new WindowManager.LayoutParams(
157 | LayoutParams.WRAP_CONTENT,
158 | LayoutParams.WRAP_CONTENT,
159 | WindowManager.LayoutParams.TYPE_APPLICATION,
160 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
161 | | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
162 | PixelFormat.TRANSLUCENT));
163 |
164 | mAppManager = this;
165 |
166 | }
167 |
168 | /** Called when the activity is closed. */
169 | @Override
170 | public void onDestroy() {
171 |
172 | getWindowManager().removeView(overlay);
173 |
174 | super.onDestroy();
175 | }
176 |
177 | @Override
178 | protected void onResume() {
179 | super.onResume();
180 |
181 | new Thread() {
182 |
183 | @Override
184 | public void run() {
185 | handler.sendEmptyMessage(MSG_LOAD_START);
186 |
187 | listApps = (ListView) findViewById(R.id.applistview);
188 |
189 | if (!appsLoaded)
190 | loadApps();
191 | handler.sendEmptyMessage(MSG_LOAD_FINISH);
192 | }
193 | }.start();
194 |
195 | }
196 |
197 | private void loadApps() {
198 | getApps(this);
199 |
200 | Arrays.sort(apps, new Comparator() {
201 | @Override
202 | public int compare(ProxyedApp o1, ProxyedApp o2) {
203 | if (o1 == null || o2 == null || o1.getName() == null
204 | || o2.getName() == null)
205 | return 1;
206 | if (o1.isProxyed() == o2.isProxyed())
207 | return o1.getName().compareTo(o2.getName());
208 | if (o1.isProxyed())
209 | return -1;
210 | return 1;
211 | }
212 | });
213 |
214 | final LayoutInflater inflater = getLayoutInflater();
215 |
216 | adapter = new ArrayAdapter(this, R.layout.layout_apps_item,
217 | R.id.itemtext, apps) {
218 | @Override
219 | public View getView(int position, View convertView, ViewGroup parent) {
220 | ListEntry entry;
221 | if (convertView == null) {
222 | // Inflate a new view
223 | convertView = inflater.inflate(R.layout.layout_apps_item,
224 | parent, false);
225 | entry = new ListEntry();
226 | entry.icon = (ImageView) convertView
227 | .findViewById(R.id.itemicon);
228 | entry.box = (CheckBox) convertView
229 | .findViewById(R.id.itemcheck);
230 | entry.text = (TextView) convertView
231 | .findViewById(R.id.itemtext);
232 |
233 | entry.text.setOnClickListener(mAppManager);
234 |
235 | convertView.setTag(entry);
236 |
237 | entry.box.setOnCheckedChangeListener(mAppManager);
238 | } else {
239 | // Convert an existing view
240 | entry = (ListEntry) convertView.getTag();
241 | }
242 |
243 | final ProxyedApp app = apps[position];
244 |
245 | entry.icon.setTag(app.getUid());
246 |
247 | dm.DisplayImage(app.getUid(),
248 | (Activity) convertView.getContext(), entry.icon);
249 |
250 | entry.text.setText(app.getName());
251 |
252 | final CheckBox box = entry.box;
253 | box.setTag(app);
254 | box.setChecked(app.isProxyed());
255 |
256 | entry.text.setTag(box);
257 |
258 | return convertView;
259 | }
260 | };
261 |
262 | appsLoaded = true;
263 |
264 | }
265 |
266 | private static class ListEntry {
267 | private CheckBox box;
268 | private TextView text;
269 | private ImageView icon;
270 | }
271 |
272 | /*
273 | * (non-Javadoc)
274 | *
275 | * @see android.app.Activity#onStop()
276 | */
277 | @Override
278 | protected void onStop() {
279 | super.onStop();
280 |
281 | // Log.d(getClass().getName(),"Exiting Preferences");
282 | }
283 |
284 | public static ProxyedApp[] getProxyedApps(Context context, boolean self) {
285 |
286 | SharedPreferences prefs = PreferenceManager
287 | .getDefaultSharedPreferences(context);
288 |
289 | String tordAppString = prefs.getString(PREFS_KEY_PROXYED, "");
290 | String[] tordApps;
291 |
292 | StringTokenizer st = new StringTokenizer(tordAppString, "|");
293 | tordApps = new String[st.countTokens()];
294 | int tordIdx = 0;
295 | while (st.hasMoreTokens()) {
296 | tordApps[tordIdx++] = st.nextToken();
297 | }
298 |
299 | Arrays.sort(tordApps);
300 |
301 | // else load the apps up
302 | PackageManager pMgr = context.getPackageManager();
303 |
304 | List lAppInfo = pMgr.getInstalledApplications(0);
305 |
306 | Iterator itAppInfo = lAppInfo.iterator();
307 |
308 | Vector vectorApps = new Vector();
309 |
310 | ApplicationInfo aInfo = null;
311 |
312 | int appIdx = 0;
313 |
314 | while (itAppInfo.hasNext()) {
315 | aInfo = itAppInfo.next();
316 |
317 | // ignore all system apps
318 | if (aInfo.uid < 10000)
319 | continue;
320 |
321 | ProxyedApp app = new ProxyedApp();
322 |
323 | app.setUid(aInfo.uid);
324 |
325 | app.setUsername(pMgr.getNameForUid(app.getUid()));
326 |
327 | // check if this application is allowed
328 | if (aInfo.packageName != null
329 | && aInfo.packageName.equals("org.proxydroid")) {
330 | if (self)
331 | app.setProxyed(true);
332 | } else if (Arrays.binarySearch(tordApps, app.getUsername()) >= 0) {
333 | app.setProxyed(true);
334 | } else {
335 | app.setProxyed(false);
336 | }
337 |
338 | if (app.isProxyed())
339 | vectorApps.add(app);
340 |
341 | }
342 |
343 | ProxyedApp[] apps = new ProxyedApp[vectorApps.size()];
344 | vectorApps.toArray(apps);
345 | return apps;
346 | }
347 |
348 | public void getApps(Context context) {
349 |
350 | SharedPreferences prefs = PreferenceManager
351 | .getDefaultSharedPreferences(context);
352 |
353 | String tordAppString = prefs.getString(PREFS_KEY_PROXYED, "");
354 | String[] tordApps;
355 |
356 | StringTokenizer st = new StringTokenizer(tordAppString, "|");
357 | tordApps = new String[st.countTokens()];
358 | int tordIdx = 0;
359 | while (st.hasMoreTokens()) {
360 | tordApps[tordIdx++] = st.nextToken();
361 | }
362 |
363 | Arrays.sort(tordApps);
364 |
365 | Vector vectorApps = new Vector();
366 |
367 | // else load the apps up
368 | PackageManager pMgr = context.getPackageManager();
369 |
370 | List lAppInfo = pMgr.getInstalledApplications(0);
371 |
372 | Iterator itAppInfo = lAppInfo.iterator();
373 |
374 | ApplicationInfo aInfo = null;
375 |
376 | while (itAppInfo.hasNext()) {
377 | aInfo = itAppInfo.next();
378 |
379 | // ignore system apps
380 | if (aInfo.uid < 10000)
381 | continue;
382 |
383 | if (aInfo.processName == null)
384 | continue;
385 | if (pMgr.getApplicationLabel(aInfo).toString().equals(""))
386 | continue;
387 |
388 | ProxyedApp tApp = new ProxyedApp();
389 |
390 | tApp.setEnabled(aInfo.enabled);
391 | tApp.setUid(aInfo.uid);
392 | tApp.setUsername(pMgr.getNameForUid(tApp.getUid()));
393 | tApp.setProcname(aInfo.processName);
394 | tApp.setName(pMgr.getApplicationLabel(aInfo).toString());
395 |
396 | // check if this application is allowed
397 | if (Arrays.binarySearch(tordApps, tApp.getUsername()) >= 0) {
398 | tApp.setProxyed(true);
399 | } else {
400 | tApp.setProxyed(false);
401 | }
402 |
403 | vectorApps.add(tApp);
404 | }
405 |
406 | apps = new ProxyedApp[vectorApps.size()];
407 | vectorApps.toArray(apps);
408 |
409 | }
410 |
411 | public void saveAppSettings(Context context) {
412 | if (apps == null)
413 | return;
414 |
415 | SharedPreferences prefs = PreferenceManager
416 | .getDefaultSharedPreferences(this);
417 |
418 | // final SharedPreferences prefs =
419 | // context.getSharedPreferences(PREFS_KEY, 0);
420 |
421 | StringBuilder tordApps = new StringBuilder();
422 |
423 | for (int i = 0; i < apps.length; i++) {
424 | if (apps[i].isProxyed()) {
425 | tordApps.append(apps[i].getUsername());
426 | tordApps.append("|");
427 | }
428 | }
429 |
430 | Editor edit = prefs.edit();
431 | edit.putString(PREFS_KEY_PROXYED, tordApps.toString());
432 | edit.commit();
433 |
434 | }
435 |
436 | /**
437 | * Called an application is check/unchecked
438 | */
439 | @Override
440 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
441 | final ProxyedApp app = (ProxyedApp) buttonView.getTag();
442 | if (app != null) {
443 | app.setProxyed(isChecked);
444 | }
445 |
446 | saveAppSettings(this);
447 |
448 | }
449 |
450 | @Override
451 | public void onClick(View v) {
452 |
453 | CheckBox cbox = (CheckBox) v.getTag();
454 |
455 | final ProxyedApp app = (ProxyedApp) cbox.getTag();
456 | if (app != null) {
457 | app.setProxyed(!app.isProxyed());
458 | cbox.setChecked(app.isProxyed());
459 | }
460 |
461 | saveAppSettings(this);
462 |
463 | }
464 |
465 | }
466 |
--------------------------------------------------------------------------------