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() {
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index 0aba332..1c8c080 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -16,11 +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;
import com.google.common.annotations.VisibleForTesting;
import android.app.Application;
@@ -36,7 +33,6 @@
private static InjectedServices sInjectedServices;
private AccountTypeManager mAccountTypeManager;
private ContactPhotoManager mContactPhotoManager;
- private BackgroundTaskService mBackgroundTaskService;
/**
* Overrides the system services with mocks for testing.
@@ -97,13 +93,6 @@
return mContactPhotoManager;
}
- if (BackgroundTaskService.BACKGROUND_TASK_SERVICE.equals(name)) {
- if (mBackgroundTaskService == null) {
- mBackgroundTaskService = createAsyncTaskBackgroundTaskService();
- }
- return mBackgroundTaskService;
- }
-
return super.getSystemService(name);
}
diff --git a/src/com/android/contacts/util/AbstractBackgroundTask.java b/src/com/android/contacts/util/AbstractBackgroundTask.java
deleted file mode 100644
index c492e7c..0000000
--- a/src/com/android/contacts/util/AbstractBackgroundTask.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2011 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.contacts.util;
-
-import com.android.contacts.util.BackgroundTask;
-
-/**
- * Base class you can use if you only want to override the {@link #doInBackground()} method.
- */
-public abstract class AbstractBackgroundTask implements BackgroundTask {
- @Override
- public void onPostExecute() {
- // No action necessary.
- }
-}
diff --git a/src/com/android/contacts/util/AsyncTaskExecutor.java b/src/com/android/contacts/util/AsyncTaskExecutor.java
new file mode 100644
index 0000000..f202949
--- /dev/null
+++ b/src/com/android/contacts/util/AsyncTaskExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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.contacts.util;
+
+import android.os.AsyncTask;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Interface used to submit {@link AsyncTask} objects to run in the background.
+ * <p>
+ * This interface has a direct parallel with the {@link Executor} interface. It exists to decouple
+ * the mechanics of AsyncTask submission from the description of how that AsyncTask will execute.
+ * <p>
+ * One immediate benefit of this approach is that testing becomes much easier, since it is easy to
+ * introduce a mock or fake AsyncTaskExecutor in unit/integration tests, and thus inspect which
+ * tasks have been submitted and control their execution in an orderly manner.
+ * <p>
+ * Another benefit in due course will be the management of the submitted tasks. An extension to this
+ * interface is planned to allow Activities to easily cancel all the submitted tasks that are still
+ * pending in the onDestroy() method of the Activity.
+ */
+public interface AsyncTaskExecutor {
+ /**
+ * Executes the given AsyncTask with the default Executor.
+ * <p>
+ * This method <b>must only be called from the ui thread</b>.
+ * <p>
+ * The identifier supplied is any Object that can be used to identify the task later. Most
+ * commonly this will be an enum which the tests can also refer to. {@code null} is also
+ * accepted, though of course this won't help in identifying the task later.
+ */
+ <T> AsyncTask<T, ?, ?> submit(Object identifier, AsyncTask<T, ?, ?> task, T... params);
+}
diff --git a/src/com/android/contacts/util/AsyncTaskExecutors.java b/src/com/android/contacts/util/AsyncTaskExecutors.java
new file mode 100644
index 0000000..539dee7
--- /dev/null
+++ b/src/com/android/contacts/util/AsyncTaskExecutors.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 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.contacts.util;
+
+import com.android.contacts.test.NeededForTesting;
+import com.google.common.base.Preconditions;
+
+import android.os.AsyncTask;
+import android.os.Looper;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Factory methods for creating AsyncTaskExecutors.
+ * <p>
+ * All of the factory methods on this class check first to see if you have set a static
+ * {@link AsyncTaskExecutorFactory} set through the
+ * {@link #setFactoryForTest(AsyncTaskExecutorFactory)} method, and if so delegate to that instead,
+ * which is one way of injecting dependencies for testing classes whose construction cannot be
+ * controlled such as {@link android.app.Activity}.
+ */
+public final class AsyncTaskExecutors {
+ /**
+ * A single instance of the {@link AsyncTaskExecutorFactory}, to which we delegate if it is
+ * non-null, for injecting when testing.
+ */
+ private static AsyncTaskExecutorFactory mInjectedAsyncTaskExecutorFactory = null;
+
+ /**
+ * Creates an AsyncTaskExecutor that submits tasks to run with
+ * {@link AsyncTask#SERIAL_EXECUTOR}.
+ */
+ public static AsyncTaskExecutor createAsyncTaskExecutor() {
+ synchronized (AsyncTaskExecutors.class) {
+ if (mInjectedAsyncTaskExecutorFactory != null) {
+ return mInjectedAsyncTaskExecutorFactory.createAsyncTaskExeuctor();
+ }
+ return new SimpleAsyncTaskExecutor(AsyncTask.SERIAL_EXECUTOR);
+ }
+ }
+
+ /**
+ * Creates an AsyncTaskExecutor that submits tasks to run with
+ * {@link AsyncTask#THREAD_POOL_EXECUTOR}.
+ */
+ public static AsyncTaskExecutor createThreadPoolExecutor() {
+ synchronized (AsyncTaskExecutors.class) {
+ if (mInjectedAsyncTaskExecutorFactory != null) {
+ return mInjectedAsyncTaskExecutorFactory.createAsyncTaskExeuctor();
+ }
+ return new SimpleAsyncTaskExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+
+ /** Interface for creating AsyncTaskExecutor objects. */
+ public interface AsyncTaskExecutorFactory {
+ AsyncTaskExecutor createAsyncTaskExeuctor();
+ }
+
+ @NeededForTesting
+ public static void setFactoryForTest(AsyncTaskExecutorFactory factory) {
+ synchronized (AsyncTaskExecutors.class) {
+ mInjectedAsyncTaskExecutorFactory = factory;
+ }
+ }
+
+ public static void checkCalledFromUiThread() {
+ Preconditions.checkState(Thread.currentThread() == Looper.getMainLooper().getThread(),
+ "submit method must be called from ui thread, was: " + Thread.currentThread());
+ }
+
+ private static class SimpleAsyncTaskExecutor implements AsyncTaskExecutor {
+ private final Executor mExecutor;
+
+ public SimpleAsyncTaskExecutor(Executor executor) {
+ mExecutor = executor;
+ }
+
+ @Override
+ public <T> AsyncTask<T, ?, ?> submit(Object identifer, AsyncTask<T, ?, ?> task,
+ T... params) {
+ checkCalledFromUiThread();
+ return task.executeOnExecutor(mExecutor, params);
+ }
+ }
+}
diff --git a/src/com/android/contacts/util/BackgroundTask.java b/src/com/android/contacts/util/BackgroundTask.java
deleted file mode 100644
index ba791fb..0000000
--- a/src/com/android/contacts/util/BackgroundTask.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 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.contacts.util;
-
-/**
- * Simple interface to improve the testability of code using AsyncTasks.
- * <p>
- * Provides a trivial replacement for no-arg versions of AsyncTask clients. We may extend this
- * to add more functionality as we require.
- * <p>
- * The same memory-visibility guarantees are made here as are made for AsyncTask objects, namely
- * that fields set in {@link #doInBackground()} are visible to {@link #onPostExecute()}.
- */
-public interface BackgroundTask {
- public void doInBackground();
- public void onPostExecute();
-}
diff --git a/src/com/android/contacts/util/BackgroundTaskService.java b/src/com/android/contacts/util/BackgroundTaskService.java
deleted file mode 100644
index 310a178..0000000
--- a/src/com/android/contacts/util/BackgroundTaskService.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2011 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.contacts.util;
-
-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);
-
- /**
- * 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(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) {
- task.doInBackground();
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- task.onPostExecute();
- }
- }.executeOnExecutor(executor);
- }
- }
-}
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
index 5e53b76..5eb0ddf 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
@@ -21,7 +21,7 @@
import com.android.common.io.MoreCloseables;
import com.android.contacts.R;
-import com.android.contacts.util.BackgroundTaskService;
+import com.android.contacts.util.AsyncTaskExecutors;
import com.android.ex.variablespeed.MediaPlayerProxy;
import com.android.ex.variablespeed.VariableSpeed;
import com.google.common.base.Preconditions;
@@ -93,15 +93,11 @@
boolean startPlayback = arguments.getBoolean(EXTRA_VOICEMAIL_START_PLAYBACK, false);
mPresenter = new VoicemailPlaybackPresenter(createPlaybackViewImpl(),
createMediaPlayer(mScheduledExecutorService), voicemailUri,
- mScheduledExecutorService, startPlayback, getBackgroundTaskService());
+ mScheduledExecutorService, startPlayback,
+ AsyncTaskExecutors.createAsyncTaskExecutor());
mPresenter.onCreate(savedInstanceState);
}
- private BackgroundTaskService getBackgroundTaskService() {
- return (BackgroundTaskService) getActivity().getApplicationContext().getSystemService(
- BackgroundTaskService.BACKGROUND_TASK_SERVICE);
- }
-
@Override
public void onSaveInstanceState(Bundle outState) {
mPresenter.onSaveInstanceState(outState);
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index bd01991..d3e4bef 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -19,10 +19,10 @@
import static android.util.MathUtils.constrain;
import com.android.contacts.R;
-import com.android.contacts.util.BackgroundTask;
-import com.android.contacts.util.BackgroundTaskService;
+import com.android.contacts.util.AsyncTaskExecutor;
import com.android.ex.variablespeed.MediaPlayerProxy;
import com.android.ex.variablespeed.SingleThreadedMediaPlayerProxy;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import android.content.Context;
@@ -57,7 +57,8 @@
* the main ui thread.
*/
@NotThreadSafe
-/*package*/ class VoicemailPlaybackPresenter {
+@VisibleForTesting
+public class VoicemailPlaybackPresenter {
/** Contract describing the behaviour we need from the ui we are controlling. */
public interface PlaybackView {
Context getDataSourceContext();
@@ -87,6 +88,13 @@
void unregisterContentObserver(ContentObserver observer);
}
+ /** The enumeration of {@link AsyncTask} objects we use in this class. */
+ public enum Tasks {
+ CHECK_FOR_CONTENT,
+ CHECK_CONTENT_AFTER_CHANGE,
+ PREPARE_MEDIA_PLAYER,
+ }
+
/** Update rate for the slider, 30fps. */
private static final int SLIDER_UPDATE_PERIOD_MILLIS = 1000 / 30;
/** Time our ui will wait for content to be fetched before reporting not available. */
@@ -143,8 +151,8 @@
private final Uri mVoicemailUri;
/** Start playing in onCreate iff this is true. */
private final boolean mStartPlayingImmediately;
- /** Used to run background tasks that need to interact with the ui. */
- private final BackgroundTaskService mBackgroundTaskService;
+ /** Used to run async tasks that need to interact with the ui. */
+ private final AsyncTaskExecutor mAsyncTaskExecutor;
/**
* Used to handle the result of a successful or time-out fetch result.
@@ -155,12 +163,12 @@
public VoicemailPlaybackPresenter(PlaybackView view, MediaPlayerProxy player,
Uri voicemailUri, ScheduledExecutorService executorService,
- boolean startPlayingImmediately, BackgroundTaskService backgroundTaskService) {
+ boolean startPlayingImmediately, AsyncTaskExecutor asyncTaskExecutor) {
mView = view;
mPlayer = player;
mVoicemailUri = voicemailUri;
mStartPlayingImmediately = startPlayingImmediately;
- mBackgroundTaskService = backgroundTaskService;
+ mAsyncTaskExecutor = asyncTaskExecutor;
mPositionUpdater = new PositionUpdater(executorService, SLIDER_UPDATE_PERIOD_MILLIS);
}
@@ -181,23 +189,21 @@
*/
private void checkThatWeHaveContent() {
mView.setIsFetchingContent();
- mBackgroundTaskService.submit(new BackgroundTask() {
- private boolean mHasContent = false;
-
+ mAsyncTaskExecutor.submit(Tasks.CHECK_FOR_CONTENT, new AsyncTask<Void, Void, Boolean>() {
@Override
- public void doInBackground() {
- mHasContent = mView.queryHasContent(mVoicemailUri);
+ public Boolean doInBackground(Void... params) {
+ return mView.queryHasContent(mVoicemailUri);
}
@Override
- public void onPostExecute() {
- if (mHasContent) {
+ public void onPostExecute(Boolean hasContent) {
+ if (hasContent) {
postSuccessfullyFetchedContent();
} else {
makeRequestForContent();
}
}
- }, AsyncTask.THREAD_POOL_EXECUTOR);
+ });
}
/**
@@ -253,24 +259,23 @@
@Override
public void onChange(boolean selfChange) {
- mBackgroundTaskService.submit(new BackgroundTask() {
- private boolean mHasContent = false;
-
+ mAsyncTaskExecutor.submit(Tasks.CHECK_CONTENT_AFTER_CHANGE,
+ new AsyncTask<Void, Void, Boolean>() {
@Override
- public void doInBackground() {
- mHasContent = mView.queryHasContent(mVoicemailUri);
+ public Boolean doInBackground(Void... params) {
+ return mView.queryHasContent(mVoicemailUri);
}
@Override
- public void onPostExecute() {
- if (mHasContent) {
+ public void onPostExecute(Boolean hasContent) {
+ if (hasContent) {
if (mResultStillPending.getAndSet(false)) {
mView.unregisterContentObserver(FetchResultHandler.this);
postSuccessfullyFetchedContent();
}
}
}
- }, AsyncTask.THREAD_POOL_EXECUTOR);
+ });
}
}
@@ -286,29 +291,29 @@
*/
private void postSuccessfullyFetchedContent() {
mView.setIsBuffering();
- mBackgroundTaskService.submit(new BackgroundTask() {
- private Exception mException;
+ mAsyncTaskExecutor.submit(Tasks.PREPARE_MEDIA_PLAYER,
+ new AsyncTask<Void, Void, Exception>() {
+ @Override
+ public Exception doInBackground(Void... params) {
+ try {
+ mPlayer.reset();
+ mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
+ mPlayer.prepare();
+ return null;
+ } catch (IOException e) {
+ return e;
+ }
+ }
- @Override
- public void doInBackground() {
- try {
- mPlayer.reset();
- mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
- mPlayer.prepare();
- } catch (IOException e) {
- mException = e;
- }
- }
-
- @Override
- public void onPostExecute() {
- if (mException == null) {
- postSuccessfulPrepareActions();
- } else {
- mView.playbackError(mException);
- }
- }
- }, AsyncTask.THREAD_POOL_EXECUTOR);
+ @Override
+ public void onPostExecute(Exception exception) {
+ if (exception == null) {
+ postSuccessfulPrepareActions();
+ } else {
+ mView.playbackError(exception);
+ }
+ }
+ });
}
/**