1cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/*
2cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
3cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
4cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * you may not use this file except in compliance with the License.
6cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * You may obtain a copy of the License at
7cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
8cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
10cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * See the License for the specific language governing permissions and
14cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * limitations under the License.
15cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
16cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
17cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpackage android.support.v4.content;
18cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas
21cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.content.Context;
22cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.os.Handler;
23cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.os.SystemClock;
24c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo;
25220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.support.v4.os.OperationCanceledException;
26cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.support.v4.util.TimeUtils;
27cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport android.util.Log;
28cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
29cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.FileDescriptor;
30cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.io.PrintWriter;
31cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornimport java.util.concurrent.CountDownLatch;
32220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport java.util.concurrent.Executor;
33cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
34cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/**
35cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Static library support version of the framework's {@link android.content.AsyncTaskLoader}.
36cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Used to write apps that run on platforms prior to Android 3.0.  When running
37cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * on Android 3.0 or above, this implementation is still used; it does not try
38cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * to switch to the framework's implementation.  See the framework SDK
39cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * documentation for a class overview.
40cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
41cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackbornpublic abstract class AsyncTaskLoader<D> extends Loader<D> {
42cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    static final String TAG = "AsyncTaskLoader";
43cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    static final boolean DEBUG = false;
44cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
45fbabff99ccbcb576c713991c5db5dec21a0d0ce0Dianne Hackborn    final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable {
46220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        private final CountDownLatch mDone = new CountDownLatch(1);
47cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
48220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        // Set to true to indicate that the task has been posted to a handler for
49220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        // execution at a later time.  Used to throttle updates.
50cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        boolean waiting;
51cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
52cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        /* Runs on a worker thread */
53cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
54cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        protected D doInBackground(Void... params) {
55cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
56220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            try {
57220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                D data = AsyncTaskLoader.this.onLoadInBackground();
58220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
59220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                return data;
60220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            } catch (OperationCanceledException ex) {
61220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                if (!isCancelled()) {
62220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    // onLoadInBackground threw a canceled exception spuriously.
63220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    // This is problematic because it means that the LoaderManager did not
64220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    // cancel the Loader itself and still expects to receive a result.
65220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    // Additionally, the Loader's own state will not have been updated to
66220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    // reflect the fact that the task was being canceled.
67220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    // So we treat this case as an unhandled exception.
68220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    throw ex;
69220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                }
70220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
71220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                return null;
72220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
73cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
74cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
75cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        /* Runs on the UI thread */
76cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
77cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        protected void onPostExecute(D data) {
78cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, this + " onPostExecute");
79cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            try {
80cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
81cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            } finally {
82220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                mDone.countDown();
83cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
84cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
85cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
86220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        /* Runs on the UI thread */
87cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
88220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        protected void onCancelled(D data) {
89cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, this + " onCancelled");
90cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            try {
91220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                AsyncTaskLoader.this.dispatchOnCancelled(this, data);
92cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            } finally {
93220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                mDone.countDown();
94cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
95cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
96cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
97220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        /* Runs on the UI thread, when the waiting task is posted to a handler.
98220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown         * This method is only executed when task execution was deferred (waiting was true). */
99cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        @Override
100cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        public void run() {
101cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            waiting = false;
102cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            AsyncTaskLoader.this.executePendingTask();
103cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
104220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
105220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        /* Used for testing purposes to wait for the task to complete. */
106220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        public void waitForLoader() {
107220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            try {
108220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                mDone.await();
109220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            } catch (InterruptedException e) {
110220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                // Ignore
111220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
112220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
113cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
114cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
115220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private final Executor mExecutor;
116220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
117cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    volatile LoadTask mTask;
118cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    volatile LoadTask mCancellingTask;
119cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
120cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    long mUpdateThrottle;
121cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    long mLastLoadCompleteTime = -10000;
122cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    Handler mHandler;
123cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
124cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public AsyncTaskLoader(Context context) {
125220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        this(context, ModernAsyncTask.THREAD_POOL_EXECUTOR);
126220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
127220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
128220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private AsyncTaskLoader(Context context, Executor executor) {
129cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        super(context);
130220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        mExecutor = executor;
131cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
132cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
133cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
134cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Set amount to throttle updates by.  This is the minimum time from
135220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * when the last {@link #loadInBackground()} call has completed until
136cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * a new load is scheduled.
137cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
138cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @param delayMS Amount of delay, in milliseconds.
139cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
140cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void setUpdateThrottle(long delayMS) {
141cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mUpdateThrottle = delayMS;
142cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (delayMS != 0) {
143cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mHandler = new Handler();
144cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
145cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
146cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
147cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @Override
148cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected void onForceLoad() {
149cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        super.onForceLoad();
150cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        cancelLoad();
151cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mTask = new LoadTask();
152cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
153cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        executePendingTask();
154cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
155cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
156220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    @Override
157220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    protected boolean onCancelLoad() {
158220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);
159cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mTask != null) {
16068e91a863a33bd9bca500f0c8bce38014b5018b9George Mount            if (!mStarted) {
16168e91a863a33bd9bca500f0c8bce38014b5018b9George Mount                mContentChanged = true;
16268e91a863a33bd9bca500f0c8bce38014b5018b9George Mount            }
163cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mCancellingTask != null) {
164cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // There was a pending task already waiting for a previous
165cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // one being canceled; just drop it.
166cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG,
167cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                        "cancelLoad: still waiting for cancelled task; dropping next");
168cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (mTask.waiting) {
169cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mTask.waiting = false;
170cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mHandler.removeCallbacks(mTask);
171cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
172cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mTask = null;
173cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return false;
174cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            } else if (mTask.waiting) {
175cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // There is a task, but it is waiting for the time it should
176cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // execute.  We can just toss it.
177cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it");
178cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mTask.waiting = false;
179cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mHandler.removeCallbacks(mTask);
180cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mTask = null;
181cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return false;
182cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            } else {
183cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                boolean cancelled = mTask.cancel(false);
184cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);
185cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (cancelled) {
186cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mCancellingTask = mTask;
187220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    cancelLoadInBackground();
188cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
189cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mTask = null;
190cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return cancelled;
191cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
192cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
193cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return false;
194cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
195cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
196cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
197cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Called if the task was canceled before it was completed.  Gives the class a chance
198220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * to clean up post-cancellation and to properly dispose of the result.
199220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
200220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param data The value that was returned by {@link #loadInBackground}, or null
201220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * if the task threw {@link OperationCanceledException}.
202cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
203cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void onCanceled(D data) {
204cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
205cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
206cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void executePendingTask() {
207cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCancellingTask == null && mTask != null) {
208cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mTask.waiting) {
209cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mTask.waiting = false;
210cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mHandler.removeCallbacks(mTask);
211cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
212cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mUpdateThrottle > 0) {
213cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                long now = SystemClock.uptimeMillis();
214cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
215cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    // Not yet time to do another load.
216cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    if (DEBUG) Log.v(TAG, "Waiting until "
217cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            + (mLastLoadCompleteTime+mUpdateThrottle)
218cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            + " to execute: " + mTask);
219cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mTask.waiting = true;
220cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
221cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    return;
222cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
223cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
224cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "Executing: " + mTask);
225220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            mTask.executeOnExecutor(mExecutor, (Void[]) null);
226cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
227cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
228cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
229cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void dispatchOnCancelled(LoadTask task, D data) {
230cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        onCanceled(data);
231cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCancellingTask == task) {
232cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "Cancelled task is now canceled!");
23380a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn            rollbackContentChanged();
234cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mLastLoadCompleteTime = SystemClock.uptimeMillis();
235cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mCancellingTask = null;
236220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (DEBUG) Log.v(TAG, "Delivering cancellation");
237220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            deliverCancellation();
238cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            executePendingTask();
239cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
240cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
241cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
242cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    void dispatchOnLoadComplete(LoadTask task, D data) {
243cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mTask != task) {
244cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel");
245cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            dispatchOnCancelled(task, data);
246cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        } else {
247cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (isAbandoned()) {
248cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // This cursor has been abandoned; just cancel the new data.
249cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                onCanceled(data);
250cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            } else {
25180a0a3a33e3f6c27da4681a4f02eb2c6aae1fd40Dianne Hackborn                commitContentChanged();
252cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mLastLoadCompleteTime = SystemClock.uptimeMillis();
253cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mTask = null;
254cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (DEBUG) Log.v(TAG, "Delivering result");
255cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                deliverResult(data);
256cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
257cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
258cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
259cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
260cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
261220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Called on a worker thread to perform the actual load and to return
262220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * the result of the load operation.
263220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
264220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Implementations should not deliver the result directly, but should return them
265220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * from this method, which will eventually end up calling {@link #deliverResult} on
266220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * the UI thread.  If implementations need to process the results on the UI thread
267220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * they may override {@link #deliverResult} and do so there.
268220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
269220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * To support cancellation, this method should periodically check the value of
270220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
271220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
272220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * directly instead of polling {@link #isLoadInBackgroundCanceled}.
273220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
274220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * When the load is canceled, this method may either return normally or throw
275220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * {@link OperationCanceledException}.  In either case, the {@link Loader} will
276220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
277220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * result object, if any.
278220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
279220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @return The result of the load operation.
280220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
281220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @throws OperationCanceledException if the load is canceled during execution.
282220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
283220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see #isLoadInBackgroundCanceled
284220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see #cancelLoadInBackground
285220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see #onCanceled
286cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
287cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public abstract D loadInBackground();
288cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
289cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
290220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Calls {@link #loadInBackground()}.
291220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
292220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * This method is reserved for use by the loader framework.
293220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Subclasses should override {@link #loadInBackground} instead of this method.
294220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
295220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @return The result of the load operation.
296220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
297220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @throws OperationCanceledException if the load is canceled during execution.
298cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
299220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see #loadInBackground
300cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
301cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    protected D onLoadInBackground() {
302cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return loadInBackground();
303cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
304cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
305cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
306220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Called on the main thread to abort a load in progress.
307220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
308220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Override this method to abort the current invocation of {@link #loadInBackground}
309220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * that is running in the background on a worker thread.
310220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
311220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * This method should do nothing if {@link #loadInBackground} has not started
312220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * running or if it has already finished.
313220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
314220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see #loadInBackground
315220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
316220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public void cancelLoadInBackground() {
317220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
318220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
319220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
320220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
321220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
322220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @return True if the current invocation of {@link #loadInBackground} is being canceled.
323220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
324220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see #loadInBackground
325220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
326220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public boolean isLoadInBackgroundCanceled() {
327220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        return mCancellingTask != null;
328220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
329220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
330220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
331cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Locks the current thread until the loader completes the current load
332cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * operation. Returns immediately if there is no load operation running.
333cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Should not be called from the UI thread: calling it from the UI
334cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * thread would cause a deadlock.
335cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * <p>
336cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Use for testing only.  <b>Never</b> call this from a UI thread.
337cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     *
338cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * @hide
339cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
3408e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
341cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void waitForLoader() {
342cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        LoadTask task = mTask;
343cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (task != null) {
344220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            task.waitForLoader();
345cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
346cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
347cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
348cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    @Override
349cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
350cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        super.dump(prefix, fd, writer, args);
351cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mTask != null) {
352cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mTask="); writer.print(mTask);
353cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    writer.print(" waiting="); writer.println(mTask.waiting);
354cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
355cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mCancellingTask != null) {
356cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask);
357cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    writer.print(" waiting="); writer.println(mCancellingTask.waiting);
358cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
359cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mUpdateThrottle != 0) {
360cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            writer.print(prefix); writer.print("mUpdateThrottle=");
361cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    TimeUtils.formatDuration(mUpdateThrottle, writer);
362cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    writer.print(" mLastLoadCompleteTime=");
363cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    TimeUtils.formatDuration(mLastLoadCompleteTime,
364cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                            SystemClock.uptimeMillis(), writer);
365cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    writer.println();
366cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
367cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
368cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn}
369