Merge "Fix a bug where we could lose a loader content change." into jb-mr2-dev
diff --git a/api/current.txt b/api/current.txt
index 1668170..f4407b5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6159,6 +6159,7 @@
     ctor public Loader(android.content.Context);
     method public void abandon();
     method public boolean cancelLoad();
+    method public void commitContentChanged();
     method public java.lang.String dataToString(D);
     method public void deliverCancellation();
     method public void deliverResult(D);
@@ -6179,6 +6180,7 @@
     method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
     method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
     method public void reset();
+    method public void rollbackContentChanged();
     method public final void startLoading();
     method public void stopLoading();
     method public boolean takeContentChanged();
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 188c786..612c67f 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -231,6 +231,7 @@
         onCanceled(data);
         if (mCancellingTask == task) {
             if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
+            rollbackContentChanged();
             mLastLoadCompleteTime = SystemClock.uptimeMillis();
             mCancellingTask = null;
             if (DEBUG) Slog.v(TAG, "Delivering cancellation");
@@ -248,6 +249,7 @@
                 // This cursor has been abandoned; just cancel the new data.
                 onCanceled(data);
             } else {
+                commitContentChanged();
                 mLastLoadCompleteTime = SystemClock.uptimeMillis();
                 mTask = null;
                 if (DEBUG) Slog.v(TAG, "Delivering result");
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 3052414..911e49c 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -58,6 +58,7 @@
     boolean mAbandoned = false;
     boolean mReset = true;
     boolean mContentChanged = false;
+    boolean mProcessingChange = false;
 
     /**
      * An implementation of a ContentObserver that takes care of connecting
@@ -439,6 +440,7 @@
         mStarted = false;
         mAbandoned = false;
         mContentChanged = false;
+        mProcessingChange = false;
     }
 
     /**
@@ -458,9 +460,34 @@
     public boolean takeContentChanged() {
         boolean res = mContentChanged;
         mContentChanged = false;
+        mProcessingChange |= res;
         return res;
     }
-    
+
+    /**
+     * Commit that you have actually fully processed a content change that
+     * was returned by {@link #takeContentChanged}.  This is for use with
+     * {@link #rollbackContentChanged()} to handle situations where a load
+     * is cancelled.  Call this when you have completely processed a load
+     * without it being cancelled.
+     */
+    public void commitContentChanged() {
+        mProcessingChange = false;
+    }
+
+    /**
+     * Report that you have abandoned the processing of a content change that
+     * was returned by {@link #takeContentChanged()} and would like to rollback
+     * to the state where there is again a pending content change.  This is
+     * to handle the case where a data load due to a content change has been
+     * canceled before its data was delivered back to the loader.
+     */
+    public void rollbackContentChanged() {
+        if (mProcessingChange) {
+            mContentChanged = true;
+        }
+    }
+
     /**
      * Called when {@link ForceLoadContentObserver} detects a change.  The
      * default implementation checks to see if the loader is currently started;
@@ -512,9 +539,14 @@
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         writer.print(prefix); writer.print("mId="); writer.print(mId);
                 writer.print(" mListener="); writer.println(mListener);
-        writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
-                writer.print(" mContentChanged="); writer.print(mContentChanged);
-                writer.print(" mAbandoned="); writer.print(mAbandoned);
-                writer.print(" mReset="); writer.println(mReset);
+        if (mStarted || mContentChanged || mProcessingChange) {
+            writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
+                    writer.print(" mContentChanged="); writer.print(mContentChanged);
+                    writer.print(" mProcessingChange="); writer.println(mProcessingChange);
+        }
+        if (mAbandoned || mReset) {
+            writer.print(prefix); writer.print("mAbandoned="); writer.print(mAbandoned);
+                    writer.print(" mReset="); writer.println(mReset);
+        }
     }
 }
\ No newline at end of file