171d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williamspackage com.xtremelabs.robolectric.shadows;
271d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
371d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williamsimport android.os.AsyncTask;
471d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williamsimport android.os.ShadowAsyncTaskBridge;
571d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williamsimport com.xtremelabs.robolectric.Robolectric;
622c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.Implementation;
722c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.Implements;
822c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.RealObject;
971d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
10cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultzimport java.util.concurrent.Callable;
11cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultzimport java.util.concurrent.CancellationException;
12cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultzimport java.util.concurrent.ExecutionException;
13cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultzimport java.util.concurrent.FutureTask;
14cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultzimport java.util.concurrent.TimeUnit;
15cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultzimport java.util.concurrent.TimeoutException;
16cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultz
1771d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams@Implements(AsyncTask.class)
1871d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williamspublic class ShadowAsyncTask<Params, Progress, Result> {
198d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft
20f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    @RealObject private AsyncTask<Params, Progress, Result> realAsyncTask;
218ac50c8ceba6b4a4464a2e6619a3f06cbcd702c1Wenhui Yao
22f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    private final FutureTask<Result> future;
23f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    private final BackgroundWorker worker;
24f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    private AsyncTask.Status status = AsyncTask.Status.PENDING;
258ac50c8ceba6b4a4464a2e6619a3f06cbcd702c1Wenhui Yao
268d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft	public ShadowAsyncTask() {
278d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft		worker = new BackgroundWorker();
288d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft		future = new FutureTask<Result>(worker) {
298d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        	@Override
308d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        	protected void done() {
31f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel                status = AsyncTask.Status.FINISHED;
328d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft				try {
338d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					final Result result = get();
348d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					Robolectric.getUiThreadScheduler().post(new Runnable() {
358d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft						@Override public void run() {
368d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft							getBridge().onPostExecute(result);
378d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft						}
388d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					});
398d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft				} catch (CancellationException e) {
408d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					Robolectric.getUiThreadScheduler().post(new Runnable() {
418d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft						@Override public void run() {
428d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft							getBridge().onCancelled();
438d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft						}
448d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					});
458d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft				} catch (InterruptedException e) {
468d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					// Ignore.
478d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft				} catch (Throwable t) {
488d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft					throw new RuntimeException("An error occured while executing doInBackground()",
49277acc162389794a49c28b241b5591df63c4d637Jon Boekenoogen							t);
508d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft				}
518d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        	}
528d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        };
538d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft	}
5471d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
558d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft	@Implementation
568d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    public boolean isCancelled() {
578d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        return future.isCancelled();
588d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    }
5971d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
60c357b8918be524c83f806119eb4aead2259a9ef6Phil Goodwin & Tyler Schultz    @Implementation
6171d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams    public boolean cancel(boolean mayInterruptIfRunning) {
628d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        return future.cancel(mayInterruptIfRunning);
6371d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams    }
6471d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
65cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultz    @Implementation
668d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    public Result get() throws InterruptedException, ExecutionException {
678d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        return future.get();
688d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    }
6971d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
70cdc28f1a2d605ebc0ad6ea19251718602480a393Joe Moore & Tyler Schultz    @Implementation
718d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
728d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        return future.get(timeout, unit);
738d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    }
7471d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
75c357b8918be524c83f806119eb4aead2259a9ef6Phil Goodwin & Tyler Schultz    @Implementation
768d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    public AsyncTask<Params, Progress, Result> execute(final Params... params) {
77f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel        status = AsyncTask.Status.RUNNING;
786b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams        getBridge().onPreExecute();
798cb1d30709655f11542120d321f1293954a70d96Jan Berkel
808d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft        worker.params = params;
8171d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
820fe1965a36c508fb5b9fa4c8d0caa2d30540f2ccChristian Williams & Phil Goodwin        Robolectric.getBackgroundScheduler().post(new Runnable() {
8371d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams            @Override public void run() {
848d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft            	future.run();
8571d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams            }
8671d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams        });
878cb1d30709655f11542120d321f1293954a70d96Jan Berkel
888cb1d30709655f11542120d321f1293954a70d96Jan Berkel        return realAsyncTask;
8971d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams    }
9071d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams
91f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    @Implementation
92f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    public AsyncTask.Status getStatus() {
93f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel        return status;
94f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel    }
95f98fe60b10305335ff39a2dd6ab04948e9fc83f7Jan Berkel
966b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams    /**
976b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams     * Enqueue a call to {@link AsyncTask#onProgressUpdate(Object[])} on UI looper (or run it immediately
986b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams     * if the looper it is not paused).
996b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams     *
1006b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams     * @param values The progress values to update the UI with.
1016b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams     * @see AsyncTask#publishProgress(Object[])
1026b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams     */
1036b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams    @Implementation
1046b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams    public void publishProgress(final Progress... values) {
1056b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams        Robolectric.getUiThreadScheduler().post(new Runnable() {
1066b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams            @Override public void run() {
1076b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams                getBridge().onProgressUpdate(values);
1086b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams            }
1096b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams        });
1106b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams    }
1116b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams
1126b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams    private ShadowAsyncTaskBridge<Params, Progress, Result> getBridge() {
1136b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams        return new ShadowAsyncTaskBridge<Params, Progress, Result>(realAsyncTask);
1146b3f26530e07e46c5c79d37a3cdeb3856f9339cdChristian Williams    }
1158cb1d30709655f11542120d321f1293954a70d96Jan Berkel
1168d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    private final class BackgroundWorker implements Callable<Result> {
1178d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft    	Params[] params;
1188d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft		@Override
1198d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft		public Result call() throws Exception {
1208d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft			return getBridge().doInBackground(params);
1218d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft		}
1228d84df659ff5bf89d11256618a5e4c5f08cc15eaNeil Traft	}
12371d7c3bcf0400e4b81109dd785187e1a93da3cabChristian Williams}
124