WIP: partial android service migration

This commit is contained in:
erinn 2021-05-28 15:56:45 -07:00
parent d8059197fe
commit a99a00de30
5 changed files with 177 additions and 17 deletions

View File

@ -69,6 +69,15 @@ android {
signingConfig signingConfigs.release
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
flutter {
@ -82,4 +91,24 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
implementation "com.airbnb.android:lottie:3.5.0"
implementation "com.android.support.constraint:constraint-layout:2.0.4"
// WorkManager
// (Java only)
//implementation("androidx.work:work-runtime:$work_version")
// Kotlin + coroutines
implementation("androidx.work:work-runtime-ktx:2.5.0")
// optional - RxJava2 support
//implementation("androidx.work:work-rxjava2:$work_version")
// optional - GCMNetworkManager support
//implementation("androidx.work:work-gcm:$work_version")
// optional - Test helpers
//androidTestImplementation("androidx.work:work-testing:$work_version")
// optional - Multiprocess support
implementation "androidx.work:work-multiprocess:2.5.0"
}

View File

@ -42,4 +42,6 @@
<!--Needed to access Tor socket-->
<uses-permission android:name="android.permission.INTERNET" />
<!--Needed to run in background (lol)-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>

View File

@ -0,0 +1,122 @@
package im.cwtch.flwtch
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import androidx.work.WorkManager
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONObject
import cwtch.Cwtch
class FlwtchWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
private val CWTCH_EVENTBUS = "test.flutter.dev/eventBus"
private val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
override suspend fun doWork(): Result {
val appDir = inputData.getString(KEY_APP_DIR)
?: return Result.failure()
val torPath = inputData.getString(KEY_TOR_PATH)
?: return Result.failure()
// Mark the Worker as important
val progress = "Trying to do a Flwtch"
setForeground(createForegroundInfo(progress))
download(appDir, torPath)
return Result.success()
}
private suspend fun download(appDir: String, torPath: String) {
Cwtch.startCwtch(appDir, torPath)
// seperate coroutine to poll event bus and send to dart
//Log.i("FlwtchWorker.kt", "got event chan: " + eventbus_chan + " launching corouting...")
GlobalScope.launch(Dispatchers.IO) {
while(true) {
val evt = AppbusEvent(Cwtch.getAppBusEvent())
Log.i("FlwtchWorker.kt", "got appbusEvent: " + evt)
launch(Dispatchers.Main) {
//todo: this elides evt.EventID which may be needed at some point?
val flutterEngine = FlutterEngine(applicationContext)
val eventbus_chan = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
eventbus_chan.invokeMethod(evt.EventType, evt.Data)
}
}
}
}
// Creates an instance of ForegroundInfo which can be used to update the
// ongoing notification.
private fun createForegroundInfo(progress: String): ForegroundInfo {
val id = "flwtch"
val title = "Flwtch"
val cancel = "Nevermind"//todo: translate
// This PendingIntent can be used to cancel the worker
val intent = WorkManager.getInstance(applicationContext)
.createCancelPendingIntent(getId())
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(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)
""
}
val notification = NotificationCompat.Builder(applicationContext, id)
.setContentTitle(title)
.setTicker(title)
.setContentText(progress)
.setSmallIcon(R.mipmap.knott)
.setOngoing(true)
// Add the cancel action to the notification which can
// be used to cancel the worker
.addAction(android.R.drawable.ic_delete, cancel, intent)
.build()
return ForegroundInfo(101, notification)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String{
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
notificationManager.createNotificationChannel(chan)
return channelId
}
companion object {
const val KEY_APP_DIR = "KEY_APP_DIR"
const val KEY_TOR_PATH = "KEY_TOR_PATH"
}
class AppbusEvent(json: String) : JSONObject(json) {
val EventType = this.optString("EventType")
val EventID = this.optString("EventID")
val Data = this.optString("Data")
}
}

View File

@ -7,6 +7,11 @@ import android.os.Bundle
import android.os.Looper
import android.util.Log
import androidx.work.Data
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkRequest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -44,8 +49,6 @@ class MainActivity: FlutterActivity() {
// Note: this methods are invoked on the main thread.
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_APP_INFO).setMethodCallHandler { call, result -> handleAppInfo(call, result) }
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_CWTCH).setMethodCallHandler { call, result -> handleCwtch(call, result) }
}
private fun handleAppInfo(@NonNull call: MethodCall, @NonNull result: Result) {
@ -70,21 +73,25 @@ class MainActivity: FlutterActivity() {
val appDir = (call.argument("appDir") as? String) ?: "";
val torPath = (call.argument("torPath") as? String) ?: "tor";
Log.i("MainActivity.kt", " appDir: '" + appDir + "' torPath: '" + torPath + "'")
Cwtch.startCwtch(appDir, torPath)
//Cwtch.startCwtch(appDir, torPath)// todo
val data: Data = Data.Builder().putString(FlwtchWorker.KEY_APP_DIR, appDir).putString(FlwtchWorker.KEY_TOR_PATH, torPath).build()
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<FlwtchWorker>().setInputData(data).build()
WorkManager.getInstance(this).enqueue(uploadWorkRequest)
// seperate coroutine to poll event bus and send to dart
val eventbus_chan = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
Log.i("MainActivity.kt", "got event chan: " + eventbus_chan + " launching corouting...")
GlobalScope.launch(Dispatchers.IO) {
while(true) {
val evt = AppbusEvent(Cwtch.getAppBusEvent())
Log.i("MainActivity.kt", "got appbusEvent: " + evt)
launch(Dispatchers.Main) {
//todo: this elides evt.EventID which may be needed at some point?
eventbus_chan.invokeMethod(evt.EventType, evt.Data)
}
}
}
// val eventbus_chan = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
// Log.i("MainActivity.kt", "got event chan: " + eventbus_chan + " launching corouting...")
// GlobalScope.launch(Dispatchers.IO) {
// while(true) {
// val evt = AppbusEvent(Cwtch.getAppBusEvent())
// Log.i("MainActivity.kt", "got appbusEvent: " + evt)
// launch(Dispatchers.Main) {
// //todo: this elides evt.EventID which may be needed at some point?
// eventbus_chan.invokeMethod(evt.EventType, evt.Data)
// }
// }
// }
}
"SelectProfile" -> {
val onion = (call.argument("profile") as? String) ?: "";

View File

@ -14,7 +14,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.5.0"
boolean_selector:
dependency: transitive
description:
@ -371,7 +371,7 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "6.2.0"
version: "6.1.0+1"
webdriver:
dependency: transitive
description: