android process handling improvements
This commit is contained in:
parent
886e0956f6
commit
d0ba17b0e9
|
@ -55,8 +55,9 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
||||||
|
|
||||||
if (Cwtch.startCwtch(appDir, torPath) != 0.toLong()) return Result.failure()
|
if (Cwtch.startCwtch(appDir, torPath) != 0.toLong()) return Result.failure()
|
||||||
|
|
||||||
// infinite coroutine :)
|
Log.i("FlwtchWorker.kt", "startCwtch success, starting coroutine AppbusEvent loop...")
|
||||||
while(true) {
|
while(true) {
|
||||||
|
Log.i("FlwtchWorker.kt", "while(true)getAppbusEvent()")
|
||||||
val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent())
|
val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent())
|
||||||
if (evt.EventType == "NewMessageFromPeer" || evt.EventType == "NewMessageFromGroup") {
|
if (evt.EventType == "NewMessageFromPeer" || evt.EventType == "NewMessageFromGroup") {
|
||||||
val data = JSONObject(evt.Data)
|
val data = JSONObject(evt.Data)
|
||||||
|
@ -213,11 +214,20 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
||||||
val id = "flwtch"
|
val id = "flwtch"
|
||||||
val title = "Flwtch"
|
val title = "Flwtch"
|
||||||
val cancel = "Shut down"//todo: translate
|
val cancel = "Shut down"//todo: translate
|
||||||
|
val channelId =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
createForegroundNotificationChannel(id, id)
|
||||||
|
} else {
|
||||||
|
// If earlier version channel ID is not used
|
||||||
|
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
// This PendingIntent can be used to cancel the worker
|
// This PendingIntent can be used to cancel the worker
|
||||||
val intent = WorkManager.getInstance(applicationContext)
|
val intent = WorkManager.getInstance(applicationContext)
|
||||||
.createCancelPendingIntent(getId())
|
.createCancelPendingIntent(getId())
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(applicationContext, id)
|
val notification = NotificationCompat.Builder(applicationContext, channelId)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setTicker(title)
|
.setTicker(title)
|
||||||
.setContentText(progress)
|
.setContentText(progress)
|
||||||
|
@ -231,10 +241,18 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
||||||
return ForegroundInfo(101, notification)
|
return ForegroundInfo(101, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
private fun createForegroundNotificationChannel(channelId: String, channelName: String): String{
|
||||||
|
val chan = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE)
|
||||||
|
chan.lightColor = Color.MAGENTA
|
||||||
|
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
||||||
|
notificationManager.createNotificationChannel(chan)
|
||||||
|
return channelId
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun createMessageNotificationChannel(channelId: String, channelName: String): String{
|
private fun createMessageNotificationChannel(channelId: String, channelName: String): String{
|
||||||
val chan = NotificationChannel(channelId,
|
val chan = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)
|
||||||
channelName, NotificationManager.IMPORTANCE_HIGH)
|
|
||||||
chan.lightColor = Color.MAGENTA
|
chan.lightColor = Color.MAGENTA
|
||||||
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
||||||
notificationManager.createNotificationChannel(chan)
|
notificationManager.createNotificationChannel(chan)
|
||||||
|
|
|
@ -7,36 +7,20 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.work.*
|
import androidx.work.*
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.SplashScreen
|
import io.flutter.embedding.android.SplashScreen
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
|
||||||
import io.flutter.plugin.common.MethodChannel.Result
|
import io.flutter.plugin.common.MethodChannel.Result
|
||||||
|
|
||||||
import cwtch.Cwtch
|
|
||||||
import io.flutter.plugin.common.EventChannel
|
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.File
|
|
||||||
import java.time.Duration
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class MainActivity: FlutterActivity() {
|
class MainActivity: FlutterActivity() {
|
||||||
|
@ -55,6 +39,9 @@ class MainActivity: FlutterActivity() {
|
||||||
// Channel to trigger contactview when an external notification is clicked
|
// Channel to trigger contactview when an external notification is clicked
|
||||||
private val CHANNEL_NOTIF_CLICK = "im.cwtch.flwtch/notificationClickHandler"
|
private val CHANNEL_NOTIF_CLICK = "im.cwtch.flwtch/notificationClickHandler"
|
||||||
|
|
||||||
|
// WorkManager tag applied to all Start() infinite coroutines
|
||||||
|
val WORKER_TAG = "cwtchEventBusWorker"
|
||||||
|
|
||||||
private var myReceiver: MyBroadcastReceiver? = null
|
private var myReceiver: MyBroadcastReceiver? = null
|
||||||
private var methodChan: MethodChannel? = null
|
private var methodChan: MethodChannel? = null
|
||||||
|
|
||||||
|
@ -106,24 +93,26 @@ class MainActivity: FlutterActivity() {
|
||||||
// in case the ForegroundService is still running. in both cases, however, we *do* want to re-register
|
// in case the ForegroundService is still running. in both cases, however, we *do* want to re-register
|
||||||
// the eventbus listener.
|
// the eventbus listener.
|
||||||
if (call.method == "Start") {
|
if (call.method == "Start") {
|
||||||
val workerTag = "cwtchEventBusWorker"
|
|
||||||
val uniqueTag = argmap["torPath"] ?: "nullEventBus"
|
val uniqueTag = argmap["torPath"] ?: "nullEventBus"
|
||||||
|
|
||||||
// note: because the ForegroundService is specified as UniquePeriodicWork, it can't actually get
|
// note: because the ForegroundService is specified as UniquePeriodicWork, it can't actually get
|
||||||
// accidentally duplicated. however, we still need to manually check if it's running or not, so
|
// accidentally duplicated. however, we still need to manually check if it's running or not, so
|
||||||
// that we can divert this method call to ReconnectCwtchForeground instead if so.
|
// that we can divert this method call to ReconnectCwtchForeground instead if so.
|
||||||
val works = WorkManager.getInstance(this).getWorkInfosByTag(workerTag).get()
|
val works = WorkManager.getInstance(this).getWorkInfosByTag(WORKER_TAG).get()
|
||||||
for (workInfo in works) {
|
for (workInfo in works) {
|
||||||
|
Log.i("handleCwtch:WorkManager", "$workInfo")
|
||||||
if (!workInfo.tags.contains(uniqueTag)) {
|
if (!workInfo.tags.contains(uniqueTag)) {
|
||||||
|
Log.i("handleCwtch:WorkManager", "canceling ${workInfo.id} bc tags don't include $uniqueTag")
|
||||||
WorkManager.getInstance(this).cancelWorkById(workInfo.id)
|
WorkManager.getInstance(this).cancelWorkById(workInfo.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WorkManager.getInstance(this).pruneWork()
|
||||||
|
|
||||||
Log.i("MainActivity.kt", "Start() launching foregroundservice")
|
Log.i("MainActivity.kt", "Start() launching foregroundservice")
|
||||||
// this is where the eventbus ForegroundService gets launched. WorkManager should keep it alive after this
|
// this is where the eventbus ForegroundService gets launched. WorkManager should keep it alive after this
|
||||||
val data: Data = Data.Builder().putString(FlwtchWorker.KEY_METHOD, call.method).putString(FlwtchWorker.KEY_ARGS, JSONObject(argmap).toString()).build()
|
val data: Data = Data.Builder().putString(FlwtchWorker.KEY_METHOD, call.method).putString(FlwtchWorker.KEY_ARGS, JSONObject(argmap).toString()).build()
|
||||||
// 15 minutes is the shortest interval you can request
|
// 15 minutes is the shortest interval you can request
|
||||||
val workRequest = PeriodicWorkRequestBuilder<FlwtchWorker>(15, TimeUnit.MINUTES).setInputData(data).addTag(workerTag).addTag(uniqueTag).build()
|
val workRequest = PeriodicWorkRequestBuilder<FlwtchWorker>(15, TimeUnit.MINUTES).setInputData(data).addTag(WORKER_TAG).addTag(uniqueTag).build()
|
||||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork("req_$uniqueTag", ExistingPeriodicWorkPolicy.REPLACE, workRequest)
|
WorkManager.getInstance(this).enqueueUniquePeriodicWork("req_$uniqueTag", ExistingPeriodicWorkPolicy.REPLACE, workRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -145,8 +134,9 @@ class MainActivity: FlutterActivity() {
|
||||||
// using onresume/onstop for broadcastreceiver because of extended discussion on https://stackoverflow.com/questions/7439041/how-to-unregister-broadcastreceiver
|
// using onresume/onstop for broadcastreceiver because of extended discussion on https://stackoverflow.com/questions/7439041/how-to-unregister-broadcastreceiver
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
Log.i("MainActivity.kt", "onResume")
|
||||||
if (myReceiver == null) {
|
if (myReceiver == null) {
|
||||||
|
Log.i("MainActivity.kt", "onResume registering localbroadcastreceiver")
|
||||||
val mc = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
|
val mc = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
|
||||||
val filter = IntentFilter("im.cwtch.flwtch.broadcast.SERVICE_EVENT_BUS")
|
val filter = IntentFilter("im.cwtch.flwtch.broadcast.SERVICE_EVENT_BUS")
|
||||||
myReceiver = MyBroadcastReceiver(mc)
|
myReceiver = MyBroadcastReceiver(mc)
|
||||||
|
@ -156,12 +146,20 @@ class MainActivity: FlutterActivity() {
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
|
Log.i("MainActivity.kt", "onStop")
|
||||||
if (myReceiver != null) {
|
if (myReceiver != null) {
|
||||||
LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(myReceiver!!);
|
LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(myReceiver!!);
|
||||||
myReceiver = null;
|
myReceiver = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.i("MainActivity.kt", "onDestroy")
|
||||||
|
WorkManager.getInstance(this).cancelAllWorkByTag(WORKER_TAG)
|
||||||
|
WorkManager.getInstance(this).pruneWork()
|
||||||
|
}
|
||||||
|
|
||||||
// source: https://web.archive.org/web/20210203022531/https://stackoverflow.com/questions/41928803/how-to-parse-json-in-kotlin/50468095
|
// source: https://web.archive.org/web/20210203022531/https://stackoverflow.com/questions/41928803/how-to-parse-json-in-kotlin/50468095
|
||||||
// for reference:
|
// for reference:
|
||||||
//
|
//
|
||||||
|
|
|
@ -30,6 +30,7 @@ var globalAppState = AppState();
|
||||||
void main() {
|
void main() {
|
||||||
print("main()");
|
print("main()");
|
||||||
LicenseRegistry.addLicense(() => licenses());
|
LicenseRegistry.addLicense(() => licenses());
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
print("runApp()");
|
print("runApp()");
|
||||||
runApp(Flwtch());
|
runApp(Flwtch());
|
||||||
}
|
}
|
||||||
|
@ -55,11 +56,14 @@ class FlwtchState extends State<Flwtch> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
|
print("initState: running...");
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
print("initState: registering notification, shutdown handlers...");
|
||||||
profs = ProfileListState();
|
profs = ProfileListState();
|
||||||
notificationClickChannel.setMethodCallHandler(_externalNotificationClicked);
|
notificationClickChannel.setMethodCallHandler(_externalNotificationClicked);
|
||||||
shutdownMethodChannel.setMethodCallHandler(shutdown);
|
shutdownMethodChannel.setMethodCallHandler(shutdown);
|
||||||
|
print("initState: creating cwtchnotifier, ffi");
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
||||||
cwtch = CwtchGomobile(cwtchNotifier);
|
cwtch = CwtchGomobile(cwtchNotifier);
|
||||||
|
@ -70,7 +74,9 @@ class FlwtchState extends State<Flwtch> {
|
||||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
||||||
cwtch = CwtchFfi(cwtchNotifier);
|
cwtch = CwtchFfi(cwtchNotifier);
|
||||||
}
|
}
|
||||||
|
print("initState: invoking cwtch.Start()");
|
||||||
cwtch.Start();
|
cwtch.Start();
|
||||||
|
print("initState: done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
|
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
|
||||||
|
|
Loading…
Reference in New Issue