Fix up the unit tests for the CallDetailActivity.

- We've recently moved lots of code to use AsyncTask to avoid strict mode
  violations.
- Thanks to the new BackgroundTaskService, these weren't being executed,
  and the tests were failing.  But simply executing them is not a fix,
  we want much finer grained control over what executes when, so we
  can assert about different states of the ui.
- This cl introduces the concept of an identifier to go with the submitted
  task, so that you can uniquely identify tasks from the test.

Additionally, on further reflection, adding a new interface BackgroundTask
wasn't necessarily a great idea.  Nor was calling the thing that submits them a
Service - that name is already overloaded to mean something else in Android.

Therefore this cl makes a number of other style changes to the pattern:

- The BackgroundTaskService just becomes an interface AsyncTaskExecutor, with a
  single submit() method, in a very similar fashion to the Executor pattern in
  java.util.concurrent.
- We introduce the AsyncTaskExecutors class, which may be used to create
  AsyncTaskExecutor objects, and also introduces a seam for injecting fake
  executors for testing.
- This cl introduces a FakeAsyncTaskExecutor, which can be used to inspect the
  tasks that have been submitted, as well as being used to execute them in a
  controlled manner between assertions.
- This is now being used to control the flow of voicemail fetching from
  the unit tests, and make sure that the recently implemented logic to
  read has content, move to buffering state, then move to preparing,
  is all working correctly.
- Later this will also be used to exhaustively test all the other
  situations we care about.

Change-Id: Ia75df4996f9a5168db8d9f39560b62ccf4b98b46
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 85e0ff7..4941121 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -20,9 +20,8 @@
 import com.android.contacts.calllog.CallDetailHistoryAdapter;
 import com.android.contacts.calllog.CallTypeHelper;
 import com.android.contacts.calllog.PhoneNumberHelper;
-import com.android.contacts.util.AbstractBackgroundTask;
-import com.android.contacts.util.BackgroundTask;
-import com.android.contacts.util.BackgroundTaskService;
+import com.android.contacts.util.AsyncTaskExecutor;
+import com.android.contacts.util.AsyncTaskExecutors;
 import com.android.contacts.voicemail.VoicemailPlaybackFragment;
 import com.android.contacts.voicemail.VoicemailStatusHelper;
 import com.android.contacts.voicemail.VoicemailStatusHelper.StatusMessage;
@@ -73,6 +72,14 @@
 public class CallDetailActivity extends Activity {
     private static final String TAG = "CallDetail";
 
+    /** The enumeration of {@link AsyncTask} objects used in this class. */
+    public enum Tasks {
+        MARK_VOICEMAIL_READ,
+        DELETE_VOICEMAIL_AND_FINISH,
+        REMOVE_FROM_CALL_LOG_AND_FINISH,
+        UPDATE_PHONE_CALL_DETAILS,
+    }
+
     /** A long array extra containing ids of call log entries to display. */
     public static final String EXTRA_CALL_LOG_IDS = "EXTRA_CALL_LOG_IDS";
     /** If we are started with a voicemail, we'll find the uri to play with this extra. */
@@ -87,7 +94,7 @@
     private ImageView mMainActionView;
     private ImageButton mMainActionPushLayerView;
     private ImageView mContactBackgroundView;
-    private BackgroundTaskService mBackgroundTaskService;
+    private AsyncTaskExecutor mAsyncTaskExecutor;
 
     private String mNumber = null;
     private String mDefaultCountryIso;
@@ -161,8 +168,7 @@
 
         setContentView(R.layout.call_detail);
 
-        mBackgroundTaskService = (BackgroundTaskService) getApplicationContext().getSystemService(
-                BackgroundTaskService.BACKGROUND_TASK_SERVICE);
+        mAsyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor();
         mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
         mResources = getResources();
 
@@ -231,14 +237,15 @@
     }
 
     private void markVoicemailAsRead(final Uri voicemailUri) {
-        mBackgroundTaskService.submit(new AbstractBackgroundTask() {
+        mAsyncTaskExecutor.submit(Tasks.MARK_VOICEMAIL_READ, new AsyncTask<Void, Void, Void>() {
             @Override
-            public void doInBackground() {
+            public Void doInBackground(Void... params) {
                 ContentValues values = new ContentValues();
                 values.put(Voicemails.IS_READ, true);
                 getContentResolver().update(voicemailUri, values, null, null);
+                return null;
             }
-        }, AsyncTask.THREAD_POOL_EXECUTOR);
+        });
     }
 
     /**
@@ -288,28 +295,27 @@
      * @param callUris URIs into {@link CallLog.Calls} of the calls to be displayed
      */
     private void updateData(final Uri... callUris) {
-        mBackgroundTaskService.submit(new BackgroundTask() {
-            private PhoneCallDetails[] details;
-
+        class UpdateContactDetailsTask extends AsyncTask<Void, Void, PhoneCallDetails[]> {
             @Override
-            public void doInBackground() {
+            public PhoneCallDetails[] doInBackground(Void... params) {
                 // TODO: All phone calls correspond to the same person, so we can make a single
                 // lookup.
                 final int numCalls = callUris.length;
-                details = new PhoneCallDetails[numCalls];
+                PhoneCallDetails[] details = new PhoneCallDetails[numCalls];
                 try {
                     for (int index = 0; index < numCalls; ++index) {
                         details[index] = getPhoneCallDetailsForUri(callUris[index]);
                     }
+                    return details;
                 } catch (IllegalArgumentException e) {
                     // Something went wrong reading in our primary data.
                     Log.w(TAG, "invalid URI starting call details", e);
-                    details = null;
+                    return null;
                 }
             }
 
             @Override
-            public void onPostExecute() {
+            public void onPostExecute(PhoneCallDetails[] details) {
                 if (details == null) {
                     // Somewhere went wrong: we're going to bail out and show error to users.
                     Toast.makeText(CallDetailActivity.this, R.string.toast_call_detail_error,
@@ -461,7 +467,8 @@
                 loadContactPhotos(photoUri);
                 findViewById(R.id.call_detail).setVisibility(View.VISIBLE);
             }
-        });
+        }
+        mAsyncTaskExecutor.submit(Tasks.UPDATE_PHONE_CALL_DETAILS, new UpdateContactDetailsTask());
     }
 
     /** Return the phone call details for a given call log URI. */
@@ -707,34 +714,40 @@
             }
             callIds.append(ContentUris.parseId(callUri));
         }
-        mBackgroundTaskService.submit(new BackgroundTask() {
-            @Override
-            public void doInBackground() {
-                getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
-                        Calls._ID + " IN (" + callIds + ")", null);
-            }
-            @Override
-            public void onPostExecute() {
-                finish();
-            }
-        });
+        mAsyncTaskExecutor.submit(Tasks.REMOVE_FROM_CALL_LOG_AND_FINISH,
+                new AsyncTask<Void, Void, Void>() {
+                    @Override
+                    public Void doInBackground(Void... params) {
+                        getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+                                Calls._ID + " IN (" + callIds + ")", null);
+                        return null;
+                    }
+
+                    @Override
+                    public void onPostExecute(Void result) {
+                        finish();
+                    }
+                });
     }
+
     public void onMenuEditNumberBeforeCall(MenuItem menuItem) {
         startActivity(new Intent(Intent.ACTION_DIAL, mPhoneNumberHelper.getCallUri(mNumber)));
     }
 
     public void onMenuTrashVoicemail(MenuItem menuItem) {
         final Uri voicemailUri = getVoicemailUri();
-        mBackgroundTaskService.submit(new BackgroundTask() {
-            @Override
-            public void doInBackground() {
-                getContentResolver().delete(voicemailUri, null, null);
-            }
-            @Override
-            public void onPostExecute() {
-                finish();
-            }
-        });
+        mAsyncTaskExecutor.submit(Tasks.DELETE_VOICEMAIL_AND_FINISH,
+                new AsyncTask<Void, Void, Void>() {
+                    @Override
+                    public Void doInBackground(Void... params) {
+                        getContentResolver().delete(voicemailUri, null, null);
+                        return null;
+                    }
+                    @Override
+                    public void onPostExecute(Void result) {
+                        finish();
+                    }
+                });
     }
 
     private void configureActionBar() {