From 713ff53030856822e171f5609e8ed476724b3bb7 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 24 Jan 2016 16:11:18 +0800 Subject: [PATCH] Refine Traffic Stat --- project/plugins.sbt | 5 +- src/main/res/layout/status_pref.xml | 108 ++++++++++++++++++ src/main/res/values-zh/strings.xml | 16 ++- src/main/res/values/strings.xml | 14 ++- src/main/res/xml/pref_all.xml | 5 +- .../com/github/shadowsocks/Shadowsocks.scala | 19 ++- .../shadowsocks/ShadowsocksSettings.scala | 10 +- .../preferences/StatusPreference.scala | 46 ++++++++ 8 files changed, 204 insertions(+), 19 deletions(-) create mode 100644 src/main/res/layout/status_pref.xml create mode 100644 src/main/scala/com/github/shadowsocks/preferences/StatusPreference.scala diff --git a/project/plugins.sbt b/project/plugins.sbt index c7b6fae9..82d45b05 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,8 +1,11 @@ resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns) -addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.13") + +addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.14") resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" + addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.7.0-SNAPSHOT") resolvers += Resolver.url("rtimush/sbt-plugin-snapshots", new URL("https://dl.bintray.com/rtimush/sbt-plugin-snapshots/"))(Resolver.ivyStylePatterns) + addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.9-6-g5a7705c") diff --git a/src/main/res/layout/status_pref.xml b/src/main/res/layout/status_pref.xml new file mode 100644 index 00000000..80e7fa5c --- /dev/null +++ b/src/main/res/layout/status_pref.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index f7d28474..0fbd0408 100755 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -75,14 +75,13 @@ 网络流量 发送: \t%3$s\t↑\t%1$s/s\n接收: \t%4$s\t↓\t%2$s/s - - 字节 - - 点击检查是否接入互联网。 + + 检查网络连接 测试中…… - 已接入互联网。(延时:%d 毫秒) + 连接有效: 延时 %d 毫秒 + 无互联网连接 失败:%s - 状态码无效。(#%d) + 状态码无效(#%d) 配置文件 @@ -114,4 +113,9 @@ 切换到 %s 使用当前配置 + + 发送: + 接收: + 检查网络连接 + diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index bc35aa22..89320c23 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -19,11 +19,12 @@ Byte Bytes - Tap to check Internet connection availability. + Check Connectivity Testing… - Internet connection available. (latency: %dms) - Fail: %s - Invalid status code. (#%d) + Success: %dms latency to Internet + Fail to detect internet connection: %s + Internet Unavailable + Error code: #%d Server Settings @@ -119,4 +120,9 @@ Connect to %s Switch to %s Use the current profile + + + Sent: + Received: + Check Connectivity diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml index c5d7a3b5..23447138 100644 --- a/src/main/res/xml/pref_all.xml +++ b/src/main/res/xml/pref_all.xml @@ -8,7 +8,10 @@ - + diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index e1a1cc3a..61e7f8a6 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -58,6 +58,7 @@ import android.view.{View, ViewGroup, ViewParent} import android.widget._ import com.github.jorgecastilloprz.FABProgressCircle import com.github.shadowsocks.aidl.IShadowsocksServiceCallback +import com.github.shadowsocks.preferences._ import com.github.shadowsocks.database._ import com.github.shadowsocks.utils._ import com.google.android.gms.ads.{AdRequest, AdSize, AdView} @@ -106,8 +107,9 @@ class Shadowsocks var state = State.STOPPED var currentProfile = new Profile var vpnEnabled = -1 - var trafficCache: String = _ + var trafficCache: Array[String] = _ var connectionTestResult: String = _ + var connectionTestSuccess: Boolean = true // Services var currentServiceName = classOf[ShadowsocksNatService].getName @@ -155,8 +157,9 @@ class Shadowsocks }) } def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) { - trafficCache = getString(R.string.stat_summary).formatLocal(Locale.ENGLISH, - TrafficMonitor.formatTraffic(txRate), TrafficMonitor.formatTraffic(rxRate), + trafficCache = Array( + "▲ " + TrafficMonitor.formatTraffic(txRate) + "/s", + "▼ " + TrafficMonitor.formatTraffic(rxRate) + "/s", TrafficMonitor.formatTraffic(txTotal), TrafficMonitor.formatTraffic(rxTotal)) handler.post(updateTraffic) } @@ -165,10 +168,16 @@ class Shadowsocks def updateTraffic(): Unit = if (trafficCache == null) callback.trafficUpdated(0, 0, 0, 0) else { if (connectionTestResult == null) connectionTestResult = getString(R.string.connection_test_pending) if (preferences.natSwitch.isChecked) { - preferences.stat.setSummary(trafficCache) + preferences.stat.setSummary("") } else { - preferences.stat.setSummary(connectionTestResult + "\n" + trafficCache) + if (connectionTestSuccess) { + preferences.stat.setSummary(connectionTestResult) + } else { + preferences.stat.setSummary(getString(R.string.connection_test_fail)) + Snackbar.make(findViewById(android.R.id.content), connectionTestResult, Snackbar.LENGTH_LONG).show + } } + preferences.stat.asInstanceOf[StatusPreference].setRate(trafficCache(2), trafficCache(3), trafficCache(0), trafficCache(1)) } def attachService: Unit = attachService(callback) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index a3a2d193..bd2902e0 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -78,11 +78,12 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan addPreferencesFromResource(R.xml.pref_all) getPreferenceManager.getSharedPreferences.registerOnSharedPreferenceChangeListener(this) - stat = findPreference(Key.stat) + stat= findPreference(Key.stat) stat.setOnPreferenceClickListener(_ => { val id = synchronized { testCount += 1 activity.connectionTestResult = getString(R.string.connection_test_testing) + activity.connectionTestSuccess = true activity.updateTraffic() testCount } @@ -96,6 +97,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan conn.setUseCaches(false) if (testCount == id) { var result: String = null + var success: Boolean = true try { val start = currentTimeMillis conn.getInputStream @@ -105,9 +107,13 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan result = getString(R.string.connection_test_available, elapsed: java.lang.Long) else throw new Exception(getString(R.string.connection_test_error_status_code, code: Integer)) } catch { - case e: Exception => result = getString(R.string.connection_test_error, e.getMessage) + case e: Exception => { + success = false + result = getString(R.string.connection_test_error, e.getMessage) + } } synchronized(if (testCount == id) { + activity.connectionTestSuccess = success activity.connectionTestResult = result activity.handler.post(activity.updateTraffic) }) diff --git a/src/main/scala/com/github/shadowsocks/preferences/StatusPreference.scala b/src/main/scala/com/github/shadowsocks/preferences/StatusPreference.scala new file mode 100644 index 00000000..2b198e5d --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/preferences/StatusPreference.scala @@ -0,0 +1,46 @@ +package com.github.shadowsocks.preferences + +import android.content.Context +import android.preference.Preference +import android.view.{View, ViewGroup, LayoutInflater} +import android.util.AttributeSet +import android.widget.TextView +import com.github.shadowsocks.R + +/** + * @author madeye + */ +final class StatusPreference(context: Context, attrs: AttributeSet = null) + extends Preference(context, attrs) { + var txView: TextView = null + var rxView: TextView = null + var txRateView: TextView = null + var rxRateView: TextView = null + + override def onCreateView(parent: ViewGroup): View = { + val li = getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE).asInstanceOf[LayoutInflater] + val view = li.inflate(R.layout.status_pref, parent, false) + + txView = view.findViewById(R.id.tx).asInstanceOf[TextView] + rxView = view.findViewById(R.id.rx).asInstanceOf[TextView] + txRateView = view.findViewById(R.id.txRate).asInstanceOf[TextView] + rxRateView = view.findViewById(R.id.rxRate).asInstanceOf[TextView] + + view + } + + def setRate(tx: String, rx: String, txRate: String, rxRate: String) { + if (txView != null) { + txView.setText(tx) + } + if (rxView != null) { + rxView.setText(rx) + } + if (txRateView != null) { + txRateView.setText(txRate) + } + if (rxRateView != null) { + rxRateView.setText(rxRate) + } + } +}