aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/moe/yuuta/workmode/suspend
diff options
context:
space:
mode:
authorYuutaW <17158086+Trumeet@users.noreply.github.com>2019-02-24 11:59:17 -0800
committerYuutaW <17158086+Trumeet@users.noreply.github.com>2019-02-24 11:59:17 -0800
commita08328403be84d85c006f801169a3feed0d956a4 (patch)
treeceebece6443a3e6662a4937b911c58904bb5b1ff /app/src/main/java/moe/yuuta/workmode/suspend
downloadWorkMode-a08328403be84d85c006f801169a3feed0d956a4.tar
WorkMode-a08328403be84d85c006f801169a3feed0d956a4.tar.gz
WorkMode-a08328403be84d85c006f801169a3feed0d956a4.tar.bz2
WorkMode-a08328403be84d85c006f801169a3feed0d956a4.zip
First Commit
Signed-off-by: YuutaW <17158086+Trumeet@users.noreply.github.com>
Diffstat (limited to 'app/src/main/java/moe/yuuta/workmode/suspend')
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/AsyncSuspender.kt27
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/SuspendTile.kt30
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/SuspendedApp.kt38
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/Suspender.kt40
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/data/ListMode.kt6
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/data/Status.kt6
-rw-r--r--app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt68
7 files changed, 215 insertions, 0 deletions
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/AsyncSuspender.kt b/app/src/main/java/moe/yuuta/workmode/suspend/AsyncSuspender.kt
new file mode 100644
index 0000000..8cb4947
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/AsyncSuspender.kt
@@ -0,0 +1,27 @@
+package moe.yuuta.workmode.suspend
+
+import android.content.Context
+import moe.yuuta.workmode.async.Async
+import moe.yuuta.workmode.async.Callback
+import moe.yuuta.workmode.async.Runnable
+import moe.yuuta.workmode.async.Stoppable
+
+/**
+ * An async suspender which wraps suspend tasks and run them in the background
+ */
+class AsyncSuspender(private val mContext: Context) {
+ fun suspend(packageNames: Array<String>, suspended: Boolean, callback: Callback<Array<String>>): Stoppable =
+ Async.beginTask(object : Runnable<Array<String>> {
+ override fun run(): Array<String> = Suspender(mContext).suspend(packageNames, suspended)
+ }, callback)
+
+ fun isSuspended(packageNames: Array<String>, callback: Callback<Boolean>): Stoppable =
+ Async.beginTask(object : Runnable<Boolean> {
+ override fun run(): Boolean = Suspender(mContext).isSuspended(packageNames)
+ }, callback)
+
+ fun applyFromSettings(callback: Callback<Unit>): Stoppable =
+ Async.beginTask(object : Runnable<Unit> {
+ override fun run(): Unit = Suspender(mContext).applyFromSettings()
+ }, callback)
+} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/SuspendTile.kt b/app/src/main/java/moe/yuuta/workmode/suspend/SuspendTile.kt
new file mode 100644
index 0000000..f3fbc70
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/SuspendTile.kt
@@ -0,0 +1,30 @@
+package moe.yuuta.workmode.suspend
+
+import android.content.Intent
+import android.service.quicksettings.Tile
+import android.service.quicksettings.TileService
+import moe.yuuta.workmode.suspend.data.Status
+import moe.yuuta.workmode.suspend.data.SuspendedStorage
+
+class SuspendTile : TileService() {
+ override fun onClick() {
+ val storage = SuspendedStorage(this)
+ storage.setStatus(
+ when (storage.getStatus()) {
+ Status.ON -> Status.OFF
+ Status.OFF -> Status.ON
+ }
+ )
+ sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ Suspender(this).applyFromSettings()
+ }
+
+ override fun onStartListening() {
+ val tile = qsTile
+ tile.state = when (SuspendedStorage(this@SuspendTile).getStatus()) {
+ Status.ON -> Tile.STATE_ACTIVE
+ Status.OFF -> Tile.STATE_INACTIVE
+ }
+ tile.updateTile()
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/SuspendedApp.kt b/app/src/main/java/moe/yuuta/workmode/suspend/SuspendedApp.kt
new file mode 100644
index 0000000..9c6ddf7
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/SuspendedApp.kt
@@ -0,0 +1,38 @@
+package moe.yuuta.workmode.suspend
+
+import android.os.Bundle
+import android.os.PersistableBundle
+import moe.yuuta.workmode.BuildConfig
+
+/**
+ * The data class of a suspended app. This is ONLY used in this app, which
+ * can be understood as "a bridge between the extras stored in the system and
+ * information which is used in this app"
+ */
+data class SuspendedApp(
+ val isSuspendedByWorkMode: Boolean, // The flag which is used to determine whatever is suspended by WorkMode
+ val versionCodeSuspended: Int // The version code of this app when suspended the target
+) {
+ companion object {
+ // These values are stored by the system, should not be usually changed for migrating
+ const val EXTRA_IS_SUSPENDED_BY_WORK_MODE = "moe.yuuta.workmode.EXTRA_IS_SUSPENDED_BY_WORK_MODE"
+ const val EXTRA_VERSION_CODE = "moe.yuuta.workmode.EXTRA_VERSION_CODE"
+
+ fun deserializeBundle(launcherExtras: Bundle?): SuspendedApp {
+ if (launcherExtras == null) return SuspendedApp(false, -1)
+ return SuspendedApp(
+ launcherExtras.getBoolean(EXTRA_IS_SUSPENDED_BY_WORK_MODE, false),
+ launcherExtras.getInt(EXTRA_VERSION_CODE, -1)
+ )
+ }
+
+ fun getDefault(): SuspendedApp = SuspendedApp(true, BuildConfig.VERSION_CODE)
+ }
+
+ fun serializeBundle(): PersistableBundle {
+ val bundle = PersistableBundle()
+ bundle.putBoolean(EXTRA_IS_SUSPENDED_BY_WORK_MODE, isSuspendedByWorkMode)
+ bundle.putInt(EXTRA_VERSION_CODE, versionCodeSuspended)
+ return bundle
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/Suspender.kt b/app/src/main/java/moe/yuuta/workmode/suspend/Suspender.kt
new file mode 100644
index 0000000..49924bb
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/Suspender.kt
@@ -0,0 +1,40 @@
+package moe.yuuta.workmode.suspend
+
+import android.content.ComponentName
+import android.content.Context
+import android.os.PersistableBundle
+import android.service.quicksettings.TileService
+import moe.yuuta.workmode.R
+import moe.yuuta.workmode.access.ApplicationAccessorStarter
+import moe.yuuta.workmode.suspend.data.SuspendedStorage
+
+/**
+ * The highest-level suspender to wrap all information needed to suspend or vice versa. This
+ * should be called from UI components directly
+ * Chain: UI -> Suspender -> AccessorStarter -> WorkModeAccessor -> AccessLayer -> Framework
+ */
+class Suspender(private val mContext: Context) {
+ fun suspend(packageNames: Array<String>, suspended: Boolean): Array<String> =
+ ApplicationAccessorStarter(mContext).setPackagesSuspended(packageNames,
+ suspended,
+ PersistableBundle(),
+ SuspendedApp.getDefault().serializeBundle(), // We use LauncherExtras because they are easy to read
+ mContext.getString(R.string.suspended_message),
+ true)
+
+ fun isSuspended(packageNames: Array<String>): Boolean =
+ ApplicationAccessorStarter(mContext).isPackageSuspended(packageNames, true)
+
+ fun getPackagesSuspendedByWorkMode(): List<String> =
+ ApplicationAccessorStarter(mContext).getPackagesSuspendedByWorkMode(true)
+
+ fun applyFromSettings() {
+ val storage = SuspendedStorage(mContext)
+ storage.cleanList(mContext)
+ val status = storage.getStatus()
+ val listMode = storage.getListMode()
+ val list = storage.getList()
+ ApplicationAccessorStarter(mContext).apply(list.toTypedArray(), listMode, status, true)
+ TileService.requestListeningState(mContext, ComponentName(mContext, SuspendTile::class.java))
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/data/ListMode.kt b/app/src/main/java/moe/yuuta/workmode/suspend/data/ListMode.kt
new file mode 100644
index 0000000..2ba0cc1
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/data/ListMode.kt
@@ -0,0 +1,6 @@
+package moe.yuuta.workmode.suspend.data
+
+enum class ListMode {
+ BLACKLIST,
+ WHITELIST
+} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/data/Status.kt b/app/src/main/java/moe/yuuta/workmode/suspend/data/Status.kt
new file mode 100644
index 0000000..aa57564
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/data/Status.kt
@@ -0,0 +1,6 @@
+package moe.yuuta.workmode.suspend.data
+
+enum class Status {
+ OFF,
+ ON
+} \ No newline at end of file
diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt b/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt
new file mode 100644
index 0000000..c02af49
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt
@@ -0,0 +1,68 @@
+package moe.yuuta.workmode.suspend.data
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.elvishew.xlog.XLog
+import moe.yuuta.workmode.utils.Utils
+import java.util.stream.Collectors
+
+/**
+ * An independent storage of suspended status
+ */
+class SuspendedStorage(private val mContext: Context) {
+ private val logger = XLog.tag("Storage").build()
+
+ private fun getStorage(): SharedPreferences = mContext.getSharedPreferences("suspended", Context.MODE_PRIVATE)
+
+ fun getList(): List<String> = (getStorage().getStringSet("list", setOf()) ?: listOf<String>()).toList()
+
+ fun setList(set: Set<String>) {
+ logger.d("s() $set")
+ getStorage().edit().putStringSet("list", set).apply()
+ }
+
+ fun setStatus(status: Status) {
+ getStorage().edit().putInt("status",
+ when (status) {
+ Status.OFF -> 0
+ Status.ON -> 1
+ }).apply()
+ }
+
+ fun getStatus(): Status =
+ when (getStorage().getInt("status", 0)) {
+ 0 -> Status.OFF
+ 1 -> Status.ON
+ else -> Status.OFF
+ }
+
+ fun setListMode(listMode: ListMode) {
+ getStorage().edit().putInt("list_mode",
+ when (listMode) {
+ ListMode.BLACKLIST -> 0
+ ListMode.WHITELIST -> 1
+ }).apply()
+ }
+
+ fun getListMode(): ListMode =
+ when (getStorage().getInt("list_mode", 0)) {
+ 0 -> ListMode.BLACKLIST
+ 1 -> ListMode.WHITELIST
+ else -> ListMode.BLACKLIST
+ }
+
+ fun cleanList(context: Context) {
+ val installed = mContext.packageManager.getInstalledApplications(0)
+ .stream()
+ .filter(Utils.buildGeneralApplicationInfoFilter(context))
+ .map {
+ return@map it.packageName
+ }
+ .collect(Collectors.toList())
+ setList(getList().stream()
+ .filter {
+ return@filter installed.contains(it)
+ }
+ .collect(Collectors.toSet()))
+ }
+} \ No newline at end of file