diff options
author | Svetoslav <svetoslavganov@google.com> | 2014-05-15 10:47:19 -0700 |
---|---|---|
committer | svetoslavganov <svetoslavganov@google.com> | 2014-06-06 13:33:16 -0700 |
commit | a798c0a984f29f7180883a61839f68d2cbf0c6ce (patch) | |
tree | 4e0c54dbc67f45dd3b5a243399a28a0ed0a00ed7 /core/java/android/print/PrintManager.java | |
parent | 67a0ed001dbd59cd58992508e386f6eb6fefe7ed (diff) | |
download | frameworks_base-a798c0a984f29f7180883a61839f68d2cbf0c6ce.zip frameworks_base-a798c0a984f29f7180883a61839f68d2cbf0c6ce.tar.gz frameworks_base-a798c0a984f29f7180883a61839f68d2cbf0c6ce.tar.bz2 |
Refactor printing
Change-Id: I19850154ef2798afff511e4490a268ce38e8cbae
Diffstat (limited to 'core/java/android/print/PrintManager.java')
-rw-r--r-- | core/java/android/print/PrintManager.java | 566 |
1 files changed, 261 insertions, 305 deletions
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index 811751d..9361286 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -24,6 +24,7 @@ import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; +import android.os.ICancellationSignal; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -41,6 +42,7 @@ import libcore.io.IoUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -50,12 +52,12 @@ import java.util.Map; * <p> * To obtain a handle to the print manager do the following: * </p> - * + * * <pre> * PrintManager printManager = * (PrintManager) context.getSystemService(Context.PRINT_SERVICE); * </pre> - * + * * <h3>Print mechanics</h3> * <p> * The key idea behind printing on the platform is that the content to be printed @@ -344,7 +346,7 @@ public final class PrintManager { try { mService.cancelPrintJob(printJobId, mAppId, mUserId); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error cancleing a print job: " + printJobId, re); + Log.e(LOG_TAG, "Error canceling a print job: " + printJobId, re); } } @@ -505,30 +507,17 @@ public final class PrintManager { private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub implements ActivityLifecycleCallbacks { - private final Object mLock = new Object(); - private CancellationSignal mLayoutOrWriteCancellation; - - private Activity mActivity; // Strong reference OK - cleared in finish() - - private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish + private Activity mActivity; // Strong reference OK - cleared in destroy - private Handler mHandler; // Strong reference OK - cleared in finish() + private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in destroy - private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in finish + private Handler mHandler; // Strong reference OK - cleared in destroy - private LayoutSpec mLastLayoutSpec; + private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in destroy - private WriteSpec mLastWriteSpec; - - private boolean mStartReqeusted; - private boolean mStarted; - - private boolean mFinishRequested; - private boolean mFinished; - - private boolean mDestroyed; + private DestroyableCallback mPendingCallback; public PrintDocumentAdapterDelegate(Activity activity, PrintDocumentAdapter documentAdapter) { @@ -542,11 +531,10 @@ public final class PrintManager { public void setObserver(IPrintDocumentAdapterObserver observer) { final boolean destroyed; synchronized (mLock) { - if (!mDestroyed) { - mObserver = observer; - } - destroyed = mDestroyed; + mObserver = observer; + destroyed = isDestroyedLocked(); } + if (destroyed) { try { observer.onDestroy(); @@ -559,126 +547,89 @@ public final class PrintManager { @Override public void start() { synchronized (mLock) { - // Started called or finish called or destroyed - nothing to do. - if (mStartReqeusted || mFinishRequested || mDestroyed) { - return; + // If destroyed the handler is null. + if (!isDestroyedLocked()) { + mHandler.obtainMessage(MyHandler.MSG_ON_START, + mDocumentAdapter).sendToTarget(); } - - mStartReqeusted = true; - - doPendingWorkLocked(); } } @Override public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes, ILayoutResultCallback callback, Bundle metadata, int sequence) { - final boolean destroyed; - synchronized (mLock) { - destroyed = mDestroyed; - // If start called and not finished called and not destroyed - do some work. - if (mStartReqeusted && !mFinishRequested && !mDestroyed) { - // 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(); - } + ICancellationSignal cancellationTransport = CancellationSignal.createTransport(); + try { + callback.onLayoutStarted(cancellationTransport, sequence); + } catch (RemoteException re) { + // The spooler is dead - can't recover. + Log.e(LOG_TAG, "Error notifying for layout start", re); + return; } - if (destroyed) { - try { - callback.onLayoutFailed(null, sequence); - } catch (RemoteException re) { - Log.i(LOG_TAG, "Error notifying for cancelled layout", re); + + synchronized (mLock) { + // If destroyed the handler is null. + if (isDestroyedLocked()) { + return; } + + CancellationSignal cancellationSignal = CancellationSignal.fromTransport( + cancellationTransport); + + SomeArgs args = SomeArgs.obtain(); + args.arg1 = mDocumentAdapter; + args.arg2 = oldAttributes; + args.arg3 = newAttributes; + args.arg4 = cancellationSignal; + args.arg5 = new MyLayoutResultCallback(callback, sequence); + args.arg6 = metadata; + + mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT, args).sendToTarget(); } } @Override public void write(PageRange[] pages, ParcelFileDescriptor fd, IWriteResultCallback callback, int sequence) { - final boolean destroyed; - synchronized (mLock) { - destroyed = mDestroyed; - // If start called and not finished called and not destroyed - do some work. - if (mStartReqeusted && !mFinishRequested && !mDestroyed) { - // 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(); - } - } - if (destroyed) { - try { - callback.onWriteFailed(null, sequence); - } catch (RemoteException re) { - Log.i(LOG_TAG, "Error notifying for cancelled write", re); - } + ICancellationSignal cancellationTransport = CancellationSignal.createTransport(); + try { + callback.onWriteStarted(cancellationTransport, sequence); + } catch (RemoteException re) { + // The spooler is dead - can't recover. + Log.e(LOG_TAG, "Error notifying for write start", re); + return; } - } - @Override - public void finish() { synchronized (mLock) { - // Start not called or finish called or destroyed - nothing to do. - if (!mStartReqeusted || mFinishRequested || mDestroyed) { + // If destroyed the handler is null. + if (isDestroyedLocked()) { return; } - mFinishRequested = true; + CancellationSignal cancellationSignal = CancellationSignal.fromTransport( + cancellationTransport); - // 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; - } + SomeArgs args = SomeArgs.obtain(); + args.arg1 = mDocumentAdapter; + args.arg2 = pages; + args.arg3 = fd; + args.arg4 = cancellationSignal; + args.arg5 = new MyWriteResultCallback(callback, fd, sequence); - doPendingWorkLocked(); + mHandler.obtainMessage(MyHandler.MSG_ON_WRITE, args).sendToTarget(); } } @Override - public void cancel() { - // Start not called or finish called or destroyed - nothing to do. - if (!mStartReqeusted || mFinishRequested || mDestroyed) { - return; - } - // Request cancellation of pending work if needed. + public void finish() { synchronized (mLock) { - cancelPreviousCancellableOperationLocked(); + // If destroyed the handler is null. + if (!isDestroyedLocked()) { + mHandler.obtainMessage(MyHandler.MSG_ON_FINISH, + mDocumentAdapter).sendToTarget(); + } } } @@ -719,20 +670,14 @@ public final class PrintManager { // Note the the spooler has a death recipient that observes if // this process gets killed so we cover the case of onDestroy not // being called due to this process being killed to reclaim memory. - final IPrintDocumentAdapterObserver observer; + IPrintDocumentAdapterObserver observer = null; synchronized (mLock) { if (activity == mActivity) { - mDestroyed = true; observer = mObserver; - clearLocked(); - } else { - observer = null; - activity = null; + destroyLocked(); } } if (observer != null) { - activity.getApplication().unregisterActivityLifecycleCallbacks( - PrintDocumentAdapterDelegate.this); try { observer.onDestroy(); } catch (RemoteException re) { @@ -741,67 +686,39 @@ public final class PrintManager { } } - private boolean isFinished() { - return mDocumentAdapter == null; + private boolean isDestroyedLocked() { + return (mActivity == null); } - private void clearLocked() { + private void destroyLocked() { + mActivity.getApplication().unregisterActivityLifecycleCallbacks( + PrintDocumentAdapterDelegate.this); mActivity = null; + mDocumentAdapter = null; + + // This method is only called from the main thread, so + // clearing the messages guarantees that any time a + // message is handled we are not in a destroyed state. + mHandler.removeMessages(MyHandler.MSG_ON_START); + mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT); + mHandler.removeMessages(MyHandler.MSG_ON_WRITE); + mHandler.removeMessages(MyHandler.MSG_ON_FINISH); mHandler = null; - mLayoutOrWriteCancellation = null; - mLastLayoutSpec = null; - if (mLastWriteSpec != null) { - IoUtils.closeQuietly(mLastWriteSpec.fd); - mLastWriteSpec = null; - } - } - private boolean cancelPreviousCancellableOperationLocked() { - if (mLayoutOrWriteCancellation != null) { - mLayoutOrWriteCancellation.cancel(); - if (DEBUG) { - Log.i(LOG_TAG, "Cancelling previous operation"); - } - return true; - } - return false; - } + mObserver = null; - 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); + if (mPendingCallback != null) { + mPendingCallback.destroy(); + mPendingCallback = null; } } - 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 { - public static final int MSG_START = 1; - public static final int MSG_LAYOUT = 2; - public static final int MSG_WRITE = 3; - public static final int MSG_FINISH = 4; + public static final int MSG_ON_START = 1; + public static final int MSG_ON_LAYOUT = 2; + public static final int MSG_ON_WRITE = 3; + public static final int MSG_ON_FINISH = 4; public MyHandler(Looper looper) { super(looper, null, true); @@ -809,84 +726,71 @@ public final class PrintManager { @Override public void handleMessage(Message message) { - if (isFinished()) { - return; - } switch (message.what) { - case MSG_START: { - final PrintDocumentAdapter adapter; - synchronized (mLock) { - adapter = mDocumentAdapter; - } - if (adapter != null) { - adapter.onStart(); + case MSG_ON_START: { + if (DEBUG) { + Log.i(LOG_TAG, "onStart()"); } + + ((PrintDocumentAdapter) message.obj).onStart(); } break; - case MSG_LAYOUT: { - final PrintDocumentAdapter adapter; - final CancellationSignal cancellation; - final LayoutSpec layoutSpec; + case MSG_ON_LAYOUT: { + SomeArgs args = (SomeArgs) message.obj; + PrintDocumentAdapter adapter = (PrintDocumentAdapter) args.arg1; + PrintAttributes oldAttributes = (PrintAttributes) args.arg2; + PrintAttributes newAttributes = (PrintAttributes) args.arg3; + CancellationSignal cancellation = (CancellationSignal) args.arg4; + LayoutResultCallback callback = (LayoutResultCallback) args.arg5; + Bundle metadata = (Bundle) args.arg6; + args.recycle(); - synchronized (mLock) { - adapter = mDocumentAdapter; - layoutSpec = mLastLayoutSpec; - mLastLayoutSpec = null; - cancellation = new CancellationSignal(); - mLayoutOrWriteCancellation = cancellation; + if (DEBUG) { + StringBuilder builder = new StringBuilder(); + builder.append("PrintDocumentAdapter#onLayout() {\n"); + builder.append("\n oldAttributes:").append(oldAttributes); + builder.append("\n newAttributes:").append(newAttributes); + builder.append("\n preview:").append(metadata.getBoolean( + PrintDocumentAdapter.EXTRA_PRINT_PREVIEW)); + builder.append("\n}"); + Log.i(LOG_TAG, builder.toString()); } - if (layoutSpec != null && adapter != null) { - if (DEBUG) { - Log.i(LOG_TAG, "Performing layout"); - } - adapter.onLayout(layoutSpec.oldAttributes, - layoutSpec.newAttributes, cancellation, - new MyLayoutResultCallback(layoutSpec.callback, - layoutSpec.sequence), layoutSpec.metadata); - } + adapter.onLayout(oldAttributes, newAttributes, cancellation, + callback, metadata); } break; - case MSG_WRITE: { - final PrintDocumentAdapter adapter; - final CancellationSignal cancellation; - final WriteSpec writeSpec; + case MSG_ON_WRITE: { + SomeArgs args = (SomeArgs) message.obj; + PrintDocumentAdapter adapter = (PrintDocumentAdapter) args.arg1; + PageRange[] pages = (PageRange[]) args.arg2; + ParcelFileDescriptor fd = (ParcelFileDescriptor) args.arg3; + CancellationSignal cancellation = (CancellationSignal) args.arg4; + WriteResultCallback callback = (WriteResultCallback) args.arg5; + args.recycle(); - synchronized (mLock) { - adapter = mDocumentAdapter; - writeSpec = mLastWriteSpec; - mLastWriteSpec = null; - cancellation = new CancellationSignal(); - mLayoutOrWriteCancellation = cancellation; + if (DEBUG) { + StringBuilder builder = new StringBuilder(); + builder.append("PrintDocumentAdapter#onWrite() {\n"); + builder.append("\n pages:").append(Arrays.toString(pages)); + builder.append("\n}"); + Log.i(LOG_TAG, builder.toString()); } - if (writeSpec != null && adapter != null) { - if (DEBUG) { - Log.i(LOG_TAG, "Performing write"); - } - adapter.onWrite(writeSpec.pages, writeSpec.fd, - cancellation, new MyWriteResultCallback(writeSpec.callback, - writeSpec.fd, writeSpec.sequence)); - } + adapter.onWrite(pages, fd, cancellation, callback); } break; - case MSG_FINISH: { + case MSG_ON_FINISH: { if (DEBUG) { - Log.i(LOG_TAG, "Performing finish"); + Log.i(LOG_TAG, "onFinish()"); } - final PrintDocumentAdapter adapter; - final Activity activity; + + ((PrintDocumentAdapter) message.obj).onFinish(); + + // Done printing, so destroy this instance as it + // should not be used anymore. synchronized (mLock) { - adapter = mDocumentAdapter; - activity = mActivity; - clearLocked(); - } - if (adapter != null) { - adapter.onFinish(); - } - if (activity != null) { - activity.getApplication().unregisterActivityLifecycleCallbacks( - PrintDocumentAdapterDelegate.this); + destroyLocked(); } } break; @@ -898,7 +802,12 @@ public final class PrintManager { } } - private final class MyLayoutResultCallback extends LayoutResultCallback { + private interface DestroyableCallback { + public void destroy(); + } + + private final class MyLayoutResultCallback extends LayoutResultCallback + implements DestroyableCallback { private ILayoutResultCallback mCallback; private final int mSequence; @@ -910,25 +819,31 @@ public final class PrintManager { @Override public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { - if (info == null) { - throw new NullPointerException("document info cannot be null"); - } final ILayoutResultCallback callback; synchronized (mLock) { - if (mDestroyed) { - Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " - + "finish the printing activity before print completion?"); - return; - } callback = mCallback; - clearLocked(); } - if (callback != null) { + + // If the callback is null we are destroyed. + if (callback == null) { + Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " + + "finish the printing activity before print completion " + + "or did you invoke a callback after finish?"); + return; + } + + try { + if (info == null) { + throw new NullPointerException("document info cannot be null"); + } + try { callback.onLayoutFinished(info, changed, mSequence); } catch (RemoteException re) { Log.e(LOG_TAG, "Error calling onLayoutFinished", re); } + } finally { + destroy(); } } @@ -936,46 +851,64 @@ public final class PrintManager { public void onLayoutFailed(CharSequence error) { final ILayoutResultCallback callback; synchronized (mLock) { - if (mDestroyed) { - Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " - + "finish the printing activity before print completion?"); - return; - } callback = mCallback; - clearLocked(); } - if (callback != null) { - try { - callback.onLayoutFailed(error, mSequence); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onLayoutFailed", re); - } + + // If the callback is null we are destroyed. + if (callback == null) { + Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " + + "finish the printing activity before print completion " + + "or did you invoke a callback after finish?"); + return; + } + + try { + callback.onLayoutFailed(error, mSequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onLayoutFailed", re); + } finally { + destroy(); } } @Override public void onLayoutCancelled() { + final ILayoutResultCallback callback; synchronized (mLock) { - if (mDestroyed) { - Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " - + "finish the printing activity before print completion?"); - return; - } - clearLocked(); + callback = mCallback; + } + + // If the callback is null we are destroyed. + if (callback == null) { + Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " + + "finish the printing activity before print completion " + + "or did you invoke a callback after finish?"); + return; + } + + try { + callback.onLayoutCanceled(mSequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onLayoutFailed", re); + } finally { + destroy(); } } - private void clearLocked() { - mLayoutOrWriteCancellation = null; - mCallback = null; - doPendingWorkLocked(); + @Override + public void destroy() { + synchronized (mLock) { + mCallback = null; + mPendingCallback = null; + } } } - private final class MyWriteResultCallback extends WriteResultCallback { + private final class MyWriteResultCallback extends WriteResultCallback + implements DestroyableCallback { private ParcelFileDescriptor mFd; - private int mSequence; private IWriteResultCallback mCallback; + private final int mSequence; public MyWriteResultCallback(IWriteResultCallback callback, ParcelFileDescriptor fd, int sequence) { @@ -988,26 +921,32 @@ public final class PrintManager { public void onWriteFinished(PageRange[] pages) { final IWriteResultCallback callback; synchronized (mLock) { - if (mDestroyed) { - Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " - + "finish the printing activity before print completion?"); - return; - } callback = mCallback; - clearLocked(); - } - if (pages == null) { - throw new IllegalArgumentException("pages cannot be null"); } - if (pages.length == 0) { - throw new IllegalArgumentException("pages cannot be empty"); + + // If the callback is null we are destroyed. + if (callback == null) { + Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " + + "finish the printing activity before print completion " + + "or did you invoke a callback after finish?"); + return; } - if (callback != null) { + + try { + if (pages == null) { + throw new IllegalArgumentException("pages cannot be null"); + } + if (pages.length == 0) { + throw new IllegalArgumentException("pages cannot be empty"); + } + try { callback.onWriteFinished(pages, mSequence); } catch (RemoteException re) { Log.e(LOG_TAG, "Error calling onWriteFinished", re); } + } finally { + destroy(); } } @@ -1015,41 +954,58 @@ public final class PrintManager { public void onWriteFailed(CharSequence error) { final IWriteResultCallback callback; synchronized (mLock) { - if (mDestroyed) { - Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " - + "finish the printing activity before print completion?"); - return; - } callback = mCallback; - clearLocked(); } - if (callback != null) { - try { - callback.onWriteFailed(error, mSequence); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onWriteFailed", re); - } + + // If the callback is null we are destroyed. + if (callback == null) { + Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " + + "finish the printing activity before print completion " + + "or did you invoke a callback after finish?"); + return; + } + + try { + callback.onWriteFailed(error, mSequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onWriteFailed", re); + } finally { + destroy(); } } @Override public void onWriteCancelled() { + final IWriteResultCallback callback; synchronized (mLock) { - if (mDestroyed) { - Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " - + "finish the printing activity before print completion?"); - return; - } - clearLocked(); + callback = mCallback; + } + + // If the callback is null we are destroyed. + if (callback == null) { + Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you " + + "finish the printing activity before print completion " + + "or did you invoke a callback after finish?"); + return; + } + + try { + callback.onWriteCanceled(mSequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onWriteCanceled", re); + } finally { + destroy(); } } - private void clearLocked() { - mLayoutOrWriteCancellation = null; - IoUtils.closeQuietly(mFd); - mCallback = null; - mFd = null; - doPendingWorkLocked(); + @Override + public void destroy() { + synchronized (mLock) { + IoUtils.closeQuietly(mFd); + mCallback = null; + mFd = null; + mPendingCallback = null; + } } } } |