aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt')
-rw-r--r--app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt199
1 files changed, 199 insertions, 0 deletions
diff --git a/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt b/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt
new file mode 100644
index 0000000..c8aae67
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt
@@ -0,0 +1,199 @@
+package moe.yuuta.workmode.access
+
+import android.content.Context
+import android.os.Bundle
+import android.os.Parcel
+import android.os.PersistableBundle
+import com.elvishew.xlog.Logger
+import com.elvishew.xlog.XLog
+import eu.chainfire.librootjava.RootJava
+import eu.chainfire.libsuperuser.Shell
+import moe.yuuta.workmode.BuildConfig
+import moe.yuuta.workmode.suspend.data.ListMode
+import moe.yuuta.workmode.suspend.data.Status
+import moe.yuuta.workmode.utils.ByteArraySerializer
+
+/**
+ * The high-level API accessor, as known as the launcher (starter) of the accessor, wraps
+ * the necessary start steps to launch it and deserialize the result.
+ */
+open class AccessorStarter(private val mContext: Context, private val mLogPath: String) {
+ private val logger: Logger = XLog.tag("AccessorStarter").build()
+
+ companion object {
+ const val ACTION_UPDATE_UI_STATE = "moe.yuuta.workmode.access.ACTION_UPDATE_UI_STATE"
+ const val ACTION_UPDATE_UI_PROGRESS = "moe.yuuta.workmode.access.ACTION_UPDATE_UI_PROGRESS"
+ const val EXTRA_SHOW_PROGRESS = "moe.yuuta.workmode.access.EXTRA_SHOW_PROGRESS"
+ }
+
+ private fun launchRootProcess(root: Boolean, vararg args: String): MutableList<String> {
+ val command = RootJava.getLaunchScript(mContext,
+ WorkModeAccessor::class.java,
+ null,
+ null,
+ args,
+ BuildConfig.APPLICATION_ID + ":accessor")
+
+ return if (root) {
+ Shell.SU.run(command)
+ } else {
+ Shell.SH.run(command)
+ }
+ }
+
+ fun getSuspendedPackageAppExtras(packageName: String, root: Boolean): Bundle? {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_GET_APP_EXTRAS)
+ argumentParcel.writeString(packageName)
+ val marshalledResult = launchRootProcess(root,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ val bundle = result.readBundle()
+ result.recycle()
+ return bundle
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+
+ fun getSuspendedPackageLauncherExtras(packageName: String, root: Boolean): Bundle? {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_GET_LAUNCHER_EXTRAS)
+ argumentParcel.writeString(packageName)
+ val marshalledResult = launchRootProcess(root,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ val bundle = result.readBundle()
+ result.recycle()
+ return bundle
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+
+ fun isPackageSuspended(packageNames: Array<out String>, root: Boolean): Boolean {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_IS_SUSPENDED)
+ argumentParcel.writeStringArray(packageNames)
+ val marshalledResult = launchRootProcess(root,
+ WorkModeAccessor.ACTION_IS_SUSPENDED,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ val isSuspended = result.readByte() == 1.toByte()
+ result.recycle()
+ return isSuspended
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+
+ fun dump(packageName: String, root: Boolean): DumpResult {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_DUMP)
+ argumentParcel.writeString(packageName)
+ val marshalledResult = launchRootProcess(root,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ val data = DumpResult(
+ result.readByte() == 1.toByte(),
+ result.readBundle(),
+ result.readBundle()
+ )
+ result.recycle()
+ return data
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+
+ fun setPackagesSuspended(packageNames: Array<String>, suspended: Boolean,
+ appExtras: PersistableBundle, launcherExtras: PersistableBundle,
+ dialogMessage: String, root: Boolean): Array<String> {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_SET_SUSPENDED)
+ argumentParcel.writeStringArray(packageNames)
+ argumentParcel.writeByte(if (suspended) 1 else 0)
+ argumentParcel.writeBundle(Bundle(appExtras))
+ argumentParcel.writeBundle(Bundle(launcherExtras))
+ argumentParcel.writeString(dialogMessage)
+ val marshalledResult = launchRootProcess(root,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ val rs = result.createStringArray() ?: arrayOf()
+ result.recycle()
+ return rs
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+
+ @Throws(Throwable::class)
+ private fun deserialize(byteArray: ByteArray): Parcel {
+ val result = Parcel.obtain()
+ result.unmarshall(byteArray, 0, byteArray.size)
+ // Thanks to https://github.com/jiaminghan/droidplanner-master/blob/743b5436df6311cbbbfdecd21f796e2b948cbac7/Android/src/com/o3dr/services/android/lib/util/ParcelableUtils.java#L35
+ result.setDataPosition(0)
+ when (result.readByte()) {
+ 1.toByte() -> {
+ }
+ 0.toByte() -> {
+ val throwable = result.readSerializable() as Throwable?
+ if (throwable != null) {
+ throw throwable
+ }
+ throw RuntimeException("Unsuccessful result with unknown stacktrace")
+ }
+ }
+ return result
+ }
+
+ fun getPackagesSuspendedByWorkMode(root: Boolean): List<String> {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_GET_ALL_PACKAGES_SUSPENDED_BY_WORK_MODE)
+ val marshalledResult = launchRootProcess(root,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ val data = result.createStringArrayList()
+ result.recycle()
+ return data ?: listOf()
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+
+ fun apply(suspendList: Array<String>, listMode: ListMode, status: Status, root: Boolean) {
+ val argumentParcel: Parcel = Parcel.obtain()
+ try {
+ argumentParcel.writeString(mLogPath)
+ argumentParcel.writeString(WorkModeAccessor.ACTION_APPLY)
+ argumentParcel.writeStringArray(suspendList)
+ argumentParcel.writeInt(when (listMode) {
+ ListMode.BLACKLIST -> 1
+ ListMode.WHITELIST -> 2
+ })
+ argumentParcel.writeInt(when (status) {
+ Status.ON -> 1
+ Status.OFF -> 2
+ })
+ val marshalledResult = launchRootProcess(root,
+ ByteArraySerializer.serialize(argumentParcel.marshall()))[0]
+ val result = deserialize(ByteArraySerializer.deserialize(marshalledResult))
+ result.recycle()
+ } finally {
+ argumentParcel.recycle()
+ }
+ }
+} \ No newline at end of file