diff --git a/build.sbt b/build.sbt
index fcd92b70..10646322 100644
--- a/build.sbt
+++ b/build.sbt
@@ -38,6 +38,7 @@ libraryDependencies ++= Seq(
"com.google.android.gms" % "play-services-analytics" % "8.4.0",
"com.android.support" % "design" % "23.1.1",
"com.android.support" % "gridlayout-v7" % "23.1.1",
+ "com.android.support" % "cardview-v7" % "23.2.0",
"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/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 80f7f67d..82c629f0 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -86,6 +86,17 @@
+
+
+
+
+
+
+
diff --git a/src/main/res/layout/layout_quick_switch.xml b/src/main/res/layout/layout_quick_switch.xml
new file mode 100644
index 00000000..b461f18d
--- /dev/null
+++ b/src/main/res/layout/layout_quick_switch.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml
index 31bf0e56..bd08a6ef 100755
--- a/src/main/res/values-zh/strings.xml
+++ b/src/main/res/values-zh/strings.xml
@@ -38,6 +38,7 @@
NAT 模式需要 ROOT 权限
切换到 VPN 模式
停止服务
+ 快速切换
正在关闭……
后台服务启动失败:%s
VPN 服务启动失败。你可能需要重启设备。
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 7ef92294..1c6f63e8 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -73,6 +73,7 @@
Shutting down…
%s
Failed to start VPN service. You might need to reboot your device.
+ Quick Switch
Close
diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml
index 7463b6bb..3b6dd526 100644
--- a/src/main/res/values/styles.xml
+++ b/src/main/res/values/styles.xml
@@ -5,6 +5,7 @@
+
+
+
+
+
@@ -39,4 +44,10 @@
- @android:color/transparent
+
+
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala
index 1b29cbc5..09962ff0 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala
@@ -41,6 +41,8 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, service.getString(R.string.stop),
PendingIntent.getBroadcast(service, 0, new Intent(Action.CLOSE), 0))
+ .addAction(android.R.drawable.ic_menu_manage, service.getString(R.string.quick_switch),
+ PendingIntent.getActivity(service, 0, new Intent(Action.QUICK_SWITCH), 0))
private lazy val style = new BigTextStyle(builder)
private val showOnUnlock = visible && Utils.isLollipopOrAbove
private var isVisible = true
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksQuickSwitchActivity.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksQuickSwitchActivity.scala
new file mode 100644
index 00000000..90519940
--- /dev/null
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksQuickSwitchActivity.scala
@@ -0,0 +1,78 @@
+package com.github.shadowsocks
+
+import android.content.res.Resources
+import android.os.{Handler, Build, Bundle}
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.{Toolbar, DefaultItemAnimator, LinearLayoutManager, RecyclerView}
+import android.view.{LayoutInflater, View, ViewGroup}
+import android.widget.CheckedTextView
+import com.github.shadowsocks.database.Profile
+import com.github.shadowsocks.utils.Utils
+
+/**
+ * Created by Lucas on 3/10/16.
+ */
+class ShadowsocksQuickSwitchActivity extends AppCompatActivity {
+
+ private class ProfileViewHolder(val view: View) extends RecyclerView.ViewHolder(view) with View.OnClickListener {
+ {
+ val typedArray = obtainStyledAttributes(Array(android.R.attr.selectableItemBackground))
+ view.setBackgroundResource(typedArray.getResourceId(0, 0))
+ typedArray.recycle
+ }
+ private var item: Profile = _
+ private val text = itemView.findViewById(android.R.id.text1).asInstanceOf[CheckedTextView]
+ itemView.setOnClickListener(this)
+
+ def bind(item: Profile) {
+ this.item = item
+ text.setText(item.name)
+ if (item.id == ShadowsocksApplication.profileId) {
+ text.setChecked(true)
+ } else {
+ text.setChecked(false)
+ }
+ }
+
+ def onClick(v: View) {
+ Utils.stopSsService(ShadowsocksQuickSwitchActivity.this)
+ ShadowsocksApplication.switchProfile(item.id)
+ val handler = new Handler(ShadowsocksQuickSwitchActivity.this.getMainLooper)
+ handler.postDelayed(() => {
+ Utils.startSsService(ShadowsocksQuickSwitchActivity.this)
+ }, 3000)
+ finish
+ }
+ }
+
+ private class ProfilesAdapter extends RecyclerView.Adapter[ProfileViewHolder] {
+ val profiles = ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List.empty[Profile])
+
+ def getItemCount = profiles.length
+
+ def onBindViewHolder(vh: ProfileViewHolder, i: Int) = i match {
+ case _ => vh.bind(profiles(i))
+ }
+
+ private val name = "select_dialog_singlechoice_" + (if (Build.VERSION.SDK_INT >= 21) "material" else "holo")
+
+ def onCreateViewHolder(vg: ViewGroup, i: Int) = new ProfileViewHolder(LayoutInflater.from(vg.getContext)
+ .inflate(Resources.getSystem.getIdentifier(name, "layout", "android"), vg, false))
+ }
+
+ private val profilesAdapter = new ProfilesAdapter
+
+ override def onCreate(savedInstanceState: Bundle) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.layout_quick_switch)
+
+ val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
+ toolbar.setTitle(R.string.quick_switch)
+
+ val profilesList = findViewById(R.id.profilesList).asInstanceOf[RecyclerView]
+ val lm = new LinearLayoutManager(this)
+ profilesList.setLayoutManager(lm)
+ profilesList.setItemAnimator(new DefaultItemAnimator)
+ profilesList.setAdapter(profilesAdapter)
+ }
+}
diff --git a/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/src/main/scala/com/github/shadowsocks/utils/Constants.scala
index 92e4f2ac..ee4bccd4 100644
--- a/src/main/scala/com/github/shadowsocks/utils/Constants.scala
+++ b/src/main/scala/com/github/shadowsocks/utils/Constants.scala
@@ -104,6 +104,7 @@ object State {
object Action {
val SERVICE = "com.github.shadowsocks.SERVICE"
val CLOSE = "com.github.shadowsocks.CLOSE"
+ val QUICK_SWITCH = "com.github.shadowsocks.QUICK_SWITCH"
}
object Route {