switch to alsa.omap3 module
[android_pandora.git] / apps / AndroidSupportV2 / src / android / support / v2 / content / Loader.java
1 /*
2  * Copyright (C) 2011 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 android.support.v2.content;
18
19 import android.content.Context;
20 import android.database.ContentObserver;
21 import android.os.Handler;
22 import android.support.v2.util.DebugUtils;
23
24 import java.io.FileDescriptor;
25 import java.io.PrintWriter;
26
27 /**
28  * Static library support version of the framework's {@link android.content.Loader}.
29  * Used to write apps that run on platforms prior to Android 3.0.  When running
30  * on Android 3.0 or above, this implementation is still used; it does not try
31  * to switch to the framework's implementation.  See the framework SDK
32  * documentation for a class overview.
33  */
34 public class Loader<D> {
35     int mId;
36     OnLoadCompleteListener<D> mListener;
37     Context mContext;
38     boolean mStarted = false;
39     boolean mAbandoned = false;
40     boolean mReset = true;
41     boolean mContentChanged = false;
42
43     public final class ForceLoadContentObserver extends ContentObserver {
44         public ForceLoadContentObserver() {
45             super(new Handler());
46         }
47
48         @Override
49         public boolean deliverSelfNotifications() {
50             return true;
51         }
52
53         @Override
54         public void onChange(boolean selfChange) {
55             onContentChanged();
56         }
57     }
58
59     public interface OnLoadCompleteListener<D> {
60         /**
61          * Called on the thread that created the Loader when the load is complete.
62          *
63          * @param loader the loader that completed the load
64          * @param data the result of the load
65          */
66         public void onLoadComplete(Loader<D> loader, D data);
67     }
68
69     /**
70      * Stores away the application context associated with context. Since Loaders can be used
71      * across multiple activities it's dangerous to store the context directly.
72      *
73      * @param context used to retrieve the application context.
74      */
75     public Loader(Context context) {
76         mContext = context.getApplicationContext();
77     }
78
79     /**
80      * Sends the result of the load to the registered listener. Should only be called by subclasses.
81      *
82      * Must be called from the process's main thread.
83      *
84      * @param data the result of the load
85      */
86     public void deliverResult(D data) {
87         if (mListener != null) {
88             mListener.onLoadComplete(this, data);
89         }
90     }
91
92     /**
93      * @return an application context retrieved from the Context passed to the constructor.
94      */
95     public Context getContext() {
96         return mContext;
97     }
98
99     /**
100      * @return the ID of this loader
101      */
102     public int getId() {
103         return mId;
104     }
105
106     /**
107      * Registers a class that will receive callbacks when a load is complete.
108      * The callback will be called on the process's main thread so it's safe to
109      * pass the results to widgets.
110      *
111      * <p>Must be called from the process's main thread.
112      */
113     public void registerListener(int id, OnLoadCompleteListener<D> listener) {
114         if (mListener != null) {
115             throw new IllegalStateException("There is already a listener registered");
116         }
117         mListener = listener;
118         mId = id;
119     }
120
121     /**
122      * Remove a listener that was previously added with {@link #registerListener}.
123      *
124      * Must be called from the process's main thread.
125      */
126     public void unregisterListener(OnLoadCompleteListener<D> listener) {
127         if (mListener == null) {
128             throw new IllegalStateException("No listener register");
129         }
130         if (mListener != listener) {
131             throw new IllegalArgumentException("Attempting to unregister the wrong listener");
132         }
133         mListener = null;
134     }
135
136     /**
137      * Return whether this load has been started.  That is, its {@link #startLoading()}
138      * has been called and no calls to {@link #stopLoading()} or
139      * {@link #reset()} have yet been made.
140      */
141     public boolean isStarted() {
142         return mStarted;
143     }
144
145     /**
146      * Return whether this loader has been abandoned.  In this state, the
147      * loader <em>must not</em> report any new data, and <em>must</em> keep
148      * its last reported data valid until it is finally reset.
149      */
150     public boolean isAbandoned() {
151         return mAbandoned;
152     }
153
154     /**
155      * Return whether this load has been reset.  That is, either the loader
156      * has not yet been started for the first time, or its {@link #reset()}
157      * has been called.
158      */
159     public boolean isReset() {
160         return mReset;
161     }
162
163     /**
164      * Starts an asynchronous load of the Loader's data. When the result
165      * is ready the callbacks will be called on the process's main thread.
166      * If a previous load has been completed and is still valid
167      * the result may be passed to the callbacks immediately.
168      * The loader will monitor the source of
169      * the data set and may deliver future callbacks if the source changes.
170      * Calling {@link #stopLoading} will stop the delivery of callbacks.
171      *
172      * <p>This updates the Loader's internal state so that
173      * {@link #isStarted()} and {@link #isReset()} will return the correct
174      * values, and then calls the implementation's {@link #onStartLoading()}.
175      *
176      * <p>Must be called from the process's main thread.
177      */
178     public final void startLoading() {
179         mStarted = true;
180         mReset = false;
181         mAbandoned = false;
182         onStartLoading();
183     }
184
185     /**
186      * Subclasses must implement this to take care of loading their data,
187      * as per {@link #startLoading()}.  This is not called by clients directly,
188      * but as a result of a call to {@link #startLoading()}.
189      */
190     protected void onStartLoading() {
191     }
192
193     /**
194      * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
195      * loaded data set and load a new one.  This simply calls through to the
196      * implementation's {@link #onForceLoad()}.  You generally should only call this
197      * when the loader is started -- that is, {@link #isStarted()} returns true.
198      *
199      * <p>Must be called from the process's main thread.
200      */
201     public void forceLoad() {
202         onForceLoad();
203     }
204
205     /**
206      * Subclasses must implement this to take care of requests to {@link #forceLoad()}.
207      * This will always be called from the process's main thread.
208      */
209     protected void onForceLoad() {
210     }
211
212     /**
213      * Stops delivery of updates until the next time {@link #startLoading()} is called.
214      * Implementations should <em>not</em> invalidate their data at this point --
215      * clients are still free to use the last data the loader reported.  They will,
216      * however, typically stop reporting new data if the data changes; they can
217      * still monitor for changes, but must not report them to the client until and
218      * if {@link #startLoading()} is later called.
219      *
220      * <p>This updates the Loader's internal state so that
221      * {@link #isStarted()} will return the correct
222      * value, and then calls the implementation's {@link #onStopLoading()}.
223      *
224      * <p>Must be called from the process's main thread.
225      */
226     public void stopLoading() {
227         mStarted = false;
228         onStopLoading();
229     }
230
231     /**
232      * Subclasses must implement this to take care of stopping their loader,
233      * as per {@link #stopLoading()}.  This is not called by clients directly,
234      * but as a result of a call to {@link #stopLoading()}.
235      * This will always be called from the process's main thread.
236      */
237     protected void onStopLoading() {
238     }
239
240     /**
241      * Tell the Loader that it is being abandoned.  This is called prior
242      * to {@link #reset} to have it retain its current data but not report
243      * any new data.
244      */
245     public void abandon() {
246         mAbandoned = true;
247         onAbandon();
248     }
249     
250     /**
251      * Subclasses implement this to take care of being abandoned.  This is
252      * an optional intermediate state prior to {@link #onReset()} -- it means that
253      * the client is no longer interested in any new data from the loader,
254      * so the loader must not report any further updates.  However, the
255      * loader <em>must</em> keep its last reported data valid until the final
256      * {@link #onReset()} happens.  You can retrieve the current abandoned
257      * state with {@link #isAbandoned}.
258      */
259     protected void onAbandon() {        
260     }
261     
262     /**
263      * Resets the state of the Loader.  The Loader should at this point free
264      * all of its resources, since it may never be called again; however, its
265      * {@link #startLoading()} may later be called at which point it must be
266      * able to start running again.
267      *
268      * <p>This updates the Loader's internal state so that
269      * {@link #isStarted()} and {@link #isReset()} will return the correct
270      * values, and then calls the implementation's {@link #onReset()}.
271      *
272      * <p>Must be called from the process's main thread.
273      */
274     public void reset() {
275         onReset();
276         mReset = true;
277         mStarted = false;
278         mAbandoned = false;
279         mContentChanged = false;
280     }
281
282     /**
283      * Subclasses must implement this to take care of resetting their loader,
284      * as per {@link #reset()}.  This is not called by clients directly,
285      * but as a result of a call to {@link #reset()}.
286      * This will always be called from the process's main thread.
287      */
288     protected void onReset() {
289     }
290
291     /**
292      * Take the current flag indicating whether the loader's content had
293      * changed while it was stopped.  If it had, true is returned and the
294      * flag is cleared.
295      */
296     public boolean takeContentChanged() {
297         boolean res = mContentChanged;
298         mContentChanged = false;
299         return res;
300     }
301     
302     /**
303      * Called when {@link ForceLoadContentObserver} detects a change.  The
304      * default implementation checks to see if the loader is currently started;
305      * if so, it simply calls {@link #forceLoad()}; otherwise, it sets a flag
306      * so that {@link #takeContentChanged()} returns true.
307      *
308      * <p>Must be called from the process's main thread.
309      */
310     public void onContentChanged() {
311         if (mStarted) {
312             forceLoad();
313         } else {
314             // This loader has been stopped, so we don't want to load
315             // new data right now...  but keep track of it changing to
316             // refresh later if we start again.
317             mContentChanged = true;
318         }
319     }
320
321     /**
322      * For debugging, converts an instance of the Loader's data class to
323      * a string that can be printed.  Must handle a null data.
324      */
325     public String dataToString(D data) {
326         StringBuilder sb = new StringBuilder(64);
327         DebugUtils.buildShortClassTag(data, sb);
328         sb.append("}");
329         return sb.toString();
330     }
331
332     @Override
333     public String toString() {
334         StringBuilder sb = new StringBuilder(64);
335         DebugUtils.buildShortClassTag(this, sb);
336         sb.append(" id=");
337         sb.append(mId);
338         sb.append("}");
339         return sb.toString();
340     }
341
342     /**
343      * Print the Loader's state into the given stream.
344      *
345      * @param prefix Text to print at the front of each line.
346      * @param fd The raw file descriptor that the dump is being sent to.
347      * @param writer A PrintWriter to which the dump is to be set.
348      * @param args Additional arguments to the dump request.
349      */
350     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
351         writer.print(prefix); writer.print("mId="); writer.print(mId);
352                 writer.print(" mListener="); writer.println(mListener);
353         writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
354                 writer.print(" mContentChanged="); writer.print(mContentChanged);
355                 writer.print(" mAbandoned="); writer.print(mAbandoned);
356                 writer.print(" mReset="); writer.println(mReset);
357     }
358 }