Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9517f0703 | ||
|
|
72f4586acb | ||
|
|
3d6daccbb1 | ||
|
|
33a8967f30 | ||
|
|
762da4c62f | ||
|
|
8e83272fa7 | ||
|
|
d17d791b3b | ||
|
|
63ae014581 | ||
|
|
95e1eee59f | ||
|
|
98df31c258 | ||
|
|
04092bf8e0 | ||
|
|
5e56bfec89 | ||
|
|
635105ca05 |
@@ -36,6 +36,7 @@ The exclamation mark in the Wi-Fi/cellular icon appears because the system fails
|
|||||||
* Samsung and/or Brevent: [#1410](https://github.com/shadowsocks/shadowsocks-android/issues/1410)
|
* Samsung and/or Brevent: [#1410](https://github.com/shadowsocks/shadowsocks-android/issues/1410)
|
||||||
* Another Samsung: [#1712](https://github.com/shadowsocks/shadowsocks-android/issues/1712)
|
* Another Samsung: [#1712](https://github.com/shadowsocks/shadowsocks-android/issues/1712)
|
||||||
* Don't install this app on SD card because of permission issues: [#1124 (comment)](https://github.com/shadowsocks/shadowsocks-android/issues/1124#issuecomment-307556453)
|
* Don't install this app on SD card because of permission issues: [#1124 (comment)](https://github.com/shadowsocks/shadowsocks-android/issues/1124#issuecomment-307556453)
|
||||||
|
* `INTERACT_ACROSS_USERS` permission missing: [#1184](https://github.com/shadowsocks/shadowsocks-android/issues/1184)
|
||||||
|
|
||||||
### How to pause Shadowsocks service?
|
### How to pause Shadowsocks service?
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -30,18 +30,6 @@ MKDIR %TARGET%\arm64-v8a>nul 2>nul
|
|||||||
|
|
||||||
SET CC=%ANDROID_ARM_TOOLCHAIN%\bin\arm-linux-androideabi-gcc.exe
|
SET CC=%ANDROID_ARM_TOOLCHAIN%\bin\arm-linux-androideabi-gcc.exe
|
||||||
|
|
||||||
REM Check environment availability
|
|
||||||
IF NOT EXIST %CC% (
|
|
||||||
ECHO "gcc not found"
|
|
||||||
EXIT 1
|
|
||||||
)
|
|
||||||
|
|
||||||
WHERE python.exe
|
|
||||||
IF "%ERRORLEVEL%" == 1 (
|
|
||||||
ECHO "python not found"
|
|
||||||
EXIT 1
|
|
||||||
)
|
|
||||||
|
|
||||||
IF NOT EXIST %ANDROID_ARM_CC% (
|
IF NOT EXIST %ANDROID_ARM_CC% (
|
||||||
ECHO "Make standalone toolchain for ARM arch"
|
ECHO "Make standalone toolchain for ARM arch"
|
||||||
python.exe %ANDROID_NDK_HOME%\build\tools\make_standalone_toolchain.py --arch arm ^
|
python.exe %ANDROID_NDK_HOME%\build\tools\make_standalone_toolchain.py --arch arm ^
|
||||||
@@ -60,6 +48,18 @@ IF NOT EXIST %ANDROID_X86_CC% (
|
|||||||
--api %MIN_API% --install-dir %ANDROID_X86_TOOLCHAIN%
|
--api %MIN_API% --install-dir %ANDROID_X86_TOOLCHAIN%
|
||||||
)
|
)
|
||||||
|
|
||||||
|
REM Check environment availability
|
||||||
|
IF NOT EXIST %CC% (
|
||||||
|
ECHO "gcc not found"
|
||||||
|
EXIT 1
|
||||||
|
)
|
||||||
|
|
||||||
|
WHERE python.exe
|
||||||
|
IF "%ERRORLEVEL%" == 1 (
|
||||||
|
ECHO "python not found"
|
||||||
|
EXIT 1
|
||||||
|
)
|
||||||
|
|
||||||
IF NOT EXIST %DIR%\go\bin\go.exe (
|
IF NOT EXIST %DIR%\go\bin\go.exe (
|
||||||
ECHO "Build the custom go"
|
ECHO "Build the custom go"
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ android {
|
|||||||
applicationId "com.github.shadowsocks"
|
applicationId "com.github.shadowsocks"
|
||||||
minSdkVersion rootProject.minSdkVersion
|
minSdkVersion rootProject.minSdkVersion
|
||||||
targetSdkVersion rootProject.sdkVersion
|
targetSdkVersion rootProject.sdkVersion
|
||||||
versionCode 4050600
|
versionCode 4050700
|
||||||
versionName "4.5.6"
|
versionName "4.5.7"
|
||||||
testApplicationId "com.github.shadowsocks.test"
|
testApplicationId "com.github.shadowsocks.test"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
resConfigs "fa", "fr", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
|
resConfigs "fa", "fr", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
|
||||||
|
|||||||
@@ -1,17 +1,3 @@
|
|||||||
0.0.0.0/8
|
|
||||||
10.0.0.0/8
|
|
||||||
100.64.0.0/10
|
|
||||||
127.0.0.0/8
|
|
||||||
169.254.0.0/16
|
|
||||||
172.16.0.0/12
|
|
||||||
192.0.0.0/29
|
|
||||||
192.0.2.0/24
|
|
||||||
192.88.99.0/24
|
|
||||||
192.168.0.0/16
|
|
||||||
198.18.0.0/15
|
|
||||||
198.51.100.0/24
|
|
||||||
203.0.113.0/24
|
|
||||||
224.0.0.0/3
|
|
||||||
1.0.1.0/24
|
1.0.1.0/24
|
||||||
1.0.2.0/23
|
1.0.2.0/23
|
||||||
1.0.8.0/21
|
1.0.8.0/21
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ class App : Application() {
|
|||||||
app = this
|
app = this
|
||||||
if (!BuildConfig.DEBUG) System.setProperty(LocalLog.LOCAL_LOG_LEVEL_PROPERTY, "ERROR")
|
if (!BuildConfig.DEBUG) System.setProperty(LocalLog.LOCAL_LOG_LEVEL_PROPERTY, "ERROR")
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java,
|
PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java,
|
||||||
BottomSheetPreferenceDialogFragment::class.java)
|
BottomSheetPreferenceDialogFragment::class.java)
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import android.support.v7.app.AlertDialog
|
|||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.support.v7.content.res.AppCompatResources
|
import android.support.v7.content.res.AppCompatResources
|
||||||
import android.support.v7.preference.PreferenceDataStore
|
import android.support.v7.preference.PreferenceDataStore
|
||||||
|
import android.text.format.Formatter
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
@@ -49,7 +50,6 @@ import com.github.shadowsocks.aidl.IShadowsocksService
|
|||||||
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
||||||
import com.github.shadowsocks.bg.BaseService
|
import com.github.shadowsocks.bg.BaseService
|
||||||
import com.github.shadowsocks.bg.Executable
|
import com.github.shadowsocks.bg.Executable
|
||||||
import com.github.shadowsocks.bg.TrafficMonitor
|
|
||||||
import com.github.shadowsocks.database.Profile
|
import com.github.shadowsocks.database.Profile
|
||||||
import com.github.shadowsocks.database.ProfileManager
|
import com.github.shadowsocks.database.ProfileManager
|
||||||
import com.github.shadowsocks.preference.DataStore
|
import com.github.shadowsocks.preference.DataStore
|
||||||
@@ -149,10 +149,10 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
|
|||||||
stateListener?.invoke(state)
|
stateListener?.invoke(state)
|
||||||
}
|
}
|
||||||
fun updateTraffic(profileId: Int, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
|
fun updateTraffic(profileId: Int, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
|
||||||
txText.text = TrafficMonitor.formatTraffic(txTotal)
|
txText.text = Formatter.formatFileSize(this, txTotal)
|
||||||
rxText.text = TrafficMonitor.formatTraffic(rxTotal)
|
rxText.text = Formatter.formatFileSize(this, rxTotal)
|
||||||
txRateText.text = getString(R.string.speed, TrafficMonitor.formatTraffic(txRate))
|
txRateText.text = getString(R.string.speed, Formatter.formatFileSize(this, txRate))
|
||||||
rxRateText.text = getString(R.string.speed, TrafficMonitor.formatTraffic(rxRate))
|
rxRateText.text = getString(R.string.speed, Formatter.formatFileSize(this, rxRate))
|
||||||
val child = supportFragmentManager.findFragmentById(R.id.fragment_holder) as ToolbarFragment?
|
val child = supportFragmentManager.findFragmentById(R.id.fragment_holder) as ToolbarFragment?
|
||||||
if (state != BaseService.STOPPING)
|
if (state != BaseService.STOPPING)
|
||||||
child?.onTrafficUpdated(profileId, txRate, rxRate, txTotal, rxTotal)
|
child?.onTrafficUpdated(profileId, txRate, rxRate, txTotal, rxTotal)
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ import android.support.design.widget.Snackbar
|
|||||||
import android.support.v4.app.DialogFragment
|
import android.support.v4.app.DialogFragment
|
||||||
import android.support.v7.widget.*
|
import android.support.v7.widget.*
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper
|
import android.support.v7.widget.helper.ItemTouchHelper
|
||||||
|
import android.text.format.Formatter
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import com.github.shadowsocks.App.Companion.app
|
import com.github.shadowsocks.App.Companion.app
|
||||||
import com.github.shadowsocks.bg.BaseService
|
import com.github.shadowsocks.bg.BaseService
|
||||||
import com.github.shadowsocks.bg.TrafficMonitor
|
|
||||||
import com.github.shadowsocks.database.Profile
|
import com.github.shadowsocks.database.Profile
|
||||||
import com.github.shadowsocks.database.ProfileManager
|
import com.github.shadowsocks.database.ProfileManager
|
||||||
import com.github.shadowsocks.plugin.PluginConfiguration
|
import com.github.shadowsocks.plugin.PluginConfiguration
|
||||||
@@ -159,10 +159,11 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
|
|||||||
text2.visibility = View.VISIBLE
|
text2.visibility = View.VISIBLE
|
||||||
text2.text = t2.joinToString("\n")
|
text2.text = t2.joinToString("\n")
|
||||||
}
|
}
|
||||||
|
val context = requireContext()
|
||||||
if (tx <= 0 && rx <= 0) traffic.visibility = View.GONE else {
|
if (tx <= 0 && rx <= 0) traffic.visibility = View.GONE else {
|
||||||
traffic.visibility = View.VISIBLE
|
traffic.visibility = View.VISIBLE
|
||||||
traffic.text = getString(R.string.traffic,
|
traffic.text = getString(R.string.traffic,
|
||||||
TrafficMonitor.formatTraffic(tx), TrafficMonitor.formatTraffic(rx))
|
Formatter.formatFileSize(context, tx), Formatter.formatFileSize(context, rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.id == DataStore.profileId) {
|
if (item.id == DataStore.profileId) {
|
||||||
@@ -179,7 +180,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
|
|||||||
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT)
|
ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
params.gravity = Gravity.CENTER_HORIZONTAL
|
params.gravity = Gravity.CENTER_HORIZONTAL
|
||||||
val context = requireContext()
|
|
||||||
adView = AdView(context)
|
adView = AdView(context)
|
||||||
adView.layoutParams = params
|
adView.layoutParams = params
|
||||||
adView.adUnitId = "ca-app-pub-9097031975646651/7760346322"
|
adView.adUnitId = "ca-app-pub-9097031975646651/7760346322"
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.os.Build
|
|||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.support.v4.app.NotificationCompat
|
import android.support.v4.app.NotificationCompat
|
||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.text.format.Formatter
|
||||||
import com.github.shadowsocks.MainActivity
|
import com.github.shadowsocks.MainActivity
|
||||||
import com.github.shadowsocks.R
|
import com.github.shadowsocks.R
|
||||||
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
||||||
@@ -55,11 +56,11 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam
|
|||||||
override fun stateChanged(state: Int, profileName: String?, msg: String?) { } // ignore
|
override fun stateChanged(state: Int, profileName: String?, msg: String?) { } // ignore
|
||||||
override fun trafficUpdated(profileId: Int, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
|
override fun trafficUpdated(profileId: Int, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
|
||||||
service as Context
|
service as Context
|
||||||
val txr = service.getString(R.string.speed, TrafficMonitor.formatTraffic(txRate))
|
val txr = service.getString(R.string.speed, Formatter.formatFileSize(service, txRate))
|
||||||
val rxr = service.getString(R.string.speed, TrafficMonitor.formatTraffic(rxRate))
|
val rxr = service.getString(R.string.speed, Formatter.formatFileSize(service, rxRate))
|
||||||
builder.setContentText("$txr↑\t$rxr↓")
|
builder.setContentText("$txr↑\t$rxr↓")
|
||||||
style.bigText(service.getString(R.string.stat_summary).format(Locale.ENGLISH, txr, rxr,
|
style.bigText(service.getString(R.string.stat_summary).format(Locale.ENGLISH, txr, rxr,
|
||||||
TrafficMonitor.formatTraffic(txTotal), TrafficMonitor.formatTraffic(rxTotal)))
|
Formatter.formatFileSize(service, txTotal), Formatter.formatFileSize(service, rxTotal)))
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
override fun trafficPersisted(profileId: Int) { }
|
override fun trafficPersisted(profileId: Int) { }
|
||||||
|
|||||||
@@ -21,9 +21,6 @@
|
|||||||
package com.github.shadowsocks.bg
|
package com.github.shadowsocks.bg
|
||||||
|
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import com.github.shadowsocks.App.Companion.app
|
|
||||||
import com.github.shadowsocks.R
|
|
||||||
import java.text.DecimalFormat
|
|
||||||
|
|
||||||
object TrafficMonitor {
|
object TrafficMonitor {
|
||||||
// Bytes per second
|
// Bytes per second
|
||||||
@@ -41,19 +38,6 @@ object TrafficMonitor {
|
|||||||
@Volatile
|
@Volatile
|
||||||
private var dirty = true
|
private var dirty = true
|
||||||
|
|
||||||
private val units = arrayOf("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB")
|
|
||||||
private val numberFormat = DecimalFormat("@@@")
|
|
||||||
fun formatTraffic(size: Long): String {
|
|
||||||
var n = size.toDouble()
|
|
||||||
var i = -1
|
|
||||||
while (n >= 999.5) {
|
|
||||||
n /= 1024
|
|
||||||
++i
|
|
||||||
}
|
|
||||||
return if (i < 0) "$size ${app.resources.getQuantityString(R.plurals.bytes, size.toInt())}"
|
|
||||||
else "${numberFormat.format(n)} ${units[i]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateRate(): Boolean {
|
fun updateRate(): Boolean {
|
||||||
val now = SystemClock.elapsedRealtime()
|
val now = SystemClock.elapsedRealtime()
|
||||||
val delta = now - timestampLast
|
val delta = now - timestampLast
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp">
|
||||||
<Spinner android:id="@+id/template_selector"
|
<Spinner android:id="@+id/template_selector"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -20,10 +20,6 @@
|
|||||||
<string name="traffic">%s↑\t%s↓</string>
|
<string name="traffic">%s↑\t%s↓</string>
|
||||||
<string name="stat_summary">Sent: \t\t\t\t\t%3$s\t↑\t%1$s\nReceived: \t%4$s\t↓\t%2$s</string>
|
<string name="stat_summary">Sent: \t\t\t\t\t%3$s\t↑\t%1$s\nReceived: \t%4$s\t↓\t%2$s</string>
|
||||||
<string name="speed">%s/s</string>
|
<string name="speed">%s/s</string>
|
||||||
<plurals name="bytes">
|
|
||||||
<item quantity="one">Byte</item>
|
|
||||||
<item quantity="other">Bytes</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="connection_test_pending">Check Connectivity</string>
|
<string name="connection_test_pending">Check Connectivity</string>
|
||||||
<string name="connection_test_testing">Testing…</string>
|
<string name="connection_test_testing">Testing…</string>
|
||||||
<string name="connection_test_available">Success: %dms latency</string>
|
<string name="connection_test_available">Success: %dms latency</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user