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