diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2013-10-07 14:31:18 -0700 |
---|---|---|
committer | Svetoslav Ganov <svetoslavganov@google.com> | 2013-10-07 17:13:01 -0700 |
commit | db63677c7c02cad7c25627533e5add5ed46870f8 (patch) | |
tree | 2833bbf954a77eaac35c3b06d54eec5cf80c5f0a /core/java/android/print/PrintManager.java | |
parent | 9470cd95dcf691eec33839065948bd32aab06fc6 (diff) | |
download | frameworks_base-db63677c7c02cad7c25627533e5add5ed46870f8.zip frameworks_base-db63677c7c02cad7c25627533e5add5ed46870f8.tar.gz frameworks_base-db63677c7c02cad7c25627533e5add5ed46870f8.tar.bz2 |
Do not do a layout and write while a cancellation is in progress.
While printing the app gets callbacks to do a layout and a write. Since
these operations can take a very long time they are implemented in a async
fashion. For example, if there is a layout request while we are still doing
a layout, we ask the application to cancel the previous layout. The problem
was that we were not waiting for the cancellation result before calling
the subsequent layout. Hence, the app ends up having to do two layouts at
the same time which breaks the printing contract. Same for write.
bug:11118426
Change-Id: If7b191c44387d88d5cec195d1785a47f986965ba
Diffstat (limited to 'core/java/android/print/PrintManager.java')
-rw-r--r-- | core/java/android/print/PrintManager.java | 208 |
1 files changed, 165 insertions, 43 deletions
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 @@ public final class PrintManager { 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 @@ public final class PrintManager { 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 @@ public final class PrintManager { @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 @@ public final class PrintManager { 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 @@ public final class PrintManager { } 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(); - - CancellationSignal cancellation = new CancellationSignal(); + final CancellationSignal cancellation; + final LayoutSpec layoutSpec; + 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(); - - CancellationSignal cancellation = new CancellationSignal(); + final CancellationSignal cancellation; + final WriteSpec writeSpec; + 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 @@ public final class PrintManager { private void clearLocked() { mLayoutOrWriteCancellation = null; mCallback = null; + doPendingWorkLocked(); } } @@ -598,6 +719,7 @@ public final class PrintManager { IoUtils.closeQuietly(mFd); mCallback = null; mFd = null; + doPendingWorkLocked(); } } } |