diff --git a/app/src/main/java/com/github/kr328/clash/ProfileEditActivity.kt b/app/src/main/java/com/github/kr328/clash/ProfileEditActivity.kt index cda7396..250e588 100644 --- a/app/src/main/java/com/github/kr328/clash/ProfileEditActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/ProfileEditActivity.kt @@ -98,7 +98,7 @@ class ProfileEditActivity : BaseActivity() { override fun onDestroy() { runBlocking { withProfile { - cancel(intent.getLongExtra("id", -1)) + release(intent.getLongExtra("id", -1)) } } diff --git a/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt b/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt index d77caa7..5723903 100644 --- a/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt @@ -1,16 +1,15 @@ package com.github.kr328.clash -import android.app.Activity import android.content.Intent +import android.net.Uri import android.os.Bundle import androidx.recyclerview.widget.LinearLayoutManager import com.github.kr328.clash.adapter.ProfileAdapter import com.github.kr328.clash.common.util.intent -import com.github.kr328.clash.common.util.startForegroundServiceCompat import com.github.kr328.clash.remote.withProfile -import com.github.kr328.clash.service.ProfileProvider import com.github.kr328.clash.service.ProfileReceiver import com.github.kr328.clash.service.model.Profile +import com.github.kr328.clash.service.util.sendBroadcastSelf import com.github.kr328.clash.weight.ProfilesMenu import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.activity_profiles.* @@ -27,7 +26,6 @@ class ProfilesActivity : BaseActivity(), ProfileAdapter.Callback, ProfilesMenu.C private const val EDITOR_REQUEST_CODE = 30000 } - private val self = this private var backgroundJob: Job? = null private val reloadMutex = Mutex() private val editorStack = Stack() @@ -69,12 +67,7 @@ class ProfilesActivity : BaseActivity(), ProfileAdapter.Callback, ProfilesMenu.C val id = editorStack.pop() withProfile { - if (resultCode == Activity.RESULT_OK) - commitAsync(id) - else - ProfileProvider.releaseTemp(self, id) - - Unit + startUpdate(id) } } @@ -132,13 +125,15 @@ class ProfilesActivity : BaseActivity(), ProfileAdapter.Callback, ProfilesMenu.C if (id < 0) throw FileNotFoundException() - val uri = ProfileProvider.acquireTemp(self, id) + val uri = withProfile { + acquireTempUri(id) + } ?: throw FileNotFoundException() editorStack.push(id) startActivityForResult( Intent(Intent.ACTION_VIEW) - .setDataAndType(uri, "text/plain") + .setDataAndType(Uri.parse(uri), "text/plain") .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION), EDITOR_REQUEST_CODE ) @@ -149,7 +144,7 @@ class ProfilesActivity : BaseActivity(), ProfileAdapter.Callback, ProfilesMenu.C } private fun startUpdate(id: Long) { - startForegroundServiceCompat(ProfileReceiver.buildUpdateIntentForId(id)) + sendBroadcastSelf(ProfileReceiver.buildUpdateIntentForId(id)) } override fun onOpenEditor(entity: Profile) { diff --git a/app/src/main/java/com/github/kr328/clash/remote/ProfileClient.kt b/app/src/main/java/com/github/kr328/clash/remote/ProfileClient.kt index 9c039a4..631456f 100644 --- a/app/src/main/java/com/github/kr328/clash/remote/ProfileClient.kt +++ b/app/src/main/java/com/github/kr328/clash/remote/ProfileClient.kt @@ -18,6 +18,10 @@ class ProfileClient(private val service: IProfileService) { service.acquireCloned(id) } + suspend fun acquireTempUri(id: Long): String? = withContext(Dispatchers.IO) { + service.acquireTempUri(id) + } + suspend fun updateMetadata(id: Long, metadata: Profile) = withContext(Dispatchers.IO) { service.updateMetadata(id, metadata) } @@ -38,8 +42,8 @@ class ProfileClient(private val service: IProfileService) { } } - suspend fun cancel(id: Long) = withContext(Dispatchers.IO) { - service.cancel(id) + suspend fun release(id: Long) = withContext(Dispatchers.IO) { + service.release(id) } suspend fun delete(id: Long) = withContext(Dispatchers.IO) { diff --git a/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl b/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl index 4769fec..21c6b5f 100644 --- a/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl +++ b/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl @@ -1,5 +1,3 @@ package com.github.kr328.clash.core.event; -parcelable LogEvent; -parcelable TrafficEvent; -parcelable BandwidthEvent; \ No newline at end of file +parcelable LogEvent; \ No newline at end of file diff --git a/service/src/main/aidl/com/github/kr328/clash/service/IProfileService.aidl b/service/src/main/aidl/com/github/kr328/clash/service/IProfileService.aidl index 43d17f5..6f3ca47 100644 --- a/service/src/main/aidl/com/github/kr328/clash/service/IProfileService.aidl +++ b/service/src/main/aidl/com/github/kr328/clash/service/IProfileService.aidl @@ -1,20 +1,21 @@ package com.github.kr328.clash.service; import com.github.kr328.clash.service.transact.IStreamCallback; -import com.github.kr328.clash.service.model.ProfileMetadata; +import com.github.kr328.clash.service.model.Profile; interface IProfileService { long acquireUnused(String type); long acquireCloned(long id); - void updateMetadata(long id, in ProfileMetadata metadata); + String acquireTempUri(long id); + void release(long id); + void updateMetadata(long id, in Profile metadata); void commit(long id, in IStreamCallback callback); - void cancel(long id); void delete(long id); void clear(long id); - ProfileMetadata queryById(long id); - ProfileMetadata[] queryAll(); - ProfileMetadata queryActive(); + Profile queryById(long id); + Profile[] queryAll(); + Profile queryActive(); void setActive(long id); } diff --git a/service/src/main/aidl/com/github/kr328/clash/service/model/ProfileMetadata.aidl b/service/src/main/aidl/com/github/kr328/clash/service/model/Profile.aidl similarity index 63% rename from service/src/main/aidl/com/github/kr328/clash/service/model/ProfileMetadata.aidl rename to service/src/main/aidl/com/github/kr328/clash/service/model/Profile.aidl index 852ec1a..b3c51e8 100644 --- a/service/src/main/aidl/com/github/kr328/clash/service/model/ProfileMetadata.aidl +++ b/service/src/main/aidl/com/github/kr328/clash/service/model/Profile.aidl @@ -1,3 +1,3 @@ package com.github.kr328.clash.service.model; -parcelable ProfileMetadata; \ No newline at end of file +parcelable Profile; \ No newline at end of file diff --git a/service/src/main/java/com/github/kr328/clash/service/ProfileProvider.kt b/service/src/main/java/com/github/kr328/clash/service/ProfileProvider.kt index d477f49..170bc68 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ProfileProvider.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ProfileProvider.kt @@ -2,22 +2,11 @@ package com.github.kr328.clash.service import android.content.Context import android.net.Uri -import android.os.Bundle import androidx.core.content.FileProvider -import androidx.core.os.bundleOf -import com.github.kr328.clash.service.util.resolveProfileFile -import com.github.kr328.clash.service.util.resolveTempProfileFile -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import java.io.File -import java.io.FileNotFoundException class ProfileProvider : FileProvider() { companion object { - private const val METHOD_ACQUIRE_TEMP = "acquireTemp" - private const val METHOD_RELEASE_TEMP = "releaseTemp" - - // service side functions fun resolveUri(context: Context, file: File): Uri { return getUriForFile( context, @@ -25,45 +14,5 @@ class ProfileProvider : FileProvider() { file ) } - - // client side functions - suspend fun acquireTemp(context: Context, id: Long): Uri = withContext(Dispatchers.IO) { - val uri = Uri.parse(context.packageName + Constants.PROFILE_PROVIDER_SUFFIX) - - context.contentResolver - .call(uri, METHOD_ACQUIRE_TEMP, id.toString(), null)?.getParcelable("uri") - ?: throw FileNotFoundException("No such profile") - } - - suspend fun releaseTemp(context: Context, id: Long) = withContext(Dispatchers.IO) { - val uri = Uri.parse(context.packageName + Constants.PROFILE_PROVIDER_SUFFIX) - - context.contentResolver - .call(uri, METHOD_RELEASE_TEMP, id.toString(), null) - } - } - - override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { - when (method) { - METHOD_ACQUIRE_TEMP -> { - val id = arg?.toLongOrNull() ?: return null - - val file = context!!.resolveProfileFile(id) - if (!file.exists()) - return null - - val temp = context!!.resolveTempProfileFile(id) - if (!temp.exists()) - file.copyTo(context!!.resolveTempProfileFile(id)) - - return bundleOf("uri" to resolveUri(context!!, temp)) - } - METHOD_RELEASE_TEMP -> { - val id = arg?.toLongOrNull() ?: return null - - context!!.resolveTempProfileFile(id).delete() - } - } - return super.call(method, arg, extras) } } \ No newline at end of file diff --git a/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt b/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt index 860cfc5..36bd931 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt @@ -44,7 +44,7 @@ class ProfileService : BaseService() { } } - override fun cancel(id: Long) { + override fun release(id: Long) { launch { lock.withLock { pending.remove(id) @@ -138,6 +138,26 @@ class ProfileService : BaseService() { } } + override fun acquireTempUri(id: Long): String? { + val file = service.resolveProfileFile(id) + if ( !file.exists() ) + return null + + val tempFile = service.resolveTempProfileFile(id) + + file.copyTo(tempFile) + + val uri = ProfileProvider.resolveUri(service, tempFile) + + return runBlocking { + lock.withLock { + pending[id] = queryMetadataById(id)?.copy(uri = uri) ?: return@withLock + } + + uri.toString() + } + } + override fun updateMetadata(id: Long, metadata: Profile?) { launch { lock.withLock { @@ -164,7 +184,7 @@ class ProfileService : BaseService() { val ctx = lock.withLock { tasks.entries.firstOrNull()?.also { - tasks.remove(it.key) + tasks[it.key] } } ?: continue @@ -172,10 +192,6 @@ class ProfileService : BaseService() { val metadata = queryMetadataById(ctx.key) ?: throw RemoteException("No such profile") - lock.withLock { - pending.remove(metadata.id) - } - ProfileProcessor.createOrUpdate(service, metadata) ctx.value?.complete() @@ -184,6 +200,11 @@ class ProfileService : BaseService() { } catch (e: Exception) { ctx.value?.completeExceptionally(e.message) } + finally { + lock.withLock { + tasks.remove(ctx.key) + } + } request.offer(Unit) }