Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7922159e5e | ||
|
|
fabab2854f | ||
|
|
6a9464e08d | ||
|
|
f70e905bce | ||
|
|
90b5780d91 | ||
|
|
d189044808 | ||
|
|
5a03f52545 | ||
|
|
2d4d6737ff | ||
|
|
80fdc07bdd | ||
|
|
5ca3a8e9fd | ||
|
|
f3a458161a | ||
|
|
e067c6fae2 | ||
|
|
f48ad61220 | ||
|
|
27f9992447 | ||
|
|
546a5d010d | ||
|
|
cbb839ec11 | ||
|
|
179e5456f8 | ||
|
|
30700facd3 | ||
|
|
82103d286d | ||
|
|
a9ca3c049d | ||
|
|
0433704d87 | ||
|
|
2f23462c84 | ||
|
|
c1dd21e0c3 | ||
|
|
d0b4819dc5 | ||
|
|
d99757f1a3 | ||
|
|
8ed71d1707 | ||
|
|
ffdb6f84e3 | ||
|
|
094b307254 | ||
|
|
bd5fff100d | ||
|
|
479e697e6d | ||
|
|
e98dadf0a2 | ||
|
|
4cfab40ec2 | ||
|
|
0fdbd19bff | ||
|
|
913ec3c06b | ||
|
|
617c6dac1b | ||
|
|
244c2ecdfd | ||
|
|
54c696d00a | ||
|
|
c4d9edc224 | ||
|
|
7a7cbf5803 | ||
|
|
f53936421d | ||
|
|
5ef2849c4a | ||
|
|
e1f58bfd0c | ||
|
|
7098e57893 | ||
|
|
a4c5fc4919 | ||
|
|
3c69b23a5b | ||
|
|
738febbac7 | ||
|
|
ed91010b18 | ||
|
|
8f4d7db797 | ||
|
|
52ead0a02c | ||
|
|
7d099b1faf | ||
|
|
89b9914f15 | ||
|
|
809b81a332 | ||
|
|
395c07a0f6 | ||
|
|
cb61c290a4 | ||
|
|
9ccf2bc436 |
@@ -5,6 +5,7 @@ Please read FAQ in wiki then answer these questions before submitting your issue
|
|||||||
* Android version: *e.g. "7.0.0_r14", more detailed description is preferred*
|
* Android version: *e.g. "7.0.0_r14", more detailed description is preferred*
|
||||||
* Device: *e.g. Google Pixel XL*
|
* Device: *e.g. Google Pixel XL*
|
||||||
* Shadowsocks version: *version code "v3.0.0" or commit ID "a073f85"*
|
* Shadowsocks version: *version code "v3.0.0" or commit ID "a073f85"*
|
||||||
|
* Last version that did not exhibit the issue (if applicable):
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
@@ -17,7 +18,13 @@ _Put an `x` inside the [ ] that applies._
|
|||||||
* Local port: 1080
|
* Local port: 1080
|
||||||
* Encrypt method:
|
* Encrypt method:
|
||||||
* [ ] One-time authentication
|
* [ ] One-time authentication
|
||||||
* Route:
|
* Route
|
||||||
|
* [ ] All
|
||||||
|
* [ ] Bypass LAN
|
||||||
|
* [ ] Bypass China
|
||||||
|
* [ ] Bypass LAN & China
|
||||||
|
* [ ] GFW List
|
||||||
|
* [ ] China List
|
||||||
* [ ] IPv6 route
|
* [ ] IPv6 route
|
||||||
* [ ] Per-App Proxy
|
* [ ] Per-App Proxy
|
||||||
* [ ] Bypass mode
|
* [ ] Bypass mode
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ cache:
|
|||||||
android:
|
android:
|
||||||
components:
|
components:
|
||||||
- tools
|
- tools
|
||||||
- build-tools-24.0.1
|
- build-tools-25.0.0
|
||||||
- extra-android-m2repository
|
- extra-android-m2repository
|
||||||
- extra-google-m2repository
|
- extra-google-m2repository
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
|||||||
* SBT 0.13.0+
|
* SBT 0.13.0+
|
||||||
* Go 1.4+
|
* Go 1.4+
|
||||||
* Android SDK
|
* Android SDK
|
||||||
- Build Tools 24+ (as required by [`sbt-android`](https://github.com/scala-android/sbt-android))
|
- Build Tools 25+
|
||||||
- Android Support Repository and Google Repository (see `build.sbt` for version)
|
- Android Support Repository and Google Repository (see `build.sbt` for version)
|
||||||
* Android NDK r12b+
|
* Android NDK r12b+
|
||||||
|
|
||||||
@@ -24,7 +24,6 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
|||||||
* Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk`
|
* Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk`
|
||||||
* Set environment variable `GOROOT_BOOTSTRAP` to `/path/to/go`
|
* Set environment variable `GOROOT_BOOTSTRAP` to `/path/to/go`
|
||||||
* Create your key following the instructions at https://developer.android.com/studio/publish/app-signing.html
|
* Create your key following the instructions at https://developer.android.com/studio/publish/app-signing.html
|
||||||
* Put your key in ~/.keystore
|
|
||||||
* Create `local.properties` from `local.properties.example` with your own key information
|
* Create `local.properties` from `local.properties.example` with your own key information
|
||||||
* Invoke the building like this
|
* Invoke the building like this
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +1,55 @@
|
|||||||
import android.Keys._
|
scalaVersion := "2.11.8"
|
||||||
|
dexMaxHeap := "4g"
|
||||||
|
|
||||||
android.Plugin.androidBuild
|
enablePlugins(AndroidApp)
|
||||||
|
android.useSupportVectors
|
||||||
platformTarget in Android := "android-24"
|
|
||||||
|
|
||||||
name := "shadowsocks"
|
name := "shadowsocks"
|
||||||
|
version := "3.2.9"
|
||||||
|
versionCode := Some(169)
|
||||||
|
|
||||||
scalaVersion := "2.11.8"
|
platformTarget := "android-25"
|
||||||
|
|
||||||
compileOrder in Compile := CompileOrder.JavaThenScala
|
compileOrder := CompileOrder.JavaThenScala
|
||||||
|
javacOptions ++= "-source" :: "1.7" :: "-target" :: "1.7" :: Nil
|
||||||
|
scalacOptions ++= "-target:jvm-1.7" :: "-Xexperimental" :: Nil
|
||||||
|
ndkJavah := Seq()
|
||||||
|
ndkBuild := Seq()
|
||||||
|
|
||||||
javacOptions ++= Seq("-source", "1.7", "-target", "1.7")
|
proguardVersion := "5.3.1"
|
||||||
|
proguardCache := Seq()
|
||||||
|
proguardOptions ++=
|
||||||
|
"-keep class com.github.shadowsocks.System { *; }" ::
|
||||||
|
"-dontwarn com.google.android.gms.internal.**" ::
|
||||||
|
"-dontwarn com.j256.ormlite.**" ::
|
||||||
|
"-dontwarn org.xbill.**" ::
|
||||||
|
Nil
|
||||||
|
|
||||||
scalacOptions ++= Seq("-target:jvm-1.7", "-Xexperimental")
|
shrinkResources := true
|
||||||
|
typedResources := false
|
||||||
ndkJavah in Android := List()
|
resConfigs := Seq("ja", "ru", "zh-rCN", "zh-rTW")
|
||||||
|
|
||||||
ndkBuild in Android := List()
|
|
||||||
|
|
||||||
shrinkResources in Android := true
|
|
||||||
|
|
||||||
typedResources in Android := false
|
|
||||||
|
|
||||||
resConfigs in Android := Seq("ru", "zh-rCN", "zh-rTW")
|
|
||||||
|
|
||||||
dexMaxHeap in Android := "4g"
|
|
||||||
|
|
||||||
resolvers += Resolver.jcenterRepo
|
resolvers += Resolver.jcenterRepo
|
||||||
|
libraryDependencies ++=
|
||||||
useSupportVectors
|
"com.android.support" % "design" % "25.0.0" ::
|
||||||
|
"com.android.support" % "gridlayout-v7" % "25.0.0" ::
|
||||||
libraryDependencies ++= Seq(
|
"com.android.support" % "preference-v14" % "25.0.0" ::
|
||||||
"com.android.support" % "design" % "24.2.1",
|
"com.evernote" % "android-job" % "1.1.3" ::
|
||||||
"com.android.support" % "gridlayout-v7" % "24.2.1",
|
"com.github.clans" % "fab" % "1.6.4" ::
|
||||||
"com.android.support" % "preference-v14" % "24.2.1",
|
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" ::
|
||||||
"com.evernote" % "android-job" % "1.1.0",
|
"com.github.kevinsawicki" % "http-request" % "6.0" ::
|
||||||
"com.github.clans" % "fab" % "1.6.4",
|
"com.google.android.gms" % "play-services-ads" % "9.8.0" ::
|
||||||
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
|
"com.google.android.gms" % "play-services-analytics" % "9.8.0" ::
|
||||||
"com.github.kevinsawicki" % "http-request" % "6.0",
|
"com.google.android.gms" % "play-services-gcm" % "9.8.0" ::
|
||||||
"com.google.android.gms" % "play-services-ads" % "9.6.1",
|
"com.j256.ormlite" % "ormlite-android" % "5.0" ::
|
||||||
"com.google.android.gms" % "play-services-analytics" % "9.6.1",
|
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2" ::
|
||||||
"com.google.android.gms" % "play-services-gcm" % "9.6.1",
|
"dnsjava" % "dnsjava" % "2.1.7" ::
|
||||||
"com.j256.ormlite" % "ormlite-android" % "5.0",
|
"eu.chainfire" % "libsuperuser" % "1.0.0.201608240809" ::
|
||||||
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
|
"me.dm7.barcodescanner" % "zxing" % "1.9" ::
|
||||||
"dnsjava" % "dnsjava" % "2.1.7",
|
"net.glxn.qrgen" % "android" % "2.0" ::
|
||||||
"eu.chainfire" % "libsuperuser" % "1.0.0.201608240809",
|
Nil
|
||||||
"me.dm7.barcodescanner" % "zxing" % "1.9",
|
|
||||||
"net.glxn.qrgen" % "android" % "2.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
proguardVersion in Android := "5.3"
|
|
||||||
|
|
||||||
proguardCache in Android := Seq()
|
|
||||||
|
|
||||||
proguardOptions in Android ++= Seq(
|
|
||||||
"-keep class com.github.shadowsocks.System { *; }",
|
|
||||||
"-dontwarn com.google.android.gms.internal.**",
|
|
||||||
"-dontwarn com.j256.ormlite.**",
|
|
||||||
"-dontwarn org.xbill.**")
|
|
||||||
|
|
||||||
lazy val nativeBuild = TaskKey[Unit]("native-build", "Build native executables")
|
lazy val nativeBuild = TaskKey[Unit]("native-build", "Build native executables")
|
||||||
|
|
||||||
nativeBuild := {
|
nativeBuild := {
|
||||||
val logger = streams.value.log
|
val logger = streams.value.log
|
||||||
Process("./build.sh") ! logger match {
|
Process("./build.sh") ! logger match {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<issue id="NewApi">
|
||||||
|
<ignore path="src/main/res/drawable"/>
|
||||||
|
</issue>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.18")
|
addSbtPlugin("org.scala-android" % "sbt-android" % "1.7.1")
|
||||||
|
|
||||||
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")
|
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools" package="com.github.shadowsocks"
|
xmlns:tools="http://schemas.android.com/tools" package="com.github.shadowsocks">
|
||||||
android:versionCode="166"
|
|
||||||
android:versionName="3.2.6">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
@@ -20,13 +18,15 @@
|
|||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="19"
|
android:minSdkVersion="19"
|
||||||
android:targetSdkVersion="24"/>
|
android:targetSdkVersion="25"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
android:extractNativeLibs="false"
|
||||||
android:name=".ShadowsocksApplication"
|
android:name=".ShadowsocksApplication"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:backupAgent=".ShadowsocksBackupAgent"
|
android:backupAgent=".ShadowsocksBackupAgent"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.Material"
|
android:theme="@style/Theme.Material"
|
||||||
@@ -37,10 +37,6 @@
|
|||||||
<meta-data android:name="com.google.android.backup.api_key"
|
<meta-data android:name="com.google.android.backup.api_key"
|
||||||
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
|
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="com.google.android.gms.ads.AdActivity"
|
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".Shadowsocks"
|
android:name=".Shadowsocks"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@@ -51,14 +47,17 @@
|
|||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.app.shortcuts"
|
||||||
|
android:resource="@xml/shortcuts"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ShadowsocksRunnerActivity"
|
android:name=".ShadowsocksRunnerActivity"
|
||||||
android:theme="@android:style/Theme.NoDisplay"
|
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
|
android:taskAffinity=""
|
||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
@@ -99,13 +98,14 @@
|
|||||||
android:launchMode="singleTask"/>
|
android:launchMode="singleTask"/>
|
||||||
|
|
||||||
<activity android:name=".TaskerActivity"
|
<activity android:name=".TaskerActivity"
|
||||||
android:icon="@drawable/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
|
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".ShadowsocksQuickSwitchActivity"
|
<activity android:name=".ShadowsocksQuickSwitchActivity"
|
||||||
|
android:label="@string/quick_switch"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
@@ -116,6 +116,18 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".QuickToggleShortcut"
|
||||||
|
android:label="@string/quick_toggle"
|
||||||
|
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:taskAffinity=""
|
||||||
|
android:launchMode="singleTask">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".ShadowsocksRunnerService"
|
android:name=".ShadowsocksRunnerService"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
@@ -170,6 +182,9 @@
|
|||||||
android:process=":bg"/>
|
android:process=":bg"/>
|
||||||
<receiver android:name="com.evernote.android.job.JobBootReceiver"
|
<receiver android:name="com.evernote.android.job.JobBootReceiver"
|
||||||
android:process=":bg"/>
|
android:process=":bg"/>
|
||||||
|
|
||||||
|
<!-- Strip useless components -->
|
||||||
|
<activity android:name="com.google.android.gms.ads.purchase.InAppPurchaseActivity" tools:node="remove"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#f5f5f5"
|
||||||
|
android:pathData="M24,24m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#546e7a"
|
||||||
|
android:pathData="M24,21.8 C25.7673,21.8,27.2,23.2327,27.2,25 C27.2,26.7673,25.7673,28.2,24,28.2
|
||||||
|
C22.2327,28.2,20.8,26.7673,20.8,25 C20.8,23.2327,22.2327,21.8,24,21.8 Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#546e7a"
|
||||||
|
android:pathData="M21,15 L19.17,17 L16,17 A2,2,0,0,0,14,19 L14,31 A2,2,0,0,0,16,33 L32,33
|
||||||
|
A2,2,0,0,0,34,31 L34,19 A2,2,0,0,0,32,17 L28.83,17 L27,15 Z M24,30
|
||||||
|
A5,5,0,1,1,29,25 A5,5,0,0,1,24,30 Z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#f5f5f5"
|
||||||
|
android:pathData="M24,24m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#546e7a"
|
||||||
|
android:pathData="M34,14.72 L30.52,30.04 L22.72,27.53 L29.61,19.31 L20.43,27.04 L14,24.62
|
||||||
|
L34,14.72 Z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#546e7a"
|
||||||
|
android:pathData="M22.89,29.1 L25.38,29.9 L22.9,33.28 L22.89,29.1 Z" />
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFFFF"
|
|
||||||
android:pathData="M18,7l-1.41,-1.41 -6.34,6.34 1.41,1.41L18,7zM22.24,5.59L11.66,16.17 7.48,12l-1.41,1.41L11.66,19l12,-12 -1.42,-1.41zM0.41,13.41L6,19l1.41,-1.41L1.83,12 0.41,13.41z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--suppress NewApi -->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
<FrameLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/content_frame"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
<include layout="@layout/toolbar_light_dark" />
|
<include layout="@layout/toolbar_light_dark" />
|
||||||
</FrameLayout>
|
<me.dm7.barcodescanner.zxing.ZXingScannerView android:id="@+id/scanner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item android:id="@+id/action_apply_all"
|
<item android:id="@+id/action_apply_all"
|
||||||
android:title="@string/action_apply_all"
|
android:title="@string/action_apply_all"
|
||||||
android:icon="@drawable/ic_done_all"
|
|
||||||
android:alphabeticShortcut="a"
|
android:alphabeticShortcut="a"
|
||||||
android:numericShortcut="1"
|
android:numericShortcut="1"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="never"/>
|
||||||
<item android:id="@+id/action_export"
|
<item android:id="@+id/action_export"
|
||||||
android:title="@string/action_export"
|
android:title="@string/action_export"
|
||||||
android:icon="@drawable/ic_content_copy"
|
android:icon="@drawable/ic_content_copy"
|
||||||
|
|||||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="proxied_apps_summary">選択したアプリにプロキシを設定する</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">シャドーソックス</string>
|
||||||
|
<string name="quick_toggle">スイッチ</string>
|
||||||
|
|
||||||
|
<string name="misc_cat">その他</string>
|
||||||
|
<string name="proxy_cat">サーバーの設定</string>
|
||||||
|
<string name="profile_name">設定名</string>
|
||||||
|
<string name="profile">配置ファイル</string>
|
||||||
|
<string name="profile_summary">配置ファイルを新規作成か他のを切り替える</string>
|
||||||
|
<string name="proxy">サーバー</string>
|
||||||
|
<string name="remote_port">リモートポート</string>
|
||||||
|
<string name="port">ローカルポート</string>
|
||||||
|
<string name="sitekey">パスワード</string>
|
||||||
|
<string name="enc_method">暗号方式</string>
|
||||||
|
<string name="feature_cat">機能設定</string>
|
||||||
|
<string name="http_proxy">HTTP 代理サーバー</string>
|
||||||
|
<string name="http_proxy_summary">ローカル HTTP 代理</string>
|
||||||
|
<string name="dns_proxy">DNS 代理</string>
|
||||||
|
<string name="dns_proxy_summary">重定向 DNS 查询到远程服务器</string>
|
||||||
|
<string name="auto_set_gfwlist">中国ルーティング</string>
|
||||||
|
<string name="auto_set_gfwlist_summary">中国本土アドレスをバイパス</string>
|
||||||
|
<string name="route_list">ルーティング</string>
|
||||||
|
<string name="proxied_apps">選択したアプリにプロキシ</string>
|
||||||
|
<string name="proxied_apps_summary">为应用程序分别设置代理,在 4.x 下需要启用 NAT 模式</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_summary">随系统启动后台服务</string>
|
||||||
|
<string name="tcp_fastopen_summary">切り替えるはROOT権限が必要です</string>
|
||||||
|
<string name="tcp_fastopen_summary_unsupported">不支持的内核版本:%s < 3.7.1</string>
|
||||||
|
<string name="forward_success">后台服务已开始运行。</string>
|
||||||
|
<string name="service_failed">リモートサーバーを接続できません</string>
|
||||||
|
<string name="invalid_server">サーバー名が無効です</string>
|
||||||
|
<string name="method_unsafe">警告する:この暗号化アルゴリズムは不安です</string>
|
||||||
|
<string name="nat_deprecated">警告:在 Android 5.0 及更高版本中不建议使用 NAT 模式</string>
|
||||||
|
<string name="nat_no_root">NAT モードは ROOT権限が必要です</string>
|
||||||
|
<string name="switch_to_vpn">VPN モードに切り替える</string>
|
||||||
|
<string name="stop">止める</string>
|
||||||
|
<string name="quick_switch">切り替える</string>
|
||||||
|
<string name="stopping">閉じます……</string>
|
||||||
|
<string name="vpn_error">后台服务启动失败:%s</string>
|
||||||
|
<string name="reboot_required">VPN 服务启动失败。你可能需要重启设备。</string>
|
||||||
|
<string name="close">閉じる</string>
|
||||||
|
<string name="proxy_empty">代理サーバのアドレスやパスワードは空白がいけません</string>
|
||||||
|
<string name="connect">接続</string>
|
||||||
|
<string name="initializing">初期化します……</string>
|
||||||
|
<string name="recovering">リセットします……</string>
|
||||||
|
<string name="loading">読み込み中……</string>
|
||||||
|
<string name="profiles">配置ファイル</string>
|
||||||
|
<string name="settings">オプションの設定</string>
|
||||||
|
<string name="remove_profile">このサーバーの設定を削除する「%s」?</string>
|
||||||
|
<string name="recovery">リセット</string>
|
||||||
|
<string name="recovery_summary">すべてのバックグラウンドサービスをリセットする</string>
|
||||||
|
<string name="about">関する</string>
|
||||||
|
<string name="about_title">シャドーソックス(shadowsocks)%s</string>
|
||||||
|
<string name="flush_dnscache">DNS キャッシングをリフレッシュする</string>
|
||||||
|
<string name="flush_dnscache_summary">只需在 NAT 模式下使用,需要 ROOT 权限</string>
|
||||||
|
<string name="flush_dnscache_no_root">在没有 ROOT 权限的情况下无法刷新 DNS 缓存</string>
|
||||||
|
<string name="flushing">リフレッシュします……</string>
|
||||||
|
<string name="share">シェア</string>
|
||||||
|
<string name="share_message">QRコードを読み取るやAndroid Beam (NFC) 使用する</string>
|
||||||
|
<string name="share_message_without_nfc">QRコードを読み取る</string>
|
||||||
|
<string name="share_message_nfc_disabled">QRコードを読み取る\nAndroid Beam が無効にする</string>
|
||||||
|
<string name="turn_on_nfc">NFC を付ける & Android Beam</string>
|
||||||
|
<string name="add_profile">配置ファイルを加える</string>
|
||||||
|
|
||||||
|
<string name="nat">NAT モード (デバッギングだけ)</string>
|
||||||
|
<string name="nat_summary">从 VPN 模式切换为 NAT 模式,需要 ROOT 权限</string>
|
||||||
|
|
||||||
|
<string name="udp_dns">UDP 転送</string>
|
||||||
|
<string name="udp_dns_summary">リモートサーバーでUDPプロトコルのパケット</string>
|
||||||
|
|
||||||
|
<string name="onetime_auth">ワンタイム認証</string>
|
||||||
|
<string name="onetime_auth_summary">ワンタイム認証を付ける</string>
|
||||||
|
|
||||||
|
<string name="ipv6">IPv6 ルーティング</string>
|
||||||
|
<string name="ipv6_summary">リモートサーバーに IPv6 トラフィックを転送</string>
|
||||||
|
|
||||||
|
<string name="stat">ネットワークトラフィック</string>
|
||||||
|
<string name="stat_summary">送信済み: \t%3$s\t↑\t%1$s/s\n受け取る: \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">成功: %d ミリ秒の遅延</string>
|
||||||
|
<string name="connection_test_fail">インターネット利用不可</string>
|
||||||
|
<string name="connection_test_error">失敗します:%s</string>
|
||||||
|
<string name="connection_test_error_status_code">状態コード無効(#%d)</string>
|
||||||
|
|
||||||
|
<!-- profile -->
|
||||||
|
<string name="profile_manager_dialog">配置ファイル</string>
|
||||||
|
<string name="profile_manager_dialog_content">• クリックで配置ファイルに選択する;\n• 左/右へ滑るか左にクリックするで削除する;\n•
|
||||||
|
長押しやドラッグで順序を変える。</string>
|
||||||
|
<string name="gotcha">分かる</string>
|
||||||
|
<string name="copy_url">コピー URL</string>
|
||||||
|
<string name="add_profile_dialog">シャドーソックスに配置ファイルを加えますか</string>
|
||||||
|
<string name="add_profile_methods_scan_qr_code">QRコードを読み取る</string>
|
||||||
|
<string name="add_profile_methods_manual_settings">手動でセットアップ</string>
|
||||||
|
<string name="add_profile_nfc_hint_title">Android Beam (NFC) で配置ファイルを加える</string>
|
||||||
|
<string name="add_profile_nfc_hint">2台の設備を保持すると同時に、また別の設備に、配置ファイルの共有ボタンをクリックし、彼らをいっしょに置きます。\nNFC ラベルスがキャニングもできる。</string>
|
||||||
|
<string name="add_profile_scanner_permission_required">QRコードを読み取るはカメラ権限が必要である。</string>
|
||||||
|
|
||||||
|
<string-array name="route_entry">
|
||||||
|
<item>すべで</item>
|
||||||
|
<item>LANアドレスをバイパス</item>
|
||||||
|
<item>中国本土アドレスをバイパス</item>
|
||||||
|
<item>LANアドレスや中国本土アドレスをバイパス</item>
|
||||||
|
<item>中国本土で接続できないのアドレスだけを代理する</item>
|
||||||
|
<item>中国本土のアドレスだけを代理する</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string name="action_apply_all">すべでの配置ファイルに使用する</string>
|
||||||
|
<string name="action_export">クリップボードに輸出</string>
|
||||||
|
<string name="action_import">クリップボードからインポート</string>
|
||||||
|
<string name="action_export_msg">クリップボードに輸出成功</string>
|
||||||
|
<string name="action_export_err">クリップボードに輸出失敗</string>
|
||||||
|
<string name="action_import_msg">インポート成功</string>
|
||||||
|
<string name="action_import_err">インポート失敗</string>
|
||||||
|
|
||||||
|
<plurals name="removed">
|
||||||
|
<item quantity="one">削除しました</item>
|
||||||
|
<item quantity="other">%d アイテムを削除しました</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="undo">取り消し</string>
|
||||||
|
<string name="toggle_service_state">サービスを開始する</string>
|
||||||
|
<string name="start_service_default">当面のサーバー接続する</string>
|
||||||
|
<string name="start_service">%s に接続する</string>
|
||||||
|
<string name="stop_service">%s に切り替える</string>
|
||||||
|
<string name="profile_default">当面の配置を使用する</string>
|
||||||
|
|
||||||
|
<!-- status -->
|
||||||
|
<string name="sent">送信済み:</string>
|
||||||
|
<string name="received">受け取る:</string>
|
||||||
|
|
||||||
|
<!-- kcp -->
|
||||||
|
<string name="kcp_summary">KCP ロトコル を有効にする</string>
|
||||||
|
<string name="kcp_port">KCP ポート</string>
|
||||||
|
<string name="kcp_port_summary">%d(リモート KCPTUN サーバーのポート番号)</string>
|
||||||
|
<string name="kcpcli">KCP パラメータ</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -47,23 +47,6 @@
|
|||||||
<item>china-list</item>
|
<item>china-list</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="private_route">
|
|
||||||
<item>0.0.0.0/8</item>
|
|
||||||
<item>10.0.0.0/8</item>
|
|
||||||
<item>100.64.0.0/10</item>
|
|
||||||
<item>127.0.0.0/8</item>
|
|
||||||
<item>169.254.0.0/16</item>
|
|
||||||
<item>172.16.0.0/12</item>
|
|
||||||
<item>192.0.0.0/29</item>
|
|
||||||
<item>192.0.2.0/24</item>
|
|
||||||
<item>192.88.99.0/24</item>
|
|
||||||
<item>192.168.0.0/16</item>
|
|
||||||
<item>198.18.0.0/15</item>
|
|
||||||
<item>198.51.100.0/24</item>
|
|
||||||
<item>203.0.113.0/24</item>
|
|
||||||
<item>224.0.0.0/3</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string-array name="bypass_private_route">
|
<string-array name="bypass_private_route">
|
||||||
<item>1.0.0.0/8</item>
|
<item>1.0.0.0/8</item>
|
||||||
<item>2.0.0.0/7</item>
|
<item>2.0.0.0/7</item>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="black_list" translatable="false">".appspot.com",".blogspot.com",".blogspot.kr",".blogspot.sg",".cdninstagram.com",".connect.facebook.net",".facebook.br",".facebook.com",".facebook.hu",".facebook.nl",".facebook.se",".fbcdn.net",".google.co.kr",".google.com",".google.com",".google.com.hk",".google.com.sg",".google.com.tw",".googleapis.com",".googleapps.com",".googleartproject.com",".googleblog.com",".googlecode.com",".googlecommerce.com",".googledomains.com",".googledrive.com",".googleearth.com",".googlegroups.com",".googlehosted.com",".googleideas.com",".googlelabs.com",".googlemail.com",".googleplay.com",".googleplus.com",".googlesile.com",".googlesource.com",".googleusercontent.com",".googlevideo.com",".googlezip.net",".gstatic.com",".yahoo.com",".igoogle.com",".instagram.com",".institut-tibetain.org",".nic.google",".registry.google",".thinkwithgoogle.com",".withgoogle.com",".youtube-nocookie.com",".youtube.com",".gvt1.com",".gvt2.com",".gvt3.com",".1e100.net"</string>
|
<string name="black_list" translatable="false">".appspot.com",".blogspot.com",".blogspot.kr",".blogspot.sg",".cdninstagram.com",".connect.facebook.net",".facebook.br",".facebook.com",".facebook.hu",".facebook.nl",".facebook.se",".fbcdn.net",".google.co.jp",".google.co.kr",".google.com",".google.com",".google.com.hk",".google.com.sg",".google.com.tw",".googleapis.com",".googleapps.com",".googleartproject.com",".googleblog.com",".googlecode.com",".googlecommerce.com",".googledomains.com",".googledrive.com",".googleearth.com",".googlegroups.com",".googlehosted.com",".googleideas.com",".googlelabs.com",".googlemail.com",".googleplay.com",".googleplus.com",".googlesile.com",".googlesource.com",".googleusercontent.com",".googlevideo.com",".googlezip.net",".gstatic.com",".yahoo.com",".igoogle.com",".instagram.com",".institut-tibetain.org",".nic.google",".registry.google",".thinkwithgoogle.com",".withgoogle.com",".youtube-nocookie.com",".youtube.com",".gvt1.com",".gvt2.com",".gvt3.com",".1e100.net"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<shortcut android:shortcutId="toggle"
|
||||||
|
android:icon="@drawable/ic_qu_shadowsocks_launcher"
|
||||||
|
android:shortcutShortLabel="@string/quick_toggle"
|
||||||
|
android:shortcutLongLabel="@string/quick_toggle">
|
||||||
|
<intent android:action="android.intent.action.MAIN"
|
||||||
|
android:targetPackage="com.github.shadowsocks"
|
||||||
|
android:targetClass="com.github.shadowsocks.QuickToggleShortcut" />
|
||||||
|
</shortcut>
|
||||||
|
<shortcut android:shortcutId="switch"
|
||||||
|
android:icon="@drawable/ic_qu_shadowsocks_launcher"
|
||||||
|
android:shortcutShortLabel="@string/quick_switch"
|
||||||
|
android:shortcutLongLabel="@string/quick_switch">
|
||||||
|
<intent android:action="android.intent.action.MAIN"
|
||||||
|
android:targetPackage="com.github.shadowsocks"
|
||||||
|
android:targetClass="com.github.shadowsocks.ShadowsocksQuickSwitchActivity" />
|
||||||
|
</shortcut>
|
||||||
|
<shortcut android:shortcutId="scan"
|
||||||
|
android:icon="@drawable/ic_qu_camera_launcher"
|
||||||
|
android:shortcutShortLabel="@string/add_profile_methods_scan_qr_code"
|
||||||
|
android:shortcutLongLabel="@string/add_profile_methods_scan_qr_code">
|
||||||
|
<intent android:action="android.intent.action.MAIN"
|
||||||
|
android:targetPackage="com.github.shadowsocks"
|
||||||
|
android:targetClass="com.github.shadowsocks.ScannerActivity" />
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package be.mygod.preference
|
||||||
|
|
||||||
|
import android.app.DialogFragment
|
||||||
|
import android.support.v7.preference.DialogPreference
|
||||||
|
|
||||||
|
trait DialogPreferencePlus extends DialogPreference {
|
||||||
|
def createDialog(): DialogFragment
|
||||||
|
}
|
||||||
@@ -11,10 +11,12 @@ import android.util.AttributeSet
|
|||||||
* Based on: https://github.com/Gericop/Android-Support-Preference-V7-Fix/tree/master/app/src/main/java/android/support/v7/preference
|
* Based on: https://github.com/Gericop/Android-Support-Preference-V7-Fix/tree/master/app/src/main/java/android/support/v7/preference
|
||||||
*/
|
*/
|
||||||
class EditTextPreference(context: Context, attrs: AttributeSet = null) extends Parent(context, attrs)
|
class EditTextPreference(context: Context, attrs: AttributeSet = null) extends Parent(context, attrs)
|
||||||
with SummaryPreference {
|
with DialogPreferencePlus with SummaryPreference {
|
||||||
val editText = new AppCompatEditText(context, attrs)
|
val editText = new AppCompatEditText(context, attrs)
|
||||||
editText.setId(android.R.id.edit)
|
editText.setId(android.R.id.edit)
|
||||||
|
|
||||||
|
override def createDialog() = new EditTextPreferenceDialogFragment()
|
||||||
|
|
||||||
override protected def getSummaryValue = {
|
override protected def getSummaryValue = {
|
||||||
var text = getText
|
var text = getText
|
||||||
if (text == null) text = ""
|
if (text == null) text = ""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import android.widget.NumberPicker
|
|||||||
import com.github.shadowsocks.R
|
import com.github.shadowsocks.R
|
||||||
|
|
||||||
class NumberPickerPreference(private val context: Context, attrs: AttributeSet = null)
|
class NumberPickerPreference(private val context: Context, attrs: AttributeSet = null)
|
||||||
extends DialogPreference(context, attrs) with SummaryPreference {
|
extends DialogPreference(context, attrs) with DialogPreferencePlus with SummaryPreference {
|
||||||
private[preference] val picker = new NumberPicker(new ContextThemeWrapper(context, R.style.NumberPickerStyle))
|
private[preference] val picker = new NumberPicker(new ContextThemeWrapper(context, R.style.NumberPickerStyle))
|
||||||
private var value: Int = _
|
private var value: Int = _
|
||||||
|
|
||||||
@@ -20,6 +20,8 @@ class NumberPickerPreference(private val context: Context, attrs: AttributeSet =
|
|||||||
a.recycle
|
a.recycle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def createDialog() = new NumberPickerPreferenceDialogFragment()
|
||||||
|
|
||||||
def getValue = value
|
def getValue = value
|
||||||
def getMin = if (picker == null) 0 else picker.getMinValue
|
def getMin = if (picker == null) 0 else picker.getMinValue
|
||||||
def getMax = picker.getMaxValue
|
def getMax = picker.getMaxValue
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ package be.mygod.preference
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.support.v14.preference.PreferenceDialogFragment
|
import android.support.v14.preference.PreferenceDialogFragment
|
||||||
import android.view.inputmethod.InputMethodManager
|
|
||||||
import android.view.{View, ViewGroup}
|
import android.view.{View, ViewGroup}
|
||||||
|
|
||||||
class NumberPickerPreferenceDialogFragment extends PreferenceDialogFragment {
|
class NumberPickerPreferenceDialogFragment extends PreferenceDialogFragment {
|
||||||
private lazy val preference = getPreference.asInstanceOf[NumberPickerPreference]
|
private lazy val preference = getPreference.asInstanceOf[NumberPickerPreference]
|
||||||
private lazy val picker = preference.picker
|
private lazy val picker = preference.picker
|
||||||
private lazy val inputMethodManager =
|
|
||||||
getActivity.getSystemService(Context.INPUT_METHOD_SERVICE).asInstanceOf[InputMethodManager]
|
|
||||||
|
|
||||||
override protected def onCreateDialogView(context: Context) = {
|
override protected def onCreateDialogView(context: Context) = {
|
||||||
val parent = picker.getParent.asInstanceOf[ViewGroup]
|
val parent = picker.getParent.asInstanceOf[ViewGroup]
|
||||||
@@ -30,7 +27,5 @@ class NumberPickerPreferenceDialogFragment extends PreferenceDialogFragment {
|
|||||||
val value = picker.getValue
|
val value = picker.getValue
|
||||||
if (preference.callChangeListener(value)) preference.setValue(value)
|
if (preference.callChangeListener(value)) preference.setValue(value)
|
||||||
}
|
}
|
||||||
inputMethodManager.hideSoftInputFromWindow(getActivity.getCurrentFocus.getWindowToken,
|
|
||||||
InputMethodManager.HIDE_NOT_ALWAYS)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package be.mygod.preference
|
|||||||
import android.app.DialogFragment
|
import android.app.DialogFragment
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v14.preference.{PreferenceFragment => Base}
|
import android.support.v14.preference.{PreferenceFragment => Base}
|
||||||
import android.support.v7.preference.PreferenceScreen
|
import android.support.v7.preference.{Preference, PreferenceScreen}
|
||||||
import android.view.{LayoutInflater, ViewGroup}
|
import android.view.{LayoutInflater, ViewGroup}
|
||||||
|
|
||||||
abstract class PreferenceFragment extends Base {
|
abstract class PreferenceFragment extends Base {
|
||||||
@@ -15,7 +15,14 @@ abstract class PreferenceFragment extends Base {
|
|||||||
bundle.putString("key", key)
|
bundle.putString("key", key)
|
||||||
fragment.setArguments(bundle)
|
fragment.setArguments(bundle)
|
||||||
fragment.setTargetFragment(this, 0)
|
fragment.setTargetFragment(this, 0)
|
||||||
fragment.show(getFragmentManager, "android.support.v14.preference.PreferenceFragment.DIALOG")
|
getFragmentManager.beginTransaction()
|
||||||
|
.add(fragment, "android.support.v14.preference.PreferenceFragment.DIALOG")
|
||||||
|
.commitAllowingStateLoss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onDisplayPreferenceDialog(preference: Preference) = preference match {
|
||||||
|
case dpp: DialogPreferencePlus => displayPreferenceDialog(preference.getKey, dpp.createDialog())
|
||||||
|
case _ => super.onDisplayPreferenceDialog(preference)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def onCreateAdapter(screen: PreferenceScreen) = new PreferenceGroupAdapter(screen)
|
override protected def onCreateAdapter(screen: PreferenceScreen) = new PreferenceGroupAdapter(screen)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ package com.github.shadowsocks
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
import android.Manifest.permission
|
import android.Manifest.permission
|
||||||
|
import android.app.TaskStackBuilder
|
||||||
import android.content._
|
import android.content._
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@@ -220,9 +221,11 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
|
|||||||
toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
|
toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
|
||||||
toolbar.setTitle(R.string.proxied_apps)
|
toolbar.setTitle(R.string.proxied_apps)
|
||||||
toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_material)
|
toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_material)
|
||||||
toolbar.setNavigationOnClickListener((v: View) => {
|
toolbar.setNavigationOnClickListener(_ => {
|
||||||
val intent = getParentActivityIntent
|
val intent = getParentActivityIntent
|
||||||
if (intent == null) finish else navigateUpTo(intent)
|
if (shouldUpRecreateTask(intent) || isTaskRoot)
|
||||||
|
TaskStackBuilder.create(this).addNextIntentWithParentStack(intent).startActivities()
|
||||||
|
else finish()
|
||||||
})
|
})
|
||||||
toolbar.inflateMenu(R.menu.app_manager_menu)
|
toolbar.inflateMenu(R.menu.app_manager_menu)
|
||||||
toolbar.setOnMenuItemClickListener(this)
|
toolbar.setOnMenuItemClickListener(this)
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package com.github.shadowsocks
|
|||||||
|
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.{Activity, TaskStackBuilder}
|
||||||
import android.content._
|
import android.content._
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.nfc.NfcAdapter.CreateNdefMessageCallback
|
import android.nfc.NfcAdapter.CreateNdefMessageCallback
|
||||||
import android.nfc.{NdefMessage, NdefRecord, NfcAdapter, NfcEvent}
|
import android.nfc.{NdefMessage, NdefRecord, NfcAdapter, NfcEvent}
|
||||||
import android.os.{Bundle, Handler}
|
import android.os.{Build, Bundle, Handler, UserManager}
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.support.v7.app.{AlertDialog, AppCompatActivity}
|
import android.support.v7.app.{AlertDialog, AppCompatActivity}
|
||||||
import android.support.v7.widget.RecyclerView.ViewHolder
|
import android.support.v7.widget.RecyclerView.ViewHolder
|
||||||
@@ -86,7 +86,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
val builder = new SpannableStringBuilder
|
val builder = new SpannableStringBuilder
|
||||||
val tx = item.tx + txTotal
|
val tx = item.tx + txTotal
|
||||||
val rx = item.rx + rxTotal
|
val rx = item.rx + rxTotal
|
||||||
builder.append(item.name)
|
builder.append(if (isDemoMode) "Profile #" + item.id else item.name)
|
||||||
if (tx != 0 || rx != 0) {
|
if (tx != 0 || rx != 0) {
|
||||||
val start = builder.length
|
val start = builder.length
|
||||||
builder.append(getString(R.string.stat_profiles,
|
builder.append(getString(R.string.stat_profiles,
|
||||||
@@ -186,6 +186,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
private var undoManager: UndoSnackbarManager[Profile] = _
|
private var undoManager: UndoSnackbarManager[Profile] = _
|
||||||
|
|
||||||
private lazy val clipboard = getSystemService(Context.CLIPBOARD_SERVICE).asInstanceOf[ClipboardManager]
|
private lazy val clipboard = getSystemService(Context.CLIPBOARD_SERVICE).asInstanceOf[ClipboardManager]
|
||||||
|
private lazy val isDemoMode = Build.VERSION.SDK_INT >= 25 && getSystemService(classOf[UserManager]).isDemoUser
|
||||||
|
|
||||||
private var nfcAdapter : NfcAdapter = _
|
private var nfcAdapter : NfcAdapter = _
|
||||||
private var nfcShareItem: Array[Byte] = _
|
private var nfcShareItem: Array[Byte] = _
|
||||||
@@ -202,9 +203,11 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
|
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
|
||||||
toolbar.setTitle(R.string.profiles)
|
toolbar.setTitle(R.string.profiles)
|
||||||
toolbar.setNavigationIcon(R.drawable.ic_navigation_close)
|
toolbar.setNavigationIcon(R.drawable.ic_navigation_close)
|
||||||
toolbar.setNavigationOnClickListener((v: View) => {
|
toolbar.setNavigationOnClickListener(_ => {
|
||||||
val intent = getParentActivityIntent
|
val intent = getParentActivityIntent
|
||||||
if (intent == null) finish else navigateUpTo(intent)
|
if (shouldUpRecreateTask(intent) || isTaskRoot)
|
||||||
|
TaskStackBuilder.create(this).addNextIntentWithParentStack(intent).startActivities()
|
||||||
|
else finish()
|
||||||
})
|
})
|
||||||
toolbar.inflateMenu(R.menu.profile_manager_menu)
|
toolbar.inflateMenu(R.menu.profile_manager_menu)
|
||||||
toolbar.setOnMenuItemClickListener(this)
|
toolbar.setOnMenuItemClickListener(this)
|
||||||
@@ -292,7 +295,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
case R.id.fab_qrcode_add =>
|
case R.id.fab_qrcode_add =>
|
||||||
menu.toggle(false)
|
menu.toggle(false)
|
||||||
val intent = new Intent(this, classOf[ScannerActivity])
|
val intent = new Intent(this, classOf[ScannerActivity])
|
||||||
startActivityForResult(intent, REQUEST_QRCODE)
|
startActivity(intent)
|
||||||
case R.id.fab_nfc_add =>
|
case R.id.fab_nfc_add =>
|
||||||
menu.toggle(true)
|
menu.toggle(true)
|
||||||
val dialog = new AlertDialog.Builder(ProfileManagerActivity.this)
|
val dialog = new AlertDialog.Builder(ProfileManagerActivity.this)
|
||||||
@@ -382,14 +385,6 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
super.onDestroy
|
super.onDestroy
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
|
|
||||||
if (requestCode == REQUEST_QRCODE && resultCode == Activity.RESULT_OK) {
|
|
||||||
val contents = data.getStringExtra("uri")
|
|
||||||
if (!TextUtils.isEmpty(contents))
|
|
||||||
Parser.findAll(contents).foreach(app.profileManager.createProfile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onBackPressed() {
|
override def onBackPressed() {
|
||||||
if (menu.isOpened) menu.close(true) else super.onBackPressed()
|
if (menu.isOpened) menu.close(true) else super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.github.shadowsocks
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.ShortcutManager
|
||||||
|
import android.os.{Build, Bundle}
|
||||||
|
import com.github.shadowsocks.utils.{State, Utils}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mygod
|
||||||
|
*/
|
||||||
|
class QuickToggleShortcut extends Activity with ServiceBoundContext {
|
||||||
|
override def onCreate(savedInstanceState: Bundle) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
getIntent.getAction match {
|
||||||
|
case Intent.ACTION_CREATE_SHORTCUT =>
|
||||||
|
setResult(Activity.RESULT_OK, new Intent()
|
||||||
|
.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(this, classOf[QuickToggleShortcut]))
|
||||||
|
.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.quick_toggle))
|
||||||
|
.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
|
||||||
|
Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_launcher)))
|
||||||
|
finish()
|
||||||
|
case _ =>
|
||||||
|
attachService()
|
||||||
|
if (Build.VERSION.SDK_INT >= 25) getSystemService(classOf[ShortcutManager]).reportShortcutUsed("toggle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onDestroy() {
|
||||||
|
detachService()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onServiceConnected() {
|
||||||
|
bgService.getState match {
|
||||||
|
case State.STOPPED => Utils.startSsService(this)
|
||||||
|
case State.CONNECTED => Utils.stopSsService(this)
|
||||||
|
case _ => // ignore
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,28 @@
|
|||||||
package com.github.shadowsocks
|
package com.github.shadowsocks
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.{Activity, TaskStackBuilder}
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.{PackageManager, ShortcutManager}
|
||||||
import android.os.Bundle
|
import android.os.{Build, Bundle}
|
||||||
import android.support.v4.app.ActivityCompat
|
import android.support.v4.app.ActivityCompat
|
||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.support.v7.widget.Toolbar
|
import android.support.v7.widget.Toolbar
|
||||||
import android.view.{MenuItem, ViewGroup}
|
import android.text.TextUtils
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.google.zxing.Result
|
import com.google.zxing.Result
|
||||||
|
import com.github.shadowsocks.ShadowsocksApplication.app
|
||||||
|
import com.github.shadowsocks.utils.Parser
|
||||||
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||||
|
|
||||||
|
object ScannerActivity {
|
||||||
|
private final val MY_PERMISSIONS_REQUEST_CAMERA = 1
|
||||||
|
}
|
||||||
|
|
||||||
class ScannerActivity extends AppCompatActivity with ZXingScannerView.ResultHandler {
|
class ScannerActivity extends AppCompatActivity with ZXingScannerView.ResultHandler {
|
||||||
|
import ScannerActivity._
|
||||||
|
|
||||||
val MY_PERMISSIONS_REQUEST_CAMERA = 1
|
private var scannerView: ZXingScannerView = _
|
||||||
|
|
||||||
var scannerView: ZXingScannerView = _
|
|
||||||
|
|
||||||
override def onRequestPermissionsResult(requestCode: Int, permissions: Array[String],
|
override def onRequestPermissionsResult(requestCode: Int, permissions: Array[String],
|
||||||
grantResults: Array[Int]) {
|
grantResults: Array[Int]) {
|
||||||
@@ -34,14 +39,22 @@ class ScannerActivity extends AppCompatActivity with ZXingScannerView.ResultHand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def navigateUp() {
|
||||||
|
val intent = getParentActivityIntent
|
||||||
|
if (shouldUpRecreateTask(intent) || isTaskRoot)
|
||||||
|
TaskStackBuilder.create(this).addNextIntentWithParentStack(intent).startActivities()
|
||||||
|
else finish()
|
||||||
|
}
|
||||||
|
|
||||||
override def onCreate(state: Bundle) {
|
override def onCreate(state: Bundle) {
|
||||||
super.onCreate(state)
|
super.onCreate(state)
|
||||||
setContentView(R.layout.layout_scanner)
|
setContentView(R.layout.layout_scanner)
|
||||||
setupToolbar()
|
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
|
||||||
|
toolbar.setTitle(getTitle)
|
||||||
scannerView = new ZXingScannerView(this)
|
toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_material)
|
||||||
val contentFrame = findViewById(R.id.content_frame).asInstanceOf[ViewGroup]
|
toolbar.setNavigationOnClickListener(_ => navigateUp())
|
||||||
contentFrame.addView(scannerView)
|
scannerView = findViewById(R.id.scanner).asInstanceOf[ZXingScannerView]
|
||||||
|
if (Build.VERSION.SDK_INT >= 25) getSystemService(classOf[ShortcutManager]).reportShortcutUsed("scan")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onResume() {
|
override def onResume() {
|
||||||
@@ -63,32 +76,10 @@ class ScannerActivity extends AppCompatActivity with ZXingScannerView.ResultHand
|
|||||||
}
|
}
|
||||||
|
|
||||||
override def handleResult(rawResult: Result) = {
|
override def handleResult(rawResult: Result) = {
|
||||||
val intent = new Intent()
|
val uri = rawResult.getText
|
||||||
intent.putExtra("uri", rawResult.getText)
|
if (!TextUtils.isEmpty(uri))
|
||||||
setResult(Activity.RESULT_OK, intent)
|
Parser.findAll(uri).foreach(app.profileManager.createProfile)
|
||||||
finish()
|
navigateUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
def setupToolbar() {
|
|
||||||
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
|
|
||||||
setSupportActionBar(toolbar)
|
|
||||||
val ab = getSupportActionBar()
|
|
||||||
if (ab != null) {
|
|
||||||
ab.setDisplayHomeAsUpEnabled(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onOptionsItemSelected(item: MenuItem): Boolean = {
|
|
||||||
item.getItemId() match {
|
|
||||||
// Respond to the action bar's Up/Home button
|
|
||||||
case android.R.id.home =>
|
|
||||||
setResult(Activity.RESULT_CANCELED, new Intent())
|
|
||||||
finish()
|
|
||||||
return true
|
|
||||||
case _ => // Do nothing
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,9 +63,7 @@ import com.github.shadowsocks.database._
|
|||||||
import com.github.shadowsocks.utils.CloseUtils._
|
import com.github.shadowsocks.utils.CloseUtils._
|
||||||
import com.github.shadowsocks.utils._
|
import com.github.shadowsocks.utils._
|
||||||
import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
|
import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
|
||||||
import eu.chainfire.libsuperuser.Shell
|
|
||||||
|
|
||||||
import scala.collection.mutable.ArrayBuffer
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
object Typefaces {
|
object Typefaces {
|
||||||
@@ -189,8 +187,8 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override def binderDied {
|
override def binderDied {
|
||||||
detachService
|
detachService()
|
||||||
crashRecovery
|
app.crashRecovery()
|
||||||
attachService
|
attachService
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,23 +226,6 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def crashRecovery() {
|
|
||||||
val cmd = new ArrayBuffer[String]()
|
|
||||||
|
|
||||||
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks", "kcptun")) {
|
|
||||||
cmd.append("killall %s".formatLocal(Locale.ENGLISH, task))
|
|
||||||
cmd.append("rm -f %1$s/%2$s-nat.conf %1$s/%2$s-vpn.conf"
|
|
||||||
.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, task))
|
|
||||||
}
|
|
||||||
if (app.isNatEnabled) {
|
|
||||||
cmd.append("iptables -t nat -F OUTPUT")
|
|
||||||
cmd.append("echo done")
|
|
||||||
val result = Shell.SU.run(cmd.toArray)
|
|
||||||
if (result != null && !result.isEmpty) return // fallback to SH
|
|
||||||
}
|
|
||||||
Shell.SH.run(cmd.toArray)
|
|
||||||
}
|
|
||||||
|
|
||||||
def cancelStart() {
|
def cancelStart() {
|
||||||
clearDialog()
|
clearDialog()
|
||||||
changeSwitch(checked = false)
|
changeSwitch(checked = false)
|
||||||
@@ -371,10 +352,11 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
preferences.setEnabled(false)
|
preferences.setEnabled(false)
|
||||||
fabProgressCircle.postDelayed(hideCircle, 100)
|
fabProgressCircle.postDelayed(hideCircle, 100)
|
||||||
stat.setVisibility(View.VISIBLE)
|
stat.setVisibility(View.VISIBLE)
|
||||||
if (resetConnectionTest) if (app.isNatEnabled) connectionTestText.setVisibility(View.GONE) else {
|
if (resetConnectionTest || state != State.CONNECTED)
|
||||||
connectionTestText.setVisibility(View.VISIBLE)
|
if (app.isNatEnabled) connectionTestText.setVisibility(View.GONE) else {
|
||||||
connectionTestText.setText(getString(R.string.connection_test_pending))
|
connectionTestText.setVisibility(View.VISIBLE)
|
||||||
}
|
connectionTestText.setText(getString(R.string.connection_test_pending))
|
||||||
|
}
|
||||||
case State.STOPPING =>
|
case State.STOPPING =>
|
||||||
fab.setBackgroundTintList(greyTint)
|
fab.setBackgroundTintList(greyTint)
|
||||||
serviceStarted = false
|
serviceStarted = false
|
||||||
@@ -463,17 +445,11 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
handler.removeCallbacksAndMessages(null)
|
handler.removeCallbacksAndMessages(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
def reset() {
|
|
||||||
crashRecovery()
|
|
||||||
|
|
||||||
app.copyAssets()
|
|
||||||
}
|
|
||||||
|
|
||||||
def recovery() {
|
def recovery() {
|
||||||
if (serviceStarted) serviceStop()
|
if (serviceStarted) serviceStop()
|
||||||
val h = showProgress(R.string.recovering)
|
val h = showProgress(R.string.recovering)
|
||||||
Utils.ThrowableFuture {
|
Utils.ThrowableFuture {
|
||||||
reset()
|
app.copyAssets()
|
||||||
h.sendEmptyMessage(0)
|
h.sendEmptyMessage(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
|
|||||||
import com.j256.ormlite.logger.LocalLog
|
import com.j256.ormlite.logger.LocalLog
|
||||||
import eu.chainfire.libsuperuser.Shell
|
import eu.chainfire.libsuperuser.Shell
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
object ShadowsocksApplication {
|
object ShadowsocksApplication {
|
||||||
var app: ShadowsocksApplication = _
|
var app: ShadowsocksApplication = _
|
||||||
|
|
||||||
@@ -207,7 +209,25 @@ class ShadowsocksApplication extends Application {
|
|||||||
IOUtils.copy(in, out)))
|
IOUtils.copy(in, out)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def crashRecovery() {
|
||||||
|
val cmd = new ArrayBuffer[String]()
|
||||||
|
|
||||||
|
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks", "kcptun")) {
|
||||||
|
cmd.append("killall %s".formatLocal(Locale.ENGLISH, task))
|
||||||
|
cmd.append("rm -f %1$s/%2$s-nat.conf %1$s/%2$s-vpn.conf"
|
||||||
|
.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, task))
|
||||||
|
}
|
||||||
|
if (app.isNatEnabled) {
|
||||||
|
cmd.append("iptables -t nat -F OUTPUT")
|
||||||
|
cmd.append("echo done")
|
||||||
|
val result = Shell.SU.run(cmd.toArray)
|
||||||
|
if (result != null && !result.isEmpty) return // fallback to SH
|
||||||
|
}
|
||||||
|
Shell.SH.run(cmd.toArray)
|
||||||
|
}
|
||||||
|
|
||||||
def copyAssets() {
|
def copyAssets() {
|
||||||
|
crashRecovery() // ensure executables are killed before writing to them
|
||||||
copyAssets(System.getABI)
|
copyAssets(System.getABI)
|
||||||
copyAssets("acl")
|
copyAssets("acl")
|
||||||
Shell.SH.run(EXECUTABLES.map("chmod 755 " + getApplicationInfo.dataDir + '/' + _))
|
Shell.SH.run(EXECUTABLES.map("chmod 755 " + getApplicationInfo.dataDir + '/' + _))
|
||||||
|
|||||||
@@ -189,12 +189,12 @@ class ShadowsocksNatService extends BaseService {
|
|||||||
val conf = profile.route match {
|
val conf = profile.route match {
|
||||||
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN | Route.GFWLIST => {
|
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN | Route.GFWLIST => {
|
||||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "", getApplicationInfo.dataDir,
|
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "", getApplicationInfo.dataDir,
|
||||||
"127.0.0.1", profile.localPort + 53, "1.2.4.8, 114.114.114.114",
|
"127.0.0.1", profile.localPort + 53, "114.114.114.114, 223.5.5.5, 1.2.4.8",
|
||||||
getBlackList, reject, profile.localPort + 63, reject)
|
getBlackList, reject, profile.localPort + 63, reject)
|
||||||
}
|
}
|
||||||
case Route.CHINALIST => {
|
case Route.CHINALIST => {
|
||||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "", getApplicationInfo.dataDir,
|
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "", getApplicationInfo.dataDir,
|
||||||
"127.0.0.1", profile.localPort + 53, "8.8.8.8, 208.67.222.222",
|
"127.0.0.1", profile.localPort + 53, "8.8.8.8, 8.8.4.4, 208.67.222.222",
|
||||||
"", reject, profile.localPort + 63, reject)
|
"", reject, profile.localPort + 63, reject)
|
||||||
}
|
}
|
||||||
case _ => {
|
case _ => {
|
||||||
@@ -332,7 +332,8 @@ class ShadowsocksNatService extends BaseService {
|
|||||||
|
|
||||||
handleConnection()
|
handleConnection()
|
||||||
|
|
||||||
AclSyncJob.schedule(profile.route)
|
if (profile.route != Route.ALL)
|
||||||
|
AclSyncJob.schedule(profile.route)
|
||||||
|
|
||||||
changeState(State.CONNECTED)
|
changeState(State.CONNECTED)
|
||||||
notification = new ShadowsocksNotification(this, profile.name, true)
|
notification = new ShadowsocksNotification(this, profile.name, true)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
|
|||||||
.setContentIntent(PendingIntent.getActivity(service, 0, new Intent(service, classOf[Shadowsocks])
|
.setContentIntent(PendingIntent.getActivity(service, 0, new Intent(service, classOf[Shadowsocks])
|
||||||
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0))
|
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0))
|
||||||
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
|
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
|
||||||
if (!ShadowsocksTileService.running) builder.addAction(R.drawable.ic_navigation_close,
|
builder.addAction(R.drawable.ic_navigation_close,
|
||||||
service.getString(R.string.stop), PendingIntent.getBroadcast(service, 0, new Intent(Action.CLOSE), 0))
|
service.getString(R.string.stop), PendingIntent.getBroadcast(service, 0, new Intent(Action.CLOSE), 0))
|
||||||
app.profileManager.getAllProfiles match {
|
app.profileManager.getAllProfiles match {
|
||||||
case Some(profiles) => if (profiles.length > 1)
|
case Some(profiles) => if (profiles.length > 1)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.github.shadowsocks
|
package com.github.shadowsocks
|
||||||
|
|
||||||
|
import android.content.pm.ShortcutManager
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.os.{Build, Bundle}
|
import android.os.{Build, Bundle}
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
@@ -70,5 +71,6 @@ class ShadowsocksQuickSwitchActivity extends AppCompatActivity {
|
|||||||
if (app.profileId >= 0) lm.scrollToPosition(profilesAdapter.profiles.zipWithIndex.collectFirst {
|
if (app.profileId >= 0) lm.scrollToPosition(profilesAdapter.profiles.zipWithIndex.collectFirst {
|
||||||
case (profile, i) if profile.id == app.profileId => i
|
case (profile, i) if profile.id == app.profileId => i
|
||||||
}.getOrElse(0))
|
}.getOrElse(0))
|
||||||
|
if (Build.VERSION.SDK_INT >= 25) getSystemService(classOf[ShortcutManager]).reportShortcutUsed("switch")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class ShadowsocksRunnerService extends Service with ServiceBoundContext {
|
|||||||
if (bgService != null) {
|
if (bgService != null) {
|
||||||
if (app.isNatEnabled) startBackgroundService()
|
if (app.isNatEnabled) startBackgroundService()
|
||||||
else if (VpnService.prepare(ShadowsocksRunnerService.this) == null) startBackgroundService()
|
else if (VpnService.prepare(ShadowsocksRunnerService.this) == null) startBackgroundService()
|
||||||
handler.postDelayed(() => stopSelf(), 10000)
|
handler.postDelayed(() => stopSelf(), 3000)
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import java.util.Locale
|
|||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
import android.content.{Intent, SharedPreferences}
|
import android.content.{Intent, SharedPreferences}
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.{Build, Bundle, UserManager}
|
||||||
import android.support.design.widget.Snackbar
|
import android.support.design.widget.Snackbar
|
||||||
import android.support.v14.preference.SwitchPreference
|
import android.support.v14.preference.SwitchPreference
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
@@ -41,13 +41,21 @@ object ShadowsocksSettings {
|
|||||||
pref.asInstanceOf[SwitchPreference].setChecked(value)
|
pref.asInstanceOf[SwitchPreference].setChecked(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
def updatePreference(pref: Preference, name: String, profile: Profile) {
|
def updatePreference(pref: Preference, name: String, profile: Profile, demo: Boolean = false) {
|
||||||
name match {
|
name match {
|
||||||
case Key.name => updateEditTextPreference(pref, profile.name)
|
case Key.name =>
|
||||||
case Key.host => updateEditTextPreference(pref, profile.host)
|
updateEditTextPreference(pref, profile.name)
|
||||||
case Key.remotePort => updateNumberPickerPreference(pref, profile.remotePort)
|
pref.setSummary(if (demo) "Profile #" + profile.id else "%s")
|
||||||
|
case Key.host =>
|
||||||
|
updateEditTextPreference(pref, profile.host)
|
||||||
|
pref.setSummary(if (demo) "shadowsocks.example.org" else "%s")
|
||||||
|
case Key.remotePort =>
|
||||||
|
updateNumberPickerPreference(pref, profile.remotePort)
|
||||||
|
pref.setSummary(if (demo) "1337" else "%d")
|
||||||
case Key.localPort => updateNumberPickerPreference(pref, profile.localPort)
|
case Key.localPort => updateNumberPickerPreference(pref, profile.localPort)
|
||||||
case Key.password => updateEditTextPreference(pref, profile.password)
|
case Key.password =>
|
||||||
|
updateEditTextPreference(pref, profile.password)
|
||||||
|
pref.setSummary(if (demo) "\u2022" * 32 else "%s")
|
||||||
case Key.method => updateDropDownPreference(pref, profile.method)
|
case Key.method => updateDropDownPreference(pref, profile.method)
|
||||||
case Key.route => updateDropDownPreference(pref, profile.route)
|
case Key.route => updateDropDownPreference(pref, profile.route)
|
||||||
case Key.proxyApps => updateSwitchPreference(pref, profile.proxyApps)
|
case Key.proxyApps => updateSwitchPreference(pref, profile.proxyApps)
|
||||||
@@ -195,12 +203,8 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onDisplayPreferenceDialog(preference: Preference) = preference match {
|
override def onDisplayPreferenceDialog(preference: Preference) = preference.getKey match {
|
||||||
case _: EditTextPreference => displayPreferenceDialog(preference.getKey,
|
case Key.kcpcli => displayPreferenceDialog(Key.kcpcli, new KcpCliPreferenceDialogFragment())
|
||||||
if (preference.getKey == Key.kcpcli) new KcpCliPreferenceDialogFragment()
|
|
||||||
else new EditTextPreferenceDialogFragment())
|
|
||||||
case _: NumberPickerPreference =>
|
|
||||||
displayPreferenceDialog(preference.getKey, new NumberPickerPreferenceDialogFragment())
|
|
||||||
case _ => super.onDisplayPreferenceDialog(preference)
|
case _ => super.onDisplayPreferenceDialog(preference)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +252,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
|
|||||||
var profile: Profile = _
|
var profile: Profile = _
|
||||||
def setProfile(profile: Profile) {
|
def setProfile(profile: Profile) {
|
||||||
this.profile = profile
|
this.profile = profile
|
||||||
for (name <- Array(PROXY_PREFS, FEATURE_PREFS).flatten) updatePreference(findPreference(name), name, profile)
|
val demo = Build.VERSION.SDK_INT >= 25 && activity.getSystemService(classOf[UserManager]).isDemoUser
|
||||||
|
for (name <- Array(PROXY_PREFS, FEATURE_PREFS).flatten) updatePreference(findPreference(name), name, profile, demo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,8 @@ import com.github.shadowsocks.utils.{State, Utils}
|
|||||||
/**
|
/**
|
||||||
* @author Mygod
|
* @author Mygod
|
||||||
*/
|
*/
|
||||||
object ShadowsocksTileService {
|
|
||||||
var running: Boolean = _
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(24)
|
@TargetApi(24)
|
||||||
final class ShadowsocksTileService extends TileService with ServiceBoundContext {
|
final class ShadowsocksTileService extends TileService with ServiceBoundContext {
|
||||||
import ShadowsocksTileService._
|
|
||||||
|
|
||||||
private lazy val iconIdle = Icon.createWithResource(this, R.drawable.ic_start_idle).setTint(0x80ffffff)
|
private lazy val iconIdle = Icon.createWithResource(this, R.drawable.ic_start_idle).setTint(0x80ffffff)
|
||||||
private lazy val iconBusy = Icon.createWithResource(this, R.drawable.ic_start_busy)
|
private lazy val iconBusy = Icon.createWithResource(this, R.drawable.ic_start_busy)
|
||||||
@@ -46,15 +41,6 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
|
|||||||
|
|
||||||
override def onServiceConnected() = callback.stateChanged(bgService.getState, bgService.getProfileName, null)
|
override def onServiceConnected() = callback.stateChanged(bgService.getState, bgService.getProfileName, null)
|
||||||
|
|
||||||
override def onCreate {
|
|
||||||
super.onCreate
|
|
||||||
running = true
|
|
||||||
}
|
|
||||||
override def onDestroy {
|
|
||||||
super.onDestroy
|
|
||||||
running = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onStartListening {
|
override def onStartListening {
|
||||||
super.onStartListening
|
super.onStartListening
|
||||||
attachService(callback)
|
attachService(callback)
|
||||||
|
|||||||
@@ -164,7 +164,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
|||||||
handleConnection()
|
handleConnection()
|
||||||
changeState(State.CONNECTED)
|
changeState(State.CONNECTED)
|
||||||
|
|
||||||
AclSyncJob.schedule(profile.route)
|
if (profile.route != Route.ALL)
|
||||||
|
AclSyncJob.schedule(profile.route)
|
||||||
|
|
||||||
notification = new ShadowsocksNotification(this, profile.name)
|
notification = new ShadowsocksNotification(this, profile.name)
|
||||||
}
|
}
|
||||||
@@ -310,7 +311,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
|||||||
val conf = profile.route match {
|
val conf = profile.route match {
|
||||||
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN | Route.GFWLIST => {
|
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN | Route.GFWLIST => {
|
||||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, protect, getApplicationInfo.dataDir,
|
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, protect, getApplicationInfo.dataDir,
|
||||||
"0.0.0.0", profile.localPort + 53, "114.114.114.114, 119.29.29.29, 1.2.4.8",
|
"0.0.0.0", profile.localPort + 53, "114.114.114.114, 223.5.5.5, 1.2.4.8",
|
||||||
getBlackList, reject, profile.localPort + 63, reject)
|
getBlackList, reject, profile.localPort + 63, reject)
|
||||||
}
|
}
|
||||||
case Route.CHINALIST => {
|
case Route.CHINALIST => {
|
||||||
|
|||||||