Make the enqueue() of a continuation transactional.
Test: Updated unit tests

Change-Id: Iecd60d247b008856a59fb8f61c24d0e9f86e54ae
diff --git a/background/workmanager/src/androidTest/java/android/arch/background/workmanager/impl/WorkContinuationImplTest.java b/background/workmanager/src/androidTest/java/android/arch/background/workmanager/impl/WorkContinuationImplTest.java
index 572b3e6..de17404 100644
--- a/background/workmanager/src/androidTest/java/android/arch/background/workmanager/impl/WorkContinuationImplTest.java
+++ b/background/workmanager/src/androidTest/java/android/arch/background/workmanager/impl/WorkContinuationImplTest.java
@@ -16,58 +16,104 @@
 
 package android.arch.background.workmanager.impl;
 
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
 
+import android.arch.background.workmanager.TestLifecycleOwner;
 import android.arch.background.workmanager.Work;
-import android.arch.background.workmanager.impl.utils.EnqueueRunnable;
-import android.arch.background.workmanager.impl.utils.taskexecutor.TaskExecutor;
+import android.arch.background.workmanager.executors.SynchronousExecutorService;
+import android.arch.background.workmanager.impl.utils.taskexecutor.InstantTaskExecutorRule;
 import android.arch.background.workmanager.worker.TestWorker;
+import android.arch.core.executor.ArchTaskExecutor;
+import android.arch.lifecycle.Lifecycle;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class WorkContinuationImplTest {
 
+    private WorkDatabase mDatabase;
     private WorkManagerImpl mWorkManagerImpl;
-    private TaskExecutor mTaskExecutor;
+
+    @Rule
+    public InstantTaskExecutorRule mRule = new InstantTaskExecutorRule();
 
     @Before
-    public void setup() {
-        mWorkManagerImpl = mock(WorkManagerImpl.class);
-        mTaskExecutor = mock(TaskExecutor.class);
-        when(mWorkManagerImpl.getTaskExecutor()).thenReturn(mTaskExecutor);
+    public void setUp() {
+        ArchTaskExecutor.getInstance().setDelegate(new android.arch.core.executor.TaskExecutor() {
+            @Override
+            public void executeOnDiskIO(@NonNull Runnable runnable) {
+                runnable.run();
+            }
+
+            @Override
+            public void postToMainThread(@NonNull Runnable runnable) {
+                runnable.run();
+            }
+
+            @Override
+            public boolean isMainThread() {
+                return true;
+            }
+        });
+
+        TestLifecycleOwner lifecycleOwner = new TestLifecycleOwner();
+        lifecycleOwner.mLifecycleRegistry.markState(Lifecycle.State.CREATED);
+
+        Context context = InstrumentationRegistry.getTargetContext();
+        WorkManagerConfiguration configuration = new WorkManagerConfiguration(
+                context,
+                true,
+                new SynchronousExecutorService(),
+                new SynchronousExecutorService(),
+                lifecycleOwner);
+        mWorkManagerImpl = new WorkManagerImpl(context, configuration);
+        mDatabase = mWorkManagerImpl.getWorkDatabase();
+    }
+
+    @After
+    public void tearDown() {
+        List<String> ids = mDatabase.workSpecDao().getAllWorkSpecIds();
+        for (String id : ids) {
+            mWorkManagerImpl.cancelWorkForId(id);
+        }
+        mDatabase.close();
+        ArchTaskExecutor.getInstance().setDelegate(null);
     }
 
     @Test
-    public void testLazyContinuation_noParent() {
+    public void testContinuation_noParent() {
         Work testWork = createTestWorker();
-        WorkContinuationImpl continuation = new WorkContinuationImpl(mWorkManagerImpl,
-                testWork);
-        assertNull(continuation.mParent);
+        WorkContinuationImpl continuation =
+                new WorkContinuationImpl(mWorkManagerImpl, testWork);
 
-        assertEquals(continuation.mIds[0], testWork.getId());
-        assertEquals(continuation.mIds.length, 1);
-        assertEquals(continuation.mAllIds.size(), 1);
+        assertThat(continuation.getParent(), is(nullValue()));
+        assertThat(continuation.getIds().length, is(1));
+        assertThat(continuation.getIds()[0], is(testWork.getId()));
+        assertThat(continuation.getAllIds().size(), is(1));
     }
 
     @Test
-    public void testLazyContinuation_singleChain() {
+    public void testContinuation_singleChain() {
         Work testWork = createTestWorker();
         Work dependentWork = createTestWorker();
         WorkContinuationImpl continuation =
@@ -75,59 +121,59 @@
         WorkContinuationImpl dependent = (WorkContinuationImpl) (continuation.then(
                 dependentWork));
 
-        assertNotNull(dependent.mParent);
-        assertEquals(dependent.mParent, continuation);
 
-        assertEquals(dependent.mIds.length, 1);
-        assertEquals(dependent.mAllIds.size(), 2);
+        assertThat(dependent.getParent(), is(notNullValue()));
+        assertThat(dependent.getParent(), is(continuation));
+        assertThat(dependent.getIds().length, is(1));
+        assertThat(dependent.getIds()[0], is(dependentWork.getId()));
+        assertThat(dependent.getAllIds().size(), is(2));
+        assertThat(
+                dependent.getAllIds(),
+                containsInAnyOrder(dependentWork.getId(), testWork.getId()));
     }
 
     @Test
-    public void testLazyContinuation_enqueue() {
+    public void testContinuation_enqueue() {
         Work testWork = createTestWorker();
         WorkContinuationImpl continuation = new WorkContinuationImpl(mWorkManagerImpl,
                 testWork);
-        assertEquals(continuation.mEnqueued, false);
+        assertThat(continuation.isEnqueued(), is(false));
         continuation.enqueue();
-
         verifyEnqueued(continuation);
-        verify(mTaskExecutor, times(1)).executeOnBackgroundThread(any(EnqueueRunnable.class));
     }
 
     @Test
-    public void testLazyContinuation_chainEnqueue() {
+    public void testContinuation_chainEnqueue() {
         Work testWork = createTestWorker();
         WorkContinuationImpl continuation =
                 new WorkContinuationImpl(mWorkManagerImpl, testWork);
         WorkContinuationImpl chain = (WorkContinuationImpl) (
                 continuation.then(createTestWorker()).then(createTestWorker(), createTestWorker()));
-
         chain.enqueue();
         verifyEnqueued(continuation);
-        verify(mTaskExecutor, times(3)).executeOnBackgroundThread(any(EnqueueRunnable.class));
     }
 
     @Test
-    public void testLazyContinuation_chainEnqueueNoOpOnRetry() {
+    public void testContinuation_chainEnqueueNoOpOnRetry() {
         Work testWork = createTestWorker();
         WorkContinuationImpl continuation =
                 new WorkContinuationImpl(mWorkManagerImpl, testWork);
         WorkContinuationImpl chain = (WorkContinuationImpl) (
                 continuation.then(createTestWorker()).then(createTestWorker(), createTestWorker()));
-
         chain.enqueue();
         verifyEnqueued(continuation);
-        verify(mTaskExecutor, times(3)).executeOnBackgroundThread(any(EnqueueRunnable.class));
-        chain.enqueue();
-        verifyNoMoreInteractions(mTaskExecutor);
+        WorkContinuationImpl spy = spy(chain);
+        spy.enqueue();
+        // Verify no more calls to markEnqueued().
+        verify(spy, times(0)).markEnqueued();
     }
 
     private void verifyEnqueued(WorkContinuationImpl continuation) {
-        assertEquals(continuation.mEnqueued, true);
-        WorkContinuationImpl parent = continuation.mParent;
+        assertThat(continuation.isEnqueued(), is(true));
+        WorkContinuationImpl parent = continuation.getParent();
         while (parent != null) {
-            assertEquals(parent.mEnqueued, true);
-            parent = parent.mParent;
+            assertThat(parent.isEnqueued(), is(true));
+            parent = parent.getParent();
         }
     }
 
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkContinuationImpl.java b/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkContinuationImpl.java
index a63c347..00ef536 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkContinuationImpl.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkContinuationImpl.java
@@ -16,6 +16,7 @@
 
 package android.arch.background.workmanager.impl;
 
+import android.arch.background.workmanager.BaseWork;
 import android.arch.background.workmanager.Work;
 import android.arch.background.workmanager.WorkContinuation;
 import android.arch.background.workmanager.WorkManager;
@@ -26,7 +27,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -42,45 +42,75 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class WorkContinuationImpl extends WorkContinuation {
 
-    private static final String TAG = "LzyWrkContinuationImpl";
+    private static final String TAG = "WorkContinuationImpl";
 
-    @VisibleForTesting
-    final WorkManagerImpl mWorkManagerImpl;
+    private final WorkManagerImpl mWorkManagerImpl;
+    private final String mUniqueTag;
+    private final @WorkManager.ExistingWorkPolicy int mExistingWorkPolicy;
+    private final BaseWork[] mWork;
+    private final String[] mIds;
+    private final List<String> mAllIds;
+    private boolean mEnqueued;
+    private WorkContinuationImpl mParent;
 
-    final String mUniqueTag;
+    @NonNull
+    public WorkManagerImpl getWorkManagerImpl() {
+        return mWorkManagerImpl;
+    }
 
-    final @WorkManager.ExistingWorkPolicy int mExistingWorkPolicy;
+    @Nullable
+    public String getUniqueTag() {
+        return mUniqueTag;
+    }
 
-    @VisibleForTesting
-    final Work[] mWork;
+    public @WorkManager.ExistingWorkPolicy int getExistingWorkPolicy() {
+        return mExistingWorkPolicy;
+    }
 
-    @VisibleForTesting
-    final String[] mIds;
+    @NonNull
+    public BaseWork[] getWork() {
+        return mWork;
+    }
 
-    @VisibleForTesting
-    final List<String> mAllIds;
+    @NonNull
+    public String[] getIds() {
+        return mIds;
+    }
 
-    @VisibleForTesting
-    boolean mEnqueued;
+    public List<String> getAllIds() {
+        return mAllIds;
+    }
 
-    @VisibleForTesting
-    WorkContinuationImpl mParent;
+    public boolean isEnqueued() {
+        return mEnqueued;
+    }
 
-    WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl, @NonNull Work... work) {
+    /**
+     * Marks the {@link WorkContinuationImpl} as enqueued.
+     */
+    public void markEnqueued() {
+        mEnqueued = true;
+    }
+
+    public WorkContinuationImpl getParent() {
+        return mParent;
+    }
+
+    WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl, @NonNull BaseWork... work) {
         this(workManagerImpl, null, WorkManager.KEEP_EXISTING_WORK, work, null);
     }
 
     WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl,
             @NonNull String uniqueTag,
             @WorkManager.ExistingWorkPolicy int existingWorkPolicy,
-            @NonNull Work... work) {
+            @NonNull BaseWork... work) {
         this(workManagerImpl, uniqueTag, existingWorkPolicy, work, null);
     }
 
     private WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl,
             String uniqueTag,
             @WorkManager.ExistingWorkPolicy int existingWorkPolicy,
-            @NonNull Work[] work,
+            @NonNull BaseWork[] work,
             @Nullable WorkContinuationImpl parent) {
         mWorkManagerImpl = workManagerImpl;
         mUniqueTag = uniqueTag;
@@ -126,34 +156,12 @@
 
     @Override
     public void enqueue() {
-        // TODO(sumir): Change enqueuing to be transactional, where everything gets enqueued
-        // together in one pass instead of spawning multiple runnables.
-
         // Only enqueue if not already enqueued.
         if (!mEnqueued) {
-            if (mParent == null) {
-                mWorkManagerImpl.getTaskExecutor()
-                        .executeOnBackgroundThread(
-                                new EnqueueRunnable(
-                                        mWorkManagerImpl,
-                                        mWork,
-                                        null /* no prerequisites*/,
-                                        mUniqueTag,
-                                        mExistingWorkPolicy));
-            } else {
-                // has dependencies which need to be enqueued first
-                mParent.enqueue();
-                // now enqueue the work continuation, given the dependencies have been enqueued.
-                mWorkManagerImpl.getTaskExecutor()
-                        .executeOnBackgroundThread(
-                                new EnqueueRunnable(
-                                        mWorkManagerImpl,
-                                        mWork,
-                                        mParent.mIds,
-                                        mUniqueTag,
-                                        mExistingWorkPolicy));
-            }
-            mEnqueued = true;
+            // The runnable walks the heirarchy of the continuations
+            // and marks them enqueued using the markEnqueued() method, parent first.
+            mWorkManagerImpl.getTaskExecutor()
+                    .executeOnBackgroundThread(new EnqueueRunnable(this));
         } else {
             Log.w(TAG,
                     String.format("Already enqueued work ids (%s).", TextUtils.join(", ", mIds)));
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkManagerImpl.java b/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkManagerImpl.java
index 3301d0f..b1b828b 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkManagerImpl.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/impl/WorkManagerImpl.java
@@ -27,7 +27,6 @@
 import android.arch.background.workmanager.impl.model.WorkSpecDao;
 import android.arch.background.workmanager.impl.utils.BaseWorkHelper;
 import android.arch.background.workmanager.impl.utils.CancelWorkRunnable;
-import android.arch.background.workmanager.impl.utils.EnqueueRunnable;
 import android.arch.background.workmanager.impl.utils.LiveDataUtils;
 import android.arch.background.workmanager.impl.utils.PruneDatabaseRunnable;
 import android.arch.background.workmanager.impl.utils.taskexecutor.TaskExecutor;
@@ -158,13 +157,7 @@
 
     @Override
     public void enqueue(@NonNull PeriodicWork... periodicWork) {
-        mTaskExecutor.executeOnBackgroundThread(
-                new EnqueueRunnable(
-                        this,
-                        periodicWork,
-                        null,
-                        null,
-                        KEEP_EXISTING_WORK));
+        new WorkContinuationImpl(this, periodicWork).enqueue();
     }
 
     @Override
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/impl/utils/EnqueueRunnable.java b/background/workmanager/src/main/java/android/arch/background/workmanager/impl/utils/EnqueueRunnable.java
index fd718d1..690e2ca 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/impl/utils/EnqueueRunnable.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/impl/utils/EnqueueRunnable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -20,9 +20,9 @@
 import static android.arch.background.workmanager.BaseWork.STATUS_SUCCEEDED;
 
 import android.arch.background.workmanager.BaseWork;
-import android.arch.background.workmanager.Work;
 import android.arch.background.workmanager.WorkManager;
 import android.arch.background.workmanager.impl.InternalWorkImpl;
+import android.arch.background.workmanager.impl.WorkContinuationImpl;
 import android.arch.background.workmanager.impl.WorkDatabase;
 import android.arch.background.workmanager.impl.WorkManagerImpl;
 import android.arch.background.workmanager.impl.model.Dependency;
@@ -30,14 +30,13 @@
 import android.arch.background.workmanager.impl.model.WorkTag;
 import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
-import android.support.annotation.WorkerThread;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.List;
 
 /**
- * A {@link Runnable} to enqueue a {@link Work} in the database.
+ * Manages the enqueuing of a {@link WorkContinuationImpl}.
  *
  * @hide
  */
@@ -46,110 +45,151 @@
 
     private static final String TAG = "EnqueueRunnable";
 
-    private WorkManagerImpl mWorkManagerImpl;
-    private InternalWorkImpl[] mWorkArray;
-    private String[] mPrerequisiteIds;
-    private String mUniqueTag;
-    @WorkManager.ExistingWorkPolicy private int mExistingWorkPolicy;
+    private final WorkContinuationImpl mWorkContinuation;
 
-    public EnqueueRunnable(WorkManagerImpl workManagerImpl,
+    public EnqueueRunnable(@NonNull WorkContinuationImpl workContinuation) {
+        mWorkContinuation = workContinuation;
+    }
+
+    @Override
+    public void run() {
+        WorkManagerImpl workManagerImpl = mWorkContinuation.getWorkManagerImpl();
+        WorkDatabase workDatabase = workManagerImpl.getWorkDatabase();
+        workDatabase.beginTransaction();
+        try {
+            processContinuation(mWorkContinuation);
+            workDatabase.setTransactionSuccessful();
+        } finally {
+            workDatabase.endTransaction();
+        }
+    }
+
+    private static void processContinuation(@NonNull WorkContinuationImpl workContinuation) {
+        WorkContinuationImpl parent = workContinuation.getParent();
+        if (parent != null) {
+            // When chaining off a completed continuation we need to pay
+            // attention to parents that may have been marked as enqueued before.
+            if (!parent.isEnqueued()) {
+                processContinuation(parent);
+            } else {
+                Log.w(TAG,
+                        String.format(
+                                "Already enqueued work ids (%s).",
+                                TextUtils.join(", ", parent.getIds())));
+            }
+
+        }
+        enqueueContinuation(workContinuation);
+    }
+
+    private static void enqueueContinuation(@NonNull WorkContinuationImpl workContinuation) {
+        WorkContinuationImpl parent = workContinuation.getParent();
+        String[] prerequisiteIds = parent != null ? parent.getIds() : null;
+
+        enqueueWorkWithPrerequisites(
+                workContinuation.getWorkManagerImpl(),
+                workContinuation.getWork(),
+                prerequisiteIds,
+                workContinuation.getUniqueTag(),
+                workContinuation.getExistingWorkPolicy());
+
+        workContinuation.markEnqueued();
+    }
+
+    /**
+     * Enqueues the {@link WorkSpec}'s while keeping track of the prerequisites.
+     */
+    private static void enqueueWorkWithPrerequisites(
+            WorkManagerImpl workManagerImpl,
             @NonNull BaseWork[] workArray,
             String[] prerequisiteIds,
             String uniqueTag,
             @WorkManager.ExistingWorkPolicy int existingWorkPolicy) {
-        mWorkManagerImpl = workManagerImpl;
-        mWorkArray = new InternalWorkImpl[workArray.length];
-        for (int i = 0; i < workArray.length; ++i) {
-            mWorkArray[i] = (InternalWorkImpl) workArray[i];
-        }
-        mPrerequisiteIds = prerequisiteIds;
-        mUniqueTag = uniqueTag;
-        mExistingWorkPolicy = existingWorkPolicy;
-    }
 
-    @WorkerThread
-    @Override
-    public void run() {
-        WorkDatabase workDatabase = mWorkManagerImpl.getWorkDatabase();
-        workDatabase.beginTransaction();
-        try {
-            long currentTimeMillis = System.currentTimeMillis();
-            boolean hasPrerequisite = (mPrerequisiteIds != null && mPrerequisiteIds.length > 0);
-            boolean hasCompletedAllPrerequisites = true;
+        long currentTimeMillis = System.currentTimeMillis();
+        WorkDatabase workDatabase = workManagerImpl.getWorkDatabase();
+
+        InternalWorkImpl[] workImplArray = new InternalWorkImpl[workArray.length];
+        for (int i = 0; i < workArray.length; ++i) {
+            workImplArray[i] = (InternalWorkImpl) workArray[i];
+        }
+
+        boolean hasPrerequisite = (prerequisiteIds != null && prerequisiteIds.length > 0);
+        boolean hasCompletedAllPrerequisites = true;
+
+        if (hasPrerequisite) {
+            // If there are prerequisites, make sure they actually exist before enqueuing
+            // anything.  Prerequisites may not exist if we are using unique tags, because the
+            // chain of work could have been wiped out already.
+            for (String id : prerequisiteIds) {
+                WorkSpec prerequisiteWorkSpec = workDatabase.workSpecDao().getWorkSpec(id);
+                if (prerequisiteWorkSpec == null) {
+                    Log.e(TAG, "Prerequisite " + id + " doesn't exist; not enqueuing");
+                    return;
+                }
+                hasCompletedAllPrerequisites &=
+                        (prerequisiteWorkSpec.getStatus() == STATUS_SUCCEEDED);
+            }
+        }
+
+        boolean hasUniqueTag = !TextUtils.isEmpty(uniqueTag);
+        if (hasUniqueTag && !hasPrerequisite) {
+            List<String> existingWorkSpecIds =
+                    workDatabase.workSpecDao().getWorkSpecIdsForTag(uniqueTag);
+            if (!existingWorkSpecIds.isEmpty()) {
+                if (existingWorkPolicy == WorkManager.KEEP_EXISTING_WORK) {
+                    return;
+                }
+
+                // Cancel all of these workers.
+                CancelWorkRunnable cancelWorkRunnable =
+                        new CancelWorkRunnable(workManagerImpl, null, uniqueTag);
+                cancelWorkRunnable.run();
+                // And delete all the database records.
+                workDatabase.workSpecDao().delete(existingWorkSpecIds);
+            }
+        }
+
+        for (InternalWorkImpl work : workImplArray) {
+            WorkSpec workSpec = work.getWorkSpec();
+
+            if (hasPrerequisite && !hasCompletedAllPrerequisites) {
+                workSpec.setStatus(STATUS_BLOCKED);
+            } else {
+                // Set scheduled times only for work without prerequisites. Dependent work
+                // will set their scheduled times when they are unblocked.
+                workSpec.setPeriodStartTime(currentTimeMillis);
+            }
+
+            workDatabase.workSpecDao().insertWorkSpec(workSpec);
 
             if (hasPrerequisite) {
-                // If there are prerequisites, make sure they actually exist before enqueuing
-                // anything.  Prerequisites may not exist if we are using unique tags, because the
-                // chain of work could have been wiped out already.
-                for (String id : mPrerequisiteIds) {
-                    WorkSpec prerequisiteWorkSpec = workDatabase.workSpecDao().getWorkSpec(id);
-                    if (prerequisiteWorkSpec == null) {
-                        Log.e(TAG, "Prerequisite " + id + " doesn't exist; not enqueuing");
-                        return;
-                    }
-                    hasCompletedAllPrerequisites &=
-                            (prerequisiteWorkSpec.getStatus() == STATUS_SUCCEEDED);
+                for (String prerequisiteId : prerequisiteIds) {
+                    Dependency dep = new Dependency(work.getId(), prerequisiteId);
+                    workDatabase.dependencyDao().insertDependency(dep);
                 }
             }
 
-            boolean hasUniqueTag = !TextUtils.isEmpty(mUniqueTag);
-            if (hasUniqueTag && !hasPrerequisite) {
-                List<String> existingWorkSpecIds =
-                        workDatabase.workSpecDao().getWorkSpecIdsForTag(mUniqueTag);
-                if (!existingWorkSpecIds.isEmpty()) {
-                    if (mExistingWorkPolicy == WorkManager.KEEP_EXISTING_WORK) {
-                        return;
-                    }
-
-                    // Cancel all of these workers.
-                    CancelWorkRunnable cancelWorkRunnable =
-                            new CancelWorkRunnable(mWorkManagerImpl, null, mUniqueTag);
-                    cancelWorkRunnable.run();
-                    // And delete all the database records.
-                    workDatabase.workSpecDao().delete(existingWorkSpecIds);
-                }
+            for (String tag : work.getTags()) {
+                workDatabase.workTagDao().insert(new WorkTag(tag, work.getId()));
             }
 
-            for (InternalWorkImpl work : mWorkArray) {
-                WorkSpec workSpec = work.getWorkSpec();
-
-                if (hasPrerequisite && !hasCompletedAllPrerequisites) {
-                    workSpec.setStatus(STATUS_BLOCKED);
-                } else {
-                    // Set scheduled times only for work without prerequisites. Dependent work
-                    // will set their scheduled times when they are unblocked.
-                    workSpec.setPeriodStartTime(currentTimeMillis);
-                }
-
-                workDatabase.workSpecDao().insertWorkSpec(workSpec);
-
-                if (hasPrerequisite) {
-                    for (String prerequisiteId : mPrerequisiteIds) {
-                        Dependency dep = new Dependency(work.getId(), prerequisiteId);
-                        workDatabase.dependencyDao().insertDependency(dep);
-                    }
-                }
-
-                for (String tag : work.getTags()) {
-                    workDatabase.workTagDao().insert(new WorkTag(tag, work.getId()));
-                }
-
-                // Enforce that the unique tag is always present.
-                if (hasUniqueTag) {
-                    workDatabase.workTagDao().insert(new WorkTag(mUniqueTag, work.getId()));
-                }
+            // Enforce that the unique tag is always present.
+            if (hasUniqueTag) {
+                workDatabase.workTagDao().insert(new WorkTag(uniqueTag, work.getId()));
             }
-            workDatabase.setTransactionSuccessful();
+        }
 
-            // Schedule in the background if there are no prerequisites.  Foreground scheduling
-            // happens automatically if a ForegroundProcessor is available.
-            if (!hasPrerequisite) {
-                for (InternalWorkImpl work : mWorkArray) {
-                    mWorkManagerImpl.getBackgroundScheduler().schedule(work.getWorkSpec());
-                }
+        // TODO(rahulrav@) It's dangerous to ask the background scheduler to schedule things.
+        // Revisit this and see if there is a better way to do this, after the transaction
+        // has settled.
+
+        // Schedule in the background if there are no prerequisites.  Foreground scheduling
+        // happens automatically if a ForegroundProcessor is available.
+        if (!hasPrerequisite) {
+            for (InternalWorkImpl work : workImplArray) {
+                workManagerImpl.getBackgroundScheduler().schedule(work.getWorkSpec());
             }
-        } finally {
-            workDatabase.endTransaction();
         }
     }
 }