android process handling improvements

This commit is contained in:
erinn 2021-06-21 17:56:34 -07:00
parent 886e0956f6
commit d0ba17b0e9
3 changed files with 46 additions and 24 deletions

View File

@ -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)

View File

@ -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:
// //

View File

@ -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);