Commit b505ff37 authored by Mygod's avatar Mygod

Move NAT/VPN switch to a more user-friendly place

parent 51e155c9
......@@ -38,16 +38,16 @@
<string name="service_running">已连接到「%s」</string>
<string name="service_failed">无法连接远程服务器</string>
<string name="stop">停止服务</string>
<string name="stopping">正在关闭...</string>
<string name="stopping">正在关闭……</string>
<string name="vpn_error">后台服务启动失败:%s</string>
<string name="close">关闭</string>
<string name="port_alert">本地端口号应大于1024</string>
<string name="port_empty">端口号不能为空</string>
<string name="proxy_empty">代理服务器地址不能为空</string>
<string name="connect">连接</string>
<string name="initializing">正在初始化...</string>
<string name="recovering">重置中...</string>
<string name="loading">正在加载...</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>
......@@ -55,13 +55,10 @@
<string name="about">关于</string>
<string name="about_title">影梭(shadowsocks)%s</string>
<string name="flush_dnscache">刷新 DNS 缓存</string>
<string name="flushing">刷新中...</string>
<string name="flushing">刷新中……</string>
<string name="qrcode">二维码</string>
<string name="add_profile">添加配置文件</string>
<string name="enable_nat">启用 NAT 模式.</string>
<string name="disable_nat">禁用 NAT 模式.</string>
<string name="udp_dns">UDP 转发</string>
<string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string>
......
......@@ -8,6 +8,9 @@
<string name="global_cat">Global Settings</string>
<string name="profile">Profile</string>
<string name="profile_summary">Switch to another profile</string>
<string name="nat">NAT mode</string>
<string name="nat_summary">Use NAT/VPN mode.</string>
<string name="nat_summary_no_root">NAT mode is disabled without root.</string>
<!-- proxy category -->
<string name="proxy_cat">Server Settings</string>
......@@ -55,10 +58,8 @@
<string name="service_running">Connected to "%s"</string>
<string name="service_failed">Failed to connect the remote server</string>
<string name="stop">Stop the service</string>
<string name="stopping">Shutting down...</string>
<string name="stopping">Shutting down</string>
<string name="vpn_error">%s</string>
<string name="enable_nat">Turn on NAT mode.</string>
<string name="disable_nat">Turn off NAT mode.</string>
<!-- alert category -->
<string name="close">Close</string>
......
......@@ -7,7 +7,9 @@
<Preference android:summary="@string/profile_summary" android:title="@string/profile">
<intent android:action="com.github.shadowsocks.ProfileManagerActivity"/>
</Preference>
<!-- TODO: VPN/NAT SwitchPreference -->
<com.github.shadowsocks.preferences.NatSwitchPreference android:key="isNAT"
android:title="@string/nat"
android:summary="@string/nat_summary"/>
<SwitchPreference
android:key="isAutoConnect"
android:summary="@string/auto_connect_summary"
......
......@@ -197,8 +197,8 @@ class Shadowsocks
if (fab != null) fab.setEnabled(true)
stateUpdate()
if (!status.getBoolean(ShadowsocksApplication.getVersionName, false)) {
status.edit.putBoolean(ShadowsocksApplication.getVersionName, true).apply()
if (!ShadowsocksApplication.settings.getBoolean(ShadowsocksApplication.getVersionName, false)) {
ShadowsocksApplication.settings.edit.putBoolean(ShadowsocksApplication.getVersionName, true).apply()
recovery()
}
}
......@@ -216,7 +216,6 @@ class Shadowsocks
private lazy val preferences =
getFragmentManager.findFragmentById(android.R.id.content).asInstanceOf[ShadowsocksSettings]
private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
private lazy val greyTint = ContextCompat.getColorStateList(this, R.color.material_blue_grey_700)
private lazy val greenTint = ContextCompat.getColorStateList(this, R.color.material_green_600)
......@@ -340,7 +339,7 @@ class Shadowsocks
def prepareStartService() {
Future {
if (isVpnEnabled) {
if (ShadowsocksApplication.isVpnEnabled) {
val intent = VpnService.prepare(this)
if (intent != null) {
startActivityForResult(intent, Shadowsocks.REQUEST_CONNECT)
......@@ -374,7 +373,7 @@ class Shadowsocks
}
// Update the profile
if (!status.getBoolean(ShadowsocksApplication.getVersionName, false)) {
if (!ShadowsocksApplication.settings.getBoolean(ShadowsocksApplication.getVersionName, false)) {
currentProfile = ShadowsocksApplication.profileManager.create()
}
......@@ -396,21 +395,6 @@ class Shadowsocks
ShadowsocksApplication.track(TAG, "about")
showAbout()
})
title.setOnLongClickListener((v: View) => {
if (Utils.isLollipopOrAbove && bgService != null
&& (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) {
val natEnabled = !status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove)
status.edit().putBoolean(Key.isNAT, natEnabled).apply()
deattachService()
attachService()
if (!Utils.isLollipopOrAbove) setPreferenceEnabled(State.isAvailable(bgService.getState))
Toast.makeText(getBaseContext, if (natEnabled) R.string.enable_nat else R.string.disable_nat, Toast.LENGTH_LONG)
.show()
true
} else {
false
}
})
fab = findViewById(R.id.fab).asInstanceOf[FloatingActionButton]
fabProgressCircle = findViewById(R.id.fabProgressCircle).asInstanceOf[FABProgressCircle]
......@@ -446,7 +430,8 @@ class Shadowsocks
def attachService() {
if (bgService == null) {
val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService]
val s = if (ShadowsocksApplication.isVpnEnabled) classOf[ShadowsocksVpnService]
else classOf[ShadowsocksNatService]
val intent = new Intent(this, s)
intent.setAction(Action.SERVICE)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
......@@ -526,6 +511,7 @@ class Shadowsocks
}
private def setPreferenceEnabled(enabled: Boolean) {
preferences.findPreference(Key.isNAT).setEnabled(enabled)
for (name <- Shadowsocks.PROXY_PREFS) {
val pref = preferences.findPreference(name)
if (pref != null) {
......@@ -537,7 +523,7 @@ class Shadowsocks
if (pref != null) {
if (Seq(Key.isGlobalProxy, Key.proxyedApps)
.contains(name)) {
pref.setEnabled(enabled && (Utils.isLollipopOrAbove || !isVpnEnabled))
pref.setEnabled(enabled && (Utils.isLollipopOrAbove || !ShadowsocksApplication.isVpnEnabled))
} else {
pref.setEnabled(enabled)
}
......@@ -628,12 +614,6 @@ class Shadowsocks
Log.e(Shadowsocks.TAG, "Failed to start VpnService")
}
var isRoot: Option[Boolean] = None
def isVpnEnabled: Boolean = {
if (isRoot.isEmpty) isRoot = Some(Console.isRoot)
!(isRoot.get && status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove))
}
def serviceStop() {
if (bgService != null) bgService.stop()
}
......@@ -666,7 +646,7 @@ class Shadowsocks
def serviceStart() {
bgService.start(ConfigUtils.load(ShadowsocksApplication.settings))
if (isVpnEnabled) {
if (ShadowsocksApplication.isVpnEnabled) {
changeSwitch(checked = false)
}
}
......
......@@ -46,8 +46,8 @@ import android.app.Application
import android.content.pm.PackageManager
import android.preference.PreferenceManager
import com.github.shadowsocks.database.{DBHelper, ProfileManager}
import com.github.shadowsocks.utils.{Key, Utils}
import com.google.android.gms.analytics.{HitBuilders, GoogleAnalytics}
import com.github.shadowsocks.utils.{Console, Key, Utils}
import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders}
import com.google.android.gms.common.api.ResultCallback
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
......@@ -60,6 +60,9 @@ object ShadowsocksApplication {
lazy val settings = PreferenceManager.getDefaultSharedPreferences(instance)
lazy val profileManager = new ProfileManager(settings, dbHelper)
val isRoot = Console.isRoot
def isVpnEnabled = !(isRoot && settings.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove))
def getVersionName = try {
instance.getPackageManager.getPackageInfo(instance.getPackageName, 0).versionName
} catch {
......
......@@ -39,12 +39,7 @@
package com.github.shadowsocks
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.preference.PreferenceManager
import android.content.{BroadcastReceiver, Context, Intent}
import com.github.shadowsocks.utils._
class ShadowsocksReceiver extends BroadcastReceiver {
......@@ -52,18 +47,8 @@ class ShadowsocksReceiver extends BroadcastReceiver {
val TAG = "Shadowsocks"
def onReceive(context: Context, intent: Intent) {
val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val status = context.getSharedPreferences(Key.status, Context.MODE_PRIVATE)
var versionName: String = null
try {
versionName = context.getPackageManager.getPackageInfo(context.getPackageName, 0).versionName
} catch {
case e: PackageManager.NameNotFoundException =>
versionName = "NONE"
}
val isAutoConnect: Boolean = settings.getBoolean(Key.isAutoConnect, false)
val isInstalled: Boolean = status.getBoolean(versionName, false)
val isAutoConnect: Boolean = ShadowsocksApplication.settings.getBoolean(Key.isAutoConnect, false)
val isInstalled: Boolean = ShadowsocksApplication.settings.getBoolean(ShadowsocksApplication.getVersionName, false)
if (isAutoConnect && isInstalled) {
if (Utils.isLollipopOrAbove) {
val intent = new Intent(context, classOf[ShadowsocksRunnerService])
......
......@@ -40,19 +40,15 @@
package com.github.shadowsocks
import android.app.{Activity, KeyguardManager}
import android.os._
import android.net.VpnService
import android.content._
import android.net.VpnService
import android.os._
import android.util.Log
import android.preference.PreferenceManager
import com.github.shadowsocks.utils._
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.utils._
class ShadowsocksRunnerActivity extends Activity {
private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
val handler = new Handler()
val connection = new ServiceConnection {
override def onServiceConnected(name: ComponentName, service: IBinder) {
......@@ -65,18 +61,12 @@ class ShadowsocksRunnerActivity extends Activity {
}
// Variables
var isRoot: Option[Boolean] = None
var bgService: IShadowsocksService = _
var receiver:BroadcastReceiver = _
def isVpnEnabled: Boolean = {
if (isRoot.isEmpty) isRoot = Some(Console.isRoot)
!(isRoot.get && status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove))
}
def startBackgroundService() {
if (isVpnEnabled) {
if (ShadowsocksApplication.isVpnEnabled) {
val intent = VpnService.prepare(ShadowsocksRunnerActivity.this)
if (intent != null) {
startActivityForResult(intent, Shadowsocks.REQUEST_CONNECT)
......@@ -84,14 +74,15 @@ class ShadowsocksRunnerActivity extends Activity {
onActivityResult(Shadowsocks.REQUEST_CONNECT, Activity.RESULT_OK, null)
}
} else {
bgService.start(ConfigUtils.load(settings))
bgService.start(ConfigUtils.load(ShadowsocksApplication.settings))
finish()
}
}
def attachService() {
if (bgService == null) {
val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService]
val s = if (ShadowsocksApplication.isVpnEnabled) classOf[ShadowsocksVpnService]
else classOf[ShadowsocksNatService]
val intent = new Intent(this, s)
intent.setAction(Action.SERVICE)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
......@@ -137,7 +128,7 @@ class ShadowsocksRunnerActivity extends Activity {
resultCode match {
case Activity.RESULT_OK =>
if (bgService != null) {
bgService.start(ConfigUtils.load(settings))
bgService.start(ConfigUtils.load(ShadowsocksApplication.settings))
}
case _ =>
Log.e(Shadowsocks.TAG, "Failed to start VpnService")
......
......@@ -43,15 +43,10 @@ import android.app.Service
import android.content._
import android.net.VpnService
import android.os._
import android.preference.PreferenceManager
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.utils._
class ShadowsocksRunnerService extends Service {
private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
val handler = new Handler()
val connection = new ServiceConnection {
override def onServiceConnected(name: ComponentName, service: IBinder) {
......@@ -64,35 +59,29 @@ class ShadowsocksRunnerService extends Service {
}
// Variables
var isRoot: Option[Boolean] = None
var bgService: IShadowsocksService = _
def isVpnEnabled: Boolean = {
if (isRoot.isEmpty) isRoot = Some(Console.isRoot)
!(isRoot.get && status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove))
}
override def onBind(intent: Intent): IBinder = {
null
}
def startBackgroundService() {
if (isVpnEnabled) {
if (ShadowsocksApplication.isVpnEnabled) {
val intent = VpnService.prepare(ShadowsocksRunnerService.this)
if (intent == null) {
if (bgService != null) {
bgService.start(ConfigUtils.load(settings))
bgService.start(ConfigUtils.load(ShadowsocksApplication.settings))
}
}
} else {
bgService.start(ConfigUtils.load(settings))
bgService.start(ConfigUtils.load(ShadowsocksApplication.settings))
}
stopSelf()
}
def attachService() {
if (bgService == null) {
val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService]
val s = if (!ShadowsocksApplication.isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService]
val intent = new Intent(this, s)
intent.setAction(Action.SERVICE)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
......
......@@ -2,6 +2,7 @@ package com.github.shadowsocks
import android.os.Bundle
import android.preference.{Preference, PreferenceFragment}
import com.github.shadowsocks.utils.Key
// TODO: Move related logic here
class ShadowsocksSettings extends PreferenceFragment {
......@@ -10,6 +11,12 @@ class ShadowsocksSettings extends PreferenceFragment {
override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_all)
findPreference(Key.isNAT).setOnPreferenceChangeListener((preference: Preference, newValue: Any) =>
if (ShadowsocksApplication.isRoot) activity.handler.post(() => {
activity.deattachService()
activity.attachService()
true
}) else false)
findPreference("recovery").setOnPreferenceClickListener((preference: Preference) => {
ShadowsocksApplication.track(Shadowsocks.TAG, "reset")
activity.recovery()
......
package com.github.shadowsocks.preferences
import android.content.Context
import android.content.res.TypedArray
import android.preference.SwitchPreference
import android.util.AttributeSet
import com.github.shadowsocks.{R, ShadowsocksApplication}
/**
* TODO: No animations?
* @author Mygod
*/
final class NatSwitchPreference(context: Context, attrs: AttributeSet) extends SwitchPreference(context, attrs) {
private var disabled = false
override def isEnabled = super.isEnabled && !disabled
override def onGetDefaultValue(a: TypedArray, index: Int) = {
val result = ShadowsocksApplication.isVpnEnabled
if (!ShadowsocksApplication.isRoot) {
disabled = true
setEnabled(false)
setSummary(R.string.nat_summary_no_root)
}
result.asInstanceOf[AnyRef]
}
}
......@@ -66,7 +66,6 @@ object Key {
val proxied = "Proxyed"
val isNAT = "isNAT"
val status = "status"
val proxyedApps = "proxyedApps"
val route = "route"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment