From fa4b88dc95605920e346a8393edc4d06fbca5c0c Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 20:10:51 +0800 Subject: [PATCH 01/11] Update dependencies --- build.sbt | 8 ++++---- src/main/scala/com/github/shadowsocks/Shadowsocks.scala | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 45c762f1..5a83ff5c 100644 --- a/build.sbt +++ b/build.sbt @@ -32,10 +32,10 @@ libraryDependencies ++= Seq( "commons-net" % "commons-net" % "3.3", "com.google.zxing" % "android-integration" % "3.2.1", "net.glxn.qrgen" % "android" % "2.0", - "com.google.android.gms" % "play-services-base" % "8.1.0", - "com.google.android.gms" % "play-services-ads" % "8.1.0", - "com.google.android.gms" % "play-services-analytics" % "8.1.0", - "com.android.support" % "design" % "23.1.0", + "com.google.android.gms" % "play-services-base" % "8.3.0", + "com.google.android.gms" % "play-services-ads" % "8.3.0", + "com.google.android.gms" % "play-services-analytics" % "8.3.0", + "com.android.support" % "design" % "23.1.1", "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01", "com.j256.ormlite" % "ormlite-core" % "4.48", "com.j256.ormlite" % "ormlite-android" % "4.48" diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 3ce10ab7..2da2874c 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -138,7 +138,6 @@ object Shadowsocks { case Key.isUdpDns => updateSwitchPreference(pref, profile.udpdns) case Key.isAuth => updateSwitchPreference(pref, profile.auth) case Key.isIpv6 => updateSwitchPreference(pref, profile.ipv6) - case _ => } } } From eed2f47c831237c878610802832daa03e5a9c816 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 20:43:19 +0800 Subject: [PATCH 02/11] Trim styles --- src/main/res/values-v21/styles.xml | 36 ++---------------------------- src/main/res/values/styles.xml | 14 +++++++----- 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/main/res/values-v21/styles.xml b/src/main/res/values-v21/styles.xml index efa07058..3d6dc203 100644 --- a/src/main/res/values-v21/styles.xml +++ b/src/main/res/values-v21/styles.xml @@ -2,39 +2,7 @@ - - - - - - + - + + - From 95952f0fec96717633f4cbf07339ffc94cc6b0a2 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 21:19:20 +0800 Subject: [PATCH 03/11] Fix division by zero --- .../github/shadowsocks/utils/TrafficMonitor.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala index b762eb2e..e8ebf22e 100644 --- a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala +++ b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala @@ -1,9 +1,10 @@ package com.github.shadowsocks.utils +import java.lang.{Math, System} +import java.util.Locale + import android.net.TrafficStats import android.os.Process -import java.lang.{String, System, Math} -import java.util.Locale case class Traffic(tx: Long, rx: Long, timestamp: Long) @@ -40,8 +41,11 @@ object TrafficMonitor { def update() { val now = getTraffic - txRate = (now.tx - last.tx) / (now.timestamp - last.timestamp) - rxRate = (now.rx - last.rx) / (now.timestamp - last.timestamp) + val delta = now.timestamp - last.timestamp + if (delta != 0) { + txRate = (now.tx - last.tx) / delta + rxRate = (now.rx - last.rx) / delta + } txTotal += (now.tx - last.tx) / 1024 rxTotal += (now.rx - last.rx) / 1024 last = now From 14414c644d73ed5ebf7fe7d65f85153e200d1b53 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 21:40:33 +0800 Subject: [PATCH 04/11] Copy feature settings from the current profile to the new profile. And fix #432. --- .../github/shadowsocks/ParserActivity.scala | 2 +- .../shadowsocks/ProfileManagerActivity.scala | 2 +- .../shadowsocks/database/ProfileManager.scala | 26 ++++++++++++------- .../shadowsocks/utils/TrafficMonitor.scala | 3 +-- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/ParserActivity.scala b/src/main/scala/com/github/shadowsocks/ParserActivity.scala index 6d24af45..f1265ccd 100644 --- a/src/main/scala/com/github/shadowsocks/ParserActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ParserActivity.scala @@ -61,7 +61,7 @@ class ParserActivity extends Activity { .setTitle(R.string.add_profile_dialog) .setCancelable(false) .setPositiveButton(android.R.string.yes, ((dialog: DialogInterface, id: Int) => { - ShadowsocksApplication.profileManager.createOrUpdateProfile(profile.get) + ShadowsocksApplication.profileManager.createProfile(profile.get) dialog.dismiss() }): DialogInterface.OnClickListener) .setNegativeButton(android.R.string.no, ((dialog: DialogInterface, id: Int) => { diff --git a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala index 8bbebe0c..5297827a 100644 --- a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala @@ -153,7 +153,7 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) if (scanResult != null) Parser.parse(scanResult.getContents) match { - case Some(profile) => ShadowsocksApplication.profileManager.createOrUpdateProfile(profile) + case Some(profile) => ShadowsocksApplication.profileManager.createProfile(profile) case _ => // ignore } } diff --git a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala index fd2cda35..b83fb597 100644 --- a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala +++ b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala @@ -49,15 +49,27 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { var profileAddedListener: Profile => Any = _ def setProfileAddedListener(listener: Profile => Any) = this.profileAddedListener = listener - def createOrUpdateProfile(profile: Profile): Boolean = { + def createProfile(p: Profile = null): Profile = { try { + val profile = if (p == null) new Profile else p + profile.id = 0 + ShadowsocksApplication.currentProfile match { + case Some(oldProfile) => + // Copy Feature Settings from old profile + profile.route = oldProfile.route + profile.ipv6 = oldProfile.ipv6 + profile.proxyApps = oldProfile.proxyApps + profile.individual = oldProfile.individual + profile.udpdns = oldProfile.udpdns + case _ => + } dbHelper.profileDao.createOrUpdate(profile) if (profileAddedListener != null) profileAddedListener(profile) - true + profile } catch { case ex: Exception => Log.e(Shadowsocks.TAG, "addProfile", ex) - false + p } } @@ -114,11 +126,7 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { def load(id: Int): Profile = { - val profile = getProfile(id) getOrElse { - val p = new Profile() - createOrUpdateProfile(p) - p - } + val profile = getProfile(id) getOrElse createProfile() val edit = settings.edit() edit.putBoolean(Key.isProxyApps, profile.proxyApps) @@ -175,7 +183,7 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { remotePort = 443 password = "u1rRWTssNv0p" } - createOrUpdateProfile(profile) + createProfile(profile) profile } } diff --git a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala index e8ebf22e..00a737bf 100644 --- a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala +++ b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala @@ -20,7 +20,7 @@ object TrafficMonitor { var txTotal: Long = 0 var rxTotal: Long = 0 - def getTraffic(): Traffic = { + def getTraffic: Traffic = { new Traffic(Math.max(TrafficStats.getTotalTxBytes - TrafficStats.getUidTxBytes(uid), 0), Math.max(TrafficStats.getTotalRxBytes - TrafficStats.getUidRxBytes(uid), 0), System.currentTimeMillis()) } @@ -84,4 +84,3 @@ object TrafficMonitor { } } -class TrafficMonitor () From 3f8acd85abfabbc9abf3e4ebeb17d5b5defc65ef Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 22:12:31 +0800 Subject: [PATCH 05/11] Optimize timer code. Apparently onStop will be executed when the screen goes off. --- .../com/github/shadowsocks/Shadowsocks.scala | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 2da2874c..dcfc103c 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -475,15 +475,12 @@ class Shadowsocks } else { TrafficMonitor.reset() } - val pm = getSystemService(Context.POWER_SERVICE).asInstanceOf[PowerManager] - if (pm.isScreenOn) { - val trafficStat = getString(R.string.stat_summary).formatLocal(Locale.ENGLISH, - TrafficMonitor.getTxRate, TrafficMonitor.getRxRate, - TrafficMonitor.getTxTotal, TrafficMonitor.getRxTotal) - handler.post(() => { - preferences.findPreference(Key.stat).setSummary(trafficStat) - }) - } + val trafficStat = getString(R.string.stat_summary).formatLocal(Locale.ENGLISH, + TrafficMonitor.getTxRate, TrafficMonitor.getRxRate, + TrafficMonitor.getTxTotal, TrafficMonitor.getRxTotal) + handler.post(() => { + preferences.findPreference(Key.stat).setSummary(trafficStat) + }) } } timer = new Timer(true) From a57d631ef282d5b3393582486aadc1fe71afd55f Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 22:16:21 +0800 Subject: [PATCH 06/11] Add some spaces --- src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ba72d186..397155f6 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -13,7 +13,7 @@ Use NAT mode instead of VPN mode NAT mode is disabled without root Network Traffic - Send:\t%1$s\t|\tReceive:\t%2$s\nUpload:\t%3$s\t|\tDownload:\t%4$s + Send: \t%1$s\t|\tReceive: \t%2$s\nUpload: \t%3$s\t|\tDownload: \t%4$s Server Settings From f4401f8b9381f5a412d6efd9e7a69bb70114c848 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 22:18:51 +0800 Subject: [PATCH 07/11] Optimize DBHelper --- .../shadowsocks/database/DBHelper.scala | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/database/DBHelper.scala b/src/main/scala/com/github/shadowsocks/database/DBHelper.scala index 627d6b48..3df2e5d5 100644 --- a/src/main/scala/com/github/shadowsocks/database/DBHelper.scala +++ b/src/main/scala/com/github/shadowsocks/database/DBHelper.scala @@ -65,35 +65,36 @@ class DBHelper(val context: Context) if (oldVersion < 7) { profileDao.executeRawNoArgs("DROP TABLE IF EXISTS 'profile';") onCreate(database, connectionSource) - } else { - if (oldVersion < 8) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;") - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") - } - if (oldVersion < 9) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") - } - if (oldVersion < 10) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;") - } - if (oldVersion < 11) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;") - } - if (oldVersion < 12) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") - onCreate(database, connectionSource) - profileDao.executeRawNoArgs( - "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," + - " udpdns, auth, ipv6, individual) " + - "SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, auth," + - " ipv6, individual FROM `tmp`;") - profileDao.executeRawNoArgs("DROP TABLE `tmp`;") - } - if (oldVersion < 13) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN tx LONG;") - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN rx LONG;") - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN date DATE;") - } + return + } + if (oldVersion < 8) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") + } + if (oldVersion < 9) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") + } + if (oldVersion < 10) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;") + } + if (oldVersion < 11) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;") + } + if (oldVersion < 12) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") + onCreate(database, connectionSource) + profileDao.executeRawNoArgs( + "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," + + " udpdns, auth, ipv6, individual) " + + "SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, auth," + + " ipv6, individual FROM `tmp`;") + profileDao.executeRawNoArgs("DROP TABLE `tmp`;") + return + } + if (oldVersion < 13) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN tx LONG;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN rx LONG;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN date DATE;") } } } From 509a4e79fc5a41406900bfe53e019c4a697f9ad9 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 23:06:25 +0800 Subject: [PATCH 08/11] Add network traffic display in profile selector --- src/main/res/values-zh/strings.xml | 4 +++ src/main/res/values/strings.xml | 5 ++++ .../shadowsocks/ProfileManagerActivity.scala | 19 +++++++++++-- .../shadowsocks/utils/TrafficMonitor.scala | 28 +++++++++---------- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index 02d6f29d..75a7070a 100755 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -74,6 +74,10 @@ 网络流量 发送:\t%1$s\t|\t接收:\t%2$s\n上传:\t%3$s\t|\t下载:\t%4$s + \n发送:\t%1$s\t|\t接收:\t%2$s + + 字节 + 为影梭添加此配置文件? diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 397155f6..888e211a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -14,6 +14,11 @@ NAT mode is disabled without root Network Traffic Send: \t%1$s\t|\tReceive: \t%2$s\nUpload: \t%3$s\t|\tDownload: \t%4$s + \nSend: \t%1$s\t|\tReceive: \t%2$s + + Byte + Bytes + Server Settings diff --git a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala index 5297827a..975a0a38 100644 --- a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala @@ -10,11 +10,13 @@ import android.support.v7.widget.Toolbar.OnMenuItemClickListener import android.support.v7.widget.helper.ItemTouchHelper import android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar} +import android.text.style.TextAppearanceSpan +import android.text.{Spanned, SpannableStringBuilder} import android.view.View.{OnAttachStateChangeListener, OnClickListener} import android.view.{LayoutInflater, MenuItem, View, ViewGroup} import android.widget.{LinearLayout, ImageView, CheckedTextView, Toast} import com.github.shadowsocks.database.Profile -import com.github.shadowsocks.utils.{Parser, Utils} +import com.github.shadowsocks.utils.{TrafficMonitor, Parser, Utils} import com.google.zxing.integration.android.IntentIntegrator import net.glxn.qrgen.android.QRCode @@ -54,10 +56,21 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe }) } + def updateText() { + val builder = new SpannableStringBuilder + builder.append(item.name) + val start = builder.length + builder.append(getString(R.string.stat_profiles, + TrafficMonitor.formatTraffic(item.tx), TrafficMonitor.formatTraffic(item.rx))) + builder.setSpan(new TextAppearanceSpan(ProfileManagerActivity.this, android.R.style.TextAppearance_Small), + start + 1, builder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + text.setText(builder) + } + def bind(item: Profile) { - text.setText(item.name) - text.setChecked(item.id == ShadowsocksApplication.profileId) this.item = item + updateText() + text.setChecked(item.id == ShadowsocksApplication.profileId) } def onClick(v: View) = { diff --git a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala index 00a737bf..3236a026 100644 --- a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala +++ b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitor.scala @@ -1,10 +1,11 @@ package com.github.shadowsocks.utils import java.lang.{Math, System} -import java.util.Locale +import java.text.DecimalFormat import android.net.TrafficStats import android.os.Process +import com.github.shadowsocks.{R, ShadowsocksApplication} case class Traffic(tx: Long, rx: Long, timestamp: Long) @@ -25,18 +26,17 @@ object TrafficMonitor { Math.max(TrafficStats.getTotalRxBytes - TrafficStats.getUidRxBytes(uid), 0), System.currentTimeMillis()) } - def formatTraffic(n: Long): String = { - if (n <= 1024) { - "%d KB".formatLocal(Locale.ENGLISH, n) - } else if (n > 1024) { - "%d MB".formatLocal(Locale.ENGLISH, n / 1024) - } else if (n > 1024 * 1024) { - "%d GB".formatLocal(Locale.ENGLISH, n / 1024 / 1024) - } else if (n > 1024 * 1024 * 1024) { - "%d TB".formatLocal(Locale.ENGLISH, n / 1024 / 1024 / 1024) - } else { - ">1024 TB" + private val units = Array("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB") + private val numberFormat = new DecimalFormat("0.00") + def formatTraffic(size: Long): String = { + var n: Double = size + var i = -1 + while (n >= 1024) { + n /= 1024 + i = i + 1 } + if (i < 0) size + " " + ShadowsocksApplication.instance.getResources.getQuantityString(R.plurals.bytes, size.toInt) + else numberFormat.format(n) + ' ' + units(i) } def update() { @@ -46,8 +46,8 @@ object TrafficMonitor { txRate = (now.tx - last.tx) / delta rxRate = (now.rx - last.rx) / delta } - txTotal += (now.tx - last.tx) / 1024 - rxTotal += (now.rx - last.rx) / 1024 + txTotal += now.tx - last.tx + rxTotal += now.rx - last.rx last = now } From 79ade0ef7f276f870798726412cfb3844a955aa3 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 23:06:52 +0800 Subject: [PATCH 09/11] Fix stat_summary --- src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 888e211a..bc12046f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -13,8 +13,8 @@ Use NAT mode instead of VPN mode NAT mode is disabled without root Network Traffic - Send: \t%1$s\t|\tReceive: \t%2$s\nUpload: \t%3$s\t|\tDownload: \t%4$s - \nSend: \t%1$s\t|\tReceive: \t%2$s + Sent: \t%1$s\t|\tReceived: \t%2$s\nUpload: \t%3$s\t|\tDownload: \t%4$s + \nSent: \t%1$s\t|\tReceived: \t%2$s Byte Bytes From c4c1682983c04f5bf1c23a9e70ca4ba1c16df562 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 23:15:36 +0800 Subject: [PATCH 10/11] Fix flashing --- src/main/scala/com/github/shadowsocks/Shadowsocks.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index dcfc103c..a93a2813 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -483,6 +483,7 @@ class Shadowsocks }) } } + task.run() timer = new Timer(true) timer.schedule(task, TIMER_INTERVAL * 1000, TIMER_INTERVAL * 1000) } From 9adf11713fa5a1f8b9fc5ddb24d9f603eac3bd7e Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 18 Nov 2015 23:15:56 +0800 Subject: [PATCH 11/11] Hide stats for profiles that have no traffic --- .../github/shadowsocks/ProfileManagerActivity.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala index 975a0a38..ce69db3c 100644 --- a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala @@ -59,11 +59,13 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe def updateText() { val builder = new SpannableStringBuilder builder.append(item.name) - val start = builder.length - builder.append(getString(R.string.stat_profiles, - TrafficMonitor.formatTraffic(item.tx), TrafficMonitor.formatTraffic(item.rx))) - builder.setSpan(new TextAppearanceSpan(ProfileManagerActivity.this, android.R.style.TextAppearance_Small), - start + 1, builder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + if (item.tx != 0 || item.rx != 0) { + val start = builder.length + builder.append(getString(R.string.stat_profiles, + TrafficMonitor.formatTraffic(item.tx), TrafficMonitor.formatTraffic(item.rx))) + builder.setSpan(new TextAppearanceSpan(ProfileManagerActivity.this, android.R.style.TextAppearance_Small), + start + 1, builder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + } text.setText(builder) }