From aec1417ca9eb63209668ac17da90cf8a07c6076c Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Tue, 27 Aug 2013 00:30:54 -0700 Subject: Print APIs update. 1. Added scale to fit and scale to fill fitting modes. 2. Added APIs for a print app to specify which constraints imposed by the print attributes were satsified during a layout so they are not handled by the printer again, e.g. if the content is to be in landscape the the app generated such content the printer should rotate the content again. 3. Added some printer statuses. 4. Added a helper class that generates PDF documents with correct size based on the passed in print attributes. 5. Exposed a ctor for PageRange which was hidden by mistake and apps could not create page ranges. Added API for changing the printer status. Change-Id: If1334a61d2d931027b98075f653018d456b1b768 --- api/current.txt | 34 ++- core/java/android/print/PageRange.java | 2 - core/java/android/print/PrintAttributes.java | 60 ++--- core/java/android/print/PrintDocumentAdapter.java | 22 ++ core/java/android/print/PrintDocumentInfo.java | 255 ++++++++++++++++++++- .../android/print/PrinterCapabilitiesInfo.java | 4 +- core/java/android/print/PrinterInfo.java | 29 ++- core/java/android/print/pdf/PdfDocument.java | 43 +--- .../java/android/print/pdf/PrintedPdfDocument.java | 162 +++++++++++++ .../printspooler/PrintJobConfigActivity.java | 188 +++++++++++---- 10 files changed, 671 insertions(+), 128 deletions(-) create mode 100644 core/java/android/print/pdf/PrintedPdfDocument.java diff --git a/api/current.txt b/api/current.txt index 27a848062a4c..29a817c9911d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -18877,6 +18877,7 @@ package android.preference { package android.print { public final class PageRange implements android.os.Parcelable { + ctor public PageRange(int, int); method public int describeContents(); method public int getEnd(); method public int getStart(); @@ -18904,8 +18905,9 @@ package android.print { field public static final int DUPLEX_MODE_LONG_EDGE = 2; // 0x2 field public static final int DUPLEX_MODE_NONE = 1; // 0x1 field public static final int DUPLEX_MODE_SHORT_EDGE = 4; // 0x4 - field public static final int FITTING_MODE_FIT_TO_PAGE = 2; // 0x2 field public static final int FITTING_MODE_NONE = 1; // 0x1 + field public static final int FITTING_MODE_SCALE_TO_FILL = 4; // 0x4 + field public static final int FITTING_MODE_SCALE_TO_FIT = 2; // 0x2 field public static final int ORIENTATION_LANDSCAPE = 2; // 0x2 field public static final int ORIENTATION_PORTRAIT = 1; // 0x1 } @@ -18930,6 +18932,7 @@ package android.print { method public int getLeftMils(); method public int getRightMils(); method public int getTopMils(); + field public static final android.print.PrintAttributes.Margins NO_MARGINS; } public static final class PrintAttributes.MediaSize { @@ -19017,21 +19020,33 @@ package android.print { public final class PrintDocumentInfo implements android.os.Parcelable { method public int describeContents(); + method public int getColorMode(); method public int getContentType(); + method public int getFittingMode(); + method public android.print.PrintAttributes.Margins getMargins(); + method public android.print.PrintAttributes.MediaSize getMediaSize(); method public java.lang.String getName(); + method public int getOrientation(); method public int getPageCount(); method public void writeToParcel(android.os.Parcel, int); field public static final int CONTENT_TYPE_DOCUMENT = 0; // 0x0 field public static final int CONTENT_TYPE_PHOTO = 1; // 0x1 field public static final int CONTENT_TYPE_UNKNOWN = -1; // 0xffffffff field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.print.PrintAttributes.MediaSize MEDIA_SIZE_UNKNOWN; field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff } public static final class PrintDocumentInfo.Builder { + ctor public PrintDocumentInfo.Builder(java.lang.String, android.print.PrintAttributes); ctor public PrintDocumentInfo.Builder(java.lang.String); method public android.print.PrintDocumentInfo create(); + method public android.print.PrintDocumentInfo.Builder setColorMode(int); method public android.print.PrintDocumentInfo.Builder setContentType(int); + method public android.print.PrintDocumentInfo.Builder setFittingMode(int); + method public android.print.PrintDocumentInfo.Builder setMargins(android.print.PrintAttributes.Margins); + method public android.print.PrintDocumentInfo.Builder setMediaSize(android.print.PrintAttributes.MediaSize); + method public android.print.PrintDocumentInfo.Builder setOrientation(int); method public android.print.PrintDocumentInfo.Builder setPageCount(int); } @@ -19119,7 +19134,9 @@ package android.print { method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static final int STATUS_READY = 1; // 0x1 + field public static final int STATUS_BUSY = 2; // 0x2 + field public static final int STATUS_IDLE = 1; // 0x1 + field public static final int STATUS_UNAVAILABLE = 3; // 0x3 } public static final class PrinterInfo.Builder { @@ -19129,6 +19146,7 @@ package android.print { method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo); method public android.print.PrinterInfo.Builder setDescription(java.lang.String); method public android.print.PrinterInfo.Builder setName(java.lang.String); + method public android.print.PrinterInfo.Builder setStatus(int); } } @@ -19151,19 +19169,27 @@ package android.print.pdf { public static final class PdfDocument.PageInfo { method public android.graphics.Rect getContentSize(); - method public int getDesity(); method public android.graphics.Matrix getInitialTransform(); method public int getPageNumber(); method public android.graphics.Rect getPageSize(); } public static final class PdfDocument.PageInfo.Builder { - ctor public PdfDocument.PageInfo.Builder(android.graphics.Rect, int, int); + ctor public PdfDocument.PageInfo.Builder(android.graphics.Rect, int); method public android.print.pdf.PdfDocument.PageInfo create(); method public android.print.pdf.PdfDocument.PageInfo.Builder setContentSize(android.graphics.Rect); method public android.print.pdf.PdfDocument.PageInfo.Builder setInitialTransform(android.graphics.Matrix); } + public final class PrintedPdfDocument { + method public void close(); + method public void finishPage(android.print.pdf.PdfDocument.Page); + method public java.util.List getPages(); + method public static android.print.pdf.PrintedPdfDocument open(android.content.Context, android.print.PrintAttributes); + method public android.print.pdf.PdfDocument.Page startPage(int); + method public void writeTo(java.io.OutputStream); + } + } package android.printservice { diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java index ba455f622810..cdcd0c7d2e6a 100644 --- a/core/java/android/print/PageRange.java +++ b/core/java/android/print/PageRange.java @@ -42,8 +42,6 @@ public final class PageRange implements Parcelable { * @throws IllegalArgumentException If start is less than zero. * @throws IllegalArgumentException If end is less than zero. * @throws IllegalArgumentException If start greater than end. - * - * @hide */ 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 a902c7204bbd..caa10aee03b0 100644 --- a/core/java/android/print/PrintAttributes.java +++ b/core/java/android/print/PrintAttributes.java @@ -50,9 +50,15 @@ public final class PrintAttributes implements Parcelable { /** Fitting mode: No fitting. */ - public static final int FITTING_MODE_NONE = 0x00000001; - /** Fitting mode: Fit the content to the page. */ - public static final int FITTING_MODE_FIT_TO_PAGE = 0x00000002; + public static final int FITTING_MODE_NONE = 1 << 0; + /** Fitting mode: Scale the content to fit in the page + * without cropping it in any dimension. */ + public static final int FITTING_MODE_SCALE_TO_FIT = 1 << 1; + /** + * Fitting mode: Uniformly scale the content to fill the entire page + * potentially cropping the content if it overflows in one dimension. + */ + public static final int FITTING_MODE_SCALE_TO_FILL = 1 << 2; private static final int VALID_DUPLEX_MODES = @@ -62,7 +68,7 @@ public final class PrintAttributes implements Parcelable { COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR; private static final int VALID_FITTING_MODES = - FITTING_MODE_NONE | FITTING_MODE_FIT_TO_PAGE; + FITTING_MODE_NONE | FITTING_MODE_SCALE_TO_FIT | FITTING_MODE_SCALE_TO_FILL; private static final int VALID_ORIENTATIONS = ORIENTATION_PORTRAIT | ORIENTATION_LANDSCAPE; @@ -252,7 +258,8 @@ public final class PrintAttributes implements Parcelable { * @return The fitting mode or zero if not set. * * @see #FITTING_MODE_NONE - * @see #FITTING_MODE_FIT_TO_PAGE + * @see #FITTING_MODE_SCALE_TO_FILL + * @see #FITTING_MODE_SCALE_TO_FIT */ public int getFittingMode() { return mFittingMode; @@ -264,12 +271,13 @@ public final class PrintAttributes implements Parcelable { * @param The fitting mode. * * @see #FITTING_MODE_NONE - * @see #FITTING_MODE_FIT_TO_PAGE + * @see #FITTING_MODE_SCALE_TO_FILL + * @see #FITTING_MODE_SCALE_TO_FIT * * @hide */ public void setFittingMode(int fittingMode) { - enfoceValidFittingMode(fittingMode); + enforceValidFittingMode(fittingMode); mFittingMode = fittingMode; } @@ -1220,6 +1228,8 @@ public final class PrintAttributes implements Parcelable { * This class specifies content margins. */ public static final class Margins { + public static final Margins NO_MARGINS = new Margins(0, 0, 0, 0); + private final int mLeftMils; private final int mTopMils; private final int mRightMils; @@ -1232,24 +1242,13 @@ public final class PrintAttributes implements Parcelable { * @param topMils The top margin in mils (thousands of an inch). * @param rightMils The right margin in mils (thousands of an inch). * @param bottomMils The bottom margin in mils (thousands of an inch). - * - * @throws IllegalArgumentException If the leftMils is less than zero. - * @throws IllegalArgumentException If the topMils is less than zero. - * @throws IllegalArgumentException If the rightMils is less than zero. - * @throws IllegalArgumentException If the bottomMils is less than zero. */ public Margins(int leftMils, int topMils, int rightMils, int bottomMils) { - if (leftMils < 0) { - throw new IllegalArgumentException("leftMils cannot be less than zero."); + if (leftMils > rightMils) { + throw new IllegalArgumentException("leftMils cannot be less than rightMils."); } - if (topMils < 0) { - throw new IllegalArgumentException("topMils cannot be less than zero."); - } - if (rightMils < 0) { - throw new IllegalArgumentException("rightMils cannot be less than zero."); - } - if (bottomMils < 0) { - throw new IllegalArgumentException("bottomMils cannot be less than zero."); + if (topMils > bottomMils) { + throw new IllegalArgumentException("topMils cannot be less than bottomMils."); } mTopMils = topMils; mLeftMils = leftMils; @@ -1504,8 +1503,11 @@ public final class PrintAttributes implements Parcelable { case FITTING_MODE_NONE: { return "FITTING_MODE_NONE"; } - case FITTING_MODE_FIT_TO_PAGE: { - return "FITTING_MODE_FIT_TO_PAGE"; + case FITTING_MODE_SCALE_TO_FIT: { + return "FITTING_MODE_SCALE_TO_FIT"; + } + case FITTING_MODE_SCALE_TO_FILL: { + return "FITTING_MODE_SCALE_TO_FILL"; } default: return "FITTING_MODE_UNKNOWN"; @@ -1513,25 +1515,25 @@ public final class PrintAttributes implements Parcelable { } static void enforceValidDuplexMode(int duplexMode) { - if ((duplexMode & VALID_DUPLEX_MODES) == 0) { + if ((duplexMode & VALID_DUPLEX_MODES) == 0 && Integer.bitCount(duplexMode) == 1) { throw new IllegalArgumentException("invalid duplex mode: " + duplexMode); } } static void enforceValidColorMode(int colorMode) { - if ((colorMode & VALID_COLOR_MODES) == 0) { + if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) { throw new IllegalArgumentException("invalid color mode: " + colorMode); } } - static void enfoceValidFittingMode(int fittingMode) { - if ((fittingMode & VALID_FITTING_MODES) == 0) { + static void enforceValidFittingMode(int fittingMode) { + if ((fittingMode & VALID_FITTING_MODES) == 0 && Integer.bitCount(fittingMode) == 1) { throw new IllegalArgumentException("invalid fitting mode: " + fittingMode); } } static void enforceValidOrientation(int orientation) { - if ((orientation & VALID_ORIENTATIONS) == 0) { + if ((orientation & VALID_ORIENTATIONS) == 0 && Integer.bitCount(orientation) == 1) { throw new IllegalArgumentException("invalid orientation: " + orientation); } } diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java index d3202262bbd5..8a64e85cd07d 100644 --- a/core/java/android/print/PrintDocumentAdapter.java +++ b/core/java/android/print/PrintDocumentAdapter.java @@ -101,6 +101,28 @@ public abstract class PrintDocumentAdapter { * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred. *

*

+ * When doing a layout you may satisfy some of the constraints in the print + * attributes such as applying the appropriate fitting, emitting content in the + * requested orientation, using the specified margins, generating content with + * the desired color mode, producing output with the given media size. Ideally, + * you will satisfy all of these constraints. It is important that if you + * satisfy a given constraint, you update the {@link PrintDocumentInfo} that + * is returned in the given {@link LayoutResultCallback}. This way the printer + * will have more accurate information about the content, thus producing a + * better output. For example, assume that your application is printing + * an image and the print attributes request landscape and fitting mode scale + * to fill. The result of this operation should be the entire media is filled + * and the content is rotated ninety degrees. In this case it is beneficial + * you do the rotation and select a higher resolution image to utilize + * the wider media (the height is now the width), rather to use a lower + * resolution image that is later stretched by the printer. If you applied + * the rotation you have to update the returned print document info to + * reflect that the content is already in landscape by calling + * {@link PrintDocumentInfo.Builder#setOrientation(int)} with {@link + * PrintAttributes#ORIENTATION_LANDSCAPE}. In this case the printer does not + * have to rotate the content. + *

+ *

* Note: 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 diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java index 653ad4bfc4e4..b32961b641cf 100644 --- a/core/java/android/print/PrintDocumentInfo.java +++ b/core/java/android/print/PrintDocumentInfo.java @@ -18,6 +18,8 @@ package android.print; import android.os.Parcel; import android.os.Parcelable; +import android.print.PrintAttributes.Margins; +import android.print.PrintAttributes.MediaSize; import android.text.TextUtils; /** @@ -26,12 +28,17 @@ import android.text.TextUtils; public final class PrintDocumentInfo implements Parcelable { /** - * Constant for unknown page count (default). + * Constant for an unknown media size. + */ + public static final MediaSize MEDIA_SIZE_UNKNOWN = new MediaSize("Unknown", "Unknown", 1, 1); + + /** + * Constant for unknown page count.. */ public static final int PAGE_COUNT_UNKNOWN = -1; /** - * Content type: unknown (default). + * Content type: unknown. */ public static final int CONTENT_TYPE_UNKNOWN = -1; @@ -48,13 +55,17 @@ public final class PrintDocumentInfo implements Parcelable { private String mName; private int mPageCount; private int mContentType; + private int mOrientation; + private int mFittingMode; + private int mColorMode; + private Margins mMargins; + private MediaSize mMediaSize; /** * Creates a new instance. */ private PrintDocumentInfo() { - mPageCount = PAGE_COUNT_UNKNOWN; - mContentType = CONTENT_TYPE_UNKNOWN; + /* do nothing */ } /** @@ -66,6 +77,11 @@ public final class PrintDocumentInfo implements Parcelable { mName = prototype.mName; mPageCount = prototype.mPageCount; mContentType = prototype.mContentType; + mOrientation = prototype.mOrientation; + mFittingMode = prototype.mFittingMode; + mColorMode = prototype.mColorMode; + mMargins = prototype.mMargins; + mMediaSize = prototype.mMediaSize; } /** @@ -77,6 +93,11 @@ public final class PrintDocumentInfo implements Parcelable { mName = parcel.readString(); mPageCount = parcel.readInt(); mContentType = parcel.readInt(); + mOrientation = parcel.readInt(); + mFittingMode = parcel.readInt(); + mColorMode = parcel.readInt(); + mMargins = Margins.createFromParcel(parcel); + mMediaSize = MediaSize.createFromParcel(parcel); } /** @@ -112,6 +133,61 @@ public final class PrintDocumentInfo implements Parcelable { return mContentType; } + /** + * Gets the document orientation. + * + * @return The orientation. + * + * @see PrintAttributes#ORIENTATION_PORTRAIT PrintAttributes.ORIENTATION_PORTRAIT + * @see PrintAttributes#ORIENTATION_LANDSCAPE PrintAttributes.ORIENTATION_LANDSCAPE + */ + public int getOrientation() { + return mOrientation; + } + + /** + * Gets the document fitting mode. + * + * @return The fitting mode. + * + * @see PrintAttributes#FITTING_MODE_NONE PrintAttributes.FITTING_MODE_NONE + * @see PrintAttributes#FITTING_MODE_SCALE_TO_FILL PrintAttributes.FITTING_MODE_SCALE_TO_FILL + * @see PrintAttributes#FITTING_MODE_SCALE_TO_FIT PrintAttributes.FITTING_MODE_SCALE_TO_FIT + */ + public int getFittingMode() { + return mFittingMode; + } + + /** + * Gets document color mode. + * + * @return The color mode. + * + * @see PrintAttributes#COLOR_MODE_COLOR PrintAttributes.COLOR_MODE_COLOR + * @see PrintAttributes#COLOR_MODE_MONOCHROME PrintAttributes.COLOR_MODE_MONOCHROME + */ + public int getColorMode() { + return mColorMode; + } + + /** + * Gets the document margins. + * + * @return The margins. + */ + public Margins getMargins() { + return mMargins; + } + + /** + * Gets the media size. + * + * @return The media size. + */ + public MediaSize getMediaSize() { + return mMediaSize; + } + @Override public int describeContents() { return 0; @@ -122,6 +198,11 @@ public final class PrintDocumentInfo implements Parcelable { parcel.writeString(mName); parcel.writeInt(mPageCount); parcel.writeInt(mContentType); + parcel.writeInt(mOrientation); + parcel.writeInt(mFittingMode); + parcel.writeInt(mColorMode); + mMargins.writeToParcel(parcel); + mMediaSize.writeToParcel(parcel); } @Override @@ -131,6 +212,11 @@ public final class PrintDocumentInfo implements Parcelable { result = prime * result + ((mName != null) ? mName.hashCode() : 0); result = prime * result + mContentType; result = prime * result + mPageCount; + result = prime * result + mOrientation; + result = prime * result + mFittingMode; + result = prime * result + mColorMode; + result = prime * result + (mMargins != null ? mMargins.hashCode() : 0); + result = prime * result + (mMediaSize != null ? mMediaSize.hashCode() : 0); return result; } @@ -155,6 +241,29 @@ public final class PrintDocumentInfo implements Parcelable { if (mPageCount != other.mPageCount) { return false; } + if (mOrientation != other.mOrientation) { + return false; + } + if (mFittingMode != other.mFittingMode) { + return false; + } + if (mColorMode != other.mColorMode) { + 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; + } return true; } @@ -165,6 +274,11 @@ public final class PrintDocumentInfo implements Parcelable { builder.append("name=").append(mName); builder.append(", pageCount=").append(mPageCount); builder.append(", contentType=").append(contentTyepToString(mContentType)); + builder.append(", orientation=").append(PrintAttributes.orientationToString(mOrientation)); + builder.append(", fittingMode=").append(PrintAttributes.fittingModeToString(mFittingMode)); + builder.append(", colorMode=").append(PrintAttributes.colorModeToString(mColorMode)); + builder.append(", margins=").append(mMargins); + builder.append(", mediaSize=").append(mMediaSize); builder.append("}"); return builder.toString(); } @@ -191,21 +305,62 @@ public final class PrintDocumentInfo implements Parcelable { /** * Constructor. + *

+ * The values of the relevant properties are initialized from the + * provided print attributes. For example, the orientation is set + * to be the same as the orientation returned by calling {@link + * PrintAttributes#getOrientation() PrintAttributes.getOrientation()}. + *

* * @param name The document name. Cannot be empty. + * @param attributes Print attributes. Cannot be null. * * @throws IllegalArgumentException If the name is empty. */ + public Builder(String name, PrintAttributes attributes) { + if (TextUtils.isEmpty(name)) { + throw new IllegalArgumentException("name cannot be empty"); + } + if (attributes == null) { + throw new IllegalArgumentException("attributes cannot be null"); + } + mPrototype = new PrintDocumentInfo(); + mPrototype.mName = name; + mPrototype.mOrientation = attributes.getOrientation(); + mPrototype.mFittingMode = attributes.getFittingMode(); + mPrototype.mColorMode = attributes.getColorMode(); + mPrototype.mMargins = attributes.getMargins(); + mPrototype.mMediaSize = attributes.getMediaSize(); + } + + /** + * Constructor. + *

+ * 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. + *

+ * + * @param name The document name. Cannot be empty. + */ public Builder(String name) { if (TextUtils.isEmpty(name)) { throw new IllegalArgumentException("name cannot be empty"); } mPrototype = new PrintDocumentInfo(); mPrototype.mName = name; + mPrototype.mOrientation = PrintAttributes.ORIENTATION_PORTRAIT; + mPrototype.mFittingMode = PrintAttributes.FITTING_MODE_NONE; + mPrototype.mColorMode = PrintAttributes.COLOR_MODE_COLOR; + mPrototype.mMargins = Margins.NO_MARGINS; + mPrototype.mMediaSize = MEDIA_SIZE_UNKNOWN; } /** * Sets the total number of pages. + *

+ * Default: {@link #PAGE_COUNT_UNKNOWN} + *

* * @param pageCount The number of pages. Must be greater than * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}. @@ -222,6 +377,9 @@ public final class PrintDocumentInfo implements Parcelable { /** * Sets the content type. + *

+ * Default: {@link #CONTENT_TYPE_UNKNOWN} + *

* * @param type The content type. * @@ -234,6 +392,95 @@ public final class PrintDocumentInfo implements Parcelable { return this; } + /** + * Sets the orientation. + *

+ * Default: {@link PrintAttributes#ORIENTATION_PORTRAIT + * PrintAttributes.ORIENTATION_PORTRAIT} + *

+ * + * @param orientation The orientation. + * + * @see PrintAttributes#ORIENTATION_PORTRAIT PrintAttributes.ORIENTATION_PORTRAIT + * @see PrintAttributes#ORIENTATION_LANDSCAPE PrintAttributes.ORIENTATION_LANDSCAPE + */ + public Builder setOrientation(int orientation) { + PrintAttributes.enforceValidOrientation(orientation); + mPrototype.mOrientation = orientation; + return this; + } + + /** + * Sets the content fitting mode. + *

+ * Default: {@link PrintAttributes#FITTING_MODE_NONE + * PrintAttributes.FITTING_MODE_NONE} + *

+ * + * @param fittingMode The fitting mode. + * + * @see PrintAttributes#FITTING_MODE_NONE PrintAttributes.FITTING_MODE_NONE + * @see PrintAttributes#FITTING_MODE_SCALE_TO_FILL PrintAttributes.FITTING_MODE_SCALE_TO_FILL + * @see PrintAttributes#FITTING_MODE_SCALE_TO_FIT PrintAttributes.FITTING_MODE_SCALE_TO_FIT + */ + public Builder setFittingMode(int fittingMode) { + PrintAttributes.enforceValidFittingMode(fittingMode); + mPrototype.mFittingMode = fittingMode; + return this; + } + + /** + * Sets the content color mode. + *

+ * Default: {@link PrintAttributes#COLOR_MODE_COLOR + * PrintAttributes.COLOR_MODE_COLOR} + *

+ * + * @param colorMode The color mode. + * + * @see PrintAttributes#COLOR_MODE_COLOR PrintAttributes.COLOR_MODE_COLOR + * @see PrintAttributes#COLOR_MODE_MONOCHROME PrintAttributes.COLOR_MODE_MONOCHROME + */ + public Builder setColorMode(int colorMode) { + PrintAttributes.enforceValidColorMode(colorMode); + mPrototype.mColorMode = colorMode; + return this; + } + + /** + * Sets the document margins. + *

+ * Default: {@link PrintAttributes.Margins#NO_MARGINS Margins.NO_MARGINS} + *

+ * + * @param margins The margins. Cannot be null. + */ + public Builder setMargins(Margins margins) { + if (margins == null) { + throw new IllegalArgumentException("margins cannot be null"); + } + mPrototype.mMargins = margins; + return this; + } + + /** + * Sets the document media size. + *

+ * Default: #MEDIA_SIZE_UNKNOWN + *

+ * + * @param mediaSize The media size. Cannot be null. + * + * @see #MEDIA_SIZE_UNKNOWN + */ + public Builder setMediaSize(MediaSize mediaSize) { + if (mediaSize == null) { + throw new IllegalArgumentException("media size cannot be null"); + } + mPrototype.mMediaSize = mediaSize; + return this; + } + /** * Creates a new {@link PrintDocumentInfo} instance. * diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java index 70b418c2a145..941e6e1f7d2c 100644 --- a/core/java/android/print/PrinterCapabilitiesInfo.java +++ b/core/java/android/print/PrinterCapabilitiesInfo.java @@ -863,12 +863,12 @@ public final class PrinterCapabilitiesInfo implements Parcelable { while (currentModes > 0) { final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); currentModes &= ~currentMode; - PrintAttributes.enfoceValidFittingMode(currentMode); + PrintAttributes.enforceValidFittingMode(currentMode); } if ((fittingModes & defaultFittingMode) == 0) { throw new IllegalArgumentException("Default fitting mode not in fiting modes."); } - PrintAttributes.enfoceValidFittingMode(defaultFittingMode); + PrintAttributes.enforceValidFittingMode(defaultFittingMode); mPrototype.mFittingModes = fittingModes; mPrototype.mDefaults[PROPERTY_FITTING_MODE] = defaultFittingMode; return this; diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java index 6f567a64d709..0ea319be8b1d 100644 --- a/core/java/android/print/PrinterInfo.java +++ b/core/java/android/print/PrinterInfo.java @@ -25,10 +25,14 @@ import android.text.TextUtils; */ public final class PrinterInfo implements Parcelable { - /** Printer status: the printer is ready to print. */ - public static final int STATUS_READY = 1; + /** Printer status: the printer is idle and ready to print. */ + public static final int STATUS_IDLE = 1; - // TODO: Add printer status constants. + /** Printer status: the printer is busy printing. */ + public static final int STATUS_BUSY = 2; + + /** Printer status: the printer is not available. */ + public static final int STATUS_UNAVAILABLE = 3; private PrinterId mId; @@ -236,6 +240,21 @@ public final class PrinterInfo implements Parcelable { mPrototype.copyFrom(other); } + /** + * Sets the printer status. + * + * @param status The status. + * @return This builder. + * + * @see PrinterInfo#STATUS_IDLE + * @see PrinterInfo#STATUS_BUSY + * @see PrinterInfo#STATUS_UNAVAILABLE + */ + public Builder setStatus(int status) { + mPrototype.mStatus = status; + return this; + } + /** * Sets the printer name. * @@ -279,7 +298,9 @@ public final class PrinterInfo implements Parcelable { } private boolean isValidStatus(int status) { - return (status == PrinterInfo.STATUS_READY); + return (status == STATUS_IDLE + || status == STATUS_IDLE + || status == STATUS_UNAVAILABLE); } } diff --git a/core/java/android/print/pdf/PdfDocument.java b/core/java/android/print/pdf/PdfDocument.java index dbd7dd1448c5..a2883cf83e3a 100644 --- a/core/java/android/print/pdf/PdfDocument.java +++ b/core/java/android/print/pdf/PdfDocument.java @@ -44,7 +44,7 @@ import java.util.List; * PdfDocument document = PdfDocument.open(); * * // crate a page description - * PageInfo pageInfo = new PageInfo.Builder(new Rect(0, 0, 100, 100), 1, 300).create(); + * PageInfo pageInfo = new PageInfo.Builder(new Rect(0, 0, 100, 100), 1).create(); * * // start a page * Page page = document.startPage(pageInfo); @@ -125,8 +125,7 @@ public final class PdfDocument { throw new IllegalStateException("Previous page not finished!"); } Canvas canvas = new PdfCanvas(nativeCreatePage(pageInfo.mPageSize, - pageInfo.mContentSize, pageInfo.mInitialTransform.native_instance), - pageInfo.mDensity); + pageInfo.mContentSize, pageInfo.mInitialTransform.native_instance)); mCurrentPage = new Page(canvas, pageInfo); return mCurrentPage; } @@ -230,25 +229,14 @@ public final class PdfDocument { private final class PdfCanvas extends Canvas { - public PdfCanvas(int nativeCanvas, int density) { + public PdfCanvas(int nativeCanvas) { super(nativeCanvas); - super.setDensity(density); } @Override public void setBitmap(Bitmap bitmap) { throw new UnsupportedOperationException(); } - - @Override - public void setDensity(int density) { - throw new UnsupportedOperationException(); - } - - @Override - public void setScreenDensity(int density) { - throw new UnsupportedOperationException(); - } } /** @@ -259,7 +247,6 @@ public final class PdfDocument { private Rect mContentSize; private Matrix mInitialTransform; private int mPageNumber; - private int mDensity; /** * Creates a new instance. @@ -269,7 +256,7 @@ public final class PdfDocument { } /** - * Gets the page size in pixels. + * Gets the page size in PostScript points (1/72th of an inch). * * @return The page size. */ @@ -278,7 +265,7 @@ public final class PdfDocument { } /** - * Get the content size in pixels. + * Get the content size in PostScript points (1/72th of an inch). * * @return The content size. */ @@ -306,15 +293,6 @@ public final class PdfDocument { return mPageNumber; } - /** - * Gets the density of the page in DPI. - * - * @return The density. - */ - public int getDesity() { - return mDensity; - } - /** * Builder for creating a {@link PageInfo}. */ @@ -324,11 +302,10 @@ public final class PdfDocument { /** * Creates a new builder with the mandatory page info attributes. * - * @param pageSize The page size in points, not dips. + * @param pageSize The page size in PostScript (1/72th of an inch). * @param pageNumber The page number. - * @param density The page density in DPI. */ - public Builder(Rect pageSize, int pageNumber, int density) { + public Builder(Rect pageSize, int pageNumber) { if (pageSize.width() == 0 || pageSize.height() == 0) { throw new IllegalArgumentException("page width and height" + " must be greater than zero!"); @@ -336,16 +313,12 @@ public final class PdfDocument { if (pageNumber < 0) { throw new IllegalArgumentException("pageNumber cannot be less than zero!"); } - if (density <= 0) { - throw new IllegalArgumentException("density must be greater than zero!"); - } mPageInfo.mPageSize = pageSize; mPageInfo.mPageNumber = pageNumber; - mPageInfo.mDensity = density; } /** - * Sets the content size in pixels. + * Sets the content size in PostScript point (1/72th of an inch). * * @param contentSize The content size. */ diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java new file mode 100644 index 000000000000..a3be38bb1f71 --- /dev/null +++ b/core/java/android/print/pdf/PrintedPdfDocument.java @@ -0,0 +1,162 @@ +/* + * 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.pdf; + +import android.content.Context; +import android.graphics.Rect; +import android.print.PrintAttributes; +import android.print.PrintAttributes.Margins; +import android.print.PrintAttributes.MediaSize; +import android.print.pdf.PdfDocument; +import android.print.pdf.PdfDocument.Page; +import android.print.pdf.PdfDocument.PageInfo; + +import java.io.OutputStream; +import java.util.List; + +/** + * This class is a helper for printing content to a different media + * size. This class is responsible for computing a correct page size + * given some print constraints, i.e. {@link PrintAttributes}. It is + * an adapter around a {@link PdfDocument}. + */ +public final class PrintedPdfDocument { + private static final int MILS_PER_INCH = 1000; + private static final int POINTS_IN_INCH = 72; + + private final PdfDocument mDocument = PdfDocument.open(); + private final Rect mPageSize = new Rect(); + private final Rect mContentSize = new Rect(); + + /** + * Opens a new document. The document pages are computed based on + * the passes in {@link PrintAttributes}. + *

+ * Note: You must close the document after you are + * done by calling {@link #close()} + *

+ * + * @param context Context instance for accessing resources. + * @param attributes The print attributes. + * @return The document. + * + * @see #close() + */ + public static PrintedPdfDocument open(Context context, PrintAttributes attributes) { + return new PrintedPdfDocument(context, attributes); + } + + /** + * Creates a new instance. + * + * @param context Context instance for accessing resources and services. + * @param attributes The {@link PrintAttributes} to user. + */ + private PrintedPdfDocument(Context context, PrintAttributes attributes) { + MediaSize mediaSize = attributes.getMediaSize(); + + // Compute the size of the target canvas from the attributes. + final int pageWidth = (int) (((float) mediaSize.getWidthMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + final int pageHeight = (int) (((float) mediaSize.getHeightMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + mPageSize.set(0, 0, pageWidth, pageHeight); + + // Compute the content size from the attributes. + Margins margins = attributes.getMargins(); + final int marginLeft = (int) (((float) margins.getLeftMils() /MILS_PER_INCH) + * POINTS_IN_INCH); + final int marginTop = (int) (((float) margins.getTopMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + final int marginRight = (int) (((float) margins.getRightMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + final int marginBottom = (int) (((float) margins.getBottomMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + mContentSize.set(mPageSize.left + marginLeft, mPageSize.top + marginTop, + mPageSize.right - marginRight, mPageSize.bottom - marginBottom); + } + + /** + * Starts a page using a page size computed from the print attributes + * passed in {@link #open(Context, PrintAttributes)} and the given page + * number to create appropriate {@link PageInfo}. + *

+ * After the page is created you can draw arbitrary content on the page's + * canvas which you can get by calling {@link Page#getCanvas() Page.getCanvas()}. + * After you are done drawing the content you should finish the page by calling + * {@link #finishPage(Page)}. After the page is finished you should no longer + * access the page or its canvas. + *

+ *

+ * Note: Do not call this method after {@link #close()}. + *

+ * + * @param pageNumber The page number. + * @return A blank page. + * + * @see #finishPage(Page) + */ + public Page startPage(int pageNumber) { + PageInfo pageInfo = new PageInfo.Builder(mPageSize, 0).create(); + Page page = mDocument.startPage(pageInfo); + return page; + } + + /** + * Finishes a started page. You should always finish the last started page. + *

+ * Note: Do not call this method after {@link #close()}. + *

+ * + * @param page The page. + * + * @see #startPage(int) + */ + public void finishPage(Page page) { + mDocument.finishPage(page); + } + + /** + * Writes the document to an output stream. + *

+ * Note: Do not call this method after {@link #close()}. + *

+ * + * @param out The output stream. + */ + public void writeTo(OutputStream out) { + mDocument.writeTo(out); + } + + /** + * Gets the pages of the document. + * + * @return The pages. + */ + public List getPages() { + return mDocument.getPages(); + } + + /** + * Closes this document. This method should be called after you + * are done working with the document. After this call the document + * is considered closed and none of its methods should be called. + */ + public void close() { + mDocument.close(); + } +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index c01d8f83190f..607be9050bbd 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -42,6 +42,7 @@ import android.print.IPrintDocumentAdapter; import android.print.IWriteResultCallback; import android.print.PageRange; import android.print.PrintAttributes; +import android.print.PrintAttributes.Margins; import android.print.PrintAttributes.MediaSize; import android.print.PrintAttributes.Resolution; import android.print.PrintDocumentAdapter; @@ -388,14 +389,20 @@ public class PrintJobConfigActivity extends Activity { final boolean infoChanged = !info.equals(mDocument.info); if (infoChanged) { mDocument.info = info; + // Set the info. PrintSpoolerService.peekInstance().setPrintJobPrintDocumentInfoNoPersistence( mPrintJobId, info); } + // Update the fitting mode based on the document type. + updateCurrentFittingMode(info); + // If the document info or the layout changed, then // drop the pages since we have to fetch them again. if (infoChanged || layoutChanged) { mDocument.pages = null; + PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence( + mPrintJobId, null); } // No pages means that the user selected an invalid range while we @@ -489,7 +496,7 @@ public class PrintJobConfigActivity extends Activity { } else if (PageRangeUtils.contains(mDocument.pages, mRequestedPages)) { // We requested specific pages and got more but not all pages. // Hence, we have to offset appropriately the printed pages to - // excle the pages we did not request. Note that pages is + // exclude the pages we did not request. Note that pages is // guaranteed to be not null and not empty. final int offset = mDocument.pages[0].getStart() - pages[0].getStart(); PageRange[] offsetPages = Arrays.copyOf(mDocument.pages, mDocument.pages.length); @@ -514,6 +521,10 @@ public class PrintJobConfigActivity extends Activity { } if (mEditor.isDone()) { + // Update the print attributes based on whether the application + // handled some of the print attribute constraints, e.g. rotation. + updateAndSaveCurrentPrintAttributes(mDocument.info); + if (mEditor.isPrintingToPdf()) { PrintJobInfo printJob = PrintSpoolerService.peekInstance() .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY); @@ -536,6 +547,58 @@ public class PrintJobConfigActivity extends Activity { PrintJobConfigActivity.this.finish(); } + private void updateCurrentFittingMode(PrintDocumentInfo document) { + // Update the fitting mode based on content type. + switch (document.getContentType()) { + case PrintDocumentInfo.CONTENT_TYPE_DOCUMENT: { + mCurrPrintAttributes.setFittingMode( + PrintAttributes.FITTING_MODE_SCALE_TO_FIT); + } break; + + case PrintDocumentInfo.CONTENT_TYPE_PHOTO: { + mCurrPrintAttributes.setFittingMode( + PrintAttributes.FITTING_MODE_SCALE_TO_FILL); + } + } + } + + private void updateAndSaveCurrentPrintAttributes(PrintDocumentInfo document) { + PrintAttributes attributes = mTempPrintAttributes; + attributes.copyFrom(mCurrPrintAttributes); + + // Update the orientation + if (document.getOrientation() == PrintAttributes.ORIENTATION_LANDSCAPE) { + if (attributes.getOrientation() == PrintAttributes.ORIENTATION_LANDSCAPE) { + // If the document is in landscape and we want to print it in + // landscape, then we do not need to rotate, so portrait. + attributes.setOrientation(PrintAttributes.ORIENTATION_PORTRAIT); + } else { + // If the document is in landscape and we want to print it in + // portrait, then we have to rotate the content, so landscape. + attributes.setOrientation(PrintAttributes.ORIENTATION_LANDSCAPE); + } + } + + // Update margins. + Margins documentMargins = document.getMargins(); + if (documentMargins.getLeftMils() != 0 + || documentMargins.getTopMils() != 0 + || documentMargins.getRightMils() != 0 + || documentMargins.getBottomMils() != 0) { + // If the application has applied some of the margins, then + // the printer should only apply the difference. + Margins oldMargins = attributes.getMargins(); + attributes.setMargins(new Margins( + oldMargins.getLeftMils() - documentMargins.getLeftMils(), + oldMargins.getTopMils() - documentMargins.getTopMils(), + oldMargins.getRightMils() - documentMargins.getRightMils(), + oldMargins.getBottomMils() - documentMargins.getBottomMils())); + } + + PrintSpoolerService.peekInstance().setPrintJobAttributesNoPersistence( + mPrintJobId, attributes); + } + private final class ControllerHandler extends Handler { public static final int MSG_ON_LAYOUT_FINISHED = 1; public static final int MSG_ON_LAYOUT_FAILED = 2; @@ -1409,8 +1472,6 @@ public class PrintJobConfigActivity extends Activity { mOrientationSpinner.setEnabled(false); mRangeOptionsSpinner.setEnabled(false); mPageRangeEditText.setEnabled(false); - // TODO: Remove entirely or implement print preview. -// mPrintPreviewButton.setEnabled(false); mPrintButton.setEnabled(false); return false; } @@ -1474,10 +1535,6 @@ public class PrintJobConfigActivity extends Activity { mPageRangeEditText.setVisibility(View.INVISIBLE); mPageRangeTitle.setVisibility(View.INVISIBLE); -// // Print preview -// mPrintPreviewButton.setEnabled(false); -// mPrintPreviewButton.setText(getString(R.string.print_preview)); - // Print mPrintButton.setEnabled(false); @@ -1548,6 +1605,8 @@ public class PrintJobConfigActivity extends Activity { // Color mode. final int colorModes = capabilities.getColorModes(); + + // If the color modes changed, we update the adapter and the spinner. boolean colorModesChanged = false; if (Integer.bitCount(colorModes) != mColorModeSpinnerAdapter.getCount()) { colorModesChanged = true; @@ -1567,6 +1626,11 @@ public class PrintJobConfigActivity extends Activity { } } if (colorModesChanged) { + // Remember the old color mode to try selecting it again. + int oldColorModeNewIndex = AdapterView.INVALID_POSITION; + final int oldColorMode = mCurrPrintAttributes.getColorMode(); + + // Rebuild the adapter data. mColorModeSpinnerAdapter.clear(); String[] colorModeLabels = getResources().getStringArray( R.array.color_mode_labels); @@ -1575,6 +1639,10 @@ public class PrintJobConfigActivity extends Activity { final int colorBitOffset = Integer.numberOfTrailingZeros( remainingColorModes); final int colorMode = 1 << colorBitOffset; + if (colorMode == oldColorMode) { + // Update the index of the old selection. + oldColorModeNewIndex = colorBitOffset; + } remainingColorModes &= ~colorMode; mColorModeSpinnerAdapter.add(new SpinnerItem(colorMode, colorModeLabels[colorBitOffset])); @@ -1585,11 +1653,14 @@ public class PrintJobConfigActivity extends Activity { mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION); } else { mColorModeSpinner.setEnabled(true); - final int selectedColorModeIndex = Integer.numberOfTrailingZeros( - (colorModes & defaultAttributes.getColorMode())); - if (mColorModeSpinner.getSelectedItemPosition() != selectedColorModeIndex) { - mIgnoreNextColorModeChange = true; - mColorModeSpinner.setSelection(selectedColorModeIndex); + if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) { + // Select the old color mode - nothing really changed. + setColorModeSpinnerSelectionNoCallback(oldColorModeNewIndex); + } else { + final int selectedColorModeIndex = Integer.numberOfTrailingZeros( + (colorModes & defaultAttributes.getColorMode())); + someAttributeSelectionChanged = setColorModeSpinnerSelectionNoCallback( + selectedColorModeIndex); } } } @@ -1597,6 +1668,8 @@ public class PrintJobConfigActivity extends Activity { // Orientation. final int orientations = capabilities.getOrientations(); + + // If the orientations changed, we update the adapter and the spinner. boolean orientationsChanged = false; if (Integer.bitCount(orientations) != mOrientationSpinnerAdapter.getCount()) { orientationsChanged = true; @@ -1617,6 +1690,10 @@ public class PrintJobConfigActivity extends Activity { } } if (orientationsChanged) { + // Remember the old orientation to try selecting it again. + int oldOrientationNewIndex = AdapterView.INVALID_POSITION; + final int oldOrientation = mCurrPrintAttributes.getOrientation(); + mOrientationSpinnerAdapter.clear(); String[] orientationLabels = getResources().getStringArray( R.array.orientation_labels); @@ -1625,6 +1702,10 @@ public class PrintJobConfigActivity extends Activity { final int orientationBitOffset = Integer.numberOfTrailingZeros( remainingOrientations); final int orientation = 1 << orientationBitOffset; + if (orientation == oldOrientation) { + // Update the index of the old selection. + oldOrientationNewIndex = orientationBitOffset; + } remainingOrientations &= ~orientation; mOrientationSpinnerAdapter.add(new SpinnerItem(orientation, orientationLabels[orientationBitOffset])); @@ -1635,12 +1716,15 @@ public class PrintJobConfigActivity extends Activity { mOrientationSpinner.setSelection(AdapterView.INVALID_POSITION); } else { mOrientationSpinner.setEnabled(true); - final int selectedOrientationIndex = Integer.numberOfTrailingZeros( - (orientations & defaultAttributes.getOrientation())); - if (mOrientationSpinner.getSelectedItemPosition() - != selectedOrientationIndex) { - mIgnoreNextOrientationChange = true; - mOrientationSpinner.setSelection(selectedOrientationIndex); + if (oldOrientationNewIndex != AdapterView.INVALID_POSITION) { + // Select the old orientation - nothing really changed. + setOrientationSpinnerSelectionNoCallback(oldOrientationNewIndex); + } else { + final int selectedOrientationIndex = Integer.numberOfTrailingZeros( + (orientations & defaultAttributes.getOrientation())); + someAttributeSelectionChanged = + setOrientationSpinnerSelectionNoCallback( + selectedOrientationIndex); } } } @@ -1648,23 +1732,27 @@ public class PrintJobConfigActivity extends Activity { // Range options PrintDocumentInfo info = mDocument.info; - if (info != null && (info.getPageCount() > 1 + if (info != null && (info.getPageCount() > 0 || info.getPageCount() == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) { - mRangeOptionsSpinner.setEnabled(true); - if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) { - if (!mPageRangeEditText.isEnabled()) { - mPageRangeEditText.setEnabled(true); - mPageRangeEditText.setVisibility(View.VISIBLE); - mPageRangeTitle.setVisibility(View.VISIBLE); - mPageRangeEditText.requestFocus(); - InputMethodManager imm = (InputMethodManager) - getSystemService(INPUT_METHOD_SERVICE); - imm.showSoftInput(mPageRangeEditText, 0); - } + if (info.getPageCount() == 1) { + mRangeOptionsSpinner.setEnabled(false); } else { - mPageRangeEditText.setEnabled(false); - mPageRangeEditText.setVisibility(View.INVISIBLE); - mPageRangeTitle.setVisibility(View.INVISIBLE); + mRangeOptionsSpinner.setEnabled(true); + if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) { + if (!mPageRangeEditText.isEnabled()) { + mPageRangeEditText.setEnabled(true); + mPageRangeEditText.setVisibility(View.VISIBLE); + mPageRangeTitle.setVisibility(View.VISIBLE); + mPageRangeEditText.requestFocus(); + InputMethodManager imm = (InputMethodManager) + getSystemService(INPUT_METHOD_SERVICE); + imm.showSoftInput(mPageRangeEditText, 0); + } + } else { + mPageRangeEditText.setEnabled(false); + mPageRangeEditText.setVisibility(View.INVISIBLE); + mPageRangeTitle.setVisibility(View.INVISIBLE); + } } final int pageCount = mDocument.info.getPageCount(); mRangeOptionsTitle.setText(getString(R.string.label_pages, @@ -1702,15 +1790,8 @@ public class PrintJobConfigActivity extends Activity { && (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors())) || (mRangeOptionsSpinner.getSelectedItemPosition() == 0 && (!mController.hasPerformedLayout() || hasErrors()))) { -// mPrintPreviewButton.setEnabled(false); mPrintButton.setEnabled(false); } else { -// mPrintPreviewButton.setEnabled(true); -// if (hasPdfViewer()) { -// mPrintPreviewButton.setText(getString(R.string.print_preview)); -// } else { -// mPrintPreviewButton.setText(getString(R.string.install_for_print_preview)); -// } mPrintButton.setEnabled(true); } @@ -1742,6 +1823,24 @@ public class PrintJobConfigActivity extends Activity { return false; } + private boolean setColorModeSpinnerSelectionNoCallback(int position) { + if (mColorModeSpinner.getSelectedItemPosition() != position) { + mIgnoreNextColorModeChange = true; + mColorModeSpinner.setSelection(position); + return true; + } + return false; + } + + private boolean setOrientationSpinnerSelectionNoCallback(int position) { + if (mOrientationSpinner.getSelectedItemPosition() != position) { + mIgnoreNextOrientationChange = true; + mOrientationSpinner.setSelection(position); + return true; + } + return false; + } + private void updateUiForNewPrinterCapabilities() { // The printer changed so we want to start with a clean slate // for the print options and let them be populated from the @@ -1786,13 +1885,6 @@ public class PrintJobConfigActivity extends Activity { && mPageRangeEditText.getError() != null; } -// private boolean hasPdfViewer() { -// Intent intent = new Intent(Intent.ACTION_VIEW); -// intent.setType("application/pdf"); -// return !getPackageManager().queryIntentActivities(intent, -// PackageManager.MATCH_DEFAULT_ONLY).isEmpty(); -// } - private final class SpinnerItem { final T value; CharSequence label; @@ -1998,7 +2090,7 @@ public class PrintJobConfigActivity extends Activity { .create(); return new PrinterInfo.Builder(printerId, getString(R.string.save_as_pdf), - PrinterInfo.STATUS_READY) + PrinterInfo.STATUS_IDLE) .setCapabilities(capabilities) .create(); } -- cgit v1.2.3-59-g8ed1b