Home | History | Annotate | Download | only in shadows
      1 package com.xtremelabs.robolectric.shadows;
      2 
      3 import android.os.AsyncTask;
      4 import android.os.ShadowAsyncTaskBridge;
      5 import com.xtremelabs.robolectric.Robolectric;
      6 import com.xtremelabs.robolectric.internal.Implementation;
      7 import com.xtremelabs.robolectric.internal.Implements;
      8 import com.xtremelabs.robolectric.internal.RealObject;
      9 
     10 import java.util.concurrent.Callable;
     11 import java.util.concurrent.CancellationException;
     12 import java.util.concurrent.ExecutionException;
     13 import java.util.concurrent.FutureTask;
     14 import java.util.concurrent.TimeUnit;
     15 import java.util.concurrent.TimeoutException;
     16 
     17 @Implements(AsyncTask.class)
     18 public class ShadowAsyncTask<Params, Progress, Result> {
     19 
     20     @RealObject private AsyncTask<Params, Progress, Result> realAsyncTask;
     21 
     22     private final FutureTask<Result> future;
     23     private final BackgroundWorker worker;
     24     private AsyncTask.Status status = AsyncTask.Status.PENDING;
     25 
     26 	public ShadowAsyncTask() {
     27 		worker = new BackgroundWorker();
     28 		future = new FutureTask<Result>(worker) {
     29         	@Override
     30         	protected void done() {
     31                 status = AsyncTask.Status.FINISHED;
     32 				try {
     33 					final Result result = get();
     34 					Robolectric.getUiThreadScheduler().post(new Runnable() {
     35 						@Override public void run() {
     36 							getBridge().onPostExecute(result);
     37 						}
     38 					});
     39 				} catch (CancellationException e) {
     40 					Robolectric.getUiThreadScheduler().post(new Runnable() {
     41 						@Override public void run() {
     42 							getBridge().onCancelled();
     43 						}
     44 					});
     45 				} catch (InterruptedException e) {
     46 					// Ignore.
     47 				} catch (Throwable t) {
     48 					throw new RuntimeException("An error occured while executing doInBackground()",
     49 							t);
     50 				}
     51         	}
     52         };
     53 	}
     54 
     55 	@Implementation
     56     public boolean isCancelled() {
     57         return future.isCancelled();
     58     }
     59 
     60     @Implementation
     61     public boolean cancel(boolean mayInterruptIfRunning) {
     62         return future.cancel(mayInterruptIfRunning);
     63     }
     64 
     65     @Implementation
     66     public Result get() throws InterruptedException, ExecutionException {
     67         return future.get();
     68     }
     69 
     70     @Implementation
     71     public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
     72         return future.get(timeout, unit);
     73     }
     74 
     75     @Implementation
     76     public AsyncTask<Params, Progress, Result> execute(final Params... params) {
     77         status = AsyncTask.Status.RUNNING;
     78         getBridge().onPreExecute();
     79 
     80         worker.params = params;
     81 
     82         Robolectric.getBackgroundScheduler().post(new Runnable() {
     83             @Override public void run() {
     84             	future.run();
     85             }
     86         });
     87 
     88         return realAsyncTask;
     89     }
     90 
     91     @Implementation
     92     public AsyncTask.Status getStatus() {
     93         return status;
     94     }
     95 
     96     /**
     97      * Enqueue a call to {@link AsyncTask#onProgressUpdate(Object[])} on UI looper (or run it immediately
     98      * if the looper it is not paused).
     99      *
    100      * @param values The progress values to update the UI with.
    101      * @see AsyncTask#publishProgress(Object[])
    102      */
    103     @Implementation
    104     public void publishProgress(final Progress... values) {
    105         Robolectric.getUiThreadScheduler().post(new Runnable() {
    106             @Override public void run() {
    107                 getBridge().onProgressUpdate(values);
    108             }
    109         });
    110     }
    111 
    112     private ShadowAsyncTaskBridge<Params, Progress, Result> getBridge() {
    113         return new ShadowAsyncTaskBridge<Params, Progress, Result>(realAsyncTask);
    114     }
    115 
    116     private final class BackgroundWorker implements Callable<Result> {
    117     	Params[] params;
    118 		@Override
    119 		public Result call() throws Exception {
    120 			return getBridge().doInBackground(params);
    121 		}
    122 	}
    123 }
    124