Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package be.tramckrijte.workmanager
- import android.app.Notification
- import android.app.NotificationChannel
- import android.app.NotificationManager
- import android.content.Context
- import android.os.Build
- import android.os.Handler
- import android.os.Looper
- import android.util.Log
- import androidx.annotation.RequiresApi
- import androidx.concurrent.futures.ResolvableFuture
- import androidx.core.app.NotificationCompat
- import androidx.core.content.ContextCompat.getSystemService
- import androidx.work.ForegroundInfo
- import androidx.work.ListenableWorker
- import androidx.work.WorkManager
- import androidx.work.WorkerParameters
- import com.google.common.util.concurrent.ListenableFuture
- import io.flutter.embedding.engine.FlutterEngine
- import io.flutter.embedding.engine.dart.DartExecutor
- import io.flutter.embedding.engine.loader.FlutterLoader
- import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistry
- import io.flutter.plugin.common.MethodCall
- import io.flutter.plugin.common.MethodChannel
- import io.flutter.view.FlutterCallbackInformation
- import java.util.*
- /***
- * A simple worker that will post your input back to your Flutter application.
- *
- * It will block the background thread until a value of either true or false is received back from Flutter code.
- */
- class BackgroundWorker(
- applicationContext: Context,
- private val workerParams: WorkerParameters
- ) : ListenableWorker(applicationContext, workerParams), MethodChannel.MethodCallHandler {
- private lateinit var backgroundChannel: MethodChannel
- companion object {
- const val TAG = "BackgroundWorker"
- const val PAYLOAD_KEY = "be.tramckrijte.workmanager.INPUT_DATA"
- const val DART_TASK_KEY = "be.tramckrijte.workmanager.DART_TASK"
- const val IS_IN_DEBUG_MODE_KEY = "be.tramckrijte.workmanager.IS_IN_DEBUG_MODE_KEY"
- const val BACKGROUND_CHANNEL_NAME =
- "be.tramckrijte.workmanager/background_channel_work_manager"
- const val BACKGROUND_CHANNEL_INITIALIZED = "backgroundChannelInitialized"
- private val flutterLoader = FlutterLoader()
- }
- private val payload
- get() = workerParams.inputData.getString(PAYLOAD_KEY)
- private val dartTask
- get() = workerParams.inputData.getString(DART_TASK_KEY)!!
- private val isInDebug
- get() = workerParams.inputData.getBoolean(IS_IN_DEBUG_MODE_KEY, false)
- private val randomThreadIdentifier = Random().nextInt()
- private var engine: FlutterEngine? = null
- private var startTime: Long = 0
- private val resolvableFuture = ResolvableFuture.create<Result>()
- override fun startWork(): ListenableFuture<Result> {
- setForegroundAsync(createForegroundInfo());
- startTime = System.currentTimeMillis()
- engine = FlutterEngine(applicationContext)
- if (!flutterLoader.initialized()) {
- flutterLoader.startInitialization(applicationContext)
- }
- flutterLoader.ensureInitializationCompleteAsync(
- applicationContext,
- null,
- Handler(Looper.getMainLooper())
- ) {
- val callbackHandle = SharedPreferenceHelper.getCallbackHandle(applicationContext)
- val callbackInfo = FlutterCallbackInformation.lookupCallbackInformation(callbackHandle)
- val dartBundlePath = flutterLoader.findAppBundlePath()
- if (isInDebug) {
- DebugHelper.postTaskStarting(
- applicationContext,
- randomThreadIdentifier,
- dartTask,
- payload,
- callbackHandle,
- callbackInfo,
- dartBundlePath
- )
- }
- // Backwards compatibility with v1. We register all the user's plugins.
- WorkmanagerPlugin.pluginRegistryCallback?.registerWith(ShimPluginRegistry(engine!!))
- engine?.let { engine ->
- backgroundChannel = MethodChannel(engine.dartExecutor, BACKGROUND_CHANNEL_NAME)
- backgroundChannel.setMethodCallHandler(this@BackgroundWorker)
- engine.dartExecutor.executeDartCallback(
- DartExecutor.DartCallback(
- applicationContext.assets,
- dartBundlePath,
- callbackInfo
- )
- )
- }
- }
- return resolvableFuture
- }
- override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
- val future = ResolvableFuture.create<ForegroundInfo?>()
- future.set(createForegroundInfo())
- return future
- }
- override fun onStopped() {
- stopEngine(null)
- }
- private fun stopEngine(result: Result?) {
- val fetchDuration = System.currentTimeMillis() - startTime
- if (isInDebug) {
- DebugHelper.postTaskCompleteNotification(
- applicationContext,
- randomThreadIdentifier,
- dartTask,
- payload,
- fetchDuration,
- result ?: Result.failure()
- )
- }
- // No result indicates we were signalled to stop by WorkManager. The result is already
- // STOPPED, so no need to resolve another one.
- if (result != null) {
- resolvableFuture.set(result)
- }
- // If stopEngine is called from `onStopped`, it may not be from the main thread.
- Handler(Looper.getMainLooper()).post {
- engine?.destroy()
- engine = null
- }
- }
- override fun onMethodCall(call: MethodCall, r: MethodChannel.Result) {
- when (call.method) {
- BACKGROUND_CHANNEL_INITIALIZED ->
- backgroundChannel.invokeMethod(
- "onResultSend",
- mapOf(DART_TASK_KEY to dartTask, PAYLOAD_KEY to payload),
- object : MethodChannel.Result {
- override fun notImplemented() {
- stopEngine(Result.failure())
- }
- override fun error(
- errorCode: String,
- errorMessage: String?,
- errorDetails: Any?
- ) {
- Log.e(TAG, "errorCode: $errorCode, errorMessage: $errorMessage")
- stopEngine(Result.failure())
- }
- override fun success(receivedResult: Any?) {
- val wasSuccessFul = receivedResult?.let { it as Boolean? } == true
- stopEngine(if (wasSuccessFul) Result.success() else Result.retry())
- }
- }
- )
- }
- }
- private fun createForegroundInfo(): ForegroundInfo {
- // Use a different id for each Notification.
- val notificationId = 1
- val notificationn = createNotification()
- return ForegroundInfo(notificationId, notificationn)
- }
- private fun createNotification(): Notification {
- // This PendingIntent can be used to cancel the Worker.
- val intent = WorkManager.getInstance(applicationContext).createCancelPendingIntent(id)
- val builder = NotificationCompat.Builder(applicationContext, "background_worker")
- .setContentTitle("uploading post")
- .setTicker("title")
- .setOngoing(true)
- .setSmallIcon(android.R.drawable.stat_notify_sync)
- .setChannelId("background_worker")
- .setPriority(NotificationCompat.PRIORITY_DEFAULT)
- .addAction(R.drawable.notification_bg, "cancel", intent)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- createNotificationChannel("background_worker", "background_worker").also {
- builder.setChannelId(it.id)
- }
- }
- return builder.build()
- }
- @RequiresApi(Build.VERSION_CODES.O)
- private fun createNotificationChannel(
- channelId: String,
- name: String
- ): NotificationChannel {
- return NotificationChannel(
- channelId, name, NotificationManager.IMPORTANCE_LOW
- ).also { channel ->
- val mNotificationManager =
- applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
- mNotificationManager?.createNotificationChannel(channel)
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment