Rewrite sleep root gesture handler

It now runs on its own thread and keeps old su session for later use.
This commit is contained in:
paphonb
2018-07-03 21:18:26 +07:00
parent edc1b6d726
commit d71a6b2f35
4 changed files with 94 additions and 16 deletions

View File

@@ -302,13 +302,19 @@ class LawnchairPreferences(val context: Context) : SharedPreferences.OnSharedPre
}
open inner class StringBasedPref<T : Any>(key: String, defaultValue: T, onChange: () -> Unit = doNothing,
private val fromString: (String) -> T, private val toString: (T) -> String) :
private val fromString: (String) -> T,
private val toString: (T) -> String,
private val dispose: (T) -> Unit) :
PrefDelegate<T>(key, defaultValue, onChange) {
override fun onGetValue(): T = sharedPrefs.getString(getKey(), null)?.run(fromString) ?: defaultValue
override fun onSetValue(value: T) {
edit { putString(getKey(), toString(value)) }
}
override fun disposeOldValue(oldValue: T) {
dispose(oldValue)
}
}
open inner class StringPref(key: String, defaultValue: String = "", onChange: () -> Unit = doNothing) :
@@ -442,7 +448,7 @@ class LawnchairPreferences(val context: Context) : SharedPreferences.OnSharedPre
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
cached = false
discardCachedValue()
onSetValue(value)
}
@@ -461,9 +467,20 @@ class LawnchairPreferences(val context: Context) : SharedPreferences.OnSharedPre
internal fun getKey() = key
private fun onValueChanged() {
cached = false
discardCachedValue()
onChange.invoke()
}
private fun discardCachedValue() {
if (cached) {
cached = false
value.let(::disposeOldValue)
}
}
open fun disposeOldValue(oldValue: T) {
}
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String) {

View File

@@ -46,7 +46,7 @@ class GestureController(val launcher: LawnchairLauncher) : TouchController {
}
fun createHandlerPref(key: String, defaultValue: GestureHandler = blankGestureHandler) = prefs.StringBasedPref(
key, defaultValue, prefs.doNothing, ::createGestureHandler, GestureHandler::toString)
key, defaultValue, prefs.doNothing, ::createGestureHandler, GestureHandler::toString, GestureHandler::onDestroy)
private fun createGestureHandler(jsonString: String) = createGestureHandler(launcher, jsonString, blankGestureHandler)

View File

@@ -21,6 +21,10 @@ abstract class GestureHandler(val context: Context, val config: JSONObject?) {
}
open fun onDestroy() {
}
override fun toString(): String {
return JSONObject().apply {
put("class", this@GestureHandler::class.java.name)

View File

@@ -3,9 +3,10 @@ package ch.deletescape.lawnchair.gestures.handlers
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Handler
import android.os.HandlerThread
import android.provider.Settings
import android.support.annotation.Keep
import android.view.KeyEvent
import ch.deletescape.lawnchair.gestures.GestureController
import ch.deletescape.lawnchair.gestures.GestureHandler
import com.android.launcher3.R
@@ -14,23 +15,79 @@ import org.json.JSONObject
import java.io.DataOutputStream
import java.io.IOException
private val suThread = HandlerThread("su").apply { start() }
private val suHandler = Handler(suThread.looper)
@Keep
class SleepGestureHandlerRoot(context: Context, config: JSONObject?) : GestureHandler(context, config) {
override val displayName = context.getString(R.string.action_sleep_root)!!
private var currentSession: Session? = null
private val destroy = Runnable { currentSession?.destroy() }
private val sleep = Runnable {
getSuSession().run {
write("sendevent /dev/input/event1 1 116 1\n")
write("sendevent /dev/input/event1 0 0 0\n")
write("sendevent /dev/input/event1 1 116 0\n")
write("sendevent /dev/input/event1 0 0 0\n")
}
}
private fun getSuSession(): Session {
if (currentSession == null || !currentSession!!.isAlive) {
currentSession = Session()
}
return currentSession!!
}
override fun onDestroy() {
super.onDestroy()
suHandler.post(destroy)
}
override fun onGestureTrigger(controller: GestureController) {
try {
val p = Runtime.getRuntime().exec("su")
val outputStream = DataOutputStream(p.outputStream)
outputStream.writeBytes("input keyevent ${KeyEvent.KEYCODE_POWER}\n")
outputStream.writeBytes("exit\n")
outputStream.flush()
outputStream.close()
p.waitFor()
p.destroy()
} catch (e: IOException) {
} catch (e: InterruptedException) {
suHandler.post(sleep)
}
class Session {
private val process = Runtime.getRuntime().exec("su")!!
private val outputStream = DataOutputStream(process.outputStream)
val isAlive get() = isAlive(process)
fun write(string: String) {
try {
outputStream.writeBytes(string)
outputStream.flush()
} catch (e: IOException) {
} catch (e: InterruptedException) {
}
}
fun destroy() {
try {
if (isAlive) {
outputStream.writeBytes("exit\n")
outputStream.flush()
outputStream.close()
}
process.waitFor()
process.destroy()
} catch (e: IOException) {
} catch (e: InterruptedException) {
}
}
private fun isAlive(process: Process?): Boolean {
if (process == null) return false
return try {
process.exitValue()
false
} catch (e: IllegalThreadStateException) {
true
}
}
}
}