Commit 45daac82 authored by Max Lv's avatar Max Lv

clean up

parent c6164acf
...@@ -30,11 +30,67 @@ import java.util.*; ...@@ -30,11 +30,67 @@ import java.util.*;
public class AppManager extends Activity implements OnCheckedChangeListener, public class AppManager extends Activity implements OnCheckedChangeListener,
OnClickListener { OnClickListener {
private static class ListEntry { public final static String PREFS_KEY_PROXYED = "Proxyed";
private CheckBox box; private static final int MSG_LOAD_START = 1;
private TextView text; private static final int MSG_LOAD_FINISH = 2;
private ImageView icon; final Handler handler = new Handler() {
} @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOAD_START:
pd = ProgressDialog.show(AppManager.this, "",
getString(R.string.loading), true, true);
break;
case MSG_LOAD_FINISH:
listApps.setAdapter(adapter);
listApps.setOnScrollListener(new OnScrollListener() {
boolean visible;
@Override
public void onScroll(AbsListView view,
int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (visible) {
String name = apps[firstVisibleItem].getName();
if (name != null && name.length() > 1)
overlay.setText(apps[firstVisibleItem]
.getName().substring(0, 1));
else
overlay.setText("*");
overlay.setVisibility(View.VISIBLE);
}
}
@Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
visible = true;
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
overlay.setVisibility(View.INVISIBLE);
}
}
});
if (pd != null) {
pd.dismiss();
pd = null;
}
break;
}
super.handleMessage(msg);
}
};
private ProxyedApp[] apps = null;
private ListView listApps;
private AppManager mAppManager;
private TextView overlay;
private ProgressDialog pd = null;
private ListAdapter adapter;
private ImageLoader dm;
private boolean appsLoaded = false;
public static ProxyedApp[] getProxyedApps(Context context) { public static ProxyedApp[] getProxyedApps(Context context) {
...@@ -96,77 +152,6 @@ public class AppManager extends Activity implements OnCheckedChangeListener, ...@@ -96,77 +152,6 @@ public class AppManager extends Activity implements OnCheckedChangeListener,
return apps; return apps;
} }
private ProxyedApp[] apps = null;
private ListView listApps;
private AppManager mAppManager;
private TextView overlay;
private ProgressDialog pd = null;
private ListAdapter adapter;
private ImageLoader dm;
private static final int MSG_LOAD_START = 1;
private static final int MSG_LOAD_FINISH = 2;
public final static String PREFS_KEY_PROXYED = "Proxyed";
private boolean appsLoaded = false;
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOAD_START:
pd = ProgressDialog.show(AppManager.this, "",
getString(R.string.loading), true, true);
break;
case MSG_LOAD_FINISH:
listApps.setAdapter(adapter);
listApps.setOnScrollListener(new OnScrollListener() {
boolean visible;
@Override
public void onScroll(AbsListView view,
int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (visible) {
String name = apps[firstVisibleItem].getName();
if (name != null && name.length() > 1)
overlay.setText(apps[firstVisibleItem]
.getName().substring(0, 1));
else
overlay.setText("*");
overlay.setVisibility(View.VISIBLE);
}
}
@Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
visible = true;
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
overlay.setVisibility(View.INVISIBLE);
}
}
});
if (pd != null) {
pd.dismiss();
pd = null;
}
break;
}
super.handleMessage(msg);
}
};
public void getApps(Context context) { public void getApps(Context context) {
SharedPreferences prefs = PreferenceManager SharedPreferences prefs = PreferenceManager
...@@ -413,4 +398,10 @@ public class AppManager extends Activity implements OnCheckedChangeListener, ...@@ -413,4 +398,10 @@ public class AppManager extends Activity implements OnCheckedChangeListener,
} }
private static class ListEntry {
private CheckBox box;
private TextView text;
private ImageView icon;
}
} }
...@@ -51,7 +51,7 @@ public class Exec { ...@@ -51,7 +51,7 @@ public class Exec {
* @param scripts The scripts to execute. * @param scripts The scripts to execute.
* @param processId A one-element array to which the process ID of the started * @param processId A one-element array to which the process ID of the started
* process will be written. * process will be written.
* @return File descriptor * @return File descriptor
*/ */
public static native FileDescriptor createSubprocess(int rdt, String cmd, public static native FileDescriptor createSubprocess(int rdt, String cmd,
String[] args, String[] envVars, String[] args, String[] envVars,
......
...@@ -16,101 +16,15 @@ import java.util.Stack; ...@@ -16,101 +16,15 @@ import java.util.Stack;
public class ImageLoader { public class ImageLoader {
// Used to display bitmap in the UI thread final int stub_id = R.drawable.sym_def_app_icon;
class BitmapDisplayer implements Runnable { PhotosQueue photosQueue = new PhotosQueue();
Bitmap bitmap; PhotosLoader photoLoaderThread = new PhotosLoader();
ImageView imageView;
public BitmapDisplayer(Bitmap b, ImageView i) {
bitmap = b;
imageView = i;
}
@Override
public void run() {
if (bitmap != null)
imageView.setImageBitmap(bitmap);
else
imageView.setImageResource(stub_id);
}
}
class PhotosLoader extends Thread {
@Override
public void run() {
try {
while (true) {
// thread waits until there are any images to load in the
// queue
if (photosQueue.photosToLoad.size() == 0)
synchronized (photosQueue.photosToLoad) {
photosQueue.photosToLoad.wait();
}
if (photosQueue.photosToLoad.size() != 0) {
PhotoToLoad photoToLoad;
synchronized (photosQueue.photosToLoad) {
photoToLoad = photosQueue.photosToLoad.pop();
}
Bitmap bmp = getBitmap(photoToLoad.uid);
cache.put(photoToLoad.uid, bmp);
Object tag = photoToLoad.imageView.getTag();
if (tag != null && ((Integer) tag) == photoToLoad.uid) {
BitmapDisplayer bd = new BitmapDisplayer(bmp,
photoToLoad.imageView);
Activity a = (Activity) photoToLoad.imageView
.getContext();
a.runOnUiThread(bd);
}
}
if (Thread.interrupted())
break;
}
} catch (InterruptedException e) {
// allow thread to exit
}
}
}
// stores list of photos to download
class PhotosQueue {
private final Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();
// removes all instances of this ImageView
public void Clean(ImageView image) {
synchronized (photosToLoad) {
for (int j = 0; j < photosToLoad.size(); ) {
if (photosToLoad.get(j).imageView == image) photosToLoad.remove(j);
else ++j;
}
}
}
}
// Task for the queue
private class PhotoToLoad {
public int uid;
public ImageView imageView;
public PhotoToLoad(int u, ImageView i) {
uid = u;
imageView = i;
}
}
// the simplest in-memory cache implementation. This should be replaced with // the simplest in-memory cache implementation. This should be replaced with
// something like SoftReference or BitmapOptions.inPurgeable(since 1.6) // something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
private HashMap<Integer, Bitmap> cache = new HashMap<Integer, Bitmap>(); private HashMap<Integer, Bitmap> cache = new HashMap<Integer, Bitmap>();
private File cacheDir; private File cacheDir;
private Context context; private Context context;
final int stub_id = R.drawable.sym_def_app_icon;
PhotosQueue photosQueue = new PhotosQueue();
PhotosLoader photoLoaderThread = new PhotosLoader();
public ImageLoader(Context c) { public ImageLoader(Context c) {
// Make the background thead low priority. This way it will not affect // Make the background thead low priority. This way it will not affect
// the UI performance // the UI performance
...@@ -158,7 +72,7 @@ public class ImageLoader { ...@@ -158,7 +72,7 @@ public class ImageLoader {
BitmapFactory.Options o2 = new BitmapFactory.Options(); BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale; o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) { } catch (FileNotFoundException ignored) {
} }
return null; return null;
} }
...@@ -212,4 +126,85 @@ public class ImageLoader { ...@@ -212,4 +126,85 @@ public class ImageLoader {
photoLoaderThread.interrupt(); photoLoaderThread.interrupt();
} }
// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable {
Bitmap bitmap;
ImageView imageView;
public BitmapDisplayer(Bitmap b, ImageView i) {
bitmap = b;
imageView = i;
}
@Override
public void run() {
if (bitmap != null)
imageView.setImageBitmap(bitmap);
else
imageView.setImageResource(stub_id);
}
}
class PhotosLoader extends Thread {
@Override
public void run() {
try {
while (true) {
// thread waits until there are any images to load in the
// queue
if (photosQueue.photosToLoad.size() == 0)
synchronized (photosQueue.photosToLoad) {
photosQueue.photosToLoad.wait();
}
if (photosQueue.photosToLoad.size() != 0) {
PhotoToLoad photoToLoad;
synchronized (photosQueue.photosToLoad) {
photoToLoad = photosQueue.photosToLoad.pop();
}
Bitmap bmp = getBitmap(photoToLoad.uid);
cache.put(photoToLoad.uid, bmp);
Object tag = photoToLoad.imageView.getTag();
if (tag != null && ((Integer) tag) == photoToLoad.uid) {
BitmapDisplayer bd = new BitmapDisplayer(bmp,
photoToLoad.imageView);
Activity a = (Activity) photoToLoad.imageView
.getContext();
a.runOnUiThread(bd);
}
}
if (Thread.interrupted())
break;
}
} catch (InterruptedException e) {
// allow thread to exit
}
}
}
// stores list of photos to download
class PhotosQueue {
private final Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();
// removes all instances of this ImageView
public void Clean(ImageView image) {
synchronized (photosToLoad) {
for (int j = 0; j < photosToLoad.size(); ) {
if (photosToLoad.get(j).imageView == image) photosToLoad.remove(j);
else ++j;
}
}
}
}
// Task for the queue
private class PhotoToLoad {
public int uid;
public ImageView imageView;
public PhotoToLoad(int u, ImageView i) {
uid = u;
imageView = i;
}
}
} }
...@@ -4,5 +4,6 @@ public class Node { ...@@ -4,5 +4,6 @@ public class Node {
static { static {
System.loadLibrary("node"); System.loadLibrary("node");
} }
public static native void exec(String cmd); public static native void exec(String cmd);
} }
...@@ -7,7 +7,6 @@ public class ProxyedApp { ...@@ -7,7 +7,6 @@ public class ProxyedApp {
private String username; private String username;
private String procname; private String procname;
private String name; private String name;
private boolean proxyed = false; private boolean proxyed = false;
/** /**
...@@ -17,6 +16,13 @@ public class ProxyedApp { ...@@ -17,6 +16,13 @@ public class ProxyedApp {
return name; return name;
} }
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/** /**
* @return the procname * @return the procname
*/ */
...@@ -24,6 +30,13 @@ public class ProxyedApp { ...@@ -24,6 +30,13 @@ public class ProxyedApp {
return procname; return procname;
} }
/**
* @param procname the procname to set
*/
public void setProcname(String procname) {
this.procname = procname;
}
/** /**
* @return the uid * @return the uid
*/ */
...@@ -31,6 +44,13 @@ public class ProxyedApp { ...@@ -31,6 +44,13 @@ public class ProxyedApp {
return uid; return uid;
} }
/**
* @param uid the uid to set
*/
public void setUid(int uid) {
this.uid = uid;
}
/** /**
* @return the username * @return the username
*/ */
...@@ -39,17 +59,17 @@ public class ProxyedApp { ...@@ -39,17 +59,17 @@ public class ProxyedApp {
} }
/** /**
* @return the enabled * @param username the username to set
*/ */
public boolean isEnabled() { public void setUsername(String username) {
return enabled; this.username = username;
} }
/** /**
* @return the proxyed * @return the enabled
*/ */
public boolean isProxyed() { public boolean isEnabled() {
return proxyed; return enabled;
} }
/** /**
...@@ -60,17 +80,10 @@ public class ProxyedApp { ...@@ -60,17 +80,10 @@ public class ProxyedApp {
} }
/** /**
* @param name the name to set * @return the proxyed
*/
public void setName(String name) {
this.name = name;
}
/**
* @param procname the procname to set
*/ */
public void setProcname(String procname) { public boolean isProxyed() {
this.procname = procname; return proxyed;
} }
/** /**
...@@ -79,18 +92,4 @@ public class ProxyedApp { ...@@ -79,18 +92,4 @@ public class ProxyedApp {
public void setProxyed(boolean proxyed) { public void setProxyed(boolean proxyed) {
this.proxyed = proxyed; this.proxyed = proxyed;
} }
/**
* @param uid the uid to set
*/
public void setUid(int uid) {
this.uid = uid;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
} }
\ No newline at end of file
...@@ -66,13 +66,11 @@ import java.io.OutputStream; ...@@ -66,13 +66,11 @@ import java.io.OutputStream;
public class Shadowsocks extends PreferenceActivity implements public class Shadowsocks extends PreferenceActivity implements
OnSharedPreferenceChangeListener { OnSharedPreferenceChangeListener {
private static final String TAG = "Shadowsocks";
public static final String PREFS_NAME = "Shadowsocks"; public static final String PREFS_NAME = "Shadowsocks";
private static final String TAG = "Shadowsocks";
private static final int MSG_CRASH_RECOVER = 1; private static final int MSG_CRASH_RECOVER = 1;
private static final int MSG_INITIAL_FINISH = 2; private static final int MSG_INITIAL_FINISH = 2;
private static ProgressDialog mProgressDialog = null;
final Handler handler = new Handler() { final Handler handler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
...@@ -96,9 +94,6 @@ public class Shadowsocks extends PreferenceActivity implements ...@@ -96,9 +94,6 @@ public class Shadowsocks extends PreferenceActivity implements
super.handleMessage(msg); super.handleMessage(msg);
} }
}; };
private static ProgressDialog mProgressDialog = null;
private EditTextPreference proxyText; private EditTextPreference proxyText;
private EditTextPreference portText; private EditTextPreference portText;
private EditTextPreference remotePortText; private EditTextPreference remotePortText;
......
package com.github.shadowsocks; package com.github.shadowsocks;
import android.app.Application; import android.app.Application;
import android.content.Context;
import com.google.analytics.tracking.android.EasyTracker; import com.google.analytics.tracking.android.EasyTracker;
public class ShadowsocksApplication extends Application { public class ShadowsocksApplication extends Application {
......
...@@ -16,151 +16,19 @@ import java.util.ArrayList; ...@@ -16,151 +16,19 @@ import java.util.ArrayList;
public class Utils { public class Utils {
/**
* Internal thread used to execute scripts (as root or not).
*/
private static final class ScriptRunner extends Thread {
private final String scripts;
private final StringBuilder result;
private final boolean asroot;
public int exitcode = -1;
/**
* Creates a new script runner.
*
* @param script script to run
* @param result result output
* @param asroot if true, executes the script as root
*/
public ScriptRunner(String script, StringBuilder result,
boolean asroot) {
this.scripts = script;
this.result = result;
this.asroot = asroot;
}
private FileDescriptor createSubprocess(int[] processId, String cmd) {
ArrayList<String> argList = parse(cmd);
String arg0 = argList.get(0);
String[] args = argList.toArray(new String[1]);
return Exec.createSubprocess(result != null ? 1 : 0, arg0, args, null,
scripts + "\nexit\n", processId);
}
private ArrayList<String> parse(String cmd) {
final int PLAIN = 0;
final int WHITESPACE = 1;
final int INQUOTE = 2;
int state = WHITESPACE;
ArrayList<String> result = new ArrayList<String>();
int cmdLen = cmd.length();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < cmdLen; i++) {
char c = cmd.charAt(i);
if (state == PLAIN) {
if (Character.isWhitespace(c)) {
result.add(builder.toString());
builder.delete(0, builder.length());
state = WHITESPACE;
} else if (c == '"') {
state = INQUOTE;
} else {
builder.append(c);
}
} else if (state == WHITESPACE) {
if (Character.isWhitespace(c)) {
// do nothing
} else if (c == '"') {
state = INQUOTE;
} else {
state = PLAIN;
builder.append(c);
}
} else if (state == INQUOTE) {
if (c == '\\') {
if (i + 1 < cmdLen) {
i += 1;
builder.append(cmd.charAt(i));
}
} else if (c == '"') {
state = PLAIN;
} else {
builder.append(c);
}
}
}
if (builder.length() > 0) {
result.add(builder.toString());
}
return result;
}
@Override
public void run() {
FileDescriptor pipe = null;
int pid[] = new int[1];
pid[0] = -1;
try {
if (this.asroot) {
// Create the "su" request to run the script
pipe = createSubprocess(pid, root_shell);
} else {
// Create the "sh" request to run the script
pipe = createSubprocess(pid, getShell());
}
if (pid[0] != -1) {
exitcode = Exec.waitFor(pid[0]);
}
if (result == null || pipe == null) return;
final InputStream stdout = new FileInputStream(pipe);
final byte buf[] = new byte[8192];
int read = 0;
// Read stdout
while (stdout.available() > 0) {
read = stdout.read(buf);
result.append(new String(buf, 0, read));
}
} catch (Exception ex) {
Log.e(TAG, "Cannot execute command", ex);
if (result != null)
result.append("\n").append(ex);
} finally {
if (pipe != null) {
Exec.close(pipe);
}
if (pid[0] != -1) {
Exec.hangupProcessGroup(pid[0]);
}
}
}
}
public final static String TAG = "Shadowsocks"; public final static String TAG = "Shadowsocks";
public final static String DEFAULT_SHELL = "/system/bin/sh"; public final static String DEFAULT_SHELL = "/system/bin/sh";
public final static String DEFAULT_ROOT = "/system/bin/su"; public final static String DEFAULT_ROOT = "/system/bin/su";
public final static String ALTERNATIVE_ROOT = "/system/xbin/su"; public final static String ALTERNATIVE_ROOT = "/system/xbin/su";
public final static String DEFAULT_IPTABLES = "/data/data/com.github.shadowsocks/iptables"; public final static String DEFAULT_IPTABLES = "/data/data/com.github.shadowsocks/iptables";
public final static String ALTERNATIVE_IPTABLES = "/system/bin/iptables"; public final static String ALTERNATIVE_IPTABLES = "/system/bin/iptables";
public final static int TIME_OUT = -99; public final static int TIME_OUT = -99;
private static boolean initialized = false; private static boolean initialized = false;
private static int hasRedirectSupport = -1; private static int hasRedirectSupport = -1;
private static int isRoot = -1; private static int isRoot = -1;
private static String shell = null; private static String shell = null;
private static String root_shell = null; private static String root_shell = null;
private static String iptables = null; private static String iptables = null;
private static String data_path = null; private static String data_path = null;
private static void checkIptables() { private static void checkIptables() {
...@@ -393,4 +261,131 @@ public class Utils { ...@@ -393,4 +261,131 @@ public class Utils {
} }
return runner.exitcode; return runner.exitcode;
} }
/**
* Internal thread used to execute scripts (as root or not).
*/
private static final class ScriptRunner extends Thread {
private final String scripts;
private final StringBuilder result;
private final boolean asroot;
public int exitcode = -1;
/**
* Creates a new script runner.
*
* @param script script to run
* @param result result output
* @param asroot if true, executes the script as root
*/
public ScriptRunner(String script, StringBuilder result,
boolean asroot) {
this.scripts = script;
this.result = result;
this.asroot = asroot;
}
private FileDescriptor createSubprocess(int[] processId, String cmd) {
ArrayList<String> argList = parse(cmd);
String arg0 = argList.get(0);
String[] args = argList.toArray(new String[1]);
return Exec.createSubprocess(result != null ? 1 : 0, arg0, args, null,
scripts + "\nexit\n", processId);
}
private ArrayList<String> parse(String cmd) {
final int PLAIN = 0;
final int WHITESPACE = 1;
final int INQUOTE = 2;
int state = WHITESPACE;
ArrayList<String> result = new ArrayList<String>();
int cmdLen = cmd.length();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < cmdLen; i++) {
char c = cmd.charAt(i);
if (state == PLAIN) {
if (Character.isWhitespace(c)) {
result.add(builder.toString());
builder.delete(0, builder.length());
state = WHITESPACE;
} else if (c == '"') {
state = INQUOTE;
} else {
builder.append(c);
}
} else if (state == WHITESPACE) {
if (Character.isWhitespace(c)) {
// do nothing
} else if (c == '"') {
state = INQUOTE;
} else {
state = PLAIN;
builder.append(c);
}
} else if (state == INQUOTE) {
if (c == '\\') {
if (i + 1 < cmdLen) {
i += 1;
builder.append(cmd.charAt(i));
}
} else if (c == '"') {
state = PLAIN;
} else {
builder.append(c);
}
}
}
if (builder.length() > 0) {
result.add(builder.toString());
}
return result;
}
@Override
public void run() {
FileDescriptor pipe = null;
int pid[] = new int[1];
pid[0] = -1;
try {
if (this.asroot) {
// Create the "su" request to run the script
pipe = createSubprocess(pid, root_shell);
} else {
// Create the "sh" request to run the script
pipe = createSubprocess(pid, getShell());
}
if (pid[0] != -1) {
exitcode = Exec.waitFor(pid[0]);
}
if (result == null || pipe == null) return;
final InputStream stdout = new FileInputStream(pipe);
final byte buf[] = new byte[8192];
int read = 0;
// Read stdout
while (stdout.available() > 0) {
read = stdout.read(buf);
result.append(new String(buf, 0, read));
}
} catch (Exception ex) {
Log.e(TAG, "Cannot execute command", ex);
if (result != null)
result.append("\n").append(ex);
} finally {
if (pipe != null) {
Exec.close(pipe);
}
if (pid[0] != -1) {
Exec.hangupProcessGroup(pid[0]);
}
}
}
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment