Background tasks can decide which executor to run with.

- Allow BackgroundTaskService to take an Executor as an optional argument,
  most commonly these will be one of the static fields defined on
  AsyncTask.
- Make voicemail prepare media on async background thread.
- Mark voicemails as read concurrently with other async tasks.
- Change background task service to accept an Executor as argument.
- Remove the initial progress and initial time from seek bar.

Bug: 5148472
Change-Id: I55815294fe671d3a42af0b2d6d5e29e6eaea271e
diff --git a/res/layout/playback_layout.xml b/res/layout/playback_layout.xml
index 83b1c01..bb32014 100644
--- a/res/layout/playback_layout.xml
+++ b/res/layout/playback_layout.xml
@@ -69,19 +69,18 @@
                 android:progressDrawable="@drawable/seekbar_drawable"
                 android:thumb="@drawable/seek_bar_thumb"
                 android:thumbOffset="8dip"
-                android:progress="20"
+                android:progress="0"
                 android:paddingLeft="8dip"
                 android:paddingRight="8dip"
                 android:paddingTop="30dip"
                 android:paddingBottom="20dip"
                 android:layout_marginRight="64dip"
                 android:layout_marginLeft="64dip"
-                android:max="50"
+                android:max="0"
                 android:layout_centerVertical="true"
             />
             <TextView
                 android:id="@+id/playback_position_text"
-                android:text="@string/voicemail_initial_time"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:textSize="14sp"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2e8983f..f20f6c3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1619,9 +1619,6 @@
     <!-- Text used in the ticker to notify the user of the latest voicemail. [CHAR LIMIT=30] -->
     <string name="notification_new_voicemail_ticker">New voicemail from <xliff:g id="caller">%1$s</xliff:g></string>
 
-    <!-- Initial display for position of current playback, do not translate. -->
-    <string name="voicemail_initial_time">00:05</string>
-
     <!-- Message to show when there is an error playing back the voicemail. [CHAR LIMIT=40] -->
     <string name="voicemail_playback_error">failed to play voicemail</string>
 
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 5a2e9ea..662485a 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -37,6 +37,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.provider.CallLog;
 import android.provider.CallLog.Calls;
@@ -222,7 +223,7 @@
                 values.put(Voicemails.IS_READ, true);
                 getContentResolver().update(voicemailUri, values, null, null);
             }
-        });
+        }, AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     /**
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index 1e791b6..0aba332 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts;
 
+import static com.android.contacts.util.BackgroundTaskService.createAsyncTaskBackgroundTaskService;
+
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.test.InjectedServices;
 import com.android.contacts.util.BackgroundTaskService;
@@ -97,7 +99,7 @@
 
         if (BackgroundTaskService.BACKGROUND_TASK_SERVICE.equals(name)) {
             if (mBackgroundTaskService == null) {
-                mBackgroundTaskService = BackgroundTaskService.createBackgroundTaskService();
+                mBackgroundTaskService = createAsyncTaskBackgroundTaskService();
             }
             return mBackgroundTaskService;
         }
diff --git a/src/com/android/contacts/util/BackgroundTaskService.java b/src/com/android/contacts/util/BackgroundTaskService.java
index 00f9e3e..310a178 100644
--- a/src/com/android/contacts/util/BackgroundTaskService.java
+++ b/src/com/android/contacts/util/BackgroundTaskService.java
@@ -18,25 +18,54 @@
 
 import android.os.AsyncTask;
 
+import java.util.concurrent.Executor;
+
 /**
  * Service used to submit tasks to run in the background.
  * <p>
  * BackgroundTaskService makes the same memory-visibility guarantees that AsyncTask which it
  * emulates makes, namely that fields set in the {@link BackgroundTask#doInBackground()} method
  * will be visible to the {@link BackgroundTask#onPostExecute()} method.
+ * <p>
+ * You are not expected to derive from this class unless you are writing your own test
+ * implementation, or you are absolutely sure that the instance in
+ * {@link #createAsyncTaskBackgroundTaskService()} doesn't do what you need.
  */
 public abstract class BackgroundTaskService {
     public static final String BACKGROUND_TASK_SERVICE = BackgroundTaskService.class.getName();
 
+    /**
+     * Executes the given BackgroundTask with the default Executor.
+     * <p>
+     * All {@link BackgroundTask#doInBackground()} tasks will be guaranteed to happen serially.
+     * If this is not what you want, see {@link #submit(BackgroundTask, Executor)}.
+     */
     public abstract void submit(BackgroundTask task);
 
-    public static BackgroundTaskService createBackgroundTaskService() {
+    /**
+     * Executes the BackgroundTask with the supplied Executor.
+     * <p>
+     * The main use-case for this method will be to allow submitted tasks to perform their
+     * {@link BackgroundTask#doInBackground()} methods concurrently.
+     */
+    public abstract void submit(BackgroundTask task, Executor executor);
+
+    /**
+     * Creates a concrete BackgroundTaskService whose default Executor is
+     * {@link AsyncTask#SERIAL_EXECUTOR}.
+     */
+    public static BackgroundTaskService createAsyncTaskBackgroundTaskService() {
         return new AsyncTaskBackgroundTaskService();
     }
 
     private static final class AsyncTaskBackgroundTaskService extends BackgroundTaskService {
         @Override
-        public void submit(final BackgroundTask task) {
+        public void submit(BackgroundTask task) {
+            submit(task, AsyncTask.SERIAL_EXECUTOR);
+        }
+
+        @Override
+        public void submit(final BackgroundTask task, Executor executor) {
             new AsyncTask<Void, Void, Void>() {
                 @Override
                 protected Void doInBackground(Void... params) {
@@ -48,7 +77,7 @@
                 protected void onPostExecute(Void result) {
                     task.onPostExecute();
                 }
-            }.execute();
+            }.executeOnExecutor(executor);
         }
     }
 }
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index e901fab..494888c 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.media.MediaPlayer;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.SeekBar;
@@ -165,7 +166,7 @@
                     mView.playbackError(mException);
                 }
             }
-        });
+        }, AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     private void postSuccessfulPrepareActions() {
diff --git a/tests/src/com/android/contacts/util/FakeBackgroundTaskService.java b/tests/src/com/android/contacts/util/FakeBackgroundTaskService.java
index a9d80b4..26be519 100644
--- a/tests/src/com/android/contacts/util/FakeBackgroundTaskService.java
+++ b/tests/src/com/android/contacts/util/FakeBackgroundTaskService.java
@@ -35,6 +35,11 @@
         mSubmittedTasks.add(task);
     }
 
+    @Override
+    public void submit(BackgroundTask task, Executor executor) {
+        mSubmittedTasks.add(task);
+    }
+
     public List<BackgroundTask> getSubmittedTasks() {
         return mSubmittedTasks;
     }