Gradle dependencies
compile group: 'androidx.work', name: 'work-runtime', version: '2.10.0-alpha03'
- groupId: androidx.work
 - artifactId: work-runtime
 - version: 2.10.0-alpha03
 
Artifact androidx.work:work-runtime:2.10.0-alpha03 it located at Google repository (https://maven.google.com/)
Overview
A concrete implementation of WorkManager.
Summary
| Methods | 
|---|
| public abstract WorkContinuation | beginUniqueWork(java.lang.String uniqueWorkName, ExistingWorkPolicy existingWorkPolicy, java.util.List<OneTimeWorkRequest> work)
 This method allows you to begin unique chains of work for situations where you only want one
 chain with a given name to be active at a time.  | 
| public abstract WorkContinuation | beginWith(java.util.List<OneTimeWorkRequest> work)
 Begins a chain with one or more OneTimeWorkRequests, which can be enqueued together
 in the future using WorkContinuation.enqueue().  | 
| public abstract Operation | cancelAllWork()
 Cancels all unfinished work.  | 
| public abstract Operation | cancelAllWorkByTag(java.lang.String tag)
 Cancels all unfinished work with the given tag.  | 
| public abstract Operation | cancelUniqueWork(java.lang.String uniqueWorkName)
 Cancels all unfinished work in the work chain with the given name.  | 
| public abstract Operation | cancelWorkById(java.util.UUID id)
 Cancels work with the given id if it isn't finished.  | 
| public void | closeDatabase()
 Cancels workmanager's scope and closes the database  | 
| public abstract PendingIntent | createCancelPendingIntent(java.util.UUID id)
 Creates a PendingIntent which can be used to cancel a WorkRequest with the
 given id.  | 
| public WorkContinuationImpl | createWorkContinuationForUniquePeriodicWork(java.lang.String uniqueWorkName, ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy, PeriodicWorkRequest periodicWork)
 Creates a WorkContinuation for the given unique PeriodicWorkRequest.  | 
| public abstract Operation | enqueue(java.util.List<WorkRequest> requests)
 Enqueues one or more items for background processing.  | 
| public abstract Operation | enqueueUniquePeriodicWork(java.lang.String uniqueWorkName, ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy, PeriodicWorkRequest periodicWork)
 This method allows you to enqueue a uniquely-named PeriodicWorkRequest, where only
 one PeriodicWorkRequest of a particular name can be active at a time.  | 
| public abstract Operation | enqueueUniqueWork(java.lang.String uniqueWorkName, ExistingWorkPolicy existingWorkPolicy, java.util.List<OneTimeWorkRequest> work)
 This method allows you to enqueue work requests to a uniquely-named
 WorkContinuation, where only one continuation of a particular name can be active at
 a time.  | 
| public Context | getApplicationContext()
  | 
| public Configuration | getConfiguration()
  | 
| public static WorkManagerImpl | getInstance()
 Retrieves the singleton instance of WorkManagerImpl.  | 
| public static WorkManagerImpl | getInstance(Context context)
 Retrieves the singleton instance of WorkManagerImpl.  | 
| public abstract <any> | getLastCancelAllTimeMillis()
 Gets a  of the last time all work was cancelled.  | 
| public abstract LiveData<java.lang.Long> | getLastCancelAllTimeMillisLiveData()
 Gets a LiveData of the last time all work was cancelled.  | 
| public PreferenceUtils | getPreferenceUtils()
  | 
| public Processor | getProcessor()
  | 
| public RemoteWorkManager | getRemoteWorkManager()
  | 
| public java.util.List<Scheduler> | getSchedulers()
  | 
| public Trackers | getTrackers()
  | 
| public WorkDatabase | getWorkDatabase()
  | 
| public abstract <any> | getWorkInfoById(java.util.UUID id)
 Gets a  of the WorkInfo for a given work id.  | 
| public <any> | getWorkInfoByIdFlow(java.util.UUID id)
  | 
| public abstract LiveData<WorkInfo> | getWorkInfoByIdLiveData(java.util.UUID id)
 Gets a LiveData of the WorkInfo for a given work id.  | 
| public abstract <any> | getWorkInfos(WorkQuery workQuery)
 Gets the  of the java.util.List of WorkInfo for all work
 referenced by the WorkQuery specification.  | 
| public abstract <any> | getWorkInfosByTag(java.lang.String tag)
 Gets a  of the WorkInfo for all work for a given tag.  | 
| public <any> | getWorkInfosByTagFlow(java.lang.String tag)
  | 
| public abstract LiveData<java.util.List> | getWorkInfosByTagLiveData(java.lang.String tag)
 Gets a LiveData of the WorkInfo for all work for a given tag.  | 
| public <any> | getWorkInfosFlow(WorkQuery workQuery)
  | 
| public abstract <any> | getWorkInfosForUniqueWork(java.lang.String uniqueWorkName)
 Gets a  of the WorkInfo for all work in a work chain
 with a given unique name.  | 
| public <any> | getWorkInfosForUniqueWorkFlow(java.lang.String uniqueWorkName)
  | 
| public abstract LiveData<java.util.List> | getWorkInfosForUniqueWorkLiveData(java.lang.String uniqueWorkName)
 Gets a LiveData of the WorkInfo for all work in a work chain with a given
 unique name.  | 
| public abstract LiveData<java.util.List> | getWorkInfosLiveData(WorkQuery workQuery)
 Gets the LiveData of the java.util.List of WorkInfo for all work
 referenced by the WorkQuery specification.  | 
| public TaskExecutor | getWorkTaskExecutor()
  | 
| public static void | initialize(Context context, Configuration configuration)
 Initializes the singleton instance of WorkManagerImpl.  | 
| public static boolean | isInitialized()
  | 
| public void | onForceStopRunnableCompleted()
 A way for ForceStopRunnable to tell WorkManagerImpl that it has completed.  | 
| public abstract Operation | pruneWork()
 Prunes all eligible finished work from the internal database.  | 
| public void | rescheduleEligibleWork()
 Reschedules all the eligible work.  | 
| public static void | setDelegate(WorkManagerImpl delegate)
  | 
| public void | setReschedulePendingResult(BroadcastReceiver.PendingResult rescheduleReceiverResult)
 This method is invoked by
 RescheduleReceiver
 after a call to BroadcastReceiver.  | 
| public void | stopForegroundWork(WorkGenerationalId id)
  | 
| public <any> | updateWork(WorkRequest request)
  | 
| from WorkManager | beginUniqueWork, beginWith, enqueue, enqueueUniqueWork | 
| from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait | 
Fields
public static final int 
MAX_PRE_JOB_SCHEDULER_API_LEVELpublic static final int 
MIN_JOB_SCHEDULER_API_LEVELpublic static final int 
CONTENT_URI_TRIGGER_API_LEVELpublic static final java.lang.String 
REMOTE_WORK_MANAGER_CLIENTConstructors
Create an instance of WorkManagerImpl.
Parameters:
context: The application 
configuration: The Configuration configuration
workTaskExecutor: The TaskExecutor for running "processing" jobs, such as
                         enqueueing, scheduling, cancellation, etc.
workDatabase: The WorkDatabase instance
processor: The Processor instance
trackers: Trackers
Methods
Parameters:
delegate: The delegate for WorkManagerImpl for testing; null to use the
                 default instance
Deprecated: Call WorkManagerImpl.getInstance(Context) instead.
Retrieves the singleton instance of WorkManagerImpl.
Returns:
The singleton instance of WorkManagerImpl
public static boolean 
isInitialized()
Retrieves the singleton instance of WorkManagerImpl.
Parameters:
context: A context for on-demand initialization.
Returns:
The singleton instance of WorkManagerImpl
public static void 
initialize(Context context, 
Configuration configuration)
Initializes the singleton instance of WorkManagerImpl.  You should only do this if
 you want to use a custom Configuration object and have disabled
 WorkManagerInitializer.
Parameters:
context: A  object for configuration purposes. Internally, this
                      class will call , so you may
                      safely pass in any Context without risking a memory leak.
configuration: The Configuration for used to set up WorkManager.
public Context 
getApplicationContext()
Returns:
The application  associated with this WorkManager.
Returns:
The WorkDatabase instance associated with this WorkManager.
Returns:
The Configuration instance associated with this WorkManager.
public java.util.List<Scheduler> 
getSchedulers()
Returns:
The Schedulers associated with this WorkManager based on the device's
 capabilities, SDK version, etc.
Returns:
The Processor used to process background work.
Returns:
the TaskExecutor used by the instance of WorkManager.
Returns:
the PreferenceUtils used by the instance of WorkManager.
Returns:
the Trackers used by WorkManager
public abstract 
Operation enqueue(java.util.List<WorkRequest> requests)
Enqueues one or more items for background processing.
Parameters:
requests: One or more WorkRequest to enqueue
Returns:
An Operation that can be used to determine when the enqueue has completed
public abstract 
WorkContinuation beginWith(java.util.List<OneTimeWorkRequest> work)
Begins a chain with one or more OneTimeWorkRequests, which can be enqueued together
 in the future using WorkContinuation.enqueue().
 
 If any work in the chain fails or is cancelled, all of its dependent work inherits that state
 and will never run.
Parameters:
work: One or more OneTimeWorkRequest to start a chain of work
Returns:
A WorkContinuation that allows for further chaining of dependent
         OneTimeWorkRequest
This method allows you to begin unique chains of work for situations where you only want one
 chain with a given name to be active at a time.  For example, you may only want one sync
 operation to be active.  If there is one pending, you can choose to let it run or replace it
 with your new work.
 
 The uniqueWorkName uniquely identifies this set of work.
 
 If this method determines that new work should be enqueued and run, all records of previous
 work with uniqueWorkName will be pruned.  If this method determines that new work
 should NOT be run, then the entire chain will be considered a no-op.
 
 If any work in the chain fails or is cancelled, all of its dependent work inherits that state
 and will never run.  This is particularly important if you are using APPEND as your
 ExistingWorkPolicy.
Parameters:
uniqueWorkName: A unique name which for this chain of work
existingWorkPolicy: An ExistingWorkPolicy; see below for more information
work: One or more OneTimeWorkRequest to enqueue. REPLACE ensures that
             if there is pending work labelled with uniqueWorkName, it will be
             cancelled and the new work will run. KEEP will run the new sequence of
             work only if there is no pending work labelled with uniqueWorkName.
             APPEND will create a new sequence of work if there is no
             existing work with uniqueWorkName; otherwise, work will be added
             as a child of all leaf nodes labelled with uniqueWorkName.
Returns:
A WorkContinuation that allows further chaining
public abstract 
Operation enqueueUniqueWork(java.lang.String uniqueWorkName, 
ExistingWorkPolicy existingWorkPolicy, java.util.List<OneTimeWorkRequest> work)
This method allows you to enqueue work requests to a uniquely-named
 WorkContinuation, where only one continuation of a particular name can be active at
 a time. For example, you may only want one sync operation to be active. If there is one
 pending, you can choose to let it run or replace it with your new work.
 
 The uniqueWorkName uniquely identifies this WorkContinuation.
Parameters:
uniqueWorkName: A unique name which for this operation
existingWorkPolicy: An ExistingWorkPolicy
work: OneTimeWorkRequests to enqueue. REPLACE ensures
                     that if there is pending work labelled with uniqueWorkName, it
                     will be cancelled and the new work will run. KEEP will run the
                     new OneTimeWorkRequests only if there is no pending work labelled with
                     uniqueWorkName. APPEND will append the
                     OneTimeWorkRequests as leaf nodes labelled with uniqueWorkName.
Returns:
An Operation that can be used to determine when the enqueue has completed
This method allows you to enqueue a uniquely-named PeriodicWorkRequest, where only
 one PeriodicWorkRequest of a particular name can be active at a time.  For example, you may
 only want one sync operation to be active.  If there is one pending, you can choose to let it
 run or replace it with your new work.
 
 The uniqueWorkName uniquely identifies this PeriodicWorkRequest.
Parameters:
uniqueWorkName: A unique name which for this operation
existingPeriodicWorkPolicy: An ExistingPeriodicWorkPolicy
periodicWork: A PeriodicWorkRequest to enqueue. REPLACE ensures that if
                     there is pending work labelled with uniqueWorkName, it will be
                     cancelled and the new work will run. KEEP will run the new
                     PeriodicWorkRequest only if there is no pending work labelled with
                     uniqueWorkName.
Returns:
An Operation that can be used to determine when the enqueue has completed
Creates a WorkContinuation for the given unique PeriodicWorkRequest.
public abstract 
Operation cancelWorkById(java.util.UUID id)
Cancels work with the given id if it isn't finished.  Note that cancellation is a best-effort
 policy and work that is already executing may continue to run.  Upon cancellation,
 ListenableWorker.onStopped() will be invoked for any affected workers.
Parameters:
id: The id of the work
Returns:
An Operation that can be used to determine when the cancelWorkById has
 completed
public abstract 
Operation cancelAllWorkByTag(java.lang.String tag)
Cancels all unfinished work with the given tag.  Note that cancellation is a best-effort
 policy and work that is already executing may continue to run.  Upon cancellation,
 ListenableWorker.onStopped() will be invoked for any affected workers.
Parameters:
tag: The tag used to identify the work
Returns:
An Operation that can be used to determine when the cancelAllWorkByTag has
 completed
public abstract 
Operation cancelUniqueWork(java.lang.String uniqueWorkName)
Cancels all unfinished work in the work chain with the given name.  Note that cancellation is
 a best-effort policy and work that is already executing may continue to run.  Upon
 cancellation, ListenableWorker.onStopped() will be invoked for any affected workers.
Parameters:
uniqueWorkName: The unique name used to identify the chain of work
Returns:
An Operation that can be used to determine when the cancelUniqueWork has
 completed
Cancels all unfinished work.  Use this method with extreme caution!  By invoking it,
 you will potentially affect other modules or libraries in your codebase.  It is strongly
 recommended that you use one of the other cancellation methods at your disposal.
 
 Upon cancellation, ListenableWorker.onStopped() will be invoked for any affected
 workers.
Returns:
An Operation that can be used to determine when the cancelAllWork has
 completed
public abstract PendingIntent 
createCancelPendingIntent(java.util.UUID id)
Creates a PendingIntent which can be used to cancel a WorkRequest with the
 given id.
Parameters:
id: The WorkRequest id.
Returns:
The PendingIntent that can be used to cancel the WorkRequest.
public abstract 
LiveData<java.lang.Long> 
getLastCancelAllTimeMillisLiveData()
Gets a LiveData of the last time all work was cancelled.  This method is intended for
 use by library and module developers who have dependent data in their own repository that
 must be updated or deleted in case someone cancels their work without their prior knowledge.
Returns:
A LiveData of the timestamp (System#getCurrentTimeMillis()) when
         WorkManager.cancelAllWork() was last invoked; this timestamp may be 0L if this
         never occurred
public abstract <any> 
getLastCancelAllTimeMillis()
Gets a  of the last time all work was cancelled.  This method is
 intended for use by library and module developers who have dependent data in their own
 repository that must be updated or deleted in case someone cancels their work without
 their prior knowledge.
Returns:
A  of the timestamp (System#getCurrentTimeMillis())
         when WorkManager.cancelAllWork() was last invoked; this timestamp may be 0L if
         this never occurred
Prunes all eligible finished work from the internal database.  Eligible work must be finished
 (WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, or
 WorkInfo.State.CANCELLED), with zero unfinished dependents.
 
 Use this method with caution; by invoking it, you (and any modules and libraries in
 your codebase) will no longer be able to observe the WorkInfo of the pruned work.
 You do not normally need to call this method - WorkManager takes care to auto-prune its work
 after a sane period of time.  This method also ignores the
 WorkRequest.Builder.keepResultsForAtLeast(long, TimeUnit) policy.
Returns:
An Operation that can be used to determine when the pruneWork has
 completed
public abstract 
LiveData<WorkInfo> 
getWorkInfoByIdLiveData(java.util.UUID id)
Gets a LiveData of the WorkInfo for a given work id.
Parameters:
id: The id of the work
Returns:
A LiveData of the WorkInfo associated with id; note that
         this WorkInfo may be null if id is not known to
         WorkManager.
public <any> 
getWorkInfoByIdFlow(java.util.UUID id)
public abstract <any> 
getWorkInfoById(java.util.UUID id)
Gets a  of the WorkInfo for a given work id.
Parameters:
id: The id of the work
Returns:
A  of the WorkInfo associated with id;
 note that this WorkInfo may be null if id is not known to
 WorkManager
public <any> 
getWorkInfosByTagFlow(java.lang.String tag)
public abstract 
LiveData<java.util.List> 
getWorkInfosByTagLiveData(java.lang.String tag)
Gets a LiveData of the WorkInfo for all work for a given tag.
Parameters:
tag: The tag of the work
Returns:
A LiveData list of WorkInfo for work tagged with tag
public abstract <any> 
getWorkInfosByTag(java.lang.String tag)
Gets a  of the WorkInfo for all work for a given tag.
Parameters:
tag: The tag of the work
Returns:
A  list of WorkInfo for work tagged with
 tag
public abstract 
LiveData<java.util.List> 
getWorkInfosForUniqueWorkLiveData(java.lang.String uniqueWorkName)
Gets a LiveData of the WorkInfo for all work in a work chain with a given
 unique name.
Parameters:
uniqueWorkName: The unique name used to identify the chain of work
Returns:
A LiveData of the WorkInfo for work in the chain named
         uniqueWorkName
public <any> 
getWorkInfosForUniqueWorkFlow(java.lang.String uniqueWorkName)
public abstract <any> 
getWorkInfosForUniqueWork(java.lang.String uniqueWorkName)
Gets a  of the WorkInfo for all work in a work chain
 with a given unique name.
Parameters:
uniqueWorkName: The unique name used to identify the chain of work
Returns:
A  of the WorkInfo for work in the chain named
         uniqueWorkName
Gets the LiveData of the java.util.List of WorkInfo for all work
 referenced by the WorkQuery specification.
Parameters:
workQuery: The work query specification
Returns:
A LiveData of the java.util.List of WorkInfo for work
 referenced by this WorkQuery.
public <any> 
getWorkInfosFlow(
WorkQuery workQuery)
public abstract <any> 
getWorkInfos(
WorkQuery workQuery)
Gets the  of the java.util.List of WorkInfo for all work
 referenced by the WorkQuery specification.
Parameters:
workQuery: The work query specification
Returns:
A  of the java.util.List of WorkInfo for work
 referenced by this WorkQuery.
public void 
stopForegroundWork(WorkGenerationalId id)
Parameters:
id: The WorkSpec id to stop when running in the context of a
           foreground service.
public void 
rescheduleEligibleWork()
Reschedules all the eligible work. Useful for cases like, app was force stopped or
 BOOT_COMPLETED, TIMEZONE_CHANGED and TIME_SET for AlarmManager.
public void 
onForceStopRunnableCompleted()
A way for ForceStopRunnable to tell WorkManagerImpl that it has completed.
public void 
setReschedulePendingResult(BroadcastReceiver.PendingResult rescheduleReceiverResult)
This method is invoked by
 RescheduleReceiver
 after a call to BroadcastReceiver. Once ForceStopRunnable is done,
 we can safely call .
public void 
closeDatabase()
Cancels workmanager's scope and closes the database
Source
/*
 * Copyright 2017 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.impl;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.text.TextUtils.isEmpty;
import static androidx.work.ListenableFutureKt.executeAsync;
import static androidx.work.impl.UnfinishedWorkListenerKt.maybeLaunchUnfinishedWorkListener;
import static androidx.work.impl.WorkManagerImplExtKt.createWorkManager;
import static androidx.work.impl.WorkManagerImplExtKt.createWorkManagerScope;
import static androidx.work.impl.WorkerUpdater.enqueueUniquelyNamedPeriodic;
import static androidx.work.impl.foreground.SystemForegroundDispatcher.createCancelWorkIntent;
import static androidx.work.impl.model.RawWorkInfoDaoKt.getWorkInfoPojosFlow;
import static androidx.work.impl.model.WorkSpecDaoKt.getWorkStatusPojoFlowDataForIds;
import static androidx.work.impl.model.WorkSpecDaoKt.getWorkStatusPojoFlowForName;
import static androidx.work.impl.model.WorkSpecDaoKt.getWorkStatusPojoFlowForTag;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.arch.core.util.Function;
import androidx.lifecycle.LiveData;
import androidx.work.Configuration;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.ExistingWorkPolicy;
import androidx.work.Logger;
import androidx.work.OneTimeWorkRequest;
import androidx.work.Operation;
import androidx.work.PeriodicWorkRequest;
import androidx.work.TracerKt;
import androidx.work.WorkContinuation;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import androidx.work.WorkQuery;
import androidx.work.WorkRequest;
import androidx.work.impl.background.systemalarm.RescheduleReceiver;
import androidx.work.impl.background.systemjob.SystemJobScheduler;
import androidx.work.impl.constraints.trackers.Trackers;
import androidx.work.impl.model.RawWorkInfoDao;
import androidx.work.impl.model.WorkGenerationalId;
import androidx.work.impl.model.WorkSpec;
import androidx.work.impl.model.WorkSpecDao;
import androidx.work.impl.utils.CancelWorkRunnable;
import androidx.work.impl.utils.ForceStopRunnable;
import androidx.work.impl.utils.LiveDataUtils;
import androidx.work.impl.utils.PreferenceUtils;
import androidx.work.impl.utils.PruneWorkRunnableKt;
import androidx.work.impl.utils.RawQueries;
import androidx.work.impl.utils.StatusRunnable;
import androidx.work.impl.utils.StopWorkRunnable;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
import androidx.work.multiprocess.RemoteWorkManager;
import com.google.common.util.concurrent.ListenableFuture;
import kotlin.Unit;
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.flow.Flow;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
/**
 * A concrete implementation of {@link WorkManager}.
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class WorkManagerImpl extends WorkManager {
    private static final String TAG = Logger.tagWithPrefix("WorkManagerImpl");
    public static final int MAX_PRE_JOB_SCHEDULER_API_LEVEL = 22;
    public static final int MIN_JOB_SCHEDULER_API_LEVEL = 23;
    public static final int CONTENT_URI_TRIGGER_API_LEVEL = 24;
    public static final String REMOTE_WORK_MANAGER_CLIENT =
            "androidx.work.multiprocess.RemoteWorkManagerClient";
    private Context mContext;
    private Configuration mConfiguration;
    private WorkDatabase mWorkDatabase;
    private TaskExecutor mWorkTaskExecutor;
    private List<Scheduler> mSchedulers;
    private Processor mProcessor;
    private PreferenceUtils mPreferenceUtils;
    private boolean mForceStopRunnableCompleted = false;
    private BroadcastReceiver.PendingResult mRescheduleReceiverResult;
    private volatile RemoteWorkManager mRemoteWorkManager;
    private final Trackers mTrackers;
    /**
     * Job for the scope of the whole WorkManager
     */
    private final CoroutineScope mWorkManagerScope;
    private static WorkManagerImpl sDelegatedInstance = null;
    private static WorkManagerImpl sDefaultInstance = null;
    private static final Object sLock = new Object();
    /**
     * @param delegate The delegate for {@link WorkManagerImpl} for testing; {@code null} to use the
     *                 default instance
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static void setDelegate(@Nullable WorkManagerImpl delegate) {
        synchronized (sLock) {
            sDelegatedInstance = delegate;
        }
    }
    /**
     * Retrieves the singleton instance of {@link WorkManagerImpl}.
     *
     * @return The singleton instance of {@link WorkManagerImpl}
     * @deprecated Call {@link WorkManagerImpl#getInstance(Context)} instead.
     */
    @Deprecated
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @SuppressWarnings("NullableProblems")
    public static @Nullable WorkManagerImpl getInstance() {
        synchronized (sLock) {
            if (sDelegatedInstance != null) {
                return sDelegatedInstance;
            }
            return sDefaultInstance;
        }
    }
    /**
     *
     */
    @SuppressWarnings("deprecation")
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static boolean isInitialized() {
        WorkManagerImpl instance = getInstance();
        return instance != null;
    }
    /**
     * Retrieves the singleton instance of {@link WorkManagerImpl}.
     *
     * @param context A context for on-demand initialization.
     * @return The singleton instance of {@link WorkManagerImpl}
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) {
        synchronized (sLock) {
            WorkManagerImpl instance = getInstance();
            if (instance == null) {
                Context appContext = context.getApplicationContext();
                if (appContext instanceof Configuration.Provider) {
                    initialize(
                            appContext,
                            ((Configuration.Provider) appContext).getWorkManagerConfiguration());
                    instance = getInstance(appContext);
                } else {
                    throw new IllegalStateException("WorkManager is not initialized properly.  You "
                            + "have explicitly disabled WorkManagerInitializer in your manifest, "
                            + "have not manually called WorkManager#initialize at this point, and "
                            + "your Application does not implement Configuration.Provider.");
                }
            }
            return instance;
        }
    }
    /**
     * Initializes the singleton instance of {@link WorkManagerImpl}.  You should only do this if
     * you want to use a custom {@link Configuration} object and have disabled
     * WorkManagerInitializer.
     *
     * @param context       A {@link Context} object for configuration purposes. Internally, this
     *                      class will call {@link Context#getApplicationContext()}, so you may
     *                      safely pass in any Context without risking a memory leak.
     * @param configuration The {@link Configuration} for used to set up WorkManager.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
        synchronized (sLock) {
            if (sDelegatedInstance != null && sDefaultInstance != null) {
                throw new IllegalStateException("WorkManager is already initialized.  Did you "
                        + "try to initialize it manually without disabling "
                        + "WorkManagerInitializer? See "
                        + "WorkManager#initialize(Context, Configuration) or the class level "
                        + "Javadoc for more information.");
            }
            if (sDelegatedInstance == null) {
                context = context.getApplicationContext();
                if (sDefaultInstance == null) {
                    sDefaultInstance = createWorkManager(context, configuration);
                }
                sDelegatedInstance = sDefaultInstance;
            }
        }
    }
    /**
     * Create an instance of {@link WorkManagerImpl}.
     *
     * @param context          The application {@link Context}
     * @param configuration    The {@link Configuration} configuration
     * @param workTaskExecutor The {@link TaskExecutor} for running "processing" jobs, such as
     *                         enqueueing, scheduling, cancellation, etc.
     * @param workDatabase     The {@link WorkDatabase} instance
     * @param processor        The {@link Processor} instance
     * @param trackers         Trackers
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public WorkManagerImpl(
            @NonNull Context context,
            @NonNull Configuration configuration,
            @NonNull TaskExecutor workTaskExecutor,
            @NonNull WorkDatabase workDatabase,
            @NonNull List<Scheduler> schedulers,
            @NonNull Processor processor,
            @NonNull Trackers trackers) {
        context = context.getApplicationContext();
        // Check for direct boot mode
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Api24Impl.isDeviceProtectedStorage(
                context)) {
            throw new IllegalStateException("Cannot initialize WorkManager in direct boot mode");
        }
        Logger.setLogger(new Logger.LogcatLogger(configuration.getMinimumLoggingLevel()));
        mContext = context;
        mWorkTaskExecutor = workTaskExecutor;
        mWorkDatabase = workDatabase;
        mProcessor = processor;
        mTrackers = trackers;
        mConfiguration = configuration;
        mSchedulers = schedulers;
        mWorkManagerScope = createWorkManagerScope(mWorkTaskExecutor);
        mPreferenceUtils = new PreferenceUtils(mWorkDatabase);
        Schedulers.registerRescheduling(schedulers, mProcessor,
                workTaskExecutor.getSerialTaskExecutor(), mWorkDatabase, configuration);
        // Checks for app force stops.
        mWorkTaskExecutor.executeOnTaskThread(new ForceStopRunnable(context, this));
        maybeLaunchUnfinishedWorkListener(mWorkManagerScope, mContext, configuration, workDatabase);
    }
    /**
     * @return The application {@link Context} associated with this WorkManager.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    public Context getApplicationContext() {
        return mContext;
    }
    /**
     * @return The {@link WorkDatabase} instance associated with this WorkManager.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    public WorkDatabase getWorkDatabase() {
        return mWorkDatabase;
    }
    /**
     * @return workmanager's CoroutineScope
     */
    @NonNull
    CoroutineScope getWorkManagerScope() {
        return mWorkManagerScope;
    }
    /**
     * @return The {@link Configuration} instance associated with this WorkManager.
     */
    @NonNull
    @Override
    public Configuration getConfiguration() {
        return mConfiguration;
    }
    /**
     * @return The {@link Scheduler}s associated with this WorkManager based on the device's
     * capabilities, SDK version, etc.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull List<Scheduler> getSchedulers() {
        return mSchedulers;
    }
    /**
     * @return The {@link Processor} used to process background work.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull Processor getProcessor() {
        return mProcessor;
    }
    /**
     * @return the {@link TaskExecutor} used by the instance of {@link WorkManager}.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull TaskExecutor getWorkTaskExecutor() {
        return mWorkTaskExecutor;
    }
    /**
     * @return the {@link PreferenceUtils} used by the instance of {@link WorkManager}.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull PreferenceUtils getPreferenceUtils() {
        return mPreferenceUtils;
    }
    /**
     * @return the {@link Trackers} used by {@link WorkManager}
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    public Trackers getTrackers() {
        return mTrackers;
    }
    @Override
    @NonNull
    public Operation enqueue(
            @NonNull List<? extends WorkRequest> requests) {
        // This error is not being propagated as part of the Operation, as we want the
        // app to crash during development. Having no workRequests is always a developer error.
        if (requests.isEmpty()) {
            throw new IllegalArgumentException(
                    "enqueue needs at least one WorkRequest.");
        }
        return new WorkContinuationImpl(this, requests).enqueue();
    }
    @Override
    public @NonNull WorkContinuation beginWith(@NonNull List<OneTimeWorkRequest> requests) {
        if (requests.isEmpty()) {
            throw new IllegalArgumentException(
                    "beginWith needs at least one OneTimeWorkRequest.");
        }
        return new WorkContinuationImpl(this, requests);
    }
    @Override
    public @NonNull WorkContinuation beginUniqueWork(
            @NonNull String uniqueWorkName,
            @NonNull ExistingWorkPolicy existingWorkPolicy,
            @NonNull List<OneTimeWorkRequest> requests) {
        if (requests.isEmpty()) {
            throw new IllegalArgumentException(
                    "beginUniqueWork needs at least one OneTimeWorkRequest.");
        }
        return new WorkContinuationImpl(this, uniqueWorkName, existingWorkPolicy, requests);
    }
    @NonNull
    @Override
    public Operation enqueueUniqueWork(@NonNull String uniqueWorkName,
            @NonNull ExistingWorkPolicy existingWorkPolicy,
            @NonNull List<OneTimeWorkRequest> requests) {
        return new WorkContinuationImpl(this, uniqueWorkName,
                existingWorkPolicy, requests).enqueue();
    }
    @Override
    @NonNull
    public Operation enqueueUniquePeriodicWork(
            @NonNull String uniqueWorkName,
            @NonNull ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy,
            @NonNull PeriodicWorkRequest request) {
        if (existingPeriodicWorkPolicy == ExistingPeriodicWorkPolicy.UPDATE) {
            return enqueueUniquelyNamedPeriodic(this, uniqueWorkName, request);
        }
        return createWorkContinuationForUniquePeriodicWork(
                uniqueWorkName,
                existingPeriodicWorkPolicy,
                request)
                .enqueue();
    }
    /**
     * Creates a {@link WorkContinuation} for the given unique {@link PeriodicWorkRequest}.
     */
    @NonNull
    public WorkContinuationImpl createWorkContinuationForUniquePeriodicWork(
            @NonNull String uniqueWorkName,
            @NonNull ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy,
            @NonNull PeriodicWorkRequest periodicWork) {
        ExistingWorkPolicy existingWorkPolicy;
        if (existingPeriodicWorkPolicy == ExistingPeriodicWorkPolicy.KEEP) {
            existingWorkPolicy = ExistingWorkPolicy.KEEP;
        } else {
            existingWorkPolicy = ExistingWorkPolicy.REPLACE;
        }
        return new WorkContinuationImpl(
                this,
                uniqueWorkName,
                existingWorkPolicy,
                Collections.singletonList(periodicWork));
    }
    @Override
    public @NonNull Operation cancelWorkById(@NonNull UUID id) {
        return CancelWorkRunnable.forId(id, this);
    }
    @Override
    public @NonNull Operation cancelAllWorkByTag(@NonNull final String tag) {
        return CancelWorkRunnable.forTag(tag, this);
    }
    @Override
    @NonNull
    public Operation cancelUniqueWork(@NonNull String uniqueWorkName) {
        return CancelWorkRunnable.forName(uniqueWorkName, this);
    }
    @Override
    public @NonNull Operation cancelAllWork() {
        return CancelWorkRunnable.forAll(this);
    }
    @NonNull
    @Override
    public PendingIntent createCancelPendingIntent(@NonNull UUID id) {
        Intent intent = createCancelWorkIntent(mContext, id.toString());
        int flags = FLAG_UPDATE_CURRENT;
        if (Build.VERSION.SDK_INT >= 31) {
            flags |= FLAG_MUTABLE;
        }
        return PendingIntent.getService(mContext, 0, intent, flags);
    }
    @Override
    public @NonNull LiveData<Long> getLastCancelAllTimeMillisLiveData() {
        return mPreferenceUtils.getLastCancelAllTimeMillisLiveData();
    }
    @Override
    public @NonNull ListenableFuture<Long> getLastCancelAllTimeMillis() {
        final PreferenceUtils preferenceUtils = mPreferenceUtils;
        return executeAsync(mWorkTaskExecutor.getSerialTaskExecutor(),
                "getLastCancelAllTimeMillis", preferenceUtils::getLastCancelAllTimeMillis);
    }
    @Override
    public @NonNull Operation pruneWork() {
        return PruneWorkRunnableKt.pruneWork(mWorkDatabase, mConfiguration, mWorkTaskExecutor);
    }
    @Override
    public @NonNull LiveData<WorkInfo> getWorkInfoByIdLiveData(@NonNull UUID id) {
        WorkSpecDao dao = mWorkDatabase.workSpecDao();
        LiveData<List<WorkSpec.WorkInfoPojo>> inputLiveData =
                dao.getWorkStatusPojoLiveDataForIds(Collections.singletonList(id.toString()));
        return LiveDataUtils.dedupedMappedLiveDataFor(inputLiveData,
                new Function<List<WorkSpec.WorkInfoPojo>, WorkInfo>() {
                    @Override
                    public WorkInfo apply(List<WorkSpec.WorkInfoPojo> input) {
                        WorkInfo workInfo = null;
                        if (input != null && input.size() > 0) {
                            workInfo = input.get(0).toWorkInfo();
                        }
                        return workInfo;
                    }
                },
                mWorkTaskExecutor);
    }
    @NonNull
    @Override
    public Flow<WorkInfo> getWorkInfoByIdFlow(@NonNull UUID id) {
        return getWorkStatusPojoFlowDataForIds(getWorkDatabase().workSpecDao(), id);
    }
    @Override
    public @NonNull ListenableFuture<WorkInfo> getWorkInfoById(@NonNull UUID id) {
        return StatusRunnable.forUUID(mWorkDatabase, mWorkTaskExecutor, id);
    }
    @NonNull
    @Override
    public Flow<List<WorkInfo>> getWorkInfosByTagFlow(@NonNull String tag) {
        WorkSpecDao workSpecDao = mWorkDatabase.workSpecDao();
        return getWorkStatusPojoFlowForTag(workSpecDao,
                mWorkTaskExecutor.getTaskCoroutineDispatcher(), tag);
    }
    @Override
    public @NonNull LiveData<List<WorkInfo>> getWorkInfosByTagLiveData(@NonNull String tag) {
        WorkSpecDao workSpecDao = mWorkDatabase.workSpecDao();
        LiveData<List<WorkSpec.WorkInfoPojo>> inputLiveData =
                workSpecDao.getWorkStatusPojoLiveDataForTag(tag);
        return LiveDataUtils.dedupedMappedLiveDataFor(
                inputLiveData,
                WorkSpec.WORK_INFO_MAPPER,
                mWorkTaskExecutor);
    }
    @Override
    public @NonNull ListenableFuture<List<WorkInfo>> getWorkInfosByTag(@NonNull String tag) {
        return StatusRunnable.forTag(mWorkDatabase, mWorkTaskExecutor, tag);
    }
    @Override
    @NonNull
    public LiveData<List<WorkInfo>> getWorkInfosForUniqueWorkLiveData(
            @NonNull String uniqueWorkName) {
        WorkSpecDao workSpecDao = mWorkDatabase.workSpecDao();
        LiveData<List<WorkSpec.WorkInfoPojo>> inputLiveData =
                workSpecDao.getWorkStatusPojoLiveDataForName(uniqueWorkName);
        return LiveDataUtils.dedupedMappedLiveDataFor(
                inputLiveData,
                WorkSpec.WORK_INFO_MAPPER,
                mWorkTaskExecutor);
    }
    @NonNull
    @Override
    public Flow<List<WorkInfo>> getWorkInfosForUniqueWorkFlow(@NonNull String uniqueWorkName) {
        WorkSpecDao workSpecDao = mWorkDatabase.workSpecDao();
        return getWorkStatusPojoFlowForName(workSpecDao,
                mWorkTaskExecutor.getTaskCoroutineDispatcher(), uniqueWorkName);
    }
    @Override
    @NonNull
    public ListenableFuture<List<WorkInfo>> getWorkInfosForUniqueWork(
            @NonNull String uniqueWorkName) {
        return StatusRunnable.forUniqueWork(mWorkDatabase, mWorkTaskExecutor, uniqueWorkName);
    }
    @NonNull
    @Override
    public LiveData<List<WorkInfo>> getWorkInfosLiveData(
            @NonNull WorkQuery workQuery) {
        RawWorkInfoDao rawWorkInfoDao = mWorkDatabase.rawWorkInfoDao();
        LiveData<List<WorkSpec.WorkInfoPojo>> inputLiveData =
                rawWorkInfoDao.getWorkInfoPojosLiveData(
                        RawQueries.toRawQuery(workQuery));
        return LiveDataUtils.dedupedMappedLiveDataFor(
                inputLiveData,
                WorkSpec.WORK_INFO_MAPPER,
                mWorkTaskExecutor);
    }
    @NonNull
    @Override
    public Flow<List<WorkInfo>> getWorkInfosFlow(@NonNull WorkQuery workQuery) {
        RawWorkInfoDao rawWorkInfoDao = mWorkDatabase.rawWorkInfoDao();
        return getWorkInfoPojosFlow(rawWorkInfoDao, mWorkTaskExecutor.getTaskCoroutineDispatcher(),
                RawQueries.toRawQuery(workQuery));
    }
    @NonNull
    @Override
    public ListenableFuture<List<WorkInfo>> getWorkInfos(@NonNull WorkQuery workQuery) {
        return StatusRunnable.forWorkQuerySpec(mWorkDatabase, mWorkTaskExecutor, workQuery);
    }
    @NonNull
    @Override
    public ListenableFuture<UpdateResult> updateWork(@NonNull WorkRequest request) {
        return WorkerUpdater.updateWorkImpl(this, request);
    }
    LiveData<List<WorkInfo>> getWorkInfosById(@NonNull List<String> workSpecIds) {
        WorkSpecDao dao = mWorkDatabase.workSpecDao();
        LiveData<List<WorkSpec.WorkInfoPojo>> inputLiveData =
                dao.getWorkStatusPojoLiveDataForIds(workSpecIds);
        return LiveDataUtils.dedupedMappedLiveDataFor(
                inputLiveData,
                WorkSpec.WORK_INFO_MAPPER,
                mWorkTaskExecutor);
    }
    /**
     *
     */
    @Nullable
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public RemoteWorkManager getRemoteWorkManager() {
        if (mRemoteWorkManager == null) {
            synchronized (sLock) {
                if (mRemoteWorkManager == null) {
                    // Initialize multi-process support.
                    tryInitializeMultiProcessSupport();
                    if (mRemoteWorkManager == null && !isEmpty(
                            mConfiguration.getDefaultProcessName())) {
                        String message = "Invalid multiprocess configuration. Define an "
                                + "`implementation` dependency on :work:work-multiprocess library";
                        throw new IllegalStateException(message);
                    }
                }
            }
        }
        return mRemoteWorkManager;
    }
    /**
     * @param id The {@link WorkSpec} id to stop when running in the context of a
     *           foreground service.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void stopForegroundWork(@NonNull WorkGenerationalId id) {
        mWorkTaskExecutor.executeOnTaskThread(new StopWorkRunnable(mProcessor,
                new StartStopToken(id), true));
    }
    /**
     * Reschedules all the eligible work. Useful for cases like, app was force stopped or
     * BOOT_COMPLETED, TIMEZONE_CHANGED and TIME_SET for AlarmManager.
     */
    public void rescheduleEligibleWork() {
        // Delegate to the getter so mocks continue to work when testing.
        Configuration configuration = getConfiguration();
        TracerKt.traced(configuration.getTracer(), "ReschedulingWork", () -> {
            // This gives us an easy way to clear persisted work state, and then reschedule work
            // that WorkManager is aware of. Ideally, we do something similar for other
            // persistent schedulers.
            if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
                SystemJobScheduler.cancelAllInAllNamespaces(getApplicationContext());
            }
            // Reset scheduled state.
            getWorkDatabase().workSpecDao().resetScheduledState();
            // Delegate to the WorkManager's schedulers.
            // Using getters here so we can use from a mocked instance
            // of WorkManagerImpl.
            Schedulers.schedule(getConfiguration(), getWorkDatabase(), getSchedulers());
            return Unit.INSTANCE;
        });
    }
    /**
     * A way for {@link ForceStopRunnable} to tell {@link WorkManagerImpl} that it has completed.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void onForceStopRunnableCompleted() {
        synchronized (sLock) {
            mForceStopRunnableCompleted = true;
            if (mRescheduleReceiverResult != null) {
                mRescheduleReceiverResult.finish();
                mRescheduleReceiverResult = null;
            }
        }
    }
    /**
     * This method is invoked by
     * {@link RescheduleReceiver}
     * after a call to {@link BroadcastReceiver#goAsync()}. Once {@link ForceStopRunnable} is done,
     * we can safely call {@link BroadcastReceiver.PendingResult#finish()}.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void setReschedulePendingResult(
            @NonNull BroadcastReceiver.PendingResult rescheduleReceiverResult) {
        synchronized (sLock) {
            // if we have two broadcast in the row, finish old one and use new one
            if (mRescheduleReceiverResult != null) {
                mRescheduleReceiverResult.finish();
            }
            mRescheduleReceiverResult = rescheduleReceiverResult;
            if (mForceStopRunnableCompleted) {
                mRescheduleReceiverResult.finish();
                mRescheduleReceiverResult = null;
            }
        }
    }
    /**
     * Cancels workmanager's scope and closes the database
     */
    public void closeDatabase() {
        WorkManagerImplExtKt.close(this);
    }
    /**
     * Tries to find a multi-process safe implementation for  {@link WorkManager}.
     */
    private void tryInitializeMultiProcessSupport() {
        try {
            Class<?> klass = Class.forName(REMOTE_WORK_MANAGER_CLIENT);
            mRemoteWorkManager = (RemoteWorkManager) klass.getConstructor(
                    Context.class, WorkManagerImpl.class
            ).newInstance(mContext, this);
        } catch (Throwable throwable) {
            Logger.get().debug(TAG, "Unable to initialize multi-process support", throwable);
        }
    }
    @RequiresApi(24)
    static class Api24Impl {
        private Api24Impl() {
            // This class is not instantiable.
        }
        static boolean isDeviceProtectedStorage(Context context) {
            return context.isDeviceProtectedStorage();
        }
    }
}