[WIP] refactor service
This commit is contained in:
16 files changed
+495
-81
No files matched your search
@@ -3,10 +3,7 @@ package com.github.kr328.clash.core
|
||||
import android.content.Context
|
||||
import bridge.Bridge
|
||||
import bridge.EventPoll
|
||||
import com.github.kr328.clash.core.event.BandwidthEvent
|
||||
import com.github.kr328.clash.core.event.LogEvent
|
||||
import com.github.kr328.clash.core.event.ProcessEvent
|
||||
import com.github.kr328.clash.core.event.TrafficEvent
|
||||
import com.github.kr328.clash.core.event.*
|
||||
import com.github.kr328.clash.core.model.General
|
||||
import com.github.kr328.clash.core.model.Proxy
|
||||
import com.github.kr328.clash.core.model.ProxyGroup
|
||||
@@ -15,6 +12,7 @@ import com.github.kr328.clash.core.transact.ProxyCollectionImpl
|
||||
import com.github.kr328.clash.core.transact.ProxyGroupCollectionImpl
|
||||
import java.io.InputStream
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.concurrent.BrokenBarrierException
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class Clash(
|
||||
@@ -41,7 +39,7 @@ class Clash(
|
||||
}
|
||||
|
||||
fun start() {
|
||||
if ( currentProcess == ProcessEvent.STARTED )
|
||||
if (currentProcess == ProcessEvent.STARTED)
|
||||
return
|
||||
|
||||
currentProcess = ProcessEvent.STARTED
|
||||
@@ -52,7 +50,7 @@ class Clash(
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
if ( currentProcess == ProcessEvent.STOPPED )
|
||||
if (currentProcess == ProcessEvent.STOPPED)
|
||||
return
|
||||
|
||||
currentProcess = ProcessEvent.STOPPED
|
||||
@@ -86,7 +84,7 @@ class Clash(
|
||||
|
||||
fun downloadProfile(url: String, output: String, baseDir: String): CompletableFuture<Unit> {
|
||||
return DoneCallbackImpl().apply {
|
||||
Bridge.downloadProfileAndCheck(url, output, baseDir,this)
|
||||
Bridge.downloadProfileAndCheck(url, output, baseDir, this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,30 +131,49 @@ class Clash(
|
||||
fun queryGeneral(): General {
|
||||
val t = Bridge.queryGeneral()
|
||||
|
||||
return General(General.Mode.fromString(t.mode),
|
||||
t.httpPort.toInt(), t.socksPort.toInt(), t.redirectPort.toInt())
|
||||
return General(
|
||||
General.Mode.fromString(t.mode),
|
||||
t.httpPort.toInt(), t.socksPort.toInt(), t.redirectPort.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
fun pollTraffic(onEvent: (TrafficEvent) -> Unit): Poll {
|
||||
return Poll(Bridge.pollTraffic { down, up ->
|
||||
onEvent(TrafficEvent(down, up))
|
||||
})
|
||||
fun openTrafficEvent(): EventStream<TrafficEvent> {
|
||||
return object: EventStream<TrafficEvent>() {
|
||||
val traffic = Bridge.pollTraffic { down, up ->
|
||||
send(TrafficEvent(down, up))
|
||||
}
|
||||
|
||||
override fun onClose() {
|
||||
traffic.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pollBandwidth(onEvent: (BandwidthEvent) -> Unit): Poll {
|
||||
return Poll(Bridge.pollBandwidth {
|
||||
onEvent(BandwidthEvent(it))
|
||||
})
|
||||
fun openBandwidthEvent(): EventStream<BandwidthEvent> {
|
||||
return object: EventStream<BandwidthEvent>() {
|
||||
val bandwidth = Bridge.pollBandwidth {
|
||||
send(BandwidthEvent(it))
|
||||
}
|
||||
|
||||
override fun onClose() {
|
||||
bandwidth.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pollLogs(onEvent: (LogEvent) -> Unit): Poll {
|
||||
return Poll(Bridge.pollLogs { level, payload ->
|
||||
onEvent(LogEvent(LogEvent.Level.fromString(level), payload))
|
||||
})
|
||||
fun openLogEvent(): EventStream<LogEvent> {
|
||||
return object: EventStream<LogEvent>() {
|
||||
val log = Bridge.pollLogs { level, payload ->
|
||||
send(LogEvent(LogEvent.Level.fromString(level), payload))
|
||||
}
|
||||
|
||||
override fun onClose() {
|
||||
log.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun enforceStarted() {
|
||||
if ( currentProcess == ProcessEvent.STOPPED )
|
||||
throw IllegalStateException("Clash Stopped")
|
||||
check(currentProcess != ProcessEvent.STOPPED) { "Clash Stopped" }
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.github.kr328.clash.core.serialization.Parcels
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class BandwidthEvent(val total: Long): Parcelable {
|
||||
data class BandwidthEvent(val total: Long): Event {
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
Parcels.dump(serializer(), this, parcel)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.github.kr328.clash.core.event
|
||||
|
||||
interface Event {
|
||||
import android.os.Parcelable
|
||||
|
||||
interface Event: Parcelable {
|
||||
companion object {
|
||||
const val EVENT_LOG = 1
|
||||
const val EVENT_TRAFFIC = 3
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.kr328.clash.core.event
|
||||
|
||||
import android.os.Parcelable
|
||||
|
||||
abstract class EventStream<T: Event> {
|
||||
private var on: (T) -> Unit = {}
|
||||
|
||||
fun onEvent(callback: (T) -> Unit) {
|
||||
on = callback
|
||||
}
|
||||
|
||||
fun close() {
|
||||
onClose()
|
||||
}
|
||||
|
||||
fun send(event: T) {
|
||||
on(event)
|
||||
}
|
||||
|
||||
abstract fun onClose()
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import kotlinx.serialization.internal.StringDescriptor
|
||||
|
||||
@Serializable
|
||||
data class LogEvent(val level: Level, val message: String, val time: Long = System.currentTimeMillis()) :
|
||||
Event, Parcelable {
|
||||
Event {
|
||||
companion object {
|
||||
const val DEBUG_VALUE = "debug"
|
||||
const val INFO_VALUE = "info"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.github.kr328.clash.core.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.github.kr328.clash.core.serialization.MergedParcels
|
||||
import com.github.kr328.clash.core.serialization.Parcels
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@@ -9,4 +13,22 @@ data class ProxyGroup(
|
||||
val delay: Long,
|
||||
val current: String,
|
||||
val proxies: List<Proxy>
|
||||
)
|
||||
): Parcelable {
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
MergedParcels.dump(serializer(), this, parcel)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<ProxyGroup> {
|
||||
override fun createFromParcel(parcel: Parcel): ProxyGroup {
|
||||
return MergedParcels.load(serializer(), parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ProxyGroup?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package com.github.kr328.clash.core.serialization
|
||||
|
||||
import android.os.Parcel
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.modules.EmptyModule
|
||||
import kotlinx.serialization.modules.SerialModule
|
||||
|
||||
object MergedParcels: AbstractSerialFormat(EmptyModule) {
|
||||
fun <T> dump(serializer: SerializationStrategy<T>, obj: T, parcel: Parcel) {
|
||||
val data = Parcel.obtain()
|
||||
val encoder = ParcelsEncoder(data)
|
||||
|
||||
try {
|
||||
serializer.serialize(encoder, obj)
|
||||
|
||||
data.setDataPosition(0)
|
||||
|
||||
parcel.writeStringList(encoder.getStringList())
|
||||
parcel.appendFrom(data, 0, data.dataSize())
|
||||
}
|
||||
finally {
|
||||
data.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> load(deserializer: DeserializationStrategy<T>, parcel: Parcel): T {
|
||||
val strings = mutableListOf<String>().apply { parcel.readStringList(this) }
|
||||
return deserializer.deserialize(ParcelsDecoder(strings, parcel))
|
||||
}
|
||||
|
||||
private class ParcelsEncoder(private val parcel: Parcel) :
|
||||
Encoder, CompositeEncoder {
|
||||
private val strings = mutableMapOf<String, Int>()
|
||||
private var stringIndex = 0
|
||||
|
||||
fun getStringList(): List<String> {
|
||||
val result = mutableListOf<String>()
|
||||
strings.map { it.value to it.key }
|
||||
.sortedBy { it.first }
|
||||
.forEach { result.add(it.second) }
|
||||
return result
|
||||
}
|
||||
|
||||
override val context: SerialModule
|
||||
get() = EmptyModule
|
||||
|
||||
override fun beginCollection(
|
||||
desc: SerialDescriptor,
|
||||
collectionSize: Int,
|
||||
vararg typeParams: KSerializer<*>
|
||||
): CompositeEncoder {
|
||||
encodeInt(collectionSize)
|
||||
return super.beginCollection(desc, collectionSize, *typeParams)
|
||||
}
|
||||
|
||||
override fun encodeBooleanElement(desc: SerialDescriptor, index: Int, value: Boolean) =
|
||||
encodeBoolean(value)
|
||||
override fun encodeByteElement(desc: SerialDescriptor, index: Int, value: Byte) =
|
||||
encodeByte(value)
|
||||
override fun encodeCharElement(desc: SerialDescriptor, index: Int, value: Char) =
|
||||
encodeChar(value)
|
||||
override fun encodeDoubleElement(desc: SerialDescriptor, index: Int, value: Double) =
|
||||
encodeDouble(value)
|
||||
override fun encodeFloatElement(desc: SerialDescriptor, index: Int, value: Float) =
|
||||
encodeFloat(value)
|
||||
override fun encodeIntElement(desc: SerialDescriptor, index: Int, value: Int) =
|
||||
encodeInt(value)
|
||||
override fun encodeLongElement(desc: SerialDescriptor, index: Int, value: Long) =
|
||||
encodeLong(value)
|
||||
override fun encodeShortElement(desc: SerialDescriptor, index: Int, value: Short) =
|
||||
encodeShort(value)
|
||||
override fun encodeStringElement(desc: SerialDescriptor, index: Int, value: String) =
|
||||
encodeString(value)
|
||||
override fun encodeUnitElement(desc: SerialDescriptor, index: Int) =
|
||||
encodeUnit()
|
||||
|
||||
override fun encodeNonSerializableElement(desc: SerialDescriptor, index: Int, value: Any) =
|
||||
throw IllegalArgumentException("Unsupported")
|
||||
override fun <T : Any> encodeNullableSerializableElement(
|
||||
desc: SerialDescriptor,
|
||||
index: Int,
|
||||
serializer: SerializationStrategy<T>,
|
||||
value: T?
|
||||
) = encodeNullableSerializableValue(serializer, value)
|
||||
override fun <T> encodeSerializableElement(
|
||||
desc: SerialDescriptor,
|
||||
index: Int,
|
||||
serializer: SerializationStrategy<T>,
|
||||
value: T
|
||||
) = encodeSerializableValue(serializer, value)
|
||||
|
||||
override fun beginStructure(
|
||||
desc: SerialDescriptor,
|
||||
vararg typeParams: KSerializer<*>
|
||||
): CompositeEncoder = this
|
||||
|
||||
override fun encodeBoolean(value: Boolean) =
|
||||
parcel.writeByte(if ( value ) 1 else 0)
|
||||
override fun encodeByte(value: Byte) =
|
||||
parcel.writeByte(value)
|
||||
override fun encodeChar(value: Char) =
|
||||
parcel.writeInt(value.toInt())
|
||||
override fun encodeDouble(value: Double) =
|
||||
parcel.writeDouble(value)
|
||||
override fun encodeEnum(enumDescription: SerialDescriptor, ordinal: Int) =
|
||||
parcel.writeInt(ordinal)
|
||||
override fun encodeFloat(value: Float) =
|
||||
parcel.writeFloat(value)
|
||||
override fun encodeInt(value: Int) =
|
||||
parcel.writeInt(value)
|
||||
override fun encodeLong(value: Long) =
|
||||
parcel.writeLong(value)
|
||||
override fun encodeNotNullMark() =
|
||||
encodeBoolean(true)
|
||||
override fun encodeNull() =
|
||||
encodeBoolean(false)
|
||||
override fun encodeShort(value: Short) =
|
||||
parcel.writeInt(value.toInt())
|
||||
override fun encodeUnit() {}
|
||||
override fun encodeString(value: String) {
|
||||
val index = strings.computeIfAbsent(value) {
|
||||
stringIndex++
|
||||
}
|
||||
parcel.writeInt(index)
|
||||
}
|
||||
}
|
||||
|
||||
class ParcelsDecoder(private val strings: List<String>, private val parcel: Parcel) : Decoder, CompositeDecoder {
|
||||
override val context: SerialModule
|
||||
get() = EmptyModule
|
||||
override val updateMode: UpdateMode
|
||||
get() = UpdateMode.BANNED
|
||||
|
||||
override fun decodeElementIndex(desc: SerialDescriptor) =
|
||||
CompositeDecoder.READ_ALL
|
||||
override fun decodeCollectionSize(desc: SerialDescriptor) =
|
||||
decodeInt()
|
||||
|
||||
override fun decodeBooleanElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeBoolean()
|
||||
override fun decodeByteElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeByte()
|
||||
override fun decodeCharElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeChar()
|
||||
override fun decodeDoubleElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeDouble()
|
||||
override fun decodeFloatElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeFloat()
|
||||
override fun decodeIntElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeInt()
|
||||
override fun decodeShortElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeShort()
|
||||
override fun decodeLongElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeLong()
|
||||
override fun decodeStringElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeString()
|
||||
override fun decodeUnitElement(desc: SerialDescriptor, index: Int) =
|
||||
decodeUnit()
|
||||
|
||||
override fun <T : Any> decodeNullableSerializableElement(
|
||||
desc: SerialDescriptor,
|
||||
index: Int,
|
||||
deserializer: DeserializationStrategy<T?>
|
||||
) = decodeNullableSerializableValue(deserializer)
|
||||
override fun <T> decodeSerializableElement(
|
||||
desc: SerialDescriptor,
|
||||
index: Int,
|
||||
deserializer: DeserializationStrategy<T>
|
||||
) = decodeSerializableValue(deserializer)
|
||||
|
||||
override fun <T : Any> updateNullableSerializableElement(
|
||||
desc: SerialDescriptor,
|
||||
index: Int,
|
||||
deserializer: DeserializationStrategy<T?>,
|
||||
old: T?
|
||||
) = updateNullableSerializableValue(deserializer, old)
|
||||
|
||||
override fun <T> updateSerializableElement(
|
||||
desc: SerialDescriptor,
|
||||
index: Int,
|
||||
deserializer: DeserializationStrategy<T>,
|
||||
old: T
|
||||
) = updateSerializableValue(deserializer, old)
|
||||
|
||||
override fun beginStructure(
|
||||
desc: SerialDescriptor,
|
||||
vararg typeParams: KSerializer<*>
|
||||
): CompositeDecoder = this
|
||||
|
||||
override fun decodeBoolean() =
|
||||
parcel.readByte() != 0.toByte()
|
||||
override fun decodeByte() =
|
||||
parcel.readByte()
|
||||
override fun decodeChar() =
|
||||
parcel.readInt().toChar()
|
||||
override fun decodeDouble() =
|
||||
parcel.readDouble()
|
||||
override fun decodeEnum(enumDescription: SerialDescriptor) =
|
||||
parcel.readInt()
|
||||
override fun decodeFloat() =
|
||||
parcel.readFloat()
|
||||
override fun decodeInt() =
|
||||
parcel.readInt()
|
||||
override fun decodeLong() =
|
||||
parcel.readLong()
|
||||
override fun decodeNotNullMark() =
|
||||
decodeBoolean()
|
||||
override fun decodeNull() =
|
||||
null
|
||||
override fun decodeShort() =
|
||||
parcel.readInt().toShort()
|
||||
override fun decodeUnit() {}
|
||||
override fun decodeString() =
|
||||
strings[parcel.readInt()]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.github.kr328.clash.callback;
|
||||
|
||||
interface IUrlTestCallback {
|
||||
void onResult(String proxy, long delay);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.github.kr328.clash.service;
|
||||
|
||||
import com.github.kr328.clash.core.event.Event;
|
||||
|
||||
interface IClashEventObserver {
|
||||
void onProcessEvent(in ProcessEvent event);
|
||||
void onLogEvent(in LogEvent event);
|
||||
void onErrorEvent(in ErrorEvent event);
|
||||
void onTrafficEvent(in TrafficEvent event);
|
||||
void onBandwidthEvent(in BandwidthEvent event);
|
||||
void onProfileChanged(in ProfileChangedEvent event);
|
||||
void onProfileReloaded(in ProfileReloadEvent event);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.github.kr328.clash.service;
|
||||
|
||||
import com.github.kr328.clash.service.IClashEventObserver;
|
||||
|
||||
interface IClashEventService {
|
||||
void registerEventObserver(String id, in IClashEventObserver observer, in int[] events);
|
||||
void unregisterEventObserver(String id);
|
||||
}
|
||||
+4
-16
@@ -4,29 +4,17 @@ import com.github.kr328.clash.service.IClashEventObserver;
|
||||
import com.github.kr328.clash.service.IClashEventService;
|
||||
import com.github.kr328.clash.service.IClashProfileService;
|
||||
import com.github.kr328.clash.service.IClashSettingService;
|
||||
import com.github.kr328.clash.service.ipc.IPCParcelables;
|
||||
import com.github.kr328.clash.callback.IUrlTestCallback;
|
||||
import com.github.kr328.clash.core.event.Event;
|
||||
import com.github.kr328.clash.core.model.Packet;
|
||||
|
||||
interface IClashService {
|
||||
// Services
|
||||
IClashEventService getEventService();
|
||||
IClashProfileService getProfileService();
|
||||
IClashSettingService getSettingService();
|
||||
|
||||
// Status
|
||||
ProcessEvent getCurrentProcessStatus();
|
||||
|
||||
interface IClashManager {
|
||||
// Control
|
||||
void setSelectProxy(String proxy, String selected);
|
||||
void start();
|
||||
void stop();
|
||||
ParcelableCompletedFuture setSelectProxy(String proxy, String selected);
|
||||
|
||||
// Query
|
||||
CompressedProxyList queryAllProxies();
|
||||
General queryGeneral();
|
||||
void startUrlTest(in String[] proxies, IUrlTestCallback callback);
|
||||
|
||||
// Utils
|
||||
String checkProfileValid(in ParcelFileDescriptor pipe);
|
||||
ParcelableCompletedFuture startUrlTest(String group);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.github.kr328.clash.service;
|
||||
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity;
|
||||
|
||||
interface IClashProfileService {
|
||||
ClashProfileEntity[] queryProfiles();
|
||||
void setActiveProfile(int id);
|
||||
void addProfile(in ClashProfileEntity profile);
|
||||
void removeProfile(int id);
|
||||
void touchProfile(int id);
|
||||
ClashProfileEntity queryActiveProfile();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.kr328.clash.service.ipc;
|
||||
|
||||
parcelable ParcelablePipe;
|
||||
parcelable ParcelableResult;
|
||||
parcelable ParcelableCompletedFuture;
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.github.kr328.clash.service.ipc
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.RemoteException
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ParcelableCompletedFuture(private val pipe: ParcelablePipe = ParcelablePipe()) :
|
||||
CompletableFuture<Parcelable?>(), Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readParcelable<ParcelablePipe>(
|
||||
ParcelableCompletedFuture::class.java.classLoader
|
||||
) ?: throw NullPointerException()
|
||||
) {
|
||||
pipe.onReceive {
|
||||
val result = (it ?: throw NullPointerException()) as ParcelableResult
|
||||
|
||||
if ( result.exception != null ) {
|
||||
completeExceptionally(RemoteException(result.exception))
|
||||
}
|
||||
else {
|
||||
complete(result.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun complete(value: Parcelable?): Boolean {
|
||||
if ( super.complete(value) ) {
|
||||
pipe.send(ParcelableResult(value, null))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun completeExceptionally(ex: Throwable?): Boolean {
|
||||
if ( super.completeExceptionally(ex) ) {
|
||||
pipe.send(ParcelableResult(null, ex?.message ?: "Unknown"))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeParcelable(pipe, 0)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<ParcelableCompletedFuture> {
|
||||
override fun createFromParcel(parcel: Parcel): ParcelableCompletedFuture {
|
||||
return ParcelableCompletedFuture(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ParcelableCompletedFuture?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.github.kr328.clash.service.ipc
|
||||
|
||||
import android.os.Binder
|
||||
import android.os.IBinder
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
class ParcelablePipe() : Parcelable {
|
||||
private inner class Slave: Binder() {
|
||||
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
|
||||
if ( code == TRANSACT_CODE_SEND_PARCELABLE ) {
|
||||
receiveCallback(data.readParcelable(ParcelablePipe::class.java.classLoader))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
private inner class Master: Binder() {
|
||||
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
|
||||
if ( code == TRANSACT_CODE_SET_SLAVE ) {
|
||||
slave = data.readStrongBinder()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private var slave: IBinder? = null
|
||||
private var receiveCallback: (Parcelable?) -> Unit = {}
|
||||
|
||||
constructor(parcel: Parcel) : this() {
|
||||
val master = parcel.readStrongBinder()
|
||||
val data = Parcel.obtain()
|
||||
|
||||
try {
|
||||
data.writeStrongBinder(Slave())
|
||||
|
||||
master.transact(TRANSACT_CODE_SET_SLAVE, data, null, 0)
|
||||
}
|
||||
finally {
|
||||
data.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel?, flags: Int) {
|
||||
if ( dest == null )
|
||||
return
|
||||
|
||||
dest.writeStrongBinder(Master())
|
||||
}
|
||||
|
||||
override fun describeContents(): Int = 0
|
||||
|
||||
fun send(parcelable: Parcelable?): Boolean {
|
||||
val s = slave ?: return false
|
||||
val data = Parcel.obtain()
|
||||
|
||||
try {
|
||||
data.writeParcelable(parcelable, 0)
|
||||
|
||||
s.transact(TRANSACT_CODE_SEND_PARCELABLE, data, null, 0)
|
||||
}
|
||||
finally {
|
||||
data.recycle()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun onReceive(callback: (Parcelable?) -> Unit) {
|
||||
this.receiveCallback = callback
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TRANSACT_CODE_SET_SLAVE = 1
|
||||
private const val TRANSACT_CODE_SEND_PARCELABLE = 2
|
||||
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<ParcelablePipe> {
|
||||
override fun createFromParcel(parcel: Parcel): ParcelablePipe {
|
||||
return ParcelablePipe(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ParcelablePipe?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.github.kr328.clash.service.ipc
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
data class ParcelableResult(val data: Parcelable?, val exception: String?): Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readParcelable(ParcelableResult::class.java.classLoader),
|
||||
parcel.readString()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeParcelable(data, 0)
|
||||
parcel.writeString(exception)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<ParcelableResult> {
|
||||
override fun createFromParcel(parcel: Parcel): ParcelableResult {
|
||||
return ParcelableResult(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ParcelableResult?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user