From 253cfec33dac584e024f4bdc795ea58c5855308c Mon Sep 17 00:00:00 2001 From: CzBiX Date: Tue, 1 Dec 2015 17:32:49 +0800 Subject: [PATCH] add switch profile for Tasker --- src/main/res/layout/layout_tasker.xml | 12 +- .../layout/layout_tasker_toggle_service.xml | 13 ++ src/main/res/values/arrays.xml | 10 ++ src/main/res/values/strings.xml | 3 + .../github/shadowsocks/TaskerActivity.scala | 140 ++++++++++++++++-- .../github/shadowsocks/TaskerReceiver.scala | 16 +- .../shadowsocks/helper/TaskerSettings.scala | 56 ++++++- 7 files changed, 221 insertions(+), 29 deletions(-) create mode 100644 src/main/res/layout/layout_tasker_toggle_service.xml 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)