am b02b14b2: am ef4a6f86: Merge "Do not do a layout and write while a cancellation is in progress." into klp-dev

* commit 'b02b14b21e46c531ae726094413f036ae36c56f9':
  Do not do a layout and write while a cancellation is in progress.
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 0859fdd..9c7c1fe 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -57,6 +57,8 @@
 
     private static final String LOG_TAG = "PrintManager";
 
+    private static final boolean DEBUG = false;
+
     /** @hide */
     public static final int APP_ID_ANY = -2;
 
@@ -350,6 +352,16 @@
 
         private Handler mHandler; // Strong reference OK - cleared in finish()
 
+        private LayoutSpec mLastLayoutSpec;
+
+        private WriteSpec mLastWriteSpec;
+
+        private boolean mStartReqeusted;
+        private boolean mStarted;
+
+        private boolean mFinishRequested;
+        private boolean mFinished;
+
         public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
             mDocumentAdapter = documentAdapter;
             mHandler = new MyHandler(looper);
@@ -357,47 +369,102 @@
 
         @Override
         public void start() {
-            mHandler.sendEmptyMessage(MyHandler.MSG_START);
+            synchronized (mLock) {
+                // Started or finished - nothing to do.
+                if (mStartReqeusted || mFinishRequested) {
+                    return;
+                }
+
+                mStartReqeusted = true;
+
+                doPendingWorkLocked();
+            }
         }
 
         @Override
         public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
                 ILayoutResultCallback callback, Bundle metadata, int sequence) {
             synchronized (mLock) {
-                if (mLayoutOrWriteCancellation != null) {
-                    mLayoutOrWriteCancellation.cancel();
+                // Start not called or finish called - nothing to do.
+                if (!mStartReqeusted || mFinishRequested) {
+                    return;
                 }
+
+                // Layout cancels write and overrides layout.
+                if (mLastWriteSpec != null) {
+                    IoUtils.closeQuietly(mLastWriteSpec.fd);
+                    mLastWriteSpec = null;
+                }
+
+                mLastLayoutSpec = new LayoutSpec();
+                mLastLayoutSpec.callback = callback;
+                mLastLayoutSpec.oldAttributes = oldAttributes;
+                mLastLayoutSpec.newAttributes = newAttributes;
+                mLastLayoutSpec.metadata = metadata;
+                mLastLayoutSpec.sequence = sequence;
+
+                // Cancel the previous cancellable operation.When the
+                // cancellation completes we will do the pending work.
+                if (cancelPreviousCancellableOperationLocked()) {
+                    return;
+                }
+
+                doPendingWorkLocked();
             }
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = oldAttributes;
-            args.arg2 = newAttributes;
-            args.arg3 = callback;
-            args.arg4 = metadata;
-            args.argi1 = sequence;
-            mHandler.removeMessages(MyHandler.MSG_LAYOUT);
-            mHandler.obtainMessage(MyHandler.MSG_LAYOUT, args).sendToTarget();
         }
 
         @Override
         public void write(PageRange[] pages, ParcelFileDescriptor fd,
                 IWriteResultCallback callback, int sequence) {
             synchronized (mLock) {
-                if (mLayoutOrWriteCancellation != null) {
-                    mLayoutOrWriteCancellation.cancel();
+                // Start not called or finish called - nothing to do.
+                if (!mStartReqeusted || mFinishRequested) {
+                    return;
                 }
+
+                // Write cancels previous writes.
+                if (mLastWriteSpec != null) {
+                    IoUtils.closeQuietly(mLastWriteSpec.fd);
+                    mLastWriteSpec = null;
+                }
+
+                mLastWriteSpec = new WriteSpec();
+                mLastWriteSpec.callback = callback;
+                mLastWriteSpec.pages = pages;
+                mLastWriteSpec.fd = fd;
+                mLastWriteSpec.sequence = sequence;
+
+                // Cancel the previous cancellable operation.When the
+                // cancellation completes we will do the pending work.
+                if (cancelPreviousCancellableOperationLocked()) {
+                    return;
+                }
+
+                doPendingWorkLocked();
             }
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = pages;
-            args.arg2 = fd;
-            args.arg3 = callback;
-            args.argi1 = sequence;
-            mHandler.removeMessages(MyHandler.MSG_WRITE);
-            mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget();
         }
 
         @Override
         public void finish() {
-            mHandler.sendEmptyMessage(MyHandler.MSG_FINISH);
+            synchronized (mLock) {
+                // Start not called or finish called - nothing to do.
+                if (!mStartReqeusted || mFinishRequested) {
+                    return;
+                }
+
+                mFinishRequested = true;
+
+                // When the current write or layout complete we
+                // will do the pending work.
+                if (mLastLayoutSpec != null || mLastWriteSpec != null) {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Waiting for current operation");
+                    }
+                    return;
+                }
+
+                doPendingWorkLocked();
+            }
         }
 
         private boolean isFinished() {
@@ -407,7 +474,49 @@
         private void doFinish() {
             mDocumentAdapter = null;
             mHandler = null;
-            mLayoutOrWriteCancellation = null;
+            synchronized (mLock) {
+                mLayoutOrWriteCancellation = null;
+            }
+        }
+
+        private boolean cancelPreviousCancellableOperationLocked() {
+            if (mLayoutOrWriteCancellation != null) {
+                mLayoutOrWriteCancellation.cancel();
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Cancelling previous operation");
+                }
+                return true;
+            }
+            return false;
+        }
+
+        private void doPendingWorkLocked() {
+            if (mStartReqeusted && !mStarted) {
+                mStarted = true;
+                mHandler.sendEmptyMessage(MyHandler.MSG_START);
+            } else if (mLastLayoutSpec != null) {
+                mHandler.sendEmptyMessage(MyHandler.MSG_LAYOUT);
+            } else if (mLastWriteSpec != null) {
+                mHandler.sendEmptyMessage(MyHandler.MSG_WRITE);
+            } else if (mFinishRequested && !mFinished) {
+                mFinished = true;
+                mHandler.sendEmptyMessage(MyHandler.MSG_FINISH);
+            }
+        }
+
+        private class LayoutSpec {
+            ILayoutResultCallback callback;
+            PrintAttributes oldAttributes;
+            PrintAttributes newAttributes;
+            Bundle metadata;
+            int sequence;
+        }
+
+        private class WriteSpec {
+            IWriteResultCallback callback;
+            PageRange[] pages;
+            ParcelFileDescriptor fd;
+            int sequence;
         }
 
         private final class MyHandler extends Handler {
@@ -431,41 +540,52 @@
                     } break;
 
                     case MSG_LAYOUT: {
-                        SomeArgs args = (SomeArgs) message.obj;
-                        PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
-                        PrintAttributes newAttributes = (PrintAttributes) args.arg2;
-                        ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
-                        Bundle metadata = (Bundle) args.arg4;
-                        final int sequence = args.argi1;
-                        args.recycle();
+                        final CancellationSignal cancellation;
+                        final LayoutSpec layoutSpec;
 
-                        CancellationSignal cancellation = new CancellationSignal();
                         synchronized (mLock) {
+                            layoutSpec = mLastLayoutSpec;
+                            mLastLayoutSpec = null;
+                            cancellation = new CancellationSignal();
                             mLayoutOrWriteCancellation = cancellation;
                         }
 
-                        mDocumentAdapter.onLayout(oldAttributes, newAttributes, cancellation,
-                                new MyLayoutResultCallback(callback, sequence), metadata);
+                        if (layoutSpec != null) {
+                            if (DEBUG) {
+                                Log.i(LOG_TAG, "Performing layout");
+                            }
+                            mDocumentAdapter.onLayout(layoutSpec.oldAttributes,
+                                    layoutSpec.newAttributes, cancellation,
+                                    new MyLayoutResultCallback(layoutSpec.callback,
+                                            layoutSpec.sequence), layoutSpec.metadata);
+                        }
                     } break;
 
                     case MSG_WRITE: {
-                        SomeArgs args = (SomeArgs) message.obj;
-                        PageRange[] pages = (PageRange[]) args.arg1;
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args.arg2;
-                        IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
-                        final int sequence = args.argi1;
-                        args.recycle();
+                        final CancellationSignal cancellation;
+                        final WriteSpec writeSpec;
 
-                        CancellationSignal cancellation = new CancellationSignal();
                         synchronized (mLock) {
+                            writeSpec= mLastWriteSpec;
+                            mLastWriteSpec = null;
+                            cancellation = new CancellationSignal();
                             mLayoutOrWriteCancellation = cancellation;
                         }
 
-                        mDocumentAdapter.onWrite(pages, fd, cancellation,
-                                new MyWriteResultCallback(callback, fd, sequence));
+                        if (writeSpec != null) {
+                            if (DEBUG) {
+                                Log.i(LOG_TAG, "Performing write");
+                            }
+                            mDocumentAdapter.onWrite(writeSpec.pages, writeSpec.fd,
+                                    cancellation, new MyWriteResultCallback(writeSpec.callback,
+                                            writeSpec.fd, writeSpec.sequence));
+                        }
                     } break;
 
                     case MSG_FINISH: {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Performing finish");
+                        }
                         mDocumentAdapter.onFinish();
                         doFinish();
                     } break;
@@ -533,6 +653,7 @@
             private void clearLocked() {
                 mLayoutOrWriteCancellation = null;
                 mCallback = null;
+                doPendingWorkLocked();
             }
         }
 
@@ -598,6 +719,7 @@
                 IoUtils.closeQuietly(mFd);
                 mCallback = null;
                 mFd = null;
+                doPendingWorkLocked();
             }
         }
     }