19911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton/*
29911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * Copyright (C) 2010 The Android Open Source Project
39911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *
49911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
59911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * you may not use this file except in compliance with the License.
69911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * You may obtain a copy of the License at
79911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *
89911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
99911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton *
109911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * Unless required by applicable law or agreed to in writing, software
119911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
129911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * See the License for the specific language governing permissions and
149911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * limitations under the License.
159911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton */
169911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
179911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonpackage android.content;
189911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
199911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonimport android.os.AsyncTask;
20247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.os.Handler;
21a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.OperationCanceledException;
22247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.os.SystemClock;
23540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackbornimport android.util.Slog;
24247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport android.util.TimeUtils;
25cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov
26247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport java.io.FileDescriptor;
27247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackbornimport java.io.PrintWriter;
2859d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikovimport java.util.concurrent.CountDownLatch;
299911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
309911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton/**
319567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * Abstract Loader that provides an {@link AsyncTask} to do the work.  See
329567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@link Loader} and {@link android.app.LoaderManager} for more details.
339567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
349567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * <p>Here is an example implementation of an AsyncTaskLoader subclass that
359567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * loads the currently installed applications from the package manager.  This
369567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * implementation takes care of retrieving the application labels and sorting
379567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * its result set from them, monitoring for changes to the installed
389567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * applications, and rebuilding the list when a change in configuration requires
399567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * this (such as a locale change).
409567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
419567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
429567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *      loader}
439567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
449567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * <p>An example implementation of a fragment that uses the above loader to show
459567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * the currently installed applications in a list is below.
469567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *
479567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
489567a66a5e6f49dd8495fb5f6e2efb9f32e84b35Dianne Hackborn *      fragment}
49bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov *
509911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton * @param <D> the data type to be loaded.
519911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton */
529911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamiltonpublic abstract class AsyncTaskLoader<D> extends Loader<D> {
53540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn    static final String TAG = "AsyncTaskLoader";
54540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn    static final boolean DEBUG = false;
55cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov
56247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
57b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        private final CountDownLatch mDone = new CountDownLatch(1);
58bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
59b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        // Set to true to indicate that the task has been posted to a handler for
60b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        // execution at a later time.  Used to throttle updates.
61247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        boolean waiting;
62bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
639911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        /* Runs on a worker thread */
649911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        @Override
659911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        protected D doInBackground(Void... params) {
66540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn            if (DEBUG) Slog.v(TAG, this + " >>> doInBackground");
67b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            try {
68b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                D data = AsyncTaskLoader.this.onLoadInBackground();
69b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
70b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                return data;
71b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            } catch (OperationCanceledException ex) {
72b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                if (!isCancelled()) {
73b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // onLoadInBackground threw a canceled exception spuriously.
74b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // This is problematic because it means that the LoaderManager did not
75b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // cancel the Loader itself and still expects to receive a result.
76b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // Additionally, the Loader's own state will not have been updated to
77b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // reflect the fact that the task was being canceled.
78b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    // So we treat this case as an unhandled exception.
79b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    throw ex;
80b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                }
81b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground (was canceled)");
82b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                return null;
83b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            }
849911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        }
859911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
869911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        /* Runs on the UI thread */
879911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        @Override
889911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        protected void onPostExecute(D data) {
89540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn            if (DEBUG) Slog.v(TAG, this + " onPostExecute");
9059d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            try {
9159d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
9259d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            } finally {
93b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                mDone.countDown();
9459d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            }
959911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        }
96bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
97b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        /* Runs on the UI thread */
98bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov        @Override
99b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        protected void onCancelled(D data) {
100540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn            if (DEBUG) Slog.v(TAG, this + " onCancelled");
10159d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            try {
102b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                AsyncTaskLoader.this.dispatchOnCancelled(this, data);
10359d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            } finally {
104b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                mDone.countDown();
10559d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov            }
106247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
107247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
108b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        /* Runs on the UI thread, when the waiting task is posted to a handler.
109b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown         * This method is only executed when task execution was deferred (waiting was true). */
110247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        @Override
111247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        public void run() {
112247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            waiting = false;
113247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            AsyncTaskLoader.this.executePendingTask();
114bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov        }
115b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown
116b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        /* Used for testing purposes to wait for the task to complete. */
117b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        public void waitForLoader() {
118b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            try {
119b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                mDone.await();
120b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            } catch (InterruptedException e) {
121b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                // Ignore
122b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            }
123b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        }
1249911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
1259911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
126cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    volatile LoadTask mTask;
127247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    volatile LoadTask mCancellingTask;
128247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
129247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    long mUpdateThrottle;
130247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    long mLastLoadCompleteTime = -10000;
131247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    Handler mHandler;
1329911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
1339911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    public AsyncTaskLoader(Context context) {
1349911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        super(context);
1359911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
1369911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
137247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    /**
138247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * Set amount to throttle updates by.  This is the minimum time from
139b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * when the last {@link #loadInBackground()} call has completed until
140247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * a new load is scheduled.
141247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     *
142247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * @param delayMS Amount of delay, in milliseconds.
143247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     */
144247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public void setUpdateThrottle(long delayMS) {
145247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        mUpdateThrottle = delayMS;
146247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (delayMS != 0) {
147247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            mHandler = new Handler();
148247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
149247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
150247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
1519911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    @Override
152a2ea747faaf5fcd437afbaaf4085cfc29e7c16b8Dianne Hackborn    protected void onForceLoad() {
1530e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        super.onForceLoad();
154bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov        cancelLoad();
1559911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        mTask = new LoadTask();
156540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn        if (DEBUG) Slog.v(TAG, "Preparing load: mTask=" + mTask);
157247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        executePendingTask();
1589911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
1599911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
160b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    @Override
161b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    protected boolean onCancelLoad() {
162b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown        if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask);
1639911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        if (mTask != null) {
164247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            if (mCancellingTask != null) {
165247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // There was a pending task already waiting for a previous
166247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // one being canceled; just drop it.
167540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                if (DEBUG) Slog.v(TAG,
168540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                        "cancelLoad: still waiting for cancelled task; dropping next");
169247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                if (mTask.waiting) {
170247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mTask.waiting = false;
171247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mHandler.removeCallbacks(mTask);
172247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                }
173247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask = null;
174247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                return false;
175247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            } else if (mTask.waiting) {
176247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // There is a task, but it is waiting for the time it should
177247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                // execute.  We can just toss it.
178540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                if (DEBUG) Slog.v(TAG, "cancelLoad: task is waiting, dropping it");
179247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask.waiting = false;
180247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mHandler.removeCallbacks(mTask);
181247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask = null;
182247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                return false;
183247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            } else {
184247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                boolean cancelled = mTask.cancel(false);
185540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
186247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                if (cancelled) {
187247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mCancellingTask = mTask;
188b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown                    cancelLoadInBackground();
189247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                }
190247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask = null;
191247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                return cancelled;
192247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            }
1939911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        }
1949911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton        return false;
1959911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
196bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov
197bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov    /**
198bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov     * Called if the task was canceled before it was completed.  Gives the class a chance
199b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * to clean up post-cancellation and to properly dispose of the result.
200b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
201b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @param data The value that was returned by {@link #loadInBackground}, or null
202b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * if the task threw {@link OperationCanceledException}.
203bef9c7a59dc020c5cdcbd555b5212ae5a10e8045Dmitri Plotnikov     */
204327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn    public void onCanceled(D data) {
205327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn    }
2064afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov
207247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    void executePendingTask() {
208247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mCancellingTask == null && mTask != null) {
209247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            if (mTask.waiting) {
210247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mTask.waiting = false;
211247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                mHandler.removeCallbacks(mTask);
212247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            }
213247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            if (mUpdateThrottle > 0) {
214247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                long now = SystemClock.uptimeMillis();
215247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
216247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    // Not yet time to do another load.
217540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                    if (DEBUG) Slog.v(TAG, "Waiting until "
218540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                            + (mLastLoadCompleteTime+mUpdateThrottle)
219540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn                            + " to execute: " + mTask);
220247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mTask.waiting = true;
221247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
222247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    return;
223247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                }
224247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            }
225540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn            if (DEBUG) Slog.v(TAG, "Executing: " + mTask);
2265d9d03a0234faa3cffd11502f973057045cafe82Dianne Hackborn            mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
227247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
228247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
229247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
230247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    void dispatchOnCancelled(LoadTask task, D data) {
231327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn        onCanceled(data);
232247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mCancellingTask == task) {
233540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn            if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
234247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            mLastLoadCompleteTime = SystemClock.uptimeMillis();
235247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            mCancellingTask = null;
236b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            if (DEBUG) Slog.v(TAG, "Delivering cancellation");
237b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            deliverCancellation();
238247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            executePendingTask();
239247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
240247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
241247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
2420e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn    void dispatchOnLoadComplete(LoadTask task, D data) {
2430e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        if (mTask != task) {
244540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn            if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel");
245247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            dispatchOnCancelled(task, data);
2460e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        } else {
247260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn            if (isAbandoned()) {
248260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                // This cursor has been abandoned; just cancel the new data.
249260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                onCanceled(data);
250260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn            } else {
251260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                mLastLoadCompleteTime = SystemClock.uptimeMillis();
252260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                mTask = null;
253260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                if (DEBUG) Slog.v(TAG, "Delivering result");
254260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn                deliverResult(data);
255260c3c77d9b340164e055f87002c64d78da6e836Dianne Hackborn            }
2560e3b8f421dfcc5363f234eb1b76479cb2fb2e8eeDianne Hackborn        }
2579911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    }
2589911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton
2599911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton    /**
260b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Called on a worker thread to perform the actual load and to return
261b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * the result of the load operation.
262b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
263b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Implementations should not deliver the result directly, but should return them
264b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * from this method, which will eventually end up calling {@link #deliverResult} on
265b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * the UI thread.  If implementations need to process the results on the UI thread
266b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * they may override {@link #deliverResult} and do so there.
267b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
268b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * To support cancellation, this method should periodically check the value of
269b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
270b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
271b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * directly instead of polling {@link #isLoadInBackgroundCanceled}.
272b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
273b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * When the load is canceled, this method may either return normally or throw
274b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * {@link OperationCanceledException}.  In either case, the {@link Loader} will
275b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
276b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * result object, if any.
277b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
278b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @return The result of the load operation.
279b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
280b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @throws OperationCanceledException if the load is canceled during execution.
281b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
282b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #isLoadInBackgroundCanceled
283b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #cancelLoadInBackground
284b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #onCanceled
285247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     */
286247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public abstract D loadInBackground();
287247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
288247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    /**
289b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Calls {@link #loadInBackground()}.
290b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
291b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * This method is reserved for use by the loader framework.
292b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Subclasses should override {@link #loadInBackground} instead of this method.
293b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
294b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @return The result of the load operation.
2959911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton     *
296b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @throws OperationCanceledException if the load is canceled during execution.
297b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
298b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #loadInBackground
2999911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton     */
300247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    protected D onLoadInBackground() {
301247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        return loadInBackground();
302247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
303cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov
304cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    /**
305b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Called on the main thread to abort a load in progress.
306b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
307b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Override this method to abort the current invocation of {@link #loadInBackground}
308b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * that is running in the background on a worker thread.
30975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
310b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * This method should do nothing if {@link #loadInBackground} has not started
311b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * running or if it has already finished.
312b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
313b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #loadInBackground
31475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
315b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    public void cancelLoadInBackground() {
31675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
31775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
31875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
319b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
320b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     *
321b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @return True if the current invocation of {@link #loadInBackground} is being canceled.
32275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
323b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown     * @see #loadInBackground
32475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
325b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown    public boolean isLoadInBackgroundCanceled() {
32675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return mCancellingTask != null;
32775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
32875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
32975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
330cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     * Locks the current thread until the loader completes the current load
331cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     * operation. Returns immediately if there is no load operation running.
33259d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov     * Should not be called from the UI thread: calling it from the UI
33359d8edd09dc88cc0eb629bdee711a004d300f2faDmitri Plotnikov     * thread would cause a deadlock.
334cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     * <p>
335247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn     * Use for testing only.  <b>Never</b> call this from a UI thread.
3364afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov     *
3374afde4fda383116a9730aea1e931d4bce7ea0fd0Dmitri Plotnikov     * @hide
338cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov     */
339cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    public void waitForLoader() {
340cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov        LoadTask task = mTask;
341cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov        if (task != null) {
342b19a71a20adb48c084e87d06a1e6b0dcb49170f5Jeff Brown            task.waitForLoader();
343cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov        }
344cd3676e7b835653b04d4f66251a63749e7603f5bDmitri Plotnikov    }
345247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
346247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    @Override
347247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
348247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        super.dump(prefix, fd, writer, args);
349247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mTask != null) {
350247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            writer.print(prefix); writer.print("mTask="); writer.print(mTask);
351247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.print(" waiting="); writer.println(mTask.waiting);
352247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
353247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mCancellingTask != null) {
354247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask);
355247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.print(" waiting="); writer.println(mCancellingTask.waiting);
356247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
357247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        if (mUpdateThrottle != 0) {
358247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn            writer.print(prefix); writer.print("mUpdateThrottle=");
359247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    TimeUtils.formatDuration(mUpdateThrottle, writer);
360247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.print(" mLastLoadCompleteTime=");
361247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    TimeUtils.formatDuration(mLastLoadCompleteTime,
362247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                            SystemClock.uptimeMillis(), writer);
363247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn                    writer.println();
364247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        }
365247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
3669911b7f83db2e960f72345e6d50df2b77ca75e3fJeff Hamilton}
367