summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt7
-rw-r--r--api/system-current.txt7
-rw-r--r--core/java/android/print/PrintAttributes.java109
-rw-r--r--core/java/android/print/PrinterCapabilitiesInfo.java91
-rw-r--r--packages/PrintSpooler/res/layout/print_activity_controls.xml28
-rw-r--r--packages/PrintSpooler/res/values/strings.xml15
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java11
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java108
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 &amp; 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();