Files
shadowsocks-android/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala
T
Mygod 80d93a84bd Add support for TCP Fast Open (#809)
* Add support for TCP Fast Open

* Remove useless echo done line

* Check return values before proceeding in TcpFastOpen.enabled
2016-08-16 14:37:21 +08:00

241 lines
9.2 KiB
Scala

package com.github.shadowsocks
import java.util.Locale
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.content.{Intent, SharedPreferences}
import android.net.Uri
import android.os.Bundle
import android.preference.{Preference, PreferenceFragment, SwitchPreference}
import android.support.v7.app.AlertDialog
import android.webkit.{WebView, WebViewClient}
import com.github.shadowsocks.ShadowsocksApplication.app
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.preferences._
import com.github.shadowsocks.utils.{Key, TcpFastOpen, Utils}
object ShadowsocksSettings {
// Constants
private final val TAG = "ShadowsocksSettings"
private val PROXY_PREFS = Array(Key.name, Key.host, Key.remotePort, Key.localPort, Key.password, Key.method,
Key.auth, Key.kcp, Key.kcpPort, Key.kcpcli)
private val FEATURE_PREFS = Array(Key.route, Key.proxyApps, Key.udpdns, Key.ipv6)
// Helper functions
def updateDropDownPreference(pref: Preference, value: String) {
pref.asInstanceOf[DropDownPreference].setValue(value)
}
def updatePasswordEditTextPreference(pref: Preference, value: String) {
pref.setSummary(value)
pref.asInstanceOf[PasswordEditTextPreference].setText(value)
}
def updateNumberPickerPreference(pref: Preference, value: Int) {
pref.asInstanceOf[NumberPickerPreference].setValue(value)
}
def updateSummaryEditTextPreference(pref: Preference, value: String) {
pref.setSummary(value)
pref.asInstanceOf[SummaryEditTextPreference].setText(value)
}
def updateSwitchPreference(pref: Preference, value: Boolean) {
pref.asInstanceOf[SwitchPreference].setChecked(value)
}
def updatePreference(pref: Preference, name: String, profile: Profile) {
name match {
case Key.name => updateSummaryEditTextPreference(pref, profile.name)
case Key.host => updateSummaryEditTextPreference(pref, profile.host)
case Key.remotePort => updateNumberPickerPreference(pref, profile.remotePort)
case Key.localPort => updateNumberPickerPreference(pref, profile.localPort)
case Key.password => updatePasswordEditTextPreference(pref, profile.password)
case Key.method => updateDropDownPreference(pref, profile.method)
case Key.route => updateDropDownPreference(pref, profile.route)
case Key.proxyApps => updateSwitchPreference(pref, profile.proxyApps)
case Key.udpdns => updateSwitchPreference(pref, profile.udpdns)
case Key.auth => updateSwitchPreference(pref, profile.auth)
case Key.ipv6 => updateSwitchPreference(pref, profile.ipv6)
case Key.kcp => updateSwitchPreference(pref, profile.kcp)
case Key.kcpPort => updateNumberPickerPreference(pref, profile.kcpPort)
case Key.kcpcli => updateSummaryEditTextPreference(pref, profile.kcpcli)
}
}
}
class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChangeListener {
import ShadowsocksSettings._
private def activity = getActivity.asInstanceOf[Shadowsocks]
lazy val natSwitch = findPreference(Key.isNAT).asInstanceOf[SwitchPreference]
private var isProxyApps: SwitchPreference = _
override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_all)
getPreferenceManager.getSharedPreferences.registerOnSharedPreferenceChangeListener(this)
findPreference(Key.name).setOnPreferenceChangeListener((_, value) => {
profile.name = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
findPreference(Key.host).setOnPreferenceChangeListener((_, value) => {
profile.host = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
findPreference(Key.remotePort).setOnPreferenceChangeListener((_, value) => {
profile.remotePort = value.asInstanceOf[Int]
app.profileManager.updateProfile(profile)
})
findPreference(Key.localPort).setOnPreferenceChangeListener((_, value) => {
profile.localPort = value.asInstanceOf[Int]
app.profileManager.updateProfile(profile)
})
findPreference(Key.password).setOnPreferenceChangeListener((_, value) => {
profile.password = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
findPreference(Key.method).setOnPreferenceChangeListener((_, value) => {
profile.method = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
findPreference(Key.route).setOnPreferenceChangeListener((_, value) => {
profile.route = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
findPreference(Key.kcp).setOnPreferenceChangeListener((_, value) => {
profile.kcp = value.asInstanceOf[Boolean]
app.profileManager.updateProfile(profile)
})
findPreference(Key.kcpPort).setOnPreferenceChangeListener((_, value) => {
profile.kcpPort = value.asInstanceOf[Int]
app.profileManager.updateProfile(profile)
})
findPreference(Key.kcpcli).setOnPreferenceChangeListener((_, value) => {
profile.kcpcli = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
isProxyApps = findPreference(Key.proxyApps).asInstanceOf[SwitchPreference]
isProxyApps.setOnPreferenceClickListener(_ => {
startActivity(new Intent(activity, classOf[AppManager]))
isProxyApps.setChecked(true)
false
})
isProxyApps.setOnPreferenceChangeListener((_, value) => {
profile.proxyApps = value.asInstanceOf[Boolean]
app.profileManager.updateProfile(profile)
})
findPreference(Key.udpdns).setOnPreferenceChangeListener((_, value) => {
profile.udpdns = value.asInstanceOf[Boolean]
app.profileManager.updateProfile(profile)
})
findPreference(Key.auth).setOnPreferenceChangeListener((_, value) => {
profile.auth = value.asInstanceOf[Boolean]
app.profileManager.updateProfile(profile)
})
findPreference(Key.ipv6).setOnPreferenceChangeListener((_, value) => {
profile.ipv6 = value.asInstanceOf[Boolean]
app.profileManager.updateProfile(profile)
})
val switch = findPreference(Key.isAutoConnect).asInstanceOf[SwitchPreference]
switch.setOnPreferenceChangeListener((_, value) => {
BootReceiver.setEnabled(activity, value.asInstanceOf[Boolean])
true
})
if (getPreferenceManager.getSharedPreferences.getBoolean(Key.isAutoConnect, false)) {
BootReceiver.setEnabled(activity, true)
getPreferenceManager.getSharedPreferences.edit.remove(Key.isAutoConnect).apply
}
switch.setChecked(BootReceiver.getEnabled(activity))
val tfo = findPreference("tcp_fastopen").asInstanceOf[SwitchPreference]
tfo.setChecked(TcpFastOpen.sendEnabled)
tfo.setOnPreferenceChangeListener((_, v) => {
val value = v.asInstanceOf[Boolean]
TcpFastOpen.enabled(value)
value == TcpFastOpen.sendEnabled
})
if (!TcpFastOpen.supported) {
tfo.setEnabled(false)
tfo.setSummary(getString(R.string.tcp_fastopen_summary_unsupported, java.lang.System.getProperty("os.version")))
}
findPreference("recovery").setOnPreferenceClickListener((preference: Preference) => {
app.track(TAG, "reset")
activity.recovery()
true
})
findPreference("flush_dnscache").setOnPreferenceClickListener(_ => {
app.track(TAG, "flush_dnscache")
activity.flushDnsCache()
true
})
findPreference("about").setOnPreferenceClickListener((preference: Preference) => {
app.track(TAG, "about")
val web = new WebView(activity)
web.loadUrl("file:///android_asset/pages/about.html")
web.setWebViewClient(new WebViewClient() {
override def shouldOverrideUrlLoading(view: WebView, url: String): Boolean = {
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)))
} catch {
case _: android.content.ActivityNotFoundException => // Ignore
}
true
}
})
new AlertDialog.Builder(activity)
.setTitle(getString(R.string.about_title).formatLocal(Locale.ENGLISH, app.getVersionName))
.setNegativeButton(getString(android.R.string.ok), null)
.setView(web)
.create()
.show()
true
})
}
def refreshProfile() {
profile = app.currentProfile.get
isProxyApps.setChecked(profile.proxyApps)
}
override def onDestroy {
super.onDestroy()
app.settings.unregisterOnSharedPreferenceChangeListener(this)
}
def onSharedPreferenceChanged(pref: SharedPreferences, key: String) = key match {
case Key.isNAT =>
activity.handler.post(() => {
activity.detachService
activity.attachService
})
case _ =>
}
private var enabled = true
def setEnabled(enabled: Boolean) {
this.enabled = enabled
for (name <- Key.isNAT #:: PROXY_PREFS.toStream #::: FEATURE_PREFS.toStream) {
val pref = findPreference(name)
if (pref != null) pref.setEnabled(enabled &&
(name != Key.proxyApps || Utils.isLollipopOrAbove || app.isNatEnabled))
}
}
var profile: Profile = _
def setProfile(profile: Profile) {
this.profile = profile
for (name <- Array(PROXY_PREFS, FEATURE_PREFS).flatten) updatePreference(findPreference(name), name, profile)
}
}