Compare commits

...
22 Commits
Author SHA1 Message Date
Max Lv d9fa4481a2 Bump version 2018-01-22 19:12:23 -08:00
Max Lv e2c29594f2 Set different timeouts 2018-01-22 19:04:00 -08:00
Max Lv 2ef042d56b Merge pull request #1593 from chon219/fix-windows-script
fixed windows build script for overture
2018-01-22 12:58:36 +08:00
Zichuan Ma 0fa97f064f fixed windows build script for overture 2018-01-21 18:57:20 +08:00
Max Lv d7ecc34836 Merge pull request #1491 from Mygod/split-abi
Split ABIs for smaller apk size
2018-01-19 15:38:44 +08:00
Mygod 168c0588a6 Fix debug builds 2018-01-18 23:10:12 -08:00
Mygod 4f5ee68f40 Add universalApk 2018-01-18 22:58:26 -08:00
Mygod 0c3352935a Merge branch 'master' into split-abi 2018-01-18 22:34:22 -08:00
Mygod 0d02a39b61 Update Application.mk
Update min api.
2018-01-18 21:54:01 -08:00
Mygod 090cc35bff Fix links in build-shared-executable 2018-01-18 20:58:15 -08:00
Max Lv 042ee55421 Merge pull request #1585 from Mygod/min21
Min API 19 -> 21
2018-01-19 12:33:15 +08:00
Mygod ac96e6fc9c Min API 19 -> 21
Fix #1579.
2018-01-18 19:57:30 -08:00
Mygod c6ff9b3d89 Add license badge 2018-01-18 11:51:10 -08:00
Mygod 77af5f6e3c Refine #1579 2018-01-18 11:46:53 -08:00
Reker 95db29bd13 Fix Windows build script of overture (#1582)
make.bat not detect Windows go binary due to missing '.exe' of filename
when the script convert from bash to bat
2018-01-18 16:12:40 +08:00
Max Lv 7297a2664c Avoid problematic local DNS resolver 2018-01-16 23:17:00 -08:00
Mygod 195e2afbeb Fix keyboard navigations 2018-01-15 22:24:08 -08:00
Mygod 3dbc5f4147 Import translations from POEditor 2018-01-15 21:32:56 -08:00
Mygod 580ce14809 Refine animations 2018-01-15 21:01:29 -08:00
Mygod d4213e8ee8 Remove checkChineseLocale
This was introduced by commit 396d31a0a7. I just did some further testing and:

* zh_rCN and zh_rTW are the only zh locales you can pick before Android 7;
* Since Android 7, user can use locale list to specify their fallback preferences and there's no need to enforce it.

Therefore this method isn't really necessary and will be thus removed.
2018-01-15 19:58:16 -08:00
Mygod cd1f94f4a0 Change version code 2017-12-14 12:26:32 -08:00
Mygod 6dace959d2 Split ABIs for smaller apk size 2017-12-06 23:58:11 -08:00
58 changed files with 206 additions and 464 deletions
+3
View File
@@ -24,3 +24,6 @@ core/src/overture/src/gopkg.in
# work in progress
tv/
things/
# release apks
*.apk
+2
View File
@@ -1,7 +1,9 @@
## Shadowsocks for Android
[![Build Status](https://api.travis-ci.org/shadowsocks/shadowsocks-android.svg)](https://travis-ci.org/shadowsocks/shadowsocks-android)
[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21)
[![Releases](https://img.shields.io/github/downloads/shadowsocks/shadowsocks-android/total.svg)](https://github.com/shadowsocks/shadowsocks-android/releases)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
A [shadowsocks](http://shadowsocks.org) client for Android, written in Kotlin.
<a href="https://play.google.com/store/apps/details?id=com.github.shadowsocks"><img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" height="48"></a>
+2 -2
View File
@@ -2,8 +2,8 @@
buildscript {
ext {
kotlinVersion = '1.2.10'
minSdkVersion = 19
kotlinVersion = '1.2.20'
minSdkVersion = 21
sdkVersion = 27
buildToolsVersion = '27.0.3'
supportLibraryVersion = '27.0.2'
+2 -2
View File
@@ -38,7 +38,7 @@ android {
task goBuild(type: Exec) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
executable "cmd.exe"
args "/c", "src/overture/make.bat " + minSdkVersion
args "/c", "src\\overture\\make.bat " + minSdkVersion
} else {
executable "sh"
args "-c", "src/overture/make.bash " + minSdkVersion
@@ -48,7 +48,7 @@ task goBuild(type: Exec) {
task goClean(type: Exec) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
executable "cmd.exe"
args "/c", "src/overture/clean.bat"
args "/c", "src\\overture\\clean.bat"
} else {
executable "sh"
args "-c", "src/overture/clean.bash"
@@ -43,8 +43,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.system.ErrnoException;
import java.net.InetAddress;
public class JniHelper {
static {
System.loadLibrary("jni-helper");
@@ -54,8 +52,7 @@ public class JniHelper {
public static void sigtermCompat(@NonNull Process process) throws Exception {
if (Build.VERSION.SDK_INT >= 24) throw new UnsupportedOperationException("Never call this method in OpenJDK!");
int errno = sigterm(process);
if (errno != 0) throw Build.VERSION.SDK_INT >= 21
? new ErrnoException("kill", errno) : new Exception("kill failed: " + errno);
if (errno != 0) throw new ErrnoException("kill", errno);
}
@Deprecated // only implemented for before API 24
+1 -1
View File
@@ -1,4 +1,4 @@
APP_ABI := armeabi-v7a arm64-v8a x86
APP_PLATFORM := android-19
APP_PLATFORM := android-21
APP_STL := c++_static
NDK_TOOLCHAIN_VERSION := clang
+2 -2
View File
@@ -16,8 +16,8 @@
# executable program
#
# Modified by @Mygod, based on:
# https://android.googlesource.com/platform/ndk/+/f2e98f8c066aed59caf61163d4b87c2b858f9814/build/core/build-shared-library.mk
# https://android.googlesource.com/platform/ndk/+/f2e98f8c066aed59caf61163d4b87c2b858f9814/build/core/build-executable.mk
# https://android.googlesource.com/platform/ndk/+/a355a4e/build/core/build-shared-library.mk
# https://android.googlesource.com/platform/ndk/+/a355a4e/build/core/build-executable.mk
LOCAL_BUILD_SCRIPT := BUILD_EXECUTABLE
LOCAL_MAKEFILE := $(local-makefile)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
+4 -4
View File
@@ -1,10 +1,10 @@
@ECHO OFF
SET DIR=%CD%
SET DIR=%~dp0
SET DEPS=%DIR%\.deps
RD /SQ %DEPS%
RD /SQ %DIR%\go\bin
RD /SQ %DIR%\bin
RD /S /Q %DEPS%
RD /S /Q %DIR%\go\bin
RD /S /Q %DIR%\bin
ECHO "Successfully clean overture"
+2 -2
View File
@@ -12,7 +12,7 @@ TARGET=$DIR/bin
DEPS=$DIR/.deps
ANDROID_ARM_TOOLCHAIN=$DEPS/android-toolchain-${MIN_API}-arm
ANDROID_ARM64_TOOLCHAIN=$DEPS/android-toolchain-21-arm64
ANDROID_ARM64_TOOLCHAIN=$DEPS/android-toolchain-${MIN_API}-arm64
ANDROID_X86_TOOLCHAIN=$DEPS/android-toolchain-${MIN_API}-x86
ANDROID_ARM_CC=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-clang
@@ -35,7 +35,7 @@ fi
if [ ! -f "$ANDROID_ARM64_CC" ]; then
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
--api $MIN_API --install-dir $ANDROID_ARM64_TOOLCHAIN
fi
if [ ! -f "$ANDROID_X86_CC" ]; then
+4 -4
View File
@@ -5,13 +5,13 @@ IF NOT DEFINED ANDROID_NDK_HOME (
SET ANDROID_NDK_HOME=%ANDROID_HOME%\ndk-bundle
)
SET DIR=%CD%
SET DIR=%~dp0
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_ARM64_TOOLCHAIN=%DEPS%\android-toolchain-%MIN_API%-arm64
SET ANDROID_X86_TOOLCHAIN=%DEPS%\android-toolchain-%MIN_API%-x86
SET ANDROID_ARM_CC=%ANDROID_ARM_TOOLCHAIN%\bin\arm-linux-androideabi-clang
@@ -37,7 +37,7 @@ IF NOT EXIST %ANDROID_ARM_CC% (
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%
--api %MIN_API% --install-dir %ANDROID_ARM64_TOOLCHAIN%
)
IF NOT EXIST %ANDROID_X86_CC% (
@@ -46,7 +46,7 @@ IF NOT EXIST %ANDROID_X86_CC% (
--api %MIN_API% --install-dir %ANDROID_X86_TOOLCHAIN%
)
IF NOT EXIST %DIR%\go\bin\go (
IF NOT EXIST %DIR%\go\bin\go.exe (
ECHO "Build the custom go"
PUSHD %DIR%\go\src
+21 -8
View File
@@ -1,3 +1,4 @@
import com.android.build.OutputFile
import java.util.regex.Matcher
import java.util.regex.Pattern
@@ -20,11 +21,10 @@ android {
applicationId "com.github.shadowsocks"
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.sdkVersion
versionCode 205
versionName "4.4.5"
versionCode 211
versionName "4.4.6"
testApplicationId "com.github.shadowsocks.test"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary true
resConfigs "fa", "fr", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
}
buildTypes {
@@ -37,6 +37,15 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions.checkReleaseBuilds false
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86'
universalApk true
}
}
sourceSets.main.jniLibs.srcDirs +=
new File(project(':core').buildDir, "intermediates/bundles/${getCurrentFlavor()}/jni")
sourceSets.main.jniLibs.srcDirs += new File(project(':core').projectDir, "src/overture/bin")
@@ -48,17 +57,13 @@ dependencies {
implementation "com.android.support:design:$supportLibraryVersion"
implementation "com.android.support:gridlayout-v7:$supportLibraryVersion"
implementation 'com.futuremind.recyclerfastscroll:fastscroll:0.2.5'
implementation 'com.evernote:android-job:1.2.1'
implementation 'com.evernote:android-job:1.2.2'
implementation "com.google.android.gms:play-services-ads:$playServicesVersion"
implementation "com.google.android.gms:play-services-analytics:$playServicesVersion"
implementation "com.google.android.gms:play-services-gcm:$playServicesVersion"
implementation "com.google.firebase:firebase-config:$playServicesVersion"
implementation 'com.j256.ormlite:ormlite-android:5.0'
implementation 'com.mikepenz:crossfader:1.5.1'
implementation 'com.mikepenz:fastadapter:3.0.4'
implementation 'com.mikepenz:iconics-core:3.0.0'
implementation 'com.mikepenz:materialdrawer:6.0.2'
implementation 'com.mikepenz:materialize:1.1.2'
implementation 'com.squareup.okhttp3:okhttp:3.9.1'
implementation "com.takisoft.fix:preference-v7-simplemenu:$takisoftFixVersion"
implementation 'com.twofortyfouram:android-plugin-api-for-locale:1.0.2'
@@ -76,3 +81,11 @@ repositories {
}
apply plugin: 'com.google.gms.google-services'
ext.abiCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, x86: 3]
if (getCurrentFlavor() == 'release') android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def offset = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
if (offset != null) output.versionCodeOverride = variant.versionCode + offset
}
}
+3 -1
View File
@@ -171,9 +171,11 @@
<service android:name="com.evernote.android.job.v14.PlatformAlarmService"
android:process=":bg"
android:directBootAware="true"/>
<service android:name="com.evernote.android.job.gcm.PlatformGcmService"
<service android:name="com.evernote.android.job.v14.PlatformAlarmServiceExact"
android:process=":bg"
android:directBootAware="true"/>
<service android:name="com.evernote.android.job.gcm.PlatformGcmService"
tools:node="remove"/>
<service android:name="com.evernote.android.job.JobRescheduleService"
android:process=":bg"
android:directBootAware="true"/>
@@ -32,7 +32,6 @@ import android.content.pm.PackageManager
import android.content.res.Configuration
import android.os.Build
import android.os.Handler
import android.os.LocaleList
import android.os.Looper
import android.support.annotation.RequiresApi
import android.support.v4.os.UserManagerCompat
@@ -59,20 +58,11 @@ import com.j256.ormlite.logger.LocalLog
import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat
import java.io.File
import java.io.IOException
import java.util.*
class App : Application() {
companion object {
lateinit var app: App
private const val TAG = "ShadowsocksApplication"
// The ones in Locale doesn't have script included
private val SIMPLIFIED_CHINESE by lazy {
if (Build.VERSION.SDK_INT >= 21) Locale.forLanguageTag("zh-Hans-CN") else Locale.SIMPLIFIED_CHINESE
}
private val TRADITIONAL_CHINESE by lazy {
if (Build.VERSION.SDK_INT >= 21) Locale.forLanguageTag("zh-Hant-TW") else Locale.TRADITIONAL_CHINESE
}
}
val handler by lazy { Handler(Looper.getMainLooper()) }
@@ -112,59 +102,11 @@ class App : Application() {
t.printStackTrace()
}
private fun checkChineseLocale(config: Configuration) {
fun check(locale: Locale): Locale? {
if (locale.language != "zh") return null
when (locale.country) { "CN", "TW" -> return null }
if (Build.VERSION.SDK_INT >= 21) when (locale.script) {
"Hans" -> return SIMPLIFIED_CHINESE
"Hant" -> return TRADITIONAL_CHINESE
else -> Log.w(TAG, "Unknown zh locale script: ${locale.script}. Falling back to trying countries...")
}
when (locale.country) {
"SG" -> return SIMPLIFIED_CHINESE
"HK", "MO" -> return TRADITIONAL_CHINESE
}
Log.w(TAG, "Unknown zh locale: %s. Falling back to zh-Hans-CN..."
.format(Locale.ENGLISH, if (Build.VERSION.SDK_INT >= 21) locale.toLanguageTag() else locale))
return SIMPLIFIED_CHINESE
}
if (Build.VERSION.SDK_INT >= 24) @RequiresApi(24) {
val localeList = config.locales
var changed = false
val newList = Array<Locale>(localeList.size(), { i ->
val locale = localeList[i]
val newLocale = check(locale)
if (newLocale == null) locale else {
changed = true
newLocale
}
})
if (changed) {
val newConfig = Configuration(config)
newConfig.locales = LocaleList(*(newList.distinct().toTypedArray()))
val res = resources
res.updateConfiguration(newConfig, res.displayMetrics)
}
} else {
@Suppress("DEPRECATION")
val newLocale = check(config.locale)
if (newLocale != null) {
val newConfig = Configuration(config)
@Suppress("DEPRECATION")
newConfig.locale = newLocale
val res = resources
res.updateConfiguration(newConfig, res.displayMetrics)
}
}
}
override fun onCreate() {
super.onCreate()
app = this
if (!BuildConfig.DEBUG) System.setProperty(LocalLog.LOCAL_LOG_LEVEL_PROPERTY, "ERROR")
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
checkChineseLocale(resources.configuration)
PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java,
BottomSheetPreferenceDialogFragment::class.java)
@@ -208,7 +150,6 @@ class App : Application() {
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
checkChineseLocale(newConfig)
updateNotificationChannels()
}
@@ -80,13 +80,11 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
val serviceMode = DataStore.serviceMode
findPreference(Key.remoteDns).isEnabled = serviceMode != Key.modeProxy
isProxyApps = findPreference(Key.proxyApps) as SwitchPreference
if (Build.VERSION.SDK_INT < 21) isProxyApps.parent!!.removePreference(isProxyApps) else {
isProxyApps.isEnabled = serviceMode == Key.modeVpn
isProxyApps.setOnPreferenceClickListener {
startActivity(Intent(activity, AppManager::class.java))
isProxyApps.isChecked = true
false
}
isProxyApps.isEnabled = serviceMode == Key.modeVpn
isProxyApps.setOnPreferenceClickListener {
startActivity(Intent(activity, AppManager::class.java))
isProxyApps.isChecked = true
false
}
findPreference(Key.udpdns).isEnabled = serviceMode != Key.modeProxy
plugin = findPreference(Key.plugin) as IconListPreference
@@ -20,49 +20,19 @@
package com.github.shadowsocks.bg
import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.os.Build
import android.util.Log
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.BuildConfig
import okhttp3.Dns as Okdns
import org.xbill.DNS.*
import java.net.Inet6Address
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.UnknownHostException
import java.util.*
import okhttp3.Dns as Okdns
object Dns {
private const val TAG = "Dns"
@Throws(Exception::class)
fun getDnsResolver(context: Context): String {
val dnsResolvers = getDnsResolvers(context)
if (dnsResolvers.isEmpty()) throw Exception("Couldn't find an active DNS resolver")
val dnsResolver = dnsResolvers.iterator().next().toString()
if (dnsResolver.startsWith("/")) return dnsResolver.substring(1)
return dnsResolver
}
@Throws(Exception::class)
private fun getDnsResolvers(context: Context): Collection<InetAddress> {
val addresses = ArrayList<InetAddress>()
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val classLinkProperties = Class.forName("android.net.LinkProperties")
val getActiveLinkPropertiesMethod = ConnectivityManager::class.java.getMethod("getActiveLinkProperties")
val linkProperties = getActiveLinkPropertiesMethod.invoke(connectivityManager)
if (linkProperties != null) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
val dnses = classLinkProperties.getMethod("getDnses").invoke(linkProperties) as Collection<*>
dnses.mapTo(addresses) { it as InetAddress }
} else addresses.addAll((linkProperties as LinkProperties).dnsServers)
}
return addresses
}
private val hasIPv6Support get() = try {
val result = NetworkInterface.getNetworkInterfaces().asSequence().flatMap { it.inetAddresses.asSequence() }
.count { it is Inet6Address && !it.isLoopbackAddress && !it.isLinkLocalAddress } > 0
@@ -47,14 +47,14 @@ object LocalDnsService {
val data = data
val profile = data.profile!!
fun makeDns(name: String, address: String, edns: Boolean = true): JSONObject {
fun makeDns(name: String, address: String, timeout: Int, edns: Boolean = true): JSONObject {
val dns = JSONObject()
.put("Name", name)
.put("Address", (when (address.parseNumericAddress()) {
is Inet6Address -> "[$address]"
else -> address
}) + ":53")
.put("Timeout", 3)
.put("Timeout", timeout)
.put("EDNSClientSubnet", JSONObject().put("Policy", "disable"))
if (edns) dns
.put("Protocol", "tcp")
@@ -73,18 +73,12 @@ object LocalDnsService {
.put("MinimumTTL", 120)
.put("CacheSize", 4096)
val remoteDns = JSONArray(profile.remoteDns.split(",")
.mapIndexed { i, dns -> makeDns("UserDef-" + i, dns.trim()) })
.mapIndexed { i, dns -> makeDns("UserDef-" + i, dns.trim(), 9) })
val localDns = JSONArray(arrayOf(
makeDns("Primary-1", "119.29.29.29", false),
makeDns("Primary-2", "114.114.114.114", false)
makeDns("Primary-1", "119.29.29.29", 3, false),
makeDns("Primary-2", "114.114.114.114", 3, false)
))
this as Context
try {
val localLinkDns = Dns.getDnsResolver(this)
localDns.put(makeDns("Primary-3", localLinkDns, false))
} catch (_: Exception) { } // ignore
when (profile.route) {
Acl.BYPASS_CHN, Acl.BYPASS_LAN_CHN, Acl.GFWLIST, Acl.CUSTOM_RULES -> config
.put("PrimaryDNS", localDns)
@@ -40,8 +40,7 @@ import java.util.*
/**
* Android < 8 VPN: always invisible because of VPN notification/icon
* Android 4.x other: always visible
* Android 5-7 other: only invisible in (possibly unsecure) lockscreen
* Android < 8 other: only invisible in (possibly unsecure) lockscreen
* Android 8+: always visible due to system limitations
* (user can choose to hide the notification in secure lockscreen or anywhere)
*/
@@ -85,24 +84,22 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam
if (Build.VERSION.SDK_INT < 24) builder.addAction(R.drawable.ic_navigation_close,
service.getString(R.string.stop), PendingIntent.getBroadcast(service, 0, Intent(Action.CLOSE), 0))
val power = service.getSystemService(Context.POWER_SERVICE) as PowerManager
update(if (if (Build.VERSION.SDK_INT >= 20) power.isInteractive else @Suppress("DEPRECATION") power.isScreenOn)
Intent.ACTION_SCREEN_ON else Intent.ACTION_SCREEN_OFF, true)
update(if (power.isInteractive) Intent.ACTION_SCREEN_ON else Intent.ACTION_SCREEN_OFF, true)
val screenFilter = IntentFilter()
screenFilter.addAction(Intent.ACTION_SCREEN_ON)
screenFilter.addAction(Intent.ACTION_SCREEN_OFF)
if (visible && Build.VERSION.SDK_INT in 21 until 26) screenFilter.addAction(Intent.ACTION_USER_PRESENT)
if (visible && Build.VERSION.SDK_INT < 26) screenFilter.addAction(Intent.ACTION_USER_PRESENT)
service.registerReceiver(lockReceiver, screenFilter)
}
private fun update(action: String, forceShow: Boolean = false) {
if (forceShow || service.data.state == BaseService.CONNECTED) when (action) {
Intent.ACTION_SCREEN_OFF -> {
setVisible(visible && Build.VERSION.SDK_INT < 21, forceShow)
setVisible(false, forceShow)
unregisterCallback() // unregister callback to save battery
}
Intent.ACTION_SCREEN_ON -> {
setVisible(visible && (Build.VERSION.SDK_INT < 21 || !keyGuard.inKeyguardRestrictedInputMode()),
forceShow)
setVisible(visible && !keyGuard.inKeyguardRestrictedInputMode(), forceShow)
service.data.binder.registerCallback(callback)
service.data.binder.startListeningForBandwidth(callback)
callbackRegistered = true
@@ -24,7 +24,6 @@ import android.app.Service
import android.content.Intent
import android.content.pm.PackageManager
import android.net.LocalSocket
import android.os.Build
import android.os.IBinder
import android.os.ParcelFileDescriptor
import android.util.Log
@@ -140,7 +139,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
builder.addRoute("::", 0)
}
if (Build.VERSION.SDK_INT >= 21 && profile.proxyApps) {
if (profile.proxyApps) {
val me = packageName
profile.individual.split('\n')
.filter { it != me }
@@ -29,6 +29,7 @@ import android.os.Bundle
import android.provider.Settings
import android.support.design.widget.BottomSheetDialog
import android.support.v7.preference.PreferenceDialogFragmentCompat
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
@@ -107,10 +108,12 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
recycler.setPadding(0, padding, 0, padding)
recycler.setHasFixedSize(true)
recycler.layoutManager = LinearLayoutManager(activity)
recycler.itemAnimator = DefaultItemAnimator()
recycler.adapter = IconListAdapter(dialog)
recycler.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
dialog.setContentView(recycler)
dialog.findViewById<View>(R.id.touch_outside)!!.isFocusable = false
return dialog
}
@@ -22,7 +22,6 @@ package com.github.shadowsocks.tasker
import android.app.Activity
import android.content.res.Resources
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.DefaultItemAnimator
@@ -71,13 +70,12 @@ class ConfigActivity : AppCompatActivity() {
inner class ProfilesAdapter : RecyclerView.Adapter<ProfileViewHolder>() {
internal val profiles = ProfileManager.getAllProfiles()?.toMutableList() ?: mutableListOf()
private val name = "select_dialog_singlechoice_" + (if (Build.VERSION.SDK_INT >= 21) "material" else "holo")
override fun onBindViewHolder(holder: ProfileViewHolder, position: Int) =
if (position == 0) holder.bindDefault() else holder.bind(profiles[position - 1])
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProfileViewHolder = ProfileViewHolder(
LayoutInflater.from(parent.context).inflate(Resources.getSystem()
.getIdentifier(name, "layout", "android"), parent, false))
.getIdentifier("select_dialog_singlechoice_material", "layout", "android"), parent, false))
override fun getItemCount(): Int = 1 + profiles.size
}
@@ -9,7 +9,6 @@ import android.support.annotation.AttrRes
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v7.util.SortedList
import android.view.accessibility.AccessibilityManager
import android.util.TypedValue
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.JniHelper
@@ -22,11 +21,6 @@ private val fieldChildFragmentManager by lazy {
field
}
fun isAccessibilityEnabled(context: Context): Boolean {
val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
return am.isEnabled()
}
fun String.isNumericAddress() = JniHelper.parseNumericAddress(this) != null
fun String.parseNumericAddress(): InetAddress? {
val addr = JniHelper.parseNumericAddress(this)
@@ -1,40 +0,0 @@
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package com.github.shadowsocks.widget
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.util.AttributeSet
import android.view.View
import com.github.shadowsocks.R
class BottomMarginBehavior : CoordinatorLayout.Behavior<View> {
constructor() : super()
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean =
dependency.id == R.id.stat // sorry I'm too lazy to write an attribute
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
(child.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = (parent.height - dependency.y).toInt()
return true
}
}
@@ -20,34 +20,27 @@
package com.github.shadowsocks.widget
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.os.Build
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.SnackbarAnimation
import android.support.design.widget.Snackbar
import android.support.v4.view.ViewCompat
import android.support.design.widget.SnackbarAnimation
import android.util.AttributeSet
import android.view.View
import com.github.shadowsocks.utils.isAccessibilityEnabled
import android.view.accessibility.AccessibilityManager
/**
* Full credits go to: https://stackoverflow.com/a/35904421/2245107
*/
class MoveUpwardBehavior : CoordinatorLayout.Behavior<View> {
constructor() : super()
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
class ShrinkUpwardBehavior(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<View>(context, attrs) {
private val accessibility = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean =
dependency is Snackbar.SnackbarLayout
dependency is Snackbar.SnackbarLayout
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
val params = child.layoutParams
params.height = parent.height - dependency.height
child.layoutParams = params
child.layoutParams.height = dependency.y.toInt()
child.requestLayout()
return true
}
@@ -55,25 +48,18 @@ class MoveUpwardBehavior : CoordinatorLayout.Behavior<View> {
* Based on BaseTransientBottomBar.animateViewOut (support lib 27.0.2).
*/
override fun onDependentViewRemoved(parent: CoordinatorLayout, child: View, dependency: View) {
if (!isAccessibilityEnabled(parent.getContext())) {
if (accessibility.isEnabled) child.layoutParams.height = parent.height else {
val animator = ValueAnimator()
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 {
override fun onAnimationUpdate(animator: ValueAnimator) {
val currentValue = animator.animatedValue as Int
val params = child.layoutParams
params.height = currentValue
child.layoutParams = params
}
})
@Suppress("NAME_SHADOWING")
animator.addUpdateListener { animator ->
child.layoutParams.height = animator.animatedValue as Int
child.requestLayout()
}
animator.start()
} else {
val params = child.layoutParams
params.height = parent.height
child.layoutParams = params
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 B

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/material_primary_300" />
</shape>
</item>
<item>
<selector android:enterFadeDuration="@android:integer/config_mediumAnimTime"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/material_green_700" />
</shape>
</item>
</selector>
</item>
<!-- android:start not available until API 23 -->
<item android:left="8dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
</shape>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
</layer-list>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:colorControlHighlight">
<item>
<selector android:enterFadeDuration="@android:integer/config_mediumAnimTime"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_selected="true">
<color android:color="@color/material_primary_100"/>
</item>
</selector>
</item>
</ripple>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:colorControlHighlight">
<item>
<color android:color="@color/material_primary_300"/>
</item>
</ripple>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

@@ -15,18 +15,11 @@
</item>
</selector>
</item>
<item android:left="@dimen/profile_padding">
<!-- android:start not available until API 23 -->
<item android:left="8dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
</shape>
</item>
<item>
<selector>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#12000000" />
</shape>
</item>
</selector>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
</layer-list>
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:enterFadeDuration="@android:integer/config_mediumAnimTime"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_selected="true">
<color android:color="@color/material_primary_100"/>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector android:enterFadeDuration="@android:integer/config_mediumAnimTime"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_selected="true">
<color android:color="@color/material_primary_100"/>
</item>
</selector>
</item>
</selector>
<item android:drawable="?android:attr/selectableItemBackground"/>
</layer-list>
@@ -1,17 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/material_primary_300" />
</shape>
</item>
<item>
<selector>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#12000000" />
</shape>
</item>
</selector>
<color android:color="@color/material_primary_300"/>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
</layer-list>
+2 -2
View File
@@ -12,7 +12,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.github.shadowsocks.widget.MoveUpwardBehavior">
app:layout_behavior="com.github.shadowsocks.widget.ShrinkUpwardBehavior">
<FrameLayout
android:id="@+id/fragment_holder"
@@ -148,7 +148,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="@dimen/fab_margin_top"
android:layout_marginTop="-28dp"
android:elevation="6dp"
app:layout_anchor="@id/stat"
app:layout_anchorGravity="top|end">
+3 -5
View File
@@ -4,7 +4,7 @@
<!-- misc -->
<string name="profile">"پروفایل"</string>
<string name="connection_test_testing">"در حال آزمایش..."</string>
<string name="connection_test_testing">"در حال آزمایش…"</string>
<!-- proxy category -->
<string name="profile_name">"نام پروفایل"</string>
@@ -20,7 +20,7 @@
<string name="invalid_server">"آدرس سرور نامعتبر است"</string>
<string name="service_failed">"اتصال به سرور ناموفق بود!"</string>
<string name="stop">"غیرفعال‌کردن"</string>
<string name="stopping">"در حال قطع‌کردن اتصال..."</string>
<string name="stopping">"در حال قطع‌کردن اتصال…"</string>
<string name="profile_invalid_input">"هیچ پروفایل معتبری یافت نشد!"</string>
<!-- alert category -->
@@ -33,7 +33,6 @@
<string name="profiles">"پروفایل‌ها"</string>
<string name="settings">"تنظیمات"</string>
<string name="faq">"سوالات مداول"</string>
<string name="recovery">"ریست"</string>
<string name="about">"درباره ما"</string>
<string name="edit">"ویرایش"</string>
<string name="share">"به اشتراک گذاری"</string>
@@ -52,9 +51,8 @@
<!-- status -->
<string name="sent">"فرستاده‌شده:"</string>
<string name="received">"دریافت‌شده:"</string>
<string name="connecting">"در حال اتصال..."</string>
<string name="connecting">"در حال اتصال…"</string>
<string name="vpn_connected">"وصل شد. برای بررسی اتصال ضربه (Tap) بزنید."</string>
<string name="nat_connected">"اتصال برقرار است."</string>
<string name="not_connected">"اتصال برقرار نیست!"</string>
<string name="route_entry_all">"همه"</string>
</resources>
+32
View File
@@ -1,3 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- misc -->
<string name="profile">"Profil"</string>
<string name="connection_test_error">"Impossible de détecter la connexion Internet :%s"</string>
<string name="connection_test_fail">"Internet Indisponible"</string>
<string name="connection_test_error_status_code">"Code de l'Erreur : #%d"</string>
<string name="proxy">"Serveur"</string>
<string name="sitekey">"Mot de passe"</string>
<string name="service_failed">"Échec de la connexion au serveur distant"</string>
<!-- alert category -->
<string name="close">"Fermer"</string>
<string name="profile_empty">"Veuillez sélectionner un profil"</string>
<!-- menu category -->
<string name="profiles">"Profils"</string>
<string name="settings">"Paramètres"</string>
<string name="about">"À propos"</string>
<string name="share">"Partager"</string>
<string name="add_profile">"Ajouter un Profil"</string>
<string name="action_apply_all">"Appliquer les Paramètres à tous les Profils"</string>
<string name="action_export">"Exporter vers le presse-papiers"</string>
<string name="action_import">"Importer depuis le presse-papiers"</string>
<string name="delete">"Supprimer"</string>
<string name="delete_confirm_prompt">"Êtes-vous sûr de vouloir supprimer ce profil?"</string>
<string name="share_qr_nfc">"QR Code/NFC"</string>
<string name="add_profile_methods_scan_qr_code">"Scanner le QR Code"</string>
<plurals name="removed">
<item quantity="one">"Supprimé"</item>
<item quantity="other">"%d éléments supprimés"</item>
</plurals>
<string name="undo">"Annuler"</string>
</resources>
+7 -14
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">"Shadowsocks"</string>
<string name="quick_toggle">"ON/OFF"</string>
<!-- misc -->
@@ -9,7 +8,6 @@
<string name="remote_dns">"リモートDNS"</string>
<string name="stat_summary">"送信済み: \t%3$s\t↑\t%1$s/s
受信済み: \t%4$s\t↓\t%2$s/s"</string>
<string name="connection_test_pending">"接続状況確認"</string>
<string name="connection_test_testing">"テスト中…"</string>
<string name="connection_test_available">"成功: %dmsの遅延"</string>
@@ -35,10 +33,8 @@
<string name="ipv6_summary">"リモートサーバーに IPv6 パケットを転送"</string>
<string name="route_list">"プロキシ方式"</string>
<string name="route_entry_gfwlist">"中国本土からアクセス不可なアドレス以外を迂回する"</string>
<string name="proxied_apps">"アプリ別のプロキシを使用"</string>
<string name="proxied_apps_summary">"アプリ別でプロキシを指定、Android 4.x では必ずNATモードを使用して下さい"</string>
<string name="proxied_apps">"アプリ別のVPNモードを使用"</string>
<string name="proxied_apps_summary">"アプリ別のVPNモードを設定"</string>
<string name="on">"ON"</string>
<string name="bypass_apps">"バイパスモード(迂回モード)"</string>
<string name="bypass_apps_summary">"このモードを選択した場合、指定したアプリのパケットはプロキシを経由しない"</string>
@@ -74,9 +70,7 @@
<string name="profiles">"プロファイル"</string>
<string name="settings">"オプション設定"</string>
<string name="faq">"よくある質問"</string>
<string name="faq_url">"https://github.com/shadowsocks/shadowsocks-android/blob/master/.github/faq.md"</string>
<string name="about">"本アプリについて"</string>
<string name="about_title">"Shadowsocks %s"</string>
<string name="edit">"編集"</string>
<string name="share">"共有"</string>
<string name="add_profile">"プロファイルを追加"</string>
@@ -127,10 +121,7 @@
<string name="route_entry_bypass_chn">"中国本土のアドレスを迂回する"</string>
<string name="route_entry_bypass_lan_chn">"LAN 及び中国本土のアドレスを迂回する"</string>
<string name="route_entry_chinalist">"中国本土のアドレス以外を迂回する"</string>
<string name="proxied_apps_summary_v21">"選択したアプリにプロキシを設定する"</string>
<string name="acl_rule_templates_generic">"URL/サブネット/ホスト名 PCRE パターン"</string>
<string name="acl_rule_templates_generic">"サブネットまたはホスト名のPCREパターン"</string>
<string name="acl_rule_templates_domain">"ドメイン及び全てのサブドメイン"</string>
<!-- plugin -->
@@ -148,7 +139,6 @@
<string name="advanced">"アドバンス"</string>
<string name="service_mode">"サービスモード"</string>
<string name="service_mode_proxy">"プロキシのみ"</string>
<string name="service_mode_vpn">"VPN"</string>
<string name="service_mode_transproxy">"トランスプロキシ"</string>
<string name="port_proxy">"SOCKS5プロキシポート"</string>
<string name="port_local_dns">"ローカルDNSポート"</string>
@@ -157,4 +147,7 @@
<string name="service_transproxy">"トランスプロキシサービス"</string>
<string name="vpn_permission_denied">"VPNサービス作成のアクセス許可が拒否されました"</string>
<string name="auto_connect_summary_v24">"起動時にShadowsockを有効。 VPN常時接続の使用をお勧めします"</string>
</resources>
<string name="direct_boot_aware">"ダイレクトブート"</string>
<string name="direct_boot_aware_summary">"デバイスがロック解除される前にShadowsocksの自動起動を許可(選択されたプロファイル情報はより少ない保護を受けることになります)"</string>
<string name="acl_rule_online_config">"オンライン設定のURL"</string>
</resources>
+7 -47
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">"Shadowsocks"</string>
<string name="quick_toggle">"켜기/끄기"</string>
<!-- misc -->
@@ -9,7 +8,9 @@
<string name="remote_dns">"원격 DNS"</string>
<string name="stat_summary">"송신: \t%3$s\t↑\t%1$s/s
수신: \t%4$s\t↓\t%2$s/s"</string>
<plurals name="bytes">
<item quantity="other">"바이트"</item>
</plurals>
<string name="connection_test_pending">"인터넷 연결 상태 검사하기"</string>
<string name="connection_test_testing">"검사 중…"</string>
<string name="connection_test_available">"성공: 지연시간 %dms"</string>
@@ -34,11 +35,10 @@
<string name="ipv6">"IPv6 라우팅"</string>
<string name="ipv6_summary">"IPv6 트래픽도 원격으로 리다이렉트 합니다"</string>
<string name="route_list">"라우팅 대상"</string>
<string name="route_entry_gfwlist">"GFW List"</string>
<!-- Fuzzy -->
<string name="proxied_apps">"원하는 앱만 프락시 적용하기"</string>
<string name="proxied_apps_summary">"선택한 앱에만 프락시를 적용합니다. Android 4.x 이하에서는 NAT 모드를 써야 합니다."</string>
<string name="proxied_apps_summary">"선택한 앱에만 프락시를 적용합니다"</string>
<string name="on">"활성화"</string>
<string name="bypass_apps">"선택된 앱들만 프록시 적용 제외하기"</string>
<string name="bypass_apps_summary">"이 옵션을 활성화하면 선택된 앱들은 프락시를 사용하지 않습니다"</string>
@@ -55,7 +55,6 @@
<string name="service_failed">"원격 서버에 접속하는 데 실패했습니다"</string>
<string name="stop">"중지"</string>
<string name="stopping">"종료 중…"</string>
<string name="vpn_error">"%s"</string>
<string name="reboot_required">"VPN 서비스를 시작하는 데 실패했습니다. 장치를 재시작해 보세요."</string>
<string name="profile_invalid_input">"올바른 프로필 데이터를 찾을 수 없습니다"</string>
@@ -74,13 +73,10 @@
<string name="profiles">"프로필"</string>
<string name="settings">"설정"</string>
<string name="faq">"자주 묻는 질문"</string>
<string name="faq_url">"https://github.com/shadowsocks/shadowsocks-android/blob/master/.github/faq.md"</string>
<string name="about">"이 앱에 대하여"</string>
<string name="about_title">"Shadowsocks %s"</string>
<string name="edit">"수정"</string>
<string name="share">"공유"</string>
<string name="add_profile">"프로필 추가"</string>
<string name="action_apply_all">"Apply Settings to All Profiles"</string>
<string name="action_export">"클립보드로 내보내기"</string>
<string name="action_import">"클립보드에서 불러오기"</string>
<string name="action_export_msg">"성공적으로 내보냈습니다"</string>
@@ -102,34 +98,15 @@
</plurals>
<string name="undo">"실행 취소"</string>
<!-- tasker -->
<string name="toggle_service_state">"Start the service"</string>
<string name="start_service_default">"Connect to the current server"</string>
<string name="start_service">"Connect to %s"</string>
<string name="stop_service">"Switch to %s"</string>
<string name="profile_default">"Use the current profile"</string>
<!-- status -->
<string name="sent">"송신:"</string>
<string name="received">"수신:"</string>
<string name="connecting">"연결 중…"</string>
<string name="vpn_connected">"연결 완료. 탭 하면 연결 상태를 검사합니다."</string>
<string name="not_connected">"Not connected"</string>
<!-- acl -->
<string name="custom_rules">"사용자 정의 규칙"</string>
<string name="action_selection">"Selection…"</string>
<string name="action_add_rule">"Add rule(s)…"</string>
<string name="edit_rule">"Edit rule"</string>
<string name="route_entry_all">"All"</string>
<string name="route_entry_bypass_lan">"Bypass LAN"</string>
<string name="route_entry_bypass_chn">"Bypass mainland China"</string>
<string name="route_entry_bypass_lan_chn">"Bypass LAN &amp; mainland China"</string>
<string name="route_entry_chinalist">"China List"</string>
<string name="proxied_apps_summary_v21">"Configure VPN mode for selected apps"</string>
<string name="acl_rule_templates_generic">"URL, 서브넷 혹은 호스트 이름 PCRE 패턴"</string>
<string name="acl_rule_templates_domain">"Domain name and all its subdomain names"</string>
<string name="acl_rule_templates_generic">"서브넷 혹은 호스트 이름 PCRE 패턴"</string>
<!-- plugin -->
<string name="plugin">"플러그인"</string>
@@ -139,21 +116,4 @@
<string name="plugin_untrusted">"경고: 이 플러그인은 신뢰할 수 있는 출처에서 온 것이 아닌 것 같습니다"</string>
<string name="profile_plugin">"플러그인: %s"</string>
<string name="add_profile_scanner_permission_required">"QR 코드를 읽어 들이려면 카메라 권한이 필요합니다"</string>
<!-- notification category -->
<string name="service_vpn">"VPN Service"</string>
<string name="add_profile_methods_manual_settings">"Manual Settings"</string>
<string name="advanced">"Advanced"</string>
<string name="service_mode">"Service mode"</string>
<string name="service_mode_proxy">"Proxy only"</string>
<string name="service_mode_vpn">"VPN"</string>
<string name="service_mode_transproxy">"Transproxy"</string>
<string name="port_proxy">"SOCKS5 proxy port"</string>
<string name="port_local_dns">"Local DNS port"</string>
<string name="port_transproxy">"Transproxy port"</string>
<string name="service_proxy">"Proxy Service"</string>
<string name="service_transproxy">"Transproxy Service"</string>
<string name="vpn_permission_denied">"Permission denied to create a VPN service"</string>
<string name="auto_connect_summary_v24">"Enable Shadowsocks on startup. Recommended to use always-on VPN
instead"</string>
</resources>
</resources>
+31 -37
View File
@@ -1,15 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">"Shadowsocks"</string>
<string name="quick_toggle">"Подключение"</string>
<!-- misc -->
<string name="profile">"Профиль"</string>
<string name="profile_summary">"Переключить на другой профиль или добавить новые"</string>
<string name="remote_dns">"Удалённый DNS"</string>
<string name="stat_summary">"Отправлено: \t%3$s\t↑\t%1$s/s
Получено: \t%4$s\t↓\t%2$s/s"</string>
<string name="stat_summary">"Отправлено: \t%3$s\t↑\t%1$s
Получено: \t\t\t%4$s\t↓\t%2$s"</string>
<plurals name="bytes">
<item quantity="one">"байт"</item>
<item quantity="few">"байта"</item>
@@ -27,11 +25,11 @@
<string name="proxy_cat">"Настройки Сервера"</string>
<!-- proxy category -->
<string name="profile_name">"Имя Профиля"</string>
<string name="profile_name">"Имя профиля"</string>
<string name="proxy">"Сервер"</string>
<string name="remote_port">"Удалённый порт"</string>
<string name="sitekey">"Пароль"</string>
<string name="enc_method">"Метод Шифрования"</string>
<string name="enc_method">"Метод шифрования"</string>
<!-- feature category -->
<string name="feature_cat">"Дополнительные Настройки"</string>
@@ -41,14 +39,12 @@
<string name="ipv6_summary">"Перенаправлять трафик IPv6 на удалённый сервер"</string>
<string name="route_list">"Маршрут"</string>
<string name="route_entry_gfwlist">"Список GFW"</string>
<string name="proxied_apps">"Прокси для выбранных приложений"</string>
<string name="proxied_apps_summary">"Установить прокси для выбранных приложений, требует режим NAT под Android 4.x"</string>
<string name="proxied_apps">"Режим VPN для выбранных приложений"</string>
<string name="proxied_apps_summary">"Выбрать приложения, для которых нужно использовать режим VPN"</string>
<string name="on">"Вкл"</string>
<string name="bypass_apps">"В обход прокси"</string>
<string name="bypass_apps_summary">"Включите эту опцию для работы выбранных приложений в обход прокси"</string>
<string name="auto_connect">"Авто Подключение"</string>
<string name="auto_connect">"Авто-подключение"</string>
<string name="auto_connect_summary">"Запускать Shadowsocks при включении"</string>
<string name="tcp_fastopen_summary">"Переключение требует наличия ROOT прав"</string>
<string name="tcp_fastopen_summary_unsupported">"Неподдерживаемая версия ядра: %s &lt; 3.7.1"</string>
@@ -61,9 +57,8 @@
<string name="service_failed">"Ошибка при подключении к удалённому серверу"</string>
<string name="stop">"Остановить"</string>
<string name="stopping">"Останавливается…"</string>
<string name="vpn_error">"%s"</string>
<string name="reboot_required">"Не удалось запустить службу VPN. Возможно, требуется перезагрузить ваше устройство."</string>
<string name="profile_invalid_input">"No valid profile data found."</string>
<string name="profile_invalid_input">"Не найдено действительных данных профиля."</string>
<!-- alert category -->
<string name="yes">"Да"</string>
@@ -79,13 +74,13 @@
<!-- menu category -->
<string name="profiles">"Профили"</string>
<string name="settings">"Настройки"</string>
<string name="faq">"FAQ"</string>
<string name="faq_url">"https://github.com/shadowsocks/shadowsocks-android/blob/master/.github/faq.md"</string>
<string name="faq">"ЧаВо"</string>
<string name="faq_url">"https://github.com/shadowsocks/shadowsocks-android/blob/master/.github/faq.ru.md"</string>
<string name="about">"О приложении"</string>
<string name="about_title">"Shadowsocks %s"</string>
<string name="edit">"Изменить"</string>
<string name="share">"Поделиться"</string>
<string name="add_profile">"Добавить Профиль"</string>
<string name="add_profile">"Добавить профиль"</string>
<string name="action_apply_all">"Применить настройки для всех профилей"</string>
<string name="action_export">"Экспортировать в буфер обмена"</string>
<string name="action_import">"Импортировать из буфера обмена"</string>
@@ -101,7 +96,7 @@
<string name="delete">"Удалить"</string>
<string name="delete_confirm_prompt">"Вы уверены, что хотите удалить этот профиль?"</string>
<string name="share_qr_nfc">"QR-код/NFC"</string>
<string name="add_profile_dialog">"Добавить этот Профиль Shadowsocks?"</string>
<string name="add_profile_dialog">"Добавить этот профиль Shadowsocks?"</string>
<string name="add_profile_methods_scan_qr_code">"Сканировать QR-код"</string>
<plurals name="removed">
<item quantity="one">"Удалено %d элементов"</item>
@@ -135,10 +130,7 @@
<string name="route_entry_bypass_chn">"Все, кроме Китая"</string>
<string name="route_entry_bypass_lan_chn">"Все, кроме LAN и Китая"</string>
<string name="route_entry_chinalist">"Список Китай"</string>
<string name="proxied_apps_summary_v21">"Установить прокси для выбранных приложений"</string>
<string name="acl_rule_templates_generic">"URL/Подсеть/Регулярное выражение (PCRE) имени хоста"</string>
<string name="acl_rule_templates_generic">"Подсеть или имя хоста, записанное регулярным выражением (PCRE)"</string>
<string name="acl_rule_templates_domain">"Доменное имя и все его поддомены"</string>
<!-- plugin -->
@@ -151,19 +143,21 @@
<string name="add_profile_scanner_permission_required">"Разрешение камеры требуется для сканирования QR код."</string>
<!-- notification category -->
<string name="service_vpn">"VPN Service"</string>
<string name="add_profile_methods_manual_settings">"Manual Settings"</string>
<string name="advanced">"Advanced"</string>
<string name="service_mode">"Service mode"</string>
<string name="service_mode_proxy">"Proxy only"</string>
<string name="service_mode_vpn">"VPN"</string>
<string name="service_mode_transproxy">"Transproxy"</string>
<string name="port_proxy">"SOCKS5 proxy port"</string>
<string name="port_local_dns">"Local DNS port"</string>
<string name="port_transproxy">"Transproxy port"</string>
<string name="service_proxy">"Proxy Service"</string>
<string name="service_transproxy">"Transproxy Service"</string>
<string name="vpn_permission_denied">"Permission denied to create a VPN service"</string>
<string name="auto_connect_summary_v24">"Enable Shadowsocks on startup. Recommended to use always-on VPN
instead"</string>
</resources>
<string name="service_vpn">"Служба VPN"</string>
<string name="add_profile_methods_manual_settings">"Ручные настройки"</string>
<string name="advanced">"Дополнительно"</string>
<string name="service_mode">"Режим"</string>
<string name="service_mode_proxy">"Только прокси"</string>
<string name="service_mode_transproxy">"Прозрачный прокси"</string>
<string name="port_proxy">"Порт SOCKS5 прокси"</string>
<string name="port_local_dns">"Локальный порт DNS"</string>
<string name="port_transproxy">"Порт прозрачного прокси"</string>
<string name="service_proxy">"Служба прокси"</string>
<string name="service_transproxy">"Служба прозрачный прокси"</string>
<string name="vpn_permission_denied">"Нет разрешения на создание VPN соединения"</string>
<string name="auto_connect_summary_v24">"Включить Shadowsocks во время запуска. Лучше использовать режим постоянной VPN."</string>
<string name="speed">"%s/с"</string>
<string name="direct_boot_aware">"Непосредственная загрузка"</string>
<string name="direct_boot_aware_summary">"Позволить Shadowsocks запускаться до того, как устройство будет разблокировано (данные выбранного профиля будут хуже защищены)"</string>
<string name="acl_rule_online_config">"URL конфигурации"</string>
</resources>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="fab_margin_top">-28dp</dimen>
</resources>
+7 -20
View File
@@ -1,27 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">"影梭"</string>
<string name="quick_toggle">"开关"</string>
<!-- misc -->
<string name="profile">"配置文件"</string>
<string name="profile_summary">"新建或切换到其他配置文件"</string>
<string name="remote_dns">"远程 DNS"</string>
<string name="stat_summary">"上传: \t%3$s\t↑\t%1$s/s
下载: \t%4$s\t↓\t%2$s/s"</string>
<string name="stat_summary">"上传: \t%3$s\t↑\t%1$s
下载: \t%4$s\t↓\t%2$s"</string>
<string name="connection_test_pending">"检查网络连接"</string>
<string name="connection_test_testing">"测试中…"</string>
<string name="connection_test_available">"连接成功:延时 %d 毫秒"</string>
<string name="connection_test_error">"失败:%s"</string>
<string name="connection_test_fail">"无互联网连接"</string>
<string name="connection_test_error_status_code">"状态码无效(#%d)"</string>
<!-- proxy category -->
@@ -29,7 +21,6 @@
<!-- proxy category -->
<string name="profile_name">"配置名称"</string>
<string name="proxy">"服务器"</string>
<string name="remote_port">"远程端口"</string>
<string name="sitekey">"密码"</string>
@@ -44,7 +35,6 @@
<string name="route_list">"路由"</string>
<string name="route_entry_gfwlist">"GFW 列表"</string>
<string name="proxied_apps">"分应用 VPN"</string>
<string name="proxied_apps_summary">"允许部分应用绕过 VPN"</string>
<string name="on">"启用"</string>
<string name="bypass_apps">"绕行模式"</string>
@@ -81,7 +71,6 @@
<string name="profiles">"配置文件"</string>
<string name="settings">"设置选项"</string>
<string name="faq">"常见问题"</string>
<string name="faq_url">"https://github.com/shadowsocks/shadowsocks-android/blob/master/.github/faq.md"</string>
<string name="about">"关于"</string>
<string name="about_title">"影梭 (Shadowsocks) %s"</string>
<string name="edit">"编辑"</string>
@@ -133,12 +122,8 @@
<string name="route_entry_bypass_chn">"绕过中国大陆地址"</string>
<string name="route_entry_bypass_lan_chn">"绕过局域网及中国大陆地址"</string>
<string name="route_entry_chinalist">"仅代理中国大陆地址"</string>
<string name="proxied_apps_summary_v21">"为应用程序分别设置代理"</string>
<string name="acl_rule_templates_generic">"URL/子网/域名 PCRE 正则表达式"</string>
<string name="acl_rule_templates_generic">"子网/域名 PCRE 正则表达式"</string>
<string name="acl_rule_templates_domain">"域名及其子域名"</string>
<string name="acl_rule_online_config">配置文件地址</string>
<!-- plugin -->
<string name="plugin">"插件"</string>
@@ -155,7 +140,6 @@
<string name="advanced">"高级选项"</string>
<string name="service_mode">"服务模式"</string>
<string name="service_mode_proxy">"仅代理"</string>
<string name="service_mode_vpn">"VPN"</string>
<string name="service_mode_transproxy">"透明代理"</string>
<string name="port_proxy">"SOCKS5 代理端口"</string>
<string name="port_local_dns">"本地 DNS 端口"</string>
@@ -164,4 +148,7 @@
<string name="service_transproxy">"透明代理模式"</string>
<string name="vpn_permission_denied">"创建 VPN 服务权限不足"</string>
<string name="auto_connect_summary_v24">"允许 Shadowsocks 随系统启动,建议使用始终开启的 VPN"</string>
</resources>
<string name="direct_boot_aware">"直接启动"</string>
<string name="direct_boot_aware_summary">"允许在设备解锁前启动服务(选中的配置信息会不那么安全)"</string>
<string name="acl_rule_online_config">"在线规则文件 URL"</string>
</resources>
+4 -13
View File
@@ -37,10 +37,8 @@
<string name="ipv6_summary">"向遠端重新導向 IPv6 流量"</string>
<string name="route_list">"路由"</string>
<string name="route_entry_gfwlist">"GFW List"</string>
<string name="proxied_apps">"個別應用程式的 Proxy"</string>
<string name="proxied_apps_summary">"為已選擇的應用程式設定 Proxy,在 Android 4.X 以下需要開啟 NAT 模式"</string>
<string name="proxied_apps">"個別應用程式的 VPN"</string>
<string name="proxied_apps_summary">"為已選擇的應用程式設定 VPN"</string>
<string name="on">"開"</string>
<string name="bypass_apps">"略過模式"</string>
<string name="bypass_apps_summary">"啟用此選項,會略過已選擇的應用程式"</string>
@@ -57,7 +55,6 @@
<string name="service_failed">"連線至遠端伺服器失敗"</string>
<string name="stop">"停止"</string>
<string name="stopping">"關閉中…"</string>
<string name="vpn_error">"%s"</string>
<string name="reboot_required">"VPN 服務啟動失敗。您或許需要重新啟動您的裝置。"</string>
<string name="profile_invalid_input">"未找到有效的設定檔資料。"</string>
@@ -76,7 +73,6 @@
<string name="profiles">"設定檔"</string>
<string name="settings">"設定"</string>
<string name="faq">"常見問題"</string>
<string name="faq_url">"https://github.com/shadowsocks/shadowsocks-android/blob/master/.github/faq.md"</string>
<string name="about">"關於"</string>
<string name="about_title">"Shadowsocks %s"</string>
<string name="edit">"編輯"</string>
@@ -128,12 +124,8 @@
<string name="route_entry_bypass_chn">"略過中國大陸"</string>
<string name="route_entry_bypass_lan_chn">"略過區域網路及中國大陸"</string>
<string name="route_entry_chinalist">"China List"</string>
<string name="proxied_apps_summary_v21">"為已選擇的應用程式設定 Proxy"</string>
<string name="acl_rule_templates_generic">"URL/子網路/主機名稱 PCRE 模式"</string>
<string name="acl_rule_templates_generic">"子網路/主機名稱 PCRE 模式"</string>
<string name="acl_rule_templates_domain">"網域及其所有子網域"</string>
<string name="acl_rule_online_config">配置文件地址</string>
<!-- plugin -->
<string name="plugin">"外掛程式"</string>
@@ -150,7 +142,6 @@
<string name="advanced">"高級"</string>
<string name="service_mode">"服務模式"</string>
<string name="service_mode_proxy">"仅代理"</string>
<string name="service_mode_vpn">"VPN"</string>
<string name="service_mode_transproxy">"透明代理"</string>
<string name="port_proxy">"SOCKS5 代理連接埠"</string>
<string name="port_local_dns">"本地 DNS 連接埠"</string>
@@ -159,4 +150,4 @@
<string name="service_transproxy">"透明代理服務"</string>
<string name="vpn_permission_denied">"没有權限創建 VPN 服務"</string>
<string name="auto_connect_summary_v24">"允許 Shadowsocks 隨系統啟動,建議使用始終開啟的 VPN"</string>
</resources>
</resources>
-1
View File
@@ -4,5 +4,4 @@
<dimen name="qr_code_size">250dp</dimen>
<dimen name="profile_padding">8dp</dimen>
<dimen name="bottom_sheet_padding">8dp</dimen>
<dimen name="fab_margin_top">-44dp</dimen>
</resources>
+2
View File
@@ -13,6 +13,7 @@
<AutoSummaryEditTextPreference
android:key="proxy"
app:pref_summaryHasText="%s"
android:singleLine="true"
android:title="@string/proxy"/>
<AutoSummaryEditTextPreference
android:key="remotePortNum"
@@ -25,6 +26,7 @@
app:pref_summaryPasswordSubstituteLength="0"
android:key="sitekey"
app:pref_summaryHasText="%s"
android:singleLine="true"
android:title="@string/sitekey"/>
<SimpleMenuPreference
android:key="encMethod"
-1
View File
@@ -24,7 +24,6 @@ android {
}
dependencies {
api "com.android.support:preference-v7:$supportLibraryVersion"
api "com.android.support:preference-v14:$supportLibraryVersion"
api "com.takisoft.fix:preference-v7:$takisoftFixVersion"
api "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion"
@@ -6,6 +6,7 @@
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:touchscreenBlocksFocus="false"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:id="@+id/toolbar" />
+3 -9
View File
@@ -1,15 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- proxy category -->
<string name="proxy_cat">"サーバー設定"</string>
<!-- feature category -->
<string name="feature_cat">"ファンクション設定"</string>
<!-- alert category -->
<string name="feature_cat">"機能設定"</string>
<string name="unsaved_changes_prompt">"変更は保存されておりません、保存しますか?"</string>
<string name="yes">"はい"</string>
<string name="no">"いいえ"</string>
<string name="unsaved_changes_prompt">"変更は適応されておりません、保存しますか?"</string>
<string name="apply">"適用"</string>
<string name="apply">"適応"</string>
</resources>
+3 -9
View File
@@ -1,15 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- proxy category -->
<string name="proxy_cat">"Настройки Сервера"</string>
<!-- feature category -->
<string name="feature_cat">"Дополнительные Настройки"</string>
<!-- alert category -->
<string name="proxy_cat">"Настройки сервера"</string>
<string name="feature_cat">"Настройки опций"</string>
<string name="unsaved_changes_prompt">"Сохранить изменения?"</string>
<string name="yes">"Да"</string>
<string name="no">"Нет"</string>
<string name="unsaved_changes_prompt">"Изменения не сохранены. Сохранить?"</string>
<string name="apply">"Применить"</string>
</resources>
@@ -1,15 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- proxy category -->
<string name="proxy_cat">"服务器设置"</string>
<!-- feature category -->
<string name="feature_cat">"功能设置"</string>
<!-- alert category -->
<string name="unsaved_changes_prompt">"是否要保存修改?"</string>
<string name="yes">"是"</string>
<string name="no">"否"</string>
<string name="unsaved_changes_prompt">"保存修改吗?"</string>
<string name="apply">"应用"</string>
</resources>
Executable
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
release=$1
cp mobile/build/outputs/apk/release/mobile-armeabi-v7a-release.apk shadowsocks-armeabi-v7a-${release}.apk
cp mobile/build/outputs/apk/release/mobile-arm64-v8a-release.apk shadowsocks-arm64-v8a-${release}.apk
cp mobile/build/outputs/apk/release/mobile-x86-release.apk shadowsocks-x86-${release}.apk