1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.mms.ui; 18 19 import com.android.mms.R; 20 import com.android.mms.layout.LayoutManager; 21 22 import android.app.Activity; 23 import android.app.ProgressDialog; 24 import android.content.Context; 25 import android.os.AsyncTask; 26 import android.os.Handler; 27 28 29 /** 30 * This AsyncDialog class is used to execute a runnable in a background thread and once that 31 * finishes, execute a runnable on the UI thread. If the background runnable task takes longer 32 * than half a second, a progress modal dialog is displayed. 33 * 34 */ 35 public class AsyncDialog { 36 private ProgressDialog mProgressDialog; 37 private final Activity mActivity; 38 private final Handler mHandler; 39 40 public AsyncDialog(Activity activity) { 41 mActivity = activity; 42 mHandler = new Handler(); 43 } 44 45 /** 46 * Asynchronously executes a task while blocking the UI with a progress spinner. 47 * 48 * Must be invoked by the UI thread. No exceptions! 49 * 50 * @param backgroundTask the work to be done in the background wrapped in a Runnable 51 * @param postExecuteTask an optional runnable to run on the UI thread when the background 52 * runnable is finished 53 * @param dialogStringId the id of the string to be shown in the dialog 54 */ 55 public void runAsync(final Runnable backgroundTask, 56 final Runnable postExecuteTask, final int dialogStringId) { 57 new ModalDialogAsyncTask(dialogStringId, postExecuteTask) 58 .execute(new Runnable[] {backgroundTask}); 59 } 60 61 // Shows the activity's progress spinner. Should be canceled if exiting the activity. 62 private Runnable mShowProgressDialogRunnable = new Runnable() { 63 @Override 64 public void run() { 65 if (mProgressDialog != null) { 66 mProgressDialog.show(); 67 } 68 } 69 }; 70 71 public void clearPendingProgressDialog() { 72 // remove any callback to display a progress spinner 73 mHandler.removeCallbacks(mShowProgressDialogRunnable); 74 // clear the dialog so any pending dialog.dismiss() call can be avoided 75 mProgressDialog = null; 76 } 77 78 /** 79 * Asynchronously performs tasks specified by Runnables. 80 * Displays a progress spinner while the tasks are running. The progress spinner 81 * will only show if tasks have not finished after a certain amount of time. 82 * 83 * This AsyncTask must be instantiated and invoked on the UI thread. 84 * 85 * TODO: Need to implement a way for the background thread to pass a result to 86 * the onPostExecute thread. AsyncTask already provides this functionality. 87 */ 88 private class ModalDialogAsyncTask extends AsyncTask<Runnable, Void, Void> { 89 final Runnable mPostExecuteTask; 90 91 /** 92 * Creates the Task with the specified string id to be shown in the dialog 93 */ 94 public ModalDialogAsyncTask(int dialogStringId, 95 final Runnable postExecuteTask) { 96 mPostExecuteTask = postExecuteTask; 97 // lazy initialization of progress dialog for loading attachments 98 if (mProgressDialog == null) { 99 mProgressDialog = createProgressDialog(); 100 } 101 mProgressDialog.setMessage(mActivity.getText(dialogStringId)); 102 } 103 104 /** 105 * Initializes the progress dialog with its intended settings. 106 */ 107 private ProgressDialog createProgressDialog() { 108 ProgressDialog dialog = new ProgressDialog(mActivity); 109 dialog.setIndeterminate(true); 110 dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 111 dialog.setCanceledOnTouchOutside(false); 112 dialog.setCancelable(false); 113 return dialog; 114 } 115 116 /** 117 * Activates a progress spinner on the UI. This assumes the UI has invoked this Task. 118 */ 119 @Override 120 protected void onPreExecute() { 121 // activate spinner after half a second 122 mHandler.postDelayed(mShowProgressDialogRunnable, 500); 123 } 124 125 /** 126 * Perform the specified Runnable tasks on a background thread 127 */ 128 @Override 129 protected Void doInBackground(Runnable... params) { 130 if (params != null) { 131 try { 132 for (int i = 0; i < params.length; i++) { 133 params[i].run(); 134 } 135 136 // Test code. Uncomment this block to test the progress dialog popping up. 137 // try { 138 // Thread.sleep(2000); 139 // } catch (Exception e) { 140 // } 141 } finally { 142 // Cancel pending display of the progress bar if the background task has 143 // finished before the progress bar has popped up. 144 mHandler.removeCallbacks(mShowProgressDialogRunnable); 145 } 146 } 147 return null; 148 } 149 150 /** 151 * Deactivates the progress spinner on the UI. This assumes the UI has invoked this Task. 152 */ 153 @Override 154 protected void onPostExecute(Void result) { 155 if (mProgressDialog != null && mProgressDialog.isShowing()) { 156 mProgressDialog.dismiss(); 157 } 158 if (mPostExecuteTask != null) { 159 mPostExecuteTask.run(); 160 } 161 } 162 } 163 }