fix external intent lost & replace application observer

This commit is contained in:
Kr328 committed 2020-04-14 19:17:24 +08:00
1 parent a809f94a02
commit eaf16318de
9 files changed
+133 -87

No files matched your search

@@ -15,6 +15,7 @@ import android.widget.BaseAdapter
import android.widget.TextView
import com.github.kr328.clash.common.util.intent
import com.github.kr328.clash.remote.withProfile
import com.github.kr328.clash.service.model.Profile
import com.github.kr328.clash.service.model.Profile.Type
import kotlinx.android.synthetic.main.activity_create_profile.*
import kotlinx.coroutines.Dispatchers
@@ -47,7 +48,7 @@ class CreateProfileActivity : BaseActivity() {
self.launch {
val id = withProfile {
acquireUnused(item.type)
acquireUnused(item.type, item.intent?.toUri(0))
}
startActivityForResult(
@@ -118,7 +118,7 @@ class ProfileEditActivity : BaseActivity() {
launch {
try {
withProfile {
updateMetadata(metadata.id, metadata)
update(metadata.id, metadata)
commitAsync(metadata.id).await()
}
@@ -67,7 +67,7 @@ class ProfilesActivity : BaseActivity(), ProfileAdapter.Callback, ProfilesMenu.C
val profile = editorStack.pop()
withProfile {
updateMetadata(profile.id, profile)
update(profile.id, profile)
startUpdate(profile.id)
}
}
@@ -5,11 +5,11 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import com.github.kr328.clash.common.Global
import com.github.kr328.clash.common.Permissions
import com.github.kr328.clash.common.ids.Intents
import com.github.kr328.clash.common.utils.Log
import com.github.kr328.clash.utils.ApplicationObserver
object Broadcasts {
interface Receiver {
@@ -63,35 +63,37 @@ object Broadcasts {
receivers.remove(receiver)
}
fun init(application: Application) {
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
application.registerReceiver(broadcastReceiver, IntentFilter().apply {
addAction(Intents.INTENT_ACTION_PROFILE_CHANGED)
addAction(Intents.INTENT_ACTION_CLASH_STOPPED)
addAction(Intents.INTENT_ACTION_CLASH_STARTED)
addAction(Intents.INTENT_ACTION_PROFILE_LOADED)
}, Permissions.PERMISSION_RECEIVE_BROADCASTS, null)
private val observer = ApplicationObserver {
Log.d("Global Broadcast Receiver State = $it")
val current = RemoteUtils.detectClashRunning(application)
if (current != clashRunning) {
clashRunning = current
if ( it ) {
Global.application.registerReceiver(broadcastReceiver, IntentFilter().apply {
addAction(Intents.INTENT_ACTION_PROFILE_CHANGED)
addAction(Intents.INTENT_ACTION_CLASH_STOPPED)
addAction(Intents.INTENT_ACTION_CLASH_STARTED)
addAction(Intents.INTENT_ACTION_PROFILE_LOADED)
}, Permissions.PERMISSION_RECEIVE_BROADCASTS, null)
if (current) {
receivers.forEach {
it.onStarted()
}
} else {
receivers.forEach {
it.onStopped(null)
}
val current = RemoteUtils.detectClashRunning(Global.application)
if (current != clashRunning) {
clashRunning = current
if (current) {
receivers.forEach { receiver ->
receiver.onStarted()
}
} else {
receivers.forEach { receiver ->
receiver.onStopped(null)
}
}
}
} else {
Global.application.unregisterReceiver(broadcastReceiver)
}
}
override fun onStop(owner: LifecycleOwner) {
application.unregisterReceiver(broadcastReceiver)
}
})
fun init(application: Application) {
observer.register(application)
}
}
@@ -10,8 +10,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class ProfileClient(private val service: IProfileService) {
suspend fun acquireUnused(type: Profile.Type) = withContext(Dispatchers.IO) {
service.acquireUnused(type.name)
suspend fun acquireUnused(type: Profile.Type, source: String?) = withContext(Dispatchers.IO) {
service.acquireUnused(type.name, source)
}
suspend fun acquireCloned(id: Long) = withContext(Dispatchers.IO) {
@@ -22,8 +22,8 @@ class ProfileClient(private val service: IProfileService) {
service.acquireTempUri(id)
}
suspend fun updateMetadata(id: Long, metadata: Profile) = withContext(Dispatchers.IO) {
service.updateMetadata(id, metadata)
suspend fun update(id: Long, metadata: Profile) = withContext(Dispatchers.IO) {
service.update(id, metadata)
}
suspend fun commitAsync(id: Long) = withContext(Dispatchers.IO) {
@@ -9,16 +9,16 @@ import android.os.Build
import android.os.Handler
import android.os.IBinder
import androidx.core.content.edit
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import com.github.kr328.clash.ApkBrokenActivity
import com.github.kr328.clash.Constants
import com.github.kr328.clash.common.Global
import com.github.kr328.clash.common.util.intent
import com.github.kr328.clash.common.utils.Log
import com.github.kr328.clash.service.ClashManagerService
import com.github.kr328.clash.service.IClashManager
import com.github.kr328.clash.service.IProfileService
import com.github.kr328.clash.service.ProfileService
import com.github.kr328.clash.utils.ApplicationObserver
import com.microsoft.appcenter.crashes.Crashes
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
@@ -82,60 +82,63 @@ object Remote {
}
}
fun init(application: Application) {
val handler = Handler()
private val handler = Handler()
private val observer = ApplicationObserver {
Log.d("Remote Connection State = $it")
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
handler.removeMessages(0)
val application = Global.application
GlobalScope.launch {
val valid = withContext(Dispatchers.IO) {
verifyApk(application)
}
if ( it ) {
handler.removeMessages(0)
if (!valid) {
application.startActivity(
ApkBrokenActivity::class.intent
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
return@launch
}
GlobalScope.launch {
val valid = withContext(Dispatchers.IO) {
verifyApk(application)
}
clashConnection = ClashConnection().apply {
application.bindService(
ClashManagerService::class.intent,
this,
Context.BIND_AUTO_CREATE
)
}
if (!valid) {
application.startActivity(
ApkBrokenActivity::class.intent
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
return@launch
}
profileConnection = ProfileConnection().apply {
application.bindService(
ProfileService::class.intent,
this,
Context.BIND_AUTO_CREATE
)
}
clashConnection = ClashConnection().apply {
application.bindService(
ClashManagerService::class.intent,
this,
Context.BIND_AUTO_CREATE
)
}
profileConnection = ProfileConnection().apply {
application.bindService(
ProfileService::class.intent,
this,
Context.BIND_AUTO_CREATE
)
}
}
} else {
handler.postDelayed({
clashConnection?.also {
application.unbindService(it)
it.onServiceDisconnected(null)
}
profileConnection?.also {
application.unbindService(it)
it.onServiceDisconnected(null)
}
override fun onStop(owner: LifecycleOwner) {
handler.postDelayed({
clashConnection?.also {
application.unbindService(it)
it.onServiceDisconnected(null)
}
profileConnection?.also {
application.unbindService(it)
it.onServiceDisconnected(null)
}
clashConnection = null
profileConnection = null
}, 5000)
}
}
clashConnection = null
profileConnection = null
}, 5000)
}
})
fun init(application: Application) {
observer.register(application)
}
private fun verifyApk(application: Application): Boolean {
@@ -0,0 +1,40 @@
package com.github.kr328.clash.utils
import android.app.Activity
import android.app.Application
import android.os.Bundle
class ApplicationObserver(val stateChanged: (Boolean) -> Unit) {
private var applicationRunning = false
private set(value) {
if ( field != value )
stateChanged(value)
field = value
}
private var activityCount: Int = 0
private val activityObserver = object: Application.ActivityLifecycleCallbacks {
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityDestroyed(activity: Activity) {
synchronized(this) {
activityCount--
applicationRunning = activityCount > 0
}
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
synchronized(this) {
activityCount++
applicationRunning = activityCount > 0
}
}
}
fun register(application: Application) {
application.registerActivityLifecycleCallbacks(activityObserver)
}
}
@@ -4,11 +4,11 @@ import com.github.kr328.clash.service.transact.IStreamCallback;
import com.github.kr328.clash.service.model.Profile;
interface IProfileService {
long acquireUnused(String type);
long acquireUnused(String type, String source);
long acquireCloned(long id);
String acquireTempUri(long id);
void release(long id);
void updateMetadata(long id, in Profile metadata);
void update(long id, in Profile metadata);
void commit(long id, in IStreamCallback callback);
void delete(long id);
void clear(long id);
@@ -52,7 +52,7 @@ class ProfileService : BaseService() {
}
}
override fun acquireUnused(type: String): Long {
override fun acquireUnused(type: String, source: String?): Long {
return runBlocking {
lock.withLock {
val id = generateNextId()
@@ -62,7 +62,7 @@ class ProfileService : BaseService() {
name = "",
type = Profile.Type.valueOf(type),
uri = Uri.EMPTY,
source = null,
source = source?.let { Uri.parse(it) },
active = false,
interval = 0,
lastModified = 0
@@ -152,7 +152,7 @@ class ProfileService : BaseService() {
return ProfileProvider.resolveUri(service, tempFile).toString()
}
override fun updateMetadata(id: Long, metadata: Profile?) {
override fun update(id: Long, metadata: Profile?) {
launch {
lock.withLock {
pending[id] = metadata ?: return@launch