diff options
-rw-r--r-- | api/current.txt | 7 | ||||
-rw-r--r-- | api/system-current.txt | 7 | ||||
-rw-r--r-- | core/java/android/print/PrintAttributes.java | 109 | ||||
-rw-r--r-- | core/java/android/print/PrinterCapabilitiesInfo.java | 91 | ||||
-rw-r--r-- | packages/PrintSpooler/res/layout/print_activity_controls.xml | 28 | ||||
-rw-r--r-- | packages/PrintSpooler/res/values/strings.xml | 15 | ||||
-rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java | 11 | ||||
-rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java | 108 |
8 files changed, 359 insertions, 17 deletions
diff --git a/api/current.txt b/api/current.txt index 123d8cc..0c77904 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23234,6 +23234,7 @@ package android.print { public final class PrintAttributes implements android.os.Parcelable { method public int describeContents(); method public int getColorMode(); + method public int getDuplexMode(); method public android.print.PrintAttributes.MediaSize getMediaSize(); method public android.print.PrintAttributes.Margins getMinMargins(); method public android.print.PrintAttributes.Resolution getResolution(); @@ -23241,12 +23242,16 @@ package android.print { field public static final int COLOR_MODE_COLOR = 2; // 0x2 field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1 field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR; + 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 } public static final class PrintAttributes.Builder { ctor public PrintAttributes.Builder(); method public android.print.PrintAttributes build(); method public android.print.PrintAttributes.Builder setColorMode(int); + method public android.print.PrintAttributes.Builder setDuplexMode(int); method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize); method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins); method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution); @@ -23464,6 +23469,7 @@ package android.print { method public int describeContents(); method public int getColorModes(); method public android.print.PrintAttributes getDefaults(); + method public int getDuplexModes(); method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes(); method public android.print.PrintAttributes.Margins getMinMargins(); method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions(); @@ -23477,6 +23483,7 @@ package android.print { method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean); method public android.print.PrinterCapabilitiesInfo build(); method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int); + method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int); method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins); } diff --git a/api/system-current.txt b/api/system-current.txt index 6224dfb..8597e25 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -24823,6 +24823,7 @@ package android.print { public final class PrintAttributes implements android.os.Parcelable { method public int describeContents(); method public int getColorMode(); + method public int getDuplexMode(); method public android.print.PrintAttributes.MediaSize getMediaSize(); method public android.print.PrintAttributes.Margins getMinMargins(); method public android.print.PrintAttributes.Resolution getResolution(); @@ -24830,12 +24831,16 @@ package android.print { field public static final int COLOR_MODE_COLOR = 2; // 0x2 field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1 field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR; + 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 } public static final class PrintAttributes.Builder { ctor public PrintAttributes.Builder(); method public android.print.PrintAttributes build(); method public android.print.PrintAttributes.Builder setColorMode(int); + method public android.print.PrintAttributes.Builder setDuplexMode(int); method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize); method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins); method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution); @@ -25053,6 +25058,7 @@ package android.print { method public int describeContents(); method public int getColorModes(); method public android.print.PrintAttributes getDefaults(); + method public int getDuplexModes(); method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes(); method public android.print.PrintAttributes.Margins getMinMargins(); method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions(); @@ -25066,6 +25072,7 @@ package android.print { method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean); method public android.print.PrinterCapabilitiesInfo build(); method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int); + method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int); method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins); } diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java index 30f0c6a..90d30d6 100644 --- a/core/java/android/print/PrintAttributes.java +++ b/core/java/android/print/PrintAttributes.java @@ -45,11 +45,22 @@ public final class PrintAttributes implements Parcelable { private static final int VALID_COLOR_MODES = COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR; + /** Duplex mode: No duplexing. */ + public static final int DUPLEX_MODE_NONE = 1 << 0; + /** Duplex mode: Pages are turned sideways along the long edge - like a book. */ + public static final int DUPLEX_MODE_LONG_EDGE = 1 << 1; + /** Duplex mode: Pages are turned upwards along the short edge - like a notpad. */ + public static final int DUPLEX_MODE_SHORT_EDGE = 1 << 2; + + private static final int VALID_DUPLEX_MODES = + DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE; + private MediaSize mMediaSize; private Resolution mResolution; private Margins mMinMargins; private int mColorMode; + private int mDuplexMode = DUPLEX_MODE_NONE; PrintAttributes() { /* hide constructor */ @@ -60,6 +71,7 @@ public final class PrintAttributes implements Parcelable { mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null; mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null; mColorMode = parcel.readInt(); + mDuplexMode = parcel.readInt(); } /** @@ -74,7 +86,7 @@ public final class PrintAttributes implements Parcelable { /** * Sets the media size. * - * @param The media size. + * @param mediaSize The media size. * * @hide */ @@ -94,7 +106,7 @@ public final class PrintAttributes implements Parcelable { /** * Sets the resolution. * - * @param The resolution. + * @param resolution The resolution. * * @hide */ @@ -130,7 +142,7 @@ public final class PrintAttributes implements Parcelable { * </strong> * </p> * - * @param The margins. + * @param margins The margins. * * @hide */ @@ -153,7 +165,7 @@ public final class PrintAttributes implements Parcelable { /** * Sets the color mode. * - * @param The color mode. + * @param colorMode The color mode. * * @see #COLOR_MODE_MONOCHROME * @see #COLOR_MODE_COLOR @@ -179,6 +191,35 @@ public final class PrintAttributes implements Parcelable { } /** + * Gets the duplex mode. + * + * @return The duplex mode. + * + * @see #DUPLEX_MODE_NONE + * @see #DUPLEX_MODE_LONG_EDGE + * @see #DUPLEX_MODE_SHORT_EDGE + */ + public int getDuplexMode() { + return mDuplexMode; + } + + /** + * Sets the duplex mode. + * + * @param duplexMode The duplex mode. + * + * @see #DUPLEX_MODE_NONE + * @see #DUPLEX_MODE_LONG_EDGE + * @see #DUPLEX_MODE_SHORT_EDGE + * + * @hide + */ + public void setDuplexMode(int duplexMode) { + enforceValidDuplexMode(duplexMode); + mDuplexMode = duplexMode; + } + + /** * Gets a new print attributes instance which is in portrait orientation, * which is the media size is in portrait and all orientation dependent * attributes such as resolution and margins are properly adjusted. @@ -211,6 +252,7 @@ public final class PrintAttributes implements Parcelable { attributes.setMinMargins(getMinMargins()); attributes.setColorMode(getColorMode()); + attributes.setDuplexMode(getDuplexMode()); return attributes; } @@ -248,6 +290,7 @@ public final class PrintAttributes implements Parcelable { attributes.setMinMargins(getMinMargins()); attributes.setColorMode(getColorMode()); + attributes.setDuplexMode(getDuplexMode()); return attributes; } @@ -273,6 +316,7 @@ public final class PrintAttributes implements Parcelable { parcel.writeInt(0); } parcel.writeInt(mColorMode); + parcel.writeInt(mDuplexMode); } @Override @@ -285,6 +329,7 @@ public final class PrintAttributes implements Parcelable { final int prime = 31; int result = 1; result = prime * result + mColorMode; + result = prime * result + mDuplexMode; result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode()); result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode()); result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode()); @@ -306,6 +351,9 @@ public final class PrintAttributes implements Parcelable { if (mColorMode != other.mColorMode) { return false; } + if (mDuplexMode != other.mDuplexMode) { + return false; + } if (mMinMargins == null) { if (other.mMinMargins != null) { return false; @@ -344,6 +392,7 @@ public final class PrintAttributes implements Parcelable { builder.append(", resolution: ").append(mResolution); builder.append(", minMargins: ").append(mMinMargins); builder.append(", colorMode: ").append(colorModeToString(mColorMode)); + builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode)); builder.append("}"); return builder.toString(); } @@ -354,6 +403,7 @@ public final class PrintAttributes implements Parcelable { mResolution = null; mMinMargins = null; mColorMode = 0; + mDuplexMode = DUPLEX_MODE_NONE; } /** @@ -364,6 +414,7 @@ public final class PrintAttributes implements Parcelable { mResolution = other.mResolution; mMinMargins = other.mMinMargins; mColorMode = other.mColorMode; + mDuplexMode = other.mDuplexMode; } /** @@ -1270,17 +1321,41 @@ public final class PrintAttributes implements Parcelable { case COLOR_MODE_COLOR: { return "COLOR_MODE_COLOR"; } - default: + default: { return "COLOR_MODE_UNKNOWN"; + } + } + } + + static String duplexModeToString(int duplexMode) { + switch (duplexMode) { + case DUPLEX_MODE_NONE: { + return "DUPLEX_MODE_NONE"; + } + case DUPLEX_MODE_LONG_EDGE: { + return "DUPLEX_MODE_LONG_EDGE"; + } + case DUPLEX_MODE_SHORT_EDGE: { + return "DUPLEX_MODE_SHORT_EDGE"; + } + default: { + return "DUPLEX_MODE_UNKNOWN"; + } } } static void enforceValidColorMode(int colorMode) { - if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) { + if ((colorMode & VALID_COLOR_MODES) == 0 || Integer.bitCount(colorMode) != 1) { throw new IllegalArgumentException("invalid color mode: " + colorMode); } } + static void enforceValidDuplexMode(int duplexMode) { + if ((duplexMode & VALID_DUPLEX_MODES) == 0 || Integer.bitCount(duplexMode) != 1) { + throw new IllegalArgumentException("invalid duplex mode: " + duplexMode); + } + } + /** * Builder for creating {@link PrintAttributes}. */ @@ -1331,15 +1406,31 @@ public final class PrintAttributes implements Parcelable { * @see PrintAttributes#COLOR_MODE_COLOR */ public Builder setColorMode(int colorMode) { - if (Integer.bitCount(colorMode) > 1) { - throw new IllegalArgumentException("can specify at most one colorMode bit."); - } mAttributes.setColorMode(colorMode); return this; } /** + * Sets the duplex mode. + * + * @param duplexMode A valid duplex mode or zero. + * @return This builder. + * + * @see PrintAttributes#DUPLEX_MODE_NONE + * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE + * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE + */ + public Builder setDuplexMode(int duplexMode) { + mAttributes.setDuplexMode(duplexMode); + return this; + } + + /** * Creates a new {@link PrintAttributes} instance. + * <p> + * If you do not specify a duplex mode, the default + * {@link #DUPLEX_MODE_NONE} will be used. + * </p> * * @return The new instance. */ diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java index 806a89d..96f3185 100644 --- a/core/java/android/print/PrinterCapabilitiesInfo.java +++ b/core/java/android/print/PrinterCapabilitiesInfo.java @@ -47,7 +47,8 @@ public final class PrinterCapabilitiesInfo implements Parcelable { private static final int PROPERTY_MEDIA_SIZE = 0; private static final int PROPERTY_RESOLUTION = 1; private static final int PROPERTY_COLOR_MODE = 2; - private static final int PROPERTY_COUNT = 3; + private static final int PROPERTY_DUPLEX_MODE = 3; + private static final int PROPERTY_COUNT = 4; private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0); @@ -56,6 +57,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable { private List<Resolution> mResolutions; private int mColorModes; + private int mDuplexModes; private final int[] mDefaults = new int[PROPERTY_COUNT]; @@ -106,6 +108,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable { } mColorModes = other.mColorModes; + mDuplexModes = other.mDuplexModes; final int defaultCount = other.mDefaults.length; for (int i = 0; i < defaultCount; i++) { @@ -154,6 +157,19 @@ public final class PrinterCapabilitiesInfo implements Parcelable { } /** + * Gets the bit mask of supported duplex modes. + * + * @return The bit mask of supported duplex modes. + * + * @see PrintAttributes#DUPLEX_MODE_NONE + * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE + * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE + */ + public int getDuplexModes() { + return mDuplexModes; + } + + /** * Gets the default print attributes. * * @return The default attributes. @@ -178,6 +194,11 @@ public final class PrinterCapabilitiesInfo implements Parcelable { builder.setColorMode(colorMode); } + final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE]; + if (duplexMode > 0) { + builder.setDuplexMode(duplexMode); + } + return builder.build(); } @@ -187,6 +208,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable { readResolutions(parcel); mColorModes = parcel.readInt(); + mDuplexModes = parcel.readInt(); readDefaults(parcel); } @@ -203,6 +225,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable { writeResolutions(parcel); parcel.writeInt(mColorModes); + parcel.writeInt(mDuplexModes); writeDefaults(parcel); } @@ -215,6 +238,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable { result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode()); result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode()); result = prime * result + mColorModes; + result = prime * result + mDuplexModes; result = prime * result + Arrays.hashCode(mDefaults); return result; } @@ -255,6 +279,9 @@ public final class PrinterCapabilitiesInfo implements Parcelable { if (mColorModes != other.mColorModes) { return false; } + if (mDuplexModes != other.mDuplexModes) { + return false; + } if (!Arrays.equals(mDefaults, other.mDefaults)) { return false; } @@ -269,6 +296,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable { builder.append(", mediaSizes=").append(mMediaSizes); builder.append(", resolutions=").append(mResolutions); builder.append(", colorModes=").append(colorModesToString()); + builder.append(", duplexModes=").append(duplexModesToString()); builder.append("\"}"); return builder.toString(); } @@ -289,6 +317,22 @@ public final class PrinterCapabilitiesInfo implements Parcelable { return builder.toString(); } + private String duplexModesToString() { + StringBuilder builder = new StringBuilder(); + builder.append('['); + int duplexModes = mDuplexModes; + while (duplexModes != 0) { + final int duplexMode = 1 << Integer.numberOfTrailingZeros(duplexModes); + duplexModes &= ~duplexMode; + if (builder.length() > 1) { + builder.append(", "); + } + builder.append(PrintAttributes.duplexModeToString(duplexMode)); + } + builder.append(']'); + return builder.toString(); + } + private void writeMediaSizes(Parcel parcel) { if (mMediaSizes == null) { parcel.writeInt(0); @@ -495,19 +539,51 @@ public final class PrinterCapabilitiesInfo implements Parcelable { currentModes &= ~currentMode; PrintAttributes.enforceValidColorMode(currentMode); } - if ((colorModes & defaultColorMode) == 0) { - throw new IllegalArgumentException("Default color mode not in color modes."); - } - PrintAttributes.enforceValidColorMode(colorModes); + PrintAttributes.enforceValidColorMode(defaultColorMode); mPrototype.mColorModes = colorModes; mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode; return this; } /** + * Sets the duplex modes. + * <p> + * <strong>Required:</strong> No + * </p> + * + * @param duplexModes The duplex mode bit mask. + * @param defaultDuplexMode The default duplex mode. + * @return This builder. + * + * @throws IllegalArgumentException If duplex modes contains an invalid + * mode bit or if the default duplex mode is invalid. + * + * @see PrintAttributes#DUPLEX_MODE_NONE + * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE + * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE + */ + public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) { + int currentModes = duplexModes; + while (currentModes > 0) { + final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes)); + currentModes &= ~currentMode; + PrintAttributes.enforceValidDuplexMode(currentMode); + } + PrintAttributes.enforceValidDuplexMode(defaultDuplexMode); + mPrototype.mDuplexModes = duplexModes; + mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode; + return this; + } + + /** * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all * required properties have been specified. See individual methods * in this class for reference about required attributes. + * <p> + * <strong>Note:</strong> If you do not add supported duplex modes, + * {@link android.print.PrintAttributes#DUPLEX_MODE_NONE} will set + * as the only supported mode and also as the default duplex mode. + * </p> * * @return A new {@link PrinterCapabilitiesInfo}. * @@ -532,6 +608,10 @@ public final class PrinterCapabilitiesInfo implements Parcelable { if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) { throw new IllegalStateException("No default color mode specified."); } + if (mPrototype.mDuplexModes == 0) { + setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE, + PrintAttributes.DUPLEX_MODE_NONE); + } if (mPrototype.mMinMargins == null) { throw new IllegalArgumentException("margins cannot be null"); } @@ -558,4 +638,3 @@ public final class PrinterCapabilitiesInfo implements Parcelable { } }; } - diff --git a/packages/PrintSpooler/res/layout/print_activity_controls.xml b/packages/PrintSpooler/res/layout/print_activity_controls.xml index 0bf64aa..a87afe0 100644 --- a/packages/PrintSpooler/res/layout/print_activity_controls.xml +++ b/packages/PrintSpooler/res/layout/print_activity_controls.xml @@ -159,6 +159,34 @@ android:layout_marginEnd="16dip" android:orientation="vertical"> + <!-- Duplex --> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dip" + android:layout_marginStart="12dip" + android:textAppearance="?android:attr/textAppearanceSmall" + android:labelFor="@+id/duplex_spinner" + android:text="@string/label_duplex"> + </TextView> + + <Spinner + android:id="@+id/duplex_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginStart="4dip"> + </Spinner> + + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dip" + android:layout_marginEnd="16dip" + android:orientation="vertical"> + <!-- Range options --> <TextView diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index ab633ea..9d67ccc 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -40,6 +40,9 @@ <!-- Label of the color mode widget. [CHAR LIMIT=20] --> <string name="label_color">Color</string> + <!-- Label of the duplex mode widget. [CHAR LIMIT=20] --> + <string name="label_duplex">Duplex</string> + <!-- Label of the orientation widget. [CHAR LIMIT=20] --> <string name="label_orientation">Orientation</string> @@ -188,12 +191,22 @@ <!-- Color mode labels. --> <string-array name="color_mode_labels"> - <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] --> + <!-- Color mode label: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] --> <item>Black & White</item> <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] --> <item>Color</item> </string-array> + <!-- Duplex mode labels. --> + <string-array name="duplex_mode_labels"> + <!-- Duplex mode label: No duplex supported. [CHAR LIMIT=20] --> + <item>None</item> + <!-- Duplex mode label: Turn page sideways along the long edge like a book. [CHAR LIMIT=20] --> + <item>Long edge</item> + <!-- Duplex mode label: Turn page upwards along the short edge like a notepad. [CHAR LIMIT=20] --> + <item>Short edge</item> + </string-array> + <!-- Orientation labels. --> <string-array name="orientation_labels"> <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] --> diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java index 2cc5e04..377d2d5 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java @@ -695,6 +695,7 @@ public final class PrintSpoolerService extends Service { private static final String TAG_MARGINS = "margins"; private static final String ATTR_COLOR_MODE = "colorMode"; + private static final String ATTR_DUPLEX_MODE = "duplexMode"; private static final String ATTR_LOCAL_ID = "localId"; private static final String ATTR_SERVICE_NAME = "serviceName"; @@ -823,6 +824,10 @@ public final class PrintSpoolerService extends Service { serializer.attribute(null, ATTR_COLOR_MODE, String.valueOf(colorMode)); + final int duplexMode = attributes.getDuplexMode(); + serializer.attribute(null, ATTR_DUPLEX_MODE, + String.valueOf(duplexMode)); + MediaSize mediaSize = attributes.getMediaSize(); if (mediaSize != null) { serializer.startTag(null, TAG_MEDIA_SIZE); @@ -1057,6 +1062,12 @@ public final class PrintSpoolerService extends Service { String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE); builder.setColorMode(Integer.parseInt(colorMode)); + String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE); + // Duplex mode was added later, so null check is needed. + if (duplexMode != null) { + builder.setDuplexMode(Integer.parseInt(duplexMode)); + } + parser.next(); skipEmptyTextTags(parser); diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index f3a5c95..4ba04e5 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -184,6 +184,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat private Spinner mColorModeSpinner; private ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter; + private Spinner mDuplexModeSpinner; + private ArrayAdapter<SpinnerItem<Integer>> mDuplexModeSpinnerAdapter; + private Spinner mOrientationSpinner; private ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter; @@ -767,6 +770,21 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } } } + + // Take the duplex mode only if the current printer supports it. + final int currDuplexMode = currAttributes.getDuplexMode(); + final int newDuplexMode = newAttributes.getDuplexMode(); + if (currDuplexMode != newDuplexMode) { + final int duplexModeCount = mDuplexModeSpinner.getCount(); + for (int i = 0; i < duplexModeCount; i++) { + final int supportedDuplexMode = mDuplexModeSpinnerAdapter.getItem(i).value; + if (supportedDuplexMode == newDuplexMode) { + currAttributes.setDuplexMode(newDuplexMode); + mDuplexModeSpinner.setSelection(i); + break; + } + } + } } // Handle selected page changes making sure they are in the doc. @@ -985,6 +1003,12 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat attributes.setColorMode(defaults.getColorMode()); } + // Duplex mode. + final int duplexMode = attributes.getDuplexMode(); + if ((capabilities.getDuplexModes() & duplexMode) == 0) { + attributes.setDuplexMode(defaults.getDuplexMode()); + } + // Resolution Resolution resolution = attributes.getResolution(); if (resolution == null || !capabilities.getResolutions().contains(resolution)) { @@ -1111,6 +1135,13 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter); mColorModeSpinner.setOnItemSelectedListener(itemSelectedListener); + // Duplex mode. + mDuplexModeSpinnerAdapter = new ArrayAdapter<>( + this, android.R.layout.simple_spinner_dropdown_item, android.R.id.text1); + mDuplexModeSpinner = (Spinner) findViewById(R.id.duplex_spinner); + mDuplexModeSpinner.setAdapter(mDuplexModeSpinnerAdapter); + mDuplexModeSpinner.setOnItemSelectedListener(itemSelectedListener); + // Orientation mOrientationSpinnerAdapter = new ArrayAdapter<>( this, android.R.layout.simple_spinner_dropdown_item, android.R.id.text1); @@ -1187,6 +1218,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mCopiesEditText.setFocusable(false); mMediaSizeSpinner.setEnabled(false); mColorModeSpinner.setEnabled(false); + mDuplexModeSpinner.setEnabled(false); mOrientationSpinner.setEnabled(false); mRangeOptionsSpinner.setEnabled(false); mPageRangeEditText.setEnabled(false); @@ -1202,6 +1234,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mCopiesEditText.setFocusable(false); mMediaSizeSpinner.setEnabled(false); mColorModeSpinner.setEnabled(false); + mDuplexModeSpinner.setEnabled(false); mOrientationSpinner.setEnabled(false); mRangeOptionsSpinner.setEnabled(false); mPageRangeEditText.setEnabled(false); @@ -1317,7 +1350,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat final int colorMode = 1 << colorBitOffset; if (colorMode == oldColorMode) { // Update the index of the old selection. - oldColorModeNewIndex = colorBitOffset; + oldColorModeNewIndex = mColorModeSpinnerAdapter.getCount(); } remainingColorModes &= ~colorMode; mColorModeSpinnerAdapter.add(new SpinnerItem<>(colorMode, @@ -1339,11 +1372,81 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mColorModeSpinner.setSelection(i); } attributes.setColorMode(selectedColorMode); + break; } } } } + // Duplex mode. + mDuplexModeSpinner.setEnabled(true); + final int duplexModes = capabilities.getDuplexModes(); + + // If the duplex modes changed, we update the adapter and the spinner. + // Note that we use bit count +1 to account for the no duplex option. + boolean duplexModesChanged = false; + if (Integer.bitCount(duplexModes) != mDuplexModeSpinnerAdapter.getCount()) { + duplexModesChanged = true; + } else { + int remainingDuplexModes = duplexModes; + int adapterIndex = 0; + while (remainingDuplexModes != 0) { + final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes); + final int duplexMode = 1 << duplexBitOffset; + remainingDuplexModes &= ~duplexMode; + if (duplexMode != mDuplexModeSpinnerAdapter.getItem(adapterIndex).value) { + duplexModesChanged = true; + break; + } + adapterIndex++; + } + } + if (duplexModesChanged) { + // Remember the old duplex mode to try selecting it again. Also the fallback + // is no duplexing which is always the first item in the dropdown. + int oldDuplexModeNewIndex = AdapterView.INVALID_POSITION; + final int oldDuplexMode = attributes.getDuplexMode(); + + // Rebuild the adapter data. + mDuplexModeSpinnerAdapter.clear(); + String[] duplexModeLabels = getResources().getStringArray(R.array.duplex_mode_labels); + int remainingDuplexModes = duplexModes; + while (remainingDuplexModes != 0) { + final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes); + final int duplexMode = 1 << duplexBitOffset; + if (duplexMode == oldDuplexMode) { + // Update the index of the old selection. + oldDuplexModeNewIndex = mDuplexModeSpinnerAdapter.getCount(); + } + remainingDuplexModes &= ~duplexMode; + mDuplexModeSpinnerAdapter.add(new SpinnerItem<>(duplexMode, + duplexModeLabels[duplexBitOffset])); + } + + if (oldDuplexModeNewIndex != AdapterView.INVALID_POSITION) { + // Select the old duplex mode - nothing really changed. + if (mDuplexModeSpinner.getSelectedItemPosition() != oldDuplexModeNewIndex) { + mDuplexModeSpinner.setSelection(oldDuplexModeNewIndex); + } + } else { + // Select the default. + final int selectedDuplexMode = defaultAttributes.getDuplexMode(); + final int itemCount = mDuplexModeSpinnerAdapter.getCount(); + for (int i = 0; i < itemCount; i++) { + SpinnerItem<Integer> item = mDuplexModeSpinnerAdapter.getItem(i); + if (selectedDuplexMode == item.value) { + if (mDuplexModeSpinner.getSelectedItemPosition() != i) { + mDuplexModeSpinner.setSelection(i); + } + attributes.setDuplexMode(selectedDuplexMode); + break; + } + } + } + } + + mDuplexModeSpinner.setEnabled(mDuplexModeSpinnerAdapter.getCount() > 1); + // Orientation mOrientationSpinner.setEnabled(true); MediaSize mediaSize = attributes.getMediaSize(); @@ -2173,6 +2276,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } else if (spinner == mColorModeSpinner) { SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position); mPrintJob.getAttributes().setColorMode(colorModeItem.value); + } else if (spinner == mDuplexModeSpinner) { + SpinnerItem<Integer> duplexModeItem = mDuplexModeSpinnerAdapter.getItem(position); + mPrintJob.getAttributes().setDuplexMode(duplexModeItem.value); } else if (spinner == mOrientationSpinner) { SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position); PrintAttributes attributes = mPrintJob.getAttributes(); |