diff --git a/src/main/res/layout/layout_tasker.xml b/src/main/res/layout/layout_tasker.xml
index 4641264e..516fc5d4 100644
--- a/src/main/res/layout/layout_tasker.xml
+++ b/src/main/res/layout/layout_tasker.xml
@@ -5,12 +5,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+
diff --git a/src/main/res/layout/layout_tasker_toggle_service.xml b/src/main/res/layout/layout_tasker_toggle_service.xml
new file mode 100644
index 00000000..e182bc14
--- /dev/null
+++ b/src/main/res/layout/layout_tasker_toggle_service.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml
index 3f3fa9ef..f5b7f3ac 100644
--- a/src/main/res/values/arrays.xml
+++ b/src/main/res/values/arrays.xml
@@ -226,4 +226,14 @@
- 204.0.0.0/6
- 208.0.0.0/4
+
+
+ - Toggle service
+ - Switch profile
+
+
+
+ - toggle_service
+ - switch_profile
+
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index b1370ae7..7596b654 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -106,6 +106,9 @@
Toggle service state
Save
Turn service %s
+ No action was selected
+ No profile was selected
+ Switch profile to %s
on
off
diff --git a/src/main/scala/com/github/shadowsocks/TaskerActivity.scala b/src/main/scala/com/github/shadowsocks/TaskerActivity.scala
index 6677b08a..3919659d 100644
--- a/src/main/scala/com/github/shadowsocks/TaskerActivity.scala
+++ b/src/main/scala/com/github/shadowsocks/TaskerActivity.scala
@@ -41,10 +41,14 @@ package com.github.shadowsocks
import android.app.Activity
import android.content.Intent
import android.os.Bundle
+import android.support.v4.app.{Fragment, ListFragment}
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.util.Log
-import android.widget.Switch
+import android.view.{LayoutInflater, View, ViewGroup}
+import android.widget.AdapterView.OnItemClickListener
+import android.widget._
+import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.helper.TaskerSettings
import com.twofortyfouram.locale.api.{Intent => ApiIntent}
@@ -53,15 +57,12 @@ import com.twofortyfouram.locale.api.{Intent => ApiIntent}
*/
class TaskerActivity extends AppCompatActivity {
var taskerOption: TaskerSettings = _
-
- var switch: Switch = _
+ var actionSelected: Boolean = false
override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_tasker)
- switch = findViewById(R.id.service_switch).asInstanceOf[Switch]
-
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
toolbar.setTitle(R.string.app_name)
toolbar.setNavigationIcon(R.drawable.ic_close)
@@ -75,6 +76,7 @@ class TaskerActivity extends AppCompatActivity {
})
loadSettings()
+ loadFragment()
}
private def loadSettings() {
@@ -86,14 +88,134 @@ class TaskerActivity extends AppCompatActivity {
}
taskerOption = TaskerSettings.fromIntent(intent)
+ }
- switch.setChecked(taskerOption.is_start)
+ private def loadFragment() {
+ actionSelected = !taskerOption.isEmpty
+ val fragment: Fragment = taskerOption.action match {
+ case TaskerSettings.ACTION_TOGGLE_SERVICE =>
+ new ToggleServiceFragment
+ case TaskerSettings.ACTION_SWITCH_PROFILE =>
+ new ProfileChoiceFragment
+ case _ =>
+ val fragment: ActionChoiceFragment = new ActionChoiceFragment
+ fragment.onItemClickedListener = (_, _, _, id) => {
+ taskerOption.action = getResources.getStringArray(R.array.tasker_action_value)(id.toInt)
+ loadFragment()
+ actionSelected = true
+ }
+ fragment
+ }
+
+ getSupportFragmentManager.beginTransaction()
+ .replace(R.id.fragment, fragment)
+ .commit()
}
private def saveResult() {
- taskerOption.is_start = switch.isChecked
- setResult(Activity.RESULT_OK, taskerOption.toIntent(this))
- finish()
+ if (actionSelected) {
+ val fragment: OptionFragment = getSupportFragmentManager.findFragmentById(R.id.fragment).asInstanceOf[OptionFragment]
+ if (fragment.saveResult()) {
+ setResult(Activity.RESULT_OK, taskerOption.toIntent(this))
+ finish()
+ }
+ } else {
+ Toast.makeText(this, R.string.no_action_selected, Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private class ActionChoiceFragment extends ListFragment {
+ var onItemClickedListener: OnItemClickListener = _
+
+ override def onActivityCreated(savedInstanceState: Bundle) {
+ super.onActivityCreated(savedInstanceState)
+
+ val adapter = ArrayAdapter.createFromResource(getActivity, R.array.tasker_action_name, android.R.layout.simple_selectable_list_item)
+
+ setListAdapter(adapter)
+ }
+
+ override def onListItemClick(l: ListView, v: View, position: Int, id: Long) {
+ if (onItemClickedListener != null) {
+ onItemClickedListener.onItemClick(l, v, position, id)
+ }
+ }
+ }
+
+ private class ToggleServiceFragment extends Fragment with OptionFragment {
+ var switch: Switch = _
+
+ override def onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle): View = {
+ val view: View = inflater.inflate(R.layout.layout_tasker_toggle_service, container, false)
+
+ switch = view.findViewById(R.id.service_switch).asInstanceOf[Switch]
+ view
+ }
+
+ override def onActivityCreated(savedInstanceState: Bundle) {
+ super.onActivityCreated(savedInstanceState)
+
+ if (!taskerOption.isEmpty) {
+ switch.setChecked(taskerOption.isStart)
+ }
+ }
+
+ override def saveResult() = {
+ taskerOption.action = TaskerSettings.ACTION_TOGGLE_SERVICE
+ taskerOption.isStart = switch.isChecked
+ true
+ }
+ }
+
+ private class ProfileChoiceFragment extends ListFragment with OptionFragment {
+ override def onActivityCreated(savedInstanceState: Bundle) {
+ super.onActivityCreated(savedInstanceState)
+
+ import scala.collection.JavaConverters._
+ val profiles = ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List.empty)
+ val adapter = new ArrayAdapter[Profile](getActivity, 0, android.R.id.text1, profiles.asJava) {
+ override def getView(position: Int, convertView: View, parent: ViewGroup): View = {
+ val view: TextView = if (convertView == null) {
+ val inflater = LayoutInflater.from(parent.getContext)
+ inflater.inflate(android.R.layout.simple_list_item_single_choice, parent, false).asInstanceOf[TextView]
+ } else {
+ convertView.asInstanceOf[TextView]
+ }
+
+ view.setText(getItem(position).name)
+ view
+ }
+ }
+
+ setListAdapter(adapter)
+
+ val listView: ListView = getListView
+ listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE)
+
+ if (!taskerOption.isEmpty) {
+ val index = profiles.indexWhere(_.id == taskerOption.profileId)
+ if (index > -1) {
+ listView.setItemChecked(index, true)
+ }
+ }
+ }
+
+ override def saveResult() = {
+ taskerOption.action = TaskerSettings.ACTION_SWITCH_PROFILE
+ val listView = getListView
+ val item = listView.getItemAtPosition(listView.getCheckedItemPosition)
+ if (item == null) {
+ Toast.makeText(getActivity, R.string.no_profile_selected, Toast.LENGTH_SHORT).show()
+ false
+ } else {
+ taskerOption.profileId = item.asInstanceOf[Profile].id
+ true
+ }
+ }
+ }
+
+ trait OptionFragment extends Fragment {
+ def saveResult(): Boolean
}
}
diff --git a/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala b/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala
index 92ac3234..06862287 100644
--- a/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala
+++ b/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala
@@ -39,6 +39,7 @@
package com.github.shadowsocks
import android.content.{BroadcastReceiver, Context, Intent}
+import android.util.Log
import com.github.shadowsocks.helper.TaskerSettings
import com.github.shadowsocks.utils.Utils
@@ -49,10 +50,17 @@ class TaskerReceiver extends BroadcastReceiver {
override def onReceive(context: Context, intent: Intent): Unit = {
val settings: TaskerSettings = TaskerSettings.fromIntent(intent)
- if (settings.is_start) {
- Utils.startSsService(context)
- } else {
- Utils.stopSsService(context)
+ settings.action match {
+ case TaskerSettings.ACTION_TOGGLE_SERVICE =>
+ if (settings.isStart) {
+ Utils.startSsService(context)
+ } else {
+ Utils.stopSsService(context)
+ }
+ case TaskerSettings.ACTION_SWITCH_PROFILE =>
+ ShadowsocksApplication.switchProfile(settings.profileId)
+ case _ =>
+ Log.e(Shadowsocks.TAG, s"unknown tasker action: ${settings.action}")
}
}
}
diff --git a/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala b/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala
index 1927923a..a9cbc1bd 100644
--- a/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala
+++ b/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala
@@ -38,13 +38,17 @@
*/
package com.github.shadowsocks.helper
-import android.content.{Intent, Context}
+import android.content.{Context, Intent}
import android.os.Bundle
-import com.github.shadowsocks.R
-
+import android.util.Log
+import com.github.shadowsocks.{R, Shadowsocks, ShadowsocksApplication}
import com.twofortyfouram.locale.api.{Intent => ApiIntent}
object TaskerSettings {
+ val ACTION_UNKNOWN = "unknown"
+ val ACTION_TOGGLE_SERVICE = "toggle_service"
+ val ACTION_SWITCH_PROFILE = "switch_profile"
+
def fromIntent(intent: Intent): TaskerSettings = {
val bundle: Bundle = if (intent.hasExtra(ApiIntent.EXTRA_BUNDLE))
intent.getBundleExtra(ApiIntent.EXTRA_BUNDLE) else Bundle.EMPTY
@@ -58,16 +62,52 @@ object TaskerSettings {
}
class TaskerSettings(bundle: Bundle) {
- val KEY_IS_START = "is_start"
+ import TaskerSettings._
- var is_start: Boolean = bundle.getBoolean(KEY_IS_START)
+ private val KEY_ACTION = "action"
+ private val KEY_IS_START = "is_start"
+ private val KEY_PROFILE_ID = "profile_id"
+
+ var action: String = bundle.getString(KEY_ACTION, ACTION_UNKNOWN)
+
+ var isStart: Boolean = _
+ var profileId: Int = _
+
+ action match {
+ case ACTION_TOGGLE_SERVICE =>
+ isStart = bundle.getBoolean(KEY_IS_START, true)
+ case ACTION_SWITCH_PROFILE =>
+ profileId = bundle.getInt(KEY_PROFILE_ID, -1)
+ assert(profileId != -1, "profile id was wrong")
+ case _ =>
+ Log.w(Shadowsocks.TAG, s"unknown tasker action settings: $action")
+ }
+
+ def isEmpty = action == ACTION_UNKNOWN
def toIntent(context: Context): Intent = {
val bundle = new Bundle()
- bundle.putBoolean(KEY_IS_START, is_start)
- val desc = context.getString(R.string.turn_service_state,
- context.getString(if (is_start) R.string.state_on else R.string.state_off))
+ action match {
+ case ACTION_TOGGLE_SERVICE =>
+ bundle.putString(KEY_ACTION, action)
+ bundle.putBoolean(KEY_IS_START, isStart)
+ case ACTION_SWITCH_PROFILE =>
+ bundle.putString(KEY_ACTION, action)
+ bundle.putInt(KEY_PROFILE_ID, profileId)
+ }
+
+ val desc: String = action match {
+ case ACTION_TOGGLE_SERVICE =>
+ context.getString(R.string.turn_service_state,
+ context.getString(if (isStart) R.string.state_on else R.string.state_off))
+ case ACTION_SWITCH_PROFILE =>
+ val profileName = ShadowsocksApplication.profileManager.getProfile(profileId) match {
+ case Some(p) => p.name
+ case None => context.getString(R.string.removed)
+ }
+ context.getString(R.string.switch_profile_to, profileName)
+ }
val intent: Intent = new Intent()
intent.putExtra(ApiIntent.EXTRA_STRING_BLURB, desc)