diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2013-07-24 17:00:06 -0700 |
---|---|---|
committer | Svetoslav Ganov <svetoslavganov@google.com> | 2013-07-30 17:15:11 -0700 |
commit | 85b1f883056a1d74473fd9ce774948878f389ab6 (patch) | |
tree | 7417d396a98766611636e0123102154f60726737 /core | |
parent | 0d1daa50f6d180c57f92596501e2e5c0b5ef9997 (diff) | |
download | frameworks_base-85b1f883056a1d74473fd9ce774948878f389ab6.zip frameworks_base-85b1f883056a1d74473fd9ce774948878f389ab6.tar.gz frameworks_base-85b1f883056a1d74473fd9ce774948878f389ab6.tar.bz2 |
Iteration on the print sub-system.
1. API changes: Moved copies API from PrintAttributes to PrintJobInfo;
Changed the PageRange list to an array in PrintDocumentAdapter#onWrite;
Added onCancelled method to the layout and write callbacks.
2. Refactored the serialization of remote layout and write commands. Now
the commands are serialized by the code in the client instead in the spooler.
The benefit is simple code since the client has to do a serialization to delegate
to the main thread anyway. The increased IPC found is fine since these calls
are quite unfrequent.
3. Removed an unused file: IPrintSpoolerObserver.aidl
4. Added equals and hasCode implementation to PageRange, PrintAttributes,
MediaSize, Resolution, Margins, Tray, PrintDocumentInfo.
5. Added shortcut path for query APIs on PrintJob that return cached values
if the print job is in a uncuttable state, i.e. completed or cancelled. Failed
print jobs can be restarted.
6. PrintJobInfo was not properly serialized.
7. Updated the look of the print dialog to be stable if there is and there isn't
currently selected printer.
8. PrintJobCOnfigActivity now calls onLayout on every print attributes change
but requests a write only on print preview or print button press. Also if the
layout did not change the content and it is already written no subsequent
call is made. Also if the selected pages change and we already have them
no subsequent call to write is made. Also the app is called with print preview
attribute set when performing layout and with it cleared after the print button
is pressed. A lot of changes making sure that only valid actions are enabled
in the activity (looks like a dialog) at a given time frame. The print job config
activity is also hidden after we got all the data, i.e. layout and write are done.
9. The callback from the print spooler to the system are scheduled via messages
to avoid lock being held during the call. It was hard to guarantee that since a
method holding a lock may be calling one that would like to release the lock
at some point to make the callbacks.
10. Print spooler state is persisted only if something changes in a completed
print job, i.e. not one that is being constructed due the print job config dialog.
11. Fixed a potential race in the RemotePrintSpooler where it was possible that
a client that got a handle to the remote spooler calls into an unbound spooler.
E.g: the client gets the remote interface with a lock held, now the client releases
the lock to avoid IPC with a lock, during the IPC scheduling the spooler has
notified the system that it is done and the system unbinds from it, now the
client's IPC is made to a spooler that is disconnected.
Change-Id: Ie9c42255940a27ecaed21a4d326a663a4788ac9d
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/print/FileDocumentAdapter.java | 8 | ||||
-rw-r--r-- | core/java/android/print/ILayoutResultCallback.aidl | 6 | ||||
-rw-r--r-- | core/java/android/print/IPrintDocumentAdapter.aidl | 6 | ||||
-rw-r--r-- | core/java/android/print/IPrintManager.aidl | 1 | ||||
-rw-r--r-- | core/java/android/print/IPrintSpoolerCallbacks.aidl | 2 | ||||
-rw-r--r-- | core/java/android/print/IPrintSpoolerObserver.aidl | 31 | ||||
-rw-r--r-- | core/java/android/print/IWriteResultCallback.aidl | 6 | ||||
-rw-r--r-- | core/java/android/print/PageRange.java | 32 | ||||
-rw-r--r-- | core/java/android/print/PrintAttributes.java | 295 | ||||
-rw-r--r-- | core/java/android/print/PrintDocumentAdapter.java | 30 | ||||
-rw-r--r-- | core/java/android/print/PrintDocumentInfo.java | 30 | ||||
-rw-r--r-- | core/java/android/print/PrintJob.java | 13 | ||||
-rw-r--r-- | core/java/android/print/PrintJobInfo.java | 42 | ||||
-rw-r--r-- | core/java/android/print/PrintManager.java | 216 | ||||
-rw-r--r-- | core/java/android/print/PrinterInfo.java | 5 | ||||
-rw-r--r-- | core/java/android/printservice/PrintJob.java | 12 |
16 files changed, 520 insertions, 215 deletions
diff --git a/core/java/android/print/FileDocumentAdapter.java b/core/java/android/print/FileDocumentAdapter.java index c7011f4..d642a61 100644 --- a/core/java/android/print/FileDocumentAdapter.java +++ b/core/java/android/print/FileDocumentAdapter.java @@ -34,8 +34,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; /** * Adapter for printing files. @@ -69,7 +67,7 @@ final class FileDocumentAdapter extends PrintDocumentAdapter { } @Override - public void onWrite(List<PageRange> pages, FileDescriptor destination, + public void onWrite(PageRange[] pages, FileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback); mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, @@ -127,9 +125,7 @@ final class FileDocumentAdapter extends PrintDocumentAdapter { @Override protected void onPostExecute(Void result) { - List<PageRange> pages = new ArrayList<PageRange>(); - pages.add(PageRange.ALL_PAGES); - mResultCallback.onWriteFinished(pages); + mResultCallback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES}); } @Override diff --git a/core/java/android/print/ILayoutResultCallback.aidl b/core/java/android/print/ILayoutResultCallback.aidl index e4d79f3..43b8c30 100644 --- a/core/java/android/print/ILayoutResultCallback.aidl +++ b/core/java/android/print/ILayoutResultCallback.aidl @@ -16,7 +16,6 @@ package android.print; -import android.os.ICancellationSignal; import android.print.PrintDocumentInfo; /** @@ -25,7 +24,6 @@ import android.print.PrintDocumentInfo; * @hide */ oneway interface ILayoutResultCallback { - void onLayoutStarted(ICancellationSignal cancellationSignal); - void onLayoutFinished(in PrintDocumentInfo info, boolean changed); - void onLayoutFailed(CharSequence error); + void onLayoutFinished(in PrintDocumentInfo info, boolean changed, int sequence); + void onLayoutFailed(CharSequence error, int sequence); } diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl index 04da157..b12c922 100644 --- a/core/java/android/print/IPrintDocumentAdapter.aidl +++ b/core/java/android/print/IPrintDocumentAdapter.aidl @@ -31,8 +31,8 @@ import android.print.PrintAttributes; oneway interface IPrintDocumentAdapter { void start(); void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes, - ILayoutResultCallback callback, in Bundle metadata); - void write(in List<PageRange> pages, in ParcelFileDescriptor fd, - IWriteResultCallback callback); + ILayoutResultCallback callback, in Bundle metadata, int sequence); + void write(in PageRange[] pages, in ParcelFileDescriptor fd, + IWriteResultCallback callback, int sequence); void finish(); } diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl index a466e74..37ae2ca 100644 --- a/core/java/android/print/IPrintManager.aidl +++ b/core/java/android/print/IPrintManager.aidl @@ -33,5 +33,4 @@ interface IPrintManager { in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes, int appId, int userId); void cancelPrintJob(int printJobId, int appId, int userId); - } diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl index 7912964..51b5439 100644 --- a/core/java/android/print/IPrintSpoolerCallbacks.aidl +++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl @@ -28,9 +28,9 @@ import java.util.List; */ oneway interface IPrintSpoolerCallbacks { void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence); - void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence); void onCreatePrintJobResult(in PrintJobInfo printJob, int sequence); void onCancelPrintJobResult(boolean canceled, int sequence); void onSetPrintJobStateResult(boolean success, int sequence); void onSetPrintJobTagResult(boolean success, int sequence); + void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence); } diff --git a/core/java/android/print/IPrintSpoolerObserver.aidl b/core/java/android/print/IPrintSpoolerObserver.aidl deleted file mode 100644 index 7b8f40e..0000000 --- a/core/java/android/print/IPrintSpoolerObserver.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.print; - -import android.print.PrinterId; -import android.print.PrinterInfo; - -/** - * Interface for observing the state of the print spooler. - * - * @hide - */ -oneway interface IPrinterDiscoveryObserver { - void onPrintJobQueued(in PrinterId printerId, in PrintJobInfo printJob); - void onAllPrintJobsHandled(in ComponentName printService); - void onAllPrintJobsHandled(); -} diff --git a/core/java/android/print/IWriteResultCallback.aidl b/core/java/android/print/IWriteResultCallback.aidl index d5428b1..8281c4e 100644 --- a/core/java/android/print/IWriteResultCallback.aidl +++ b/core/java/android/print/IWriteResultCallback.aidl @@ -16,7 +16,6 @@ package android.print; -import android.os.ICancellationSignal; import android.print.PageRange; /** @@ -25,7 +24,6 @@ import android.print.PageRange; * @hide */ oneway interface IWriteResultCallback { - void onWriteStarted(ICancellationSignal cancellationSignal); - void onWriteFinished(in List<PageRange> pages); - void onWriteFailed(CharSequence error); + void onWriteFinished(in PageRange[] pages, int sequence); + void onWriteFailed(CharSequence error, int sequence); } diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java index 9257a04..ba455f6 100644 --- a/core/java/android/print/PageRange.java +++ b/core/java/android/print/PageRange.java @@ -93,8 +93,38 @@ public final class PageRange implements Parcelable { } @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + mEnd; + result = prime * result + mStart; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PageRange other = (PageRange) obj; + if (mEnd != other.mEnd) { + return false; + } + if (mStart != other.mStart) { + return false; + } + return true; + } + + @Override public String toString() { - if (this == ALL_PAGES) { + if (mStart == 0 && mEnd == Integer.MAX_VALUE) { return "PageRange[<all pages>]"; } StringBuilder builder = new StringBuilder(); diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java index 87d75c0..911e380 100644 --- a/core/java/android/print/PrintAttributes.java +++ b/core/java/android/print/PrintAttributes.java @@ -77,7 +77,6 @@ public final class PrintAttributes implements Parcelable { private int mColorMode; private int mFittingMode; private int mOrientation; - private int mCopies; PrintAttributes() { /* hide constructor */ @@ -93,7 +92,6 @@ public final class PrintAttributes implements Parcelable { mColorMode = parcel.readInt(); mFittingMode = parcel.readInt(); mOrientation = parcel.readInt(); - mCopies = parcel.readInt(); } /** @@ -302,29 +300,6 @@ public final class PrintAttributes implements Parcelable { mOrientation = orientation; } - /** - * Gets the number of copies. - * - * @return The number of copies or zero if not set. - */ - public int getCopies() { - return mCopies; - } - - /** - * Sets the number of copies. - * - * @param copyCount The number of copies. - * - * @hide - */ - public void setCopies(int copyCount) { - if (copyCount < 1) { - throw new IllegalArgumentException("Copies must be more than one."); - } - mCopies = copyCount; - } - @Override public void writeToParcel(Parcel parcel, int flags) { if (mMediaSize != null) { @@ -361,7 +336,6 @@ public final class PrintAttributes implements Parcelable { parcel.writeInt(mColorMode); parcel.writeInt(mFittingMode); parcel.writeInt(mOrientation); - parcel.writeInt(mCopies); } @Override @@ -369,6 +343,101 @@ public final class PrintAttributes implements Parcelable { return 0; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + mColorMode; + result = prime * result + mDuplexMode; + result = prime * result + mFittingMode; + result = prime * result + mOrientation; + result = prime * result + ((mInputTray == null) ? 0 : mInputTray.hashCode()); + result = prime * result + ((mMargins == null) ? 0 : mMargins.hashCode()); + result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode()); + result = prime * result + ((mOutputTray == null) ? 0 : mOutputTray.hashCode()); + result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PrintAttributes other = (PrintAttributes) obj; + if (mColorMode != other.mColorMode) { + return false; + } + if (mDuplexMode != other.mDuplexMode) { + return false; + } + if (mFittingMode != other.mFittingMode) { + return false; + } + if (mOrientation != other.mOrientation) { + return false; + } + if (mInputTray == null) { + if (other.mInputTray != null) { + return false; + } + } else if (!mInputTray.equals(other.mInputTray)) { + return false; + } + if (mOutputTray == null) { + if (other.mOutputTray != null) { + return false; + } + } else if (!mOutputTray.equals(other.mOutputTray)) { + return false; + } + if (mMargins == null) { + if (other.mMargins != null) { + return false; + } + } else if (!mMargins.equals(other.mMargins)) { + return false; + } + if (mMediaSize == null) { + if (other.mMediaSize != null) { + return false; + } + } else if (!mMediaSize.equals(other.mMediaSize)) { + return false; + } + if (mResolution == null) { + if (other.mResolution != null) { + return false; + } + } else if (!mResolution.equals(other.mResolution)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PrintAttributes{"); + builder.append("mediaSize: ").append(mMediaSize); + builder.append(", resolution: ").append(mResolution); + builder.append(", margins: ").append(mMargins); + builder.append(", inputTray: ").append(mInputTray); + builder.append(", outputTray: ").append(mOutputTray); + builder.append(", colorMode: ").append(colorModeToString(mColorMode)); + builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode)); + builder.append(", fittingMode: ").append(fittingModeToString(mFittingMode)); + builder.append(", orientation: ").append(orientationToString(mOrientation)); + builder.append("}"); + return builder.toString(); + } + /** hide */ public void clear() { mMediaSize = null; @@ -380,7 +449,6 @@ public final class PrintAttributes implements Parcelable { mColorMode = 0; mFittingMode = 0; mOrientation = 0; - mCopies = 0; } /** @@ -396,7 +464,6 @@ public final class PrintAttributes implements Parcelable { mColorMode = other.mColorMode; mFittingMode = other.mFittingMode; mOrientation = other.mOrientation; - mCopies = other.mCopies; } /** @@ -954,6 +1021,44 @@ public final class PrintAttributes implements Parcelable { } @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mId == null) ? 0 : mId.hashCode()); + result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode()); + result = prime * result + mWidthMils; + result = prime * result + mHeightMils; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MediaSize other = (MediaSize) obj; + if (!TextUtils.equals(mId, other.mId)) { + return false; + } + if (!TextUtils.equals(mLabel, other.mLabel)) { + return false; + } + if (mWidthMils != other.mWidthMils) { + return false; + } + if (mHeightMils != other.mHeightMils) { + return false; + } + return true; + } + + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("MediaSize{"); @@ -1061,6 +1166,44 @@ public final class PrintAttributes implements Parcelable { } @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mId == null) ? 0 : mId.hashCode()); + result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode()); + result = prime * result + mHorizontalDpi; + result = prime * result + mVerticalDpi; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Resolution other = (Resolution) obj; + if (!TextUtils.equals(mId, other.mId)) { + return false; + } + if (!TextUtils.equals(mLabel, other.mLabel)) { + return false; + } + if (mHorizontalDpi != other.mHorizontalDpi) { + return false; + } + if (mVerticalDpi != other.mVerticalDpi) { + return false; + } + return true; + } + + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Resolution{"); @@ -1166,6 +1309,44 @@ public final class PrintAttributes implements Parcelable { } @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + mBottomMils; + result = prime * result + mLeftMils; + result = prime * result + mRightMils; + result = prime * result + mTopMils; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Margins other = (Margins) obj; + if (mBottomMils != other.mBottomMils) { + return false; + } + if (mLeftMils != other.mLeftMils) { + return false; + } + if (mRightMils != other.mRightMils) { + return false; + } + if (mTopMils != other.mTopMils) { + return false; + } + return true; + } + + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Margins{"); @@ -1235,6 +1416,36 @@ public final class PrintAttributes implements Parcelable { } @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mId == null) ? 0 : mId.hashCode()); + result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Tray other = (Tray) obj; + if (!TextUtils.equals(mId, other.mId)) { + return false; + } + if (!TextUtils.equals(mLabel, other.mLabel)) { + return false; + } + return true; + } + + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Tray{"); @@ -1246,21 +1457,6 @@ public final class PrintAttributes implements Parcelable { } } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("PrintAttributes{"); - builder.append("mediaSize: ").append(mMediaSize); - builder.append(", resolution: ").append(mResolution); - builder.append(", margins: ").append(mMargins); - builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode)); - builder.append(", colorMode: ").append(colorModeToString(mColorMode)); - builder.append(", fittingMode: ").append(fittingModeToString(mFittingMode)); - builder.append(", orientation: ").append(orientationToString(mOrientation)); - builder.append(", copies: ").append(mCopies); - return builder.toString(); - } - private static String duplexModeToString(int duplexMode) { switch (duplexMode) { case DUPLEX_MODE_NONE: { @@ -1412,7 +1608,7 @@ public final class PrintAttributes implements Parcelable { * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE */ public Builder setDuplexMode(int duplexMode) { - if (Integer.bitCount(duplexMode) != 1) { + if (Integer.bitCount(duplexMode) > 1) { throw new IllegalArgumentException("can specify at most one duplexMode bit."); } mAttributes.setDuplexMode(duplexMode); @@ -1471,17 +1667,6 @@ public final class PrintAttributes implements Parcelable { } /** - * Sets the number of copies. - * - * @param copyCount A greater or equal to zero copy count. - * @return This builder. - */ - public Builder setCopyCount(int copyCount) { - mAttributes.setCopies(copyCount); - return this; - } - - /** * Creates a new {@link PrintAttributes} instance. * * @return The new instance. diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java index 1f83a45..d320226 100644 --- a/core/java/android/print/PrintDocumentAdapter.java +++ b/core/java/android/print/PrintDocumentAdapter.java @@ -41,7 +41,7 @@ import java.util.List; * <li> * After every call to {@link #onLayout(PrintAttributes, PrintAttributes, * CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to - * {@link #onWrite(List, FileDescriptor, CancellationSignal, WriteResultCallback)} + * {@link #onWrite(PageRange[], FileDescriptor, CancellationSignal, WriteResultCallback)} * asking you to write a PDF file with the content for specific pages. * </li> * <li> @@ -64,7 +64,7 @@ import java.util.List; * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on * the UI thread (assuming onStart initializes resources needed for layout). * This will ensure that the UI does not change while you are laying out the - * printed content. Then you can handle {@link #onWrite(List, FileDescriptor, + * printed content. Then you can handle {@link #onWrite(PageRange[], FileDescriptor, * CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another * thread. This will ensure that the UI is frozen for the minimal amount of * time. Also this assumes that you will generate the printed content in @@ -141,7 +141,7 @@ public abstract class PrintDocumentAdapter { * made on the main thread. * </p> * - * @param pages The pages whose content to print. + * @param pages The pages whose content to print - non-overlapping in ascending order. * @param destination The destination file descriptor to which to write. * @param cancellationSignal Signal for observing cancel writing requests. * @param callback Callback to inform the system for the write result. @@ -149,7 +149,7 @@ public abstract class PrintDocumentAdapter { * @see WriteResultCallback * @see CancellationSignal */ - public abstract void onWrite(List<PageRange> pages, FileDescriptor destination, + public abstract void onWrite(PageRange[] pages, FileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback); /** @@ -163,7 +163,7 @@ public abstract class PrintDocumentAdapter { /** * Base class for implementing a callback for the result of {@link - * PrintDocumentAdapter#onWrite(List, FileDescriptor, CancellationSignal, + * PrintDocumentAdapter#onWrite(PageRange[], FileDescriptor, CancellationSignal, * WriteResultCallback)}. */ public static abstract class WriteResultCallback { @@ -178,9 +178,9 @@ public abstract class PrintDocumentAdapter { /** * Notifies that all the data was written. * - * @param pages The pages that were written. + * @param pages The pages that were written. Cannot be null or empty. */ - public void onWriteFinished(List<PageRange> pages) { + public void onWriteFinished(PageRange[] pages) { /* do nothing - stub */ } @@ -192,6 +192,13 @@ public abstract class PrintDocumentAdapter { public void onWriteFailed(CharSequence error) { /* do nothing - stub */ } + + /** + * Notifies that write was cancelled as a result of a cancellation request. + */ + public void onWriteCancelled() { + /* do nothing - stub */ + } } /** @@ -211,7 +218,7 @@ public abstract class PrintDocumentAdapter { /** * Notifies that the layout finished and whether the content changed. * - * @param info An info object describing the document. + * @param info An info object describing the document. Cannot be null. * @param changed Whether the layout changed. * * @see PrintDocumentInfo @@ -228,5 +235,12 @@ public abstract class PrintDocumentAdapter { public void onLayoutFailed(CharSequence error) { /* do nothing - stub */ } + + /** + * Notifies that layout was cancelled as a result of a cancellation request. + */ + public void onLayoutCancelled() { + /* do nothing - stub */ + } } } diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java index 7d42b3a..29e8e7c 100644 --- a/core/java/android/print/PrintDocumentInfo.java +++ b/core/java/android/print/PrintDocumentInfo.java @@ -111,6 +111,36 @@ public final class PrintDocumentInfo implements Parcelable { } @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + mContentType; + result = prime * result + mPageCount; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PrintDocumentInfo other = (PrintDocumentInfo) obj; + if (mContentType != other.mContentType) { + return false; + } + if (mPageCount != other.mPageCount) { + return false; + } + return true; + } + + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("PrintDocumentInfo{"); diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java index a5e0b79..de28bd3 100644 --- a/core/java/android/print/PrintJob.java +++ b/core/java/android/print/PrintJob.java @@ -55,6 +55,9 @@ public final class PrintJob { * @return The print job info. */ public PrintJobInfo getInfo() { + if (isInImmutableState()) { + return mCachedInfo; + } PrintJobInfo info = mPrintManager.getPrintJobInfo(mId); if (info != null) { mCachedInfo = info; @@ -66,7 +69,15 @@ public final class PrintJob { * Cancels this print job. */ public void cancel() { - mPrintManager.cancelPrintJob(mId); + if (!isInImmutableState()) { + mPrintManager.cancelPrintJob(mId); + } + } + + private boolean isInImmutableState() { + final int state = mCachedInfo.getState(); + return state == PrintJobInfo.STATE_COMPLETED + || state == PrintJobInfo.STATE_CANCELED; } @Override diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java index 97384d9..39546f3 100644 --- a/core/java/android/print/PrintJobInfo.java +++ b/core/java/android/print/PrintJobInfo.java @@ -19,6 +19,8 @@ package android.print; import android.os.Parcel; import android.os.Parcelable; +import java.util.Arrays; + /** * This class represents the description of a print job. */ @@ -119,6 +121,9 @@ public final class PrintJobInfo implements Parcelable { /** Optional tag assigned by a print service.*/ private String mTag; + /** How many copies to print. */ + private int mCopies; + /** The pages to print */ private PageRange[] mPageRanges; @@ -142,6 +147,8 @@ public final class PrintJobInfo implements Parcelable { mAppId = other.mAppId; mUserId = other.mUserId; mTag = other.mTag; + mCopies = other.mCopies; + mPageRanges = other.mPageRanges; mAttributes = other.mAttributes; mDocumentInfo = other.mDocumentInfo; } @@ -154,8 +161,13 @@ public final class PrintJobInfo implements Parcelable { mAppId = parcel.readInt(); mUserId = parcel.readInt(); mTag = parcel.readString(); + mCopies = parcel.readInt(); if (parcel.readInt() == 1) { - mPageRanges = (PageRange[]) parcel.readParcelableArray(null); + Parcelable[] parcelables = parcel.readParcelableArray(null); + mPageRanges = new PageRange[parcelables.length]; + for (int i = 0; i < parcelables.length; i++) { + mPageRanges[i] = (PageRange) parcelables[i]; + } } if (parcel.readInt() == 1) { mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel); @@ -310,6 +322,29 @@ public final class PrintJobInfo implements Parcelable { } /** + * Gets the number of copies. + * + * @return The number of copies or zero if not set. + */ + public int getCopies() { + return mCopies; + } + + /** + * Sets the number of copies. + * + * @param copyCount The number of copies. + * + * @hide + */ + public void setCopies(int copyCount) { + if (copyCount < 1) { + throw new IllegalArgumentException("Copies must be more than one."); + } + mCopies = copyCount; + } + + /** * Gets the included pages. * * @return The included pages or <code>null</code> if not set. @@ -385,6 +420,7 @@ public final class PrintJobInfo implements Parcelable { parcel.writeInt(mAppId); parcel.writeInt(mUserId); parcel.writeString(mTag); + parcel.writeInt(mCopies); if (mPageRanges != null) { parcel.writeInt(1); parcel.writeParcelableArray(mPageRanges, flags); @@ -413,10 +449,14 @@ public final class PrintJobInfo implements Parcelable { builder.append(", id: ").append(mId); builder.append(", status: ").append(stateToString(mState)); builder.append(", printer: " + mPrinterId); + builder.append(", tag: ").append(mTag); + builder.append(", copies: ").append(mCopies); builder.append(", attributes: " + (mAttributes != null ? mAttributes.toString() : null)); builder.append(", documentInfo: " + (mDocumentInfo != null ? mDocumentInfo.toString() : null)); + builder.append(", pages: " + (mPageRanges != null + ? Arrays.toString(mPageRanges) : null)); builder.append("}"); return builder.toString(); } diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index f9f53f6..9e8cfad 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -22,7 +22,6 @@ 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; @@ -223,6 +222,11 @@ public final class PrintManager { } private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub { + + private final Object mLock = new Object(); + + private CancellationSignal mLayoutOrWriteCancellation; + private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish() private Handler mHandler; // Strong reference OK - cleared in finish() @@ -239,22 +243,36 @@ public final class PrintManager { @Override public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes, - ILayoutResultCallback callback, Bundle metadata) { + ILayoutResultCallback callback, Bundle metadata, int sequence) { + synchronized (mLock) { + if (mLayoutOrWriteCancellation != null) { + mLayoutOrWriteCancellation.cancel(); + } + } 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(List<PageRange> pages, ParcelFileDescriptor fd, - IWriteResultCallback callback) { + public void write(PageRange[] pages, ParcelFileDescriptor fd, + IWriteResultCallback callback, int sequence) { + synchronized (mLock) { + if (mLayoutOrWriteCancellation != null) { + mLayoutOrWriteCancellation.cancel(); + } + } SomeArgs args = SomeArgs.obtain(); args.arg1 = pages; args.arg2 = fd.getFileDescriptor(); args.arg3 = callback; + args.argi1 = sequence; + mHandler.removeMessages(MyHandler.MSG_WRITE); mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget(); } @@ -283,7 +301,6 @@ public final class PrintManager { } @Override - @SuppressWarnings("unchecked") public void handleMessage(Message message) { if (isFinished()) { return; @@ -295,42 +312,116 @@ public final class PrintManager { 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 PrintAttributes oldAttributes = (PrintAttributes) args.arg1; + final PrintAttributes newAttributes = (PrintAttributes) args.arg2; + final ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3; + final Bundle metadata = (Bundle) args.arg4; + final int sequence = args.argi1; args.recycle(); - try { - ICancellationSignal remoteSignal = CancellationSignal.createTransport(); - callback.onLayoutStarted(remoteSignal); - - mDocumentAdapter.onLayout(oldAttributes, newAttributes, - CancellationSignal.fromTransport(remoteSignal), - new LayoutResultCallbackWrapper(callback), metadata); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error printing", re); + CancellationSignal cancellation = new CancellationSignal(); + synchronized (mLock) { + mLayoutOrWriteCancellation = cancellation; } + + mDocumentAdapter.onLayout(oldAttributes, newAttributes, + cancellation, new LayoutResultCallback() { + @Override + public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { + if (info == null) { + throw new IllegalArgumentException("info cannot be null"); + } + synchronized (mLock) { + mLayoutOrWriteCancellation = null; + } + try { + callback.onLayoutFinished(info, changed, sequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onLayoutFinished", re); + } + } + + @Override + public void onLayoutFailed(CharSequence error) { + synchronized (mLock) { + mLayoutOrWriteCancellation = null; + } + try { + callback.onLayoutFailed(error, sequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onLayoutFailed", re); + } + } + + @Override + public void onLayoutCancelled() { + synchronized (mLock) { + mLayoutOrWriteCancellation = null; + } + } + }, metadata); } break; case MSG_WRITE: { SomeArgs args = (SomeArgs) message.obj; - List<PageRange> pages = (List<PageRange>) args.arg1; - FileDescriptor fd = (FileDescriptor) args.arg2; - IWriteResultCallback callback = (IWriteResultCallback) args.arg3; + final PageRange[] pages = (PageRange[]) args.arg1; + final FileDescriptor fd = (FileDescriptor) args.arg2; + final IWriteResultCallback callback = (IWriteResultCallback) args.arg3; + final int sequence = args.argi1; args.recycle(); - try { - ICancellationSignal remoteSignal = CancellationSignal.createTransport(); - callback.onWriteStarted(remoteSignal); - - mDocumentAdapter.onWrite(pages, fd, - CancellationSignal.fromTransport(remoteSignal), - new WriteResultCallbackWrapper(callback, fd)); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error printing", re); - IoUtils.closeQuietly(fd); + CancellationSignal cancellation = new CancellationSignal(); + synchronized (mLock) { + mLayoutOrWriteCancellation = cancellation; } + + mDocumentAdapter.onWrite(pages, fd, cancellation, + new WriteResultCallback() { + @Override + public void onWriteFinished(PageRange[] pages) { + if (pages == null) { + throw new IllegalArgumentException("pages cannot be null"); + } + if (pages.length == 0) { + throw new IllegalArgumentException("pages cannot be empty"); + } + synchronized (mLock) { + mLayoutOrWriteCancellation = null; + } + // Close before notifying the other end. We want + // to be ready by the time we announce it. + IoUtils.closeQuietly(fd); + try { + callback.onWriteFinished(pages, sequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onWriteFinished", re); + } + } + + @Override + public void onWriteFailed(CharSequence error) { + synchronized (mLock) { + mLayoutOrWriteCancellation = null; + } + // Close before notifying the other end. We want + // to be ready by the time we announce it. + IoUtils.closeQuietly(fd); + try { + callback.onWriteFailed(error, sequence); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onWriteFailed", re); + } + } + + @Override + public void onWriteCancelled() { + synchronized (mLock) { + mLayoutOrWriteCancellation = null; + } + // Just close the fd for now. + IoUtils.closeQuietly(fd); + } + }); } break; case MSG_FINISH: { @@ -346,67 +437,4 @@ public final class PrintManager { } } } - - private static final class WriteResultCallbackWrapper extends WriteResultCallback { - - private final IWriteResultCallback mWrappedCallback; - private final FileDescriptor mFd; - - public WriteResultCallbackWrapper(IWriteResultCallback callback, - FileDescriptor fd) { - mWrappedCallback = callback; - mFd = fd; - } - - @Override - public void onWriteFinished(List<PageRange> pages) { - try { - // Close before notifying the other end. We want - // to be ready by the time we announce it. - IoUtils.closeQuietly(mFd); - mWrappedCallback.onWriteFinished(pages); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onWriteFinished", re); - } - } - - @Override - public void onWriteFailed(CharSequence error) { - try { - // Close before notifying the other end. We want - // to be ready by the time we announce it. - IoUtils.closeQuietly(mFd); - mWrappedCallback.onWriteFailed(error); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onWriteFailed", re); - } - } - } - - private static final class LayoutResultCallbackWrapper extends LayoutResultCallback { - - private final ILayoutResultCallback mWrappedCallback; - - public LayoutResultCallbackWrapper(ILayoutResultCallback callback) { - mWrappedCallback = callback; - } - - @Override - public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { - try { - mWrappedCallback.onLayoutFinished(info, changed); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onLayoutFinished", re); - } - } - - @Override - public void onLayoutFailed(CharSequence error) { - try { - mWrappedCallback.onLayoutFailed(error); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onLayoutFailed", re); - } - } - } } diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java index da3b6bc..c0daa6e 100644 --- a/core/java/android/print/PrinterInfo.java +++ b/core/java/android/print/PrinterInfo.java @@ -41,8 +41,6 @@ public final class PrinterInfo implements Parcelable { */ public static final int DEFAULT_UNDEFINED = -1; - private static final int MIN_COPIES = 1; - private static final int PROPERTY_MEDIA_SIZE = 0; private static final int PROPERTY_RESOLUTION = 1; private static final int PROPERTY_INPUT_TRAY = 2; @@ -240,9 +238,6 @@ public final class PrinterInfo implements Parcelable { public void getDefaults(PrintAttributes outAttributes) { outAttributes.clear(); - // TODO: Do we want a printer to specify default copies? - outAttributes.setCopies(MIN_COPIES); - outAttributes.setMargins(mDefaultMargins); final int mediaSizeIndex = mDefaults.get(PROPERTY_MEDIA_SIZE); diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java index 80530a7..0ac5a13 100644 --- a/core/java/android/printservice/PrintJob.java +++ b/core/java/android/printservice/PrintJob.java @@ -61,6 +61,9 @@ public final class PrintJob { * @return The print job info. */ public PrintJobInfo getInfo() { + if (isInImmutableState()) { + return mCachedInfo; + } PrintJobInfo info = null; try { info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId()); @@ -182,6 +185,9 @@ public final class PrintJob { * @return True if the tag was set, false otherwise. */ public boolean setTag(String tag) { + if (isInImmutableState()) { + return false; + } try { return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag); } catch (RemoteException re) { @@ -210,6 +216,12 @@ public final class PrintJob { return mCachedInfo.getId(); } + private boolean isInImmutableState() { + final int state = mCachedInfo.getState(); + return state == PrintJobInfo.STATE_COMPLETED + || state == PrintJobInfo.STATE_CANCELED; + } + private boolean setState(int state) { try { if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state)) { |