diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9c210f56..388b0a33 100755 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -37,7 +37,12 @@ + android:label="@string/app_name"> + + + + + - 4.0.0 com.github.shadowsocks @@ -35,6 +35,13 @@ provided + + com.actionbarsherlock + actionbarsherlock + 4.3.0 + apklib + + com.google.android.analytics analytics @@ -47,6 +54,20 @@ 1.5 + + net.saik0.android.unifiedpreference + unifiedpreference + 0.0.2 + apklib + + + + org.jraf + android-switch-backport + 1.0 + apklib + + ${project.artifactId} diff --git a/res/layout/layout_apps.xml b/res/layout/layout_apps.xml index e9ce741c..a35c5974 100644 --- a/res/layout/layout_apps.xml +++ b/res/layout/layout_apps.xml @@ -1,10 +1,10 @@ - - + android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" android:duplicateParentState="false"> + + \ No newline at end of file diff --git a/res/layout/layout_apps_item.xml b/res/layout/layout_apps_item.xml index ad821a9e..bef7f510 100644 --- a/res/layout/layout_apps_item.xml +++ b/res/layout/layout_apps_item.xml @@ -13,6 +13,5 @@ - diff --git a/res/layout/layout_switch.xml b/res/layout/layout_switch.xml new file mode 100644 index 00000000..973d96cb --- /dev/null +++ b/res/layout/layout_switch.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/res/values-v11/styles.xml b/res/values-v11/styles.xml deleted file mode 100755 index ec5c08e5..00000000 --- a/res/values-v11/styles.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - + \ No newline at end of file diff --git a/res/xml/pref_feature.xml b/res/xml/pref_feature.xml new file mode 100755 index 00000000..f6312ba7 --- /dev/null +++ b/res/xml/pref_feature.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/pref_proxy.xml b/res/xml/pref_proxy.xml new file mode 100755 index 00000000..67d3ef1b --- /dev/null +++ b/res/xml/pref_proxy.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + diff --git a/res/xml/shadowsocks_headers.xml b/res/xml/shadowsocks_headers.xml new file mode 100644 index 00000000..dca94452 --- /dev/null +++ b/res/xml/shadowsocks_headers.xml @@ -0,0 +1,16 @@ + + + + +
+
+ + + \ No newline at end of file diff --git a/res/xml/shadowsocks_preference.xml b/res/xml/shadowsocks_preference.xml deleted file mode 100755 index dbaee4e5..00000000 --- a/res/xml/shadowsocks_preference.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/com/github/shadowsocks/Shadowsocks.java b/src/com/github/shadowsocks/Shadowsocks.java index 67d71d85..04c2e4f5 100755 --- a/src/com/github/shadowsocks/Shadowsocks.java +++ b/src/com/github/shadowsocks/Shadowsocks.java @@ -53,20 +53,29 @@ import android.os.Message; import android.preference.*; import android.util.Log; import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; +import android.widget.CompoundButton; +import android.widget.RelativeLayout; import android.widget.Toast; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; import com.google.analytics.tracking.android.EasyTracker; +import net.saik0.android.unifiedpreference.UnifiedPreferenceFragment; +import net.saik0.android.unifiedpreference.UnifiedSherlockPreferenceActivity; +import org.jraf.android.backport.switchwidget.Switch; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -public class Shadowsocks extends PreferenceActivity implements - OnSharedPreferenceChangeListener { +public class Shadowsocks extends UnifiedSherlockPreferenceActivity + implements CompoundButton.OnCheckedChangeListener, OnSharedPreferenceChangeListener { public static final String PREFS_NAME = "Shadowsocks"; + public static final String[] PROXY_PREFS = {"proxy", "remotePort", "port" + , "sitekey", "encMethod"}; + public static final String[] FEATRUE_PREFS = {"isHTTPProxy", "isDNSProxy", "isGFWList", "isGlobalProxy", "isBypassApps" + , "proxyedApps", "isAutoConnect"}; private static final String TAG = "Shadowsocks"; private static final int MSG_CRASH_RECOVER = 1; private static final int MSG_INITIAL_FINISH = 2; @@ -94,14 +103,7 @@ public class Shadowsocks extends PreferenceActivity implements super.handleMessage(msg); } }; - private EditTextPreference proxyText; - private EditTextPreference portText; - private EditTextPreference remotePortText; - private EditTextPreference sitekeyText; - private ListPreference encMethodText; - private Preference proxyedApps; - private CheckBoxPreference isBypassAppsCheck; - private CheckBoxPreference isRunningCheck; + private Switch switchButton; private void copyAssets(String path) { @@ -161,67 +163,43 @@ public class Shadowsocks extends PreferenceActivity implements return false; } + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + if (compoundButton == switchButton) { + if (!serviceStart()) { + switchButton.setChecked(false); + } + } + } + /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { + setHeaderRes(R.xml.shadowsocks_headers); super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.shadowsocks_preference); + RelativeLayout switchLayout = (RelativeLayout) + getLayoutInflater().inflate(R.layout.layout_switch, null); - proxyText = (EditTextPreference) findPreference("proxy"); - portText = (EditTextPreference) findPreference("port"); - remotePortText = (EditTextPreference) findPreference("remotePort"); - sitekeyText = (EditTextPreference) findPreference("sitekey"); - encMethodText = (ListPreference) findPreference("encMethod"); - proxyedApps = findPreference("proxyedApps"); + getSupportActionBar().setCustomView(switchLayout); + getSupportActionBar().setDisplayShowTitleEnabled(false); + getSupportActionBar().setDisplayShowCustomEnabled(true); - isBypassAppsCheck = (CheckBoxPreference) findPreference("isBypassApps"); - isRunningCheck = (CheckBoxPreference) findPreference("isRunning"); + switchButton = (Switch) switchLayout.findViewById(R.id.switchButton); - if (mProgressDialog == null) { - mProgressDialog = ProgressDialog.show(this, "", - getString(R.string.initializing), true, true); - } - - new Thread() { - @Override - public void run() { - - Utils.isRoot(); - - String versionName; - try { - versionName = getPackageManager().getPackageInfo( - getPackageName(), 0).versionName; - } catch (NameNotFoundException e) { - versionName = "NONE"; - } - - final SharedPreferences settings = PreferenceManager - .getDefaultSharedPreferences(Shadowsocks.this); - - if (!settings.getBoolean(versionName, false)) { - Editor edit = settings.edit(); - edit.putBoolean(versionName, true); - edit.commit(); - reset(); - } - - handler.sendEmptyMessage(MSG_INITIAL_FINISH); - } - }.start(); } @Override public boolean onCreateOptionsMenu(Menu menu) { - menu.add(Menu.NONE, Menu.FIRST + 1, 1, getString(R.string.recovery)) - .setIcon(android.R.drawable.ic_menu_delete); - menu.add(Menu.NONE, Menu.FIRST + 2, 2, getString(R.string.about)) - .setIcon(android.R.drawable.ic_menu_info_details); + menu.add(0, 0, 0, R.string.recovery) + .setIcon(android.R.drawable.ic_menu_revert) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT); + menu.add(0, 1, 1, R.string.about) + .setIcon(android.R.drawable.ic_menu_info_details) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT); return true; - } /** @@ -235,11 +213,6 @@ public class Shadowsocks extends PreferenceActivity implements editor.putBoolean("isConnected", ShadowsocksService.isServiceStarted()); editor.commit(); - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - mProgressDialog = null; - } - super.onDestroy(); } @@ -256,14 +229,13 @@ public class Shadowsocks extends PreferenceActivity implements return super.onKeyDown(keyCode, event); } - // 菜单项被选择事件 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case Menu.FIRST + 1: + case 0: recovery(); break; - case Menu.FIRST + 2: + case 1: String versionName = ""; try { versionName = getPackageManager().getPackageInfo( @@ -276,57 +248,27 @@ public class Shadowsocks extends PreferenceActivity implements break; } - return true; + return super.onOptionsItemSelected(item); } @Override protected void onPause() { super.onPause(); - - // Unregister the listener whenever a key changes - getPreferenceScreen().getSharedPreferences() + PreferenceManager.getDefaultSharedPreferences(this) .unregisterOnSharedPreferenceChangeListener(this); } - @Override - public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, - Preference preference) { - SharedPreferences settings = PreferenceManager - .getDefaultSharedPreferences(this); - - if (preference.getKey() != null - && preference.getKey().equals("proxyedApps")) { - Intent intent = new Intent(this, AppManager.class); - startActivity(intent); - } else if (preference.getKey() != null - && preference.getKey().equals("isRunning")) { - if (!serviceStart()) { - Editor edit = settings.edit(); - edit.putBoolean("isRunning", false); - edit.commit(); - } - } - return super.onPreferenceTreeClick(preferenceScreen, preference); - } - @Override protected void onResume() { super.onResume(); SharedPreferences settings = PreferenceManager .getDefaultSharedPreferences(this); - if (settings.getBoolean("isGlobalProxy", false)) { - proxyedApps.setEnabled(false); - isBypassAppsCheck.setEnabled(false); - } else { - proxyedApps.setEnabled(true); - isBypassAppsCheck.setEnabled(true); - } - Editor edit = settings.edit(); if (ShadowsocksService.isServiceStarted()) { edit.putBoolean("isRunning", true); + switchButton.setChecked(true); } else { if (settings.getBoolean("isRunning", false)) { new Thread() { @@ -338,33 +280,44 @@ public class Shadowsocks extends PreferenceActivity implements }.start(); } edit.putBoolean("isRunning", false); + switchButton.setChecked(false); } edit.commit(); - // Setup the initial values + setPreferenceEnabled(); - if (!settings.getString("sitekey", "").equals("")) - sitekeyText.setSummary(settings.getString("sitekey", "")); - - if (!settings.getString("encMethod", "").equals("")) - encMethodText.setSummary(settings.getString("encMethod", "")); - - if (!settings.getString("port", "").equals("")) - portText.setSummary(settings.getString("port", - getString(R.string.port_summary))); - - if (!settings.getString("remotePort", "").equals("")) - remotePortText.setSummary(settings.getString("remotePort", - getString(R.string.remote_port_summary))); - - if (!settings.getString("proxy", "").equals("")) - proxyText.setSummary(settings.getString("proxy", - getString(R.string.proxy_summary))); - - // Set up a listener whenever a key changes - getPreferenceScreen().getSharedPreferences() + switchButton.setOnCheckedChangeListener(this); + PreferenceManager.getDefaultSharedPreferences(this) .registerOnSharedPreferenceChangeListener(this); + + } + + private void setPreferenceEnabled() { + SharedPreferences settings = PreferenceManager + .getDefaultSharedPreferences(Shadowsocks.this); + + boolean enabled = !settings.getBoolean("isRunning", false) + && !settings.getBoolean("isConnecting", false); + + for (String name : PROXY_PREFS) { + Preference pref = findPreference(name); + if (pref != null) { + pref.setEnabled(enabled); + } + } + for (String name : FEATRUE_PREFS) { + Preference pref = findPreference(name); + if (pref != null) { + if (name.equals("isBypassApps") + || name.equals("proxyedApps")) { + boolean isGlobalProxy = settings.getBoolean("isGlobalProxy", false); + pref.setEnabled(enabled && !isGlobalProxy); + } else { + pref.setEnabled(enabled); + } + } + } } @Override @@ -376,9 +329,9 @@ public class Shadowsocks extends PreferenceActivity implements if (key.equals("isRunning")) { if (settings.getBoolean("isRunning", false)) { - isRunningCheck.setChecked(true); + switchButton.setChecked(true); } else { - isRunningCheck.setChecked(false); + switchButton.setChecked(false); } } @@ -397,44 +350,8 @@ public class Shadowsocks extends PreferenceActivity implements } } - if (key.equals("isGlobalProxy")) { - if (settings.getBoolean("isGlobalProxy", false)) { - proxyedApps.setEnabled(false); - isBypassAppsCheck.setEnabled(false); - } else { - proxyedApps.setEnabled(true); - isBypassAppsCheck.setEnabled(true); - } - } - - if (key.equals("remotePort")) { - if (settings.getString("remotePort", "").equals("")) { - remotePortText.setSummary(getString(R.string.remote_port_summary)); - } else { - remotePortText.setSummary(settings.getString("remotePort", "")); - } - } else if (key.equals("port")) { - if (settings.getString("port", "").equals("")) { - portText.setSummary(getString(R.string.port_summary)); - } else { - portText.setSummary(settings.getString("port", "")); - } - } else if (key.equals("sitekey")) { - if (settings.getString("sitekey", "").equals("")) { - sitekeyText.setSummary(getString(R.string.sitekey_summary)); - } else { - sitekeyText.setSummary(settings.getString("sitekey", "")); - } - } else if (key.equals("encMethod")) { - if (!settings.getString("encMethod", "").equals("")) { - encMethodText.setSummary(settings.getString("encMethod", "")); - } - } else if (key.equals("proxy")) { - if (settings.getString("proxy", "").equals("")) { - proxyText.setSummary(getString(R.string.proxy_summary)); - } else { - proxyText.setSummary(settings.getString("proxy", "")); - } + if (key.equals("isRunning") || key.equals("isGlobalProxy")) { + setPreferenceEnabled(); } } @@ -442,12 +359,56 @@ public class Shadowsocks extends PreferenceActivity implements public void onStart() { super.onStart(); EasyTracker.getInstance().activityStart(this); + + final SharedPreferences settings = PreferenceManager + .getDefaultSharedPreferences(Shadowsocks.this); + + boolean init = !settings.getBoolean("isRunning", false) + && !settings.getBoolean("isConnecting", false); + + if (init) { + if (mProgressDialog == null) { + mProgressDialog = ProgressDialog.show(this, "", + getString(R.string.initializing), true, true); + } + + new Thread() { + @Override + public void run() { + + Utils.isRoot(); + + String versionName; + try { + versionName = getPackageManager().getPackageInfo( + getPackageName(), 0).versionName; + } catch (NameNotFoundException e) { + versionName = "NONE"; + } + + + if (!settings.getBoolean(versionName, false)) { + Editor edit = settings.edit(); + edit.putBoolean(versionName, true); + edit.commit(); + reset(); + } + + handler.sendEmptyMessage(MSG_INITIAL_FINISH); + } + }.start(); + } } @Override public void onStop() { super.onStop(); EasyTracker.getInstance().activityStop(this); + + if (mProgressDialog != null) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } } public void reset() { @@ -560,4 +521,97 @@ public class Shadowsocks extends PreferenceActivity implements alert.show(); } + public static class ProxyFragment extends UnifiedPreferenceFragment + implements OnSharedPreferenceChangeListener { + + private void setPreferenceEnabled() { + SharedPreferences settings = PreferenceManager + .getDefaultSharedPreferences(getActivity()); + + boolean enabled = !settings.getBoolean("isRunning", false) + && !settings.getBoolean("isConnecting", false); + + for (String name : PROXY_PREFS) { + Preference pref = findPreference(name); + if (pref != null) { + pref.setEnabled(enabled); + } + } + } + + @Override + public void onResume() { + super.onResume(); + setPreferenceEnabled(); + + // Set up a listener whenever a key changes + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + + } + + @Override + public void onPause() { + // Unregister the listener whenever a key changes + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals("isRunning") || key.equals("isGlobalProxy")) { + setPreferenceEnabled(); + } + } + } + + public static class FeatureFragment extends UnifiedPreferenceFragment + implements OnSharedPreferenceChangeListener { + + private void setPreferenceEnabled() { + SharedPreferences settings = PreferenceManager + .getDefaultSharedPreferences(getActivity()); + + boolean enabled = !settings.getBoolean("isRunning", false) + && !settings.getBoolean("isConnecting", false); + + for (String name : FEATRUE_PREFS) { + Preference pref = findPreference(name); + if (pref != null) { + if (name.equals("isBypassApps") + || name.equals("proxyedApps")) { + boolean isGlobalProxy = settings.getBoolean("isGlobalProxy", false); + pref.setEnabled(enabled && !isGlobalProxy); + } else { + pref.setEnabled(enabled); + } + } + } + } + + @Override + public void onResume() { + super.onResume(); + setPreferenceEnabled(); + + // Set up a listener whenever a key changes + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + // Unregister the listener whenever a key changes + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals("isRunning") || key.equals("isGlobalProxy")) { + setPreferenceEnabled(); + } + } + } + } diff --git a/src/com/github/shadowsocks/preferences/SummaryEditTextPreference.java b/src/com/github/shadowsocks/preferences/SummaryEditTextPreference.java new file mode 100644 index 00000000..6a7ae974 --- /dev/null +++ b/src/com/github/shadowsocks/preferences/SummaryEditTextPreference.java @@ -0,0 +1,38 @@ +package com.github.shadowsocks.preferences; + +import android.content.Context; +import android.preference.EditTextPreference; +import android.util.AttributeSet; +import com.github.shadowsocks.R; + +public class SummaryEditTextPreference extends EditTextPreference { + + private CharSequence mDefaultSummary; + + public SummaryEditTextPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mDefaultSummary = getSummary(); + } + + public SummaryEditTextPreference(Context context, AttributeSet attrs) { + super(context, attrs); + mDefaultSummary = getSummary(); + } + + public SummaryEditTextPreference(Context context) { + super(context); + } + + @Override + public void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + if (positiveResult) { + String value = getEditText().getText().toString(); + if (value.isEmpty()) { + setSummary(mDefaultSummary); + } else { + setSummary(value); + } + } + } +}