Merge "Improved dagger support for executor services."
diff --git a/java/com/android/dialer/app/calllog/MissedCallNotificationReceiver.java b/java/com/android/dialer/app/calllog/MissedCallNotificationReceiver.java
index a1f1c52..744c0de 100644
--- a/java/com/android/dialer/app/calllog/MissedCallNotificationReceiver.java
+++ b/java/com/android/dialer/app/calllog/MissedCallNotificationReceiver.java
@@ -53,7 +53,7 @@
 
     PendingResult pendingResult = goAsync();
 
-    DialerExecutors.createNonUiTaskBuilder(MissedCallNotifier.getInstance(context))
+    DialerExecutors.createNonUiTaskBuilder(context, MissedCallNotifier.getInstance(context))
         .onSuccess(
             output -> {
               LogUtil.i(
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java b/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java
index 8bfd48b..96d9173 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailCallLogFragment.java
@@ -80,6 +80,7 @@
 
     mPreSyncVoicemailStatusCheckExecutor =
         DialerExecutors.createUiTaskBuilder(
+                getContext(),
                 getActivity().getFragmentManager(),
                 "fetchVoicemailStatus",
                 new VoicemailStatusWorker())
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
index 77b4c11..fd0be5f 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
@@ -184,7 +184,7 @@
             context,
             CallLogNotificationsQueryHelper.getInstance(context),
             new FilteredNumberAsyncQueryHandler(context));
-    DialerExecutors.createNonUiTaskBuilder(new VisualVoicemailUpdateTask())
+    DialerExecutors.createNonUiTaskBuilder(context, new VisualVoicemailUpdateTask())
         .onSuccess(
             output -> {
               LogUtil.i("VisualVoicemailUpdateTask.scheduleTask", "update successful");
diff --git a/java/com/android/dialer/app/list/RegularSearchFragment.java b/java/com/android/dialer/app/list/RegularSearchFragment.java
index 73120c5..ca19432 100644
--- a/java/com/android/dialer/app/list/RegularSearchFragment.java
+++ b/java/com/android/dialer/app/list/RegularSearchFragment.java
@@ -67,6 +67,7 @@
 
     addContactTask =
         DialerExecutors.createUiTaskBuilder(
+                getContext(),
                 getFragmentManager(),
                 "RegularSearchFragment.addContact",
                 new AddContactWorker(getContext().getApplicationContext()))
diff --git a/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java b/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
index 685357a..2d21bd6 100644
--- a/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
+++ b/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
@@ -221,7 +221,10 @@
       }
       shareVoicemailExecutor =
           DialerExecutors.createUiTaskBuilder(
-                  mActivity.getFragmentManager(), "shareVoicemail", new ShareVoicemailWorker())
+                  mContext,
+                  mActivity.getFragmentManager(),
+                  "shareVoicemail",
+                  new ShareVoicemailWorker())
               .onSuccess(
                   output -> {
                     if (output == null) {
diff --git a/java/com/android/dialer/binary/aosp/testing/AndroidManifest.xml b/java/com/android/dialer/binary/aosp/testing/AndroidManifest.xml
deleted file mode 100644
index 15870cb..0000000
--- a/java/com/android/dialer/binary/aosp/testing/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  ~ Copyright (C) 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
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.dialer.binary.aosp.testing">
-
-  <application>
-    <activity android:name="com.android.dialer.binary.aosp.testing.TestActivity"/>
-  </application>
-
-</manifest>
diff --git a/java/com/android/dialer/binary/common/DialerApplication.java b/java/com/android/dialer/binary/common/DialerApplication.java
index 19af575..c0e6ae6 100644
--- a/java/com/android/dialer/binary/common/DialerApplication.java
+++ b/java/com/android/dialer/binary/common/DialerApplication.java
@@ -23,7 +23,7 @@
 import com.android.dialer.blocking.BlockedNumbersAutoMigrator;
 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
 import com.android.dialer.calllog.CallLogComponent;
-import com.android.dialer.common.concurrent.DefaultDialerExecutorFactory;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.inject.HasRootComponent;
 import com.android.dialer.notification.NotificationChannelManager;
 import com.android.dialer.persistentlog.PersistentLogger;
@@ -43,7 +43,7 @@
     new BlockedNumbersAutoMigrator(
             this.getApplicationContext(),
             new FilteredNumberAsyncQueryHandler(this),
-            new DefaultDialerExecutorFactory())
+            DialerExecutorComponent.get(this).dialerExecutorFactory())
         .asyncAutoMigrate();
     CallLogComponent.get(this).callLogFramework().registerContentObservers(getApplicationContext());
     PersistentLogger.initialize(this);
diff --git a/java/com/android/dialer/callcomposer/CallComposerActivity.java b/java/com/android/dialer/callcomposer/CallComposerActivity.java
index 60826fd..bad5d7f 100644
--- a/java/com/android/dialer/callcomposer/CallComposerActivity.java
+++ b/java/com/android/dialer/callcomposer/CallComposerActivity.java
@@ -224,6 +224,7 @@
 
     copyAndResizeExecutor =
         DialerExecutors.createUiTaskBuilder(
+                getApplicationContext(),
                 getFragmentManager(),
                 "copyAndResizeImageToSend",
                 new CopyAndResizeImageWorker(this.getApplicationContext()))
diff --git a/java/com/android/dialer/callcomposer/GalleryComposerFragment.java b/java/com/android/dialer/callcomposer/GalleryComposerFragment.java
index 2e6a28c..e604ec1 100644
--- a/java/com/android/dialer/callcomposer/GalleryComposerFragment.java
+++ b/java/com/android/dialer/callcomposer/GalleryComposerFragment.java
@@ -28,7 +28,6 @@
 import android.provider.Settings;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
 import android.support.v4.app.LoaderManager.LoaderCallbacks;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.content.CursorLoader;
@@ -40,11 +39,9 @@
 import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.TextView;
-import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.DefaultDialerExecutorFactory;
 import com.android.dialer.common.concurrent.DialerExecutor;
-import com.android.dialer.common.concurrent.DialerExecutorFactory;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.util.PermissionsUtil;
@@ -62,8 +59,6 @@
   private static final int RESULT_LOAD_IMAGE = 1;
   private static final int RESULT_OPEN_SETTINGS = 2;
 
-  private DialerExecutorFactory executorFactory = new DefaultDialerExecutorFactory();
-
   private GalleryGridAdapter adapter;
   private GridView galleryGridView;
   private View permissionView;
@@ -81,11 +76,6 @@
     return new GalleryComposerFragment();
   }
 
-  @VisibleForTesting
-  void setExecutorFactory(@NonNull DialerExecutorFactory executorFactory) {
-    this.executorFactory = Assert.isNotNull(executorFactory);
-  }
-
   @Nullable
   @Override
   public View onCreateView(
@@ -123,7 +113,8 @@
     super.onActivityCreated(bundle);
 
     copyAndResizeImage =
-        executorFactory
+        DialerExecutorComponent.get(getContext())
+            .dialerExecutorFactory()
             .createUiTaskBuilder(
                 getActivity().getFragmentManager(),
                 "copyAndResizeImage",
diff --git a/java/com/android/dialer/callcomposer/camera/CameraManager.java b/java/com/android/dialer/callcomposer/camera/CameraManager.java
index f79f654..9a9577f 100644
--- a/java/com/android/dialer/callcomposer/camera/CameraManager.java
+++ b/java/com/android/dialer/callcomposer/camera/CameraManager.java
@@ -469,6 +469,7 @@
             LogUtil.i(
                 "CameraManager.onPictureTaken", "taken picture size: " + bytes.length + " bytes");
             DialerExecutors.createNonUiTaskBuilder(
+                    mCameraPreview.getContext(),
                     new ImagePersistWorker(
                         width, height, heightPercent, bytes, mCameraPreview.getContext()))
                 .onSuccess(
diff --git a/java/com/android/dialer/common/concurrent/Annotations.java b/java/com/android/dialer/common/concurrent/Annotations.java
new file mode 100644
index 0000000..eb956c3
--- /dev/null
+++ b/java/com/android/dialer/common/concurrent/Annotations.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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 com.android.dialer.common.concurrent;
+
+import javax.inject.Qualifier;
+
+/** Annotations for dagger concurrency bindings. */
+public class Annotations {
+
+  /** Annotation for retrieving the non-UI thread pool. */
+  @Qualifier
+  public @interface NonUiParallel {}
+
+  /** Annotation for retrieving the non-UI serial executor. */
+  @Qualifier
+  public @interface NonUiSerial {}
+
+  /** Annotation for retrieving the UI thread pool. */
+  @Qualifier
+  public @interface UiParallel {}
+
+  /** Annotation for retrieving the UI serial executor. */
+  @Qualifier
+  public @interface UiSerial {}
+}
diff --git a/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java b/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java
index a87bbce..ab01654 100644
--- a/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java
+++ b/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java
@@ -17,29 +17,43 @@
 package com.android.dialer.common.concurrent;
 
 import android.app.FragmentManager;
-import android.os.AsyncTask;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.NonUiParallel;
+import com.android.dialer.common.concurrent.Annotations.NonUiSerial;
+import com.android.dialer.common.concurrent.Annotations.UiParallel;
+import com.android.dialer.common.concurrent.Annotations.UiSerial;
 import com.android.dialer.common.concurrent.DialerExecutor.Builder;
 import com.android.dialer.common.concurrent.DialerExecutor.FailureListener;
 import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener;
 import com.android.dialer.common.concurrent.DialerExecutor.Worker;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import javax.inject.Inject;
 
 /** The production {@link DialerExecutorFactory}. */
 public class DefaultDialerExecutorFactory implements DialerExecutorFactory {
+  private final ExecutorService nonUiThreadPool;
+  private final ScheduledExecutorService nonUiSerialExecutor;
+  private final Executor uiThreadPool;
+  private final ScheduledExecutorService uiSerialExecutor;
 
   @Inject
-  public DefaultDialerExecutorFactory() {}
+  DefaultDialerExecutorFactory(
+      @NonUiParallel ExecutorService nonUiThreadPool,
+      @NonUiSerial ScheduledExecutorService nonUiSerialExecutor,
+      @UiParallel Executor uiThreadPool,
+      @UiSerial ScheduledExecutorService uiSerialExecutor) {
+    this.nonUiThreadPool = nonUiThreadPool;
+    this.nonUiSerialExecutor = nonUiSerialExecutor;
+    this.uiThreadPool = uiThreadPool;
+    this.uiSerialExecutor = uiSerialExecutor;
+  }
 
   @Override
   @NonNull
@@ -48,14 +62,18 @@
       @NonNull String taskId,
       @NonNull Worker<InputT, OutputT> worker) {
     return new UiTaskBuilder<>(
-        Assert.isNotNull(fragmentManager), Assert.isNotNull(taskId), Assert.isNotNull(worker));
+        Assert.isNotNull(fragmentManager),
+        Assert.isNotNull(taskId),
+        Assert.isNotNull(worker),
+        uiSerialExecutor,
+        uiThreadPool);
   }
 
   @Override
   @NonNull
   public <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createNonUiTaskBuilder(
       @NonNull Worker<InputT, OutputT> worker) {
-    return new NonUiTaskBuilder<>(Assert.isNotNull(worker));
+    return new NonUiTaskBuilder<>(Assert.isNotNull(worker), nonUiSerialExecutor, nonUiThreadPool);
   }
 
   private abstract static class BaseTaskBuilder<InputT, OutputT>
@@ -96,34 +114,11 @@
 
   /** Convenience class for use by {@link DialerExecutorFactory} implementations. */
   public static class UiTaskBuilder<InputT, OutputT> extends BaseTaskBuilder<InputT, OutputT> {
-    private static final ScheduledExecutorService defaultSerialExecutorService =
-        Executors.newSingleThreadScheduledExecutor(
-            new ThreadFactory() {
-              @Override
-              public Thread newThread(Runnable runnable) {
-                LogUtil.i("UiTaskBuilder.newThread", "creating serial thread");
-                Thread thread = new Thread(runnable, "UiTaskBuilder-Serial");
-                thread.setPriority(5); // Corresponds to Process.THREAD_PRIORITY_DEFAULT
-                return thread;
-              }
-            });
-
-    private static final Executor defaultParallelExecutorService = AsyncTask.THREAD_POOL_EXECUTOR;
-
     private final FragmentManager fragmentManager;
     private final String id;
 
     private DialerUiTaskFragment<InputT, OutputT> dialerUiTaskFragment;
 
-    UiTaskBuilder(FragmentManager fragmentManager, String id, Worker<InputT, OutputT> worker) {
-      this(
-          fragmentManager,
-          id,
-          worker,
-          defaultSerialExecutorService,
-          defaultParallelExecutorService);
-    }
-
     public UiTaskBuilder(
         FragmentManager fragmentManager,
         String id,
@@ -153,24 +148,6 @@
 
   /** Convenience class for use by {@link DialerExecutorFactory} implementations. */
   public static class NonUiTaskBuilder<InputT, OutputT> extends BaseTaskBuilder<InputT, OutputT> {
-    private static final ScheduledExecutorService defaultSerialExecutorService =
-        Executors.newSingleThreadScheduledExecutor(
-            new ThreadFactory() {
-              @Override
-              public Thread newThread(Runnable runnable) {
-                LogUtil.i("NonUiTaskBuilder.newThread", "creating serial thread");
-                Thread thread = new Thread(runnable, "NonUiTaskBuilder-Serial");
-                thread.setPriority(4); // Corresponds to Process.THREAD_PRIORITY_BACKGROUND
-                return thread;
-              }
-            });
-
-    private static final Executor defaultParallelExecutor =
-        DialerExecutors.getLowPriorityThreadPool();
-
-    NonUiTaskBuilder(Worker<InputT, OutputT> worker) {
-      this(worker, defaultSerialExecutorService, defaultParallelExecutor);
-    }
 
     public NonUiTaskBuilder(
         Worker<InputT, OutputT> worker,
diff --git a/java/com/android/dialer/common/concurrent/DialerExecutorComponent.java b/java/com/android/dialer/common/concurrent/DialerExecutorComponent.java
index 2503325..346fdda 100644
--- a/java/com/android/dialer/common/concurrent/DialerExecutorComponent.java
+++ b/java/com/android/dialer/common/concurrent/DialerExecutorComponent.java
@@ -17,8 +17,10 @@
 package com.android.dialer.common.concurrent;
 
 import android.content.Context;
+import com.android.dialer.common.concurrent.Annotations.NonUiParallel;
 import com.android.dialer.inject.HasRootComponent;
 import dagger.Subcomponent;
+import java.util.concurrent.ExecutorService;
 
 /** Dagger component which provides a {@link DialerExecutorFactory}. */
 @Subcomponent
@@ -26,6 +28,9 @@
 
   public abstract DialerExecutorFactory dialerExecutorFactory();
 
+  @NonUiParallel
+  public abstract ExecutorService lowPriorityThreadPool();
+
   public static DialerExecutorComponent get(Context context) {
     return ((DialerExecutorComponent.HasComponent)
             ((HasRootComponent) context.getApplicationContext()).component())
diff --git a/java/com/android/dialer/common/concurrent/DialerExecutorModule.java b/java/com/android/dialer/common/concurrent/DialerExecutorModule.java
index 281f88c..68910fb 100644
--- a/java/com/android/dialer/common/concurrent/DialerExecutorModule.java
+++ b/java/com/android/dialer/common/concurrent/DialerExecutorModule.java
@@ -15,14 +15,85 @@
  */
 package com.android.dialer.common.concurrent;
 
+import android.os.AsyncTask;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.NonUiParallel;
+import com.android.dialer.common.concurrent.Annotations.NonUiSerial;
+import com.android.dialer.common.concurrent.Annotations.UiParallel;
+import com.android.dialer.common.concurrent.Annotations.UiSerial;
 import dagger.Binds;
 import dagger.Module;
+import dagger.Provides;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import javax.inject.Singleton;
 
-/** Module which binds the production {@link DialerExecutorFactory}. */
+/** Module which provides concurrency bindings. */
 @Module
 public abstract class DialerExecutorModule {
 
   @Binds
   abstract DialerExecutorFactory bindDialerExecutorFactory(
       DefaultDialerExecutorFactory defaultDialerExecutorFactory);
+
+  @Provides
+  @Singleton
+  @NonUiParallel
+  static ExecutorService provideNonUiThreadPool() {
+    return Executors.newFixedThreadPool(
+        5,
+        new ThreadFactory() {
+          @Override
+          public Thread newThread(Runnable runnable) {
+            LogUtil.i("DialerExecutorModule.newThread", "creating low priority thread");
+            Thread thread = new Thread(runnable, "DialerExecutors-LowPriority");
+            // Java thread priority 4 corresponds to Process.THREAD_PRIORITY_BACKGROUND (10)
+            thread.setPriority(4);
+            return thread;
+          }
+        });
+  }
+
+  @Provides
+  @Singleton
+  @NonUiSerial
+  static ScheduledExecutorService provideNonUiSerialExecutorService() {
+    return Executors.newSingleThreadScheduledExecutor(
+        new ThreadFactory() {
+          @Override
+          public Thread newThread(Runnable runnable) {
+            LogUtil.i("NonUiTaskBuilder.newThread", "creating serial thread");
+            Thread thread = new Thread(runnable, "DialerExecutors-LowPriority-Serial");
+            // Java thread priority 4 corresponds to Process.THREAD_PRIORITY_BACKGROUND (10)
+            thread.setPriority(4);
+            return thread;
+          }
+        });
+  }
+
+  @Provides
+  @UiParallel
+  static Executor provideUiThreadPool() {
+    return AsyncTask.THREAD_POOL_EXECUTOR;
+  }
+
+  @Provides
+  @Singleton
+  @UiSerial
+  static ScheduledExecutorService provideUiSerialExecutorService() {
+    return Executors.newSingleThreadScheduledExecutor(
+        new ThreadFactory() {
+          @Override
+          public Thread newThread(Runnable runnable) {
+            LogUtil.i("DialerExecutorModule.newThread", "creating serial thread");
+            Thread thread = new Thread(runnable, "DialerExecutors-HighPriority-Serial");
+            // Java thread priority 5 corresponds to Process.THREAD_PRIORITY_DEFAULT (0)
+            thread.setPriority(5);
+            return thread;
+          }
+        });
+  }
 }
diff --git a/java/com/android/dialer/common/concurrent/DialerExecutors.java b/java/com/android/dialer/common/concurrent/DialerExecutors.java
index 850c28c..4d8331f 100644
--- a/java/com/android/dialer/common/concurrent/DialerExecutors.java
+++ b/java/com/android/dialer/common/concurrent/DialerExecutors.java
@@ -17,13 +17,11 @@
 package com.android.dialer.common.concurrent;
 
 import android.app.FragmentManager;
+import android.content.Context;
 import android.support.annotation.NonNull;
 import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.DialerExecutor.Worker;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
 
 /**
  * Factory methods for creating {@link DialerExecutor} objects for doing background work.
@@ -118,44 +116,43 @@
  */
 public final class DialerExecutors {
 
-  /** @see DialerExecutorFactory#createUiTaskBuilder(FragmentManager, String, Worker) */
+  /**
+   * @param context any valid context object from which the application context can be retrieved
+   * @see DialerExecutorFactory#createUiTaskBuilder(FragmentManager, String, Worker)
+   */
   @NonNull
   public static <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createUiTaskBuilder(
+      @NonNull Context context,
       @NonNull FragmentManager fragmentManager,
       @NonNull String taskId,
       @NonNull Worker<InputT, OutputT> worker) {
-    return new DefaultDialerExecutorFactory()
+    return DialerExecutorComponent.get(Assert.isNotNull(context))
+        .dialerExecutorFactory()
         .createUiTaskBuilder(
             Assert.isNotNull(fragmentManager), Assert.isNotNull(taskId), Assert.isNotNull(worker));
   }
 
-  /** @see DialerExecutorFactory#createNonUiTaskBuilder(Worker) */
+  /**
+   * @param context any valid context object from which the application context can be retrieved
+   * @see DialerExecutorFactory#createNonUiTaskBuilder(Worker)
+   */
   @NonNull
   public static <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createNonUiTaskBuilder(
-      @NonNull Worker<InputT, OutputT> worker) {
-    return new DefaultDialerExecutorFactory().createNonUiTaskBuilder(Assert.isNotNull(worker));
+      Context context, @NonNull Worker<InputT, OutputT> worker) {
+    return DialerExecutorComponent.get(Assert.isNotNull(context))
+        .dialerExecutorFactory()
+        .createNonUiTaskBuilder(Assert.isNotNull(worker));
   }
 
-  private static final ExecutorService lowPriorityThreadPool =
-      Executors.newFixedThreadPool(
-          5,
-          new ThreadFactory() {
-            @Override
-            public Thread newThread(Runnable runnable) {
-              LogUtil.i("DialerExecutors.newThread", "creating low priority thread");
-              Thread thread = new Thread(runnable, "DialerExecutors-LowPriority");
-              thread.setPriority(4); // Corresponds to Process.THREAD_PRIORITY_BACKGROUND
-              return thread;
-            }
-          });
-
   /**
    * An application-wide thread pool used for low priority (non-UI) tasks.
    *
    * <p>This exists to prevent each individual dialer component from having to create its own
    * threads/pools, which would result in the application having more threads than really necessary.
+   *
+   * @param context any valid context object from which the application context can be retrieved
    */
-  public static ExecutorService getLowPriorityThreadPool() {
-    return lowPriorityThreadPool;
+  public static ExecutorService getLowPriorityThreadPool(@NonNull Context context) {
+    return DialerExecutorComponent.get(Assert.isNotNull(context)).lowPriorityThreadPool();
   }
 }
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 2316e86..7b551f7 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -344,6 +344,7 @@
 
     initPhoneNumberFormattingTextWatcherExecutor =
         DialerExecutors.createUiTaskBuilder(
+                getContext(),
                 getFragmentManager(),
                 "DialpadFragment.initPhoneNumberFormattingTextWatcher",
                 new InitPhoneNumberFormattingTextWatcherWorker())
diff --git a/java/com/android/dialer/shortcuts/ShortcutRefresher.java b/java/com/android/dialer/shortcuts/ShortcutRefresher.java
index 496f3f0..7fd02a9 100644
--- a/java/com/android/dialer/shortcuts/ShortcutRefresher.java
+++ b/java/com/android/dialer/shortcuts/ShortcutRefresher.java
@@ -45,7 +45,7 @@
       return;
     }
 
-    DialerExecutors.createNonUiTaskBuilder(new RefreshWorker(context))
+    DialerExecutors.createNonUiTaskBuilder(context, new RefreshWorker(context))
         .build()
         .executeSerial(new ArrayList<>(contacts));
   }
diff --git a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java b/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java
index d663d58..1a2cae1 100644
--- a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java
+++ b/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java
@@ -48,13 +48,13 @@
   }
 
   private static void populateDatabase(@NonNull Context context) {
-    DialerExecutors.createNonUiTaskBuilder(new PopulateDatabaseWorker())
+    DialerExecutors.createNonUiTaskBuilder(context, new PopulateDatabaseWorker())
         .build()
         .executeSerial(context);
   }
 
   private static void cleanDatabase(@NonNull Context context) {
-    DialerExecutors.createNonUiTaskBuilder(new CleanDatabaseWorker())
+    DialerExecutors.createNonUiTaskBuilder(context, new CleanDatabaseWorker())
         .build()
         .executeSerial(context);
   }
@@ -65,7 +65,7 @@
   }
 
   private static void sharePersistentLog(@NonNull Context context) {
-    DialerExecutors.createNonUiTaskBuilder(new ShareLogWorker())
+    DialerExecutors.createNonUiTaskBuilder(context, new ShareLogWorker())
         .onSuccess(
             (String log) -> {
               Intent intent = new Intent(Intent.ACTION_SEND);
diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java
index 272c2b7..2735461 100644
--- a/java/com/android/incallui/ContactInfoCache.java
+++ b/java/com/android/incallui/ContactInfoCache.java
@@ -86,8 +86,7 @@
   private final ConcurrentHashMap<String, ContactCacheEntry> mInfoMap = new ConcurrentHashMap<>();
   private final Map<String, Set<ContactInfoCacheCallback>> mCallBacks = new ArrayMap<>();
   private int mQueryId;
-  private final DialerExecutor<CnapInformationWrapper> cachedNumberLookupExecutor =
-      DialerExecutors.createNonUiTaskBuilder(new CachedNumberLookupWorker()).build();
+  private final DialerExecutor<CnapInformationWrapper> cachedNumberLookupExecutor;
 
   private static class CachedNumberLookupWorker implements Worker<CnapInformationWrapper, Void> {
     @Nullable
@@ -126,6 +125,8 @@
     Trace.beginSection("ContactInfoCache constructor");
     mContext = context;
     mPhoneNumberService = Bindings.get(context).newPhoneNumberService(context);
+    cachedNumberLookupExecutor =
+        DialerExecutors.createNonUiTaskBuilder(mContext, new CachedNumberLookupWorker()).build();
     Trace.endSection();
   }
 
@@ -718,6 +719,7 @@
     int queryId;
     /** The phone number without any changes to display to the user (ex: cnap...) */
     String originalPhoneNumber;
+
     boolean shouldShowLocation;
 
     boolean isBusiness;
diff --git a/java/com/android/incallui/ContactsAsyncHelper.java b/java/com/android/incallui/ContactsAsyncHelper.java
index 6237ca3..2e893b0 100644
--- a/java/com/android/incallui/ContactsAsyncHelper.java
+++ b/java/com/android/incallui/ContactsAsyncHelper.java
@@ -94,7 +94,7 @@
     args.displayPhotoUri = displayPhotoUri;
     args.listener = listener;
 
-    DialerExecutors.createNonUiTaskBuilder(new Worker())
+    DialerExecutors.createNonUiTaskBuilder(context, new Worker())
         .onSuccess(
             output -> {
               if (args.listener != null) {
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index b8a2baa..8535cbc 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -45,7 +45,7 @@
 import com.android.dialer.blocking.FilteredNumbersUtil;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.DefaultDialerExecutorFactory;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.enrichedcall.EnrichedCallComponent;
 import com.android.dialer.location.GeoUtil;
 import com.android.dialer.logging.InteractionEvent;
@@ -373,7 +373,9 @@
     mCallList.addListener(this);
 
     // Create spam call list listener and add it to the list of listeners
-    mSpamCallListListener = new SpamCallListListener(context, new DefaultDialerExecutorFactory());
+    mSpamCallListListener =
+        new SpamCallListListener(
+            context, DialerExecutorComponent.get(context).dialerExecutorFactory());
     mCallList.addListener(mSpamCallListListener);
 
     VideoPauseController.getInstance().setUp(this);