Compare commits

...
18 Commits
Author SHA1 Message Date
Max Lv 55f25d3272 disable NAT mode on lollipop for now 2014-10-19 14:09:27 +08:00
Max Lv 93273cbc44 fix an issue on lollipop 2014-10-19 13:58:19 +08:00
Max Lv c0514ee169 disable bypass feature of pdnsd 2014-10-18 10:46:54 +08:00
Max Lv 06d736b22d fix all issues for lollipop 2014-10-18 09:58:40 +08:00
Max Lv e34d5675eb update shadowsocks-libev 2014-10-14 12:58:09 +08:00
Max Lv 94c7ffb788 remove large icon 2014-09-30 12:59:15 +08:00
Max Lv 0647ef4c6d fix #121 2014-09-19 14:17:45 +08:00
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
84 changed files with 436 additions and 595 deletions
+1
View File
@@ -24,3 +24,4 @@ script:
- ./build-ndk.sh
- cp local.properties.travis local.properties
- sbt android:package-release
- exit 0
+18 -28
View File
@@ -1,38 +1,28 @@
#!/bin/bash
# Target 9
cp jni/Application.mk.9 jni/Application.mk
ndk-build clean
ndk-build
rm -rf src/main/assets/armeabi
function try () {
"$@" || exit -1
}
# Build
try ndk-build clean
try ndk-build
# copy executables
rm -rf src/main/assets/armeabi-v7a
rm -rf src/main/assets/x86
mkdir -p src/main/assets/armeabi
mkdir -p src/main/assets/armeabi-v7a
mkdir -p src/main/assets/x86
for app in pdnsd redsocks
do
mv libs/armeabi/$app src/main/assets/armeabi/
mv libs/armeabi-v7a/$app src/main/assets/armeabi-v7a/
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/
try mv libs/armeabi-v7a/$app src/main/assets/armeabi-v7a/
try mv libs/x86/$app src/main/assets/x86/
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/
+3 -6
View File
@@ -4,7 +4,7 @@ import android.Dependencies.{apklib,aar}
android.Plugin.androidBuild
platformTarget in Android := "android-19"
platformTarget in Android := "android-21"
name := "shadowsocks"
@@ -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/"
libraryDependencies ++= Seq(
"com.google.android" % "analytics" % "3.01",
"dnsjava" % "dnsjava" % "2.1.5",
"org.scalaj" %% "scalaj-http" % "0.3.10",
"commons-net" % "commons-net" % "3.3",
@@ -23,15 +22,13 @@ libraryDependencies ++= Seq(
)
libraryDependencies ++= Seq(
aar("com.actionbarsherlock" % "actionbarsherlock" % "4.4.0") exclude("com.google.android", "support-v4"),
"net.simonvt.menudrawer" % "menudrawer" % "3.0.6",
"org.jraf" % "android-switch-backport" % "1.3.1",
"com.google.android.gms" % "play-services" % "4.4.52",
"com.google.android.gms" % "play-services" % "5.0.89",
"com.android.support" % "support-v4" % "19.1.0"
)
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.j256.ormlite" % "ormlite-core" % "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_STL := stlport_static
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) {
abi = "mips";
} else if (family == ANDROID_CPU_FAMILY_ARM) {
if (features & ANDROID_CPU_ARM_FEATURE_ARMv7) {
abi = "armeabi-v7a";
} else {
abi = "armeabi";
}
// if (features & ANDROID_CPU_ARM_FEATURE_ARMv7) {
abi = "armeabi-v7a";
// } else {
// abi = "armeabi";
// }
}
return env->NewStringUTF(abi);
}
+5 -6
View File
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.shadowsocks"
android:versionCode="69"
android:versionName="2.2.1">
android:versionCode="75"
android:versionName="2.3.0">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@@ -15,10 +15,11 @@
android:required="false"/>
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19"/>
android:minSdkVersion="16"
android:targetSdkVersion="21"/>
<application
android:allowBackup="true"
android:name=".ShadowsocksApplication"
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher"
@@ -75,14 +76,12 @@
<service
android:name=".ShadowsocksNatService"
android:process=":proxy"
android:exported="false">
</service>
<service
android:name=".ShadowsocksVpnService"
android:label="@string/app_name"
android:process=":vpn"
android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="false">
<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"
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="true" android:drawable="@drawable/pressed_background_shadow" />
<item android:state_pressed="true" android:drawable="@drawable/list_pressed_shadow" />
<item android:drawable="@android:color/transparent" />
</selector>
+1 -1
View File
@@ -21,7 +21,7 @@
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/>
<org.jraf.android.backport.switchwidget.Switch
<Switch
android:id="@+id/bypassSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+2 -1
View File
@@ -15,8 +15,9 @@
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/>
<org.jraf.android.backport.switchwidget.Switch
<Switch
android:id="@+id/switchButton"
android:switchTextAppearance="@android:style/TextAppearance.Small.Inverse"
android:enabled="false"
android:layout_width="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 -1
View File
@@ -44,7 +44,7 @@
<string name="forward_stop">后台服务已停止。</string>
<string name="service_failed">请检查你的网络状态后并重试。</string>
<string name="stop">停止服务</string>
<string name="vpn_error">无法启动 VPN 服务:\"%s\"。看来和你的设备存在兼容性问题,请使用 Root 模式。</string>
<string name="vpn_error">无法启动服务:\"%s\"。</string>
<string name="ok_iknow">确定</string>
<string name="port_alert">端口号应大于1024</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">
<item>TABLE</item>
<item>RC4</item>
<item>RC4-MD5</item>
<item>AES-128-CFB</item>
<item>AES-192-CFB</item>
<item>AES-256-CFB</item>
@@ -22,6 +23,7 @@
<string-array name="enc_method_value">
<item>table</item>
<item>rc4</item>
<item>rc4-md5</item>
<item>aes-128-cfb</item>
<item>aes-192-cfb</item>
<item>aes-256-cfb</item>
-14
View File
@@ -1,18 +1,4 @@
<?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>
+1 -1
View File
@@ -57,7 +57,7 @@
<string name="forward_stop">Shadowsocks stopped.</string>
<string name="service_failed">Please check your network status and try again.</string>
<string name="stop">Stop the service</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>
<string name="vpn_error">Unable to start service: "%s".</string>
<!-- alert category -->
<string name="ok_iknow">OK</string>
+46 -40
View File
@@ -16,54 +16,60 @@
<resources>
<style name="Widget.Shadow.Switch" parent="@style/Widget.Holo.CompoundButton.Switch">
<item name="switchTextAppearance">@android:style/TextAppearance.Small.Inverse</item>
</style>
<style name="Theme.AppManager" parent="@style/Theme.Shadow">
</style>
<!-- Variation on the Light theme that turns off the title -->
<style name="Theme.Shadowsocks" parent="@style/Theme.Shadow">
<item name="switchStyle">@style/Widget.Shadow.Switch</item>
<item name="menuDrawerStyle">@style/MenuDrawerStyle</item>
</style>
<style name="PopupTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowContentOverlay">@null</item>
<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">
<item name="switchStyle">@style/Widget.Holo.Light.CompoundButton.Switch</item>
</style>
<!-- Variation on the Light theme that turns off the title -->
<style name="Theme.Shadowsocks" parent="@style/Theme.Shadow">
<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">
<item name="android:textStyle">bold</item>
<item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
<item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
<style name="MenuDrawer.Widget.Category">
<item name="android:textStyle">bold</item>
<item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
<item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
<item name="android:gravity">center_vertical</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:background">@drawable/md__category_background</item>
<item name="android:gravity">center_vertical</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:background">@drawable/md__category_background</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>
<style name="MenuDrawer.Widget.Title">
<item name="android:background">@drawable/md__list_selector_holo_dark</item>
<item name="android:textAppearance">?android:attr/textAppearance</item>
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="android:textSize">18sp</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item>
<item name="android:drawablePadding">16dp</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="MenuDrawer.Widget.Title">
<item name="android:background">@drawable/md__list_selector_holo_dark</item>
<item name="android:textAppearance">?android:attr/textAppearance</item>
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="android:textSize">18sp</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item>
<item name="android:drawablePadding">16dp</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="MenuDrawerStyle" parent="Widget.MenuDrawer">
<item name="mdActiveIndicator">@drawable/menu_arrow</item>
<item name="mdMenuSize">250dp</item>
</style>
<style name="MenuDrawerStyle" parent="Widget.MenuDrawer">
<item name="mdActiveIndicator">@drawable/menu_arrow</item>
<item name="mdMenuSize">250dp</item>
</style>
</resources>
+34 -47
View File
@@ -19,77 +19,64 @@
<resources>
<style name="PopupTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowContentOverlay">@null</item>
<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>
<item name="windowContentOverlay">@null</item>
</style>
<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 name="Theme.Shadow" parent="@android:style/Theme.Holo.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="background">@drawable/ab_solid_shadow</item>
<item name="backgroundStacked">@drawable/ab_stacked_solid_shadow</item>
<item name="backgroundSplit">@drawable/ab_bottom_solid_shadow</item>
<item name="progressBarStyle">@style/ProgressBar.Shadow</item>
<style name="ActionBar.Solid.Shadow" parent="@android:style/Widget.Holo.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="background">@drawable/ab_transparent_shadow</item>
<item name="progressBarStyle">@style/ProgressBar.Shadow</item>
<style name="ActionBar.Transparent.Shadow" parent="@android:style/Widget.Holo.ActionBar">
<item name="android:background">@drawable/ab_transparent_shadow</item>
<item name="android:progressBarStyle">@style/ProgressBar.Shadow</item>
</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>
</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>
</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>
</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:popupBackground">@drawable/menu_dropdown_panel_shadow</item>
<item name="android:dropDownSelector">@drawable/selectable_background_shadow</item>
</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>
</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>
</style>
<!-- this style is only referenced in a Light.DarkActionBar based theme -->
<style name="Theme.Shadow.Widget" parent="@style/Theme.Sherlock">
<item name="popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="dropDownListViewStyle">@style/DropDownListView.Shadow</item>
<style name="Theme.Shadow.Widget" parent="@android:style/Theme.Holo">
<item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
<item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
</style>
</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
import android.app.ProgressDialog
import android.app.{Activity, ProgressDialog}
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager
@@ -53,23 +53,13 @@ import android.view.View.OnClickListener
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.view.WindowManager
import android.widget.AbsListView
import android.widget._
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.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 java.io.{ByteArrayOutputStream, ByteArrayInputStream, InputStream}
import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration}
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}
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_FINISH = 2
@@ -216,9 +206,20 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
saveAppSettings(this)
}
override def onDestroy() {
super.onDestroy()
if (handler != null) {
handler.removeCallbacksAndMessages(null)
handler = null
}
}
protected override def onCreate(savedInstanceState: Bundle) {
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.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView]
getWindowManager.addView(overlay, new
@@ -233,7 +234,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
.build()
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)
bypassSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener {
def onCheckedChanged(button: CompoundButton, checked: Boolean) {
@@ -247,24 +248,14 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
super.onResume()
new Thread {
override def run() {
handler.sendEmptyMessage(MSG_LOAD_START)
handler.post(loadStartRunnable)
appListView = findViewById(R.id.applistview).asInstanceOf[ListView]
if (!appsLoaded) loadApps()
handler.sendEmptyMessage(MSG_LOAD_FINISH)
handler.post(loadFinishRunnable)
}
}.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) {
if (apps == null) return
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
@@ -279,46 +270,46 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
edit.commit
}
val handler: Handler = new Handler {
override def handleMessage(msg: Message) {
msg.what match {
case MSG_LOAD_START =>
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 loadStartRunnable = new Runnable {
override def run() {
progressDialog = ProgressDialog
.show(AppManager.this, "", getString(R.string.loading), true, true)
}
}
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)
extends BaseImageDownloader(context, connectTimeout, readTimeout) {
@@ -54,21 +54,20 @@ import android.util.{DisplayMetrics, Log}
import android.view._
import android.webkit.{WebView, WebViewClient}
import android.widget._
import com.actionbarsherlock.app.SherlockPreferenceActivity
import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback}
import com.github.shadowsocks.database._
import com.github.shadowsocks.preferences.{PasswordEditTextPreference, ProfileEditTextPreference, SummaryEditTextPreference}
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.analytics.HitBuilders
import com.google.zxing.integration.android.IntentIntegrator
import com.nostra13.universalimageloader.core.download.BaseImageDownloader
import de.keyboardsurfer.android.widget.crouton.{Configuration, Crouton, Style}
import net.simonvt.menudrawer.MenuDrawer
import org.jraf.android.backport.switchwidget.Switch
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.concurrent.ops._
import scala.ref.WeakReference
class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
extends BaseImageDownloader(context, connectTimeout, readTimeout) {
@@ -169,7 +168,7 @@ object Shadowsocks {
}
class Shadowsocks
extends SherlockPreferenceActivity
extends PreferenceActivity
with CompoundButton.OnCheckedChangeListener
with MenuAdapter.MenuListener {
@@ -214,6 +213,8 @@ class Shadowsocks
setPreferenceEnabled(enabled = false)
}
state = bgService.getState
// set the listener
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
}
override def onServiceDisconnected(name: ComponentName) {
@@ -227,16 +228,18 @@ class Shadowsocks
}
}
lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
lazy val preferenceReceiver = new PreferenceBroadcastReceiver
lazy val drawer = MenuDrawer.attach(this)
lazy val menuAdapter = new MenuAdapter(this, getMenuList)
lazy val listView = new ListView(this)
lazy val profileManager =
private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
private lazy val preferenceReceiver = new PreferenceBroadcastReceiver
private lazy val drawer = MenuDrawer.attach(this)
private lazy val menuAdapter = new MenuAdapter(this, getMenuList)
private lazy val listView = new ListView(this)
private lazy val profileManager =
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 = {
if (singlePane == -1) {
@@ -442,6 +445,8 @@ class Shadowsocks
super.onCreate(savedInstanceState)
handler = new Handler()
addPreferencesFromResource(R.xml.pref_all)
// Initialize the profile
@@ -481,10 +486,10 @@ class Shadowsocks
val tf: Typeface = Typefaces.get(this, "fonts/Iceland.ttf")
if (tf != null) title.setTypeface(tf)
switchButton = switchLayout.findViewById(R.id.switchButton).asInstanceOf[Switch]
getSupportActionBar.setCustomView(switchLayout)
getSupportActionBar.setDisplayShowTitleEnabled(false)
getSupportActionBar.setDisplayShowCustomEnabled(true)
getSupportActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
getActionBar.setCustomView(switchLayout)
getActionBar.setDisplayShowTitleEnabled(false)
getActionBar.setDisplayShowCustomEnabled(true)
getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
// Register broadcast receiver
registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS))
@@ -519,8 +524,8 @@ class Shadowsocks
case ignored: RemoteException => // Nothing
}
bgService = null
unbindService(connection)
}
unbindService(connection)
}
override def onRestoreInstanceState(inState: Bundle) {
@@ -683,32 +688,40 @@ class Shadowsocks
buf += new Category(getString(R.string.settings))
buf += new Item(-100, getString(R.string.recovery), android.R.drawable.ic_menu_revert, _ => {
EasyTracker
.getInstance(this)
.send(MapBuilder.createEvent(Shadowsocks.TAG, "reset", getVersionName, null).build())
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(Shadowsocks.TAG)
.setAction("reset")
.setLabel(getVersionName)
.build())
recovery()
})
buf +=
new Item(-200, getString(R.string.flush_dnscache), android.R.drawable.ic_menu_delete, _ => {
EasyTracker
.getInstance(this)
.send(
MapBuilder.createEvent(Shadowsocks.TAG, "flush_dnscache", getVersionName, null).build())
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(Shadowsocks.TAG)
.setAction("flush_dnscache")
.setLabel(getVersionName)
.build())
flushDnsCache()
})
buf += new Item(-300, getString(R.string.about), android.R.drawable.ic_menu_info_details, _ => {
EasyTracker
.getInstance(this)
.send(MapBuilder.createEvent(Shadowsocks.TAG, "about", getVersionName, null).build())
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(Shadowsocks.TAG)
.setAction("about")
.setLabel(getVersionName)
.build())
showAbout()
})
buf.toList
}
override def onOptionsItemSelected(item: com.actionbarsherlock.view.MenuItem): Boolean = {
override def onOptionsItemSelected(item: MenuItem): Boolean = {
item.getItemId match {
case android.R.id.home =>
drawer.toggleMenu()
@@ -735,14 +748,13 @@ class Shadowsocks
changeSwitch(checked = false)
}
state = bgService.getState
// set the listener
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
}
// set the listener
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
ConfigUtils.refresh(this)
}
private def setPreferenceEnabled(enabled: Boolean) {
val isRoot = status.getBoolean(Key.isRoot, false)
for (name <- Shadowsocks.PROXY_PREFS) {
val pref = findPreference(name)
if (pref != null) {
@@ -754,7 +766,7 @@ class Shadowsocks
if (pref != null) {
if (Seq(Key.isGlobalProxy, Key.isTrafficStat, Key.proxyedApps)
.contains(name)) {
pref.setEnabled(enabled && isRoot)
pref.setEnabled(enabled && !isVpnEnabled)
} else {
pref.setEnabled(enabled)
}
@@ -776,12 +788,10 @@ class Shadowsocks
override def onStart() {
super.onStart()
EasyTracker.getInstance(this).activityStart(this)
}
override def onStop() {
super.onStop()
EasyTracker.getInstance(this).activityStop(this)
clearDialog()
}
@@ -791,6 +801,10 @@ class Shadowsocks
Crouton.cancelAllCroutons()
unregisterReceiver(preferenceReceiver)
new BackupManager(this).dataChanged()
if (handler != null) {
handler.removeCallbacksAndMessages(null)
handler = null
}
}
def copyToSystem() {
@@ -810,15 +824,7 @@ class Shadowsocks
crash_recovery()
if (Build.VERSION.SDK_INT >= 16) {
copyAssets("api-16/" + System.getABI)
} else {
copyAssets(System.getABI)
}
if (Build.VERSION.SDK_INT >= 20) {
copyToSystem()
}
copyAssets(System.getABI)
val ab = new ArrayBuffer[String]
for (executable <- Shadowsocks.EXECUTABLES) {
@@ -868,8 +874,8 @@ class Shadowsocks
def isVpnEnabled: Boolean = {
if (vpnEnabled < 0) {
vpnEnabled = if (Build.VERSION.SDK_INT
>= Build.VERSION_CODES.ICE_CREAM_SANDWICH && !status.getBoolean(Key.isRoot, false)) {
vpnEnabled = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP
|| !status.getBoolean(Key.isRoot, false)) {
1
} else {
0
@@ -917,8 +923,6 @@ class Shadowsocks
bgService.start(ConfigUtils.load(settings))
if (isVpnEnabled) {
val style = new Style.Builder().setBackgroundColorValue(Style.holoBlueLight).build()
val config = new Configuration.Builder().setDuration(Configuration.DURATION_LONG).build()
changeSwitch(checked = false)
}
true
@@ -984,7 +988,6 @@ class Shadowsocks
changeSwitch(checked = false)
Crouton.cancelAllCroutons()
if (m != null) {
Crouton.cancelAllCroutons()
val style = new Style.Builder().setBackgroundColorValue(Style.holoRedLight).build()
val config = new Configuration.Builder()
.setDuration(Configuration.DURATION_LONG)
@@ -39,26 +39,35 @@
package com.github.shadowsocks
import java.util
import java.util.concurrent.TimeUnit
import android.app.Application
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.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 {
lazy val dbHelper = new DBHelper(this)
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() {
val tm = TagManager.getInstance(this)
ContainerOpener.openContainer(tm, "GTM-NT8WS8", OpenType.PREFER_NON_DEFAULT, null, new Notifier {
override def containerAvailable(container: Container) {
tagContainer = container
container.registerFunctionCallMacroHandler(SIG_FUNC, new FunctionCallMacroHandler {
def getValue(functionName: String, parameters: util.Map[String, AnyRef]): AnyRef = {
val pending = tm.loadContainerPreferNonDefault("GTM-NT8WS8", R.raw.gtm_default_container)
val callback = new ResultCallback[ContainerHolder] {
override def onResult(holder: ContainerHolder): Unit = {
if (!holder.getStatus.isSuccess) {
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) {
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
import android.app.backup.{FileBackupHelper, SharedPreferencesBackupHelper, BackupAgentHelper}
import android.content.Context
import android.app.backup.{BackupAgentHelper, FileBackupHelper, SharedPreferencesBackupHelper}
import com.github.shadowsocks.database.DBHelper
class ShadowsocksBackupAgent extends BackupAgentHelper {
@@ -39,30 +39,26 @@
package com.github.shadowsocks
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import java.io.File
import java.lang.reflect.{InvocationTargetException, Method}
import java.util.{Timer, TimerTask}
import android.app.{Notification, NotificationManager, PendingIntent, Service}
import android.content._
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.{PackageInfo, PackageManager}
import android.graphics.Color
import android.net.TrafficStats
import android.os._
import android.support.v4.app.NotificationCompat
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.utils._
import com.google.android.gms.analytics.HitBuilders
import org.apache.http.conn.util.InetAddressUtils
import scala.collection._
import scala.collection.mutable.ArrayBuffer
import java.io.File
import scala.concurrent.ops._
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 val TIMER_INTERVAL = 2
val handler: Handler = new Handler()
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isACLEnabled: Boolean = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
@@ -118,49 +114,52 @@ class ShadowsocksNatService extends Service with BaseService {
})
}
val raw_args = ("ss-local -b 127.0.0.1 -s %s -p %d -l %d -k %s -m %s -f " +
Path.BASE + "ss-local.pid")
.format(config.proxy, config.remotePort, config.localPort, config.sitekey, config.encMethod)
val args = if (Build.VERSION.SDK_INT >= 20) {
raw_args
} else {
Path.BASE + raw_args
}
val cmd = if (config.isGFWList && isACLEnabled) args + " --acl " + Path.BASE + "chn.acl" else args
if (BuildConfig.DEBUG) Log.d(TAG, cmd)
val cmd = new ArrayBuffer[String]
cmd += ("ss-local"
, "-b" , "127.0.0.1"
, "-s" , config.proxy
, "-p" , config.remotePort.toString
, "-l" , config.localPort.toString
, "-k" , config.sitekey
, "-m" , config.encMethod
, "-f" , (Path.BASE + "ss-local.pid"))
Core.sslocal(cmd.split(" "))
if (config.isGFWList && isACLEnabled) {
cmd += "--acl"
cmd += (Path.BASE + "chn.acl")
}
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
Core.sslocal(cmd.toArray)
}
def startDnsDaemon() {
val args = if (config.isUdpDns) {
("ss-tunnel -b 127.0.0.1 -s %s -p %d -l %d -k %s -m %s -L 8.8.8.8:53 -u -f " +
Path.BASE + "ss-tunnel.pid")
.format(config.proxy, config.remotePort, 8153, config.sitekey, config.encMethod)
if (config.isUdpDns) {
val cmd = new ArrayBuffer[String]
cmd += ("ss-tunnel" , "-u"
, "-b" , "127.0.0.1"
, "-l" , "8153"
, "-L" , "8.8.8.8:53"
, "-s" , config.proxy
, "-p" , config.remotePort.toString
, "-k" , config.sitekey
, "-m" , config.encMethod
, "-f" , (Path.BASE + "ss-tunnel.pid"))
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
Core.sstunnel(cmd.toArray)
} else {
val conf = {
if (config.isGFWList)
ConfigUtils.PDNSD_BYPASS.format("127.0.0.1", getString(R.string.exclude))
else
ConfigUtils.PDNSD.format("127.0.0.1")
ConfigUtils.PDNSD.format("127.0.0.1")
}
ConfigUtils.printToFile(new File(Path.BASE + "pdnsd.conf"))(p => {
p.println(conf)
})
"pdnsd -c " + Path.BASE + "pdnsd.conf"
}
val cmd = if (Build.VERSION.SDK_INT >= 20) {
"/system/bin/" + args
} else {
Path.BASE + args
}
val args = "pdnsd -c " + Path.BASE + "pdnsd.conf"
val cmd = Path.BASE + args
if (BuildConfig.DEBUG) Log.d(TAG, cmd)
if (config.isUdpDns) {
Core.sstunnel(cmd.split(" "))
} else {
if (BuildConfig.DEBUG) Log.d(TAG, cmd)
Console.runRootCommand(cmd)
}
}
@@ -184,11 +183,7 @@ class ShadowsocksNatService extends Service with BaseService {
ConfigUtils.printToFile(new File(Path.BASE + "redsocks.conf"))(p => {
p.println(conf)
})
val cmd = if (Build.VERSION.SDK_INT >= 20) {
"/system/bin/" + args
} else {
Path.BASE + args
}
val cmd = Path.BASE + args
Console.runRootCommand(cmd)
}
@@ -229,10 +224,6 @@ class ShadowsocksNatService extends Service with BaseService {
val icon = getResources.getDrawable(R.drawable.ic_stat_shadowsocks)
if (rate >= 0) {
val bitmap = Utils
.getBitmap(rate.toString, icon.getIntrinsicWidth * 4, icon.getIntrinsicHeight * 4,
Color.TRANSPARENT)
builder.setLargeIcon(bitmap)
if (rate < 1000) {
builder.setSmallIcon(R.drawable.ic_stat_speed, rate)
@@ -258,23 +249,8 @@ class ShadowsocksNatService extends Service with BaseService {
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 = {
Log.d(TAG, "onBind")
if (Action.SERVICE == intent.getAction) {
binder
} else {
@@ -346,10 +322,6 @@ class ShadowsocksNatService extends Service with BaseService {
init_sb.append(cmd_bypass.replace("-d 0.0.0.0", "-m owner --uid-owner " + myUid))
if (config.isGFWList) {
// Bypass DNS in China
init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-d 114.114.114.114"))
init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-d 114.114.115.115"))
if (!isACLEnabled)
{
val chn_list: Array[String] = getResources.getStringArray(R.array.chn_list)
@@ -454,12 +426,12 @@ class ShadowsocksNatService extends Service with BaseService {
}
registerReceiver(receiver, filter)
// start tracker
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "start", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "start")
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("start")
.setLabel(getVersionName)
.build())
changeState(State.CONNECTING)
@@ -495,44 +467,46 @@ class ShadowsocksNatService extends Service with BaseService {
}
spawn {
if (config.proxy == "198.199.101.152") {
val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer
val holder = application.containerHolder
try {
config = ConfigUtils.getPublicConfig(getBaseContext, container, config)
config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch {
case ex: Exception =>
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
changeState(State.STOPPED)
return
config = null
}
}
killProcesses()
if (config != null) {
var resolved: Boolean = false
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) {
Utils.resolve(config.proxy, enableIPv6 = true) match {
case Some(a) =>
config.proxy = a
resolved = true
case None => resolved = false
killProcesses()
var resolved: Boolean = false
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) {
Utils.resolve(config.proxy, enableIPv6 = true) match {
case Some(a) =>
config.proxy = a
resolved = true
case None => resolved = false
}
} else {
resolved = true
}
} else {
resolved = true
}
hasRedirectSupport = Utils.getHasRedirectSupport
hasRedirectSupport = Utils.getHasRedirectSupport
if (resolved && handleConnection) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).format(config.profileName))
changeState(State.CONNECTED)
} else {
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
stopRunner()
changeState(State.STOPPED)
if (resolved && handleConnection) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).format(config.profileName))
changeState(State.CONNECTED)
} else {
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
}
}
}
}
@@ -542,12 +516,11 @@ class ShadowsocksNatService extends Service with BaseService {
// change the state
changeState(State.STOPPED)
// stop the tracker
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "stop", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "stop")
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("stop")
.setLabel(getVersionName)
.build())
// reset timer
@@ -569,6 +542,7 @@ class ShadowsocksNatService extends Service with BaseService {
unregisterReceiver(receiver)
receiver = null
}
stopForegroundCompat(1)
}
@@ -138,7 +138,7 @@ class ShadowsocksRunnerActivity extends Activity {
deattachService()
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null;
receiver = null
}
}
@@ -39,25 +39,24 @@
package com.github.shadowsocks
import java.io.File
import java.net.InetAddress
import android.app._
import android.content._
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.{PackageInfo, PackageManager}
import android.net.VpnService
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker}
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.aidl.Config
import com.github.shadowsocks.utils._
import scala.Some
import com.github.shadowsocks.aidl.{IShadowsocksService, Config}
import com.google.android.gms.analytics.HitBuilders
import org.apache.commons.net.util.SubnetUtils
import org.apache.http.conn.util.InetAddressUtils
import scala.collection.mutable.ArrayBuffer
import java.io.File
import java.net.InetAddress
import scala.concurrent.ops._
class ShadowsocksVpnService extends VpnService with BaseService {
@@ -73,28 +72,30 @@ class ShadowsocksVpnService extends VpnService with BaseService {
var apps: Array[ProxiedApp] = null
var config: Config = null
val handler: Handler = new Handler()
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isByass(net: SubnetUtils): Boolean = {
val info = net.getInfo
info.isInRange(config.proxy) || info.isInRange("114.114.114.114") || info.isInRange("114.114.115.115")
info.isInRange(config.proxy)
}
def startShadowsocksDaemon() {
val cmd: String = (Path.BASE +
"ss-local -b 127.0.0.1 -s %s -p %d -l %d -k %s -m %s -u -f " +
Path.BASE + "ss-local.pid")
.format(config.proxy, config.remotePort, config.localPort, config.sitekey, config.encMethod)
if (BuildConfig.DEBUG) Log.d(TAG, cmd)
Core.sslocal(cmd.split(" "))
val cmd = new ArrayBuffer[String]
cmd += ("ss-local" , "-u"
, "-b" , "127.0.0.1"
, "-s" , config.proxy
, "-p" , config.remotePort.toString
, "-l" , config.localPort.toString
, "-k" , config.sitekey
, "-m" , config.encMethod
, "-f" , (Path.BASE + "ss-local.pid"))
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
Core.sslocal(cmd.toArray)
}
def startDnsDaemon() {
val conf = {
if (config.isGFWList)
ConfigUtils.PDNSD_BYPASS.format("0.0.0.0", getString(R.string.exclude))
else
ConfigUtils.PDNSD.format("0.0.0.0")
ConfigUtils.PDNSD.format("0.0.0.0")
}
ConfigUtils.printToFile(new File(Path.BASE + "pdnsd.conf"))(p => {
p.println(conf)
@@ -143,7 +144,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}
})
} else {
for (i <- 1 to 254) {
for (i <- 1 to 223) {
if (i != 26 && i != 127) {
val addr = i.toString + ".0.0.0"
val cidr = addr + "/8"
@@ -215,18 +216,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
true
}
def notifyAlert(title: String, info: String) {
val builder = new NotificationCompat.Builder(this)
builder
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.setWhen(0)
.setTicker(title)
.setContentTitle(getString(R.string.app_name))
.setContentText(info)
.setAutoCancel(true)
notificationManager.notify(1, builder.build)
}
override def onBind(intent: Intent): IBinder = {
val action = intent.getAction
if (VpnService.SERVICE_INTERFACE == action) {
@@ -272,12 +261,11 @@ class ShadowsocksVpnService extends VpnService with BaseService {
return
}
// start the tracker
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "start", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "start")
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("start")
.setLabel(getVersionName)
.build())
// register close receiver
@@ -294,41 +282,42 @@ class ShadowsocksVpnService extends VpnService with BaseService {
spawn {
if (config.proxy == "198.199.101.152") {
val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer
val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder
try {
config = ConfigUtils.getPublicConfig(getBaseContext, container, config)
config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch {
case ex: Exception =>
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
changeState(State.STOPPED)
return
config = null
}
}
// reset the context
killProcesses()
if (config != null) {
// Resolve the server address
var resolved: Boolean = false
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) {
Utils.resolve(config.proxy, enableIPv6 = true) match {
case Some(addr) =>
config.proxy = addr
resolved = true
case None => resolved = false
// reset the context
killProcesses()
// Resolve the server address
var resolved: Boolean = false
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
!InetAddressUtils.isIPv6Address(config.proxy)) {
Utils.resolve(config.proxy, enableIPv6 = true) match {
case Some(addr) =>
config.proxy = addr
resolved = true
case None => resolved = false
}
} else {
resolved = true
}
} else {
resolved = true
}
if (resolved && handleConnection) {
changeState(State.CONNECTED)
} else {
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
changeState(State.STOPPED)
stopRunner()
if (resolved && handleConnection) {
changeState(State.CONNECTED)
} else {
changeState(State.STOPPED, getString(R.string.service_failed))
stopRunner()
}
}
}
}
@@ -338,12 +327,11 @@ class ShadowsocksVpnService extends VpnService with BaseService {
// channge the state
changeState(State.STOPPED)
// stop the tracker
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "stop", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "stop")
// send event
application.tracker.send(new HitBuilders.EventBuilder()
.setCategory(TAG)
.setAction("stop")
.setLabel(getVersionName)
.build())
// reset VPN
@@ -365,18 +353,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
unregisterReceiver(receiver)
receiver = null
}
// reset notifications
notificationManager.cancel(1)
}
override def onStartCommand(intent: Intent, flags: Int, startId: Int): Int =
{
Service.START_STICKY
}
override def onTaskRemoved(intent: Intent) {
stopRunner()
}
override def stopBackgroundService() {
@@ -41,7 +41,7 @@ package com.github.shadowsocks.utils
import android.content.{SharedPreferences, Context}
import com.github.shadowsocks.ShadowsocksApplication
import com.google.tagmanager.Container
import com.google.android.gms.tagmanager.Container
import scalaj.http.{HttpOptions, Http}
import com.github.shadowsocks.aidl.Config
@@ -143,8 +143,8 @@ object ConfigUtils {
}
def refresh(context: Context) {
val container = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].tagContainer
if (container != null) container.refresh()
val holder = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].containerHolder
if (holder != null) holder.refresh()
}
def getPublicConfig(context: Context, container: Container, config: Config): Config = {
@@ -57,7 +57,10 @@ object Console {
.open(new OnCommandResultListener {
override def onCommandResult(commandCode: Int, exitCode: Int,
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) {
openShell()
}
shell.addCommand(commands)
shell.waitForIdle()
val ts = shell
ts.addCommand(commands)
ts.waitForIdle()
}
def runRootCommand(command: String): String = runRootCommand(Array(command))
@@ -95,11 +99,13 @@ object Console {
if (rootShell == null) {
openRootShell()
}
val ts = rootShell
val sb = new StringBuilder
rootShell.addCommand(commands, 0, new OnCommandResultListener {
ts.addCommand(commands, 0, new OnCommandResultListener {
override def onCommandResult(commandCode: Int, exitCode: Int,
output: util.List[String]) {
if (exitCode < 0) {
rootShell.close()
rootShell = null
} else {
import scala.collection.JavaConversions._
@@ -107,7 +113,7 @@ object Console {
}
}
})
if (rootShell.waitForIdle()) sb.toString()
if (ts.waitForIdle()) sb.toString()
else null
}