Compare commits

...
22 Commits
Author SHA1 Message Date
Max Lv be168c77f6 Bump version 2018-01-15 02:04:31 -08:00
Mygod f9b29acd82 Update notification channels on configuration change 2018-01-14 06:22:58 +08:00
Max Lv 4e943bc782 Reduce the DNS timeout 2018-01-12 17:02:22 +08:00
Max Lv b3a818b03a Merge pull request #1570 from imReker/master
Support build overture on Windows
2018-01-12 10:18:19 +08:00
Max Lv 982845e877 Enlarge the timeout of protecting socket 2018-01-11 22:11:55 +08:00
imReker 4e35fe19c8 Support build overture on Windows 2018-01-11 18:01:08 +08:00
initrider 45d8e827c1 Fixed translation mistakes + Fix #1565 (#1568)
* Create faq.ru-RU.md

* Update faq.ru-RU.md

* Translate - FAQ - Russian

* Rename .github/faq.ru-RU.md to  .github/faq.ru.md

* Fixed translation mistakes + Fix #1565

* Update faq.ru.md

* Visual improvement
2018-01-10 09:27:26 +08:00
Max Lv 90dd0ab300 Refine local DNS resolver 2018-01-06 15:13:26 +08:00
Syrone Wong dee540b83a update gradle wrapper to 4.4.1 (#1560)
$ ./gradlew wrapper --gradle-version=4.4.1 --distribution-type=all
2018-01-05 20:50:07 +08:00
Max Lv f3b3507c0f Merge pull request #1558 from wongsyrone/update-ip
update China and Telegram ip range
2018-01-05 18:25:37 +08:00
Syrone Wong 402710841b update China and Telegram ip range 2018-01-05 17:12:04 +08:00
Max Lv 6ded9d3d37 Refine #1556 2018-01-04 17:06:56 -08:00
initrider 88274fb732 Translation of FAQ to Russian language (#1552) 2018-01-04 21:09:32 +08:00
Mygod 36e6cfbe59 Remove redundant sbt file 2018-01-04 21:08:08 +08:00
Max Lv f05761ac4d Refine the animation of snackbar 2018-01-04 19:25:31 +08:00
Mygod a33efea2b5 Add French 2018-01-04 19:03:07 +08:00
Mygod b2e6639901 Remove translatable 2018-01-04 18:23:45 +08:00
Max Lv db74988190 Fix the listview issue 2018-01-03 18:37:36 -08:00
Max Lv 9a43c78e7b Fix #1548 2018-01-03 17:21:46 -08:00
Max Lv e915a4221d Merge branch 'beta' 2018-01-02 20:05:32 -08:00
Max Lv 040a6a2815 Bump version 2017-12-09 16:27:45 +08:00
Mygod 0b9b0a91c8 Fix #1490 2017-12-07 22:14:19 -08:00
28 changed files with 3766 additions and 1566 deletions
+2 -3
View File
@@ -3,9 +3,8 @@
Cannot connect to server:
1. Stop battery saver if it's active;
2. If an upgrade breaks anything, do a manual reset first by pressing Reset at the end of the list;
3. Check your config;
4. Wipe app data.
2. Check your config;
3. Wipe app data.
Crash: [Submit an issue](https://github.com/shadowsocks/shadowsocks-android/issues/new) with logcat attached, or submit a crash report to Google Play. Then, try wiping app data.
+100
View File
@@ -0,0 +1,100 @@
### Решение проблем
Не получается подключиться к серверу:
1. Выключите режим энергосбережения, если он активен;
2. Проверьте настройки;
3. Сотрите данные приложения.
Не работает: [Добавьте отчет](https://github.com/shadowsocks/shadowsocks-android/issues/new) прикрепив лог (logcat), или отправьте отзыв в Google Play. Затем попробуйте стереть данные приложения.
### Как добавить виджет и/или переключать профиль на основании состояния сети?
Использйте интеграцию с [Tasker](http://tasker.dinglisch.net/).
### Как добавить QR код из локальной галереи?
Отсканируйте его при помощи стороннего сканера, например [QuickMark Barcode Scanner](https://play.google.com/store/apps/details?id=tw.com.quickmark) и нажмите на `ss` ссылку.
### Почему режим NAT более не поддерживается?
1. Требуются ROOT права;
2. Нет поддержки IPv6;
3. Нет поддержки UDP relay.
### Как убрать восклицательный знак когда используется режим VPN?
Восклицательный знак на значке Wi-Fi/Сотовой связи появляется, потому что система не может подключиться к portal-серверу (по-умолчанию к `clients3.google.com`) без VPN подключения. Чтобы убрать его, следуйте инструкциям в [этом топике](https://www.noisyfox.cn/45.html). (на упрощенном китайском)
### Почему мой ROM не поддерживается?
1. Некоторые ROM используют неправильную реализацию службы VPN, особенно IPv6;
2. Некоторые ROM используют агрессивную (или так называемую неправильную) фоновую службу с ошибочной политикой остановки;
3. Если вы используете фреймворк Xposed и/или приложения для энергосбережения, вероятно наше приложение не будет нормально работать с ними.
* Иправления для MIUI: [#772](https://github.com/shadowsocks/shadowsocks-android/issues/772)
* Иправления для Huawei: [#1091 (комментарий)](https://github.com/shadowsocks/shadowsocks-android/issues/1091#issuecomment-276949836)
* Вызванные из-за Xposed: [#1414](https://github.com/shadowsocks/shadowsocks-android/issues/1414)
* Samsung и/или Brevent: [#1410](https://github.com/shadowsocks/shadowsocks-android/issues/1410)
* Не устанавливайте это приложение на SD карту, из-за проблем с разрешениями: [#1124 (комментарий)](https://github.com/shadowsocks/shadowsocks-android/issues/1124#issuecomment-307556453)
### Как приостановить службу Shadowsocks?
* Для Android 7.0+: Используйте переключатель в быстрых настройках;
* Используйте интеграцию с Tasker;
* Добавьте профиль c выбранными приложениями, которые будут работать через Shadowsocks прокси, выключив обходной режим.
### Почему Shadowsocks потребляет так много энергии на Android 5.0+?
Так как Shadowsocks работает со всем траффиком устройства, заряд батареи используемый другими приложениями также считается за тот, что использует Shadowsocks. Таким образом использование батареи Shadowsocks'ом равен сумме всей активности устройства в сети. Shadowsocks сам по себе в общем-то является приложением связанного процесса ввода/вывода на современных Android устройствах, которое, ожидаемо, не потребляет значительного количества энергии.
Так что если вы заметите значительное увеличение потребляемой энергии после того, как вы использовали Shadowsocks, это скорее всего вызванно другими приложениями. Например, сервисы Google Play могут потреблять больше энергии после того, как подключатся к Google, и т.д.
Больше информации: https://kb.adguard.com/en/android/solving-problems/battery
### Оно прекрасно работает при Wi-Fi но не может подключиться через сотовую связь?
Разрешите этому приложению передачу данных в фоновом режиме в настройках приложения.
Если у вас оперератор Yota, то измените точку доступа APN с `yota.ru` на `client.yota.ru`
### Почему требуется разрешение камере на устройствах младше Android 6.0?
Чтобы сканировать QR код через встроенный QR сканер.
Кстати, обновите уже свою версию Android.
### Как использовать режим Transproxy (прозрачный прокси)?
1. Установите [AFWall+](https://github.com/ukanth/afwall);
2. Настройте пользовательский скрипт:
```sh
IP6TABLES=/system/bin/ip6tables
IPTABLES=/system/bin/iptables
ULIMIT=/system/bin/ulimit
SHADOWSOCKS_UID=`dumpsys package com.github.shadowsocks | grep userId | cut -d= -f2 - | cut -d' ' -f1 -`
PORT_DNS=5450
PORT_TRANSPROXY=8200
$ULIMIT -n 4096
$IP6TABLES -F
$IP6TABLES -A INPUT -j DROP
$IP6TABLES -A OUTPUT -j DROP
$IPTABLES -t nat -F OUTPUT
$IPTABLES -t nat -A OUTPUT -o lo -j RETURN
$IPTABLES -t nat -A OUTPUT -d 127.0.0.1 -j RETURN
$IPTABLES -t nat -A OUTPUT -m owner --uid-owner $SHADOWSOCKS_UID -j RETURN
$IPTABLES -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to-destination 127.0.0.1:$PORT_DNS
$IPTABLES -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:$PORT_DNS
$IPTABLES -t nat -A OUTPUT -p tcp -j DNAT --to-destination 127.0.0.1:$PORT_TRANSPROXY
$IPTABLES -t nat -A OUTPUT -p udp -j DNAT --to-destination 127.0.0.1:$PORT_TRANSPROXY
```
3. Настройте пользовательский скрипт отключения:
```sh
IP6TABLES=/system/bin/ip6tables
IPTABLES=/system/bin/iptables
$IPTABLES -t nat -F OUTPUT
$IP6TABLES -F
```
4. Убедитесь, что траффик для Shadowsocks разрешен;
5. Запустите службу прозрачного прокси (transproxy) в Shadowsocks и включите брандмауэр.
+15 -6
View File
@@ -36,19 +36,28 @@ android {
}
task goBuild(type: Exec) {
executable "sh"
args "-c", "src/overture/make.bash " + minSdkVersion
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
executable "cmd.exe"
args "/c", "src/overture/make.bat " + minSdkVersion
} else {
executable "sh"
args "-c", "src/overture/make.bash " + minSdkVersion
}
}
task goClean(type: Exec) {
executable "sh"
args "-c", "src/overture/clean.bash"
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
executable "cmd.exe"
args "/c", "src/overture/clean.bat"
} else {
executable "sh"
args "-c", "src/overture/clean.bash"
}
}
tasks.whenTaskAdded { task ->
if ((task.name == 'generateJsonModelDebug' ||
task.name == 'generateJsonModelRelease') &&
!Os.isFamily(Os.FAMILY_WINDOWS)) {
task.name == 'generateJsonModelRelease')) {
task.dependsOn(goBuild)
}
}
+10
View File
@@ -0,0 +1,10 @@
@ECHO OFF
SET DIR=%CD%
SET DEPS=%DIR%\.deps
RD /SQ %DEPS%
RD /SQ %DIR%\go\bin
RD /SQ %DIR%\bin
ECHO "Successfully clean overture"
+121
View File
@@ -0,0 +1,121 @@
@ECHO OFF
SETLOCAL
IF NOT DEFINED ANDROID_NDK_HOME (
SET ANDROID_NDK_HOME=%ANDROID_HOME%\ndk-bundle
)
SET DIR=%CD%
SET MIN_API=%1%
SET TARGET=%DIR%\bin
SET DEPS=%DIR%\.deps
SET ANDROID_ARM_TOOLCHAIN=%DEPS%\android-toolchain-%MIN_API%-arm
SET ANDROID_ARM64_TOOLCHAIN=%DEPS%\android-toolchain-21-arm64
SET ANDROID_X86_TOOLCHAIN=%DEPS%\android-toolchain-%MIN_API%-x86
SET ANDROID_ARM_CC=%ANDROID_ARM_TOOLCHAIN%\bin\arm-linux-androideabi-clang
SET ANDROID_ARM_STRIP=%ANDROID_ARM_TOOLCHAIN%\bin\arm-linux-androideabi-strip
SET ANDROID_ARM64_CC=%ANDROID_ARM64_TOOLCHAIN%\bin\aarch64-linux-android-clang
SET ANDROID_ARM64_STRIP=%ANDROID_ARM64_TOOLCHAIN%\bin\aarch64-linux-android-strip
SET ANDROID_X86_CC=%ANDROID_X86_TOOLCHAIN%\bin\i686-linux-android-clang
SET ANDROID_X86_STRIP=%ANDROID_X86_TOOLCHAIN%\bin\i686-linux-android-strip
MKDIR %DEPS%>nul 2>nul
MKDIR %TARGET%\armeabi-v7a>nul 2>nul
MKDIR %TARGET%\x86>nul 2>nul
MKDIR %TARGET%\arm64-v8a>nul 2>nul
IF NOT EXIST %ANDROID_ARM_CC% (
ECHO "Make standalone toolchain for ARM arch"
%ANDROID_NDK_HOME%\build\tools\make_standalone_toolchain.py --arch arm ^
--api %MIN_API% --install-dir %ANDROID_ARM_TOOLCHAIN%
)
IF NOT EXIST %ANDROID_ARM64_CC% (
ECHO "Make standalone toolchain for ARM64 arch"
%ANDROID_NDK_HOME%\build\tools\make_standalone_toolchain.py --arch arm64 ^
--api 21 --install-dir %ANDROID_ARM64_TOOLCHAIN%
)
IF NOT EXIST %ANDROID_X86_CC% (
ECHO "Make standalone toolchain for X86 arch"
%ANDROID_NDK_HOME%\build\tools\make_standalone_toolchain.py --arch x86 ^
--api %MIN_API% --install-dir %ANDROID_X86_TOOLCHAIN%
)
IF NOT EXIST %DIR%\go\bin\go (
ECHO "Build the custom go"
PUSHD %DIR%\go\src
CALL make.bat
POPD
)
SET GOROOT=%DIR%\go
SET GOPATH=%DIR%
SET PATH=%GOROOT%\bin;%GOPATH%\bin;%PATH%
SET BUILD=1
IF EXIST "%TARGET%\armeabi-v7a\liboverture.so" (
IF EXIST "%TARGET%\arm64-v8a\liboverture.so" (
IF EXIST "%TARGET%\x86\liboverture.so" (
SET BUILD=0
)
)
)
IF %BUILD% == 1 (
ECHO "Get dependences for overture"
go.exe get -u github.com\tools\godep
PUSHD %GOPATH%\src\github.com\shadowsocks\overture\main
godep.exe restore
ECHO "Cross compile overture for arm"
IF NOT EXIST "%TARGET%\armeabi-v7a\liboverture.so" (
SETLOCAL
SET CGO_ENABLED=1
SET CC=%ANDROID_ARM_CC%
SET GOOS=android
SET GOARCH=arm
SET GOARM=7
go.exe build -ldflags="-s -w"
%ANDROID_ARM_STRIP% main
MOVE main %TARGET%\armeabi-v7a\liboverture.so>nul 2>nul
ENDLOCAL
)
ECHO "Cross compile overture for arm64"
IF NOT EXIST "%TARGET%\arm64-v8a\liboverture.so" (
SETLOCAL
SET CGO_ENABLED=1
SET CC=%ANDROID_ARM64_CC%
SET GOOS=android
SET GOARCH=arm64
go.exe build -ldflags="-s -w"
%ANDROID_ARM64_STRIP% main
MOVE main %TARGET%\arm64-v8a\liboverture.so>nul 2>nul
ENDLOCAL
)
ECHO "Cross compile overture for x86"
IF NOT EXIST "%TARGET%\x86\liboverture.so" (
SETLOCAL
SET CGO_ENABLED=1
SET CC=%ANDROID_X86_CC%
SET GOOS=android
SET GOARCH=386
go.exe build -ldflags="-s -w"
%ANDROID_X86_STRIP% main
MOVE main %TARGET%\x86\liboverture.so>nul 2>nul
ENDLOCAL
)
POPD
)
ECHO "Successfully build overture"
ENDLOCAL
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Fri Dec 01 17:03:17 PST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip
Vendored
+56 -44
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@@ -6,42 +6,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -60,6 +24,46 @@ cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -85,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -150,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+4 -10
View File
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
+3 -3
View File
@@ -20,12 +20,12 @@ android {
applicationId "com.github.shadowsocks"
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.sdkVersion
versionCode 203
versionName "4.4.3"
versionCode 205
versionName "4.4.5"
testApplicationId "com.github.shadowsocks.test"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary true
resConfigs "fa", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
resConfigs "fa", "fr", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
}
buildTypes {
debug {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,3 +1,6 @@
[proxy_all]
[bypass_list]
0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -4,10 +4,13 @@
[proxy_list]
# Telegram IPs$
91.108.4.0/22
91.108.56.0/23
91.108.56.0/22
91.108.4.0/22
149.154.172.0/22
149.154.168.0/22
149.154.164.0/22
109.239.140.0/24
149.154.160.0/20
(^|\.)4tern\.com$
(^|\.)adorama\.com$
(^|\.)akiba-web\.com$
File diff suppressed because it is too large Load Diff
@@ -203,6 +203,16 @@ class App : Application() {
DataStore.publicStore.putLong(Key.assetUpdateTime, info.lastUpdateTime)
}
updateNotificationChannels()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
checkChineseLocale(newConfig)
updateNotificationChannels()
}
private fun updateNotificationChannels() {
if (Build.VERSION.SDK_INT >= 26) @RequiresApi(26) {
val nm = getSystemService(NotificationManager::class.java)
nm.createNotificationChannels(listOf(
@@ -216,11 +226,6 @@ class App : Application() {
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
checkChineseLocale(newConfig)
}
fun listenForPackageChanges(callback: () -> Unit): BroadcastReceiver {
val filter = IntentFilter(Intent.ACTION_PACKAGE_ADDED)
filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
@@ -54,7 +54,7 @@ object LocalDnsService {
is Inet6Address -> "[$address]"
else -> address
}) + ":53")
.put("Timeout", 6)
.put("Timeout", 3)
.put("EDNSClientSubnet", JSONObject().put("Policy", "disable"))
if (edns) dns
.put("Protocol", "tcp")
@@ -70,7 +70,7 @@ object LocalDnsService {
.put("RedirectIPv6Record", true)
.put("DomainBase64Decode", false)
.put("HostsFile", "hosts")
.put("MinimumTTL", 3600)
.put("MinimumTTL", 120)
.put("CacheSize", 4096)
val remoteDns = JSONArray(profile.remoteDns.split(",")
.mapIndexed { i, dns -> makeDns("UserDef-" + i, dns.trim()) })
@@ -45,7 +45,9 @@ class MoveUpwardBehavior : CoordinatorLayout.Behavior<View> {
dependency is Snackbar.SnackbarLayout
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
child.translationY = Math.min(0f, dependency.translationY - dependency.height)
val params = child.layoutParams
params.height = parent.height - dependency.height
child.layoutParams = params
return true
}
@@ -55,22 +57,23 @@ class MoveUpwardBehavior : CoordinatorLayout.Behavior<View> {
override fun onDependentViewRemoved(parent: CoordinatorLayout, child: View, dependency: View) {
if (!isAccessibilityEnabled(parent.getContext())) {
val animator = ValueAnimator()
val start = child.translationY
animator.setFloatValues(start, 0f)
val start = child.height
animator.setIntValues(start, parent.height)
animator.interpolator = SnackbarAnimation.FAST_OUT_SLOW_IN_INTERPOLATOR
animator.duration = SnackbarAnimation.ANIMATION_DURATION
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
private var previousValue = start
override fun onAnimationUpdate(animator: ValueAnimator) {
val currentValue = animator.animatedValue as Float
child.translationY = currentValue
previousValue = currentValue
val currentValue = animator.animatedValue as Int
val params = child.layoutParams
params.height = currentValue
child.layoutParams = params
}
})
animator.start()
} else {
child.translationY = 0f
val params = child.layoutParams
params.height = parent.height
child.layoutParams = params
}
}
}
+116 -110
View File
@@ -9,133 +9,139 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fragment_holder"
android:background="?android:attr/windowBackground"
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/stat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/background_stat"
android:elevation="4dp"
android:focusable="true"
android:nextFocusRight="@+id/fab"
android:orientation="vertical"
android:paddingBottom="16dip"
android:paddingEnd="16dip"
android:paddingStart="16dip"
android:paddingTop="16dip"
android:layout_gravity="bottom"
android:layout_height="match_parent"
app:layout_behavior="com.github.shadowsocks.widget.MoveUpwardBehavior">
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:paddingEnd="72dip"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
tools:ignore="RtlSymmetry"/>
<FrameLayout
android:id="@+id/fragment_holder"
android:background="?android:attr/windowBackground"
android:layout_above="@+id/stat"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.github.shadowsocks.widget.BoundedGridLayout
<LinearLayout
android:id="@+id/stat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bounded_width="288dp"
app:columnCount="4">
<TextView
style="@style/TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:ellipsize="marquee"
android:gravity="end"
android:text="@string/sent"
app:layout_column="0"/>
<TextView
android:id="@+id/tx"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="1"
app:layout_columnWeight="1"/>
android:background="@drawable/background_stat"
android:elevation="4dp"
android:focusable="true"
android:nextFocusRight="@+id/fab"
android:orientation="vertical"
android:paddingBottom="16dip"
android:paddingEnd="16dip"
android:paddingStart="16dip"
android:paddingTop="16dip"
android:layout_alignParentBottom="true">
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:text="▲"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="2"/>
android:paddingEnd="72dip"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
tools:ignore="RtlSymmetry"/>
<TextView
android:id="@+id/txRate"
android:layout_width="0dp"
<com.github.shadowsocks.widget.BoundedGridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:gravity="end"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="3"
app:layout_columnWeight="1"/>
app:bounded_width="288dp"
app:columnCount="4">
<TextView
style="@style/TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:ellipsize="marquee"
android:gravity="end"
android:text="@string/received"
app:layout_column="0"
app:layout_row="1"/>
<TextView
style="@style/TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:ellipsize="marquee"
android:gravity="end"
android:text="@string/sent"
app:layout_column="0"/>
<TextView
android:id="@+id/rx"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="1"
app:layout_columnWeight="1"
app:layout_row="1"/>
<TextView
android:id="@+id/tx"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="1"
app:layout_columnWeight="1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:text="▼"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="2"
app:layout_row="1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:text="▲"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="2"/>
<TextView
android:id="@+id/rxRate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:gravity="end"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="3"
app:layout_columnWeight="1"
app:layout_row="1"/>
</com.github.shadowsocks.widget.BoundedGridLayout>
</LinearLayout>
<TextView
android:id="@+id/txRate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:gravity="end"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="3"
app:layout_columnWeight="1"/>
<TextView
style="@style/TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:ellipsize="marquee"
android:gravity="end"
android:text="@string/received"
app:layout_column="0"
app:layout_row="1"/>
<TextView
android:id="@+id/rx"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="1"
app:layout_columnWeight="1"
app:layout_row="1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:text="▼"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="2"
app:layout_row="1"/>
<TextView
android:id="@+id/rxRate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:ellipsize="marquee"
android:gravity="end"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
app:layout_column="3"
app:layout_columnWeight="1"
app:layout_row="1"/>
</com.github.shadowsocks.widget.BoundedGridLayout>
</LinearLayout>
</RelativeLayout>
<!-- workaround for 0 elevation in disabled state -->
<FrameLayout
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>
@@ -138,6 +138,7 @@
<string name="acl_rule_templates_generic">"URL/子网/域名 PCRE 正则表达式"</string>
<string name="acl_rule_templates_domain">"域名及其子域名"</string>
<string name="acl_rule_online_config">配置文件地址</string>
<!-- plugin -->
<string name="plugin">"插件"</string>
@@ -133,6 +133,7 @@
<string name="acl_rule_templates_generic">"URL/子網路/主機名稱 PCRE 模式"</string>
<string name="acl_rule_templates_domain">"網域及其所有子網域"</string>
<string name="acl_rule_online_config">配置文件地址</string>
<!-- plugin -->
<string name="plugin">"外掛程式"</string>
+1 -1
View File
@@ -224,7 +224,7 @@
<string-array name="acl_rule_templates" translatable="false">
<item>@string/acl_rule_templates_generic</item>
<item>@string/acl_rule_templates_domain</item>
<item>URL</item>
<item>@string/acl_rule_online_config</item>
</string-array>
<string-array name="service_modes">
+2 -1
View File
@@ -17,7 +17,7 @@
<string name="port_transproxy">Transproxy port</string>
<string name="remote_dns">Remote DNS</string>
<string name="traffic" translatable="false">%s↑\t%s↓</string>
<string name="traffic">%s↑\t%s↓</string>
<string name="stat_summary">Sent: \t\t\t\t\t%3$s\t↑\t%1$s\nReceived: \t%4$s\t↓\t%2$s</string>
<string name="speed">%s/s</string>
<plurals name="bytes">
@@ -139,6 +139,7 @@
<string name="action_add_rule">Add rule(s)…</string>
<string name="acl_rule_templates_generic">Subnet or Hostname PCRE pattern</string>
<string name="acl_rule_templates_domain">Domain name and all its subdomain names</string>
<string name="acl_rule_online_config">URL to online config</string>
<string name="edit_rule">Edit rule</string>
<!-- plugin -->
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>