diff options
author | YuutaW <17158086+Trumeet@users.noreply.github.com> | 2019-02-24 11:59:17 -0800 |
---|---|---|
committer | YuutaW <17158086+Trumeet@users.noreply.github.com> | 2019-02-24 11:59:17 -0800 |
commit | a08328403be84d85c006f801169a3feed0d956a4 (patch) | |
tree | ceebece6443a3e6662a4937b911c58904bb5b1ff /app/src/main/java/moe/yuuta/workmode/suspend | |
download | WorkMode-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')
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 |