| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package androidx.work |
| |
| import android.content.Context |
| import androidx.annotation.WorkerThread |
| import androidx.concurrent.futures.CallbackToFutureAdapter |
| import com.google.common.util.concurrent.ListenableFuture |
| import java.util.concurrent.Executor |
| import java.util.concurrent.atomic.AtomicBoolean |
| |
| /** |
| * A class that performs work synchronously on a background thread provided by [WorkManager]. |
| * |
| * Worker classes are instantiated at runtime by WorkManager and the [.doWork] method is called on a |
| * pre-specified background thread (see [Configuration.executor]). This method is for |
| * **synchronous** processing of your work, meaning that once you return from that method, the |
| * Worker is considered to be finished and will be destroyed. If you need to do your work |
| * asynchronously or call asynchronous APIs, you should use [ListenableWorker]. |
| * |
| * In case the work is preempted for any reason, the same instance of Worker is not reused. This |
| * means that [.doWork] is called exactly once per Worker instance. A new Worker is created if a |
| * unit of work needs to be rerun. |
| * |
| * A Worker is given a maximum of ten minutes to finish its execution and return a |
| * [androidx.work.ListenableWorker.Result]. After this time has expired, the Worker will be |
| * signalled to stop. |
| */ |
| public abstract class Worker(context: Context, workerParams: WorkerParameters) : |
| ListenableWorker(context, workerParams) { |
| |
| /** |
| * Override this method to do your actual background processing. This method is called on a |
| * background thread - you are required to **synchronously** do your work and return the |
| * [androidx.work.ListenableWorker.Result] from this method. Once you return from this method, |
| * the Worker is considered to have finished what its doing and will be destroyed. If you need |
| * to do your work asynchronously on a thread of your own choice, see [ListenableWorker]. |
| * |
| * A Worker has a well defined |
| * [execution window](https://d.android.com/reference/android/app/job/JobScheduler) to finish |
| * its execution and return a [androidx.work.ListenableWorker.Result]. After this time has |
| * expired, the Worker will be signalled to stop. |
| * |
| * @return The [androidx.work.ListenableWorker.Result] of the computation; note that dependent |
| * work will not execute if you use [androidx.work.ListenableWorker.Result.failure] or |
| * [androidx.work.ListenableWorker.Result.failure] |
| */ |
| @WorkerThread public abstract fun doWork(): Result |
| |
| final override fun startWork(): ListenableFuture<Result> = |
| backgroundExecutor.future { doWork() } |
| |
| override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> = |
| backgroundExecutor.future { getForegroundInfo() } |
| |
| /** |
| * An instance of [ForegroundInfo] if the [WorkRequest] is important to the user. In this case, |
| * WorkManager provides a signal to the OS that the process should be kept alive while this work |
| * is executing. |
| * |
| * Prior to Android S, WorkManager manages and runs a foreground service on your behalf to |
| * execute the WorkRequest, showing the notification provided in the [ForegroundInfo]. To update |
| * this notification subsequently, the application can use [android.app.NotificationManager]. |
| * |
| * Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job. |
| * |
| * @return A [ForegroundInfo] instance if the WorkRequest is marked immediate. For more |
| * information look at [WorkRequest.Builder.setExpedited]. |
| * @throws IllegalStateException if it is not overridden and worker tries to go to foreground |
| */ |
| @WorkerThread |
| public open fun getForegroundInfo(): ForegroundInfo { |
| throw IllegalStateException( |
| "Expedited WorkRequests require a Worker to provide an implementation for " + |
| "`getForegroundInfo()`" |
| ) |
| } |
| } |
| |
| private fun <T> Executor.future(block: () -> T): ListenableFuture<T> = |
| CallbackToFutureAdapter.getFuture { |
| val cancelled = AtomicBoolean(false) |
| it.addCancellationListener({ cancelled.set(true) }, DirectExecutor.INSTANCE) |
| execute { |
| if (cancelled.get()) return@execute |
| try { |
| it.set(block()) |
| } catch (t: Throwable) { |
| it.setException(t) |
| } |
| } |
| } |