Compare commits

...
15 Commits
Author SHA1 Message Date
Max Lv 97c6ff95cd fix an issue in the build scripts 2014-09-18 08:24:39 +08:00
Max Lv 971ef22186 fix a data race 2014-09-15 12:52:29 +08:00
Max Lv c35a92a927 fix a crash 2014-09-14 15:39:03 +08:00
Max Lv c05a63a75b fix #116 2014-09-13 17:18:25 +08:00
Max Lv 6074a99eb6 fix an issue 2014-09-11 20:55:57 +08:00
Max Lv e52719d1be back to old play services 2014-09-09 21:58:34 +08:00
Max Lv cfaaaf5341 update with new cipher rc4-md5 2014-09-09 21:28:19 +08:00
Max Lv 4a4d3b11fb refine handler 2014-09-07 11:44:06 +08:00
Max Lv 3538caa80d update styles 2014-09-07 11:00:12 +08:00
Max Lv ae30c218e9 drop support of Android 2.3 2014-09-07 10:06:22 +08:00
Max Lv 86e93ffa2d try to fix #114 2014-09-04 16:51:37 +08:00
Max Lv acd89cc999 refine VPN mode 2014-09-02 10:02:08 +08:00
Max Lv 382af46d91 Update .travis.yml 2014-08-24 13:37:01 +08:00
Max Lv 415a9f6847 refine onTaskRemoved 2014-08-24 12:23:38 +08:00
Max Lv 91a069bc44 Update .travis.yml 2014-07-26 21:51:32 +08:00
84 changed files with 402 additions and 579 deletions
+2 -12
View File
@@ -20,18 +20,8 @@ before_install:
- export PATH=${PATH}:${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools - export PATH=${PATH}:${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
- echo "y" | android update sdk --filter tools,platform-tools,build-tools-20.0.0,android-19,extra-google-m2repository --no-ui --no-https -a - echo "y" | android update sdk --filter tools,platform-tools,build-tools-20.0.0,android-19,extra-google-m2repository --no-ui --no-https -a
- echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a - echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a
install:
- gem install --version 0.8.9 faraday
- gem install travis-artifacts
script: script:
- ./build-ndk.sh - ./build-ndk.sh
- cp local.properties.travis local.properties - cp local.properties.travis local.properties
- sbt clean android:package-release - sbt android:package-release
after_success: - exit 0
- ./deploy target/android-bin shadowsocks-release.apk
env:
global:
- "ARTIFACTS_AWS_REGION=us-east-1"
- "ARTIFACTS_S3_BUCKET=travis-nightly"
- secure: "GkAdnMh07id2VKhpCW16lE73A0LK2Jsk3hzkFvdx76JKW8FjLgaimLJ2T/+i\nxFfDw8XBinLE09dqg8JxSNS6JbLHLcav8P3yJIlzFh1NqfJABU9U4I8atb6P\nITSdSo9nb3LX6sB8SOU0nqXb5U+nj7jiekQqiBhmEmu6iDmMtfU="
- secure: "eCh5BjCFccp+sB/FIrjsmxJU4475D4qiWvDV++khcIHLel6lgUjDX18ImBlJ\n+IdiCKxvR6EpRDV1Cs4gJ2jZEAV0PbojQMoQOXbs1FLggM8RRq/Re1qWQFq7\nWkBRjjr8w8ddjJZHRo459cTUvgvD7krhp07coabAnEahDaGWSUo="
+18 -28
View File
@@ -1,38 +1,28 @@
#!/bin/bash #!/bin/bash
# Target 9 function try () {
cp jni/Application.mk.9 jni/Application.mk "$@" || exit -1
ndk-build clean }
ndk-build
rm -rf src/main/assets/armeabi # Build
try ndk-build clean
try ndk-build
# copy executables
rm -rf src/main/assets/armeabi-v7a rm -rf src/main/assets/armeabi-v7a
rm -rf src/main/assets/x86 rm -rf src/main/assets/x86
mkdir -p src/main/assets/armeabi
mkdir -p src/main/assets/armeabi-v7a mkdir -p src/main/assets/armeabi-v7a
mkdir -p src/main/assets/x86 mkdir -p src/main/assets/x86
for app in pdnsd redsocks for app in pdnsd redsocks
do do
mv libs/armeabi/$app src/main/assets/armeabi/ try mv libs/armeabi-v7a/$app src/main/assets/armeabi-v7a/
mv libs/armeabi-v7a/$app src/main/assets/armeabi-v7a/ try mv libs/x86/$app src/main/assets/x86/
mv libs/x86/$app src/main/assets/x86/
done
rm -rf src/main/jni
mv libs src/main/jni
# Target 16
cp jni/Application.mk.16 jni/Application.mk
ndk-build clean
ndk-build
rm -rf src/main/assets/api-16/armeabi
rm -rf src/main/assets/api-16/armeabi-v7a
rm -rf src/main/assets/api-16/x86
mkdir -p src/main/assets/api-16/armeabi
mkdir -p src/main/assets/api-16/armeabi-v7a
mkdir -p src/main/assets/api-16/x86
for app in pdnsd redsocks
do
mv libs/armeabi/$app src/main/assets/api-16/armeabi/
mv libs/armeabi-v7a/$app src/main/assets/api-16/armeabi-v7a/
mv libs/x86/$app src/main/assets/api-16/x86/
done done
# copy libraries
rm -rf src/main/jni/armeabi-v7a
rm -rf src/main/jni/x86
mkdir -p src/main/jni/armeabi-v7a
mkdir -p src/main/jni/x86
try mv libs/armeabi-v7a/*.so src/main/jni/armeabi-v7a/
try mv libs/x86/*.so src/main/jni/x86/
+2 -5
View File
@@ -15,7 +15,6 @@ resolvers += "JRAF" at "http://JRAF.org/static/maven/2"
resolvers += "madeye private releases" at "http://madeye-maven-repository.googlecode.com/git/" resolvers += "madeye private releases" at "http://madeye-maven-repository.googlecode.com/git/"
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"com.google.android" % "analytics" % "3.01",
"dnsjava" % "dnsjava" % "2.1.5", "dnsjava" % "dnsjava" % "2.1.5",
"org.scalaj" %% "scalaj-http" % "0.3.10", "org.scalaj" %% "scalaj-http" % "0.3.10",
"commons-net" % "commons-net" % "3.3", "commons-net" % "commons-net" % "3.3",
@@ -23,15 +22,13 @@ libraryDependencies ++= Seq(
) )
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
aar("com.actionbarsherlock" % "actionbarsherlock" % "4.4.0") exclude("com.google.android", "support-v4"),
"net.simonvt.menudrawer" % "menudrawer" % "3.0.6", "net.simonvt.menudrawer" % "menudrawer" % "3.0.6",
"org.jraf" % "android-switch-backport" % "1.3.1", "com.google.android.gms" % "play-services" % "5.0.89",
"com.google.android.gms" % "play-services" % "4.4.52",
"com.android.support" % "support-v4" % "19.1.0" "com.android.support" % "support-v4" % "19.1.0"
) )
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"de.keyboardsurfer.android.widget" % "crouton" % "1.8.1" exclude("com.google.android", "support-v4"), "de.keyboardsurfer.android.widget" % "crouton" % "1.8.4" exclude("com.google.android", "support-v4"),
"com.nostra13.universalimageloader" % "universal-image-loader" % "1.8.4", "com.nostra13.universalimageloader" % "universal-image-loader" % "1.8.4",
"com.j256.ormlite" % "ormlite-core" % "4.47", "com.j256.ormlite" % "ormlite-core" % "4.47",
"com.j256.ormlite" % "ormlite-android" % "4.47" "com.j256.ormlite" % "ormlite-android" % "4.47"
+1 -1
View File
@@ -1,4 +1,4 @@
APP_ABI := armeabi armeabi-v7a x86 APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-16 APP_PLATFORM := android-16
APP_STL := stlport_static APP_STL := stlport_static
NDK_TOOLCHAIN_VERSION := 4.8 NDK_TOOLCHAIN_VERSION := 4.8
-4
View File
@@ -1,4 +0,0 @@
APP_ABI := armeabi armeabi-v7a x86
APP_PLATFORM := android-9
APP_STL := stlport_static
NDK_TOOLCHAIN_VERSION := 4.8
+5 -5
View File
@@ -21,11 +21,11 @@ jstring Java_com_github_shadowsocks_system_getabi(JNIEnv *env, jobject thiz) {
} else if (family == ANDROID_CPU_FAMILY_MIPS) { } else if (family == ANDROID_CPU_FAMILY_MIPS) {
abi = "mips"; abi = "mips";
} else if (family == ANDROID_CPU_FAMILY_ARM) { } else if (family == ANDROID_CPU_FAMILY_ARM) {
if (features & ANDROID_CPU_ARM_FEATURE_ARMv7) { // if (features & ANDROID_CPU_ARM_FEATURE_ARMv7) {
abi = "armeabi-v7a"; abi = "armeabi-v7a";
} else { // } else {
abi = "armeabi"; // abi = "armeabi";
} // }
} }
return env->NewStringUTF(abi); return env->NewStringUTF(abi);
} }
+4 -5
View File
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.shadowsocks" package="com.github.shadowsocks"
android:versionCode="68" android:versionCode="72"
android:versionName="2.2.0"> android:versionName="2.2.4">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@@ -15,10 +15,11 @@
android:required="false"/> android:required="false"/>
<uses-sdk <uses-sdk
android:minSdkVersion="9" android:minSdkVersion="16"
android:targetSdkVersion="19"/> android:targetSdkVersion="19"/>
<application <application
android:allowBackup="true"
android:name=".ShadowsocksApplication" android:name=".ShadowsocksApplication"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
@@ -75,14 +76,12 @@
<service <service
android:name=".ShadowsocksNatService" android:name=".ShadowsocksNatService"
android:process=":proxy"
android:exported="false"> android:exported="false">
</service> </service>
<service <service
android:name=".ShadowsocksVpnService" android:name=".ShadowsocksVpnService"
android:label="@string/app_name" android:label="@string/app_name"
android:process=":vpn"
android:permission="android.permission.BIND_VPN_SERVICE" android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 B

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 B

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 B

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 B

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 817 B

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 B

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 B

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 B

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 B

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 B

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 B

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- File created by the Android Action Bar Style Generator
Copyright (C) 2011 The Android Open Source Project
Copyright (C) 2012 readyState Software Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="@color/pressed_shadow" />
</shape>
@@ -20,6 +20,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android" <selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime" > android:exitFadeDuration="@android:integer/config_mediumAnimTime" >
<item android:state_pressed="false" android:state_focused="true" android:drawable="@drawable/list_focused_shadow" /> <item android:state_pressed="false" android:state_focused="true" android:drawable="@drawable/list_focused_shadow" />
<item android:state_pressed="true" android:drawable="@drawable/pressed_background_shadow" /> <item android:state_pressed="true" android:drawable="@drawable/list_pressed_shadow" />
<item android:drawable="@android:color/transparent" /> <item android:drawable="@android:color/transparent" />
</selector> </selector>
+1 -1
View File
@@ -21,7 +21,7 @@
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/> android:layout_centerVertical="true"/>
<org.jraf.android.backport.switchwidget.Switch <Switch
android:id="@+id/bypassSwitch" android:id="@+id/bypassSwitch"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
+2 -1
View File
@@ -15,8 +15,9 @@
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/> android:layout_centerVertical="true"/>
<org.jraf.android.backport.switchwidget.Switch <Switch
android:id="@+id/switchButton" android:id="@+id/switchButton"
android:switchTextAppearance="@android:style/TextAppearance.Small.Inverse"
android:enabled="false" android:enabled="false"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
Binary file not shown.
-65
View File
@@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- File created by the Android Action Bar Style Generator
Copyright (C) 2011 The Android Open Source Project
Copyright (C) 2012 readyState Software Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<style name="PopupTheme" parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar">
<item name="android:windowIsFloating">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<style name="Theme.Shadow" parent="@style/Theme.Sherlock.Light.DarkActionBar">
<item name="android:actionBarItemBackground">@drawable/selectable_background_shadow</item>
<item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
<item name="android:actionBarTabStyle">@style/ActionBarTabStyle.Shadow</item>
<item name="android:actionDropDownStyle">@style/DropDownNav.Shadow</item>
<item name="android:actionBarStyle">@style/ActionBar.Solid.Shadow</item>
<item name="android:actionModeBackground">@drawable/cab_background_top_shadow</item>
<item name="android:actionModeSplitBackground">@drawable/cab_background_bottom_shadow</item>
<item name="android:actionModeCloseButtonStyle">@style/ActionButton.CloseMode.Shadow</item>
<!-- Light.DarkActionBar specific -->
<item name="android:actionBarWidgetTheme">@style/Theme.Shadow.Widget</item>
</style>
<style name="ActionBar.Solid.Shadow" parent="@style/Widget.Sherlock.Light.ActionBar.Solid.Inverse">
<item name="android:background">@drawable/ab_background_textured_shadow</item>
<item name="android:backgroundStacked">@drawable/ab_stacked_solid_shadow</item>
<item name="android:backgroundSplit">@drawable/ab_background_textured_shadow</item>
<item name="android:progressBarStyle">@style/ProgressBar.Shadow</item>
</style>
<style name="ActionBar.Transparent.Shadow" parent="@style/Widget.Sherlock.ActionBar">
<item name="android:background">@drawable/ab_transparent_shadow</item>
<item name="android:progressBarStyle">@style/ProgressBar.Shadow</item>
</style>
<!-- this style is only referenced in a Light.DarkActionBar based theme -->
<style name="Theme.Shadow.Widget" parent="@style/Theme.Sherlock">
<item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
</style>
</resources>
+1 -2
View File
@@ -44,8 +44,7 @@
<string name="forward_stop">后台服务已停止。</string> <string name="forward_stop">后台服务已停止。</string>
<string name="service_failed">请检查你的网络状态后并重试。</string> <string name="service_failed">请检查你的网络状态后并重试。</string>
<string name="stop">停止服务</string> <string name="stop">停止服务</string>
<string name="vpn_status">推荐通过通知栏关闭 VPN 服务</string> <string name="vpn_error">无法启动服务:\"%s\"。</string>
<string name="vpn_error">无法启动 VPN 服务:\"%s\"。看来和你的设备存在兼容性问题,请使用 Root 模式。</string>
<string name="ok_iknow">确定</string> <string name="ok_iknow">确定</string>
<string name="port_alert">端口号应大于1024</string> <string name="port_alert">端口号应大于1024</string>
<string name="port_empty">端口号不能为空</string> <string name="port_empty">端口号不能为空</string>
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<!--Replace placeholder ID with your tracking ID-->
<string name="ga_trackingId">UA-37082941-1</string>
<!--Enable Activity tracking-->
<bool name="ga_autoActivityTracking">true</bool>
<!--Enable automatic exception tracking-->
<bool name="ga_reportUncaughtExceptions">true</bool>
<!-- Set a session timeout period of 1 week -->
<integer name="ga_sessionTimeout">604800</integer>
</resources>
+2
View File
@@ -5,6 +5,7 @@
<string-array name="enc_method_entry"> <string-array name="enc_method_entry">
<item>TABLE</item> <item>TABLE</item>
<item>RC4</item> <item>RC4</item>
<item>RC4-MD5</item>
<item>AES-128-CFB</item> <item>AES-128-CFB</item>
<item>AES-192-CFB</item> <item>AES-192-CFB</item>
<item>AES-256-CFB</item> <item>AES-256-CFB</item>
@@ -22,6 +23,7 @@
<string-array name="enc_method_value"> <string-array name="enc_method_value">
<item>table</item> <item>table</item>
<item>rc4</item> <item>rc4</item>
<item>rc4-md5</item>
<item>aes-128-cfb</item> <item>aes-128-cfb</item>
<item>aes-192-cfb</item> <item>aes-192-cfb</item>
<item>aes-256-cfb</item> <item>aes-256-cfb</item>
-14
View File
@@ -1,18 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
Zirco Browser for Android
Copyright (C) 2010 J. Devauchelle and contributors.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-->
<resources> <resources>
+1 -2
View File
@@ -57,8 +57,7 @@
<string name="forward_stop">Shadowsocks stopped.</string> <string name="forward_stop">Shadowsocks stopped.</string>
<string name="service_failed">Please check your network status and try again.</string> <string name="service_failed">Please check your network status and try again.</string>
<string name="stop">Stop the service</string> <string name="stop">Stop the service</string>
<string name="vpn_status">Recommend to disable the VPN service through the notification bar.</string> <string name="vpn_error">Unable to start service: "%s".</string>
<string name="vpn_error">Unable to start VPN service: "%s". It seems to be a compatibility issue with your device. Please consider using ROOT mode instead.</string>
<!-- alert category --> <!-- alert category -->
<string name="ok_iknow">OK</string> <string name="ok_iknow">OK</string>
+46 -40
View File
@@ -16,54 +16,60 @@
<resources> <resources>
<style name="Widget.Shadow.Switch" parent="@style/Widget.Holo.CompoundButton.Switch"> <style name="Theme.AppManager" parent="@style/Theme.Shadow">
<item name="switchTextAppearance">@android:style/TextAppearance.Small.Inverse</item> </style>
</style>
<!-- Variation on the Light theme that turns off the title --> <style name="PopupTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<style name="Theme.Shadowsocks" parent="@style/Theme.Shadow"> <item name="android:windowFrame">@null</item>
<item name="switchStyle">@style/Widget.Shadow.Switch</item> <item name="android:windowIsFloating">false</item>
<item name="menuDrawerStyle">@style/MenuDrawerStyle</item> <item name="android:windowContentOverlay">@null</item>
</style> <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowCloseOnTouchOutside">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<style name="Theme.AppManager" parent="@style/Theme.Shadow"> <!-- Variation on the Light theme that turns off the title -->
<item name="switchStyle">@style/Widget.Holo.Light.CompoundButton.Switch</item> <style name="Theme.Shadowsocks" parent="@style/Theme.Shadow">
</style> <item name="menuDrawerStyle">@style/MenuDrawerStyle</item>
</style>
<style name="MenuDrawer"/> <style name="MenuDrawer"/>
<style name="MenuDrawer.Widget"/> <style name="MenuDrawer.Widget"/>
<style name="MenuDrawer.Widget.Category"> <style name="MenuDrawer.Widget.Category">
<item name="android:textStyle">bold</item> <item name="android:textStyle">bold</item>
<item name="android:textColor">?android:attr/textColorSecondaryInverse</item> <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
<item name="android:textSize">14sp</item> <item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item> <item name="android:textAllCaps">true</item>
<item name="android:gravity">center_vertical</item> <item name="android:gravity">center_vertical</item>
<item name="android:paddingLeft">16dp</item> <item name="android:paddingLeft">16dp</item>
<item name="android:background">@drawable/md__category_background</item> <item name="android:background">@drawable/md__category_background</item>
<item name="android:singleLine">true</item> <item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item> <item name="android:ellipsize">end</item>
</style> </style>
<style name="MenuDrawer.Widget.Title"> <style name="MenuDrawer.Widget.Title">
<item name="android:background">@drawable/md__list_selector_holo_dark</item> <item name="android:background">@drawable/md__list_selector_holo_dark</item>
<item name="android:textAppearance">?android:attr/textAppearance</item> <item name="android:textAppearance">?android:attr/textAppearance</item>
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item> <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="android:textSize">18sp</item> <item name="android:textSize">18sp</item>
<item name="android:paddingLeft">16dp</item> <item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">32dp</item> <item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">8dp</item> <item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item> <item name="android:paddingBottom">8dp</item>
<item name="android:drawablePadding">16dp</item> <item name="android:drawablePadding">16dp</item>
<item name="android:gravity">center_vertical</item> <item name="android:gravity">center_vertical</item>
</style> </style>
<style name="MenuDrawerStyle" parent="Widget.MenuDrawer"> <style name="MenuDrawerStyle" parent="Widget.MenuDrawer">
<item name="mdActiveIndicator">@drawable/menu_arrow</item> <item name="mdActiveIndicator">@drawable/menu_arrow</item>
<item name="mdMenuSize">250dp</item> <item name="mdMenuSize">250dp</item>
</style> </style>
</resources> </resources>
+34 -47
View File
@@ -19,77 +19,64 @@
<resources> <resources>
<style name="PopupTheme" parent="@android:style/Theme.Translucent.NoTitleBar"> <style name="Theme.Shadow" parent="@android:style/Theme.Holo.Light.DarkActionBar">
<item name="android:windowFrame">@null</item> <item name="android:actionBarItemBackground">@drawable/selectable_background_shadow</item>
<item name="android:windowIsFloating">false</item> <item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="android:windowContentOverlay">@null</item> <item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> <item name="android:actionBarTabStyle">@style/ActionBarTabStyle.Shadow</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden</item> <item name="android:actionDropDownStyle">@style/DropDownNav.Shadow</item>
<item name="android:windowActionModeOverlay">true</item> <item name="android:actionBarStyle">@style/ActionBar.Solid.Shadow</item>
<item name="android:colorBackgroundCacheHint">@null</item> <item name="android:actionModeBackground">@drawable/cab_background_top_shadow</item>
<item name="android:windowCloseOnTouchOutside">true</item> <item name="android:actionModeSplitBackground">@drawable/cab_background_bottom_shadow</item>
<item name="android:windowIsTranslucent">true</item> <item name="android:actionModeCloseButtonStyle">@style/ActionButton.CloseMode.Shadow</item>
<item name="windowContentOverlay">@null</item>
</style> <!-- Light.DarkActionBar specific -->
<item name="android:actionBarWidgetTheme">@style/Theme.Shadow.Widget</item>
<style name="Theme.Shadow" parent="@style/Theme.Sherlock.Light.DarkActionBar">
<item name="actionBarItemBackground">@drawable/selectable_background_shadow</item>
<item name="popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="dropDownListViewStyle">@style/DropDownListView.Shadow</item>
<item name="actionBarTabStyle">@style/ActionBarTabStyle.Shadow</item>
<item name="actionDropDownStyle">@style/DropDownNav.Shadow</item>
<item name="actionBarStyle">@style/ActionBar.Solid.Shadow</item>
<item name="actionModeBackground">@drawable/cab_background_top_shadow</item>
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_shadow</item>
<item name="actionModeCloseButtonStyle">@style/ActionButton.CloseMode.Shadow</item>
<!-- Light.DarkActionBar specific -->
<item name="actionBarWidgetTheme">@style/Theme.Shadow.Widget</item>
</style> </style>
<style name="ActionBar.Solid.Shadow" parent="@style/Widget.Sherlock.Light.ActionBar.Solid.Inverse"> <style name="ActionBar.Solid.Shadow" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
<item name="background">@drawable/ab_solid_shadow</item> <item name="android:background">@drawable/ab_background_textured_shadow</item>
<item name="backgroundStacked">@drawable/ab_stacked_solid_shadow</item> <item name="android:backgroundStacked">@drawable/ab_stacked_solid_shadow</item>
<item name="backgroundSplit">@drawable/ab_bottom_solid_shadow</item> <item name="android:backgroundSplit">@drawable/ab_background_textured_shadow</item>
<item name="progressBarStyle">@style/ProgressBar.Shadow</item> <item name="android:progressBarStyle">@style/ProgressBar.Shadow</item>
</style> </style>
<style name="ActionBar.Transparent.Shadow" parent="@style/Widget.Sherlock.ActionBar"> <style name="ActionBar.Transparent.Shadow" parent="@android:style/Widget.Holo.ActionBar">
<item name="background">@drawable/ab_transparent_shadow</item> <item name="android:background">@drawable/ab_transparent_shadow</item>
<item name="progressBarStyle">@style/ProgressBar.Shadow</item> <item name="android:progressBarStyle">@style/ProgressBar.Shadow</item>
</style> </style>
<style name="PopupMenu.Shadow" parent="@style/Widget.Sherlock.ListPopupWindow"> <style name="PopupMenu.Shadow" parent="@android:style/Widget.Holo.ListPopupWindow">
<item name="android:popupBackground">@drawable/menu_dropdown_panel_shadow</item> <item name="android:popupBackground">@drawable/menu_dropdown_panel_shadow</item>
</style> </style>
<style name="DropDownListView.Shadow" parent="@style/Widget.Sherlock.ListView.DropDown"> <style name="DropDownListView.Shadow" parent="@android:style/Widget.Holo.ListView.DropDown">
<item name="android:listSelector">@drawable/selectable_background_shadow</item> <item name="android:listSelector">@drawable/selectable_background_shadow</item>
</style> </style>
<style name="ActionBarTabStyle.Shadow" parent="@style/Widget.Sherlock.ActionBar.TabView"> <style name="ActionBarTabStyle.Shadow" parent="@android:style/Widget.Holo.ActionBar.TabView">
<item name="android:background">@drawable/tab_indicator_ab_shadow</item> <item name="android:background">@drawable/tab_indicator_ab_shadow</item>
</style> </style>
<style name="DropDownNav.Shadow" parent="@style/Widget.Sherlock.Spinner.DropDown.ActionBar"> <style name="DropDownNav.Shadow" parent="@android:style/Widget.Holo.Spinner">
<item name="android:background">@drawable/spinner_background_ab_shadow</item> <item name="android:background">@drawable/spinner_background_ab_shadow</item>
<item name="android:popupBackground">@drawable/menu_dropdown_panel_shadow</item> <item name="android:popupBackground">@drawable/menu_dropdown_panel_shadow</item>
<item name="android:dropDownSelector">@drawable/selectable_background_shadow</item> <item name="android:dropDownSelector">@drawable/selectable_background_shadow</item>
</style> </style>
<style name="ProgressBar.Shadow" parent="@style/Widget.Sherlock.ProgressBar.Horizontal"> <style name="ProgressBar.Shadow" parent="@android:style/Widget.Holo.ProgressBar.Horizontal">
<item name="android:progressDrawable">@drawable/progress_horizontal_shadow</item> <item name="android:progressDrawable">@drawable/progress_horizontal_shadow</item>
</style> </style>
<style name="ActionButton.CloseMode.Shadow" parent="@style/Widget.Sherlock.ActionButton.CloseMode"> <style name="ActionButton.CloseMode.Shadow" parent="@android:style/Widget.Holo.ActionButton.CloseMode">
<item name="android:background">@drawable/btn_cab_done_shadow</item> <item name="android:background">@drawable/btn_cab_done_shadow</item>
</style> </style>
<!-- this style is only referenced in a Light.DarkActionBar based theme --> <!-- this style is only referenced in a Light.DarkActionBar based theme -->
<style name="Theme.Shadow.Widget" parent="@style/Theme.Sherlock"> <style name="Theme.Shadow.Widget" parent="@android:style/Theme.Holo">
<item name="popupMenuStyle">@style/PopupMenu.Shadow</item> <item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="dropDownListViewStyle">@style/DropDownListView.Shadow</item> <item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
</style> </style>
</resources> </resources>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Set a session timeout period of 1 week -->
<integer name="ga_sessionTimeout">604800</integer>
<!-- Enable automatic Activity measurement -->
<bool name="ga_autoActivityTracking">true</bool>
<!-- The screen names that will appear in reports -->
<screenName name="com.google.android.gms.analytics.samples.mobileplayground.ScreenviewFragment">
Shadowsocks ScreenView
</screenName>
<screenName name="com.google.android.gms.analytics.samples.mobileplayground.EcommerceFragment">
Shadowsocks EcommerceView
</screenName>
<!-- The following value should be replaced with correct property id. -->
<string name="ga_trackingId">UA-37082941-1</string>
</resources>
@@ -39,7 +39,7 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.app.ProgressDialog import android.app.{Activity, ProgressDialog}
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -53,23 +53,13 @@ import android.view.View.OnClickListener
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams import android.view.ViewGroup.LayoutParams
import android.view.WindowManager import android.view.WindowManager
import android.widget.AbsListView import android.widget._
import android.widget.AbsListView.OnScrollListener import android.widget.AbsListView.OnScrollListener
import android.widget.ArrayAdapter
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.CompoundButton.OnCheckedChangeListener import android.widget.CompoundButton.OnCheckedChangeListener
import android.widget.ImageView
import android.widget.ListAdapter
import android.widget.ListView
import android.widget.TextView
import com.actionbarsherlock.app.SherlockActivity
import com.nostra13.universalimageloader.core.download.BaseImageDownloader import com.nostra13.universalimageloader.core.download.BaseImageDownloader
import java.io.{ByteArrayOutputStream, ByteArrayInputStream, InputStream} import java.io.{ByteArrayOutputStream, ByteArrayInputStream, InputStream}
import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration} import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration}
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer
import com.google.analytics.tracking.android.EasyTracker
import org.jraf.android.backport.switchwidget.Switch
import com.github.shadowsocks.utils.{Utils, Scheme, Key} import com.github.shadowsocks.utils.{Utils, Scheme, Key}
case class ProxiedApp(uid: Int, name: String, var proxied: Boolean) case class ProxiedApp(uid: Int, name: String, var proxied: Boolean)
@@ -106,7 +96,7 @@ object AppManager {
} }
} }
class AppManager extends SherlockActivity with OnCheckedChangeListener with OnClickListener { class AppManager extends Activity with OnCheckedChangeListener with OnClickListener {
val MSG_LOAD_START = 1 val MSG_LOAD_START = 1
val MSG_LOAD_FINISH = 2 val MSG_LOAD_FINISH = 2
@@ -216,9 +206,20 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
saveAppSettings(this) saveAppSettings(this)
} }
override def onDestroy() {
super.onDestroy()
if (handler != null) {
handler.removeCallbacksAndMessages(null)
handler = null
}
}
protected override def onCreate(savedInstanceState: Bundle) { protected override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
getSupportActionBar.setTitle(R.string.proxied_help)
handler = new Handler()
getActionBar.setTitle(R.string.proxied_help)
this.setContentView(R.layout.layout_apps) this.setContentView(R.layout.layout_apps)
this.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView] this.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView]
getWindowManager.addView(overlay, new getWindowManager.addView(overlay, new
@@ -233,7 +234,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
.build() .build()
ImageLoader.getInstance().init(config) ImageLoader.getInstance().init(config)
val bypassSwitch: Switch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch] val bypassSwitch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch]
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext) val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext)
bypassSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener { bypassSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener {
def onCheckedChanged(button: CompoundButton, checked: Boolean) { def onCheckedChanged(button: CompoundButton, checked: Boolean) {
@@ -247,24 +248,14 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
super.onResume() super.onResume()
new Thread { new Thread {
override def run() { override def run() {
handler.sendEmptyMessage(MSG_LOAD_START) handler.post(loadStartRunnable)
appListView = findViewById(R.id.applistview).asInstanceOf[ListView] appListView = findViewById(R.id.applistview).asInstanceOf[ListView]
if (!appsLoaded) loadApps() if (!appsLoaded) loadApps()
handler.sendEmptyMessage(MSG_LOAD_FINISH) handler.post(loadFinishRunnable)
} }
}.start() }.start()
} }
protected override def onStart() {
super.onStart()
EasyTracker.getInstance(this).activityStart(this)
}
protected override def onStop() {
super.onStop()
EasyTracker.getInstance(this).activityStop(this)
}
def saveAppSettings(context: Context) { def saveAppSettings(context: Context) {
if (apps == null) return if (apps == null) return
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
@@ -279,46 +270,46 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
edit.commit edit.commit
} }
val handler: Handler = new Handler { val loadStartRunnable = new Runnable {
override def handleMessage(msg: Message) { override def run() {
msg.what match { progressDialog = ProgressDialog
case MSG_LOAD_START => .show(AppManager.this, "", getString(R.string.loading), true, true)
progressDialog = ProgressDialog
.show(AppManager.this, "", getString(R.string.loading), true, true)
case MSG_LOAD_FINISH =>
appListView.setAdapter(adapter)
appListView.setOnScrollListener(new AbsListView.OnScrollListener {
def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int,
totalItemCount: Int) {
if (visible) {
val name: String = apps(firstVisibleItem).name
if (name != null && name.length > 1) {
overlay.setText(apps(firstVisibleItem).name.substring(0, 1))
} else {
overlay.setText("*")
}
overlay.setVisibility(View.VISIBLE)
}
}
def onScrollStateChanged(view: AbsListView, scrollState: Int) {
visible = true
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
overlay.setVisibility(View.INVISIBLE)
}
}
var visible = false
})
if (progressDialog != null) {
progressDialog.dismiss()
progressDialog = null
}
}
super.handleMessage(msg)
} }
} }
val loadFinishRunnable = new Runnable {
override def run() = {
appListView.setAdapter(adapter)
appListView.setOnScrollListener(new AbsListView.OnScrollListener {
def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int,
totalItemCount: Int) {
if (visible) {
val name: String = apps(firstVisibleItem).name
if (name != null && name.length > 1) {
overlay.setText(apps(firstVisibleItem).name.substring(0, 1))
} else {
overlay.setText("*")
}
overlay.setVisibility(View.VISIBLE)
}
}
def onScrollStateChanged(view: AbsListView, scrollState: Int) {
visible = true
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
overlay.setVisibility(View.INVISIBLE)
}
}
var visible = false
})
if (progressDialog != null) {
progressDialog.dismiss()
progressDialog = null
}
}
}
var handler: Handler = null
class AppIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int) class AppIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
extends BaseImageDownloader(context, connectTimeout, readTimeout) { extends BaseImageDownloader(context, connectTimeout, readTimeout) {
@@ -54,21 +54,20 @@ import android.util.{DisplayMetrics, Log}
import android.view._ import android.view._
import android.webkit.{WebView, WebViewClient} import android.webkit.{WebView, WebViewClient}
import android.widget._ import android.widget._
import com.actionbarsherlock.app.SherlockPreferenceActivity
import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback} import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback}
import com.github.shadowsocks.database._ import com.github.shadowsocks.database._
import com.github.shadowsocks.preferences.{PasswordEditTextPreference, ProfileEditTextPreference, SummaryEditTextPreference} import com.github.shadowsocks.preferences.{PasswordEditTextPreference, ProfileEditTextPreference, SummaryEditTextPreference}
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
import com.google.analytics.tracking.android.{EasyTracker, MapBuilder}
import com.google.android.gms.ads.{AdRequest, AdSize, AdView} import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
import com.google.android.gms.analytics.HitBuilders
import com.google.zxing.integration.android.IntentIntegrator import com.google.zxing.integration.android.IntentIntegrator
import com.nostra13.universalimageloader.core.download.BaseImageDownloader import com.nostra13.universalimageloader.core.download.BaseImageDownloader
import de.keyboardsurfer.android.widget.crouton.{Configuration, Crouton, Style} import de.keyboardsurfer.android.widget.crouton.{Configuration, Crouton, Style}
import net.simonvt.menudrawer.MenuDrawer import net.simonvt.menudrawer.MenuDrawer
import org.jraf.android.backport.switchwidget.Switch
import scala.collection.mutable.{ArrayBuffer, ListBuffer} import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.concurrent.ops._ import scala.concurrent.ops._
import scala.ref.WeakReference
class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int) class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
extends BaseImageDownloader(context, connectTimeout, readTimeout) { extends BaseImageDownloader(context, connectTimeout, readTimeout) {
@@ -169,7 +168,7 @@ object Shadowsocks {
} }
class Shadowsocks class Shadowsocks
extends SherlockPreferenceActivity extends PreferenceActivity
with CompoundButton.OnCheckedChangeListener with CompoundButton.OnCheckedChangeListener
with MenuAdapter.MenuListener { with MenuAdapter.MenuListener {
@@ -214,6 +213,8 @@ class Shadowsocks
setPreferenceEnabled(enabled = false) setPreferenceEnabled(enabled = false)
} }
state = bgService.getState state = bgService.getState
// set the listener
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
} }
override def onServiceDisconnected(name: ComponentName) { override def onServiceDisconnected(name: ComponentName) {
@@ -227,16 +228,18 @@ class Shadowsocks
} }
} }
lazy val settings = PreferenceManager.getDefaultSharedPreferences(this) private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
lazy val preferenceReceiver = new PreferenceBroadcastReceiver private lazy val preferenceReceiver = new PreferenceBroadcastReceiver
lazy val drawer = MenuDrawer.attach(this) private lazy val drawer = MenuDrawer.attach(this)
lazy val menuAdapter = new MenuAdapter(this, getMenuList) private lazy val menuAdapter = new MenuAdapter(this, getMenuList)
lazy val listView = new ListView(this) private lazy val listView = new ListView(this)
lazy val profileManager = private lazy val profileManager =
new ProfileManager(settings, getApplication.asInstanceOf[ShadowsocksApplication].dbHelper) new ProfileManager(settings, getApplication.asInstanceOf[ShadowsocksApplication].dbHelper)
val handler = new Handler() private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
var handler: Handler = null
def isSinglePane: Boolean = { def isSinglePane: Boolean = {
if (singlePane == -1) { if (singlePane == -1) {
@@ -442,6 +445,8 @@ class Shadowsocks
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
handler = new Handler()
addPreferencesFromResource(R.xml.pref_all) addPreferencesFromResource(R.xml.pref_all)
// Initialize the profile // Initialize the profile
@@ -481,10 +486,10 @@ class Shadowsocks
val tf: Typeface = Typefaces.get(this, "fonts/Iceland.ttf") val tf: Typeface = Typefaces.get(this, "fonts/Iceland.ttf")
if (tf != null) title.setTypeface(tf) if (tf != null) title.setTypeface(tf)
switchButton = switchLayout.findViewById(R.id.switchButton).asInstanceOf[Switch] switchButton = switchLayout.findViewById(R.id.switchButton).asInstanceOf[Switch]
getSupportActionBar.setCustomView(switchLayout) getActionBar.setCustomView(switchLayout)
getSupportActionBar.setDisplayShowTitleEnabled(false) getActionBar.setDisplayShowTitleEnabled(false)
getSupportActionBar.setDisplayShowCustomEnabled(true) getActionBar.setDisplayShowCustomEnabled(true)
getSupportActionBar.setIcon(R.drawable.ic_stat_shadowsocks) getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
// Register broadcast receiver // Register broadcast receiver
registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS)) registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS))
@@ -519,8 +524,8 @@ class Shadowsocks
case ignored: RemoteException => // Nothing case ignored: RemoteException => // Nothing
} }
bgService = null bgService = null
unbindService(connection)
} }
unbindService(connection)
} }
override def onRestoreInstanceState(inState: Bundle) { override def onRestoreInstanceState(inState: Bundle) {
@@ -683,32 +688,40 @@ class Shadowsocks
buf += new Category(getString(R.string.settings)) buf += new Category(getString(R.string.settings))
buf += new Item(-100, getString(R.string.recovery), android.R.drawable.ic_menu_revert, _ => { buf += new Item(-100, getString(R.string.recovery), android.R.drawable.ic_menu_revert, _ => {
EasyTracker // send event
.getInstance(this) application.tracker.send(new HitBuilders.EventBuilder()
.send(MapBuilder.createEvent(Shadowsocks.TAG, "reset", getVersionName, null).build()) .setCategory(Shadowsocks.TAG)
.setAction("reset")
.setLabel(getVersionName)
.build())
recovery() recovery()
}) })
buf += buf +=
new Item(-200, getString(R.string.flush_dnscache), android.R.drawable.ic_menu_delete, _ => { new Item(-200, getString(R.string.flush_dnscache), android.R.drawable.ic_menu_delete, _ => {
EasyTracker // send event
.getInstance(this) application.tracker.send(new HitBuilders.EventBuilder()
.send( .setCategory(Shadowsocks.TAG)
MapBuilder.createEvent(Shadowsocks.TAG, "flush_dnscache", getVersionName, null).build()) .setAction("flush_dnscache")
.setLabel(getVersionName)
.build())
flushDnsCache() flushDnsCache()
}) })
buf += new Item(-300, getString(R.string.about), android.R.drawable.ic_menu_info_details, _ => { buf += new Item(-300, getString(R.string.about), android.R.drawable.ic_menu_info_details, _ => {
EasyTracker // send event
.getInstance(this) application.tracker.send(new HitBuilders.EventBuilder()
.send(MapBuilder.createEvent(Shadowsocks.TAG, "about", getVersionName, null).build()) .setCategory(Shadowsocks.TAG)
.setAction("about")
.setLabel(getVersionName)
.build())
showAbout() showAbout()
}) })
buf.toList buf.toList
} }
override def onOptionsItemSelected(item: com.actionbarsherlock.view.MenuItem): Boolean = { override def onOptionsItemSelected(item: MenuItem): Boolean = {
item.getItemId match { item.getItemId match {
case android.R.id.home => case android.R.id.home =>
drawer.toggleMenu() drawer.toggleMenu()
@@ -735,9 +748,9 @@ class Shadowsocks
changeSwitch(checked = false) changeSwitch(checked = false)
} }
state = bgService.getState state = bgService.getState
// set the listener
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
} }
// set the listener
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
ConfigUtils.refresh(this) ConfigUtils.refresh(this)
} }
@@ -776,12 +789,10 @@ class Shadowsocks
override def onStart() { override def onStart() {
super.onStart() super.onStart()
EasyTracker.getInstance(this).activityStart(this)
} }
override def onStop() { override def onStop() {
super.onStop() super.onStop()
EasyTracker.getInstance(this).activityStop(this)
clearDialog() clearDialog()
} }
@@ -791,6 +802,10 @@ class Shadowsocks
Crouton.cancelAllCroutons() Crouton.cancelAllCroutons()
unregisterReceiver(preferenceReceiver) unregisterReceiver(preferenceReceiver)
new BackupManager(this).dataChanged() new BackupManager(this).dataChanged()
if (handler != null) {
handler.removeCallbacksAndMessages(null)
handler = null
}
} }
def copyToSystem() { def copyToSystem() {
@@ -810,11 +825,7 @@ class Shadowsocks
crash_recovery() crash_recovery()
if (Build.VERSION.SDK_INT >= 16) { copyAssets(System.getABI)
copyAssets("api-16/" + System.getABI)
} else {
copyAssets(System.getABI)
}
if (Build.VERSION.SDK_INT >= 20) { if (Build.VERSION.SDK_INT >= 20) {
copyToSystem() copyToSystem()
@@ -917,9 +928,6 @@ class Shadowsocks
bgService.start(ConfigUtils.load(settings)) bgService.start(ConfigUtils.load(settings))
if (isVpnEnabled) { if (isVpnEnabled) {
val style = new Style.Builder().setBackgroundColorValue(Style.holoBlueLight).build()
val config = new Configuration.Builder().setDuration(Configuration.DURATION_LONG).build()
Crouton.makeText(Shadowsocks.this, R.string.vpn_status, style).setConfiguration(config).show()
changeSwitch(checked = false) changeSwitch(checked = false)
} }
true true
@@ -985,7 +993,6 @@ class Shadowsocks
changeSwitch(checked = false) changeSwitch(checked = false)
Crouton.cancelAllCroutons() Crouton.cancelAllCroutons()
if (m != null) { if (m != null) {
Crouton.cancelAllCroutons()
val style = new Style.Builder().setBackgroundColorValue(Style.holoRedLight).build() val style = new Style.Builder().setBackgroundColorValue(Style.holoRedLight).build()
val config = new Configuration.Builder() val config = new Configuration.Builder()
.setDuration(Configuration.DURATION_LONG) .setDuration(Configuration.DURATION_LONG)
@@ -39,26 +39,35 @@
package com.github.shadowsocks package com.github.shadowsocks
import java.util
import java.util.concurrent.TimeUnit
import android.app.Application import android.app.Application
import com.github.shadowsocks.database.DBHelper import com.github.shadowsocks.database.DBHelper
import com.google.tagmanager.{Container, ContainerOpener, TagManager}
import com.google.tagmanager.ContainerOpener.{Notifier, OpenType}
import com.google.tagmanager.Container.FunctionCallMacroHandler
import java.util
import com.github.shadowsocks.utils.Utils import com.github.shadowsocks.utils.Utils
import com.google.android.gms.analytics.GoogleAnalytics
import com.google.android.gms.common.api.ResultCallback
import com.google.android.gms.tagmanager.Container.FunctionCallMacroCallback
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
class ShadowsocksApplication extends Application { class ShadowsocksApplication extends Application {
lazy val dbHelper = new DBHelper(this) lazy val dbHelper = new DBHelper(this)
lazy val SIG_FUNC = "getSignature" lazy val SIG_FUNC = "getSignature"
var tagContainer: Container = null var containerHolder: ContainerHolder = null
lazy val tracker = GoogleAnalytics.getInstance(this).newTracker(R.xml.tracker)
override def onCreate() { override def onCreate() {
val tm = TagManager.getInstance(this) val tm = TagManager.getInstance(this)
ContainerOpener.openContainer(tm, "GTM-NT8WS8", OpenType.PREFER_NON_DEFAULT, null, new Notifier { val pending = tm.loadContainerPreferNonDefault("GTM-NT8WS8", R.raw.gtm_default_container)
override def containerAvailable(container: Container) { val callback = new ResultCallback[ContainerHolder] {
tagContainer = container override def onResult(holder: ContainerHolder): Unit = {
container.registerFunctionCallMacroHandler(SIG_FUNC, new FunctionCallMacroHandler { if (!holder.getStatus.isSuccess) {
def getValue(functionName: String, parameters: util.Map[String, AnyRef]): AnyRef = { return
}
containerHolder = holder
val container = holder.getContainer
container.registerFunctionCallMacroCallback(SIG_FUNC, new FunctionCallMacroCallback {
override def getValue(functionName: String, parameters: util.Map[String, AnyRef]): AnyRef = {
if (functionName == SIG_FUNC) { if (functionName == SIG_FUNC) {
Utils.getSignature(getApplicationContext) Utils.getSignature(getApplicationContext)
} }
@@ -66,6 +75,7 @@ class ShadowsocksApplication extends Application {
} }
}) })
} }
}) }
pending.setResultCallback(callback, 2, TimeUnit.SECONDS)
} }
} }
@@ -39,8 +39,7 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.app.backup.{FileBackupHelper, SharedPreferencesBackupHelper, BackupAgentHelper} import android.app.backup.{BackupAgentHelper, FileBackupHelper, SharedPreferencesBackupHelper}
import android.content.Context
import com.github.shadowsocks.database.DBHelper import com.github.shadowsocks.database.DBHelper
class ShadowsocksBackupAgent extends BackupAgentHelper { class ShadowsocksBackupAgent extends BackupAgentHelper {
@@ -39,30 +39,26 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.app.Notification import java.io.File
import android.app.NotificationManager import java.lang.reflect.{InvocationTargetException, Method}
import android.app.PendingIntent import java.util.{Timer, TimerTask}
import android.app.Service
import android.app.{Notification, NotificationManager, PendingIntent, Service}
import android.content._ import android.content._
import android.content.pm.PackageInfo import android.content.pm.{PackageInfo, PackageManager}
import android.content.pm.PackageManager import android.graphics.Color
import android.net.TrafficStats
import android.os._ import android.os._
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import android.util.Log import android.util.Log
import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker}
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import org.apache.http.conn.util.InetAddressUtils
import scala.collection._
import java.util.{TimerTask, Timer}
import android.net.TrafficStats
import scala.concurrent.ops._
import com.github.shadowsocks.utils._
import scala.Some
import android.graphics.Color
import com.github.shadowsocks.aidl.Config import com.github.shadowsocks.aidl.Config
import com.github.shadowsocks.utils._
import com.google.android.gms.analytics.HitBuilders
import org.apache.http.conn.util.InetAddressUtils
import scala.collection._
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import java.io.File import scala.concurrent.ops._
case class TrafficStat(tx: Long, rx: Long, timestamp: Long) case class TrafficStat(tx: Long, rx: Long, timestamp: Long)
@@ -100,7 +96,7 @@ class ShadowsocksNatService extends Service with BaseService {
private var timer: Timer = null private var timer: Timer = null
private val TIMER_INTERVAL = 2 private val TIMER_INTERVAL = 2
val handler: Handler = new Handler() private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isACLEnabled: Boolean = { def isACLEnabled: Boolean = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
@@ -220,12 +216,12 @@ class ShadowsocksNatService extends Service with BaseService {
} }
def notifyForegroundAlert(title: String, info: String, rate: Int) { def notifyForegroundAlert(title: String, info: String, rate: Int) {
val openIntent: Intent = new Intent(this, classOf[Shadowsocks]) val openIntent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
val contentIntent: PendingIntent = PendingIntent.getActivity(this, 0, openIntent, 0) val contentIntent = PendingIntent.getActivity(this, 0, openIntent, 0)
val closeIntent: Intent = new Intent(Action.CLOSE) val closeIntent = new Intent(Action.CLOSE)
val actionIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, closeIntent, 0) val actionIntent = PendingIntent.getBroadcast(this, 0, closeIntent, 0)
val builder: NotificationCompat.Builder = new NotificationCompat.Builder(this) val builder = new NotificationCompat.Builder(this)
val icon = getResources.getDrawable(R.drawable.ic_stat_shadowsocks) val icon = getResources.getDrawable(R.drawable.ic_stat_shadowsocks)
if (rate >= 0) { if (rate >= 0) {
@@ -258,23 +254,8 @@ class ShadowsocksNatService extends Service with BaseService {
startForegroundCompat(1, builder.build) startForegroundCompat(1, builder.build)
} }
def notifyAlert(title: String, info: String) {
val openIntent: Intent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val contentIntent: PendingIntent = PendingIntent.getActivity(this, 0, openIntent, 0)
val builder: NotificationCompat.Builder = new NotificationCompat.Builder(this)
builder
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.setWhen(0)
.setTicker(title)
.setContentTitle(getString(R.string.app_name))
.setContentText(info)
.setContentIntent(contentIntent)
.setAutoCancel(true)
notificationManager.notify(1, builder.build)
}
def onBind(intent: Intent): IBinder = { def onBind(intent: Intent): IBinder = {
Log.d(TAG, "onBind")
if (Action.SERVICE == intent.getAction) { if (Action.SERVICE == intent.getAction) {
binder binder
} else { } else {
@@ -309,14 +290,6 @@ class ShadowsocksNatService extends Service with BaseService {
} }
} }
override def onStartCommand(intent: Intent, flags: Int, startId: Int): Int = {
Service.START_STICKY
}
override def onTaskRemoved(intent: Intent) {
stopRunner()
}
def killProcesses() { def killProcesses() {
Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT") Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT")
@@ -462,12 +435,12 @@ class ShadowsocksNatService extends Service with BaseService {
} }
registerReceiver(receiver, filter) registerReceiver(receiver, filter)
// start tracker
EasyTracker // send event
.getInstance(this) application.tracker.send(new HitBuilders.EventBuilder()
.send(MapBuilder .setCategory(TAG)
.createEvent(TAG, "start", getVersionName, 0L) .setAction("start")
.set(Fields.SESSION_CONTROL, "start") .setLabel(getVersionName)
.build()) .build())
changeState(State.CONNECTING) changeState(State.CONNECTING)
@@ -503,44 +476,46 @@ class ShadowsocksNatService extends Service with BaseService {
} }
spawn { spawn {
if (config.proxy == "198.199.101.152") { if (config.proxy == "198.199.101.152") {
val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer val holder = application.containerHolder
try { try {
config = ConfigUtils.getPublicConfig(getBaseContext, container, config) config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch { } catch {
case ex: Exception => case ex: Exception =>
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed)) changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner() stopRunner()
changeState(State.STOPPED) config = null
return
} }
} }
killProcesses() if (config != null) {
var resolved: Boolean = false killProcesses()
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) { var resolved: Boolean = false
Utils.resolve(config.proxy, enableIPv6 = true) match { if (!InetAddressUtils.isIPv4Address(config.proxy) &&
case Some(a) => !InetAddressUtils.isIPv6Address(config.proxy)) {
config.proxy = a Utils.resolve(config.proxy, enableIPv6 = true) match {
resolved = true case Some(a) =>
case None => resolved = false config.proxy = a
resolved = true
case None => resolved = false
}
} else {
resolved = true
} }
} else {
resolved = true
}
hasRedirectSupport = Utils.getHasRedirectSupport hasRedirectSupport = Utils.getHasRedirectSupport
if (resolved && handleConnection) { if (resolved && handleConnection) {
notifyForegroundAlert(getString(R.string.forward_success), notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).format(config.profileName)) getString(R.string.service_running).format(config.profileName))
changeState(State.CONNECTED) changeState(State.CONNECTED)
} else { } else {
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed)) changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner() stopRunner()
changeState(State.STOPPED) }
} }
} }
} }
@@ -550,12 +525,11 @@ class ShadowsocksNatService extends Service with BaseService {
// change the state // change the state
changeState(State.STOPPED) changeState(State.STOPPED)
// stop the tracker // send event
EasyTracker application.tracker.send(new HitBuilders.EventBuilder()
.getInstance(this) .setCategory(TAG)
.send(MapBuilder .setAction("stop")
.createEvent(TAG, "stop", getVersionName, 0L) .setLabel(getVersionName)
.set(Fields.SESSION_CONTROL, "stop")
.build()) .build())
// reset timer // reset timer
@@ -564,13 +538,6 @@ class ShadowsocksNatService extends Service with BaseService {
timer = null timer = null
} }
// clean up context
stopForegroundCompat(1)
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
}
// reset NAT // reset NAT
killProcesses() killProcesses()
@@ -578,6 +545,14 @@ class ShadowsocksNatService extends Service with BaseService {
if (callbackCount == 0) { if (callbackCount == 0) {
stopSelf() stopSelf()
} }
// clean up context
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
}
stopForegroundCompat(1)
} }
override def stopBackgroundService() { override def stopBackgroundService() {
@@ -138,7 +138,7 @@ class ShadowsocksRunnerActivity extends Activity {
deattachService() deattachService()
if (receiver != null) { if (receiver != null) {
unregisterReceiver(receiver) unregisterReceiver(receiver)
receiver = null; receiver = null
} }
} }
@@ -39,25 +39,24 @@
package com.github.shadowsocks package com.github.shadowsocks
import java.io.File
import java.net.InetAddress
import android.app._ import android.app._
import android.content._ import android.content._
import android.content.pm.PackageInfo import android.content.pm.{PackageInfo, PackageManager}
import android.content.pm.PackageManager import android.net.VpnService
import android.os._ import android.os._
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import android.util.Log import android.util.Log
import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker} import com.github.shadowsocks.aidl.Config
import android.net.VpnService
import org.apache.http.conn.util.InetAddressUtils
import android.os.Message
import scala.concurrent.ops._
import org.apache.commons.net.util.SubnetUtils
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
import scala.Some import com.google.android.gms.analytics.HitBuilders
import com.github.shadowsocks.aidl.{IShadowsocksService, Config} import org.apache.commons.net.util.SubnetUtils
import org.apache.http.conn.util.InetAddressUtils
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import java.io.File import scala.concurrent.ops._
import java.net.InetAddress
class ShadowsocksVpnService extends VpnService with BaseService { class ShadowsocksVpnService extends VpnService with BaseService {
@@ -73,7 +72,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
var apps: Array[ProxiedApp] = null var apps: Array[ProxiedApp] = null
var config: Config = null var config: Config = null
val handler: Handler = new Handler() private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isByass(net: SubnetUtils): Boolean = { def isByass(net: SubnetUtils): Boolean = {
val info = net.getInfo val info = net.getInfo
@@ -118,13 +117,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
def startVpn() { def startVpn() {
val openIntent: Intent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val configIntent = PendingIntent.getActivity(this, 0, openIntent, 0)
val builder = new Builder() val builder = new Builder()
builder builder
.setConfigureIntent(configIntent)
.setSession(config.profileName) .setSession(config.profileName)
.setMtu(VPN_MTU) .setMtu(VPN_MTU)
.addAddress(PRIVATE_VLAN.format("1"), 24) .addAddress(PRIVATE_VLAN.format("1"), 24)
@@ -220,22 +214,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
true true
} }
def notifyAlert(title: String, info: String) {
val openIntent: Intent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val contentIntent: PendingIntent = PendingIntent.getActivity(this, 0, openIntent, 0)
val builder: NotificationCompat.Builder = new NotificationCompat.Builder(this)
builder
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.setWhen(0)
.setTicker(title)
.setContentTitle(getString(R.string.app_name))
.setContentText(info)
.setContentIntent(contentIntent)
.setAutoCancel(true)
notificationManager.notify(1, builder.build)
}
override def onBind(intent: Intent): IBinder = { override def onBind(intent: Intent): IBinder = {
val action = intent.getAction val action = intent.getAction
if (VpnService.SERVICE_INTERFACE == action) { if (VpnService.SERVICE_INTERFACE == action) {
@@ -255,14 +233,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
.asInstanceOf[NotificationManager] .asInstanceOf[NotificationManager]
} }
override def onStartCommand(intent: Intent, flags: Int, startId: Int): Int = {
Service.START_STICKY
}
override def onTaskRemoved(intent: Intent) {
stopRunner()
}
override def onRevoke() { override def onRevoke() {
stopRunner() stopRunner()
} }
@@ -289,12 +259,11 @@ class ShadowsocksVpnService extends VpnService with BaseService {
return return
} }
// start the tracker // send event
EasyTracker application.tracker.send(new HitBuilders.EventBuilder()
.getInstance(this) .setCategory(TAG)
.send(MapBuilder .setAction("start")
.createEvent(TAG, "start", getVersionName, 0L) .setLabel(getVersionName)
.set(Fields.SESSION_CONTROL, "start")
.build()) .build())
// register close receiver // register close receiver
@@ -311,41 +280,42 @@ class ShadowsocksVpnService extends VpnService with BaseService {
spawn { spawn {
if (config.proxy == "198.199.101.152") { if (config.proxy == "198.199.101.152") {
val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder
try { try {
config = ConfigUtils.getPublicConfig(getBaseContext, container, config) config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch { } catch {
case ex: Exception => case ex: Exception =>
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed)) changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner() stopRunner()
changeState(State.STOPPED) config = null
return
} }
} }
// reset the context if (config != null) {
killProcesses()
// Resolve the server address // reset the context
var resolved: Boolean = false killProcesses()
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) { // Resolve the server address
Utils.resolve(config.proxy, enableIPv6 = true) match { var resolved: Boolean = false
case Some(addr) => if (!InetAddressUtils.isIPv4Address(config.proxy) &&
config.proxy = addr !InetAddressUtils.isIPv6Address(config.proxy)) {
resolved = true Utils.resolve(config.proxy, enableIPv6 = true) match {
case None => resolved = false case Some(addr) =>
config.proxy = addr
resolved = true
case None => resolved = false
}
} else {
resolved = true
} }
} else {
resolved = true
}
if (resolved && handleConnection) { if (resolved && handleConnection) {
changeState(State.CONNECTED) changeState(State.CONNECTED)
} else { } else {
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed)) changeState(State.STOPPED, getString(R.string.service_failed))
changeState(State.STOPPED) stopRunner()
stopRunner() }
} }
} }
} }
@@ -355,20 +325,13 @@ class ShadowsocksVpnService extends VpnService with BaseService {
// channge the state // channge the state
changeState(State.STOPPED) changeState(State.STOPPED)
// stop the tracker // send event
EasyTracker application.tracker.send(new HitBuilders.EventBuilder()
.getInstance(this) .setCategory(TAG)
.send(MapBuilder .setAction("stop")
.createEvent(TAG, "stop", getVersionName, 0L) .setLabel(getVersionName)
.set(Fields.SESSION_CONTROL, "stop")
.build()) .build())
// clean up the context
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
}
// reset VPN // reset VPN
killProcesses() killProcesses()
@@ -378,13 +341,16 @@ class ShadowsocksVpnService extends VpnService with BaseService {
conn = null conn = null
} }
// reset notifications
notificationManager.cancel(1)
// stop the service if no callback registered // stop the service if no callback registered
if (callbackCount == 0) { if (callbackCount == 0) {
stopSelf() stopSelf()
} }
// clean up the context
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
}
} }
override def stopBackgroundService() { override def stopBackgroundService() {
@@ -41,7 +41,7 @@ package com.github.shadowsocks.utils
import android.content.{SharedPreferences, Context} import android.content.{SharedPreferences, Context}
import com.github.shadowsocks.ShadowsocksApplication import com.github.shadowsocks.ShadowsocksApplication
import com.google.tagmanager.Container import com.google.android.gms.tagmanager.Container
import scalaj.http.{HttpOptions, Http} import scalaj.http.{HttpOptions, Http}
import com.github.shadowsocks.aidl.Config import com.github.shadowsocks.aidl.Config
@@ -143,8 +143,8 @@ object ConfigUtils {
} }
def refresh(context: Context) { def refresh(context: Context) {
val container = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].tagContainer val holder = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].containerHolder
if (container != null) container.refresh() if (holder != null) holder.refresh()
} }
def getPublicConfig(context: Context, container: Container, config: Config): Config = { def getPublicConfig(context: Context, container: Container, config: Config): Config = {
@@ -57,7 +57,10 @@ object Console {
.open(new OnCommandResultListener { .open(new OnCommandResultListener {
override def onCommandResult(commandCode: Int, exitCode: Int, override def onCommandResult(commandCode: Int, exitCode: Int,
output: util.List[String]) { output: util.List[String]) {
if (exitCode < 0) shell = null if (exitCode < 0) {
shell.close()
shell = null
}
} }
}) })
} }
@@ -82,8 +85,9 @@ object Console {
if (shell == null) { if (shell == null) {
openShell() openShell()
} }
shell.addCommand(commands) val ts = shell
shell.waitForIdle() ts.addCommand(commands)
ts.waitForIdle()
} }
def runRootCommand(command: String): String = runRootCommand(Array(command)) def runRootCommand(command: String): String = runRootCommand(Array(command))
@@ -95,11 +99,13 @@ object Console {
if (rootShell == null) { if (rootShell == null) {
openRootShell() openRootShell()
} }
val ts = rootShell
val sb = new StringBuilder val sb = new StringBuilder
rootShell.addCommand(commands, 0, new OnCommandResultListener { ts.addCommand(commands, 0, new OnCommandResultListener {
override def onCommandResult(commandCode: Int, exitCode: Int, override def onCommandResult(commandCode: Int, exitCode: Int,
output: util.List[String]) { output: util.List[String]) {
if (exitCode < 0) { if (exitCode < 0) {
rootShell.close()
rootShell = null rootShell = null
} else { } else {
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
@@ -107,7 +113,7 @@ object Console {
} }
} }
}) })
if (rootShell.waitForIdle()) sb.toString() if (ts.waitForIdle()) sb.toString()
else null else null
} }