summaryrefslogtreecommitdiffstats
path: root/core/java/android/print
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/print')
-rw-r--r--core/java/android/print/IPrintDocumentAdapter.aidl3
-rw-r--r--core/java/android/print/IPrintDocumentAdapterObserver.aidl26
-rw-r--r--core/java/android/print/PageRange.java5
-rw-r--r--core/java/android/print/PrintAttributes.java59
-rw-r--r--core/java/android/print/PrintDocumentAdapter.java130
-rw-r--r--core/java/android/print/PrintDocumentInfo.java76
-rw-r--r--core/java/android/print/PrintJob.java12
-rw-r--r--core/java/android/print/PrintJobInfo.java138
-rw-r--r--core/java/android/print/PrintManager.java393
-rw-r--r--core/java/android/print/PrinterCapabilitiesInfo.java32
-rw-r--r--core/java/android/print/PrinterInfo.java23
-rw-r--r--core/java/android/print/package.html46
12 files changed, 758 insertions, 185 deletions
diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
index b12c922..2b95c12 100644
--- a/core/java/android/print/IPrintDocumentAdapter.aidl
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -19,6 +19,7 @@ package android.print;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.print.ILayoutResultCallback;
+import android.print.IPrintDocumentAdapterObserver;
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -29,10 +30,12 @@ import android.print.PrintAttributes;
* @hide
*/
oneway interface IPrintDocumentAdapter {
+ void setObserver(in IPrintDocumentAdapterObserver observer);
void start();
void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes,
ILayoutResultCallback callback, in Bundle metadata, int sequence);
void write(in PageRange[] pages, in ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence);
void finish();
+ void cancel();
}
diff --git a/core/java/android/print/IPrintDocumentAdapterObserver.aidl b/core/java/android/print/IPrintDocumentAdapterObserver.aidl
new file mode 100644
index 0000000..4443df0
--- /dev/null
+++ b/core/java/android/print/IPrintDocumentAdapterObserver.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Interface for observing the state of a print document adapter.
+ *
+ * @hide
+ */
+oneway interface IPrintDocumentAdapterObserver {
+ void onDestroy();
+}
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index cdcd0c7..d6320f0 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -39,9 +39,8 @@ public final class PageRange implements Parcelable {
* @param start The start page index (zero based and inclusive).
* @param end The end page index (zero based and inclusive).
*
- * @throws IllegalArgumentException If start is less than zero.
- * @throws IllegalArgumentException If end is less than zero.
- * @throws IllegalArgumentException If start greater than end.
+ * @throws IllegalArgumentException If start is less than zero or end
+ * is less than zero or start greater than end.
*/
public PageRange(int start, int end) {
if (start < 0) {
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e1a9cb7..c6254e0 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -30,7 +30,11 @@ import com.android.internal.R;
import java.util.Map;
/**
- * This class represents the attributes of a print job.
+ * This class represents the attributes of a print job. These attributes
+ * describe how the printed content should be laid out. For example, the
+ * print attributes may state that the content should be laid out on a
+ * letter size with 300 DPI (dots per inch) resolution, have a margin of
+ * 10 mills (thousand of an inch) on all sides, and be black and white.
*/
public final class PrintAttributes implements Parcelable {
/** Color mode: Monochrome color scheme, for example one color is used. */
@@ -277,7 +281,7 @@ public final class PrintAttributes implements Parcelable {
* Unknown media size in portrait mode.
* <p>
* <strong>Note: </strong>This is for specifying orientation without media
- * size. You should not use the dimensions reported by this class.
+ * size. You should not use the dimensions reported by this instance.
* </p>
*/
public static final MediaSize UNKNOWN_PORTRAIT =
@@ -288,7 +292,7 @@ public final class PrintAttributes implements Parcelable {
* Unknown media size in landscape mode.
* <p>
* <strong>Note: </strong>This is for specifying orientation without media
- * size. You should not use the dimensions reported by this class.
+ * size. You should not use the dimensions reported by this instance.
* </p>
*/
public static final MediaSize UNKNOWN_LANDSCAPE =
@@ -615,9 +619,7 @@ public final class PrintAttributes implements Parcelable {
private final int mHeightMils;
/**
- * Creates a new instance. This is the preferred constructor since
- * it enables the media size label to be shown in a localized fashion
- * on a locale change.
+ * Creates a new instance.
*
* @param id The unique media size id.
* @param packageName The name of the creating package.
@@ -625,10 +627,9 @@ public final class PrintAttributes implements Parcelable {
* @param widthMils The width in mils (thousands of an inch).
* @param heightMils The height in mils (thousands of an inch).
*
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
- * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+ * @throws IllegalArgumentException If the id is empty or the label
+ * is empty or the widthMils is less than or equal to zero or the
+ * heightMils is less than or equal to zero.
*
* @hide
*/
@@ -667,14 +668,13 @@ public final class PrintAttributes implements Parcelable {
*
* @param id The unique media size id. It is unique amongst other media sizes
* supported by the printer.
- * @param label The <strong>internationalized</strong> human readable label.
+ * @param label The <strong>localized</strong> human readable label.
* @param widthMils The width in mils (thousands of an inch).
* @param heightMils The height in mils (thousands of an inch).
*
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
- * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+ * @throws IllegalArgumentException If the id is empty or the label is empty
+ * or the widthMils is less than or equal to zero or the heightMils is less
+ * than or equal to zero.
*/
public MediaSize(String id, String label, int widthMils, int heightMils) {
if (TextUtils.isEmpty(id)) {
@@ -776,12 +776,16 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Returns a new media size in a portrait orientation
+ * Returns a new media size instance in a portrait orientation,
* which is the height is the greater dimension.
*
- * @return New instance in landscape orientation.
+ * @return New instance in landscape orientation if this one
+ * is in landscape, otherwise this instance.
*/
public MediaSize asPortrait() {
+ if (isPortrait()) {
+ return this;
+ }
return new MediaSize(mId, mLabel, mPackageName,
Math.min(mWidthMils, mHeightMils),
Math.max(mWidthMils, mHeightMils),
@@ -789,12 +793,16 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Returns a new media size in a landscape orientation
+ * Returns a new media size instance in a landscape orientation,
* which is the height is the lesser dimension.
*
- * @return New instance in landscape orientation.
+ * @return New instance in landscape orientation if this one
+ * is in portrait, otherwise this instance.
*/
public MediaSize asLandscape() {
+ if (!isPortrait()) {
+ return this;
+ }
return new MediaSize(mId, mLabel, mPackageName,
Math.max(mWidthMils, mHeightMils),
Math.min(mWidthMils, mHeightMils),
@@ -881,8 +889,8 @@ public final class PrintAttributes implements Parcelable {
* This class specifies a supported resolution in DPI (dots per inch).
* Resolution defines how many points with different color can be placed
* on one inch in horizontal or vertical direction of the target media.
- * For example, a printer with 600DIP can produce higher quality images
- * the one with 300DPI resolution.
+ * For example, a printer with 600 DPI can produce higher quality images
+ * the one with 300 DPI resolution.
*/
public static final class Resolution {
private final String mId;
@@ -895,14 +903,13 @@ public final class PrintAttributes implements Parcelable {
*
* @param id The unique resolution id. It is unique amongst other resolutions
* supported by the printer.
- * @param label The <strong>internationalized</strong> human readable label.
+ * @param label The <strong>localized</strong> human readable label.
* @param horizontalDpi The horizontal resolution in DPI (dots per inch).
* @param verticalDpi The vertical resolution in DPI (dots per inch).
*
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
- * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
+ * @throws IllegalArgumentException If the id is empty or the label is empty
+ * or the horizontalDpi is less than or equal to zero or the verticalDpi is
+ * less than or equal to zero.
*/
public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
if (TextUtils.isEmpty(id)) {
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 4113ac7..1f59bef 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -38,15 +38,46 @@ import android.os.ParcelFileDescriptor;
* </li>
* <li>
* After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
- * CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
- * {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal, WriteResultCallback)}
- * asking you to write a PDF file with the content for specific pages.
+ * CancellationSignal, LayoutResultCallback, Bundle)}, you <strong>may</strong> get
+ * a call to {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
+ * WriteResultCallback)} asking you to write a PDF file with the content for
+ * specific pages.
* </li>
* <li>
* Finally, you will receive a call to {@link #onFinish()}. You can use this
* callback to release resources allocated in {@link #onStart()}.
* </li>
* </ul>
+ * <p>
+ * The {@link #onStart()} callback is always the first call you will receive and
+ * is useful for doing one time setup or resource allocation before printing. You
+ * will not receive a subsequent call here.
+ * </p>
+ * <p>
+ * The {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)} callback requires that you layout the content
+ * based on the current {@link PrintAttributes}. The execution of this method is
+ * not considered completed until you invoke one of the methods on the passed in
+ * callback instance. Hence, you will not receive a subsequent call to any other
+ * method of this class until the execution of this method is complete by invoking
+ * one of the callback methods.
+ * </p>
+ * <p>
+ * The {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
+ * WriteResultCallback)} requires that you render and write the content of some
+ * pages to the provided destination. The execution of this method is not
+ * considered complete until you invoke one of the methods on the passed in
+ * callback instance. Hence, you will not receive a subsequent call to any other
+ * method of this class until the execution of this method is complete by invoking
+ * one of the callback methods. You will never receive a sequence of one or more
+ * calls to this method without a previous call to {@link #onLayout(PrintAttributes,
+ * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)}.
+ * </p>
+ * <p>
+ * The {@link #onFinish()} callback is always the last call you will receive and
+ * is useful for doing one time cleanup or resource deallocation after printing.
+ * You will not receive a subsequent call here.
+ * </p>
* </p>
* <h3>Implementation</h3>
* <p>
@@ -54,7 +85,11 @@ import android.os.ParcelFileDescriptor;
* of the work on an arbitrary thread. For example, if the printed content
* does not depend on the UI state, i.e. on what is shown on the screen, then
* you can offload the entire work on a dedicated thread, thus making your
- * application interactive while the print work is being performed.
+ * application interactive while the print work is being performed. Note that
+ * while your activity is covered by the system print UI and a user cannot
+ * interact with it, doing the printing work on the main application thread
+ * may affect the performance of your other application components as they
+ * are also executed on that thread.
* </p>
* <p>
* You can also do work on different threads, for example if you print UI
@@ -64,7 +99,7 @@ import android.os.ParcelFileDescriptor;
* This will ensure that the UI does not change while you are laying out the
* printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
* CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
- * thread. This will ensure that the UI is frozen for the minimal amount of
+ * thread. This will ensure that the main thread is busy for a minimal amount of
* time. Also this assumes that you will generate the printed content in
* {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
* LayoutResultCallback, Bundle)} which is not mandatory. If you use multiple
@@ -76,6 +111,12 @@ public abstract class PrintDocumentAdapter {
/**
* Extra: mapped to a boolean value that is <code>true</code> if
* the current layout is for a print preview, <code>false</code> otherwise.
+ * This extra is provided in the {@link Bundle} argument of the {@link
+ * #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)} callback.
+ *
+ * @see #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)
*/
public static final String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
@@ -95,17 +136,41 @@ public abstract class PrintDocumentAdapter {
* After you are done laying out, you <strong>must</strong> invoke: {@link
* LayoutResultCallback#onLayoutFinished(PrintDocumentInfo, boolean)} with
* the last argument <code>true</code> or <code>false</code> depending on
- * whether the layout changed the content or not, respectively; and {@link
- * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred.
- * Note that you must call one of the methods of the given callback.
+ * whether the layout changed the content or not, respectively; or {@link
+ * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred;
+ * or {@link LayoutResultCallback#onLayoutCancelled()} if layout was
+ * cancelled in a response to a cancellation request via the passed in
+ * {@link CancellationSignal}. Note that you <strong>must</strong> call one of
+ * the methods of the given callback for this method to be considered complete
+ * which is you will not receive any calls to this adapter until the current
+ * layout operation is complete by invoking a method on the callback instance.
+ * The callback methods can be invoked from an arbitrary thread.
+ * </p>
+ * <p>
+ * One of the arguments passed to this method is a {@link CancellationSignal}
+ * which is used to propagate requests from the system to your application for
+ * canceling the current layout operation. For example, a cancellation may be
+ * requested if the user changes a print option that may affect layout while
+ * you are performing a layout operation. In such a case the system will make
+ * an attempt to cancel the current layout as another one will have to be performed.
+ * Typically, you should register a cancellation callback in the cancellation
+ * signal. The cancellation callback <strong>will not</strong> be made on the
+ * main thread and can be registered as follows:
* </p>
+ * <pre>
+ * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ * &#064;Override
+ * public void onCancel() {
+ * // Cancel layout
+ * }
+ * });
+ * </pre>
* <p>
* <strong>Note:</strong> If the content is large and a layout will be
* performed, it is a good practice to schedule the work on a dedicated
* thread and register an observer in the provided {@link
* CancellationSignal} upon invocation of which you should stop the
- * layout. The cancellation callback will not be made on the main
- * thread.
+ * layout.
* </p>
*
* @param oldAttributes The old print attributes.
@@ -128,17 +193,41 @@ public abstract class PrintDocumentAdapter {
* on the main thread.
*<p>
* After you are done writing, you should close the file descriptor and
- * invoke {@link WriteResultCallback #onWriteFinished(PageRange[]), if writing
+ * invoke {@link WriteResultCallback#onWriteFinished(PageRange[])}, if writing
* completed successfully; or {@link WriteResultCallback#onWriteFailed(
- * CharSequence)}, if an error occurred. Note that you must call one of
- * the methods of the given callback.
+ * CharSequence)}, if an error occurred; or {@link WriteResultCallback#onWriteCancelled()},
+ * if writing was cancelled in a response to a cancellation request via the passed
+ * in {@link CancellationSignal}. Note that you <strong>must</strong> call one of
+ * the methods of the given callback for this method to be considered complete which
+ * is you will not receive any calls to this adapter until the current write
+ * operation is complete by invoking a method on the callback instance. The callback
+ * methods can be invoked from an arbitrary thread.
+ * </p>
+ * <p>
+ * One of the arguments passed to this method is a {@link CancellationSignal}
+ * which is used to propagate requests from the system to your application for
+ * canceling the current write operation. For example, a cancellation may be
+ * requested if the user changes a print option that may affect layout while
+ * you are performing a write operation. In such a case the system will make
+ * an attempt to cancel the current write as a layout will have to be performed
+ * which then may be followed by a write. Typically, you should register a
+ * cancellation callback in the cancellation signal. The cancellation callback
+ * <strong>will not</strong> be made on the main thread and can be registered
+ * as follows:
* </p>
+ * <pre>
+ * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ * &#064;Override
+ * public void onCancel() {
+ * // Cancel write
+ * }
+ * });
+ * </pre>
* <p>
* <strong>Note:</strong> If the printed content is large, it is a good
* practice to schedule writing it on a dedicated thread and register an
* observer in the provided {@link CancellationSignal} upon invocation of
- * which you should stop writing. The cancellation callback will not be
- * made on the main thread.
+ * which you should stop writing.
* </p>
*
* @param pages The pages whose content to print - non-overlapping in ascending order.
@@ -178,7 +267,8 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that all the data was written.
*
- * @param pages The pages that were written. Cannot be null or empty.
+ * @param pages The pages that were written. Cannot be <code>null</code>
+ * or empty.
*/
public void onWriteFinished(PageRange[] pages) {
/* do nothing - stub */
@@ -187,7 +277,8 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that an error occurred while writing the data.
*
- * @param error Error message. May be null if error is unknown.
+ * @param error The <strong>localized</strong> error message.
+ * shown to the user. May be <code>null</code> if error is unknown.
*/
public void onWriteFailed(CharSequence error) {
/* do nothing - stub */
@@ -218,7 +309,7 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that the layout finished and whether the content changed.
*
- * @param info An info object describing the document. Cannot be null.
+ * @param info An info object describing the document. Cannot be <code>null</code>.
* @param changed Whether the layout changed.
*
* @see PrintDocumentInfo
@@ -230,7 +321,8 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that an error occurred while laying out the document.
*
- * @param error Error message. May be null if error is unknown.
+ * @param error The <strong>localized</strong> error message.
+ * shown to the user. May be <code>null</code> if error is unknown.
*/
public void onLayoutFailed(CharSequence error) {
/* do nothing - stub */
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index b721ef4..928be6c 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -21,12 +21,56 @@ import android.os.Parcelable;
import android.text.TextUtils;
/**
- * This class encapsulates information about a printed document.
+ * This class encapsulates information about a document for printing
+ * purposes. This meta-data is used by the platform and print services,
+ * components that interact with printers. For example, this class
+ * contains the number of pages contained in the document it describes and
+ * this number of pages is shown to the user allowing him/her to select
+ * the range to print. Also a print service may optimize the printing
+ * process based on the content type, such as document or photo.
+ * <p>
+ * Instances of this class are created by the printing application and
+ * passed to the {@link PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished(
+ * PrintDocumentInfo, boolean) PrintDocumentAdapter.LayoutResultCallback.onLayoutFinished(
+ * PrintDocumentInfo, boolean)} callback after successfully laying out the
+ * content which is performed in {@link PrintDocumentAdapter#onLayout(PrintAttributes,
+ * PrintAttributes, android.os.CancellationSignal, PrintDocumentAdapter.LayoutResultCallback,
+ * android.os.Bundle) PrintDocumentAdapter.onLayout(PrintAttributes,
+ * PrintAttributes, android.os.CancellationSignal,
+ * PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle)}.
+ * </p>
+ * <p>
+ * An example usage looks like this:
+ * <pre>
+ *
+ * . . .
+ *
+ * public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ * CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ * Bundle metadata) {
+ *
+ * // Assume the app defined a LayoutResult class which contains
+ * // the layout result data and that the content is a document.
+ * LayoutResult result = doSomeLayoutWork();
+ *
+ * PrintDocumentInfo info = new PrintDocumentInfo
+ * .Builder("printed_file.pdf")
+ * .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ * .setPageCount(result.getPageCount())
+ * .build();
+ *
+ * callback.onLayoutFinished(info, result.getContentChanged());
+ * }
+ *
+ * . . .
+ *
+ * </pre>
+ * </p>
*/
public final class PrintDocumentInfo implements Parcelable {
/**
- * Constant for unknown page count..
+ * Constant for unknown page count.
*/
public static final int PAGE_COUNT_UNKNOWN = -1;
@@ -37,11 +81,23 @@ public final class PrintDocumentInfo implements Parcelable {
/**
* Content type: document.
+ * <p>
+ * A print service may use normal paper to print the content instead
+ * of dedicated photo paper. Also it may use a lower quality printing
+ * process as the content is not as sensitive to print quality variation
+ * as a photo is.
+ * </p>
*/
public static final int CONTENT_TYPE_DOCUMENT = 0;
/**
* Content type: photo.
+ * <p>
+ * A print service may use dedicated photo paper to print the content
+ * instead of normal paper. Also it may use a higher quality printing
+ * process as the content is more sensitive to print quality variation
+ * than a document.
+ * </p>
*/
public static final int CONTENT_TYPE_PHOTO = 1;
@@ -82,7 +138,8 @@ public final class PrintDocumentInfo implements Parcelable {
}
/**
- * Gets the document name.
+ * Gets the document name. This name may be shown to
+ * the user.
*
* @return The document name.
*/
@@ -213,20 +270,23 @@ public final class PrintDocumentInfo implements Parcelable {
}
/**
- * Builder for creating an {@link PrintDocumentInfo}.
+ * Builder for creating a {@link PrintDocumentInfo}.
*/
public static final class Builder {
private final PrintDocumentInfo mPrototype;
/**
* Constructor.
+ *
* <p>
- * The values of the relevant properties are initialized with default
- * values. Please refer to the documentation of the individual setters
- * for information about the default values.
+ * The values of the relevant properties are initialized with defaults.
+ * Please refer to the documentation of the individual setters for
+ * information about the default values.
* </p>
*
- * @param name The document name. Cannot be empty.
+ * @param name The document name which may be shown to the user and
+ * is the file name if the content it describes is saved as a PDF.
+ * Cannot be empty.
*/
public Builder(String name) {
if (TextUtils.isEmpty(name)) {
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 535ae43..0abe219 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -17,8 +17,13 @@
package android.print;
/**
- * This class represents a print job from the perspective of
- * an application.
+ * This class represents a print job from the perspective of an
+ * application. It contains behavior methods for performing operations
+ * on it as well as methods for querying its state. A snapshot of the
+ * print job state is represented by the {@link PrintJobInfo} class.
+ * The state of a print job may change over time. An application receives
+ * instances of this class when creating a print job or querying for
+ * its print jobs.
*/
public final class PrintJob {
@@ -145,11 +150,12 @@ public final class PrintJob {
/**
* Gets whether this print job is failed. Such a print job is
* not successfully printed due to an error. You can request
- * a restart via {@link #restart()}.
+ * a restart via {@link #restart()} or cancel via {@link #cancel()}.
*
* @return Whether the print job is failed.
*
* @see #restart()
+ * @see #cancel()
*/
public boolean isFailed() {
return getInfo().getState() == PrintJobInfo.STATE_FAILED;
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index c6f0a68..63f94fe 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -16,13 +16,17 @@
package android.print;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
/**
- * This class represents the description of a print job.
+ * This class represents the description of a print job. The print job
+ * state includes properties such as its id, print attributes used for
+ * generating the content, and so on. Note that the print jobs state may
+ * change over time and this class represents a snapshot of this state.
*/
public final class PrintJobInfo implements Parcelable {
@@ -93,7 +97,7 @@ public final class PrintJobInfo implements Parcelable {
public static final int STATE_BLOCKED = 4;
/**
- * Print job state: The print job was successfully printed.
+ * Print job state: The print job is successfully printed.
* This is a terminal state.
* <p>
* Next valid states: None
@@ -103,15 +107,14 @@ public final class PrintJobInfo implements Parcelable {
/**
* Print job state: The print job was printing but printing failed.
- * This is a terminal state.
* <p>
- * Next valid states: None
+ * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED}
* </p>
*/
public static final int STATE_FAILED = 6;
/**
- * Print job state: The print job was canceled.
+ * Print job state: The print job is canceled.
* This is a terminal state.
* <p>
* Next valid states: None
@@ -158,6 +161,9 @@ public final class PrintJobInfo implements Parcelable {
/** Information about the printed document. */
private PrintDocumentInfo mDocumentInfo;
+ /** Advanced printer specific options. */
+ private Bundle mAdvancedOptions;
+
/** Whether we are trying to cancel this print job. */
private boolean mCanceling;
@@ -182,6 +188,7 @@ public final class PrintJobInfo implements Parcelable {
mAttributes = other.mAttributes;
mDocumentInfo = other.mDocumentInfo;
mCanceling = other.mCanceling;
+ mAdvancedOptions = other.mAdvancedOptions;
}
private PrintJobInfo(Parcel parcel) {
@@ -195,20 +202,17 @@ public final class PrintJobInfo implements Parcelable {
mCreationTime = parcel.readLong();
mCopies = parcel.readInt();
mStateReason = parcel.readString();
- if (parcel.readInt() == 1) {
- Parcelable[] parcelables = parcel.readParcelableArray(null);
+ Parcelable[] parcelables = parcel.readParcelableArray(null);
+ if (parcelables != 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);
- }
- if (parcel.readInt() == 1) {
- mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel);
- }
+ mAttributes = (PrintAttributes) parcel.readParcelable(null);
+ mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
mCanceling = (parcel.readInt() == 1);
+ mAdvancedOptions = parcel.readBundle();
}
/**
@@ -297,6 +301,14 @@ public final class PrintJobInfo implements Parcelable {
* Gets the current job state.
*
* @return The job state.
+ *
+ * @see #STATE_CREATED
+ * @see #STATE_QUEUED
+ * @see #STATE_STARTED
+ * @see #STATE_COMPLETED
+ * @see #STATE_BLOCKED
+ * @see #STATE_FAILED
+ * @see #STATE_CANCELED
*/
public int getState() {
return mState;
@@ -511,6 +523,71 @@ public final class PrintJobInfo implements Parcelable {
mCanceling = cancelling;
}
+ /**
+ * Gets whether this job has a given advanced (printer specific) print
+ * option.
+ *
+ * @param key The option key.
+ * @return Whether the option is present.
+ *
+ * @hide
+ */
+ public boolean hasAdvancedOption(String key) {
+ return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
+ }
+
+ /**
+ * Gets the value of an advanced (printer specific) print option.
+ *
+ * @param key The option key.
+ * @return The option value.
+ *
+ * @hide
+ */
+ public String getAdvancedStringOption(String key) {
+ if (mAdvancedOptions != null) {
+ return mAdvancedOptions.getString(key);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value of an advanced (printer specific) print option.
+ *
+ * @param key The option key.
+ * @return The option value.
+ *
+ * @hide
+ */
+ public int getAdvancedIntOption(String key) {
+ if (mAdvancedOptions != null) {
+ return mAdvancedOptions.getInt(key);
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the advanced options.
+ *
+ * @return The advanced options.
+ *
+ * @hide
+ */
+ public Bundle getAdvancedOptions() {
+ return mAdvancedOptions;
+ }
+
+ /**
+ * Sets the advanced options.
+ *
+ * @param options The advanced options.
+ *
+ * @hide
+ */
+ public void setAdvancedOptions(Bundle options) {
+ mAdvancedOptions = options;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -528,25 +605,11 @@ public final class PrintJobInfo implements Parcelable {
parcel.writeLong(mCreationTime);
parcel.writeInt(mCopies);
parcel.writeString(mStateReason);
- if (mPageRanges != null) {
- parcel.writeInt(1);
- parcel.writeParcelableArray(mPageRanges, flags);
- } else {
- parcel.writeInt(0);
- }
- if (mAttributes != null) {
- parcel.writeInt(1);
- mAttributes.writeToParcel(parcel, flags);
- } else {
- parcel.writeInt(0);
- }
- if (mDocumentInfo != null) {
- parcel.writeInt(1);
- mDocumentInfo.writeToParcel(parcel, flags);
- } else {
- parcel.writeInt(0);
- }
+ parcel.writeParcelableArray(mPageRanges, flags);
+ parcel.writeParcelable(mAttributes, flags);
+ parcel.writeParcelable(mDocumentInfo, 0);
parcel.writeInt(mCanceling ? 1 : 0);
+ parcel.writeBundle(mAdvancedOptions);
}
@Override
@@ -567,6 +630,7 @@ public final class PrintJobInfo implements Parcelable {
builder.append(", cancelling: " + mCanceling);
builder.append(", pages: " + (mPageRanges != null
? Arrays.toString(mPageRanges) : null));
+ builder.append(", hasAdvancedOptions: " + (mAdvancedOptions != null));
builder.append("}");
return builder.toString();
}
@@ -611,7 +675,7 @@ public final class PrintJobInfo implements Parcelable {
* Constructor.
*
* @param prototype Prototype to use as a starting point.
- * Can be null.
+ * Can be <code>null</code>.
*/
public Builder(PrintJobInfo prototype) {
mPrototype = (prototype != null)
@@ -653,7 +717,10 @@ public final class PrintJobInfo implements Parcelable {
* @param value The option value.
*/
public void putAdvancedOption(String key, String value) {
-
+ if (mPrototype.mAdvancedOptions == null) {
+ mPrototype.mAdvancedOptions = new Bundle();
+ }
+ mPrototype.mAdvancedOptions.putString(key, value);
}
/**
@@ -663,7 +730,10 @@ public final class PrintJobInfo implements Parcelable {
* @param value The option value.
*/
public void putAdvancedOption(String key, int value) {
-
+ if (mPrototype.mAdvancedOptions == null) {
+ mPrototype.mAdvancedOptions = new Bundle();
+ }
+ mPrototype.mAdvancedOptions.putInt(key, value);
}
/**
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index dbd8278..d1bb8fd 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -16,6 +16,8 @@
package android.print;
+import android.app.Activity;
+import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
@@ -53,6 +55,49 @@ import java.util.Map;
* 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
+ * should be laid out for the currently selected print options resulting in an
+ * optimized output and higher user satisfaction. To achieve this goal the platform
+ * declares a contract that the printing application has to follow which is defined
+ * by the {@link PrintDocumentAdapter} class. At a higher level the contract is that
+ * when the user selects some options from the print UI that may affect the way
+ * content is laid out, for example page size, the application receives a callback
+ * allowing it to layout the content to better fit these new constraints. After a
+ * layout pass the system may ask the application to render one or more pages one
+ * or more times. For example, an application may produce a single column list for
+ * smaller page sizes and a multi-column table for larger page sizes.
+ * </p>
+ * <h3>Print jobs</h3>
+ * <p>
+ * Print jobs are started by calling the {@link #print(String, PrintDocumentAdapter,
+ * PrintAttributes)} from an activity which results in bringing up the system print
+ * UI. Once the print UI is up, when the user changes a selected print option that
+ * affects the way content is laid out the system starts to interact with the
+ * application following the mechanics described the section above.
+ * </p>
+ * <p>
+ * Print jobs can be in {@link PrintJobInfo#STATE_CREATED created}, {@link
+ * PrintJobInfo#STATE_QUEUED queued}, {@link PrintJobInfo#STATE_STARTED started},
+ * {@link PrintJobInfo#STATE_BLOCKED blocked}, {@link PrintJobInfo#STATE_COMPLETED
+ * completed}, {@link PrintJobInfo#STATE_FAILED failed}, and {@link
+ * PrintJobInfo#STATE_CANCELED canceled} state. Print jobs are stored in dedicated
+ * system spooler until they are handled which is they are cancelled or completed.
+ * Active print jobs, ones that are not cancelled or completed, are considered failed
+ * if the device reboots as the new boot may be after a very long time. The user may
+ * choose to restart such print jobs. Once a print job is queued all relevant content
+ * is stored in the system spooler and its lifecycle becomes detached from this of
+ * the application that created it.
+ * </p>
+ * <p>
+ * An applications can query the print spooler for current print jobs it created
+ * but not print jobs created by other applications.
+ * </p>
+ *
+ * @see PrintJob
+ * @see PrintJobInfo
*/
public final class PrintManager {
@@ -290,20 +335,54 @@ public final class PrintManager {
/**
* Creates a print job for printing a {@link PrintDocumentAdapter} with
* default print attributes.
- *
- * @param printJobName A name for the new print job.
+ * <p>
+ * Calling this method brings the print UI allowing the user to customize
+ * the print job and returns a {@link PrintJob} object without waiting for the
+ * user to customize or confirm the print job. The returned print job instance
+ * is in a {@link PrintJobInfo#STATE_CREATED created} state.
+ * <p>
+ * This method can be called only from an {@link Activity}. The rationale is that
+ * printing from a service will create an inconsistent user experience as the print
+ * UI would appear without any context.
+ * </p>
+ * <p>
+ * Also the passed in {@link PrintDocumentAdapter} will be considered invalid if
+ * your activity is finished. The rationale is that once the activity that
+ * initiated printing is finished, the provided adapter may be in an inconsistent
+ * state as it may depend on the UI presented by the activity.
+ * </p>
+ * <p>
+ * The default print attributes are a hint to the system how the data is to
+ * be printed. For example, a photo editor may look at the photo aspect ratio
+ * to determine the default orientation and provide a hint whether the printing
+ * should be in portrait or landscape. The system will do a best effort to
+ * selected the hinted options in the print dialog, given the current printer
+ * supports them.
+ * </p>
+ *
+ * @param printJobName A name for the new print job which is shown to the user.
* @param documentAdapter An adapter that emits the document to print.
- * @param attributes The default print job attributes.
+ * @param attributes The default print job attributes or <code>null</code>.
* @return The created print job on success or null on failure.
+ * @throws IllegalStateException If not called from an {@link Activity}.
+ * @throws IllegalArgumentException If the print job name is empty or the
+ * document adapter is null.
+ *
* @see PrintJob
*/
public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
PrintAttributes attributes) {
+ if (!(mContext instanceof Activity)) {
+ throw new IllegalStateException("Can print only from an activity");
+ }
if (TextUtils.isEmpty(printJobName)) {
- throw new IllegalArgumentException("priintJobName cannot be empty");
+ throw new IllegalArgumentException("printJobName cannot be empty");
+ }
+ if (documentAdapter == null) {
+ throw new IllegalArgumentException("documentAdapter cannot be null");
}
- PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
- mContext.getMainLooper());
+ PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(
+ (Activity) mContext, documentAdapter);
try {
Bundle result = mService.print(printJobName, delegate,
attributes, mContext.getPackageName(), mAppId, mUserId);
@@ -369,17 +448,21 @@ public final class PrintManager {
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
- private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
+ private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
+ implements ActivityLifecycleCallbacks {
private final Object mLock = new Object();
private CancellationSignal mLayoutOrWriteCancellation;
- private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK -
- // cleared in finish()
+ private Activity mActivity; // Strong reference OK - cleared in finish()
+
+ private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish
private Handler mHandler; // Strong reference OK - cleared in finish()
+ private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in finish
+
private LayoutSpec mLastLayoutSpec;
private WriteSpec mLastWriteSpec;
@@ -390,16 +473,39 @@ public final class PrintManager {
private boolean mFinishRequested;
private boolean mFinished;
- public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
+ private boolean mDestroyed;
+
+ public PrintDocumentAdapterDelegate(Activity activity,
+ PrintDocumentAdapter documentAdapter) {
+ mActivity = activity;
mDocumentAdapter = documentAdapter;
- mHandler = new MyHandler(looper);
+ mHandler = new MyHandler(mActivity.getMainLooper());
+ mActivity.getApplication().registerActivityLifecycleCallbacks(this);
+ }
+
+ @Override
+ public void setObserver(IPrintDocumentAdapterObserver observer) {
+ final boolean destroyed;
+ synchronized (mLock) {
+ if (!mDestroyed) {
+ mObserver = observer;
+ }
+ destroyed = mDestroyed;
+ }
+ if (destroyed) {
+ try {
+ observer.onDestroy();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error announcing destroyed state", re);
+ }
+ }
}
@Override
public void start() {
synchronized (mLock) {
- // Started or finished - nothing to do.
- if (mStartReqeusted || mFinishRequested) {
+ // Started called or finish called or destroyed - nothing to do.
+ if (mStartReqeusted || mFinishRequested || mDestroyed) {
return;
}
@@ -412,71 +518,85 @@ public final class PrintManager {
@Override
public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
ILayoutResultCallback callback, Bundle metadata, int sequence) {
+ final boolean destroyed;
synchronized (mLock) {
- // 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;
- }
+ 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;
+ 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;
+ }
- // Cancel the previous cancellable operation.When the
- // cancellation completes we will do the pending work.
- if (cancelPreviousCancellableOperationLocked()) {
- return;
+ doPendingWorkLocked();
+ }
+ }
+ if (destroyed) {
+ try {
+ callback.onLayoutFailed(null, sequence);
+ } catch (RemoteException re) {
+ Log.i(LOG_TAG, "Error notifying for cancelled layout", re);
}
-
- doPendingWorkLocked();
}
}
@Override
public void write(PageRange[] pages, ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence) {
+ final boolean destroyed;
synchronized (mLock) {
- // Start not called or finish called - nothing to do.
- if (!mStartReqeusted || mFinishRequested) {
- return;
- }
+ 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;
+ }
- // 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;
- 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;
+ }
- // 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);
}
-
- doPendingWorkLocked();
}
}
@Override
public void finish() {
synchronized (mLock) {
- // Start not called or finish called - nothing to do.
- if (!mStartReqeusted || mFinishRequested) {
+ // Start not called or finish called or destroyed - nothing to do.
+ if (!mStartReqeusted || mFinishRequested || mDestroyed) {
return;
}
@@ -495,15 +615,90 @@ public final class PrintManager {
}
}
+ @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.
+ synchronized (mLock) {
+ cancelPreviousCancellableOperationLocked();
+ }
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ // We really care only if the activity is being destroyed to
+ // notify the the print spooler so it can close the print dialog.
+ // 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;
+ synchronized (mLock) {
+ if (activity == mActivity) {
+ mDestroyed = true;
+ observer = mObserver;
+ clearLocked();
+ } else {
+ observer = null;
+ activity = null;
+ }
+ }
+ if (observer != null) {
+ activity.getApplication().unregisterActivityLifecycleCallbacks(
+ PrintDocumentAdapterDelegate.this);
+ try {
+ observer.onDestroy();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error announcing destroyed state", re);
+ }
+ }
+ }
+
private boolean isFinished() {
return mDocumentAdapter == null;
}
- private void doFinish() {
+ private void clearLocked() {
+ mActivity = null;
mDocumentAdapter = null;
mHandler = null;
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
+ mLayoutOrWriteCancellation = null;
+ mLastLayoutSpec = null;
+ if (mLastWriteSpec != null) {
+ IoUtils.closeQuietly(mLastWriteSpec.fd);
+ mLastWriteSpec = null;
}
}
@@ -564,63 +759,81 @@ public final class PrintManager {
}
switch (message.what) {
case MSG_START: {
- mDocumentAdapter.onStart();
- }
- break;
+ final PrintDocumentAdapter adapter;
+ synchronized (mLock) {
+ adapter = mDocumentAdapter;
+ }
+ if (adapter != null) {
+ adapter.onStart();
+ }
+ } break;
case MSG_LAYOUT: {
+ final PrintDocumentAdapter adapter;
final CancellationSignal cancellation;
final LayoutSpec layoutSpec;
synchronized (mLock) {
+ adapter = mDocumentAdapter;
layoutSpec = mLastLayoutSpec;
mLastLayoutSpec = null;
cancellation = new CancellationSignal();
mLayoutOrWriteCancellation = cancellation;
}
- if (layoutSpec != null) {
+ if (layoutSpec != null && adapter != null) {
if (DEBUG) {
Log.i(LOG_TAG, "Performing layout");
}
- mDocumentAdapter.onLayout(layoutSpec.oldAttributes,
+ adapter.onLayout(layoutSpec.oldAttributes,
layoutSpec.newAttributes, cancellation,
new MyLayoutResultCallback(layoutSpec.callback,
layoutSpec.sequence), layoutSpec.metadata);
}
- }
- break;
+ } break;
case MSG_WRITE: {
+ final PrintDocumentAdapter adapter;
final CancellationSignal cancellation;
final WriteSpec writeSpec;
synchronized (mLock) {
+ adapter = mDocumentAdapter;
writeSpec = mLastWriteSpec;
mLastWriteSpec = null;
cancellation = new CancellationSignal();
mLayoutOrWriteCancellation = cancellation;
}
- if (writeSpec != null) {
+ if (writeSpec != null && adapter != null) {
if (DEBUG) {
Log.i(LOG_TAG, "Performing write");
}
- mDocumentAdapter.onWrite(writeSpec.pages, writeSpec.fd,
+ adapter.onWrite(writeSpec.pages, writeSpec.fd,
cancellation, new MyWriteResultCallback(writeSpec.callback,
writeSpec.fd, writeSpec.sequence));
}
- }
- break;
+ } break;
case MSG_FINISH: {
if (DEBUG) {
Log.i(LOG_TAG, "Performing finish");
}
- mDocumentAdapter.onFinish();
- doFinish();
- }
- break;
+ final PrintDocumentAdapter adapter;
+ final Activity activity;
+ synchronized (mLock) {
+ adapter = mDocumentAdapter;
+ activity = mActivity;
+ clearLocked();
+ }
+ if (adapter != null) {
+ adapter.onFinish();
+ }
+ if (activity != null) {
+ activity.getApplication().unregisterActivityLifecycleCallbacks(
+ PrintDocumentAdapterDelegate.this);
+ }
+ } break;
default: {
throw new IllegalArgumentException("Unknown message: "
@@ -647,6 +860,11 @@ public final class PrintManager {
}
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();
}
@@ -663,6 +881,11 @@ 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();
}
@@ -678,6 +901,11 @@ public final class PrintManager {
@Override
public void onLayoutCancelled() {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
clearLocked();
}
}
@@ -705,6 +933,11 @@ 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();
}
@@ -727,6 +960,11 @@ 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();
}
@@ -742,6 +980,11 @@ public final class PrintManager {
@Override
public void onWriteCancelled() {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
clearLocked();
}
}
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index df51ec1..b615600 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,10 +24,17 @@ import android.print.PrintAttributes.Resolution;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
- * This class represents the capabilities of a printer.
+ * This class represents the capabilities of a printer. Instances
+ * of this class are created by a print service to report the
+ * capabilities of a printer it manages. The capabilities of a
+ * printer specify how it can print content. For example, what
+ * are the media sizes supported by the printer, what are the
+ * minimal margins of the printer based on its technical design,
+ * etc.
*/
public final class PrinterCapabilitiesInfo implements Parcelable {
/**
@@ -112,7 +119,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @return The media sizes.
*/
public List<MediaSize> getMediaSizes() {
- return mMediaSizes;
+ return Collections.unmodifiableList(mMediaSizes);
}
/**
@@ -121,7 +128,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @return The resolutions.
*/
public List<Resolution> getResolutions() {
- return mResolutions;
+ return Collections.unmodifiableList(mResolutions);
}
/**
@@ -135,9 +142,9 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Gets the supported color modes.
+ * Gets the bit mask of supported color modes.
*
- * @return The color modes.
+ * @return The bit mask of supported color modes.
*
* @see PrintAttributes#COLOR_MODE_COLOR
* @see PrintAttributes#COLOR_MODE_MONOCHROME
@@ -355,9 +362,10 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Builder for creating of a {@link PrinterInfo}. This class is responsible
- * to enforce that all required attributes have at least one default value.
- * In other words, this class creates only well-formed {@link PrinterInfo}s.
+ * Builder for creating of a {@link PrinterCapabilitiesInfo}. This class is
+ * responsible to enforce that all required attributes have at least one
+ * default value. In other words, this class creates only well-formed {@link
+ * PrinterCapabilitiesInfo}s.
* <p>
* Look at the individual methods for a reference whether a property is
* required or if it is optional.
@@ -369,9 +377,9 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
/**
* Creates a new instance.
*
- * @param printerId The printer id. Cannot be null.
+ * @param printerId The printer id. Cannot be <code>null</code>.
*
- * @throws IllegalArgumentException If the printer id is null.
+ * @throws IllegalArgumentException If the printer id is <code>null</code>.
*/
public Builder(PrinterId printerId) {
if (printerId == null) {
@@ -492,7 +500,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
/**
* Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
- * required properties have need specified. See individual methods
+ * required properties have been specified. See individual methods
* in this class for reference about required attributes.
*
* @return A new {@link PrinterCapabilitiesInfo}.
@@ -521,7 +529,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
if (mPrototype.mMinMargins == null) {
throw new IllegalArgumentException("margins cannot be null");
}
- return new PrinterCapabilitiesInfo(mPrototype);
+ return mPrototype;
}
private void throwIfDefaultAlreadySpecified(int propertyIndex) {
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index ad79a38..7fcc81f 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -21,7 +21,12 @@ import android.os.Parcelable;
import android.text.TextUtils;
/**
- * This class represents the description of a printer.
+ * This class represents the description of a printer. Instances of
+ * this class are created by print services to report to the system
+ * the printers they manage. The information of this class has two
+ * major components, printer properties such as name, id, status,
+ * description and printer capabilities which describe the various
+ * print modes a printer supports such as media sizes, margins, etc.
*/
public final class PrinterInfo implements Parcelable {
@@ -96,6 +101,10 @@ public final class PrinterInfo implements Parcelable {
* Gets the printer status.
*
* @return The status.
+ *
+ * @see #STATUS_BUSY
+ * @see #STATUS_IDLE
+ * @see #STATUS_UNAVAILABLE
*/
public int getStatus() {
return mStatus;
@@ -216,6 +225,8 @@ public final class PrinterInfo implements Parcelable {
* @param printerId The printer id. Cannot be null.
* @param name The printer name. Cannot be empty.
* @param status The printer status. Must be a valid status.
+ * @throws IllegalArgumentException If the printer id is null, or the
+ * printer name is empty or the status is not a valid one.
*/
public Builder(PrinterId printerId, String name, int status) {
if (printerId == null) {
@@ -259,7 +270,8 @@ public final class PrinterInfo implements Parcelable {
}
/**
- * Sets the printer name.
+ * Sets the <strong>localized</strong> printer name which
+ * is shown to the user
*
* @param name The name.
* @return This builder.
@@ -270,7 +282,8 @@ public final class PrinterInfo implements Parcelable {
}
/**
- * Sets the printer description.
+ * Sets the <strong>localized</strong> printer description
+ * which is shown to the user
*
* @param description The description.
* @return This builder.
@@ -292,12 +305,12 @@ public final class PrinterInfo implements Parcelable {
}
/**
- * Crates a new {@link PrinterInfo}.
+ * Creates a new {@link PrinterInfo}.
*
* @return A new {@link PrinterInfo}.
*/
public PrinterInfo build() {
- return new PrinterInfo(mPrototype);
+ return mPrototype;
}
private boolean isValidStatus(int status) {
diff --git a/core/java/android/print/package.html b/core/java/android/print/package.html
new file mode 100644
index 0000000..579567d
--- /dev/null
+++ b/core/java/android/print/package.html
@@ -0,0 +1,46 @@
+<HTML>
+<BODY>
+<h3>Overview</h3>
+<p>
+Provides classes for implementing print support in applications and also contains all
+base classes and abstractions involved in printing. These base classes are also used
+by other more specialized printing related packages.
+</p>
+<p>
+The entry point for interacting with the print system is the {@link android.print.PrintManager}
+which is a system service that can be obtained from the current context. The print manager
+provides APIs for printing, querying the state of print jobs, etc.
+<p/>
+<h3>Print contract</h3>
+<p>
+An application that wants to implement printing must extend
+{@link android.print.PrintDocumentAdapter} which defines the contract between the system
+and the application.The key idea behind this adapter is that the printed content may change
+based on the selected print options, such as media size, orientation, which
+requires the content to be re-laid out. The constraints according to which the content has
+to be laid out are encapsulated in the {@link android.print.PrintAttributes} class. Once
+layout is completed the application calls back to the system passing a
+{@link android.print.PrintDocumentInfo} instance which describes the generated content. After
+the content has been laid out the application may be asked to render some pages of that content
+for preview or printing. The range of pages that have to be rendered is abstracted by the
+{@link android.print.PageRange} class.
+</p>
+<h3>Print jobs</h3>
+<p>
+A print job is represented by the {@link android.print.PrintJob} class which has behavior
+methods as well as methods for querying its state. Each print job has a unique id represented
+by the {@link android.print.PrintJobId} class and exposes APIs for obtaining a {@link
+android.print.PrintJobInfo} which is a snapshot of its state. The print job state may
+change over time.
+</p>
+<h3>Printers</h3>
+<p>
+An available printer represented by the {@link android.print.PrinterInfo} class has a
+unique id which is abstracted by the {@link android.print.PrinterId} class. The {@link
+android.print.PrinterInfo} contains printer properties such as id, name, description, status,
+and printer capabilities encapsulated in the {@link android.print.PrinterCapabilitiesInfo}
+class. Printer capabilities describe how a printer can print content, for example what are
+the supported media sizes, color modes, resolutions, etc.
+<p>
+</BODY>
+</HTML>