/*
* Copyright (C) 2012 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.mms.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Handler;
/**
* This AsyncDialog class is used to execute a runnable in a background thread and once that
* finishes, execute a runnable on the UI thread. If the background runnable task takes longer
* than half a second, a progress modal dialog is displayed.
*
*/
public class AsyncDialog {
private ProgressDialog mProgressDialog;
private final Activity mActivity;
private final Handler mHandler;
public AsyncDialog(Activity activity) {
mActivity = activity;
mHandler = new Handler();
}
/**
* Asynchronously executes a task while blocking the UI with a progress spinner.
*
* Must be invoked by the UI thread. No exceptions!
*
* @param backgroundTask the work to be done in the background wrapped in a Runnable
* @param postExecuteTask an optional runnable to run on the UI thread when the background
* runnable is finished
* @param dialogStringId the id of the string to be shown in the dialog
*/
public void runAsync(final Runnable backgroundTask,
final Runnable postExecuteTask, final int dialogStringId) {
new ModalDialogAsyncTask(dialogStringId, postExecuteTask)
.execute(new Runnable[] {backgroundTask});
}
// Shows the activity's progress spinner. Should be canceled if exiting the activity.
private Runnable mShowProgressDialogRunnable = new Runnable() {
@Override
public void run() {
if (mProgressDialog != null) {
mProgressDialog.show();
}
}
};
public void clearPendingProgressDialog() {
// remove any callback to display a progress spinner
mHandler.removeCallbacks(mShowProgressDialogRunnable);
// clear the dialog so any pending dialog.dismiss() call can be avoided
mProgressDialog = null;
}
/**
* Asynchronously performs tasks specified by Runnables.
* Displays a progress spinner while the tasks are running. The progress spinner
* will only show if tasks have not finished after a certain amount of time.
*
* This AsyncTask must be instantiated and invoked on the UI thread.
*
* TODO: Need to implement a way for the background thread to pass a result to
* the onPostExecute thread. AsyncTask already provides this functionality.
*/
private class ModalDialogAsyncTask extends AsyncTask<Runnable, Void, Void> {
final Runnable mPostExecuteTask;
/**
* Creates the Task with the specified string id to be shown in the dialog
*/
public ModalDialogAsyncTask(int dialogStringId,
final Runnable postExecuteTask) {
mPostExecuteTask = postExecuteTask;
// lazy initialization of progress dialog for loading attachments
if (mProgressDialog == null) {
mProgressDialog = createProgressDialog();
}
mProgressDialog.setMessage(mActivity.getText(dialogStringId));
}
/**
* Initializes the progress dialog with its intended settings.
*/
private ProgressDialog createProgressDialog() {
ProgressDialog dialog = new ProgressDialog(mActivity);
dialog.setIndeterminate(true);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
return dialog;
}
/**
* Activates a progress spinner on the UI. This assumes the UI has invoked this Task.
*/
@Override
protected void onPreExecute() {
// activate spinner after half a second
mHandler.postDelayed(mShowProgressDialogRunnable, 500);
}
/**
* Perform the specified Runnable tasks on a background thread
*/
@Override
protected Void doInBackground(Runnable... params) {
if (params != null) {
try {
for (int i = 0; i < params.length; i++) {
params[i].run();
}
// Test code. Uncomment this block to test the progress dialog popping up.
// try {
// Thread.sleep(2000);
// } catch (Exception e) {
// }
} finally {
// Cancel pending display of the progress bar if the background task has
// finished before the progress bar has popped up.
mHandler.removeCallbacks(mShowProgressDialogRunnable);
}
}
return null;
}
/**
* Deactivates the progress spinner on the UI. This assumes the UI has invoked this Task.
*/
@Override
protected void onPostExecute(Void result) {
if (mActivity.isFinishing()) {
return;
}
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
if (mPostExecuteTask != null) {
mPostExecuteTask.run();
}
}
}
}