1 /* <lambda>null2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.work.integration.testapp 18 19 import android.app.Notification 20 import android.app.NotificationChannel 21 import android.app.NotificationManager 22 import android.content.Context 23 import android.os.Build 24 import android.os.Looper 25 import android.util.Log 26 import androidx.annotation.RequiresApi 27 import androidx.concurrent.futures.CallbackToFutureAdapter 28 import androidx.concurrent.futures.await 29 import androidx.core.app.NotificationCompat 30 import androidx.work.Data 31 import androidx.work.ForegroundInfo 32 import androidx.work.ListenableWorker 33 import androidx.work.WorkerParameters 34 import androidx.work.workDataOf 35 import com.google.common.util.concurrent.ListenableFuture 36 import kotlinx.coroutines.CoroutineScope 37 import kotlinx.coroutines.Dispatchers 38 import kotlinx.coroutines.Job 39 import kotlinx.coroutines.delay 40 import kotlinx.coroutines.launch 41 42 class RemoteWorker(private val context: Context, private val parameters: WorkerParameters) : 43 ListenableWorker(context, parameters) { 44 45 private val notificationManager = 46 context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 47 48 private var job: Job? = null 49 private var progress: Data = Data.EMPTY 50 51 override fun startWork(): ListenableFuture<Result> { 52 return CallbackToFutureAdapter.getFuture { completer -> 53 Log.d(TAG, "Starting Remote Worker.") 54 if (Looper.getMainLooper().thread != Thread.currentThread()) { 55 completer.set(Result.failure()) 56 return@getFuture "startRemoteWork" 57 } 58 val scope = CoroutineScope(Dispatchers.Default) 59 job = 60 scope.launch { 61 for (i in 1..10) { 62 delay(10000) 63 progress = workDataOf(Progress to i * 10) 64 setForegroundAsync(getForegroundInfo(NotificationId)) 65 setProgressAsync(progress).await() 66 } 67 } 68 69 job?.invokeOnCompletion { 70 Log.d(TAG, "Done.") 71 completer.set(Result.success()) 72 } 73 return@getFuture "startRemoteWork" 74 } 75 } 76 77 override fun onStopped() { 78 super.onStopped() 79 job?.cancel() 80 } 81 82 override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> { 83 return CallbackToFutureAdapter.getFuture { completer -> 84 val scope = CoroutineScope(Dispatchers.Default) 85 scope.launch { completer.set(getForegroundInfo(NotificationId)) } 86 return@getFuture "getForegroundInfoAsync" 87 } 88 } 89 90 private fun getForegroundInfo(notificationId: Int): ForegroundInfo { 91 val percent = progress.getInt(Progress, 0) 92 val id = applicationContext.getString(R.string.channel_id) 93 val title = applicationContext.getString(R.string.notification_title) 94 val content = "Progress ($percent) %" 95 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 96 createChannel() 97 } 98 99 val notification = 100 NotificationCompat.Builder(applicationContext, id) 101 .setContentTitle(title) 102 .setTicker(title) 103 .setContentText(content) 104 .setSmallIcon(R.drawable.ic_work_notification) 105 .setOngoing(true) 106 .build() 107 108 return ForegroundInfo(notificationId, notification) 109 } 110 111 @RequiresApi(Build.VERSION_CODES.O) 112 private fun createChannel() { 113 val id = applicationContext.getString(R.string.channel_id) 114 val name = applicationContext.getString(R.string.channel_name) 115 val description = applicationContext.getString(R.string.channel_description) 116 val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW) 117 channel.description = description 118 channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE 119 notificationManager.createNotificationChannel(channel) 120 } 121 122 companion object { 123 private const val TAG = "WM-RemoteWorker" 124 private const val NotificationId = 20 125 private const val Progress = "Progress" 126 } 127 } 128